ROS 通信机制
目录
实操2:已知turtlesim中的乌龟显示节点,会发布当前乌龟的位姿(窗体中乌龟的坐标以及朝向),要求控制乌龟运动,并时时打印当前乌龟的位姿。
话题通信
话题通信适用于不断更新的数据传输相关的应用场景,例如雷达、摄像头、GPS.... 等等一些传感器数据的采集。
案例1:实现最基本的话题通信
编写发布订阅实现,要求发布方以10HZ(每秒10次)的频率发布文本消息,订阅方订阅消息并将消息内容打印输出。
1.发布方实现
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
//发布方实现
/*
实现流程:
1.包含头文件
2.初始化 ROS 节点:命名(唯一)
3.实例化 ROS 句柄
4.实例化 发布者 对象
5.组织被发布的数据,并编写逻辑发布数据
*/
int main(int argc, char *argv[])
{
//初始化 ROS 节点:命名(唯一)
ros::init(argc,argv,"erGouzi");
//实例化 ROS 句柄
ros::NodeHandle nh;
//实例化 发布者 对象
ros::Publisher pub = nh.advertise<std_msgs::String>("fang",10); // (话题 缓存长度)
std_msgs::String msg;
ros::Rate rate(10);//10hz
int count = 0;//编号
while (ros::ok())//结点还活着
{
count ++;
std::stringstream ss;
ss<<"hello--->"<<count;
msg.data=ss.str();
pub.publish(msg);
ROS_INFO("date is :%s",ss.str().c_str());//打印日志
rate.sleep();
}
return 0;
}
验证:
2.订阅者实现
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
/*
1.包含头文件
2.初始化 ROS 节点:命名(唯一)
3.实例化 ROS 句柄
4.实例化 订阅者 对象
5.处理订阅的消息(回调函数)
6.设置循环调用回调函数
*/
void doMsg(const std_msgs::String::ConstPtr &msg){
ROS_INFO("cuihua listen:%s",msg->data.c_str());
}
int main(int argc, char *argv[])
{
ros::init(argc,argv,"cuiHua");//二狗子和翠花通信
ros::NodeHandle nh;
ros::Subscriber sub =nh.subscribe("fang",10,doMsg);
ros::spin();//循环读取接收的数据,并调用回调函数处理
/* code */
return 0;
}
3.结果
计算图:
案例2:话题通信自定义msg
创建自定义消息,该消息包含人的信息:姓名、身高、年龄等。
1.定义msg文件
功能包下新建 msg 目录,添加文件 Person.msg
string name
uint16 age
float64 height
2.编辑配置文件
3.发布者
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
#include "plumbing_pub_sub/Person.h"
int main(int argc, char *argv[])
{
/* code */
ros::init(argc,argv,"banzhuren");
ros::NodeHandle nh;
ros::Publisher pub =nh.advertise<plumbing_pub_sub::Person>("liaotian",10);
plumbing_pub_sub::Person person;
person.name ="haodong";
person.name =22;
person.height=1.80;
ros::Rate rate(0.5);
while (ros::ok)
{
pub.publish(person);
rate.sleep();
ros::spinOnce();
}
return 0;
}
4.订阅者
#include "ros/ros.h"
#include "demo02_talker_listener/Person.h"
void doPerson(const demo02_talker_listener::Person::ConstPtr& person_p){
ROS_INFO("订阅的人信息:%s, %d, %.2f", person_p->name.c_str(), person_p->age, person_p->height);
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
//1.初始化 ROS 节点
ros::init(argc,argv,"listener_person");
//2.创建 ROS 句柄
ros::NodeHandle nh;
//3.创建订阅对象
ros::Subscriber sub = nh.subscribe<demo02_talker_listener::Person>("chatter_person",10,doPerson);
//4.回调函数中处理 person
//5.ros::spin();
ros::spin();
return 0;
}
5.结果
实操1:编码实现乌龟运动控制,让小乌龟做圆周运动
分析:
- 乌龟运动控制实现,关键节点有两个,一个是乌龟运动显示节点 turtlesim_node,另一个是控制节点,二者是订阅发布模式实现通信的,乌龟运动显示节点直接调用即可,运动控制节点之前是使用的 turtle_teleop_key通过键盘 控制,现在需要自定义控制节点。
- 控制节点自实现时,首先需要了解控制节点与显示节点通信使用的话题与消息,可以使用ros命令结合计算图来获取。
1.话题获取
rostopic list获取所有话题
查看计算图
获取话题:/turtle1/cmd_vel
获取消息格式
2.实现发布节点
#include "ros/ros.h"
#include "geometry_msgs/Twist.h"
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
// 2.初始化 ROS 节点
ros::init(argc,argv,"control");
ros::NodeHandle nh;
// 3.创建发布者对象
ros::Publisher pub = nh.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel",1000);
// 4.循环发布运动控制消息
//4-1.组织消息
geometry_msgs::Twist msg;
msg.linear.x = 1.0;
msg.linear.y = 0.0;
msg.linear.z = 0.0;//线速度
msg.angular.x = 0.0;
msg.angular.y = 0.0;
msg.angular.z = 2.0;//角速度
//4-2.设置发送频率
ros::Rate r(10);
//4-3.循环发送
while (ros::ok())
{
pub.publish(msg);
ros::spinOnce();
}
return 0;
}
3.结果
实操2:已知turtlesim中的乌龟显示节点,会发布当前乌龟的位姿(窗体中乌龟的坐标以及朝向),要求控制乌龟运动,并时时打印当前乌龟的位姿。
实现分析:
- 首先,需要启动乌龟显示以及运动控制节点并控制乌龟运动。
- 要通过ROS命令,来获取乌龟位姿发布的话题以及消息。
- 编写订阅节点,订阅并打印乌龟的位姿。
1.话题获取
2.实现订阅结点
#include "ros/ros.h"
#include "turtlesim/Pose.h"
void doPose(const turtlesim::Pose::ConstPtr& p){
ROS_INFO("乌龟位姿信息:x=%.2f,y=%.2f,theta=%.2f,lv=%.2f,av=%.2f",
p->x,p->y,p->theta,p->linear_velocity,p->angular_velocity
);
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
// 2.初始化 ROS 节点
ros::init(argc,argv,"sub_pose");
// 3.创建 ROS 句柄
ros::NodeHandle nh;
// 4.创建订阅者对象
ros::Subscriber sub = nh.subscribe<turtlesim::Pose>("/turtle1/pose",1000,doPose);
// 5.回调函数处理订阅的数据
// 6.spin
ros::spin();
return 0;
}