问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

ROS话题通信详细讲解:从概念到实战案例

创作时间:
作者:
@小白创作中心

ROS话题通信详细讲解:从概念到实战案例

引用
CSDN
1.
https://blog.csdn.net/saojiakre/article/details/145529787

ROS话题通信是ROS使用最多的通信模式,通常用于数据的传输。本文将详细介绍ROS话题通信的概念、实现原理以及具体的案例实现。通过C++和Python两种编程语言,我们将展示如何实现发布者和订阅者,并提供完整的代码示例和详细的步骤说明。

数据类型

在讲解ROS话题通信之前,有必要了解与ROS配套的数据类型包std_msgs中包含的类型:

  • 整型:int8,int16,int32,int64(有int就有无符号整型uint,可以完全替代)
  • 浮点型:float32,float64
  • 其他类型:string,time,duration

此外,还可以自定义数据类型,但本文暂不涉及。

话题通信

话题通信是ROS使用最多的通信模式,通常用于数据的传输。

概念

话题通信基于发布订阅模式,由四个部分组成:

  • 发布方:负责在特定的话题中发布数据
  • 订阅方:负责从特定的话题中获取数据
  • 管理者:ROS内置,负责将发布者和订阅者建立连接
  • 话题:可以是一件事或一个主题,当发布者和订阅者有共同话题时,就可以建立连接

实现原理

下图展示了ROS话题通信的实现原理:

  1. 发布方将话题和RPC地址发布给管理者
  2. 订阅方将需要的话题发布给管理者,如果管理者有对应的话题,将把发布方信息(RPC地址)传给订阅方
  3. 订阅方与发布方连接,发布方将TCP地址给订阅方
  4. 发布方发布的数据订阅方可以接收

案例实现

案例要求

编写代码实现ROS中消息的发布与订阅:

  • 创建一个发布者,每隔100ms依次发送斐波那契数列的数字到话题/fibonacci
  • 创建一个订阅者,订阅该话题并输出订阅结果

实操步骤

建立工作空间
  1. 在终端中输入以下命令,建立demo02_ws文件夹和该文件夹下的src文件夹:

    mkdir -p demo02_ws/src
    
  2. 进入demo02_ws文件夹:

    cd demo02_ws
    
  3. demo02_ws中建立工作空间:

    catkin_make
    
  4. 打开VSCode:

    code .
    
  5. src文件夹中创建新的Catkin包,输入功能包名字,并提供依赖:

    roscpp rospy std_msgs
    
  6. 修改VSCode的配置文件(如果在集成环境中实现可以跳过):

    {
        "version": "2.0.0",
        "tasks": [
            {
                "label": "catkin_make:debug",
                "type": "shell",
                "command": "catkin_make",
                "args": [],
                "group": {"kind": "build", "isDefault": true},
                "presentation": {
                    "reveal": "always"
                },
                "problemMatcher": "$msCompile"
            }
        ]
    }
    

    Ctrl+s保存。

C++实现
  1. 修改配置文件(在C++编写中,如果不修改可能没有提示),主要修改"cStandard"和"cppStandard":

    {
        "cStandard": "gnu11",
        "cppStandard": "c++11"
    }
    
  2. 建立发布者实现文件:

    #include "ros/ros.h"
    #include "std_msgs/Int32.h"
    
    int main(int argc, char *argv[])
    {
        // 初始化ROS节点
        ros::init(argc, argv, "pub01");
        // 建立节点句柄
        ros::NodeHandle nh;
        // 建立发布者对象
        ros::Publisher pub = nh.advertise<std_msgs::Int32>("fibonacci", 10);
        // 设置发布频率
        ros::Rate rate(10);
        // 创建被发布的数据消息
        std_msgs::Int32 msg;
        // 初始化num1和num2
        int num1 = 0;
        int num2 = 1;
        // 优化操作:休眠,等待发布方在管理者那里注册完毕,避免丢失信息
        ros::Duration(2).sleep();
        // 建立循环
        while (ros::ok())
        {
            // 生成斐波那契数列
            int tmp = num2;
            num2 += num1;
            num1 = tmp;
            // 将生成的整形存入msg中
            msg.data = num1;
            // 发布数据
            pub.publish(msg);
            // 休眠使频率生效
            rate.sleep();
            // 官方建议添加,处理回调函数
            ros::spinOnce();
        }
        return 0;
    }
    
  3. 建立订阅者实现文件:

    #include "ros/ros.h"
    #include "std_msgs/Int32.h"
    
    // 回调函数——用于处理订阅到的数据
    void doMsg(const std_msgs::Int32::ConstPtr &msg)
    {
        std::cout << msg->data << std::endl;
    }
    
    int main(int argc, char *argv[])
    {
        // 初始化ROS节点
        ros::init(argc, argv, "sub01");
        // 创建节点句柄
        ros::NodeHandle nh;
        // 创建订阅者对象
        ros::Subscriber sub = nh.subscribe("fibonacci", 10, doMsg);
        // spin()函数回旋
        ros::spin();
        return 0;
    }
    
  4. 编译与运行:

  • 修改CMakeLists.txt文件:

    add_executable(pub01 src/pub01.cpp)
    add_executable(sub01 src/sub01.cpp)
    target_link_libraries(pub01 ${catkin_LIBRARIES})
    target_link_libraries(sub01 ${catkin_LIBRARIES})
    
  • 启动ROS核心:

    roscore
    
  • 刷新环境变量:

    source ./devel/setup.bash
    
  • 运行订阅方:

    rosrun test1_pub_sub sub01
    
  • 运行发布方:

    rosrun test1_pub_sub pub01
    
Python实现
  1. 创建文件夹:
  • test1_pub_sub文件夹中创建scripts文件夹
  • scripts文件夹中创建pub01.pysub01.py源文件
  1. 发布者实现:

    #! /usr/bin/env python
    import rospy
    from std_msgs.msg import Int32
    
    if __name__ == "__main__":
        # 初始化ROS节点
        rospy.init_node("pub01_p")
        # 建立发布者对象
        pub = rospy.Publisher("fibonacci", Int32, queue_size=10)
        # 建立数据消息变量
        msg = Int32()
        # 设置频率
        rate = rospy.Rate(10)
        # 优化操作:休眠2秒,等待发布方在管理者那里注册完毕
        rospy.sleep(2)
        # 初始化两个用于生成斐波那契数列的变量
        num1 = 0
        num2 = 1
        # 建立循环
        while not rospy.is_shutdown():
            tmp = num2
            num2 += num1
            num1 = tmp
            # 存储数据到消息变量中
            msg.data = num1
            # 发布数据
            pub.publish(msg)
            # 休眠保证循环的频率是rate设置的频率
            rate.sleep()
    
  2. 订阅者实现:

    #! /usr/bin/env python
    import rospy
    from std_msgs.msg import Int32
    
    # 编写回调函数
    def doMsg(msg):
        # 打印
        rospy.loginfo("%d", msg.data)
    
    if __name__ == "__main__":
        # 初始化ROS节点
        rospy.init_node("sub01_p")
        # 建立订阅者对象
        sub = rospy.Subscriber("fibonacci", Int32, doMsg, queue_size=10)
        # spin()函数回旋
        rospy.spin()
    
  3. 运行测试:

  • 添加可执行权限:

    chmod +x *.py
    
  • 修改CMakeLists.txt文件:

    catkin_install_python(PROGRAMS
      scripts/pub01.py
      scripts/sub01.py
      DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
    )
    
  • 启动ROS核心:

    roscore
    
  • 刷新环境变量:

    source ./devel/setup.bash
    
  • 先运行订阅方:

    rosrun test1_pub_sub sub01.py
    
  • 运行发布方:

    rosrun test1_pub_sub pub01.py
    
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号