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++功能包:
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::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项目,灵活控制机器人执行复杂运动任务。