ROS入门之---话题通信(简单C++实现)

参考资料:Autolabor初级教程,ROS机器人入门: https://www.bilibili.com/video/BV1Ci4y1L7ZZ?p=20&vd_source=b60677c9a8c83865444e5fa3b9d545c4

vscode下载链接: https://code.visualstudio.com/docs?start=true

vscode历史版本下载链接:https://code.visualstudio.com/updates

vscode安装方式:双击安装即可,或右键选择安装。

一、vscode基本配置

1. 创建ROS工作空间并初始化

假如我的自定义空间名称为demo01,想用别的名称将demo01做替换即可。

mkdir -p demo01/src    //(必须得有src)创建一个工作空间以及一个src子目录
cd demo01              //进入demo01这个文件夹(工作空间)中
catkin_make            //调用catkin_make这个命令进行编译

2. 启动vscode

cd demo01_ws
code .

3. vscode中编译ros

快捷键CTRL+shift+B 后,出现如下界面:
ROS入门之---话题通信(简单C++实现)_第1张图片
选择:catkin_make:build后边那个齿轮,进行设置,修改.vscode/tasks.json 文件。将以下代码直接复制粘贴并全部替换即可。

{
// 有关 tasks.json 格式的文档,请参见
    // https://go.microsoft.com/fwlink/?LinkId=733558
    "version": "2.0.0",
    "tasks": [
        {
            "label": "catkin_make:debug", //代表提示的描述性信息
            "type": "shell",  //可以选择shell或者process,如果是shell代码是在shell里面运行一个命令,如果是process代表作为一个进程来运行
            "command": "catkin_make",//这个是我们需要运行的命令
            "args": [],//如果需要在命令后面加一些后缀,可以写在这里,比如-DCATKIN_WHITELIST_PACKAGES=“pac1;pac2”
            "group": {"kind":"build","isDefault":true},
            "presentation": {
                "reveal": "always"//可选always或者silence,代表是否输出信息
            },
            "problemMatcher": "$msCompile"
        }
    ]
}

4. 创建ROS功能包

(1)选定src,右键—>createcatkin package ,并设置包名,添加依赖。如下图:

ROS入门之---话题通信(简单C++实现)_第2张图片

(2)输入包名:我这里输入了pub_sub,如下图:

ROS入门之---话题通信(简单C++实现)_第3张图片

(3)输入依赖:roscpp rospy std_msgs,如下图:

ROS入门之---话题通信(简单C++实现)_第4张图片
在工作空间下生成一个功能包,该功能包依赖于 roscpp、rospy 与 std_msgs,其中roscpp是使用C++实现的库,而rospy则是使用python实现的库,std_msgs是标准消息库,创建ROS功能包时,一般都会依赖这三个库实现。

注意:如果在src下创建功能包时,点回车手太快,忘记添加roscpp rospy std_msgs这三个依赖,直接右键该功能包选择删除即可。
ROS入门之---话题通信(简单C++实现)_第5张图片

二、话题通信基本概念

话题通信是ROS中使用频率最高的一种通信模式,话题通信是基于发布订阅模式的,也即:一个节点发布消息,另一个节点订阅该消息。

话题通信的应用场景也极其广泛,比如下面一个常见场景:

机器人在执行导航功能,使用的传感器是激光雷达,机器人会采集激光雷达感知到的信息并计算,然后生成运动控制信息驱动机器人底盘运动。

在上述场景中,就不止一次使用到了话题通信。

以激光雷达信息的采集处理为例,在 ROS 中有一个节点需要时时的发布当前雷达采集到的数据,导航模块中也有节点会订阅并解析雷达数据。

再以运动消息的发布为例,导航模块会根据传感器采集的数据时时的计算出运动控制信息并发布给底盘,底盘也可以有一个节点订阅运动信息并最终转换成控制电机的脉冲信号。

以此类推,像雷达、摄像头、GPS… 等等一些传感器数据的采集,也都是使用了话题通信,换言之,话题通信适用于不断更新的数据传输相关的应用场景。

需求:

实现最基本的发布订阅模型,发布方以固定频率发送一段文本,订阅方接收文本并输出。

编写发布订阅实现,要求发布方以10hz(每秒10次)的频率发布文本消息,订阅方订阅消息并将消息内容打印输出。

三、话题通信简单案例实现—发布方(C++)

步骤1:

右键工作空间(demo01_ws)下的src下的功能包(pub_sub)下的src,选择新建文件,新建文件的名称为:pub_c.cpp 然后回车。

ROS入门之---话题通信(简单C++实现)_第6张图片

步骤2:pub_c.cpp文件内容:

实现流程:
1.包含头文件
2.初始化 ROS 节点:命名(唯一)
3.实例化 ROS 句柄
4.实例化 发布者 对象
5.组织被发布的数据,并编写逻辑发布数据

//1. 包含头文件
#include "ros/ros.h"
#include  "std_msgs/String.h"   //普通文本类型的消息
#include 

int main(int argc, char  *argv[])
{
//2. 初始化ROS节点
    ros::init(argc,argv,"talker");  //talker为此发布方的节点的名称
//3. 实例化ROS句柄
    ros::NodeHandle nh; //该类封装了ROS中的一些常用功能
//4. 实例化发布者对象pub(也可以不是pub,p也可以,都是自定义的)
    ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",10); //<发布的消息类型>("要发布的话题名称为chatter",队列中最大保存的消息数为10,超出此阈值时,先进的先销毁)
//5. 动态组织被发布的数据msg
    std_msgs::String msg;
    ros::Rate rate(1);  //发布的频率为10,一秒10次。这里我改为1秒1次了,好观察。
    int count =0; //消息计数器
    ros::Duration(3).sleep();  //为了防止数据的丢失,会先延迟几秒钟,以免消息都发布出去了,节点在ROS master还没注册完,导致订阅方有可能会丢失前几个数据。
    while (ros::ok()) //只要节点不死
    {
       
        std::stringstream ss;  //使用stringstream拼接字符串与数字编号
        ss<< "hello--->"<<count;  //字符串为hello---> 数字编号为count,count后边会执行一次加1,编号数值依次递增
        msg.data=ss.str(); //将拼接好的字符串赋值给消息的data
        pub.publish(msg); //发布消息
        ROS_INFO("the message is:%s",msg.data.c_str());//日志输出发送的消息。
        rate.sleep(); //根据前面设置的发送频率自动休眠 休眠时间等于1/频率
         count++; //循环结束前,count自增
         ros::spinOnce(); //ros官方推荐加上这一行回头函数
    }

步骤3:配置CMakeLists.txt(注意是配置哪一个CMakeLists.txt),应该配置功能包pub_sub下的src下面的CMakeLists.txt

ROS入门之---话题通信(简单C++实现)_第7张图片

(配置1:)找到add_executable这里,修改括号里面的内容如下图。其中,src前面那个是自定义的可执行文件的名称,一般与后边的pub_c.cpp名称一致。

add_executable(pub_c
  src/pub_c.cpp
)

(配置2:)只需要改一个pub_c

target_link_libraries(pub_c
  ${catkin_LIBRARIES}
)

四、话题通信简单案例实现—订阅方(C++)

步骤1:与发布方步骤1类似。

右键工作空间(demo01_ws)下的src下的功能包(pub_sub)下的src,选择新建文件,新建文件的名称为:sub_c.cpp 然后回车。

步骤2:sub_c.cpp文件内容:

实现流程:
1.包含头文件
2.初始化 ROS 节点:命名(唯一)
3.实例化 ROS 句柄
4.实例化 订阅者 对象
5.处理订阅的消息(回调函数)
6.设置循环调用回调函数

//1. 包含头文件
#include "ros/ros.h"
#include "std_msgs/String.h"

//回调函数doMsg()的实现,进行一个日志的输出,简单调试一下。
 void doMsg(const std_msgs::String::ConstPtr& msg){
        ROS_INFO("the sub is: %s",msg->data.c_str());

    }
    
int main(int argc, char *argv[])
{

//2. 初始化ROS节点,节点名称为listener
    ros::init(argc,argv,"listener");

//3. 实例化ROS句柄
    ros::NodeHandle nh;

//4. 实例化订阅者对象sub(也可以不是sub,s也可以,都是自定义的)
    ros::Subscriber sub = nh.subscribe("chatter",10,doMsg);

//5. 处理订阅的消息:回调函数的实现见上。

//6. 循环调用回调函数
   ros::spin(); //循环读取接收的数据,并调用回调函数处理
    return 0;
}

步骤3:配置CMakeLists.txt(注意是配置哪一个CMakeLists.txt),应该配置功能包pub_sub下的src下面的CMakeLists.txt

(配置1:)找到add_executable这里,修改括号里面的内容如下图。其中,src前面那个是自定义的可执行文件的名称,一般与后边的sub_c.cpp名称一致。

add_executable(sub_c
  src/sub_c.cpp
)

(配置2:)只需要改一个sub_c

target_link_libraries(sub_c
  ${catkin_LIBRARIES}
)

五、编译+执行

1. 编译:

方式1:
可采用在工作空间(demo01_ws)下打开终端:catkin_make

方式2:
也可以直接在vscode里面Ctrl+shift+B进行编译。编译通过100%且没有报错后。

ROS入门之---话题通信(简单C++实现)_第8张图片

2. 执行:

(1)打开终端1(快捷键是CTRL+ALT+T)启动roscore

roscore

ROS入门之---话题通信(简单C++实现)_第9张图片

(2)另外打开一个终端2,先启动订阅节点

cd demo01_ws
source ./devel/setup.bash
rosrun pub_sub sub_c

ROS入门之---话题通信(简单C++实现)_第10张图片

(3)再另外打开一个终端3,启动发布节点

cd demo01_ws
source ./devel/setup.bash
rosrun pub_sub pub_c

执行到15 时,我按下了Ctrl+C,停止了消息的发布和订阅。

ROS入门之---话题通信(简单C++实现)_第11张图片

六、关于第五点source比较繁琐的说明

第五点中,我分别启动了三个终端,第一个终端用来启动ROS Master,第二个终端用来运行订阅方,第三个终端用来运行发布方。但是在第二个终端和第三个终端,我都source了环境变量。执行以下操作后,可省去这一行,直接进入demo01_ws工作空间后,即可运行rosrun XXXXX

操作如下:
进入主目录下,Ctrl+H找到隐藏文件.bashrc,双击进入这个文件后,

ROS入门之---话题通信(简单C++实现)_第12张图片
在最后一行添加:source ~/demo01_ws/devel/setup.bash
保存后关闭

ROS入门之---话题通信(简单C++实现)_第13张图片
打开任意终端,输入:source .bashrc
然后就可直接在工作空间下运行rosrun XXXX 了。
不用每次都source以下再rosrun了。

ROS入门之---话题通信(简单C++实现)_第14张图片

你可能感兴趣的:(ROS机器人操作系统,c++)