当前位置: 首页 > news >正文

【scene_manager_msgs】ROS2 自定义消息、服务的包

scene_manager_msgs
在ROS 1向ROS 2迁移的过程中,有些依赖项发生了变化,这是因为ROS 2的通信框架和工具链与ROS 1不同,尤其在消息、服务和动作生成方面有了一些新的方法和库。

动作库

如果你的ROS 1包依赖于actionlibactionlib_msgs,在迁移到ROS 2时,需要使用ROS 2的原生动作机制来代替。这是因为在ROS 2中,动作库(actionlib)被重新实现,集成进了ROS 2核心的通信框架中,不再需要像ROS 1那样单独依赖actionlib_msgsactionlib。以下是详细的替换和迁移步骤:

1. ROS 1中的actionlibactionlib_msgs

在ROS 1中,actionlib用于处理复杂的长时间操作,特别是那些需要反馈和预先终止的操作。actionlib_msgs包含了动作通信的标准消息类型,如:

  • Goal:客户端发送到服务器的目标。
  • Feedback:服务器定期发送给客户端的反馈。
  • Result:服务器完成任务后发送的结果。

2. ROS 2中的原生动作机制

在ROS 2中,动作接口被直接集成进了ROS 2通信架构中,通过rclcpp_action(C++)或rclpy_action(Python)来处理。动作在ROS 2中作为一种独立的接口,与消息和服务一起被支持。ROS 2的动作机制改进了性能、简化了开发流程,并且通过rosidl接口定义语言来生成动作接口。

主要区别:
  • 内置支持:在ROS 2中,动作系统是核心架构的一部分,直接使用与消息和服务相同的rosidl工具链。
  • 生成方式:动作文件(.action)可以直接与消息和服务一起通过rosidl_generate_interfaces生成。

3. 迁移步骤

(1) 定义动作文件(.action

在ROS 1中,你可能有一个.action文件。迁移到ROS 2时,这些文件不需要改变语法,但是要确保它们遵循ROS 2的生成规则。一个标准的.action文件如下:

# 定义目标(Goal)
int32 goal_value
---
# 定义结果(Result)
int32 result_value
---
# 定义反馈(Feedback)
float32 feedback_value
(2) 在CMakeLists.txt中生成动作接口

在ROS 2中,你需要使用rosidl_generate_interfaces来生成动作、消息和服务的接口。将以下内容添加到CMakeLists.txt中:

find_package(rosidl_default_generators REQUIRED)set(ACTION_FILES"action/MyAction.action"
)rosidl_generate_interfaces(${PROJECT_NAME}${ACTION_FILES}DEPENDENCIES std_msgs
)

ACTION_FILES变量中列出了你的.action文件。rosidl_generate_interfaces会生成C++和Python代码,供你的动作服务器和客户端使用。

(3) 修改代码以使用ROS 2的动作API

在ROS 1中,你可能用过actionlib::SimpleActionClientactionlib::SimpleActionServer。在ROS 2中,需要改用rclcpp_action::Clientrclcpp_action::Server(C++),或者用rclpy.action.ActionClientrclpy.action.ActionServer(Python)。

C++动作客户端(ROS 2)示例:

#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"
#include "my_package/action/my_action.hpp"class MyActionClient : public rclcpp::Node {
public:using MyAction = my_package::action::MyAction;using GoalHandleMyAction = rclcpp_action::ClientGoalHandle<MyAction>;MyActionClient() : Node("my_action_client") {this->client_ = rclcpp_action::create_client<MyAction>(this, "my_action");// 检查服务器是否可用if (!this->client_->wait_for_action_server(std::chrono::seconds(10))) {RCLCPP_ERROR(this->get_logger(), "Action server not available after waiting");return;}// 发送目标auto goal_msg = MyAction::Goal();goal_msg.goal_value = 42;auto goal_options = rclcpp_action::Client<MyAction>::SendGoalOptions();goal_options.result_callback = std::bind(&MyActionClient::result_callback, this, std::placeholders::_1);this->client_->async_send_goal(goal_msg, goal_options);}private:rclcpp_action::Client<MyAction>::SharedPtr client_;void result_callback(const GoalHandleMyAction::WrappedResult & result) {RCLCPP_INFO(this->get_logger(), "Result received: %d", result.result->result_value);}
};int main(int argc, char ** argv) {rclcpp::init(argc, argv);auto node = std::make_shared<MyActionClient>();rclcpp::spin(node);rclcpp::shutdown();return 0;
}

C++动作服务器(ROS 2)示例:

#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"
#include "my_package/action/my_action.hpp"class MyActionServer : public rclcpp::Node {
public:using MyAction = my_package::action::MyAction;using GoalHandleMyAction = rclcpp_action::ServerGoalHandle<MyAction>;MyActionServer() : Node("my_action_server") {this->server_ = rclcpp_action::create_server<MyAction>(this,"my_action",std::bind(&MyActionServer::handle_goal, this, std::placeholders::_1, std::placeholders::_2),std::bind(&MyActionServer::handle_cancel, this, std::placeholders::_1),std::bind(&MyActionServer::handle_accepted, this, std::placeholders::_1));}private:rclcpp_action::Server<MyAction>::SharedPtr server_;rclcpp_action::GoalResponse handle_goal(const rclcpp_action::GoalUUID & uuid,std::shared_ptr<const MyAction::Goal> goal) {RCLCPP_INFO(this->get_logger(), "Received goal request with value %d", goal->goal_value);return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;}rclcpp_action::CancelResponse handle_cancel(const std::shared_ptr<GoalHandleMyAction> goal_handle) {RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");return rclcpp_action::CancelResponse::ACCEPT;}void handle_accepted(const std::shared_ptr<GoalHandleMyAction> goal_handle) {std::thread{std::bind(&MyActionServer::execute, this, goal_handle)}.detach();}void execute(const std::shared_ptr<GoalHandleMyAction> goal_handle) {RCLCPP_INFO(this->get_logger(), "Executing goal");// 在这里执行动作,并发送反馈或结果auto result = std::make_shared<MyAction::Result>();result->result_value = 42;goal_handle->succeed(result);}
};int main(int argc, char ** argv) {rclcpp::init(argc, argv);auto node = std::make_shared<MyActionServer>();rclcpp::spin(node);rclcpp::shutdown();return 0;
}

4. 更新依赖项

package.xml中,确保你已经包含了ROS 2的相关依赖项,例如:

<depend>rclcpp_action</depend>
<depend>rosidl_default_generators</depend>

错误信息:

使用 colcon build 构建过程中遇到的错误提示表明了 scene_manager_msgs 这个 ROS 2 包的 package.xml 文件存在一个特定问题。错误信息指出你的包缺少一个必需的声明,这是定义自定义消息、服务的包所必需的。

Packages installing interfaces must include
'<member_of_group>rosidl_interface_packages</member_of_group>' in their
package.xml

告诉我们需要在 package.xml 中声明该包是 rosidl_interface_packages 组的一部分。因为在ROS 2中,负责定义消息、服务和动作接口的包必须向构建系统声明它们是接口包的一部分。这是为了让构建工具正确处理这些自定义接口,确保生成消息、服务和动作所需的代码。

如何修复

你需要在 package.xml 中添加一个 member_of_group 标签,将你的包包含在 rosidl_interface_packages 组中。这样可以告诉 ROS 构建工具你的包提供了需要处理的自定义接口。

  1. 打开你的 package.xml 文件。
  2. <package> 标签内添加以下行:
<member_of_group>rosidl_interface_packages</member_of_group>

这一行应该添加在顶级 <package> 标签内部,但在任何特定依赖声明之外。

更新后的 package.xml 示例

在修改后,你的 package.xml 部分内容可能如下所示:

<?xml version="1.0"?>
<package format="3"><name>scene_manager_msgs</name><version>0.0.1</version><description>用于场景管理的消息和服务的包</description><maintainer email="your-email@example.com">你的名字</maintainer><license>BSD</license><!-- 将此包包含在 rosidl_interface_packages 组中 --><member_of_group>rosidl_interface_packages</member_of_group><buildtool_depend>ament_cmake</buildtool_depend><depend>std_msgs</depend><depend>geometry_msgs</depend><depend>builtin_interfaces</depend><depend>rosidl_default_generators</depend><exec_depend>rosidl_default_runtime</exec_depend>
</package>

修改后的步骤

一旦你添加了这一行,应该:

  • 保存 package.xml 文件。
  • 重新运行构建命令:
colcon build --packages-select scene_manager_msgs

这应该会解决构建错误,允许 colcon 构建工具正确识别并处理你包的自定义接口。

详细解释:

  1. rosidl_interface_packages 组的作用
    在ROS 2中,rosidl(ROS Interface Definition Language)负责处理消息、服务和动作的定义和生成。所有涉及定义这些接口的包,都需要被归类为rosidl_interface_packages组的成员。通过将包声明为该组的一部分,ROS 2的构建系统可以识别该包包含自定义接口,并生成必要的消息、服务或动作文件。

  2. 生成自定义接口的流程
    当你在包中定义了消息(.msg)、服务(.srv)或动作(.action)文件时,构建工具会通过rosidl_generate_interfaces命令生成这些接口所需的C++或Python代码。然而,为了让构建系统知道你的包中包含这些接口文件,必须在package.xml中通过<member_of_group>标签将该包添加到rosidl_interface_packages组。

  3. 缺少声明的后果
    如果不将包加入到rosidl_interface_packages组,构建系统在处理这些消息和服务文件时将无法识别它们,进而无法生成必要的代码。这就会导致构建失败或在运行时无法找到相应的消息和服务接口。因此,缺少这个声明会导致类似于你之前遇到的错误。

包含消息和服务的包

从你提供的 CMakeLists.txt 文件来看,scene_manager_msgs 包定义了消息(msg/Layout.msg)和服务(如 srv/ModifyObject.srv 等),但并没有定义动作文件(.action 文件)。因此,这个包不是一个动作包,而是一个包含消息和服务的包。

动作包的定义:

  • 动作包(Action Package)通常会定义 .action 文件,这些文件用于定义长时间运行的任务,通常需要反馈机制。动作在ROS 2中可以使用 rclcpp_actionrclpy_action 库进行操作。

  • 如果这个包是一个动作包,你的 CMakeLists.txt 文件中应该有对 .action 文件的定义,比如:

    set(ACTION_FILES"action/MyAction.action"
    )rosidl_generate_interfaces(${PROJECT_NAME}${MSG_FILES}${SRV_FILES}${ACTION_FILES}DEPENDENCIES std_msgs geometry_msgs builtin_interfaces
    )
    

当前的 CMakeLists.txt 说明:

  • 你定义了消息文件 msg/Layout.msg 和服务文件 srv/ModifyObject.srvsrv/SelectObjects.srvsrv/MoveTo.srv
  • 没有提到 .action 文件,因此该包没有动作接口。

总结:

  • 不是动作包:由于没有定义动作文件(.action),这个包目前是一个消息和服务的包,而不是动作包。
  • 如何添加动作:如果你希望将其扩展为一个动作包,你需要定义 .action 文件,并在 CMakeLists.txt 中增加动作生成的配置。

消息(.msg)和服务(.srv)文件本身通常不需要修改其定义结构,因为ROS 2仍然使用相同的格式来定义这些文件

在将ROS 1软件包迁移到ROS 2时,消息(.msg)和服务(.srv)文件本身通常不需要修改其定义结构,因为ROS 2仍然使用相同的格式来定义这些文件。然而,你可能需要进行一些更新以确保这些定义与ROS 2的接口兼容和一致。

需要考虑的修改点:

  1. 依赖检查

    • 确保消息和服务文件中使用的类型在ROS 2中是有效的。例如,如果使用了geometry_msgs/PoseStamped,确保ROS 2中包含此类型。
    • 检查是否所有依赖的包都已经被迁移到ROS 2并在package.xmlCMakeLists.txt中正确引用。
  2. 包和类型的更新

    • 在ROS 2中,某些消息类型可能已经更新或替换。尽管大部分标准消息类型如std_msgsgeometry_msgs在ROS 2中仍然可用,但一些特定类型或属性可能已经有所改变。
    • 确保使用的类型与ROS 2的命名和结构标准一致。
  3. 服务定义的格式

    • 服务文件在ROS 1和ROS 2中的定义方式保持一致,格式为请求部分,一个---分割符,然后是响应部分
    • 确认服务文件的请求和响应部分是否符合你的应用需求,并考虑是否需要进行更新以利用ROS 2提供的新特性或改进。

http://www.mrgr.cn/news/51158.html

相关文章:

  • 用AI搞流量 | AI做好运壁纸号, 3个月涨粉6.4W
  • 通过SSH登录Linux系统并设置免密码登录
  • nvm安装,node多版本管理
  • MySQL创建和管理表
  • react18中实现简易增删改查useReducer搭配useContext的高级用法
  • 使用豆包MarsCode 来处理 Excel 的数据吧!
  • 4种鼓励创业创新的方法
  • GEE 批量删除 Assets 资产文件夹
  • 能源水务储能的可视化需求真多,我都忙不过来了。
  • 蓝紫激光模组常见的基本特性
  • 和数集团东南亚市场工作会议圆满举行
  • 给el-dialog的整体加动态class
  • NumPy 数组操作:从入门到精通
  • 2024年Flutter从入门到精通全网最全学习路线指南
  • 基于Cesium.js的可视化大屏,效果绝对的震撼!
  • JVM篇(学习预热 - JVM正式展开 - (实战课程学习总结))(持续更新迭代)
  • 移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——7.list(无习题)
  • 【C++】STL篇 string类(使用)
  • C嘎嘎入门篇:类和对象(3)
  • 爬虫逆向学习(十一):实战分享反爬机制快速定位与破解