2016-11-28 47 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; 

我不知道如果我只用在作家节点发布者和用户分析仪节点。也许我必须在两个节点中使用它们,例如:编写者在主题信号量中放置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; 
} 

回答

1

这可以简单地使用ROS services来完成。基本上,当你的节点A得到这个消息时,它会做它所需要的(写入文件),然后向节点B请求一个服务(分析该文件)。

我看到的唯一的con是节点A将不得不等待节点B服务完成。如果B不需要太多时间,这不会引起问题。

代码段:

SRV

创建一个在你的包的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; 
} 

服务客户端

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

这样,每当有消息到达节点“服务客户”,这将对其进行处理并最终将其写入文件。然后它要求“服务服务器”处理先前创建的文件...

当然,这只是一个片段,需要它来满足您的需求。

干杯。

+0

你好@Vtik,谢谢你的回复!你介意我是否要求你详细解释你的想法?此外代码片段将非常感激。只有当你可以,当然!我这样说是因为我对编码非常陌生,对ROS本身也是超新的。再次感谢你! – Marcofon

+0

非常感谢你!我会尝试将它应用于我的案例!再次感谢你!我会让你知道我是否可以做到。 – Marcofon

+0

我很抱歉这个愚蠢的问题,但在.srv文件中,而不是文件名,我必须把我想分析的文本文件的名称?编辑:还有一件事。有了你建议给我的结构,是每次都要调用的脚本,还是只有当我有60个数据的文本文件中有10个新数据?因为这是我的目标,也许从我的问题和我的代码中不清楚,我试图在注释部分解释这一点。我很抱歉,如果是这样的话! – Marcofon

相关问题