ROS开发专栏---话题 Topic + 消息 Message 完整实战---适配Ubuntu 22.04

🎬 渡水无言个人主页渡水无言

专栏传送门 : 《linux专栏》《嵌入式linux驱动开发》《linux系统移植专栏》

专栏传送门 : 《freertos专栏》 《STM32 HAL库专栏》《linux裸机开发专栏

专栏传送门《产品测评专栏》 《Ai智能体专栏) 《ROS开发专栏

⭐️流水不争先,争的是滔滔不绝

📚博主简介:第二十届中国研究生电子设计竞赛全国二等奖 |国家奖学金 | 省级三好学生

| 省级优秀毕业生获得者 | csdn新星杯TOP18 | 半导纵横专栏博主 | 211在读研究生

在这里主要分享自己学习的linux嵌入式领域知识;有分享错误或者不足的地方欢迎大佬指导,也欢迎各位大佬互相三连

目录

前言

[一、话题 Topic 与消息 Message 基本概念](#一、话题 Topic 与消息 Message 基本概念)

二、创建话题通信软件包

[三、编写发布者节点 Publisher以及订阅者节点 Subscriber](#三、编写发布者节点 Publisher以及订阅者节点 Subscriber)

[3.1、编写发布者节点 Publisher](#3.1、编写发布者节点 Publisher)

[3.2、编写订阅者节点 Subscriber](#3.2、编写订阅者节点 Subscriber)

四、编译配置

[4.1 修改 CMakeLists.txt](#4.1 修改 CMakeLists.txt)

[4.2、修改 package.xml](#4.2、修改 package.xml)

五、编译与运行测试

总结


前言

上一节我们成功创建了第一个 ROS2 节点 Hello World,学会了软件包、节点、编译与运行的基础流程。

但在真实机器人系统中,一个节点无法完成所有工作 。雷达、相机、底盘、导航、建图...... 都需要多个节点协同工作

节点之间如何传递数据?最常用、最核心的方式就是 ------话题(Topic)通信


一、话题 Topic 与消息 Message 基本概念

在 ROS2 中,节点与节点之间最常用的通信方式就是话题(Topic)+ 消息(Message)

话题 Topic = 一个网络聊天室

发布者 Publisher = 在聊天室里发消息的人

订阅者 Subscriber = 在聊天室里看消息的人

消息 Message = 发送的具体内容

如下图所示:

通信流程也非常简单:

发布者把数据打包成消息,发送到话题。

订阅者订阅这个话题,从中取出消息并使用。

二、创建话题通信软件包

首先进入工作空间的 src 目录,创建新包topic_pkg,输入以下代码:

cpp 复制代码
cd ~/ros2_zice/src
ros2 pkg create topic_pkg

创建好如下图所示

这个包将用来存放:

1、发布者节点。

2、订阅者节点。

三、编写发布者节点 Publisher以及订阅者节点 Subscriber

3.1、编写发布者节点 Publisher

topic_pkg/src 下新建publisher_node.cpp,输入以下代码:

cpp 复制代码
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

int main(int argc, char * argv[])
{
  // 初始化ROS2
  rclcpp::init(argc, argv);

  // 创建节点
  auto node = std::make_shared<rclcpp::Node>("publisher_node");

  // 创建发布者:话题名 /my_topic,队列长度10
  auto publisher = node->create_publisher<std_msgs::msg::String>("/my_topic", 10);

  // 定义消息内容
  std_msgs::msg::String message;
  message.data = "Hello World!";

  // 1秒发一次
  rclcpp::Rate loop_rate(1);

  // 循环发布
  while (rclcpp::ok())
  {
    publisher->publish(message);
    loop_rate.sleep();
  }

  // 关闭ROS2
  rclcpp::shutdown();
  return 0;
}

3.2、编写订阅者节点 Subscriber

topic_pkg/src 下新建:subscriber_node.cpp,输入以下代码:

cpp 复制代码
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

// 全局节点指针(给回调函数用)
std::shared_ptr<rclcpp::Node> node;

// 订阅回调函数:收到消息就会进入这里
void Callback(const std_msgs::msg::String::SharedPtr msg)
{
    RCLCPP_INFO(node->get_logger(),"Receive : %s", msg->data.c_str());
}

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);

  // 创建节点
  node = std::make_shared<rclcpp::Node>("subscriber_node");

  // 创建订阅者:订阅 /my_topic
  auto subscriber = node->create_subscription<std_msgs::msg::String>(
    "/my_topic", 10, &Callback);

  // 保持节点运行
  rclcpp::spin(node);

  rclcpp::shutdown();
  return 0;
}

四、编译配置

4.1 修改 CMakeLists.txt

打开 topic_pkg/CMakeLists.txt在原有模板基础上添加

cpp 复制代码
# 查找依赖
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

# 编译发布者
add_executable(publisher_node src/publisher_node.cpp)
ament_target_dependencies(publisher_node "rclcpp" "std_msgs")

# 编译订阅者
add_executable(subscriber_node src/subscriber_node.cpp)
ament_target_dependencies(subscriber_node "rclcpp" "std_msgs")

# 安装到lib目录
install(TARGETS
  publisher_node
  subscriber_node
  DESTINATION lib/${PROJECT_NAME}
)

最后代码如下:

cpp 复制代码
cmake_minimum_required(VERSION 3.8)
project(topic_pkg)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# 1. 必须先找基础依赖
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

# 2. 再编译发布者
add_executable(publisher_node src/publisher_node.cpp)
ament_target_dependencies(publisher_node rclcpp std_msgs)

# 3. 再编译订阅者
add_executable(subscriber_node src/subscriber_node.cpp)
ament_target_dependencies(subscriber_node rclcpp std_msgs)

# 4. 再安装
install(TARGETS
  publisher_node
  subscriber_node
  DESTINATION lib/${PROJECT_NAME}
)

# 5. 测试部分放最后
if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  set(ament_cmake_copyright_FOUND TRUE)
  set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

# 6. 必须在文件最后一行
ament_package()

4.2、修改 package.xml

添加依赖:

cpp 复制代码
<depend>rclcpp</depend>
<depend>std_msgs</depend>

最终代码如下:

cpp 复制代码
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>topic_pkg</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="duan@todo.todo">duan</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <depend>rclcpp</depend>
  <depend>std_msgs</depend>


  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

五、编译与运行测试

编译

cpp 复制代码
cd ~/ros2_zice
# 2. 清理旧缓存(如果之前编译过)
rm -rf build install log
colcon build

加载环境变量

cpp 复制代码
source install/setup.bash

# 5. 验证包 build 目录是否生成了目标文件
ls ~/ros2_zice/build/topic_pkg/CMakeFiles/ | grep node

运行测试

新开两个终端,分别执行:

终端1:

cpp 复制代码
# 终端1(发布者)
cd ~/ros2_zice
source install/setup.bash
ros2 run topic_pkg publisher_node

终端2:

cpp 复制代码
# 终端2(订阅者)
cd ~/ros2_zice
source install/setup.bash
ros2 run topic_pkg subscriber_node

订阅者终端会持续输出:Received: Hello World!,说明话题通信跑通了!,如下图所示:


总结

本期博客我们完成了ROS2 节点之间的话题通信。

相关推荐
济6174 小时前
ROS开发专栏---机器人运动控制 ---适配Ubuntu 22.04
嵌入式·ros2·机器人开发
tom021818 小时前
软考中级《嵌入式系统设计师》全套备考资料(真题 + 教材 + 笔记)
笔记·嵌入式·软考·自学·电子技术·电子资料·变成
番茄灭世神1 天前
PN学堂GD32教程第21篇——WiFiIOT
c语言·stm32·单片机·嵌入式·gd32
kobesdu1 天前
【ROS2实战笔记-23】参数系统中的动态参数与远程加载安全剖析
笔记·安全·slam·ros2
NPE~1 天前
[嵌入式]嵌入式在线仿真平台 —— Wokwi 入门指南
stm32·嵌入式·esp32·教程·平台
番茄灭世神1 天前
Vscode开发/调试ARM单片机最新教程
c语言·arm开发·vscode·stm32·嵌入式·gd32
lularible2 天前
从沙子到车辙(3.3):数据通路与控制器的“双人舞“
开源·嵌入式·汽车电子
lularible2 天前
从沙子到车辙(3.5):存储层次
开源·嵌入式·汽车电子
lularible2 天前
从沙子到车辙(3.4):流水线——指令级并行的艺术
开源·嵌入式·汽车电子