当前位置: 首页 > 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.jsqmd.com/news/957203/

相关文章:

  • k8s基础3
  • 深耕产教提质效,择校优选看赣鄱——江西优质高职院校盘点 - 品牌测评鉴赏家
  • ROS 2 治理结构解析:从代码贡献到生态决策的权力路径
  • 大学生课程设计用Python人脸识别考勤系统(含CNN模型、OpenCV检测与Qt图形界面)
  • 2026 北京团建公司权威推荐排行榜发布:六大服务商全维度评测,企业团建选型科普指南 - GrowthUME
  • 终极指南:foo2zjs - Linux系统下最全面的打印机驱动解决方案
  • AOSP 12.0 SystemUI设计原理浅析之插件化
  • 英辰朗迪发布GEO全域信源解决方案,助力企业构建AI时代品牌资产 - GrowthUME
  • Linux 内核中的调度模型:从磁盘 IO 调度算法到系统级资源瓶颈分析
  • 2026 佛山名表回收高价 TOP1 盘点|本地靠谱龙头回收机构榜单 - 奢侈品交易观察员
  • 别再手动写ROM了!Vivado里用IP核+COE文件5分钟搞定数据初始化(附完整仿真流程)
  • 2026年 海立压缩机厂家推荐榜单:卧式压缩机/热泵压缩机/空调压缩机/冷库压缩机专业品牌深度解析 - 品牌企业推荐师(官方)
  • PyFluent完全指南:用Python脚本实现CFD仿真自动化
  • 上海高雅德包包回收7家门店PK,禹竞名奢汇几乎全票 - 奢侈品交易观察员
  • 如何用一台电脑玩多人游戏?Nucleus Co-Op分屏解决方案揭秘
  • 2026惠州头部GEO企业领跑赛道,AI原生获客构建全域增长新范式 - 阿威说AI
  • 企业周年庆全员纪念礼去哪订?智美源头工厂批量定制 - GrowthUME
  • 江西高性价比优质大专院校盘点,择校优选榜单推荐 - 品牌测评鉴赏家
  • 混元3.0提示词工程:中文语义锚点与结构化指令设计指南
  • 做 excel 表格用哪个 ai 软件?多款工具实测对比,AI 导出鸭凭多端适配脱颖而出 - AI火狐
  • 为什么Inter字体正在重新定义数字排版标准:战略性的用户体验革命
  • Claude 3.5 Sonnet深度解析:架构演进与企业级RAG实战
  • # GR3六轴机械臂最终增补:OLED裸屏驱动 + 掉电断点续跑 全套源码
  • 【自媒体技术分析】头条号、小红书和公众号文章违规词、敏感词、AI率、低价创作、同质化和模板化问题的底层原因分析
  • 从糯种到冰种价差详解,成都榜单优质商户,闲置翡翠手镯稳妥高价出手 - 奢侈品回收评测
  • 2026年 艾默生卧式/涡旋/空调/热泵/冷库压缩机品牌推荐:高效稳定与低温制热核心优势深度解析 - 品牌企业推荐师(官方)
  • 3个关键设置让虚拟摄像头效果翻倍:OBS插件深度配置指南
  • 合同管理的五个“反常识”结论
  • 广东一站式宠物包装定制/彩盒包装/礼品盒包装服务商/供货商/源头工厂选择:踩坑3年总结的5个考察要点 - 变量人生001
  • LTspice变压器仿真建模:从互感原理到SPICE参数化实践