Есть ли способ иметь приоритет между двумя узлами ROS?

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

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

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

Код писателя:

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

person Marcofon    schedule 28.11.2016    source источник


Ответы (1)


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

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

Фрагмент кода:

SRV:

создайте службу с именем analyse_heart_rate.srv в папке 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;
}

Сервисный клиент

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

Таким образом, всякий раз, когда сообщение поступает в клиент службы узла, он обрабатывает его и в конечном итоге записывает в файл. Затем он просит сервисный сервер обработать ранее созданный файл ...

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

Ваше здоровье.

person Vtik    schedule 28.11.2016
comment
Привет @Vtik, спасибо за ответ! Не возражаете, если я попрошу вас подробно объяснить вашу идею? Также были бы очень признательны фрагменты кода. Только если сможешь, конечно! Я говорю это, потому что я новичок в программировании и очень новичок в самой ROS. Еще раз спасибо! - person Marcofon; 28.11.2016
comment
Огромное спасибо! Я постараюсь применить это в своем случае! Еще раз спасибо! Я дам тебе знать, смогу ли я это сделать. - person Marcofon; 29.11.2016
comment
Прошу прощения за глупый вопрос, но в файле .srv вместо имени файла я должен указать имя текстового файла, который я хочу проанализировать? РЕДАКТИРОВАТЬ: И еще кое-что. С предложенной вами структурой скрипт вызывается каждый раз или только когда у меня есть 10 новых данных в текстовом файле с 60 данными в нем? Поскольку это моя цель, возможно, это не было ясно из моего вопроса и моих кодов, я попытался объяснить это в разделе ПРИМЕЧАНИЕ. Прошу прощения, если это так! - person Marcofon; 29.11.2016
comment
Здравствуйте, @vtik, я попытался реализовать ваше решение в своем коде, и это показалось мне немного сложным, потому что я не так хорош в программировании. Затем я успешно использовал тематическое решение. Я отправлю коды, которые использую сейчас, в качестве редактирования своего вопроса. Огромное спасибо! Ваше решение очень помогло мне лучше понять ROS и решить мою проблему. Спасибо, ура !!! - person Marcofon; 01.12.2016