您正在阅读的是旧版本但仍受支持的 ROS 2 文档。 Jazzy.
实施自定义接口
目标 了解在 ROS 2 中实现自定义接口的更多方法。
辅导水平: 初学者
时间 15 分钟
背景介绍
在一个 上一个教程您已学会如何创建自定义 msg 和 srv 接口。
虽然最佳做法是在专门的接口包中声明接口,但有时在一个包中声明、创建和使用接口也很方便。
回想一下,接口目前只能在 CMake 包中定义。不过,可以在 CMake 包中加入 Python 库和节点(使用 ament_cmake_python),因此您可以在一个软件包中定义接口和 Python 节点。为了简单起见,我们在这里使用 CMake 包和 C++ 节点。
本教程的重点是 msg 接口类型,但这里的步骤适用于所有接口类型。
先决条件
我们假设您已在 创建自定义 msg 和 srv 文件 在学习本教程之前,请先阅读本教程。
您应该 已安装 ROS 2, a 工作区并了解 创建软件包.
与往常一样,不要忘记 源 ROS 2 在您打开的每个新终端中。
任务
1 创建软件包
在您的工作区 来源
目录下,创建一个包 更多接口
并在其中建立一个 msg 文件目录:
ros2 pkg create --build-type ament_cmake --license Apache-2.0 more_interfaces
mkdir more_interfaces/msg
2 创建 msg 文件
内部 more_interfaces/msg
, 创建一个新文件 地址簿.msg
然后粘贴以下代码,创建一条用于传递个人相关信息的信息:
uint8 家庭电话类型=0
uint8 工作电话类型=1
uint8 手机类型=2
字符串 名
字符串 姓氏
字符串 电话号码
uint8 电话类型
该信息由以下字段组成:
first_name:字符串类型
last_name:字符串类型
电话号码:字符串类型
phone_type:uint8 类型,定义了多个命名常量值
请注意,可以为信息定义中的字段设置默认值。请参阅 接口 了解更多自定义界面的方法。
接下来,我们需要确保将 msg 文件转化为 C++、Python 和其他语言的源代码。
2.1 建立 msg 文件
开放 package.xml
并添加以下几行:
构建工具的依赖关系<buildtool_depend>;默认生成器</buildtool_depend>;
执行依赖关系;默认运行时间</exec_depend>;
<member_of_group>;接口包</member_of_group>;
请注意,在构建时,我们需要 默认生成器
而在运行时,我们只需要 默认运行时间
.
开放 CMakeLists.txt
并添加以下几行:
查找从 msg/srv 文件生成信息代码的软件包:
查找软件包(默认生成器 要求)
声明要生成的信息列表:
设置(msg_files
"msg/AddressBook.msg";
)
通过手动添加 .msg 文件,我们可以确保 CMake 在添加其他 .msg 文件后知道何时需要重新配置项目。
生成信息:
生成接口(${项目名称}
${msg_files}
)
同时确保导出了消息运行时依赖项:
ament_export_dependencies(默认运行时间)
现在你可以根据 msg 定义生成源文件了。我们暂时跳过编译步骤,因为我们将在下文第 4 步中一并完成。
2.2 (额外)设置多个接口
备注
您可以使用 设置
于 CMakeLists.txt
来整齐地列出所有接口:
设置(msg_files
"msg/Message1.msg";
"msg/Message2.msg";
# 等等
)
设置(srv_files
"srv/Service1.srv";
"srv/Service2.srv";
# 等等
)
然后像这样一次性生成所有列表:
生成接口(${项目名称}
${msg_files}
${srv_files}
)
3 使用同一软件包中的接口
现在我们可以开始编写使用这条信息的代码了。
在 more_interfaces/src
创建一个名为 publish_address_book.cpp
并粘贴以下代码:
#include 时间顺序<chrono>;
#include <内存>;
#include "rclcpp/rclcpp.hpp";
#include "more_interfaces/msg/address_book.hpp";
使用 命名空间 标准::计时器;
类 地址簿发布者 : 公 rclcpp::节点
{
公:
地址簿发布者()
: 节点("address_book_publisher";)
{
地址簿出版商 =
此->;创建出版商<;更多接口::信息::地址簿>;("address_book";, 10);
汽车 publish_msg = [此]() ->; 空白 {
汽车 信息 = 更多接口::信息::地址簿();
信息.名 = "约翰";;
信息.姓氏 = 无名氏;;
信息.电话号码 = "1234567890";
信息.电话类型 = 信息.手机类型;
标准::cout <<; 出版联系人\n首先:"; <<; 信息.名 <<;
" Last:"; <<; 信息.姓氏 <<; 标准::endl;
此->;地址簿出版商->;发布(信息);
};
定时器 = 此->;创建隔离墙计时器(1s, publish_msg);
}
私人:
rclcpp::出版商<;更多接口::信息::地址簿>::SharedPtr 地址簿出版商;
rclcpp::定时器基数::SharedPtr 定时器;
};
int 主要(int 参数, 烧焦 * 参数[])
{
rclcpp::启动(参数, 参数);
rclcpp::后旋(标准::共享<;地址簿发布者>;());
rclcpp::关闭();
返回 0;
}
3.1 法规解释
包括我们新创建的 地址簿.msg
.
#include "more_interfaces/msg/address_book.hpp";
创建一个节点和一个 地址簿
出版商
使用 命名空间 标准::计时器;
类 地址簿发布者 : 公 rclcpp::节点
{
公:
地址簿发布者()
: 节点("address_book_publisher";)
{
地址簿出版商 =
此->;创建出版商<;更多接口::信息::地址簿>;("address_book";);
创建一个回调,定期发布信息。
汽车 publish_msg = [此]() ->; 空白 {
创建一个 地址簿
我们稍后将发布该消息实例。
汽车 信息 = 更多接口::信息::地址簿();
填充 地址簿
领域。
信息.名 = "约翰";;
信息.姓氏 = 无名氏;;
信息.电话号码 = "1234567890";
信息.电话类型 = 信息.手机类型;
最后定期发送信息。
标准::cout <<; 出版联系人\n首先:"; <<; 信息.名 <<;
" Last:"; <<; 信息.姓氏 <<; 标准::endl;
此->;地址簿出版商->;发布(信息);
创建一个 1 秒计时器,调用我们的 publish_msg
每秒执行一次。
定时器 = 此->;创建隔离墙计时器(1s, publish_msg);
3.2 建立出版商
我们需要在 CMakeLists.txt
:
查找软件包(rclcpp 要求)
添加可执行(发布地址簿 src/publish_address_book.cpp)
ament_target_dependencies(发布地址簿 rclcpp)
安装(目标
发布地址簿
目的地 lib/${项目名称})
3.3 接口链接
为了使用同一软件包中生成的信息,我们需要使用以下 CMake 代码:
rosidl_get_typesupport_target(cpp_typesupport_target
${项目名称} rosidl_typesupport_cpp)
目标链接库(发布地址簿 "${cpp_typesupport_target}";)
这将从 地址簿.msg
并允许目标对其进行链接。
你可能已经注意到,当使用的接口来自独立构建的不同软件包时,这一步是不必要的。只有当你想使用与定义接口的软件包相同的接口时,才需要这段 CMake 代码。
4 试用
返回工作区的根目录以构建软件包:
cd ~/ros2_ws
colcon build --packages-up-to more_interfaces
cd ~/ros2_ws
colcon build --packages-up-to more_interfaces
cd /ros2_ws
colcon build --merge-install --packages-up-to more_interfaces
然后创建工作区并运行发布器:
source install/local_setup.bash
ros2 run more_interfaces publish_address_book
install/local_setup.bash
ros2 run more_interfaces publish_address_book
调用 install/local_setup.bat
ros2 run more_interfaces publish_address_book
或者使用 Powershell:
install/local_setup.ps1
ros2 run more_interfaces publish_address_book
您应该会看到发布者转发您定义的 msg,包括您在 publish_address_book.cpp
.
确认信息正在 地址簿
主题,打开另一个终端,获取工作区的源代码,然后调用 主题 回响
:
source install/setup.bash
ros2 topic echo /address_book
install/setup.bash
ros2 topic echo /address_book
调用 install/setup.bat
ros2 topic echo /address_book
或者使用 Powershell:
install/setup.ps1
ros2 topic echo /address_book
在本教程中,我们不会创建订阅程序,但您可以尝试自己编写一个订阅程序进行练习(使用 编写简单的发布器和订阅器(C++) 帮助)。
5(额外)使用现有接口定义
备注
你可以在新的接口定义中使用现有的接口定义。例如,假设有一条名为 联系信息
的 ROS 2 软件包。 ROSIDL_Tutorials_MSGS
.假设它的定义与我们定制的 地址簿.msg
接口。
在这种情况下,您可以定义 地址簿.msg
(软件包中的一个接口 与 你的节点)的类型为 联系方式
(的一个接口 单独 软件包)。您甚至可以定义 地址簿.msg
作为 矩阵 属于 联系方式
就像这样:
ROSIDL_Tutorials_MSGS/联系方式[] 地址簿
要生成这条信息,您需要声明依赖于 联系信息
包装 ROSIDL_Tutorials_MSGS
在 package.xml
:
构建依赖关系;ROSIDL_Tutorials_MSGS</build_depend>;
执行依赖关系;ROSIDL_Tutorials_MSGS</exec_depend>;
而在 CMakeLists.txt
:
查找软件包(ROSIDL_Tutorials_MSGS 要求)
生成接口(${项目名称}
${msg_files}
依赖 ROSIDL_Tutorials_MSGS
)
您还需要包含 联系信息
在您的发布者节点中添加 联系人
到您的 地址簿
.
#include "rosidl_tutorials_msgs/msg/contact.hpp";
您可以将回调改成类似这样:
汽车 publish_msg = [此]() ->; 空白 {
汽车 信息 = 标准::共享<;更多接口::信息::地址簿>;();
{
ROSIDL_Tutorials_MSGS::信息::联系方式 联系;
联系.名 = "约翰";;
联系.姓氏 = 无名氏;;
联系.电话号码 = "1234567890";
联系.电话类型 = 信息.手机类型;
信息->;地址簿.推回(联系);
}
{
ROSIDL_Tutorials_MSGS::信息::联系方式 联系;
联系.名 = "简";;
联系.姓氏 = 无名氏;;
联系.电话号码 = "4254242424";
联系.电话类型 = 信息.家庭电话类型;
信息->;地址簿.推回(联系);
}
标准::cout <<; 发布地址簿:"; <<; 标准::endl;
对于 (汽车 联系 : 信息->;地址簿) {
标准::cout <<; "第一:"; <<; 联系.名 <<; " Last:"; <<; 联系.姓氏 <<;
标准::endl;
}
地址簿出版商->;发布(*信息);
};
构建并运行这些更改后,将显示所定义的 msg 和上面定义的 msg 数组。
摘要
在本教程中,您尝试了定义接口的不同字段类型,然后在使用接口的同一软件包中构建了一个接口。
您还学习了如何使用另一个界面作为字段类型,以及 package.xml
, CMakeLists.txt
和 #include
使用该功能所需的语句。
下一步工作
接下来,您将创建一个简单的 ROS 2 软件包,并学习从启动文件中设置自定义参数。同样,你可以选择以 C++ 或 Python.