J'apprends C ++.
J'ai besoin d'attendre de recevoir des données pour démarrer le fil principal. P>
Ceci est la fonction de rappel où je vais recevoir les données dont j'ai besoin : P>
int main(int argc, char **argv)
{
ros::init(argc, argv, "astar_controller");
/**
* NodeHandle is the main access point to communications with the ROS system.
* The first NodeHandle constructed will fully initialize this node, and the last
* NodeHandle destructed will close down the node.
*/
ros::NodeHandle n;
/**
* Topic where we are going to publish speed commands.
*/
ros::Publisher cmd_vel_pub = n.advertise<geometry_msgs::Twist>(cmdTopic, 1000);
/**
* Topic where we are going to receive odometry messages.
*/
ros::Subscriber odom_sub = n.subscribe(odomTopic, 1000, odomCallback);
ros::Rate loop_rate(10);
//*********************************************
// I want to wait here.
//*********************************************
// More code...
}
3 Réponses :
globalement, déclarez une variable de condition et un mutex qui sont partagés entre le fil de rappel et le principal. Et un booléen qui est sous la serrure mutex.
//*********************************************
// I want to wait here.
//*********************************************
// Wait for odomCallback to signal its done
{
std::unique_lock<std::mutex> lock(g_mutex);
while (g_isReady == false)
{
g_cv.wait(lock);
}
}
Même si la solution est correcte, votre dernière boucle ( tandis que (g_isready == false) code>) peut être simplifié à g_cv.wait (verrouiller, [] {retour g_isready;}); Code>
La dernière partie, après // attendre que OdomCallback signalait son code> bloque tout: je ne reçois aucun message dans OdomCallback et je ne peux pas tuer le programme avec CTRL. + C. Peut-être parce qu'il bloque le fil principal (je suppose, je n'ai aucune idée de la filetage en C ++).
@Vansfannel - Êtes-vous sûr que OdomCallback code> est-il invoqué? Sinon, êtes-vous absolument certain que odomcallback code> devrait être appelé sur un thread différent - ou si ce cadre s'attend-il à ce que vous penchiez des messages sur le thread principal (par conséquent, ce n'est pas vraiment un problème de threading).
edit: strong> Je ne pense pas que vous soyez censé utiliser plusieurs threads. Vous attendez des rappels en exécutant un "" boucle d'événement " dans le fil principal fort>. voir http: / /wiki.ros.org/rospp/overview/callbacks%20and%20Spinning p> La réponse originale suit: strong> p> Tout d'abord, Le la fonction de rappel doit verrouiller ce mutex lors de l'accès à < Code> is_init_pos code> et envoyez une notification sur la variable de condition: p> Maintenant, le thread principal peut attendre sur la variable de condition pour recevoir une notification lorsque l'état change: p> Le thread bloquera sur le et dans le fichier code> fileter utilise Ceci utilise une variable
is_init_pos code> variable doit être sûr d'accéder simultanément à partir de plusieurs threads. Sinon, si le fil principal le lit alors que le fil de rappel l'écrit, votre programme aura un comportement indéfini. Ainsi, utilisez un mutex pour synchroniser l'accès au booléen et utiliser une variable de condition pour envoyer une notification lorsque son état change: p> condition_variable :: wait code> appelez et ne reviendra que après qu'il soit réveillé par une notification et qu'il voit une valeur réelle pour la condition associée (définie comme une expression Lambda teste la variable booléenne). Bien qu'il n'y ait aucune notification ou que la condition est fausse, elle continuera à attendre. P>
g_isready code> est partagée entre les deux threads. Il n'est donc pas nécessaire de verrouiller le mutex dans le rappel à chaque fois, uniquement sur le premier appel: < / p> [] {return g_isready; }; code> pour la condition. P> BOOL code> supplémentaire, mais évite de verrouiller le mutex sur chaque rappel. Cela ne fera probablement pas beaucoup de différence dans la pratique, donc dans ma réponse, je viens de réutiliser la variable is_init_pos code> que vous avez déjà. P> p>
La dernière partie, après // nouvelle portée imbriquée qui détermine la durée du verrouillage mutex code>, bloque tout: je ne reçois aucun message dans odomcallback code> et je ne peux pas Tuez le programme avec CTRL. + c. Peut-être parce qu'il bloque le fil principal (je suppose, je n'ai aucune idée de la filetage en C ++).
Ensuite, vous avez fait quelque chose de mal. Peut-être que vous avez oublié de changer le rappel pour l'informer de la variable de condition. Peut-être que vous avez oublié d'ajouter le init_cv.wait (verrouillage, condition); code> ligne.
Non, j'ai tout copié de votre réponse. J'ai vérifié double vérité.
Ensuite, cela signifie que le rappel n'arrive pas. Êtes-vous sûr que les rappels se produisent sur un fil séparé? Peut-être que vous êtes censé créer une boucle pair dans principale code> qui attendra les rappels dans le fil principal i>. Je viens de regarder wiki.ros.org et je ne pense pas que cela fonctionne comme vous pensez que cela fonctionne. Tu n'es pas censé appeler ros :: spin () code> pour attendre les rappels? Pourquoi essayez-vous d'utiliser plusieurs threads? Avez-vous essayé l'exemple à wiki.ros.org/ros/ Tutoriels / ... ?
Oui, j'utilise cet exemple. J'apprends et j'essaie maintenant de comprendre comment les rappels de Ros fonctionnent. Laissez-moi voir ce que ça se passe et je vais vous dire. Merci beaucoup pour votre temps et votre aide.
La magie est quelque chose d'intéressant.
Les deux autres réponses sont correctes lorsque vous exécutez une application multithreading, mais ceci est une application de fil unique.
ROS Utilisez Procédez à une seule série de rappels. P>
Cette méthode est utile si vous avez votre propre boucle en cours d'exécution et souhaitez
traiter tous les rappels disponibles. Cela équivaut à
appeler callarvailable () sur le CallbackQueue mondial. Ça ne sera pas
traiter tous les rappels attribués à des files d'attente personnalisées. P>
BlockQuote> Merci à Jonathan Wakely pour me diriger vers la bonne direction. Désolé, j'apprends et je ne le savais pas. P> i Fixe enfin à l'aide de ce code: P> ROS :: spinonce () code> à: p>
//*********************************************
// I want to wait here.
//*********************************************
while (ros::ok)
{
ros::spinOnce();
loop_rate.sleep();
if (!is_init_pos)
break;
}
STD :: Condition_Variable Code>?std :: futur code>@ Algirdaspreidžius merci mais je ne comprends pas l'exemple sur ce site. Je veux relâcher la serrure sur le dernier
si code> condition:si (is_init_pos) code>.