ROS Topic in roscpp 通信(简介+实例+测试)

ROS Topic in roscpp 通信

  • topic 简介
  • topic demo 收发实列
    • 1、创建gps消息
    • 2、消息发布节点
    • 3、消息接收节点
    • 3、CMakeLists.txt文件修改
    • 4、编译运行
  • 操作命令
  • 实操遇到的问题汇总(关于ROS topic)
    • double类型数据不能创建

topic 简介

Topic是ROS里一种异步通信的模型,,一般是节点间分工明确,有的只负责发送,有的只负责 接收处理。对于绝大多数的机器人应用场景,比如传感器数据收发,速度控制指令的收发, Topic模型是最适合的通信方式。

ROS中的通信方式中,topic是常用的一种。对于实时性、周期性的消息,使用topic来传输是 最佳的选择。topic是一种点对点的单向通信方式,这里的“点”指的是node,也就是说node之 间可以通过topic方式来传递信息。topic要经历下面几步的初始化过程:首先,publisher节点 和subscriber节点都要到节点管理器进行注册,然后publisher会发布topic,subscriber在 master的指挥下会订阅该topic,从而建立起sub-pub之间的通信。注意整个过程是单向的。其 结构示意图如下:
ROS Topic in roscpp 通信(简介+实例+测试)_第1张图片
Subscriber接收消息会进行处理,一般这个过程叫做回调(Callback)。所谓回调就是提前定义 好了一个处理函数(写在代码中),当有消息来就会触发这个处理函数,函数会对消息进行 处理。
上图就是ROS的topic通信方式的流程示意图。topic通信属于一种异步的通信方式。

topic demo 收发实列

1、创建gps消息

在代码中,会用到自定义类型的gps消息,因此就需要来自定义gps消息,在msg路径下 创建 gps.msg。
ROS Topic in roscpp 通信(简介+实例+测试)_第2张图片

float32 x       #x坐标 
float32 y       #y坐标
string state  	#工作状态 

以上就定义了一个gps类型的消息,可以把它理解成一个C语言中的结构体,类似于

struct	gps
 {			
 	string	state;			
    float32	x;		
 	float32	y;
 }

在程序中对一个gps消息进行创建修改的方法和对结构体的操作一样。
当创建完了msg文件,记得修改 CMakeLists.txt和 package.xml,从而让系统能够编译自定义消息。在CMakeLists.txt中需要改动

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation    #generate new msg must add	#需要添加的地方 
)

add_message_files(FILES	gps.msg)	#catkin在cmake之上新增的命令,指定从哪个消息文件生成

generate_messages(DEPENDENCIES	std_msgs) #DEPENDENCIES后面指定生成msg需要依赖其他什么消息,由于gps.msg用到了flaot32这种ROS标准消息,因此需 要再把std_msgs作为依赖

package.xml 中需要的改动

  <build_depend>message_generationbuild_depend>     
  <exec_depend>message_runtimeexec_depend>          

当你完成了以上所有工作,就可以回到工作空间,然后编译了。编译完成之后会在 devel 路 径下生成 gps.msg 对应的头文件,头文件按照C++的语法规则定义了 topic_demo::gps 类型的 数据。
ROS Topic in roscpp 通信(简介+实例+测试)_第3张图片
要在代码中使用自定义消息类型,只要 #include ,然后声明,按照对结 构体操作的方式修改内容即可。

topic_demo::gps	mygpsmsg; 
 mygpsmsg.x	=	1.6;
 mygpsmsg.y	=	5.5; 
 mygpsmsg.state	=	"working";

2、消息发布节点

定义完了消息,开始写ROS代码。通常会把消息收发的两端分成两个节点来写,一个节点就是一个完整的C++程序。
在src下建立talker.cpp发送节点
ROS Topic in roscpp 通信(简介+实例+测试)_第4张图片
源码如下:

#include 
#include   //引入生成的消息类型

int main(int argc, char **argv)
{
  
   ros::init(argc,argv,"talker_jone");//用于解析ROS参数,第三个参数为本节点名  注意要与后面修改的Cmakelist.txt文件对应

   ros::NodeHandle nh ;	//实例化句柄,初始化node

   topic_demo_jone::gps msg;//自定义gps消息并初始化

   msg.x=1;
   msg.y=2;
   msg.state="working";


   ros::Publisher pub = nh.advertise<topic_demo_jone::gps>("gps_info",1);//创建publisher,往 "gps_info"话题上发布消息  gps_info就是topic的名称
   
   ros::Rate loop_rate(1);//定义发布的频率,1HZ

   while (ros::ok())	//循环发布msg
   {
     msg.x=msg.x*1.3;//处理msg
     msg.y=msg.y*1.1;//处理msg

     ROS_INFO("Talker_jone:GPS: x=%f , y=%f",msg.x,msg.y);//打印 要发布的信息
 
     pub.publish(msg); //发布消息

     loop_rate.sleep();//根据前面的定义的loop_rate,设置1s的暂停
   }
    return 0;
}

机器人上几乎所有的传感器,几乎都是按照固定频率发布消息这种通信方式来传输数据,只 是发布频率和数据类型的区别。

3、消息接收节点

源码如下

#include 
#include 
#include 

void gpsCallback(const topic_demo_jone::gps::ConstPtr &msg )
{
     std_msgs::Float32 distance;	//计算离原点(0,0)的距离
     distance.data=sqrt(pow(msg->x,2) + pow(msg->y,2));
     
     ROS_INFO( "Listener :Distance to origin = %f , state = %s"  ,distance.data,  msg->state.c_str() ); //打印计算的距离  和msg中的state            
}

int main(int argc, char ** argv)
{
    ros::init(argc, argv, "listener_jone");
    
    ros::NodeHandle nh ;

    ros::Subscriber sub = nh.subscribe("gps_info", 1, gpsCallback);	//设置回调函数gpsCallb ack

    ros::spin();//ros::spin()用于调用所有可触发的回调函数,将进入循环,不会返回,类似于在循环里反复 调用spinOnce()			//而ros::spinOnce()只会去触发一次

    return 0;
}

在topic接收方,有一个比较重要的概念,就是回调(CallBack),回调就是预先 给gps_info 话题传来的消息准备一个回调函数,你事先定义好回调函数的操作,计算到原点的距离。只有当有消息来时,回调函数才会被触发执行。具体去触发的命令就是ros::spin() ,它会反复的查看有没有消息来,如果有就会让回调函数去处理。
因此千万不要认为,只要指定了回调函数,系统就回去自动触发,你必须 ros::spin()或 者ros::spinOnce()才能真正使回调函数生效。

3、CMakeLists.txt文件修改

在 CMakeLists.txt 添加以下内容,生成可执行文件

add_executable(talker_jone src/talker.cpp )  	#生成可执行文件talker_jone  节点的名字
add_dependencies(talker_jone topic_demo_generate_messages_cpp)   #必须添加add_dependencies,否则找不到自定义的msg产生的头文件
target_link_libraries(talker_jone ${catkin_LIBRARIES})

add_executable(listener_jone src/listener.cpp )	  #生成可执行文件listener 
add_dependencies(listener_jone topic_demo_generate_messages_cpp)
target_link_libraries(listener_jone ${catkin_LIBRARIES})

4、编译运行

回到工作空间
运行指令 ,进行编译

catkin_make

之后运行ros

roscore

然后运行talker_jone 节点

rosrun topic_demo_jone talker_jone

然后运行listener_jone 节点

rosrun topic_demo_jone listener_jone

结果如下 x,y逐渐增大 不断向外发送
ROS Topic in roscpp 通信(简介+实例+测试)_第5张图片

操作命令

在实际应用中,应该熟悉topic的几种使用命令,列出各自的命令及其作 用。
命令 ————————作用
rostopic list 列出当前所有的topic
rostopic info topic_name 显示某个topic的属性信息
rostopic echo topic_name 显示某个topic的内容
rostopic pub topic_name … 向某个topic发布内容
rostopic bw topic_name 查看某个topic的带宽
rostopic hz topic_name 查看某个topic的频率
rostopic find topic_type 查找某个类型的topic
rostopic type topic_name 查看某个topic的类型(msg)

以刚写的例子进行测试

rostopic list

列出了当前运行的topic 看到了刚写的 gps_info
在这里插入图片描述

 rostopic info /gps_info

看到gps_info 的信息 发布者,订阅者
ROS Topic in roscpp 通信(简介+实例+测试)_第6张图片

rostopic echo /gps_info 

看到topic 的内容
ROS Topic in roscpp 通信(简介+实例+测试)_第7张图片

实操遇到的问题汇总(关于ROS topic)

double类型数据不能创建

你可能感兴趣的:(ros)