ROS2系列 (10) : C++话题通信节点——发布者示例

在前两篇Python话题通信的基础上,本文将聚焦C++话题发布者的实现,通过“控制海龟模拟器画圆”的案例,详解C++节点中话题发布者、定时器的配置流程,并将其集成到现有工作空间,形成多语言协同的ROS2项目。

一、需求与技术拆解

功能需求:控制turtlesim海龟模拟器中的海龟,按指定半径画圆。

需解决的核心问题:

  • 如何创建C++功能包?—— 使用ros2 pkg create指定ament_cmake构建类型,依赖rclcppgeometry_msgsturtlesim
  • 如何发布话题?—— 利用rclcppcreate_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队列大小10
    publisher_ = 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);  // 初始化rclcpp
      auto node = std::make_shared<TurtleCircle>("turtle_circle");  // 显式创建节点实例
        rclcpp::spin(node);       // 保持节点运行
        rclcpp::shutdown();       // 关闭rclcpp
        return 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(TARGETS
  circle_pub
  DESTINATION 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::SharedPtrPublisher::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项目,灵活控制机器人执行复杂运动任务。