当前位置: 首页 > news >正文

ROS2 话题通信实战:消息对象、Publisher 发布器与 Subscriber 订阅器保姆级教程

目录

摘要

一、ROS2 消息对象的常见写法

1.1 创建消息对象的基本格式

1.2 以 Twist 为例创建速度消息

1.3 给消息字段赋值

(1)让机器人向前运动

(2)让机器人原地旋转

(3)让机器人停止

二、ROS2 发布器 Publisher 的写法

2.1 发布器的基本定义方式

2.2 创建发布器

2.3 发布消息

2.4 完整发布器示例代码

2.5 发布器代码重点解释

(1)包含头文件

(2)创建发布器

(3)创建定时器

(4)发布速度消息

三、ROS2 订阅器 Subscriber 的写法

3.1 订阅器的基本定义方式

3.2 创建订阅器

3.3 回调函数中接收消息

3.4 完整订阅器示例代码

3.5 发布端和订阅端访问字段的区别

(1)发布端通常使用点号

(2)订阅端通常使用箭头


摘要

上一篇文章主要讲解了ROS2 中常见的消息类型,例如std_msgsgeometry_msgsnav_msgssensor_msgs,并重点说明了geometry_msgs::msg::TwistPosePoseStampedTransformStamped等消息的含义。链接如下:

ROS2 常见消息类型保姆级教程-CSDN博客https://blog.csdn.net/m0_58954356/article/details/161693378?spm=1001.2014.3001.5502这一篇开始进入 ROS2 话题通信实战,重点讲清楚几个问题:

1. ROS2 中如何创建消息对象?
2. Publisher 发布器怎么写?
3. Subscriber 订阅器怎么写?

本文仍然以移动机器人常用的速度控制消息:

geometry_msgs::msg::Twist

为例,带大家从代码层面真正看懂 ROS2 的话题发布、话题订阅和消息字段查看方法。


一、ROS2 消息对象的常见写法

1.1 创建消息对象的基本格式

ROS2 中创建消息对象,一般采用下面这种格式:

包名::msg::消息类型 变量名;

例如:

std_msgs::msg::String msg; geometry_msgs::msg::Twist vel_cmd; nav_msgs::msg::Odometry odom; sensor_msgs::msg::LaserScan scan;

这和普通 C++ 定义变量非常像。

普通 C++ 中可以这样定义变量:

int age; double speed; std::string name;

ROS2 中定义消息对象则是:

geometry_msgs::msg::Twist vel_cmd;

其中:

geometry_msgs::msg::Twist 消息类型 vel_cmd 消息对象名

也就是说,vel_cmd是一个变量,只不过它的类型不是intdouble,而是 ROS2 中的Twist消息类型。


1.2 以 Twist 为例创建速度消息

Twist 常用于 /cmd_vel 速度控制话题

移动机器人控制中,经常会看到:

geometry_msgs::msg::Twist vel_cmd;

这句代码的意思是:

创建一个 Twist 类型的速度消息对象,名字叫 vel_cmd。

Twist里面主要包含两部分:

Vector3 linear; // 线速度 Vector3 angular; // 角速度

完整字段如下:

vel_cmd.linear.x; vel_cmd.linear.y; vel_cmd.linear.z; vel_cmd.angular.x; vel_cmd.angular.y; vel_cmd.angular.z;

对于大多数地面移动机器人来说,最常用的是:

vel_cmd.linear.x; // 前进 / 后退速度 vel_cmd.angular.z; // 左转 / 右转角速度


1.3 给消息字段赋值

(1)让机器人向前运动

例如:

geometry_msgs::msg::Twist vel_cmd; vel_cmd.linear.x = 0.2; vel_cmd.angular.z = 0.0;

含义是:

机器人以 0.2 m/s 的速度向前运动,不旋转。

这里:

linear.x = 0.2

表示沿机器人前方方向前进。

angular.z = 0.0

表示不绕 z 轴旋转。


(2)让机器人原地旋转

如果写成:

vel_cmd.linear.x = 0.0; vel_cmd.angular.z = 0.5;

含义是:

机器人不前进,只原地旋转。

其中:

angular.z = 0.5

表示绕 z 轴旋转,单位通常是:

rad/s

也就是弧度每秒。


(3)让机器人停止

如果想让机器人停止,一般写成:

vel_cmd.linear.x = 0.0; vel_cmd.angular.z = 0.0;

并且发布出去:

pub_vel->publish(vel_cmd);

需要注意的是,机器人停止时,最好不是简单地“不发消息”,而是主动发布一个零速度消息

也就是:

linear.x = 0.0 angular.z = 0.0

这样底盘控制节点才能明确知道机器人需要停止。


二、ROS2 发布器 Publisher 的写法

2.1 发布器的基本定义方式

Publisher 需要指定消息类型

如果要发布Twist消息,发布器一般这样定义:

rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr pub_vel;

可以拆开理解:

rclcpp::Publisher<geometry_msgs::msg::Twist>

表示这是一个发布Twist消息的发布器。

SharedPtr

表示智能指针类型

pub_vel

发布器对象的名字

完整意思就是:

定义一个发布 geometry_msgs::msg::Twist 消息的发布器,名字叫 pub_vel。


2.2 创建发布器

使用 create_publisher 创建发布器

在 ROS2 节点类里面,通常使用:

create_publisher

创建发布器

例如:

pub_vel = this->create_publisher<geometry_msgs::msg::Twist>("/cmd_vel", 10);

这句代码可以拆成:

this->create_publisher<geometry_msgs::msg::Twist>

表示创建一个发布Twist消息的发布器

"/cmd_vel"

表示发布到/cmd_vel话题。

10

表示队列深度

所以这句代码整体含义是:

创建一个发布器,这个发布器向 /cmd_vel 话题发布 Twist 类型消息,队列深度为 10。


2.3 发布消息

先创建消息,再赋值,最后 publish

发布消息的基本流程是:

1. 创建消息对象
2. 给消息字段赋值
3. 调用 publish 发布出去

代码如下:

geometry_msgs::msg::Twist vel_cmd; vel_cmd.linear.x = 0.1; vel_cmd.angular.z = 0.0; pub_vel->publish(vel_cmd);

其中:

pub_vel->publish(vel_cmd);

表示vel_cmd这条速度消息发布出去

如果pub_vel发布的是/cmd_vel话题,那么底盘控制节点订阅到这个话题后,就可以控制机器人运动。


2.4 完整发布器示例代码

周期发布 /cmd_vel 速度消息

下面是一个简单的 ROS2 C++ 发布器节点,功能是周期性发布速度消息,让机器人向前运动。

#include "rclcpp/rclcpp.hpp" #include "geometry_msgs/msg/twist.hpp" using namespace std::chrono_literals; class CmdVelPublisher : public rclcpp::Node { public: CmdVelPublisher() : Node("cmd_vel_publisher") { pub_vel = this->create_publisher<geometry_msgs::msg::Twist>("/cmd_vel", 10); timer = this->create_wall_timer( 500ms, std::bind(&CmdVelPublisher::timer_callback, this) ); } private: void timer_callback() { geometry_msgs::msg::Twist vel_cmd; vel_cmd.linear.x = 0.1; vel_cmd.linear.y = 0.0; vel_cmd.linear.z = 0.0; vel_cmd.angular.x = 0.0; vel_cmd.angular.y = 0.0; vel_cmd.angular.z = 0.0; pub_vel->publish(vel_cmd); RCLCPP_INFO( this->get_logger(), "Publishing: linear.x = %.2f, angular.z = %.2f", vel_cmd.linear.x, vel_cmd.angular.z ); } private: rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr pub_vel; rclcpp::TimerBase::SharedPtr timer; }; int main(int argc, char * argv[]) { rclcpp::init(argc, argv); auto node = std::make_shared<CmdVelPublisher>(); rclcpp::spin(node); rclcpp::shutdown(); return 0; }

2.5 发布器代码重点解释

(1)包含头文件

#include "rclcpp/rclcpp.hpp" #include "geometry_msgs/msg/twist.hpp"

其中:

rclcpp/rclcpp.hpp

ROS2 C++ 客户端库头文件。

geometry_msgs/msg/twist.hpp

Twist消息类型对应的头文件。

只要代码里使用:

geometry_msgs::msg::Twist

就需要包含:

#include "geometry_msgs/msg/twist.hpp"

(2)创建发布器

pub_vel = this->create_publisher<geometry_msgs::msg::Twist>("/cmd_vel", 10);

这句表示创建/cmd_vel话题发布器。

消息类型是:

geometry_msgs::msg::Twist

话题名字是:

/cmd_vel

(3)创建定时器

timer = this->create_wall_timer( 500ms, std::bind(&CmdVelPublisher::timer_callback, this) );

这句表示每隔500ms执行一次:

timer_callback()

所以这个节点会周期性发布速度消息。


(4)发布速度消息

pub_vel->publish(vel_cmd);

这句才是真正把速度消息发布出去。

如果没有这句,前面只是创建了消息、给消息赋值,并没有真正发到话题中。


三、ROS2 订阅器 Subscriber 的写法

3.1 订阅器的基本定义方式

Subscriber 也需要指定消息类型

如果要订阅Twist消息,订阅器一般这样定义:

rclcpp::Subscription<geometry_msgs::msg::Twist>::SharedPtr sub_vel;

可以拆成:

rclcpp::Subscription<geometry_msgs::msg::Twist>

表示这是一个订阅Twist消息的订阅器。

SharedPtr

表示智能指针类型。

sub_vel

是订阅器对象名。

完整含义是:

定义一个订阅 geometry_msgs::msg::Twist 消息的订阅器,名字叫 sub_vel。


3.2 创建订阅器

使用 create_subscription 创建订阅器

创建订阅器一般这样写:

sub_vel = this->create_subscription<geometry_msgs::msg::Twist>( "/cmd_vel", 10, std::bind(&CmdVelSubscriber::cmd_vel_callback, this, std::placeholders::_1) );

其中:

geometry_msgs::msg::Twist

表示订阅的消息类型。

"/cmd_vel"

表示订阅的话题名字。

10

表示队列深度。

std::bind(&CmdVelSubscriber::cmd_vel_callback, this, std::placeholders::_1)

表示收到消息后,执行cmd_vel_callback回调函数。


3.3 回调函数中接收消息

回调函数一般这样写:

void cmd_vel_callback(const geometry_msgs::msg::Twist::SharedPtr msg) { RCLCPP_INFO( this->get_logger(), "Received: linear.x = %.2f, angular.z = %.2f", msg->linear.x, msg->angular.z ); }

这里需要特别注意:

msg

是一个指针,所以访问字段时使用:

msg->linear.x msg->angular.z

而不是:

msg.linear.x msg.angular.z

3.4 完整订阅器示例代码

订阅 /cmd_vel 并打印速度

下面代码订阅/cmd_vel话题,并打印收到的速度信息。

#include "rclcpp/rclcpp.hpp" #include "geometry_msgs/msg/twist.hpp" class CmdVelSubscriber : public rclcpp::Node { public: CmdVelSubscriber() : Node("cmd_vel_subscriber") { sub_vel = this->create_subscription<geometry_msgs::msg::Twist>( "/cmd_vel", 10, std::bind(&CmdVelSubscriber::cmd_vel_callback, this, std::placeholders::_1) ); } private: void cmd_vel_callback(const geometry_msgs::msg::Twist::SharedPtr msg) { RCLCPP_INFO( this->get_logger(), "Received: linear.x = %.2f, angular.z = %.2f", msg->linear.x, msg->angular.z ); } private: rclcpp::Subscription<geometry_msgs::msg::Twist>::SharedPtr sub_vel; }; int main(int argc, char * argv[]) { rclcpp::init(argc, argv); auto node = std::make_shared<CmdVelSubscriber>(); rclcpp::spin(node); rclcpp::shutdown(); return 0; }

3.5 发布端和订阅端访问字段的区别

(1)发布端通常使用点号

发布端一般是普通对象:

geometry_msgs::msg::Twist vel_cmd;

所以访问字段使用:

vel_cmd.linear.x vel_cmd.angular.z

(2)订阅端通常使用箭头

订阅端回调函数中收到的msg通常是智能指针:

const geometry_msgs::msg::Twist::SharedPtr msg

所以访问字段使用:

msg->linear.x msg->angular.z

可以简单记成:

  1. 普通对象用 .
  2. 指针对象用 ->

对比如下:

场景写法说明
发布端消息对象vel_cmd.linear.xvel_cmd是普通对象
订阅端消息指针msg->linear.xmsg是指针

http://www.rkmt.cn/news/1468812.html

相关文章:

  • 深耕产教提质效,择校优选看赣鄱——江西优质高职院校盘点 - 品牌测评鉴赏家
  • AOSP 12.0 SystemUI设计原理浅析之插件化
  • 2026年 海立压缩机厂家推荐榜单:卧式压缩机/热泵压缩机/空调压缩机/冷库压缩机专业品牌深度解析 - 品牌企业推荐师(官方)
  • 2026惠州头部GEO企业领跑赛道,AI原生获客构建全域增长新范式 - 阿威说AI
  • 企业周年庆全员纪念礼去哪订?智美源头工厂批量定制 - GrowthUME
  • 混元3.0提示词工程:中文语义锚点与结构化指令设计指南
  • 为什么Inter字体正在重新定义数字排版标准:战略性的用户体验革命
  • 合同管理的五个“反常识”结论
  • 2026年 艾默生卧式/涡旋/空调/热泵/冷库压缩机品牌推荐:高效稳定与低温制热核心优势深度解析 - 品牌企业推荐师(官方)
  • 【自媒体技术分析】头条号、小红书和公众号文章违规词、敏感词、AI率、低价创作、同质化和模板化问题的底层原因分析
  • 如何利用Tinke深入探索和修改NDS游戏资源?完整技术指南
  • 3个关键设置让虚拟摄像头效果翻倍:OBS插件深度配置指南
  • LTspice变压器仿真建模:从互感原理到SPICE参数化实践
  • 广东一站式宠物包装定制/彩盒包装/礼品盒包装服务商/供货商/源头工厂选择:踩坑3年总结的5个考察要点 - 变量人生001
  • GSEA结果解读与美化:从clusterProfiler输出到发表级图表(含AI调色技巧)
  • 2026年深圳包包回收一站式指南:合扬六区门店与专业鉴定,卖包不迷茫! - 奢侈品交易观察员
  • 广东高企金融咨询服务机构排行:合规与实效双维度筛选 - 互联网科技品牌测评
  • 别再瞎找了!2026年闭眼可入的专业一键生成论文工具
  • 从2层板到10层板:手把手教你规划KiCad多层PCB的叠层结构与命名(附常用方案)
  • 从Retinex到Zero-Reference:低光照增强算法这十年,我用代码带你跑一遍
  • MATLAB扫地机器人仿真包:含A*路径规划、动态避障与U型转向功能
  • 3DS上的宝可梦存档管家:如何用PKSM一站式管理你的精灵收藏
  • 太原工商注册代办机构排行 企业服务选择客观参考 - 互联网科技品牌测评
  • 择优择校指南:江西师资雄厚民办高职盘点,优质院校实力一览 - 品牌测评鉴赏家
  • 5步终极指南:用Gaggiuino微控制器改造你的Gaggia Classic咖啡机
  • RimWorld性能优化终极方案:Performance-Fish深度解析与实战指南
  • 编写程序根据出差奔波时长,住宿环境,综合评估旅途疲劳值,推荐快速恢复方案。
  • MATLAB版带时间窗VRP遗传算法求解工具包,含完整函数与实测数据
  • 3大突破:从技术债到性能飞跃的架构重构之旅
  • 文心大模型5.0正式版:从技术参数到服务契约的范式跃迁