当前位置:   article > 正文

ROS自动驾驶学习--ROS话题通讯_ros自动驾驶 小车 订阅 发布 话题

ros自动驾驶 小车 订阅 发布 话题

提示:一定要在工作空间中的src目录下,创建一个功能包,依赖是roscpp rospy std_msgs,然后在生成的功能包中的src文件夹下创建本文中的代码,代码创建后需要修改Cmakelist.txt文件后方可正常运行.


前言

这篇内容主要是介绍一下ROS通讯方式中最常用的一种:话题通信.然后通过一个示例来巩固学习效果,最后做一个进阶,订阅ROS下小乌龟的位置信息,并在终端中显示出来.


提示:以下是本篇文章正文内容,下面案例可供参考

一、话题通信是什么?

个人理解是 :

  1. 有节点在master上注册并发布消息
  2. 另外节点也在master上注册,并订阅想要得到的节点消息
  3. 订阅节点和发布节点布局限于是一对一,可以一对多
  4. 原理图如下:
    在这里插入图片描述
    原理图解释:(解释中的标号不代表原理图中的标号)
    1 发布者和订阅者使用RPC通信在master中注册信息;
    2 master匹配发布者和订阅者的注册信息,然后将对应的发布者RPC端口号发送给订阅者;
    3 订阅者通过RPC端口号连接发布者,然后发布者将TCP的端口号发布给订阅者;
    4 订阅者使用TCP通信连接发布者;
    5 订阅者和发布者通过TCP通信,进行数据交互;
    6 当发布者和订阅者建立了连接以后,即使master关闭,两者依然可以通信.

二、代码示例

1.创建一个发布者

创建发布者的架构如下:

  1. 包含对应的头文件;
  2. 初始化节点;
  3. 创建节点句柄;
  4. 使用advertise创建要发布的话题,并设置话题类型,名称,缓.存数;
  5. 创建被发布的消息类型
  6. 设置话题数据发布频率;
  7. 创建话题发布循环;
  8. 发布消息;
  9. 在话题发布循环中添加rate.sleep();
    代码如下(示例):
#include "ros/ros.h"
#include"std_msgs/String.h"
#include<sstream>
/* 
    发布方实现:
    1 包含头文件
    2.初始化ROS节点
    3.创建节点句柄
    4.创建发布对象
    5.编写发布逻辑并发布数据
    code */

int main(int argc, char *argv[])
{
    //初始化节点
    ros::init(argc,argv,"pub_node");

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

    //创建发布者对象  advertise语句格式 <消息类型>("话题",缓存数量(缓存机制,先进显出,超过后最先进得被删除))
    ros::Publisher pub=nh.advertise<std_msgs::String>("pub_topic",10);

    //编写发布逻辑并发布消息
    //先创建被发布的消息
    std_msgs::String msg;
    
    //设置发布数据频率 10hz,并在消息后添加编号,
    //添加计数器
    int count;
    ros::Rate rate(10);
    ros::Duration(3.0).sleep(); //休眠延迟消息发布
//编写循环,循环发布消息数据
    while (ros::ok())
    {
        setlocale(LC_ALL,"");
        count++;
        //实现字符串与编号拼接
        std::stringstream ss; //创建一个ss对象
        ss <<"hello ---->"<<count;

        msg.data=ss.str();
        pub.publish(msg);
        //在终端中添加发布日志
        ROS_INFO("发布的数据是:%s",ss.str().c_str());

        rate.sleep();
        
    }
    
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

完成代码后,修改功能包中的Cmakelist.txt代码,修改的第一个位置是在# add_executable(${PROJECT_NAME}_node src/com_test_pub_node.cpp)后面添加

add_executable(pub src/pub.cpp)
  • 1

这里面的pub是编译好的项目名,后面的pub.cpp是写的发布者程序名.
修改的第二个位置是:在
#target_link_libraries(${PROJECT_NAME}_node #${catkin_LIBRARIES} #)
后面添加

 target_link_libraries(pub 
   ${catkin_LIBRARIES}
 )
  • 1
  • 2
  • 3

然后保存Cmakelist.txt文件,返回工作空间,编译之后,在工作空间中输入

source ./devel/setup.bash
rosrun com_test_pub pub
  • 1
  • 2

这里的com_test_pub是创建的功能包,pub是创建的发布者项目名
即可看到如下
运行效果:
在这里插入图片描述

2.创建一个订阅者

订阅者的架构与发布者架构相似:
1.包含头文件
2. 初始化ROS节点
3. 创建ROS句柄
4. 创建订阅者话题
5. 处理订阅到的话题中的数据
6. 创建一个spin()函数
7.
订阅者代码如下(示例):

#include"ros/ros.h"
#include"std_msgs/String.h"
/*
1 包含头文件
2 初始化ROS节点
3 创建节点句柄
4 创建订阅者对象
5 订阅数据处理
6 声明一个spin函数
*/
void doMsg(const std_msgs::String::ConstPtr &msg){
    //通过msg参数获取并操作订阅到的数据
    setlocale(LC_ALL,"");
    ROS_INFO("订阅的数据:%s",msg->data.c_str());

}

int main(int argc, char *argv[])
{
    //初始化ROS节点
    ros::init(argc,argv,"listen");
    
    // 创建ROS 句柄
    ros::NodeHandle nh;

    //创建订阅者对象 使用subscribe句式进行话题订阅(需要订阅的话题名称,缓存数两,回调函数(处理接收到的话题数据))
    ros::Subscriber listen= nh.subscribe("pub_topic",10,doMsg);//

    ros::spin(); //语句执行完之后回头一下 处理回调函数

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

同样,订阅者创建完以后,也要在Cmakelist.txt文件中的对应位置添加:(可以写在发布者的add_executable和target_link_libraries的后面)

add_executable(listen src/listen.cpp)


 target_link_libraries(listen 
 ${catkin_LIBRARIES}
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

然后保存Cmakelist.txt文件,返回工作空间,编译之后,在工作空间中输入

source ./devel/setup.bash
rosrun com_test_pub pub
  • 1
  • 2

在新开一个终端进入同一个工作空间中输入

source ./devel/setup.bash
rosrun com_test_pub listen 
  • 1
  • 2

这里的com_test_pub是创建的功能包,listen是创建的订阅者项目名
即可看到如下
运行效果:
在这里插入图片描述

注意

注意:
先启动订阅者,在启动发布者,这时订阅者终端在接受数据时,可能会出现前几条数据接受不到原因是发布者已经发布出来了数据,但是这时候还没有在master里面注册成功,所以订阅者收不到前几条消息.
解决方法是:在发布者里面加入休眠
注册后,加入休眠 ros::Duration(3.0).sleep(); 延迟第一条数据的发送

进阶

然后进阶一下,订阅一个小乌龟的位置节点,并在终端中显示位置节点中的数据,废话不多说,上代码:

#include "ros/ros.h"
#include"std_msgs/String.h"
#include"turtlesim/Pose.h"

void doMsg(const turtlesim::PoseConstPtr &Msg){
    float x,y,theta,line_ve;
    x=Msg->x;
    y=Msg->y;
    theta=Msg->theta;
    line_ve=Msg->linear_velocity;
    ROS_INFO("I heard pose x:[%f] y:[%f] theta:[%f] ve:[%f]",x, y, theta, line_ve);

}

int main(int argc, char *argv[])
{
    //初始化节点 定义turtle_pos为设置订阅的节点名
    ros::init(argc,argv,"turtle_pos");

    //创建ROS句柄
    ros::NodeHandle nh;
    
    //创建订阅话题
    ros::Subscriber pos = nh.subscribe("turtle1/pose",100,doMsg);
    ros::spin();
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

同样,也要在Cmakelist.txt文件中的对应位置添加:(可以写在发布者的add_executable和target_link_libraries的后面)

add_executable(turtlesimPos src/turtlesim_pos_lis.cpp)


target_link_libraries(turtlesimPos 
${catkin_LIBRARIES}
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

然后编译工作空间,在终端中输入

source ./devel/setup.bash
  • 1

接下来的操作步骤:

  1. 启动roscore ,在终端中输入 roscore
  2. 新开一个终端,或者使用ctrl+shift+T,打开一个新终端,启动小乌龟节点,在终端中输入rosrun turtlesim turtlesim_node
  3. 同样的方法,在新开一个终端启动键盘控制节点rosrun turtlesim turtle_teleop_key,这个时候可以用键盘控制小乌龟了,
  4. 开启一个新终端中,输入
rosrun com_test_pub turtlesimPos 
  • 1

就可以在终端中看到下图
在这里插入图片描述
至此,ROS的话题通讯已经完成,可以订阅想要的到的话题数据了.

代码下载连接

此文中的代码已经上传,可以直接通过传送门下载:传送门

<- - - 如有侵权,请联系删除- - ->

<每天进步一点点>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/642806
推荐阅读
相关标签
  

闽ICP备14008679号