
ROS 系列学习教程(总目录)
ROS2 系列学习教程(总目录)
目录
- 一、创建自定义话题C++版
-
- [1.1 创建功能包](#1.1 创建功能包)
- [1.2 编辑源文件](#1.2 编辑源文件)
- [1.3 编辑编译配置文件CMakeList.txt](#1.3 编辑编译配置文件CMakeList.txt)
- [1.4 编译工程](#1.4 编译工程)
- [1.5 运行节点](#1.5 运行节点)
话题通信适用于不断更新数据、少逻辑处理的传输相关的应用场景。它是一种单向通讯方式,它通过发布和订阅的方式传递消息,与ROS1相比,该模型只涉及到两个角色:
- Publisher(发布者)
- Subscriber(订阅者)
消息数据由发布者传递到订阅者,如下图:

发布者和订阅者位于节点中,每个节点可以有多个不同的发布者和订阅者,一个节点可以向任意数量的主题发布数据,同时订阅任意数量的主题。发布者和订阅者的关系,不仅仅是一对一,还可以是一对多,多对一,多对多的关系。

一、创建自定义话题C++版
我们创建一个新的功能包来演示topic相关操作
1.1 创建功能包
bash
cd ros2_learning/src
ros2 pkg create --build-type ament_cmake hello_world_topic_cpp
其中,
使用 --build-type
指定编译系统为 ament_cmake
hello_world_topic_cpp:自定义功能包名称
结果如下图:

其中,有 [WARNING]: Unknown license 'TODO: License declaration'.
ROS2建议创建一个 License 文件以说明该功能包的发布许可。可以使用 --license LICENSE
参数指定,例如:
bash
ros2 pkg create --build-type ament_cmake --license Apache-2.0 hello_world_topic_cpp
生成的目录结构如下:
bash
hello_world_topic_cpp
├── CMakeLists.txt
├── include
│ └── hello_world_topic_cpp
├── LICENSE
├── package.xml
└── src
1.2 编辑源文件
我们需要编写一个发布者(talker)和一个订阅者(listener),让他们在不同的节点,分别发布topic和订阅topic。
在 hello_world_topic_cpp/include
目录下新增 talker.h
文件,文件内容如下:
cpp
#ifndef __HELLO_WORLD_TOPIC_TALKER_H__
#define __HELLO_WORLD_TOPIC_TALKER_H__
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
class CTalker : public rclcpp::Node
{
public:
CTalker();
~CTalker();
private:
void timercallback();
private:
rclcpp::TimerBase::SharedPtr m_timer;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr m_publisher;
size_t m_count;
};
#endif // __HELLO_WORLD_TOPIC_TALKER_H__
在 hello_world_topic_cpp/src
目录下新增 talker.cpp
文件,文件内容如下:
c++
#include "hello_world_topic_cpp/talker.h"
using namespace std::chrono_literals;
CTalker::CTalker() : Node("talker_node"), m_count(0)
{
m_publisher = this->create_publisher<std_msgs::msg::String>("/hello_world_topic", 10);
m_timer = this->create_wall_timer(500ms, std::bind(&CTalker::timercallback, this));
}
CTalker::~CTalker()
{
}
void CTalker::timercallback()
{
auto message = std_msgs::msg::String();
message.data = "Hello world ROS2 Topic! " + std::to_string(this->m_count++);
RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
this->m_publisher->publish(message);
}
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
auto talker_node = std::make_shared<CTalker>();
rclcpp::spin(talker_node);
rclcpp::shutdown();
return 0;
}
在 hello_world_topic_cpp/include
目录下新增 listener.h
文件,文件内容如下:
cpp
#ifndef __HELLO_WORLD_TOPIC_LISTENER_H__
#define __HELLO_WORLD_TOPIC_LISTENER_H__
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
class CListener : public rclcpp::Node
{
public:
CListener();
~CListener();
private:
void topic_callback(const std_msgs::msg::String & msg) const;
private:
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr m_subscriber;
};
#endif // __HELLO_WORLD_TOPIC_LISTENER_H__
在 hello_world_topic_cpp/src
目录下新增 listener.cpp
文件,文件内容如下:
cpp
#include "hello_world_topic_cpp/listener.h"
CListener::CListener() : Node("listener_node")
{
m_subscriber = this->create_subscription<std_msgs::msg::String>("/hello_world_topic", 10,
std::bind(&CListener::topic_callback, this, std::placeholders::_1));
}
CListener::~CListener()
{
}
void CListener::topic_callback(const std_msgs::msg::String &msg) const
{
RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg.data.c_str());
}
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
auto listener_node = std::make_shared<CListener>();
rclcpp::spin(listener_node);
rclcpp::shutdown();
return 0;
}
1.3 编辑编译配置文件CMakeList.txt
默认生成的 CMakeList.txt 文件内容如下:

由于新增了talker
和 listener
,所以要配置该文件的编译规则。
找到ros2_learning/src/hello_world_topic_cpp/CMakeLists.txt
,修改如下:

修改说明如下:
cmake
# 指定头文件目录
include_directories(
include
)
# 指定源文件,生成可执行文件
add_executable(talker_node src/talker.cpp)
# 指定可执行文件的依赖项
ament_target_dependencies(talker_node rclcpp std_msgs)
# 定义安装规则,指定可执行文件的安装目录
install(TARGETS
talker_node
DESTINATION lib/${PROJECT_NAME}
)
add_executable(listener_node src/listener.cpp)
ament_target_dependencies(listener_node rclcpp std_msgs)
install(TARGETS
listener_node
DESTINATION lib/${PROJECT_NAME}
)
1.4 编译工程
进入到工作空间 ros2_learning 目录,执行如下指令编译该工程:
bash
colcon build
编译成功后,会在ros2_learning目录下生成 build
、install
和 log
目录。
- **build:**存放编译过程中产生的中间文件,包括临时文件、对象文件、依赖关系等。用户通常不需要直接访问这个目录,因为构建工具会自动管理其中的内容。然而,在调试构建问题时,有时可能需要查看这个目录中的文件以获取更多信息。
- **install:**存放最终编译生成的可执行文件、库文件、配置文件、环境设置文件等资源。这些资源是构建完成后准备发布的独立包,可以被其他项目或用户直接使用。通常包含多个子目录,如bin(可执行文件)、lib(库文件)、share(配置文件、资源文件等)等。用户可以在 install 目录中查找可执行文件或库文件来运行或链接ROS2节点或服务。此外,ROS2环境设置文件(如setup.bash)也存放在该目录,用于将ROS2包添加到用户的 PATH 和其他环境变量中。
- **log:**存放编译和运行过程中产生的各种日志信息。这些日志信息包括警告、错误、信息等,对于调试和监控 ROS2 系统的运行状态非常有用。这些日志文件可以是文本文件,也可以是其他格式的文件,具体取决于 ROS2 日志系统的配置。用户可以通过查看log目录中的日志文件来了解 ROS2 系统在编译或运行过程中的行为。此外,ROS2 还提供了日志查看工具(如rqt_console),这些工具可以方便地查看和分析日志文件中的内容。
1.5 运行节点
ROS2 提供了 run
命令,可以根据包名和节点名,在任何目录执行。
但需要先设置环境变量,即让系统可以找到节点,进入到工作空间目录,执行如下指令:
bash
source install/setup.bash
运行如下命令分别启动发布者和订阅者节点:
bash
ros2 run hello_world_topic_cpp talker_node
ros2 run hello_world_topic_cpp listener_node
启动节点后,打印如下:
