• [ROS](09)ROS通信 —— 话题(Topic)通信之msg


      文章只是个人学习过程中学习笔记,主要参考ROS教程1 2 3


    [ROS](01)创建ROS工作空间

    [ROS](02)创建&编译ROS软件包Package

    1、概述

      msg(消息)文件就是文本文件,用于描述ROS消息的字段。它们用于为不同编程语言编写的消息生成源代码。
      msg文件存放在软件包的msg目录下。

    2、msg结构和类型

      msg4文件就是简单的文本文件,每行都有一个字段类型和字段名称。它的结构为:
        fieldtype + fieldname

    2.1 类型

      可以使用的类型为:

    • int8, int16, int32, int64 (以及 uint*)
    • float32, float64
    • string
    • time, duration
    • 其他msg文件
    • variable-length array[] 和 fixed-length array[C]

    2.2 举例

    # 特殊的Header类型,它含有时间戳和ROS中广泛使用的坐标帧信息
    # 在msg文件的第一行经常可以看到Header header。
    std_msgs/Header header
    uint8	is_true
    uint32	height
    uint32	width
    string child_frame_id
    time	stamp
    geometry_msgs/PoseWithCovariance pose
    geometry_msgs/TwistWithCovariance twist
    uint8[]	data
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3、msg命令rosmsg

    rosmsg显示有关ROS消息类型的信息。

    命令功能
    rosmsg show显示消息的描述(详细信息)
    rosmsg inforosmsg show的别名,功能一样
    rosmsg list列出所有消息
    rosmsg md5显示md5加密的消息
    rosmsg package列出某个软件包(package)的消息
    rosmsg packages列出包含消息的软件包(packages)

    4、msg的用法

    4.1 创建msg

      还是在原来创建的软件包 beginner_tutorials 中定义一个新的消息。

    # 切换到软件包的目录路径
    roscd beginner_tutorials
    # 创建msg文件夹目录
    mkdir msg
    # 创建名为Num.msg的文件,并添加一个消息字段
    echo "int64 num" > msg/Num.msg
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.2 配置CMakeLists.txt

      1. 为已经存在里面的find_package调用添加message_generation依赖项(),这样就能生成消息了。(添加 message_generation 依赖项,必须有 std_msgs 。)

    find_package(catkin REQUIRED COMPONENTS
      roscpp
      rospy
      std_msgs
      message_generation
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

      2. 添加自定义的消息文件。将你msg文件夹中自定义的*.msg文件添加在这里。

    add_message_files(
      FILES
      Num.msg
    )
    
    • 1
    • 2
    • 3
    • 4

      3. 用于生成所有定义的message文件,需要添加本文件需要依赖的packages。其实就是告诉编译器,编译 *.msg 文件时,需要依赖的库或package。

    generate_messages(
      DEPENDENCIES
      std_msgs
    )
    
    • 1
    • 2
    • 3
    • 4

      4. 导出消息的运行时依赖关系。

    catkin_package(
      ...
      CATKIN_DEPENDS message_runtime ...
      ...)
    
    • 1
    • 2
    • 3
    • 4

    4.3 配置package.xml

      添加编译依赖与执行依赖。

      <build_depend>message_generationbuild_depend>
      <exec_depend>message_runtimeexec_depend>
    
    • 1
    • 2

    Node :在构建时,其实只需要message_generation,而在运行时,我们只需要message_runtime

    4.4 编译package

      已经创建了一些新消息,所以需要重新make一下软件包:

    cd
    cd catkin_ws
    catkin_make
    
    • 1
    • 2
    • 3

    msg bulid
      msg目录中的任何.msg文件都将生成所有支持语言的代码。

    • C++消息的头文件将生成在~/catkin_ws/devel/include/beginner_tutorials/

    msg 生成C++头文件的位置.png

    • python脚本将创建在~/catkin_ws/devel/lib/python2.7/dist-packages/beginner_tutorials/msg

    msg 生成python头文件的位置.png

    5、msg命令实操

    5.1 rosmsg list

      rosmsg list 列出ROS中的所有消息(msg)。

    5.2 rosmsg packages

      rosmsg packages [options] 列出包含消息的软件包。

    # 列出包含消息的软件包,每行显示一个软件包名
    rosmsg packages
    # 在一行中列出包含消息的软件包
    rosmsg packages -s 
    
    • 1
    • 2
    • 3
    • 4

    5.3 rosmsg package

      rosmsg package [package-name] 列出某个软件包(package)的消息。

    rosmsg package turtlesim

    5.4 rosmsg show / rosmsg info

      rosmsg show [message type] 显示消息的详细信息。
    rosmsg show message type.png

    5.5 rosmsg md5

      rosmsg md5[message type] 显示md5加密的消息。如果编译的版本不匹配,这也会发出警告。

    Node:md5 命令仅供专家用户使用。(??)

    6、实操编程 – 话题通信发送自定义消息

      功能:基于话题通信,发布者以一定频率发布自定义消息并打印输出消息,订阅者订阅自定义消息并打印输出消息。
      实现
        1. 创建发布者(talker)节点,该节点不断广播自定义消息。
        2. 创建订阅者(listener)节点,该节点持续接收自定义消息。
        3. 创建自定义消息(Num.msg),(见4.1小节 创建msg
        4. 发布订阅话题chatter

    Num.msg
    Num.msg
    talker
    chatter
    listener

    6.1 编写程序(C++)

      在beginner_tutorials软件包的src目录下创建发布者和订阅者源文件:

    roscd beginner_tutorials
    cd src
    touch talker.cpp listener.cpp
    
    • 1
    • 2
    • 3

    6.1.1 发布者程序(talker.cpp)

    #include "ros/ros.h"
    #include "beginner_tutorials/Num.h"  // 在 /devel/include 目录下
    
    int main(int argc, char **argv)
    {
        /* 防止中文乱码 */
        setlocale(LC_ALL,"");
        
        /* 初始化ROS节点 */
        ros::init(argc, argv, "talker");
        /* 为这个进程节点创建句柄 */
        ros::NodeHandle nh;
        /* 创建发布者对象 */
        ros::Publisher pub = nh.advertise<beginner_tutorials::Num>("chatter", 1000);
        /* 设定循环发布的频率为1Hz */
        ros::Rate loop_rate(1);
        /* 要发布的消息 */
        beginner_tutorials::Num msg;
        msg.num = 0;
    
        while(ros::ok())
        {
           ROS_INFO("当前num值为: %d",msg.num);
           
            /* 发布消息 */
            pub.publish(msg);
    
            ros::spinOnce();
    
            loop_rate.sleep();
    
            msg.num += 1;
        }
    
        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

    对上边的内容进行一下总结:

    • 初始化ROS系统
    • 向主节点宣告我们将要在chatter话题上发布beginner_tutorials/Num类型的消息
    • 以每秒1次的速率向chatter话题循环发布消息

    6.1.2 订阅者程序(listener.cpp)

    #include "ros/ros.h"
    #include "beginner_tutorials/Num.h"  // 在 /devel/include 目录下
    
    /* 回调函数,当有新消息到达chatter话题时就会调用 */
    void chatterCallback(const beginner_tutorials::Num::ConstPtr& msg)
    {
        ROS_INFO("已收到的Num的值: %d",msg->num);
    }
    
    int main(int argc, char **argv)
    {
         /* 防止中文乱码 */
        setlocale(LC_ALL,"");
        
        /* 初始化ROS节点 */
        ros::init(argc, argv, "listener");
        /* 为这个进程节点创建句柄 */
        ros::NodeHandle nh;
        /* 创建订阅者对象 
         * 通过节点管理器订阅chatter话题。收到消息,调用回调函数chatterCallback。
         * 第2个参数是队列大小,>1000时,丢弃旧消息。
         */
        ros::Subscriber sub = nh.subscribe("chatter",1000, chatterCallback);
    
        /* 启动自循环 回调函数处理, 不占用太多CPU */
        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

    同样地,我们来总结一下:

    • 初始化ROS系统
    • 订阅chatter话题
    • 开始spin自循环,等待消息的到达
    • 当消息到达后,调用chatterCallback()函数

    6.1.3 配置CMakeLists.txt

      只需将这几行添加到CMakeLists.txt文件的底部:

    add_executable(talker src/talker.cpp)
    target_link_libraries(talker ${catkin_LIBRARIES})
    add_dependencies(talker ${PROJECT_NAME}_generate_messages_cpp)
    
    add_executable(listener src/listener.cpp)
    target_link_libraries(listener ${catkin_LIBRARIES})
    add_dependencies(listener ${PROJECT_NAME}_generate_messages_cpp)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    6.1.4 编译、运行

      编译后,在终端中执行过程如下所示。
    话题(Topic)通信编程之msg(C++)

    6.2 编写程序(python)

      在beginner_tutorials软件包的scripts目录下创建发布者和订阅者源文件:

    roscd beginner_tutorials
    cd scripts
    touch talker.py listener.py
    chmod +x talker.py listener.py
    
    • 1
    • 2
    • 3
    • 4

    6.2.1 发布者程序(talker.py)

    #!/usr/bin/env python
    # encoding: utf-8
    
    import rospy
    from beginner_tutorials.msg import Num
    
    def talker():
        # 初始化ROS节点
        rospy.init_node("talker",anonymous=True)
        # 创建发布者对象
        pub = rospy.Publisher('chatter', Num, queue_size=1000)
    
        
        # 创建一个Rate对象rate,1Hz
        rate = rospy.Rate(1)
    
        # 要发布的消息
        msg = Num()
        msg.num = 0
    
        # 循环
        while not rospy.is_shutdown():
            rospy.loginfo("当前num值为: %d",msg.num)
            pub.publish(msg)
            rate.sleep()
            msg.num += 1
    
    
    if __name__ == '__main__':
        try:
            talker()
        except rospy.ROSInterruptException:
            pass
    
    
    • 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

    6.2.2 订阅者程序(listener.py)

    #!/usr/bin/env python
    # encoding: utf-8
    
    import rospy
    from beginner_tutorials.msg import Num
    
    
    def callback(msg):
        rospy.loginfo("已收到的Num的值: %d",msg.num)
    
    def listener():
        # 初始化ROS节点
        rospy.init_node("listener",anonymous=True)
        # 创建发布者对象
        pub = rospy.Subscriber('chatter', Num, callback, queue_size=1000)
    
        rospy.spin()
    
    if __name__ == '__main__':
        listener()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    6.2.3 配置CMakeLists.txt

    # 安装python可执行脚本
    catkin_install_python(PROGRAMS 
      scripts/turtle_publisher.py
      scripts/talker.py
      scripts/listener.py 
      DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
      )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    6.1.4 编译、运行

      编译后,在终端中执行过程如下所示。
    话题(Topic)通信编程之msg(Python)


    1. ROS.otg. ROS教程[EB/OL]. 2020-12-22[2022-7-5].
      http://wiki.ros.org/cn/ROS/Tutorials. ↩︎

    2. .ROS.org. 编写简单的发布者和订阅者(C++)[EB/OL]. 2020-12-25[2022-07-30]. https://wiki.ros.org/cn/ROS/Tutorials/WritingPublisherSubscriber%28c%2B%2B%29. ↩︎

    3. .ROS.org. 编写简单的发布者和订阅者(Python)[EB/OL]. 2020-12-25[2022-07-30]. https://wiki.ros.org/cn/ROS/Tutorials/WritingPublisherSubscriber%28python%29. ↩︎

    4. ROS.org. msg[EB/OL]. https://wiki.ros.org/msg[2022-07-30]. https://wiki.ros.org/msg. ↩︎

  • 相关阅读:
    NumPy 泊松分布模拟与 Seaborn 可视化技巧
    java基于springboot的社区生活超市管理系统
    Langchain-Chatchat项目:1-整体介绍
    MongoDB的作用和安装方法
    章鱼猫挂件
    公司注册类型分类标准是怎样的
    单源最短路径 dijkstra
    LightDB-A 兼容oracle支持mod操作符
    el-date-picker如何回显
    PHP 文件处理
  • 原文地址:https://blog.csdn.net/CynalFly/article/details/126072684