ROS2系列 (10) : C++话题通信节点——发布者示例
ROS2系列 (10) : C++话题通信节点——发布者示例
在前两篇Python话题通信的基础上,本文将聚焦C++话题发布者的实现,通过“控制海龟模拟器画圆”的案例,详解C++节点中话题发布者、定时器的配置流程,并将其集成到现有工作空间,形成多语言协同的ROS2项目。
一、需求与技术拆解
功能需求:控制turtlesim海龟模拟器中的海龟,按指定半径画圆。
需解决的核心问题:
- 如何创建C++功能包?—— 使用ros2 pkg create指定ament_cmake构建类型,依赖rclcpp、geometry_msgs和turtlesim。
- 如何发布话题?—— 利用rclcpp的create_publisher创建发布者,结合定时器周期性发送Twist消息。
- 如何实现画圆逻辑?—— 利用“线速度/角速度=半径”的物理关系,配置合适的线速度和角速度参数。
- 如何避免隐式类型转换?—— 显式声明变量类型、使用时间字面量(如1000ms)。
二、创建C++功能包并集成到工作空间
在工作空间ros2_ws/src目录下创建C++功能包:
cd ~/ros2_ws/src
ros2 pkg create demo_cpp_topic --build-type ament_cmake \--dependencies rclcpp geometry_msgs turtlesim \--license Apache-2.0
- --dependencies rclcpp geometry_msgs turtlesim:声明依赖(- rclcpp是C++ ROS2客户端库,- geometry_msgs提供- Twist消息类型,- turtlesim是海龟模拟器功能包)。
三、编写C++发布者节点代码
在demo_cpp_topic/src/目录下创建circle_pub.cpp:
#include "rclcpp/rclcpp.hpp"
#include "geometry_msgs/msg/twist.hpp"
#include <chrono>  // 引入时间相关头文件
using namespace std::chrono_literals;  // 启用时间字面量(如1000ms)class TurtleCircle : public rclcpp::Node
{
private:rclcpp::TimerBase::SharedPtr timer_;  // 定时器智能指针(显式类型声明,避免隐式转换)rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr publisher_;  // 发布者智能指针(显式类型声明)public:explicit TurtleCircle(const std::string& node_name) : Node(node_name){// 显式创建发布者:话题名/turtle1/cmd_vel,消息类型Twist,QoS队列大小10publisher_ = this->create_publisher<geometry_msgs::msg::Twist>("/turtle1/cmd_vel", 10);RCLCPP_INFO(this->get_logger(), "话题发布者已创建,将发布/turtle1/cmd_vel话题");// 显式创建定时器:周期1000ms,绑定timer_callback回调(使用时间字面量,避免隐式转换)timer_ = this->create_wall_timer(1000ms, std::bind(&TurtleCircle::timer_callback, this));RCLCPP_INFO(this->get_logger(), "定时器已启动,周期1000ms");}private:void timer_callback(){// 显式实例化Twist消息auto msg = geometry_msgs::msg::Twist();// 线速度x方向为1.0,角速度z方向为0.5(线速度/角速度=2.0,即圆的半径为2.0)msg.linear.x = 1.0;    msg.angular.z = 0.5;  publisher_->publish(msg);  // 发布消息RCLCPP_INFO(this->get_logger(), "已发布Twist消息:线速度x=%.1f,角速度z=%.1f(圆半径=%.1f)", msg.linear.x, msg.angular.z, msg.linear.x / msg.angular.z);}
};int main(int argc, char *argv[])
{rclcpp::init(argc, argv);  // 初始化rclcppauto node = std::make_shared<TurtleCircle>("turtle_circle");  // 显式创建节点实例rclcpp::spin(node);       // 保持节点运行rclcpp::shutdown();       // 关闭rclcppreturn 0;
}
四、配置CMakeLists.txt
打开demo_cpp_topic/CMakeLists.txt,添加编译规则:
cmake_minimum_required(VERSION 3.8)
project(demo_cpp_topic)if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")add_compile_options(-Wall -Wextra -Wpedantic)
endif()# 查找依赖包
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(turtlesim REQUIRED)  # 新增turtlesim依赖查找# 编译可执行文件
add_executable(circle_pub src/circle_pub.cpp)
# 链接依赖(显式声明,避免隐式依赖问题)
ament_target_dependencies(circle_pub rclcpp geometry_msgs)# 安装可执行文件到指定目录
install(TARGETScircle_pubDESTINATION lib/${PROJECT_NAME}
)ament_package()
五、构建与运行流程
5.1 构建整个工作空间
回到工作空间根目录,执行构建:
cd ~/ros2_ws
colcon build
5.2 启动完整流程(三个终端)
终端1:启动海龟模拟器
cd ~/ros2_ws
source install/setup.bash
ros2 run turtlesim turtlesim_node
终端2:启动C++发布者节点
cd ~/ros2_ws
source install/setup.bash
ros2 run demo_cpp_topic circle_pub
终端3(可选):查看话题数据
cd ~/ros2_ws
source install/setup.bash
ros2 topic echo /turtle1/cmd_vel
5.3 效果验证
- 海龟模拟器中的海龟会以线速度1.0、角速度0.5的参数画圆(半径为1.0/0.5=2.0);
- 发布者终端会周期性输出“已发布Twist消息”的日志,显示当前圆半径;
- 若打开话题回声终端,会看到持续输出的Twist消息数据。
六、代码关键细节解析
6.1 显式类型声明与隐式转换规避
- 所有智能指针(如TimerBase::SharedPtr、Publisher::SharedPtr)均显式声明类型,避免编译器隐式类型推导导致的潜在问题。
- 使用std::chrono_literals命名空间中的时间字面量(如1000ms),显式指定时间单位,替代std::chrono::milliseconds(1000)的写法,代码更简洁且无隐式转换风险。
6.2 画圆逻辑的数学原理
海龟画圆的核心是线速度与角速度的比值等于圆的半径(即 r = v / ω)。本案例中v=1.0、ω=0.5,因此圆的半径r=2.0。可通过调整这两个参数,控制圆的大小。
6.3 定时器与发布者的协同
- create_wall_timer(period, callback):创建周期性定时器,- period通过时间字面量- 1000ms显式指定,- callback绑定类成员函数- timer_callback,实现消息的循环发布。
- create_publisher<MsgType>(topic, qos):创建话题发布者,显式指定消息类型- geometry_msgs::msg::Twist,确保与海龟模拟器的- /turtle1/cmd_vel话题通信的类型一致性。
七、总结
本文通过“控制海龟画圆”的案例,完整讲解了C++ ROS2话题发布者的实现流程,包括:
- 功能包创建与依赖配置(含turtlesim依赖);
- 代码中显式类型声明、时间字面量的使用(规避隐式转换);
- 画圆逻辑的数学原理与参数配置;
- 定时器与发布者的协同逻辑;
- 多终端联动的效果验证。
掌握这些内容后,你可以基于C++高效实现各类话题发布场景(如运动控制指令下发、传感器数据广播等),并与Python节点形成多语言协同的ROS2项目,灵活控制机器人执行复杂运动任务。
