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

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++功能包:

bash 复制代码
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

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 复制代码
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 构建整个工作空间

回到工作空间根目录,执行构建:

bash 复制代码
cd ~/ros2_ws
colcon build

5.2 启动完整流程(三个终端)

终端1:启动海龟模拟器

bash 复制代码
cd ~/ros2_ws
source install/setup.bash
ros2 run turtlesim turtlesim_node

终端2:启动C++发布者节点

bash 复制代码
cd ~/ros2_ws
source install/setup.bash
ros2 run demo_cpp_topic circle_pub

终端3(可选):查看话题数据

bash 复制代码
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项目,灵活控制机器人执行复杂运动任务。

相关推荐
..过云雨3 小时前
11.【Linux系统编程】文件系统详解——从磁盘硬件到文件系统
linux·c++·后端·缓存
码住懒羊羊3 小时前
【C++】模板进阶 | 继承
android·java·c++
yong99903 小时前
C++语法—类的声明和定义
开发语言·c++·算法
狂奔的sherry3 小时前
构造/析构/赋值运算理解
开发语言·c++
大佬,救命!!!3 小时前
C++多线程运行整理
开发语言·c++·算法·学习笔记·多线程·新手练习
蜗牛沐雨4 小时前
C++ 输出流(Output Stream)全解析
开发语言·c++
小白讲编程5 小时前
C++ 基础学习总结:从入门到构建核心认知
c++·学习·青少年编程
L_09075 小时前
【Algorithm】Day-10
c++·算法·leetcode
15Moonlight5 小时前
09-MySQL内外连接
数据库·c++·mysql