文章目录
- ① 背景
- ② 前提
- ③ 任务
- Ⅰ通过launch启动/管理多个节点
- 1. ROS2的launch系统
- 2. 写一个ROS2 launch文件
- 3.python 包
- 4.c++包
- 5.写一个launch文件
- 6.用法
- 7.ros2 launch的概念
- 8.文档
- Ⅱ 通过命令行传递参数
- 1.名字重定向
- 示例:
- 2.日志配置
- 3.配置
- 命令行
- YAML文件
- Ⅲ 通过命令行工具的自省
- Ⅳ RQt的回归和使用
- Ⅴ 多节点运行在单个进程里
- ROS 1 - Nodes vs. Nodelets
- ROS 2 - Unified API
- 写一个Component
- 使用components
- 运行demo
- 发现可用 components
- 运行时合成pub 和sub
- 运行时合成 server 和client
- 编译时合成server
- 运行时使用dlopen 合成
- 使用launch文件合成
- 其他高级用法
- Ⅵ Actions
- Ⅶ 重写Qos策略用于记录和回放
- ④ 总结
① 背景
前面介绍过ros2的相关的工具,这里主要介绍一些其他的用法
② 前提
- 安装 ROS2 (Dashing 或者更新的版本)
- 安装 colcon
- 设置好环境变量
③ 任务
Ⅰ通过launch启动/管理多个节点
1. ROS2的launch系统
ROS 2中的launch系统负责帮助用户描述其系统的配置,然后按说明执行。系统的配置包括要运行的程序、运行它们的位置、传递它们的参数以及ROS特定的约定,这些约定通过为组件提供不同的配置,使得在整个系统中重用组件变得容易。它还负责监测启动过程的状态,并报告和/或对这些过程状态的变化作出反应。
用Python编写的启动文件可以启动和停止不同的节点,也可以触发和处理各种事件。提供这个框架的包是launch_ros,它使用下面的非ros特定的发布框架。
设计文件详细说明了ROS 2发射系统的设计目标(目前并非所有功能都可用)。
2. 写一个ROS2 launch文件
跟ros1 一样,我们通过
3.python 包
python包的文件结构大概是这个样子
1 2 3 4 5 6 | src/ my_package/ launch/ setup.py setup.cfg package.xml |
python包有点特殊,需要在
这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import os from glob import glob from setuptools import setup package_name = 'my_package' setup( # Other parameters ... data_files=[ # ... Other data files # Include all launch files. This is the most important line here! (os.path.join('share', package_name), glob('launch/*.launch.py')) ] ) |
4.c++包
python是在
1 2 3 4 5 | # Install launch files. install(DIRECTORY launch DESTINATION share/${PROJECT_NAME}/ ) |
5.写一个launch文件
和ros1的launch文件差别挺大的,ros1是xml那种形式,roslaunch命令回去解析,roslaunch也是python写的,ros2 的launch文件,直接就是py文件了,可以推荐用个pyharm啥的
分了两个版本:foxy更新的是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import launch import launch.actions import launch.substitutions import launch_ros.actions def generate_launch_description(): return launch.LaunchDescription([ launch.actions.DeclareLaunchArgument( 'node_prefix', default_value=[launch.substitutions.EnvironmentVariable('USER'), '_'], description='Prefix for node names'), launch_ros.actions.Node( package='demo_nodes_cpp', node_executable='talker', output='screen', node_name=[launch.substitutions.LaunchConfiguration('node_prefix'), 'talker']), ]) |
eloquent或者更老的版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import launch import launch.actions import launch.substitutions import launch_ros.actions def generate_launch_description(): return launch.LaunchDescription([ launch.actions.DeclareLaunchArgument( 'node_prefix', default_value=[launch.substitutions.EnvironmentVariable('USER'), '_'], description='Prefix for node names'), launch_ros.actions.Node( package='demo_nodes_cpp', node_executable='talker', output='screen', node_name=[launch.substitutions.LaunchConfiguration('node_prefix'), 'talker']), ]) |
6.用法
编译完成之后,通过
1 | ros2 launch my_package script.launch.py |
7.ros2 launch的概念
可以看看这个例子:https://github.com/ros2/launch_ros/blob/master/launch_ros/examples/lifecycle_pub_sub_launch.py
这个介绍
这样可以在有启动依赖的时候用到,当前值
8.文档
传送门:https://github.com/ros2/launch/blob/master/launch/doc/source/architecture.rst
Ⅱ 通过命令行传递参数
主要是下面三个部分:
- 名称重定向
- 日志配置
- 参数
使用命令行传参在eloquent 之后需要加--ros-args 标志,dashing 版本不需要
eloquent:
1 | ros2 run my_package node_executable --ros-args ... |
dashing:
1 | ros2 run my_package node_executable ... |
说明文档的传送门在这:http://design.ros2.org/articles/ros_command_line_arguments.html
1.名字重定向
node内的名字(
示例:
重定向
eloquent 和更新的版本:
1 | ros2 run demo_nodes_cpp talker --ros-args -r __ns:=/demo -r __node:=my_talker -r chatter:=my_topic |
dashing版本:
1 | ros2 run demo_nodes_cpp talker __ns:=/demo __node:=my_talker chatter:=my_topic |
可以通过加上
就是这个样子(修改
1 | --ros-args -r talker:__node:=my_talker |
2.日志配置
命令行的话就是
3.配置
配置可以通过
命令行
dashing版本不支持
命令是这个样子:
1 | ros2 run package_name executable_name --ros-args -p param_name:=param_value |
前面改乌龟的颜色展示过
YAML文件
这个样子
1 2 3 4 5 6 7 | parameter_blackboard: ros__parameters: some_int: 42 a_string: "Hello world" some_lists: some_integers: [1, 2, 3, 4] some_doubles : [3.14, 2.718] |
Ⅲ 通过命令行工具的自省
自省其实就是用来排查观察我们的程序
主要是介绍下命令行,可以通过
- daemon: Introspect/configure the ROS 2 daemon
- launch: Run a launch file
- lifecycle: Introspect/manage nodes with managed lifecycles
- msg: Introspect msg types
- node: Introspect ROS nodes
- param: Introspect/configure parameters on a node
- pkg: Introspect ROS packages
- run: Run ROS nodes
- security: Configure security settings
- service: Introspect/call ROS services
- srv: Introspect srv types
- topic: Introspect/publish ROS topics
Ⅳ RQt的回归和使用
这个可以通过前面
Ⅴ 多节点运行在单个进程里
ROS 1 - Nodes vs. Nodelets
在
ROS 2 - Unified API
在
运行节点有两种方式:
- 多节点多进程,这样的话,降低耦合度,不会因为一个节点问题导致整个程序挂掉,但是浪费资源
- 多节点单进程,开销小,可以使用
IPC ,就是容易挂
写一个Component
看demo的话来这里 https://github.com/ros2/demos.git
这个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #include "composition/talker_component.hpp" #include <chrono> #include <iostream> #include <memory> #include <utility> #include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/string.hpp" using namespace std::chrono_literals; namespace composition { // Create a Talker "component" that subclasses the generic rclcpp::Node base class. // Components get built into shared libraries and as such do not write their own main functions. // The process using the component's shared library will instantiate the class as a ROS node. Talker::Talker(const rclcpp::NodeOptions & options) : Node("talker", options), count_(0) { // Create a publisher of "std_mgs/String" messages on the "chatter" topic. pub_ = create_publisher<std_msgs::msg::String>("chatter", 10); // Use a timer to schedule periodic message publishing. timer_ = create_wall_timer(1s, std::bind(&Talker::on_timer, this)); } void Talker::on_timer() { auto msg = std::make_unique<std_msgs::msg::String>(); msg->data = "Hello World: " + std::to_string(++count_); RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", msg->data.c_str()); std::flush(std::cout); // Put the message into a queue to be processed by the middleware. // This call is non-blocking. pub_->publish(std::move(msg)); } } // namespace composition #include "rclcpp_components/register_node_macro.hpp" // Register the component with class_loader. // This acts as a sort of entry point, allowing the component to be discoverable when its library // is being loaded into a running process. RCLCPP_COMPONENTS_REGISTER_NODE(composition::Talker) |
一般是继承
CMakelists.txt 也要跟着改一下
1 2 3 4 5 | add_library(talker_component SHARED src/talker_component.cpp) rclcpp_components_register_nodes(talker_component "composition::Talker") # To register multiple components in the same shared library, use multiple calls # rclcpp_components_register_nodes(talker_component "composition::Talker2") |
使用components
3种方式
- 启动容器,用load加载
- 创建一个管理节点
- 通过launch文件
运行demo
发现可用 components
命令:
1 | ros2 component types |
运行时合成pub 和sub
命令:
1 2 3 | ros2 run rclcpp_components component_container ros2 component load /ComponentManager composition composition::Talker ros2 component load /ComponentManager composition composition::Listener |
运行时合成 server 和client
命令:
1 2 3 | ros2 run rclcpp_components component_container ros2 component load /ComponentManager composition composition::Server ros2 component load /ComponentManager composition composition::Client |
编译时合成server
代码里包含这些:
运行下看看:
运行时使用dlopen 合成
这个
命令:
1 | ros2 run composition dlopen_composition `ros2 pkg prefix composition`/lib/libtalker_component.so `ros2 pkg prefix composition`/lib/liblistener_component.so |
实现的功能都一样,只是方法不一样
使用launch文件合成
写导python的容器里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | container = ComposableNodeContainer( node_name='my_container', node_namespace='', package='rclcpp_components', node_executable='component_container', composable_node_descriptions=[ ComposableNode( package='composition', node_plugin='composition::Talker', node_name='talker'), ComposableNode( package='composition', node_plugin='composition::Listener', node_name='listener') ], output='screen', ) |
命令:
1 | ros2 launch composition composition_demo.launch.py |
其他高级用法
可以用
这个样子:
1 | ros2 component unload /ComponentManager 1 2 |
节点同样可以重定向
Ⅵ Actions
动作是ROS中异步通信的一种形式。操作客户端向操作服务器发送目标请求。操作服务器向操作客户端发送目标反馈和结果。有关ROS操作的更多详细信息,请参阅设计文章。
此文档包含与操作相关的教程列表。作为参考,在完成所有教程之后,您应该期望有一个类似于包action_tutorials的ROS包。
具体的参考前面的教程
Ⅶ 重写Qos策略用于记录和回放
因为
主要有以下配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | history: [keep_all, keep_last] depth: int reliability: [system_default, reliable, best_effort, unknown] durability: [system_default, transient_local, volatile, unknown] deadline: sec: int nsec: int lifespan: sec: int nsec: int liveliness: [system_default, automatic, manual_by_node, manual_by_topic, unknown] liveliness_lease_duration: sec: int nsec: int avoid_ros_namespace_conventions: [true, false] |
这个用到在看,现在除了记录
④ 总结
回顾整个命令行