2016-11-28 7 views
0

Я спрашиваю вас, есть ли способ иметь приоритет между двумя узлами ROS. В частности, у меня есть узел ROS, который делает вывод, который представляет собой текстовый файл с 60 данными в нем, и он обновляет его каждый раз, потому что данные изменяются. Тогда у меня есть узел, который должен проанализировать этот текстовый файл. В принципе, мне нужно внести некоторые изменения в механизм, который останавливает узел анализатора при запуске узла записи, тогда он должен отправить сигнал узлу анализатора, чтобы он мог запускать и анализировать текстовый файл. И тогда узел-писатель должен вернуться, скажем, «ответственный», чтобы снова перезаписать текстовый файл. Итак, простыми словами, это цикл. Кто-то сказал мне, что возможное решение может быть чем-то вроде темы «семафора», в которой узел-писатель пишет, например, логическое значение 1, когда делает открытие, запись и закрытие текстового файла, поэтому анализатор узел знает, что не может выполнить свою разработку, так как файл еще не готов. И, когда автор закончил и закрыл текстовый файл, ему должно быть опубликовано значение 0, которое разрешает анализ узлом анализатора. Я искал публикацию логических значений и я нашел код, который может быть что-то вроде этого:Есть ли способ иметь приоритет между двумя ROS-узлами?

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

Я не знаю, если я только использовать издатель в узле писателя и абонент в анализаторе узел. Может быть, мне нужно использовать оба из них в двух узлах, что-то вроде: writer помещает 1 в семафор темы, поэтому анализатор знает, что не может получить доступ к текстовому файлу, делает текстовый файл, а затем помещает 0 в тему и подписывается на тема снова ждет 1; анализатор делает что-то подобное, но наоборот. Я поставил два кода ниже, потому что я не знаю, где разместить издателя и подписчика, и как заставить их работать хорошо. Если возможно, мне нужно сохранить эту структуру рабочего потока в моих кодах. ПРИМЕЧАНИЕ: новый текстовый файл создается почти каждые 10 секунд, так как в текстовом файле записываются данные, поступающие из другой темы ROS, а в коде у писателя есть механизм для такого рода разработки. Спасибо заранее! EDIT: теперь коды исправлены с помощью решения на основе темы, как я объясняю в своем последнем комментарии.

код Автор:

#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; 
} 

анализатор кода:

#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; 
} 

ответ

1

Это может быть сделано просто с помощью ROS services. В основном, когда ваш узел A получает сообщение, он делает то, что ему нужно (записывает файл), а затем запрашивает серию из узла B (анализирует файл).

Единственное, что я вижу, это то, что узлу A придется дождаться окончания обслуживания узла B. Если B не нужно слишком много времени, это не вызовет проблемы.

Код сниппета:

Srv:

создать службу под названием "analyse_heart_rate.srv" в СРВ папке пакета (я должен это имя "heart_rate_monitor").

указать запрос/ответ вашей структуры службы в файле:

string filename 
--- 
bool result 

CMakeLists:

добавить следующие строки:

add_service_files(
    FILES 
    analyse_heart_rate.srv 
) 

Сервер службы:

#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 Client

#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; 
} 

Таким образом, всякий раз, когда приходит сообщение в узле "Service Client", он будет обрабатывать его и в итоге записать его в файл. Затем он просит «Сервисный сервер» обрабатывать файл, созданный ранее ...

Конечно, это всего лишь фрагмент, рассчитанный на ваши потребности.

Cheers.

+0

Здравствуйте @Vtik, спасибо вам за ваш ответ! Не возражаете, если я попрошу вас подробно объяснить вашу идею? Также очень понравились бы фрагменты кода. Только если вы можете, конечно! Я говорю это, потому что я очень новичок в кодировании и супер новичок в ROS. Еще раз спасибо! – Marcofon

+0

Спасибо вам большое! Я постараюсь применить его к моему делу! Еще раз спасибо! Я дам вам знать, смогу ли я это сделать. – Marcofon

+0

Прошу прощения за глупый вопрос, но в файле .srv вместо имени файла я должен указать имя текстового файла, который я хочу проанализировать. EDIT: И еще одна вещь. Со структурой, которую вы мне предложили, называется ли сценарий каждый раз или только когда у меня есть 10 новых данных в текстовом файле с 60 данными в нем? Поскольку это моя цель, может быть, это было непонятно из моего вопроса и моих кодов, я попытался объяснить это в разделе NOTE. Прошу прощения, если это так! – Marcofon