手把手做ROS2机器人系统开发(七):扩展ROS2软件包接口
上一讲讲解了如何创建自定义 msg 和 srv 文件对应的接口软件包。本章节延续该内容,进一步扩展 ROS2 软件包的接口:将自定义消息直接定义在节点软件包中,实现软件包功能的扩展。通过本讲,大家可以掌握"接口随包定义、随包编译"的工程化开发方式。
手把手做ROS2机器人系统开发(七):扩展ROS2软件包接口
教程背景
上一讲讲解了如何创建自定义 msg 和 srv 文件对应的接口软件包。本章节延续该内容,进一步扩展 ROS2 软件包的接口:将自定义消息直接定义在节点软件包中,实现软件包功能的扩展。通过本讲,大家可以掌握"接口随包定义、随包编译"的工程化开发方式。
一、程序编写
1. 创建软件包
ros2 pkg create --build-type ament_cmake more_interfaces
2. 创建消息文件夹
在软件包内创建 msg 目录:
mkdir more_interfaces/msg
3. 软件包添加新消息
创建文件 src/more_interfaces/msg/AddressBook.msg,定义通讯录消息:
bool FEMALE=true
bool MALE=false
string first_name
string last_name
bool gender
uint8 age
string address
该消息包含姓名、性别、年龄、地址等字段,并定义了性别枚举常量。
4. 修改软件包设置
编辑 src/more_interfaces/package.xml:
<?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>more_interfaces</name>
<version>0.0.0</version>
<description>more interfaces</description>
<maintainer email="motion_gui@126.com">gmotion</maintainer>
<license>Apache License 2.0</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
5. 修改编译选项
编辑 src/more_interfaces/CMakeLists.txt:
cmake_minimum_required(VERSION 3.8)
project(more_interfaces)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# find dependencies
find_package(ament_cmake REQUIRED)
# 添加ros节点包
find_package(rclcpp REQUIRED)
# 添加消息生成器软件包
find_package(rosidl_default_generators REQUIRED)
# 添加自定义的消息文件
set(msg_files
"msg/AddressBook.msg"
)
# 添加消息接口
rosidl_generate_interfaces(${PROJECT_NAME}
${msg_files}
)
# 添加运行依赖
ament_export_dependencies(rosidl_default_runtime)
# 添加执行路径
add_executable(publish_address_book
src/publish_address_book.cpp
)
ament_target_dependencies(publish_address_book
"rclcpp"
)
# 针对接口内部连接
rosidl_target_interfaces(publish_address_book
${PROJECT_NAME} "rosidl_typesupport_cpp")
# 软件包生成安装包
install(TARGETS publish_address_book
DESTINATION lib/${PROJECT_NAME}
)
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()
ament_package()
6. 编写发布者程序
创建文件 src/more_interfaces/src/publish_address_book.cpp:
/**
* @file publish_address_book.cpp
* @author gmotion (motion_gui@126.com)
* @brief 带接口的发布者程序
* @version 0.1
* @date 2022-06-11
* @copyright gmotion Copyright (c) 2022
*/
#include <iostream> //系统标准接口
#include <chrono> //处理时间类
#include <functional> //函数对象
#include <memory> //内存管理
#include <string> //字符串
#include <rclcpp/rclcpp.hpp>
#include <more_interfaces/msg/address_book.hpp>
using namespace std::chrono_literals;
class AddressBookPublisher : public rclcpp::Node
{
public:
//构造函数
AddressBookPublisher() : Node("address_book_publisher")
{
//初始化发布者
publisher_ = this->create_publisher<more_interfaces::msg::AddressBook>("address_book",10);
//创建回调函数
auto publish_msg=[this]()->void{
auto messgae=more_interfaces::msg::AddressBook();
messgae.first_name="gui";
messgae.last_name="zhiwei";
messgae.age=32;
messgae.gender = messgae.MALE;
messgae.address="unknow";
std::cout << "Publishing Contact\n Name : " << messgae.first_name << messgae.last_name
<<std::endl;
this->publisher_->publish(messgae);
};
//初始化时钟
timer_ = this->create_wall_timer(1s,publish_msg);
}
//析构函数
~AddressBookPublisher()
{
}
private:
//发布者
rclcpp::Publisher<more_interfaces::msg::AddressBook>::SharedPtr publisher_;
//时间节点控制
rclcpp::TimerBase::SharedPtr timer_;
};
int main(int argc,char * argv[])
{
rclcpp::init(argc,argv);
rclcpp::spin(std::make_shared<AddressBookPublisher>());
rclcpp::shutdown();
}
7. 编程细节:头文件找不到的解决办法
#include <more_interfaces/msg/address_book.hpp>
该头文件为编译期由接口定义自动生成,若提示找不到,说明程序尚未编译。可提前执行预编译:
colcon build --packages-up-to more_interfaces
编译完成后,生成的头文件即被系统索引,编辑器即可正常识别。
8. 补充:多消息/多服务文件的编译选项规则
当软件包中包含多个消息文件和服务文件时,CMakeLists.txt 按如下方式配置:
set(msg_files "msg/Message1.msg" "msg/Message2.msg" # etc )
set(srv_files "srv/Service1.srv" "srv/Service2.srv" # etc )
rosidl_generate_interfaces(${PROJECT_NAME} ${msg_files} ${srv_files})
二、程序测试
1. 编译软件包
colcon build --packages-up-to more_interfaces
2. 测试运行
. install/setup.bash
ros2 run more_interfaces publish_address_book
3. 话题订阅测试
. install/setup.bash
ros2 topic list
ros2 run more_interfaces publish_address_book
自定义话题准确发出,可在 ros2 topic list 中看到 address_book 话题,通过 ros2 topic echo /address_book 即可订阅验证消息内容。
小结
本章节完成了软件包接口的扩展:在节点软件包内直接定义自定义消息,并通过编译选项生成接口,实现了"消息 + 节点"一体化打包。至此,本系列已完成 ROS2 开发环境搭建、核心命令、编程环境、话题/服务通信、自定义接口的完整学习闭环,为后续工业机器人动态抓取等实战项目打下坚实基础。
SEO关键词: ROS2自定义消息发布, ROS2软件包接口扩展, AddressBook.msg, rosidl_target_interfaces, ROS2机器人开发实战
