ROS topic communication custom msg

From 21 years to now, I have written no less than 10 ROS topic communication projects. Today, I systematically record the process of customizing msg, so that latecomers can avoid detours.

1. Introduction to custom msg

In the ROS communication protocol, the data carrier is an important part. ROS encapsulates some native data types through std_msgs, such as: String, Int32, Int64, Char, Bool, Empty... However, these data generally only contain one data The single field and structure means functional limitations. When transmitting some complex data, such as: lidar information... std_msgs is powerless due to its poor descriptiveness. In this scenario, a custom message type can be used.

msgs are simply text files, each line has a field type and field name, the field types that can be used are:

  • int8, int16, int32, int64 (or unsigned type: uint*)
  • float32, float64
  • string
  • time, duration
  • other msg files
  • variable-length array[] and fixed-length array[C]

There is also a special type in ROS: Header, the header contains timestamps and coordinate frame information commonly used in ROS. It is common to see that the first line of a msg file has a Header header.

2. Custom msg example

Requirement: Create a custom message that contains the 6-DOF coordinates (3D coordinates + Euler angles) of the rigid body: x, y, z, r, p, y.

Operating procedures:

  1. Create msg files in a fixed format
  2. edit configuration file
  3. Compile and generate intermediate files that can be called by Python or C++

2.1, define the msg file

Create a new msg directory under the function package, add the file Pose.msg, because the data is of floating point type, select 32-bit float.

float32 axis_x 
float32 axis_y
float32 axis_z
float32 roll
float32 pitch
float32 yaw

2.2, edit the configuration file

Add compile-time dependencies and execution-time dependencies to package.xml

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

insert image description here

CMakeLists.txt edit msg related configuration

# 需要加入 message_generation,必须有 std_msgs
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
## 配置 msg 源文件
add_message_files(
  FILES
  Pose.msg
)
# 生成消息时依赖于 std_msgs
generate_messages(
  DEPENDENCIES
  std_msgs
)
#执行时依赖
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES ros_vo
 CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
#  DEPENDS system_lib
)

2.3, compile project

Enter the workspace directory and compile with catkin_make

Scanning dependencies of target _ros_vo_generate_messages_check_deps_Pose
[  0%] Built target std_msgs_generate_messages_lisp
[  0%] Built target std_msgs_generate_messages_py
[  0%] Built target std_msgs_generate_messages_eus
[  0%] Built target std_msgs_generate_messages_nodejs
[  0%] Built target std_msgs_generate_messages_cpp
Scanning dependencies of target run_vo
[  0%] Built target _ros_vo_generate_messages_check_deps_Pose
Scanning dependencies of target ros_vo_generate_messages_py
Scanning dependencies of target ros_vo_generate_messages_eus
Scanning dependencies of target ros_vo_generate_messages_cpp
Scanning dependencies of target ros_vo_generate_messages_nodejs
Scanning dependencies of target ros_vo_generate_messages_lisp
[ 11%] Generating Lisp code from ros_vo/Pose.msg
[ 33%] Generating C++ code from ros_vo/Pose.msg
[ 33%] Generating Python from MSG ros_vo/Pose
[ 44%] Generating EusLisp manifest code for ros_vo
[ 55%] Generating EusLisp code from ros_vo/Pose.msg
[ 66%] Generating Javascript code from ros_vo/Pose.msg
[ 66%] Built target ros_vo_generate_messages_lisp
[ 66%] Built target ros_vo_generate_messages_nodejs
[ 77%] Building CXX object ros_vo/CMakeFiles/run_vo.dir/src/run_vo.cpp.o
[ 88%] Generating Python msg __init__.py for ros_vo
[ 88%] Built target ros_vo_generate_messages_cpp
[ 88%] Built target ros_vo_generate_messages_py
[ 88%] Built target ros_vo_generate_messages_eus
Scanning dependencies of target ros_vo_generate_messages
[ 88%] Built target ros_vo_generate_messages
[100%] Linking CXX executable /home/dzh/Demo/VO/devel/lib/ros_vo/run_vo
[100%] Built target run_vo

Check the compiled intermediate file:

The intermediate files that C++ needs to call (.../workspace/devel/include/package name/xxx.h), when calling related msg, are called from these intermediate files.

insert image description here

3. Custom msg call

need:

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

analyze:

In the model implementation, the ROS master does not need to be implemented, and the establishment of the connection has been encapsulated. There are three key points to pay attention to:

发布方
接收方
数据(此处为自定义消息)

process:

编写发布方实现;
编写订阅方实现;
编辑配置文件;
编译并执行。

3.1. The publisher realizes:

// 1.包含头文件 
#include "ros/ros.h"
#include "std_msgs/String.h" 
#include "geometry_msgs/Point.h"
#include "rtsp/Pose.h"

int main(int argc, char  *argv[])
{
    
       
    //设置编码
    setlocale(LC_ALL,"");

    //2.初始化 ROS 节点:命名(唯一)
    // 参数1和参数2 后期为节点传值会使用
    // 参数3 是节点名称,是一个标识符,需要保证运行后,在 ROS 网络拓扑中唯一
    ros::init(argc,  argv, "poseTalker");
    //3.实例化 ROS 句柄
    ros::NodeHandle nh;//该类封装了 ROS 中的一些常用功能

    //4.实例化 发布者 对象
    //泛型: 发布的消息类型
    //参数1: 要发布到的话题名称
    //参数2: 队列中最大保存的消息数,超出此阀值时,先进的先销毁(时间早的先销毁)
    ros::Publisher pub = nh.advertise<rtsp::Pose>("pose", 10);

    //5.组织被发布的数据,并编写逻辑发布数据
    // x方向像素偏移、y方向像素偏移、z方向真实距离(6m内有效,否则为0)
    rtsp::Pose pose;
    // 类型为float64
    pose.axis_x  = 1;
    pose.axis_y = 2;
    pose.axis_z = 3;
    pose.roll = 4;
    pose.pitch = 5;
    pose.yaw = 6;

    //逻辑(一秒1次)
    ros::Rate r(10);

    //节点不死
    while (ros::ok())
    {
    
    
        //发布消息
        pub.publish(pose);
        //加入调试,打印发送的消息
        // ROS_INFO("发送的消息:%f %f %f",point.x, point.y, point.z);
        //根据前面制定的发送频率自动休眠 休眠时间 = 1/频率;
        r.sleep();
        //暂无应用
        ros::spinOnce();
    }

    return 0;
}

3.2. Subscriber realizes:

// 1.包含头文件 
#include "ros/ros.h"
#include "std_msgs/String.h"
#include "geometry_msgs/Point.h"
#include "rtsp/Pose.h"

// 处理pose消息
void dealPose(const rtsp::Pose::ConstPtr &msg_pose){
    
    
    ROS_INFO("axis_x: %f, axis_y: %f, axis_z: %f, roll: %f, pitch: %f, yaw: %f", msg_pose.axis_x, msg_pose.axis_y, msg_pose.axis_z, msg_pose.roll, msg_pose.pitch, msg_pose.yaw);
}

int main(int argc, char  *argv[])
{
    
    
    setlocale(LC_ALL,"");
    //2.初始化 ROS 节点:命名(唯一)
    ros::init(argc,argv,"listener");
    //3.实例化 ROS 句柄
    ros::NodeHandle nh;
    //4.实例化 订阅者 对象,订阅话题为Point
    ros::Subscriber sub = nh.subscribe<rtsp::Pose>("pose", 10, dealPose);
    //5.处理订阅的消息(回调函数)
    //ros::Subscriber sub2 = nh.subscribe<未知结构体类型>("未知话题名称", 10, recvMsg);
    // 6.设置循环调用回调函数
    ros::spin();//循环读取接收的数据,并调用回调函数处理
    return 0;
}

3.3. Configure CMakeLists.txt

add_executable(pose_pub src/pose_pub.cpp)
add_executable(pose_sub src/pose_sub.cpp)

target_link_libraries(pose_pub
  ${
    
    catkin_LIBRARIES}
)
target_link_libraries(pose_sub
  ${
    
    catkin_LIBRARIES}
)

3.4. Execution

  1. start roscore;

  2. Start the publishing node;

  3. Start the subscription node.

insert image description here

PS: You can use it in the terminal rqt_graphto view the node relationship; use it rostopic listto view the topic list; use it rostopic echo poseto subscribe to the topic content. Remember to use thesource ./devel/setup.bash

Guess you like

Origin blog.csdn.net/qq_42257666/article/details/131489036