编写简单的发布器和订阅器(C++)
目标 使用 C++ 创建并运行一个发布者和订阅者节点。
辅导水平: 初学者
时间 20 分钟
背景介绍
节点 是通过 ROS 图进行通信的可执行进程。在本教程中,节点将以字符串信息的形式通过 主题.这里使用的示例是一个简单的 "说者 "和 "听者 "系统;一个节点发布数据,另一个节点订阅主题以便接收数据。
这些示例中使用的代码如下 这里.
先决条件
任务
1 创建软件包
打开一个新终端,然后 为您的 ROS 2 安装提供源代码 以便 玫瑰2
命令即可运行。
导航进入 ros2_ws
目录中创建的 上一个教程.
回顾一下,软件包应在 来源
目录,而不是工作区的根目录。因此,导航到 ros2_ws/src
然后运行软件包创建命令:
ros2 pkg create --build-type ament_cmake --license Apache-2.0 cpp_pubsub
您的终端将返回一条信息,验证是否创建了软件包 cpp_pubsub
及其所有必要的文件和文件夹。
导航进入 ros2_ws/src/cpp_pubsub/src
.请注意,这是 CMake 软件包中包含可执行文件的源文件所在的目录。
2 写入发布节点
输入以下命令下载通话代码示例:
wget -O publisher_lambda_function.cpp https://raw.githubusercontent.com/ros2/examples/jazzy/rclcpp/topics/minimal_publisher/lambda.cpp
wget -O publisher_lambda_function.cpp https://raw.githubusercontent.com/ros2/examples/jazzy/rclcpp/topics/minimal_publisher/lambda.cpp
在 Windows 命令行提示符下:
curl -sk https://raw.githubusercontent.com/ros2/examples/jazzy/rclcpp/topics/minimal_publisher/lambda.cpp -o publisher_lambda_function.cpp
或使用 powershell:
curl https://raw.githubusercontent.com/ros2/examples/jazzy/rclcpp/topics/minimal_publisher/lambda.cpp -o publisher_lambda_function.cpp
现在将有一个名为 publisher_lambda_function.cpp
.使用您喜欢的文本编辑器打开文件。
#include 时间顺序<chrono>;
#include <内存>;
#include <字符串>;
#include "rclcpp/rclcpp.hpp";
#include "std_msgs/msg/string.hpp";
使用 命名空间 标准::计时器;
/* 本例创建了 Node 的子类,并使用了花哨的 C++11 lambda
* 函数来缩短回调语法,但代价是使
* 代码乍一看有些难以理解。*/
类 最小出版商 : 公 rclcpp::节点
{
公:
最小出版商()
: 节点("minimal_publisher";), count_(0)
{
出版商_ = 此->;创建出版商<;std_msgs::信息::字符串>;("主题";, 10);
汽车 定时器回调 =
[此]() ->; 空白 {
汽车 信息 = std_msgs::信息::字符串();
信息.数据 = 世界,你好!"; + 标准::to_string(此->;count_++);
RCLCPP_INFO(此->;get_logger(), "出版:'%s'";, 信息.数据.c_str());
此->;出版商_->;发布(信息);
};
定时器 = 此->;创建隔离墙计时器(500毫秒, 定时器回调);
}
私人:
rclcpp::定时器基数::SharedPtr 定时器;
rclcpp::出版商<;std_msgs::信息::字符串>::SharedPtr 出版商_;
size_t count_;
};
int 主要(int 参数, 烧焦 * 参数[])
{
rclcpp::启动(参数, 参数);
rclcpp::后旋(标准::共享<;最小出版商>;());
rclcpp::关闭();
返回 0;
}
2.1 检查代码
代码顶部包含您将使用的标准 C++ 头文件。标准 C++ 头文件之后是 rclcpp/rclcpp.hpp
include 允许你使用 ROS 2 系统中最常用的组件。最后是 std_msgs/msg/string.hpp
,其中包括用于发布数据的内置消息类型。
#include 时间顺序<chrono>;
#include <内存>;
#include <字符串>;
#include "rclcpp/rclcpp.hpp";
#include "std_msgs/msg/string.hpp";
使用 命名空间 标准::计时器;
这些线条代表节点的依赖关系。请注意,必须将依赖关系添加到 package.xml
和 CMakeLists.txt
您将在下一节中完成这一操作。
下一行创建节点类 最小出版商
继承自 rclcpp::Node
.每 此
是指节点。
类 最小出版商 : 公 rclcpp::节点
公共构造函数为节点命名 最小出版商
并初始化 count_
初始化为 0。 字符串
消息类型、主题名称 主题
以及所需的队列大小,以便在备份时限制信息。下一步是 羊羔函数 人称 定时器回调
声明。它对当前对象执行旁引用捕获 此
不需要输入参数,返回 void。返回 定时器回调
函数会创建一个类型为 字符串
,将其数据设置为所需字符串并发布。该 RCLCPP_INFO
宏确保每一条发布的信息都会打印到控制台。最后 定时器
被初始化,这会导致 定时器回调
函数每秒执行两次。
公:
最小出版商()
: 节点("minimal_publisher";), count_(0)
{
出版商_ = 此->;创建出版商<;std_msgs::信息::字符串>;("主题";, 10);
汽车 定时器回调 =
[此]() ->; 空白 {
汽车 信息 = std_msgs::信息::字符串();
信息.数据 = 世界,你好!"; + 标准::to_string(此->;count_++);
RCLCPP_INFO(此->;get_logger(), "出版:'%s'";, 信息.数据.c_str());
此->;出版商_->;发布(信息);
};
定时器 = 此->;创建隔离墙计时器(500毫秒, 定时器回调);
}
类的底部是定时器、发布者和计数器字段的声明。
私人:
rclcpp::定时器基数::SharedPtr 定时器;
rclcpp::出版商<;std_msgs::信息::字符串>::SharedPtr 出版商_;
size_t count_;
继 最小出版商
类是 主要
,节点实际执行的位置。
rclcpp::init
初始化 ROS 2,以及 rclcpp::spin
开始处理来自节点的数据,包括来自定时器的回调。
int 主要(int 参数, 烧焦 * 参数[])
{
rclcpp::启动(参数, 参数);
rclcpp::后旋(标准::共享<;最小出版商>;());
rclcpp::关闭();
返回 0;
}
2.2 添加依赖项
导航一级回到 ros2_ws/src/cpp_pubsub
目录中的 CMakeLists.txt
和 package.xml
文件已为您创建。
开放 package.xml
使用文本编辑器。
正如 上一个教程请确保填写 <描述>;
, <维护者>;
和 许可证
标签
<描述>;实例 的 极少 出版商/订户 使用 rclcpp</description>;
维护者 电子邮件="[email protected]";>;您的 名称维护人员</maintainer>;
许可证Apache-2.0</license>;
在 ament_cmake
buildtool 依赖关系,并粘贴与节点的 include 语句相对应的下列依赖关系:
<依赖>;rclcpp依赖</depend>;
<依赖>;std_msgs依赖</depend>;
这就声明了软件包需要 rclcpp
和 std_msgs
在构建和执行代码时。
确保保存文件。
2.3 CMakeLists.txt
现在打开 CMakeLists.txt
文件。在现有依赖关系的下方 find_package(ament_cmake 必填)
添加这几行:
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
然后,添加可执行文件并将其命名为 话匣子
这样您就可以使用 玫瑰2 运行
:
add_executable(talker src/publisher_lambda_function.cpp)
ament_target_dependencies(talker rclcpp std_msgs)
最后,添加 install(TARGETS...)
因此 玫瑰2 运行
能找到你的可执行文件:
install(TARGETS
话匣子
DESTINATION lib/${PROJECT_NAME})
您可以清理您的 CMakeLists.txt
删除了一些不必要的部分和注释,所以看起来像这样:
cmake_minimum_required(VERSION 3.5)
项目(cpp_pubsub)
# 默认值 至 C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
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(std_msgs REQUIRED)
add_executable(talker src/publisher_lambda_function.cpp)
ament_target_dependencies(talker rclcpp std_msgs)
install(TARGETS
话匣子
DESTINATION lib/${PROJECT_NAME})
ament_package()
你可以现在就构建你的软件包,获取本地设置文件,然后运行它,但让我们先创建用户节点,这样你就能看到整个系统的运行情况。
3 写入用户节点
返回 ros2_ws/src/cpp_pubsub/src
来创建下一个节点。在终端中输入以下代码
wget -O subscriber_lambda_function.cpp https://raw.githubusercontent.com/ros2/examples/jazzy/rclcpp/topics/minimal_subscriber/lambda.cpp
wget -O subscriber_lambda_function.cpp https://raw.githubusercontent.com/ros2/examples/jazzy/rclcpp/topics/minimal_subscriber/lambda.cpp
在 Windows 命令行提示符下:
curl -sk https://raw.githubusercontent.com/ros2/examples/jazzy/rclcpp/topics/minimal_subscriber/lambda.cpp -o subscriber_lambda_function.cpp
或使用 powershell:
curl https://raw.githubusercontent.com/ros2/examples/jazzy/rclcpp/topics/minimal_subscriber/lambda.cpp -o subscriber_lambda_function.cpp
检查以确保这些文件存在:
publisher_lambda_function.cpp subscriber_lambda_function.cpp
打开 subscriber_lambda_function.cpp
使用文本编辑器。
#include <内存>;
#include "rclcpp/rclcpp.hpp";
#include "std_msgs/msg/string.hpp";
类 最小订阅者 : 公 rclcpp::节点
{
公:
最小订阅者()
: 节点("minimal_subscriber";)
{
汽车 topic_callback =
[此](std_msgs::信息::字符串::UniquePtr 信息) ->; 空白 {
RCLCPP_INFO(此->;get_logger(), "我听说:'%s'";, 信息->;数据.c_str());
};
订阅_ =
此->;创建订阅<;std_msgs::信息::字符串>;("主题";, 10, topic_callback);
}
私人:
rclcpp::订阅<;std_msgs::信息::字符串>::SharedPtr 订阅_;
};
int 主要(int 参数, 烧焦 * 参数[])
{
rclcpp::启动(参数, 参数);
rclcpp::后旋(标准::共享<;最小订阅者>;());
rclcpp::关闭();
返回 0;
}
3.1 检查代码
订阅者节点的代码与发布者节点几乎完全相同。现在节点被命名为 最小订阅者
,构造函数使用节点的 创建订阅
函数来执行回调。
没有计时器,因为订阅者只需在数据发布到 主题
主题。
"(《世界人权宣言》) topic_callback
函数接收通过主题发布的字符串消息数据,并使用 RCLCPP_INFO
宏观。
回顾 主题教程 发布者和订阅者使用的主题名称和信息类型必须匹配,才能进行通信。
公:
最小订阅者()
: 节点("minimal_subscriber";)
{
汽车 topic_callback =
[此](std_msgs::信息::字符串::UniquePtr 信息) ->; 空白 {
RCLCPP_INFO(此->;get_logger(), "我听说:'%s'";, 信息->;数据.c_str());
};
订阅_ =
此->;创建订阅<;std_msgs::信息::字符串>;("主题";, 10, topic_callback);
}
该类中唯一的字段声明是订阅。
私人:
rclcpp::订阅<;std_msgs::信息::字符串>::SharedPtr 订阅_;
"(《世界人权宣言》) 主要
函数完全相同,只不过现在它会旋转 最小订阅者
节点。对发布节点来说,旋转意味着启动定时器,但对订阅节点来说,旋转只是意味着准备随时接收信息。
由于该节点与发布者节点具有相同的依赖关系,因此没有什么新内容需要添加到 package.xml
.
3.2 CMakeLists.txt
重新开放 CMakeLists.txt
并在发布者条目下方为订阅者节点添加可执行文件和目标。
添加可执行(听众 src/subscriber_lambda_function.cpp)
ament_target_dependencies(听众 rclcpp std_msgs)
安装(目标
话匣子
听众
目的地 lib/${项目名称})
确保保存文件,然后你的发布/分站系统就应该准备就绪了。
4 构建和运行
您可能已经拥有 rclcpp
和 std_msgs
软件包是 ROS 2 系统的一部分。运行 rosdep
在工作区的根目录 (ros2_ws
) 在构建前检查是否缺少依赖项:
rosdep install -i --from-path src --rosdistro jazzy -y
rosdep 只能在 Linux 上运行,因此可以跳到下一步。
rosdep 只能在 Linux 上运行,因此可以跳到下一步。
还是在工作区的根目录下、 ros2_ws
, 构建您的新软件包:
colcon build --packages-select cpp_pubsub
colcon build --packages-select cpp_pubsub
colcon build --merge-install --packages-select cpp_pubsub
打开一个新终端,导航至 ros2_ws
并获取设置文件:
install/setup.bash
install/setup.bash
调用 install/setup.bat
现在运行 Talker 节点:
ros2 运行 cpp_pubsub talker
终端应该开始每 0.5 秒发布一次信息,就像这样:
[INFO] [minimal_publisher]:Publishing: "Hello World: 0";
[INFO] [minimal_publisher]:Publishing: "Hello World: 1";
[INFO] [minimal_publisher]:Publishing: "Hello World: 2";
[INFO] [minimal_publisher]:Publishing: "Hello World: 3";
[INFO] [minimal_publisher]:Publishing: "Hello World: 4";
打开另一个终端,从里面获取设置文件的源代码 ros2_ws
然后启动监听节点:
ros2 运行 cpp_pubsub 监听器
监听器将开始向控制台打印消息,从发布者当时的消息计数开始,就像这样:
[INFO] [minimal_subscriber]:我听到: "Hello World: 10";
[INFO] [minimal_subscriber]:我听到: "Hello World: 11";
[INFO] [minimal_subscriber]:我听到: "Hello World: 12";
[INFO] [minimal_subscriber]:我听到: "Hello World: 13";
[INFO] [minimal_subscriber]:我听到: "Hello World: 14";
进入 Ctrl+C
以阻止节点旋转。
摘要
您创建了两个节点,用于通过主题发布和订阅数据。在编译和运行它们之前,您在软件包配置文件中添加了它们的依赖项和可执行文件。