2016-11-28 4 views
0

Je vous demande s'il existe un moyen d'avoir une préséance entre deux nœuds ROS. En particulier, j'ai un nœud ROS qui fait une sortie qui est un fichier texte avec 60 données, et il recrée à chaque fois parce que les données changent. Ensuite, j'ai un noeud qui doit analyser ce fichier texte. Fondamentalement, ce dont j'ai besoin est de faire des changements pour avoir un mécanisme qui arrête le nœud de l'analyseur lorsque le nœud écrivain fonctionne, puis il doit envoyer un signal au nœud de l'analyseur pour le faire fonctionner et analyser le fichier texte. Et puis le noeud écrivain doit revenir disons "en charge" pour être en mesure de réécrire le fichier texte à nouveau. Donc, en termes simples, est une boucle. Quelqu'un m'a dit qu'une solution possible peut être quelque chose comme un "sémaphore" sujet dans lequel le nœud écrivain écrit, par exemple, une valeur booléenne de 1 quand est l'ouverture, l'écriture et la fermeture du fichier texte, de sorte que l'analyseur Le noeud sait qu'il ne peut pas faire son élaboration, puisque le fichier n'est pas encore prêt. Et, lorsque l'auteur a terminé et fermé le fichier texte, il doit être publié une valeur 0 qui permet l'analyse par le nœud de l'analyseur. Je recherchais la publication de valeurs booléennes et je l'ai trouvé un code qui peut être quelque chose comme ceci:Existe-t-il un moyen d'avoir une préséance entre deux nœuds ROS?

ros::Publisher pub = n.advertise<std_msgs::Bool>("semaphore", 1000); 
std_msgs::Bool state; 
state.data = 1; 

Je ne sais pas si je ne dispose que d'utiliser l'éditeur dans le nœud de l'écrivain et l'abonné dans l'analyseur nœud. Peut-être que je dois utiliser les deux dans les deux nœuds, quelque chose comme: écrivain mettre un 1 dans le thème sémaphore afin que l'analyseur sait que ne peut pas accéder au fichier texte, fait le fichier texte, puis mettre un 0 dans le sujet et souscrire le sujet attend encore 1; l'analyseur fait quelque chose de semblable mais à l'envers. J'ai mis les deux codes ci-dessous, parce que je n'ai aucune idée où placer l'éditeur et l'abonné et comment les faire fonctionner correctement. Si possible, je dois garder cette structure de flux de travail dans mes codes. NOTE: un nouveau fichier texte est créé presque toutes les 10 secondes, car dans le fichier texte, il y a des données écrites provenant d'un autre sujet ROS et le code dans l'éditeur a un mécanisme pour faire ce genre d'élaboration. Merci d'avance !!! EDIT: Maintenant, les codes sont corrigés avec une solution basée sur un sujet comme je l'explique dans mon dernier commentaire.

Code Writer:

#include "ros/ros.h" 
#include "std_msgs/String.h" 
#include "std_msgs/Bool.h" 
#include "../include/heart_rate_monitor/wfdb.h" 
#include <stdio.h> 
#include <sstream> 
#include <iostream> 
#include <fstream> 
#include <iomanip> 
#include <algorithm> 
#include <deque> 
#include "heart_rate_monitor/analyse_heart_rate.h" 

using namespace std; 



static std::deque<std::string> queue_buffer; 
static int entries_added_since_last_write = 0; 

ros::Publisher pub; 

void write_data_to_file() 
{ 
// open file; 
std::ofstream data_file("/home/marco/catkin_ws/src/heart_rate_monitor/my_data_file.txt"); 
if (data_file.is_open()) 
{ 
for (int i = 0; i < queue_buffer.size(); ++i) 
{ 
    data_file << queue_buffer[i] << std::endl; 
} 
} 
else 
{ 
std::cout << "Error - Cannot open file." << std::endl; 
exit(1); 
} 
data_file.close(); 

std_msgs::Bool state; 
state.data = 0; 

pub.publish(state); 

} 

void process_message(const std_msgs::String::ConstPtr& string_msg) 
{ 
std_msgs::Bool state; 
state.data = 1; 

pub.publish(state); 

// if buffer has already 60 entries, throw away the oldest one 
if (queue_buffer.size() == 60) 
{ 
queue_buffer.pop_front(); 
} 

// add the new data at the end 
queue_buffer.push_back(string_msg->data); 

// check if 10 elements have been added and write to file if so 
entries_added_since_last_write++; 

if (entries_added_since_last_write >= 10 
    && queue_buffer.size() == 60) 
{ 
// write data to file and reset counter 
write_data_to_file(); 
entries_added_since_last_write = 0; 
} 

} 


int main(int argc, char **argv) 
{ 

ros::init(argc, argv, "writer"); 

ros::NodeHandle n; 

ros::Subscriber sub = n.subscribe("/HeartRateInterval", 1000, process_message); 
pub = n.advertise<std_msgs::Bool>("/semaphore", 1000); 

ros::spin(); 

return 0; 
} 

Code Analyzer:

#include "ros/ros.h" 
#include "std_msgs/String.h" 
#include "std_msgs/Bool.h" 
#include "../include/heart_rate_monitor/wfdb.h" 
#include <stdio.h> 
#include <sstream> 
#include <iostream> 
#include <fstream> 
#include <iomanip> 
#include <algorithm> 
#include <deque> 
#include "heart_rate_monitor/analyse_heart_rate.h" 

void orderCallback(const std_msgs::Bool::ConstPtr& msg) 
{ 

if (msg->data == 0) 
{ 
chdir("/home/marco/catkin_ws/src/heart_rate_monitor"); 

system("get_hrv -R my_data_file.txt >doc.txt"); 
} 
} 


int main(int argc, char **argv) 
{ 

ros::init(argc, argv, "analyzer"); 

ros::NodeHandle n; 

ros::Subscriber sub = n.subscribe("/semaphore", 1000, orderCallback); 

ros::spin(); 

return 0; 
} 

Répondre

1

Cela pourrait se faire simplement à l'aide ROS services. Fondamentalement, lorsque votre noeud A reçoit le message, il fait ce dont il a besoin (écrire le fichier) et demande ensuite un serice du noeud B (analyse du fichier). La seule chose que je vois est que le nœud A devra attendre que le service du nœud B soit terminé. Si B n'a pas besoin de trop de temps, cela ne posera pas de problème.

Code Snippet:

applic:

créer un service nommé "analyse_heart_rate.srv" dans le dossier SRV de votre colis (je suppose son nom "heart_rate_monitor").

préciser la demande/réponse de votre structure de service dans le fichier:

string filename 
--- 
bool result 

CMakeLists:

ajouter les lignes suivantes:

add_service_files(
    FILES 
    analyse_heart_rate.srv 
) 

Server Service:

#include "ros/ros.h" 
#include "heart_rate_monitor/analyse_heart_rate.h" 


bool analyse(heart_rate_monitor::analyse_heart_rate::Request &req, 
    heart_rate_monitor::analyse_heart_rate::Response &res) 

{ 
    res.result = analyse_text_file(req.filename); 
    return true; 
} 

int main(int argc, char **argv) 
{ 
    ros::init(argc, argv, "heart_rate_analyser_server"); 
    ros::NodeHandle n; 

    ros::ServiceServer service = n.advertiseService("heart_rate_analyser", analyse); 
    ROS_INFO("Ready to analyse requests."); 
    ros::spin(); 

    return 0; 
} 

service à la clientèle

#include "ros/ros.h" 
#include "heart_rate_monitor/analyse_heart_rate.h" 

void process_message(const std_msgs::String::ConstPtr& string_msg) 
{ 
    std::string output_filename; 
    do_staff_with_message(); 
    write_data_to_file_(output_filename); 

    heart_rate_monitor::analyse_heart_rate srv; 
    srv.filename = output_filename ; 
    if (client.call(srv)) 
    { 
     ROS_INFO("Result: %d", (bool)srv.response.result); 
    } 
    else 
    { 
     ROS_ERROR("Failed to call service heart_rate_analyser"); 
    } 
} 

int main(int argc, char **argv) 
{ 
    ros::init(argc, argv, "add_two_ints_client"); 
    ros::NodeHandle n; 
    ros::ServiceClient client = n.serviceClient<heart_rate_monitor::analyse_heart_rate>("heart_rate_analyser"); 
    ros::Subscriber sub = n.subscribe("/HeartRateInterval", 1000, process_message); 

    return 0; 
} 

De cette façon, chaque fois qu'un message est dans le nœud "Service Client", il traitera et éventuellement écrire dans le fichier. Ensuite, il demande au "Service Server" de traiter le fichier créé précédemment ...

Bien sûr, ceci n'est qu'un extrait, vous le costumez selon vos besoins.

Cheers.

+0

Bonjour @Vtik, merci pour votre réponse! Cela vous dérangerait-il si je vous demande d'expliquer votre idée dans les détails? Des extraits de code seraient également très appréciés. Seulement si vous le pouvez, bien sûr! Je dis cela parce que je suis très nouveau pour le codage et super nouveau pour ROS lui-même. Merci encore! – Marcofon

+0

Merci beaucoup! Je vais essayer de l'appliquer à mon cas! Merci encore! Je vous ferai savoir si je serai en mesure de le faire. – Marcofon

+0

Je suis désolé pour la question stupide, mais dans le fichier .srv au lieu du nom de fichier, je dois mettre le nom du fichier texte que je veux analyser? EDIT: Et encore une chose. Avec la structure que vous m'avez suggérée, le script est-il appelé à chaque fois ou seulement quand j'ai 10 nouvelles données dans le fichier texte avec 60 données dedans? Parce que c'est mon but, peut-être que ce n'était pas clair à partir de ma question et de mes codes, j'ai essayé d'expliquer cela dans la section NOTE. Je suis désolé si c'est le cas! – Marcofon