ros话题通讯机制以及自定义消息编程

一、话题通讯机制简介

    ros的核心就是分布式通讯机制,ros的所有软件和工具都是基于这种分布式通讯机制之上的,话题通讯是ros的三大核心通讯机制之一,也是最为复杂,最为频繁的通讯模式,其模型如下图所示:

首先关注图中的三个角色:

1)、Talker:话题发布者,通过1234端口使用RPC协议向Ros Master注册发布者信息,包括话题名,RPC地址。该角色中包含了两个内容,一个是RPC通讯地址,用于注册到Ros Master当中,二是TCP通讯地址,用于后续跟Listener进行通讯传递消息数据。

2)、Listener:话题订阅者,上电后通过RPC向Ros Master注册要订阅的话题,订阅成功(即有Talker注册了Listener要订阅的话题)后方可接受Talker的消息。

3)、Ros Master:这可是Ros的核心组件了,管理了所有Talker和Listern,它们通讯前都要把自己的地址、发布或订阅的话题注册到Ros Master当中,当发布的话题和订阅的话题能够匹配到时,才能让二者进行连接。

可以说Ros Master作为Talker和Listener这两个角色通讯前的中介,当二者“对上眼”之后,Ros Master进程退出也不会影响二者的通讯,毕竟Listener都知道了Talker的TCP通讯地址了,但是,其他节点的Listener也无法订阅该话题。

这是一种多对多的异步通讯机制,就好像一个微信群里面,任何一个任务发布了一条消息,里面的人都能够看到,这种机制适合于高频的数据发布和接收:雷达探测、里程计等。

二、自定义消息

 1、创建工作空间

#创建工作空间ros_wc
mkdir -p ~/catkin_ros/src
cd ~/catkin_ros/src
#初始化工作空间
catkin_init_workspace
cd ..
#编译
catkin_make
#添加环境变量
source devel/setup.bash

  2、创建功能包

cd ~/catkin_ros/src
#创建功能包TopicTest,后续跟该功能包的依赖包
catkin_create_pkg learning_topic roscpp rospy std_msgs 
cd ..
#编译功能包
catkin_make

  3、功能包添加自定义消息文件

cd ~/catkin_ros/
#创建话题消息文件夹,必须名为msg
mkdir msg; cd msg
#编译话题文件 
vim Person.msg

在Person.msg文件中加入

string name
uint8  sex
uint8 age

uint8 unkown = 0
uint8 male = 1
uint8 femal = 2

Person.msg定义了自定义消息结构体,包含了三个未初始化变量name、sex、age,用于后续传递消息,以及三个初始化变量,作为sex变量的值,此处类似于c中的宏定义。uint8为8bit整型,string为字符串类型。

4、配置编译

打开功能包的package.xml,添加如下编译和运行的相关依赖项

 <exec_depend> message_runtime</exec_depend>
 <build_depend>message_generation</build_depend>

打开功能包的CMakeList.txt,在find_package()中添加消息生生依赖的功能包message_generation,这样在编译时才能找到所需的文件。

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)

同样的catkin依赖项也要设置

catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES learning_topic
CATKIN_DEPENDS roscpp rospy std_msgs  message_runtime
#  DEPENDS system_lib
)

配置消息生生器

add_message_files(
  FILES
  Person.msg
)

调用消息生成

 generate_messages(
    DEPENDENCIES
    std_msgs
 )

5、编译并查看消息

cd ~/catkin_ws/
catkin_make
rosmsg show Person

[learning_topic/Person]:
uint8 unkonw=0
uint8 male=1
uint8 female=2
string name
uint8 sex
uint8 age

三、基于自定义消息的c++话题编程

1、创建publisher,在功能包learning_topic的src下创建talker.cpp,内容如下

#include <stdio.h>
#include "ros/ros.h"
#include "std_msgs/String.h"
#include "learning_topic/Person.h"  //自定义消息类型的头文件
using namespace ros;

int main(int argc, char *argv[])
{
    //定义Person对象
    learning_topic::Person p;

    //初始化ros节点
    init(argc, argv, "talker");

    //创建节点句柄
    ros::NodeHandle nh;

   //创建一个消息发布者,发布名为chatter的topic,消息类型为learning_topic::Person
    ros::Publisher pub = nh.advertise<learning_topic::Person>("chatter", 1000);
    
    //设置循环频率为10HZ
    ros::Rate loopRate(10);

    int dwCnt = 0;
    //进入循环,存在异常时ros::ok()返回false,异常包括:1、SIGINT信号;2、被另一个同名节点踢掉线;3、调用ros::shutdown;4、ros::NodeHandles句柄销毁
    while (ros::ok())
    {
        //填充自定义消息Person
        char acBuf[100];
        sprintf(acBuf, "name %d", dwCnt++);
        p.name = acBuf;
        p.age = dwCnt;
        p.sex = p.male;
        // 打印,类似于printf
        ROS_INFO("%s", p.name.c_str());
        
        //发布消息
        pub.publish(p);
     
        //循环等待回调函数,虽然目前是发布者,没有订阅消息,也就是说spinOnce不是必须的,但是为了保证功能完整性,一般建议加上
        ros::spinOnce();

        //休眠,休眠时长就是前面设置的10HZ
        loopRate.sleep();
    }
    
    return 0;
}

2、创建Subscribe,订阅publish的消息,在功能包leaning_topic的src下创建listerner.cpp:

#include "ros/ros.h"
#include "std_msgs/String.h"
#include "learning_topic/Person.h"

void chatterCallBack(const learning_topic::Person::ConstPtr& msg)
{
    //将接收的消息打印出来
    ROS_INFO("i heard: [name:%s, age:%d, sex:%d]", msg->name.c_str(), msg->age, msg->sex);
}


int main(int argc, char *argv[])
{
    //定义Person对象
    learning_topic::Person p;

    //初始化ros节点
    ros::init(argc, argv, "listener");

    //创建节点句柄
    ros::NodeHandle nh;
    
    //创建Subscribe,订阅名为chatter的话题,注册回调函数chatterCallBack
    ros::Subscriber sub = nh.subscribe("chatter", 100, chatterCallBack);

    //循环等待消息回调
    ros::spin();
    return 0;
}

3、修改编译脚本并编译:打开功能包中的CMakeLists.txt文件,在末尾添加如下编译项

#设置头文件的相对路径。全局默认路径是功能包所在目录,比如功能包的头文件一般放置到功能包根目录下 的include文件夹,所以此处需添加该文件夹,这是一般的操作规范,即使本程序在include下并没有什么相关内容。此外,ros内置的${catkin_INCLUDE_DIRS}包含了ros catkin编译器默认包含安装路径、Linux系统路径下的头文件路径。
include_directories(include ${catkin_INCLUDE_DIRS})

#设置生成的可执行文件,以及对应的源码文件,如果有多个源文件用空格分隔。此处设置了生成talker
add_executable(talker src/talker.cpp)
#设置可执行文件依赖的动态库,此处talker使用默认连接库${catkin_LIBRARIES}
target_link_libraries(talker ${catkin_LIBRARIES})
#设置依赖项。当我们需要定义语言无关的消息类型时,消息类型会在编译过程中产生语言的代码,如果可执行文件依赖于这些动态代码,需要添加此项。
add_dependencies(talker ${PROJECT_NAME}_generate_message_cpp)

#设置生成listerner
add_executable(listerner src/listerner.cpp)
target_link_libraries(listerner ${catkin_LIBRARIES})
add_dependencies(listerner ${PROJECT_NAME}_generate_message_cpp)

在~/catkin_ws执行catkin_make,编译无误会在~/catki5、n_ws/devel/lib/leaning_topic/下生成talker和listerner。

5、运行publisher和Subscribe:

1)、启动roscore,执行:

roscore

2)、启动publisher(publisher和Subscribe节点的启动顺序没有要求):

lsm@lsm-Aspire-E5-472G:~/catkin_ws$ rosrun learning_topic talker
[ INFO] [1558112091.960899493]: name 0
[ INFO] [1558112092.060915997]: name 1
[ INFO] [1558112092.160923816]: name 2
[ INFO] [1558112092.260913136]: name 3
[ INFO] [1558112092.360919062]: name 4
[ INFO] [1558112092.460912128]: name 5

3)、启动Subscribe:

lsm@lsm-Aspire-E5-472G:~/catkin_ws$ rosrun learning_topic listerner
[ INFO] [1558112244.636315626]: i heard: [name:name 34, age:35, sex:1]
[ INFO] [1558112244.736236803]: i heard: [name:name 35, age:36, sex:1]
[ INFO] [1558112244.836169060]: i heard: [name:name 36, age:37, sex:1]
[ INFO] [1558112244.936199924]: i heard: [name:name 37, age:38, sex:1]
[ INFO] [1558112245.036216563]: i heard: [name:name 38, age:39, sex:1]
[ INFO] [1558112245.136180517]: i heard: [name:name 39, age:40, sex:1]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值