Publisher
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char **argv)
{
ros::init(argc, argv, "talker"); //1.启动该节点 2.并设置其名称(名称要唯一)
ros::NodeHandle n; //设置节点句柄
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
//将节点设置成发布者,并将所发布主题的类型和名称告知节点管理器。
第一个参数是消息的名称,设置为 message;
第二个参数是缓冲区的大小。如果主题发布数据速度较快,那么将缓冲区设置为 1000 个消息
ros::Rate loop_rate(10); //发送数据的频率10Hz
while (ros::ok()) //收到Crtl+C消息或者ROS停止运行,ros::ok()库会执行停止节点运行命令
{
//创建一个消息变量(消息的类型必须符合发送数据的要求)
std_msgs::String msg;
std::stringstream ss;
ss << "hello world " << count;
msg.data = ss.str();
ROS_INFO("%s", msg.data.c_str()); //ROS_INFO and friends are our replacement for printf/cout.
chatter_pub.publish(msg); //就这样,消息被发布了。
ros::spinOnce(); //若有Subscriber出现,ROS就会更新和读取所有主题
loop_rate.sleep(); //按照10Hz的频率把程序挂起。(Why???)
++count;
}
return 0;
}
ROS Node
1)在一个机器人软件中,有各种各样的node。别抢答,各种各样不是指localization,slam ,action这些功能的多种多样,而是指有消息的生产者,消费者,以及消费又生产的深加工者。先插一句吧,这次讨论涉及到这样的一个问题,在用ros构建一个机器人软件时,仅仅从功能划分的角度来构建node是否合适。是否还需要考虑让消息的流动更顺畅,让node更简洁高效呢?先说node是怎么跑的吧。当你建立一个node后,要么它按照一个固定的周期运行,要么它阻塞等待事件发生,由事件驱动运行。无论是那种,node都要干活,node干的什么活呢?callback queue里的活。这个callback queue里的callback是哪里来的呢?常见的是subscriber的callback,当然还有其他的,包括publisher的,service的。那这些callback是什么时候被调用的呢。那就是spin()或者spinonce()。spin调用在queue 里所有的availiable的callback,如果没有availible的,它就阻塞。spinonce,显然只调用一次,看看有没有准备好的callback,有就调用,没有就返回。那什么是availible的、准备好的呢?对于subscribe,准备好的就是那些有新消息的subscriber的callback。现在如果你明白了上述node的运行机理。你在感到舒服之余,请准备接收心烦的问题。1)第一个问题就是,如果subscriber没有收到新消息,那么它的callback就不会被执行。如果你想每次都运行callback呢?对不起,没办法,不是virgin我不娶。
2)第二个问题,callback执行有个timeout值,如果设置不合理,要么费时,要么callback被中止。被中止呀,兄弟们,多可怕,万一是一个重要逻辑的一环呢?今天就聊到这里,最后送点福利,如果你想实现事件触发的node就用spin;如果你要固定周期的node,那就用spinonce+sleep,但一定要牢记,在每个周期里不是所有callback被执行。
Subscriber
#include "ros/ros.h"
#include "std_msgs/String.h"
//每次该节点收到一条消息都会调用此函数,我们就可以使用或者处理数据。
ROS_INFO()函数用于命令行打印数据
(现在在这里面我们把收到的数据在命令行打印出来。)
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard: [%s]", msg->data.c_str());
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "listener");
ros::NodeHandle n;
//创建一个订阅者,并从topic获取以chatter为名的消息数据。
设置缓冲区1000
处理消息的回调函数为chatterCallback()
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
//ros::spin();库是node 读取数据的消息响应循环,当消息到达的时候,回调函数被调用。
Ctrl+C时,node退出消息循环
ros::spin();
return 0;
}
编译节点
The generated CMakeLists.txt should look like this:
添加代码: