[ros2学习]-学习ROS 2工具集


文章目录

    • ① 背景
    • ② 前提
    • ③ 任务
      • Ⅰ通过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 一样,我们通过ros2 launch命令启动launch文件,我们可以通过ros2 pkg create --dependencies [deps]命令来创建一个包,这样会自动生成一个launch文件夹

3.python 包

python包的文件结构大概是这个样子

1
2
3
4
5
6
src/
    my_package/
        launch/
        setup.py
        setup.cfg
        package.xml

python包有点特殊,需要在setup.pydata_files 里加上对launch文件的指定
这样:

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是在setup.py里,c++是在CMakeLists.txt,需要在install命令里加上对launch的指定

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.用法

编译完成之后,通过ros2 launch 启动

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

这个介绍launch_ros 的节点启动,事件注册,通知功能
这样可以在有启动依赖的时候用到,当前值launch启动导一定阶段,发布事件,启动后续步骤,可以不用通过延时这种不稳定的方式了

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内的名字( topics/services)重定向通过命令 -r :=实现. 节点的名字的和命名空间通过命令 -r __node:=-r __ns:=.

示例:

重定向 node :talker -->my_talker ,topic:my_topic–>chatter,namespace:/demo/my_topic–>/my_topic
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

可以通过加上node名称来指定具体的要重定向的节点,在执行多个节点的时候很重要
就是这个样子(修改talker节点的node的名字):

1
--ros-args -r talker:__node:=my_talker

2.日志配置

命令行的话就是--log-level这个参数的配置,具体的可以看看前面关于日志的介绍,这里就这样了

3.配置

配置可以通过cliyaml文件两种方式实现

命令行

dashing版本不支持

命令是这个样子:

1
ros2 run package_name executable_name --ros-args -p param_name:=param_value

前面改乌龟的颜色展示过

YAML文件

这个样子demo_params.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]

Ⅲ 通过命令行工具的自省

自省其实就是用来排查观察我们的程序
主要是介绍下命令行,可以通过ros2 --help查看,我就不解释了

  • 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的回归和使用

RQt是一个图形用户界面框架,它以插件的形式实现各种工具和界面。可以在RQt中将所有现有的GUI工具作为可停靠窗口运行!这些工具仍然可以在传统的独立方法中运行,但是RQt使得在一个屏幕布局管理所有不同的窗口更加容易。
这个可以通过前面cli部分的RQT部分回顾

Ⅴ 多节点运行在单个进程里

ROS 1 - Nodes vs. Nodelets

ROS 1中,您可以将代码编写为ROS nodeROS nodeletROS 1 nodes被编译成可执行文件。另一方面,ROS 1 nodelet被编译成一个共享库,然后在运行时由容器进程加载。

ROS 2 - Unified API

ros2 通过 Component来实现
运行节点有两种方式:

  • 多节点多进程,这样的话,降低耦合度,不会因为一个节点问题导致整个程序挂掉,但是浪费资源
  • 多节点单进程,开销小,可以使用IPC,就是容易挂

写一个Component

看demo的话来这里 https://github.com/ros2/demos.git
这个Component最后生成的是so,不包含main函数,长这个样子

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)

一般是继承node,通过最后一行的RCLCPP_COMPONENTS_REGISTER_NODE来注册,只有注册之后,才能被系统发现
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 合成

这个dlopen就是加载so用的
命令:

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

在这里插入图片描述

其他高级用法

可以用unload 删除 componentsload的逆操作
这个样子:

1
 ros2 component unload /ComponentManager 1 2

节点同样可以重定向

Ⅵ Actions

动作是ROS中异步通信的一种形式。操作客户端向操作服务器发送目标请求。操作服务器向操作客户端发送目标反馈和结果。有关ROS操作的更多详细信息,请参阅设计文章。

此文档包含与操作相关的教程列表。作为参考,在完成所有教程之后,您应该期望有一个类似于包action_tutorials的ROS包。

具体的参考前面的教程

Ⅶ 重写Qos策略用于记录和回放

因为ROS2 引入了DDS,所以在记录和播放bag文件的时候需要考虑导Qos配置的兼容性,可以通过参数--qos-profile-overrides-path来指定新的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]

这个用到在看,现在除了记录demo没啥意义

④ 总结

回顾整个命令行