续上一篇文章。
我们现在在VScode里面加入订阅方的实现。
demo02_sub.cpp
#include "ros/ros.h"
#include "std_msgs/String.h"/*订阅方实现:1、包含头文件ROS中文本类型 ---> std_msgs/String.h2、初始化ROS节点3、创建节点句柄4、创建订阅者对象5、处理订阅到的数据
*/
void doMsg(const std_msgs::String::ConstPtr &msg)
{//通过msg获取并操作订阅到的数据ROS_INFO("翠花订阅到的数据:%s",msg->data.c_str());
}int main(int argc, char *argv[])
{setlocale(LC_ALL,"");// 初始化 ROS 节点(节点不能重名,不然把别的节点给干掉了,要具有唯一性)ros::init(argc,argv,"cuiHua");// 创建节点句柄ros::NodeHandle nh;// 创建订阅者对象ros::Subscriber sub = nh.subscribe("fang",10,doMsg);//处理订阅到的数据//循环ros::spin();return 0;
}
demo01_pub.cpp
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
/*发布方实现:1、包含头文件ROS中文本类型 ---> std_msgs/String.h2、初始化ROS节点3、创建节点句柄4、创建发布者对象5、编写发布逻辑并发布数据
*/int main(int argc, char *argv[])
{setlocale(LC_ALL,"");// 2、初始化 ROS 节点;ros::init(argc,argv,"erGouZi");// 3、创建节点句柄 ;ros::NodeHandle nh;// 4、茶ungjian发布者对象ros::Publisher pub = nh.advertise<std_msgs::String>("fang",10);// 5、编写发布逻辑并发布数据//要求以 10HZ 的频率发布数据,并且文本后添加编码//先创建被发布的消息 std_msgs::String msg;//发布频率ros::Rate rate(0.5);//编写循环,循环中发布数据//设置编号、int count = 0;while (ros::ok()){count++;// msg.data = "hello";//实现字符串拼接数字std::stringstream ss;ss << "hello ---> " << count;msg.data = ss.str();pub.publish(msg);//添加日志ROS_INFO("发布的数据是:%s",ss.str().c_str());rate.sleep();ros::spinOnce(); //官方建议,处理回调函数}return 0;}
每次编写完后记得catkin_make一下。
可能遇到的问题
如果出现乱码,那么需要在代码里面加入这句话
讲一些代码里的知识
在ROS中,ros::spinOnce()
函数用于处理回调队列。这个函数告诉ROS节点,它需要检查回调队列并调用任何等待的回调函数。这是非常重要的,因为它允许节点响应事件,如接收到新的消息或服务请求。
回调函数
在ROS中,回调函数是当某个事件发生时自动执行的函数。最常见的回调是消息回调,它们是由节点订阅的话题上接收到新消息时触发的。例如,如果你的节点订阅了一个std_msgs::String
类型的消息,当新的消息到达时,就会调用相应的回调函数。
ros::spinOnce() 的作用
- 处理回调:
ros::spinOnce()
调用等待在回调队列中的所有回调函数。 - 非阻塞:这个函数是非阻塞的,它只处理一次回调队列,然后立即返回。
- 频率控制:在循环中调用
ros::spinOnce()
可以控制回调函数的处理频率。
使用场景
通常,你会在ROS节点的主循环中调用ros::spinOnce()
,以确保节点能够响应所有传入的消息和事件。以下是一个典型的使用示例:
#include "ros/ros.h"
#include "std_msgs/String.h"void messageCallback(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, "subscriber_node");ros::NodeHandle nh;ros::Subscriber sub = nh.subscribe("topic", 10, messageCallback);ros::Rate loop_rate(1); // 1 Hzwhile (ros::ok()){ros::spinOnce(); // 处理回调队列loop_rate.sleep(); // 等待下一次循环}return 0;
}
在这个例子中,ros::spinOnce()
被调用以确保当有新消息到达时,messageCallback
函数会被执行。然后,loop_rate.sleep()
用于控制循环的频率,这里是每秒一次。
官方建议
ROS官方建议在主循环中使用ros::spinOnce()
,因为它提供了更好的控制和灵活性。如果你不调用ros::spinOnce()
,节点可能无法响应某些事件,特别是当这些事件不是由ROS的内部定时器触发的时候。此外,ros::spin()
(一个阻塞调用,会一直运行直到节点关闭)已被弃用,因为它可能导致节点在处理大量消息时变得不够响应。