ROS学习笔记5——话题通信自定义msg

本文介绍了在ROS中如何创建和编辑msg文件,如Person.msg,以及如何在package.xml和CMakeLists.txt中配置自定义消息类型,包括依赖管理和编译过程。通过实例展示了如何在发布者和订阅者中使用自定义消息并配置CMakeLists.txt以确保正确编译。

在 ROS 通信协议中,数据载体是一个较为重要组成部分,ROS 中通过 std_msgs 封装了一些原生的数据类型,比如:String、Int32、Int64、Char、Bool、Empty.... 但是,这些数据一般只包含一个 data 字段,结构的单一意味着功能上的局限性,当传输一些复杂的数据,比如: 相机的信息... std_msgs 由于描述性较差而显得力不从心,这种场景下可以使用自定义的消息类型。

ROS中还有一种特殊类型:Header,标头包含时间戳和ROS中常用的坐标帧信息。会经常看到msg文件的第一行具有Header标头

一、定义msg文件

功能包下新建 msg 目录,添加文件 Person.msg。复合消息类型由标准消息类型组成,语法和写结构体差不多。

二、编辑配置文件

2.1 package.xml

在package.xml文件中添加编译依赖和执行依赖

2.2 CMakeLists.txt

a、find_package

编译自定义的功能包时需要依赖find_package中的功能包

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
# 需要加入 message_generation,必须有 std_msgs

b、add_message_files

配置msg源文件

add_message_files(
  FILES
  Person.msg
)

c、 generate_messages

生成消息是依赖于std_mags。因为自定义msg也是由std_msgs 中一些原生的数据类型组成的

generate_messages(
  DEPENDENCIES
  std_msgs
)

d、catkin_package

编译find_package中的依赖包时,依赖于catkin_package中的功能包

catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES demo02_talker_listener
  CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
#  DEPENDS system_lib
)

三、编译

快捷键ctrl+alt+B,配置方法之前分享过。

编译后的中间文件会放在工作空间的dev目录下,C++的中间文件在include中,python的在lib中,

后续调用相关 msg 时,是从这些中间文件调用的。

四、自定义msg调用实例

4.1 vscode 配置

为了方便代码提示以及避免误抛异常,需要先配置 vscode,将前面生成的 head 文件路径配置进 c_cpp_properties.json 的 includePath属性:

4.2 发布方

相较于最普通的发布文本信息,这里需要添加中间文件的头文件,并且实例化发布者对象的时候,发布的消息类型有所变化。

#include "ros/ros.h"
#include "topic_pub_sub/Person.h"    //添加头文件
#include <sstream>
#include <iostream>

int main(int argc, char *argv[])
{
    /* code */
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"pub_person");
    ros::NodeHandle nh;
    //实例化发布者对象
    ros::Publisher pub = nh.advertise<topic_pub_sub::Person>("chatter_person",10);
    topic_pub_sub::Person p;
    p.id = 0;
    p.name = "Robot";
    p.score = 100;
    ros::Rate rate(1);
    ros::Duration(3).sleep();
    while(ros::ok())
    {
        std::stringstream ss;   
        ss << p.name << p.score; 
        pub.publish(p);
        p.id += 1;
        ROS_INFO("name:%s%d,score:%.2f",p.name.c_str(),p.id,p.score);
        rate.sleep();
    }

    return 0;
}

4.3 订阅方

#include "ros/ros.h"
#include "topic_pub_sub/Person.h"    //添加头文件
#include <sstream>
#include <iostream>

//消息类型
void doPerson(const topic_pub_sub::Person::ConstPtr p)
{
   ROS_INFO("name:%s%d,score:%.2f",p->name.c_str(),p->id,p->score);
}

int main(int argc, char *argv[])
{
    /* code */
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"sub_person");
    ros::NodeHandle nh;
    ros::Subscriber sub = nh.subscribe<topic_pub_sub::Person>("chatter_person",10,doPerson);
    ros::spin();
    
    return 0;
}

4.4 配置 CMakeLists.txt

除了常规的add_executable和target_link_libraries配置之外。还需要配置add_dependencies,这是为了编译msg文件之后,再编译包含msg文件的cpp文件,保证不会出现逻辑错误。

add_executable(topic_pub_person src/topic_pub_person.cpp)
add_executable(topic_sub_person src/topic_sub_person.cpp)

target_link_libraries(topic_pub_person ${catkin_LIBRARIES})
target_link_libraries(topic_sub_person ${catkin_LIBRARIES})

add_dependencies(topic_pub_person ${PROJECT_NAME}_generate_messages_cpp)
add_dependencies(topic_sub_person ${PROJECT_NAME}_generate_messages_cpp)

4.5 执行结果

<think>嗯,用户想了解如何在ROS中使用自定义消息类型进行话题通信。我之前整理过一些关于ROS话题通信的引用资料,现在需要结合这些资料来回答。 首先,根据引用[1],自定义msg的流程包括创建msg文件、配置package.xml和CMakeLists.txt,然后是编写发布方和订阅方的代码。引用[2]提到msg文件中可以使用Header类型,所以可能需要包含Header标头。引用[3]强调了发布方、接收方和数据(自定义消息)三个关键点,以及vscode的配置。 用户的问题需要分步骤的教程。应该先讲创建msg文件的步骤,包括在功能包下新建msg目录,编写msg文件的内容,比如加入Header和其他字段。接着是配置package.xml,添加对message_generation和message_runtime的依赖。然后配置CMakeLists.txt,添加msg文件,生成消息代码。 然后需要说明如何编写发布者和订阅者的Python代码,注意导入自定义消息类型。同时要提醒用户可能遇到的路径问题,比如需要source devel/setup.bash,或者配置vscode的环境。这部分可以引用[3]提到的vscode配置注意事项。 最后,测试部分需要编译和运行节点,使用rostopic命令查看消息是否正确发布。可能还要提到常见错误,比如消息未生成导致导入失败,或者环境变量未设置正确。 生成的相关问题应该围绕步骤展开,比如如何定义复杂消息,如何处理依赖,以及调试方法。这样用户可以根据问题进一步深入学习。</think>### ROS自定义消息实现话题通信教程 #### 一、创建自定义消息 1. 在功能包目录下新建`msg`文件夹,创建`Person.msg`文件: ```msg Header header string name uint8 age float32 height ``` 注意:第一行的`Header`类型需要包含`std_msgs/Header`声明[^2] #### 二、配置编译规则 1. 修改`package.xml`添加依赖: ```xml <build_depend>message_generation</build_depend> <exec_depend>message_runtime</exec_depend> ``` 2. 修改`CMakeLists.txt`: ```cmake find_package(catkin REQUIRED COMPONENTS roscpp std_msgs message_generation ) add_message_files( FILES Person.msg ) generate_messages( DEPENDENCIES std_msgs ) catkin_package( CATKIN_DEPENDS message_runtime ) ``` #### 三、编写发布者节点(publisher.py) ```python #!/usr/bin/env python import rospy from std_msgs.msg import Header from your_pkg.msg import Person # 替换为实际包名 def talker(): pub = rospy.Publisher('person_info', Person, queue_size=10) rospy.init_node('person_publisher', anonymous=True) rate = rospy.Rate(1) # 1Hz while not rospy.is_shutdown(): msg = Person() msg.header.stamp = rospy.Time.now() msg.name = "Alice" msg.age = 25 msg.height = 1.68 pub.publish(msg) rate.sleep() if __name__ == '__main__': try: talker() except rospy.ROSInterruptException: pass ``` #### 四、编写订阅者节点(subscriber.py) ```python #!/usr/bin/env python import rospy from your_pkg.msg import Person # 替换为实际包名 def callback(data): rospy.loginfo(f"Received: {data.name}, Age: {data.age}, Height: {data.height}") def listener(): rospy.init_node('person_subscriber') rospy.Subscriber("person_info", Person, callback) rospy.spin() if __name__ == '__main__': listener() ``` #### 五、编译与测试 1. 执行编译: ```bash catkin_make source devel/setup.bash ``` 2. 运行测试: ```bash # 终端1 roscore # 终端2 rosrun your_pkg publisher.py # 终端3 rosrun your_pkg subscriber.py # 终端4 rostopic echo /person_info ``` #### 六、常见问题处理 1. **消息未生成**:检查`CMakeLists.txt`的`generate_messages()`是否配置正确 2. **导入失败**:确认已执行`source devel/setup.bash`[^3] 3. **字段不匹配**:修改msg文件后需要重新编译
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值