ROS2教程(7) - 在单个进程中组合多个节点、监控参数变化 - Linux

在单个进程中组合多个节点

基础使用

查找可用组件

ros2 component types

运行时组合ROS服务的pub与sub

# 终端1中启动组件容器
ros2 run rclcpp_components component_container


# 终端2中确定在运行的容器
ros2 component list
# 你应该看到有 /ComponentManager 组件名称


# 在终端2中加载talker组件
ros2 component load /ComponentManager composition composition::Talker
# 该命令返回加载组件的唯一ID以及节点名称 Loaded component 1 into '/ComponentManager' container node as '/talker'
# 现在终端1 应该显示 已加载组件的消息以及用于发布消息的重复消息
[INFO] [1721370343.552024029] [talker]: Publishing: 'Hello World: 1'
[INFO] [1721370344.552077267] [talker]: Publishing: 'Hello World: 2'
[INFO] [1721370345.552069042] [talker]: Publishing: 'Hello World: 3'
[INFO] [1721370346.552111748] [talker]: Publishing: 'Hello World: 4'
[INFO] [1721370347.552224869] [talker]: Publishing: 'Hello World: 5'
[INFO] [1721370348.552158623] [talker]: Publishing: 'Hello World: 6'
[INFO] [1721370349.552194409] [talker]: Publishing: 'Hello World: 7'
[INFO] [1721370350.552245410] [talker]: Publishing: 'Hello World: 8'


# 终端2中加载listener组件
ros2 component load /ComponentManager composition composition::Listener
# 返回 Loaded component 2 into '/ComponentManager' container node as '/listener'# 终端2
ros2 component list
# 现在应该显示以下结果
/ComponentManager
   1  /talker
   2  /listener

运行时组合ROS服务的server与client

客户端向服务器发送请求,服务器处理请求并返回响应,客户端打印接收到的响应。

# 终端1
ros2 run rclcpp_components component_container

# 终端2
ros2 component load /ComponentManager composition composition::Server
ros2 component load /ComponentManager composition composition::Client

编译时组合hardcoded nodes

  • 此实例演示可以使用相同的共享库来编译运行多个组件的单个可执行文件,而无需使用共享接口。

  • 此实例包含上述所有四个组件:pub、sub、server、client,这些组件在mian函数中是hardcoded

ros2 run composition manual_composition
  • 手动组成的组件不会被ros2 component list输出出来。

运行时组合dlopen

  • 此实例演示了运行时组合的代替方案,即创建一个通用的容器进程,并显式传递要加载的库,而不是使用ros接口。该过程打开每个库,并在库中创建每个rclcpp::Node类的实例。
ros2 run composition dlopen_composition `ros2 pkg prefix composition`/lib/libtalker_component.so `ros2 pkg prefix composition`/lib/liblistener_component.so
  • dlopen组成的组件不会被ros2 component list输出出来。

使用launch进行组合

ros2 launch composition composition_demo.launch.py

进阶操作

卸载组件

# 终端1 启动组件
ros2 run rclcpp_components component_container

# 终端2 list运行中的容器
ros2 component list
# 应输出组件名称 /ComponentManager# 终端2 加载 talker 和 listener
ros2 component load /ComponentManager composition composition::Talker
ros2 component load /ComponentManager composition composition::Listener

# 终端2 使用唯一id从组件容器中卸载节点
ros2 component unload /ComponentManager 1 2
# 终端应返回
Unloaded component 1 from '/ComponentManager' container
Unloaded component 2 from '/ComponentManager' container
# 在终端1中,消息已停止

重新映射容器名称和命名空间

  • 组件管理器名称和命名空间可以通过命令行参数重新映射
ros2 run rclcpp_components component_container --ros-args -r __node:=MyContainer -r __ns:=/ns
  • 重映射完成后可以使用更新后的容器名来加载
ros2 component load /ns/MyContainer composition composition::Listener

重映射组件名称和命名空间

  • 启动组件容器
ros2 run rclcpp_components component_container
  • 重映射节点名称
ros2 component load /ComponentManager composition composition::Talker --node-name talker2
  • 重映射命名空间名称
ros2 component load /ComponentManager composition composition::Talker --node-namespace /ns
  • 全部重映射
ros2 component load /ComponentManager composition composition::Talker --node-name talker3 --node-namespace /ns2
  • ros2 component list
ros2 component list
# 应输出
/ComponentManager
   1  /talker2
   2  /ns/talker
   3  /ns2/talker3

将参数值传递给组件

  • ros2 component load支持在构造节点时向节点传递任意参数。
ros2 component load /ComponentManager image_tools image_tools::Cam2Image -p burger_mode:=true

向组件传递附加参数

  • ros2 component load支持将特定选项传递给组件管理器,以便在构造节点时使用。 到目前为止,支持的唯一命令行选项是使用进程内通信实例化节点。
ros2 component load /ComponentManager composition composition::Talker -e use_intra_process_comms:=true

可组合节点作为共享库

https://docs.ros.org/en/humble/Tutorials/Intermediate/Composition.html#composable-nodes-as-shared-libraries

编写非节点派生组件

https://docs.ros.org/en/humble/Tutorials/Intermediate/Composition.html#composing-non-node-derived-components

监控参数变化

crate pkg

cd ~/ros2_ws/src && ros2 pkg create --build-type ament_cmake --license Apache-2.0 cpp_parameter_event_handler --dependencies rclcpp

cpp

  • ~/ros2_ws/src/cpp_parameter_event_handler/src/parameter_event_handler.cpp
#include <memory> // 使用std::make_shared模板

#include "rclcpp/rclcpp.hpp" // 需要使用 rclcpp::ParameterEventHandler

class SampleNodeWithParameters : public rclcpp::Node
{
public:
  SampleNodeWithParameters()
  : Node("node_with_parameters")
  {
    // 声明一个默认值为0的参数
    this->declare_parameter("an_int_param", 0);

    // 实例化一个ParameterEventHandler用于监控参数更改
    param_subscriber_ = std::make_shared<rclcpp::ParameterEventHandler>(this);

    // 一个内联函数,在参数更改时调用
    auto cb = [this](const rclcpp::Parameter & p) {
        RCLCPP_INFO(
          this->get_logger(), "cb: Received an update to parameter \"%s\" of type %s: \"%ld\"",
          p.get_name().c_str(),
          p.get_type_name().c_str(),
          p.as_int());
      };
    // 保存add_parameter_callback返回的句柄非常重要,否则回调将无法正常注册
    cb_handle_ = param_subscriber_->add_parameter_callback("an_int_param", cb);


    // 监控节点parameter_blackboard上的参数变化
    auto cb2 = [this](const rclcpp::Parameter & p) {
        RCLCPP_INFO(
        this->get_logger(), "cb2: Received an update to parameter \"%s\" of type: %s: \"%.02lf\"",
        p.get_name().c_str(),
        p.get_type_name().c_str(),
        p.as_double());
    };
    auto remote_node_name = std::string("parameter_blackboard");
    auto remote_param_name = std::string("a_double_param");
    cb_handle2_ = param_subscriber_->add_parameter_callback(remote_param_name, cb2, remote_node_name);

  }

private:
  std::shared_ptr<rclcpp::ParameterEventHandler> param_subscriber_;
  std::shared_ptr<rclcpp::ParameterCallbackHandle> cb_handle_;
  std::shared_ptr<rclcpp::ParameterCallbackHandle> cb_handle2_;

};

int main(int argc, char ** argv)
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<SampleNodeWithParameters>());
  rclcpp::shutdown();

  return 0;
}

CMakeLists.txt

  • ~/ros2_ws/src/cpp_parameter_event_handler/CMakeLists.txt
# add
add_executable(parameter_event_handler src/parameter_event_handler.cpp)
ament_target_dependencies(parameter_event_handler rclcpp)

install(TARGETS
  parameter_event_handler
  DESTINATION lib/${PROJECT_NAME}
)

run

# 终端1
cd ~/ros2_ws
rosdep install -i --from-path src --rosdistro $ROS_DISTRO -y # 检查依赖项是否缺失
colcon build --packages-select cpp_parameter_event_handler
. install/setup.bash
ros2 run cpp_parameter_event_handler parameter_event_handler

# 终端2
ros2 run demo_nodes_cpp parameter_blackboard

# 终端3 设置参数
ros2 param set node_with_parameters an_int_param 43
ros2 param set parameter_blackboard a_double_param 3.45
  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值