文章目录

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

3.python 包

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

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

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

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’))
]
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

4.c++包

python是在setup.py里,c++是在CMakeLists.txt,需要在install命令里加上对launch的指定

# Install launch files.
install(DIRECTORY
launch
DESTINATION share/${PROJECT_NAME}/
)
  • 1
  • 2
  • 3
  • 4
  • 5

5.写一个launch文件

和ros1的launch文件差别挺大的,ros1是xml那种形式,roslaunch命令回去解析,roslaunch也是python写的,ros2 的launch文件,直接就是py文件了,可以推荐用个pyharm啥的
分了两个版本:foxy更新的是这样的:

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’]),
])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

eloquent或者更老的版本:

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’]),
])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

6.用法

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

ros2 launch my_package script.launch.py
  • 1

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:
ros2 run my_package node_executable —ros-args ...
  • 1

dashing:


ros2 run my_package node_executable ...
  • 1

说明文档的传送门在这:http://design.ros2.org/articles/ros_command_line_arguments.html


1.名字重定向

node内的名字( topics/services)重定向通过命令 -r <old name>:=<new name>实现. 节点的名字的和命名空间通过命令 -r node:=<new node name>-r ns:=<new node namespace>.

示例:

重定向 node :talker —>my_talker ,topic:my_topic–>chatter,namespace:/demo/my_topic–>/my_topic
eloquent 和更新的版本:

ros2 run demo_nodes_cpp talker —ros-args -r ns:=/demo -r node:=my_talker -r chatter:=my_topic

  • 1
  • 2

dashing版本:

ros2 run demo_nodes_cpp talker ns:=/demo node:=my_talker chatter:=my_topic

  • 1
  • 2

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

—ros-args -r talker:node:=my_talker
  • 1

2.日志配置

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

3.配置

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

命令行

dashing版本不支持

命令是这个样子:

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

前面改乌龟的颜色展示过

YAML文件

这个样子demo_params.yaml

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]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Ⅲ 通过命令行工具的自省

自省其实就是用来排查观察我们的程序
主要是介绍下命令行,可以通过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函数,长这个样子

#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)

  • 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
  • 49

一般是继承node,通过最后一行的RCLCPP_COMPONENTS_REGISTER_NODE来注册,只有注册之后,才能被系统发现
CMakelists.txt 也要跟着改一下

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”)
  • 1
  • 2
  • 3
  • 4
  • 5

使用components

3种方式

  • 启动容器,用load加载
  • 创建一个管理节点
  • 通过launch文件

运行demo

发现可用 components

命令:

ros2 component types
  • 1

在这里插入图片描述


运行时合成pub 和sub

命令:

ros2 run rclcpp_components component_container
ros2 component load /ComponentManager composition composition::Talker
ros2 component load /ComponentManager composition composition::Listener
  • 1
  • 2
  • 3

在这里插入图片描述


运行时合成 server 和client

命令:

ros2 run rclcpp_components component_container
ros2 component load /ComponentManager composition composition::Server
ros2 component load /ComponentManager composition composition::Client
  • 1
  • 2
  • 3

在这里插入图片描述


编译时合成server

代码里包含这些:
在这里插入图片描述


运行下看看:
在这里插入图片描述


运行时使用dlopen 合成

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

ros2 run composition dlopen_composition </span>ros2 pkg prefix composition<span class="token variable">/lib/libtalker_component.so </span>ros2 pkg prefix composition<span class="token variable">/lib/liblistener_component.so

  • 1
  • 2

实现的功能都一样,只是方法不一样


在这里插入图片描述


使用launch文件合成

写导python的容器里

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

命令:


ros2 launch composition composition_demo.launch.py
  • 1

在这里插入图片描述


其他高级用法

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

 ros2 component unload /ComponentManager 1 2
  • 1

节点同样可以重定向

Ⅵ Actions

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

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


具体的参考前面的教程

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

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

主要有以下配置:

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]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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

④ 总结

回顾整个命令行