您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Model Center   Code  
会员   
   
 
     
   
 
 订阅
ROS2入门教程
 
作者:Hali_Botebie
  1258  次浏览      19 次
 2023-4-26
 
编辑推荐:
本文主要介绍了ROS2入门教程。希望对你的学习有帮助。
本文来自于CSDN,由火龙果软件Linda编辑,推荐。

ROS2入门教程-基本概念

介绍ROS2的基本概念

1. 基本概念:

ROS是一个用于在不同进程间匿名的发布、订阅、传递信息的中间件。

ROS2系统的核心部分是ROS网络(ROS Graph)。

ROS网络是指在ROS系统中不同的节点间相互通信的连接关系。

ROS Graph这里翻译成了ROS网络,因为我觉得Graph更加抽象,而网络的概念更容易帮助理解其内涵。

2. ROS网络(ROS Graph)概念简介:

节点(Nodes): 一个节点是一个利用ROS系统和其他节点通信的实体

消息(Messages): ROS中在订阅和发布主题时所用到的数据结构

主题(Topics): 节点可以发布信息到一个主题,同样也可订阅主题来接收消息

发现(Discovery): 一个自动运行的进程,通过这个进程不同的节点相互发现,建立连接

节点(Nodes)

一个节点就是一个在ROS网络中的参与者。

ROS节点通过ROS客户端程序库(ROS client library)来和其他节点进行通信。

节点可以发布或者订阅主题 节点也可以提供ROS服务(Service)。

节点有很多可以配置的相关参数。

节点间的连接时通过一个分布式发现进程来建立的(即上面所说的发现)。

不同的节点可以在同一个进程里面,也可以在不同的进程里面,甚至可以在不同的机器上。

客户端程序库

ROS客户端程序库可以让不同的语言编写的节点进行通信。

在不同的编程语言中都有对应的ROS客户端程序库(RCL),这个程序库实现了ROS的基本API。

这样就确保了不同的编程语言的客户端更加容易编写,也保证了其行为更加一致。

3.下面的客户端程序库是由ROS2团队维护的

rclcpp = C++ 客户端程序库

rclpy = Python 客户端程序库

另外其他客户端程序也已经有ROS社区开发出来。

4. 发现

节点之间的互相发现是通过ROS2底层的中间件实现的。

5. 过程总结如下

当一个节点启动后, 它会向其他拥有相同ROS域名的节点进行广播,说明它已经上线。

ROS域名(ROS domain, 可以通过设置ROS_DOMAIN_ID环境变量来设置)

其他节点在收到广播后返回自己的相关信息,这样节点间的连接就可以建立了,之后就可以通信了。

节点会定时广播它的信息,这样即使它已经错过了最初的发现过程,它也可以和新上线的节点进行连接。

节点在下线前它也会广播其他节点自己要下线了。

节点只会和具有相兼容的[服务质量]设置的节点进行通信。

例子:发布和接收

在一个终端,启动一个节点(用C++编写),这个节点会向一个主题发布消息

ros2 run demo_nodes_cpp talker

在另一个终端,同样启动一个节点(用Python编写),这个节点会订阅和上个节点相同的主题来接收消息。

ros2 run demo_nodes_py listener

你会看到节点自动发现了对方,然后开始互相通信。

你也可以在不同的电脑上启动节点,你也会发现,节点自动建立了它们的连接,然后开始通信。

6. 测试安装成果

测试使用

运行talker-listener例子测试是否成功安装

新终端,执行以下命令:

$ ros2 run demo_nodes_cpp talker

新终端,执行以下命令:

$ ros2 run demo_nodes_cpp listener

测试成功截图

ROS2入门教程-Intra-Process通讯方式

1. Intra-Process的通讯方式

ROS应用程序通常有多个单独的节点组成,这些节点的工作范围一般很小,与系统的其他部分联系不大。

这促进了故障隔离、更快的开发、模块化和代码重用, 但它往往以性能为代价。

在ROS1开发之后, 节点有效组合的需求变得明显, Nodelets 也得到了发展。 在ROS2中, 我们旨在通过解决一些需要重构节点的基本问题来改进 Nodelets 的设计。

在这个演示中,其将重点介绍如何通过单独定义节点,将其组合在不同的进程布局中,而不改变节点的代码或限制其功能作用,从而手动组合节点。

2. Build the demos

运行和理解demo

其中有几个不同的demo:一些是toy问题,旨在突出内部进程通信功能的特点;一些是使用OpenCV的端到端示例,并展示将节点重新组合到不同配置中的功能。

The two node pipeline demo

该demo旨在显示发布和订阅std::unique_ptrs时,进程内发布/订阅连接可以导致消息的零拷贝传输。

该demo的源代码:https://github.com/ros2
/demos/blob/master
/intra_process_demo/src/two
_node_pipeline/two_node_pipeline.cpp

如主函数所示,其中有一个生产者和一个消费者节点,它们被添加到一个单线程程序中,然后调用spin

如果在Producer结构中的“producer”节点的实现,可以看到其中已经创建了一个发布“number”话题的发布者和一个定期创建一个新消息且在内存中输出出它的地址和值并发布这个消息的定时器

至于“Consumer”节点,可以在Consumer结构中看到它的实现,因为它只订阅“number”话题并打印它接收的消息的地址和值。

期望效果是:生产者将输出地址和值,并且消费者将输出匹配的地址和价值。这表明进程内通信确实正在工作,同时避免使用不必要的副本。

执行 ros2 run intra_process_demo two_node
_pipeline 命令来运行demo(需要事先装好ROS2)

2.1 The image pipeline demo

首先将有一个由三个节点组成的管道, 按照这样的顺序排列: camera_node ->
watermark_node -> image_view_node

camera_node从您的计算机上的相机设备0读取,在图像上写入一些信息并发布它。watermark_node订阅camera_node的输出,并在发布之前添加更多信息。 最后,image_view_node订阅watermark_node的输出,将更多信息写入图像,然后用cv::imshow将其可视化。

在每个节点中,正在发送的或者已经接收到的消息的地址或者两者都被写入到图像中。 watermark和 image view节点被设计成在不复制图像的情况下修改图像。

so the addresses imprinted on the image
should all be the same as
long as the nodes are in the same process and the graph
remains organized in a pipeline as sketched above.

执行ros2 run intra_process_demo image_
pipeline_all_in_one命令来进行测试

ROS2入门教程-ROS2和不同的DDS程序

1. 关系:

ROS2是建立在DDS程序的基础上的。

DDS程序被用来发现节点,序列化和传递信息。

2. 这篇文章详细介绍了DDS程序的开发动机。

总而言之,DDS程序提供了ROS系统所需的一些功能,比如分布式发现节点(并不是像ROS1那样中心化)

控制传输中的不同的"通信质量(Quality of Service)"选项

3. DDS:

DDS是一个被很多公司实现的工业标准。

比如RTI的实现Connext和eProsima的实现Fast RTPS。

ROS2 支持多种实现方式。因为没有必要“一个尺码的鞋给所有人穿”。用户有选择的自由。

在选择DDS实现的时候你要考虑很多方面:比如法律上你要考虑他们的协议,技术上要考虑是否支持跨平台。

不同的公司也许会为了适应不同的场景提出不止一种的DDS实现方式。

比如RTI为了不同的目标就有很多种他们的Connext的变种。

从小到微处理器到需要特殊资质的应用程序(我们支持标准的桌面版)

4. 中间件:

为了能够在ROS2中使用一个DDS实现,需要一个ROS中间件(RMW软件包)

这个包需要利用DDS程序提供的API和工具实现ROS中间件的接口。

为了在ROS2中使用一个DDS实现,有大量的工作需要做。

但是为了防止ROS2的代码过于绑定某种DDS程序必须支持至少几种DDS程序。

因为用户可能会根据他们的项目需求选择不同的DDS程序。

5. 支持的RMW实现

eProsima Fast RTPS 等

ROS2入门教程-接口

1. 背景:

ROS程序一般通过一种或两种接口进行通信:消息和服务

ROS使用了一种简化的描述语言来描述这些接口。

这种描述语言使得ROS的工具更加容易的自动生成对应语言的源代码。

在这篇文章中,我们将介绍支持的类型和如何创建你的 msg/srv文件

2. 消息描述说明

消息的描述文件是在ROS软件包msg文件夹内的.msg文件。 .msg文件有两个部分:变量域(Fields)和常量(constants)

这里将Field翻译成变量域以和constants做作对比区分。

变量域

每一个域包含两个部分, 类型和名称。

中间用空格隔开,例如

fieldtype1 fieldname1
fieldtype2 fieldname2
fieldtype3 fieldname3

示例:

int32 my_int
string my_string

变量域类型

变量域的类型可以是一下几种

内部定义类型

有用户自己定义的类型,比如 “geometry_msgs/PoseStamped”

内部定义的类型现在支持一下几种:

每种内部定义类型都可以用来定义数组

所有比ROS变量定义中范围更广,更加宽松的变量,都会被软件限制在ROS所定义的范围中。

使用数组和限制类型的消息定义的例子

int32[] unbounded_integer_array
int32[5] five_integers_array
int32[<=5] up_to_five_integers_array

string string_of_unbounded_size
string<=10 up_to_ten_characters_string

string[<=5] up_to_five_unbounded_strings
string<=10[] unbounded_array_of_
string_up_to_ten_characters each string<=10[<=5] up_to_five_strings
_up_to_ten_characters_each

变量域名称

变量域名称必须以小写字母开始,同时以下划线作为单词的分割符。

不能以下划线结束,也不允许有两个连续的下划线。

变量域默认值

默认值可以设置成变量域类型所允许的任意值。

当前默认值还不能支持字符串数组和复杂类型。

也就是没有出现在内部定义类型里面的,同样也适用于所有的嵌套消息

定义默认值可以通过在变量域定义中添加第三个元素来实现。

也就是:

变量域名称 变量域类型 变量域默认值

示例:

uint8 x 42
int16 y -2000
string full_name "John Doe"
int32[] samples [-200, 
-100, 0, 100, 200]

特别说明:

字符串类型默认值必须用单引号或者双引号括起来

当前的字符串类型是没有被转义的

常量

常量的定义就好像有默认值的变量域定义。除了常量的值是永远不能由程序改变的。

常量通过等号进行赋值。

比如:

常量类型 常量名称=常量值

示例:

int32 X=123
int32 Y=-123
string FOO="foo"
string EXAMPLE='bar'

特别说明:常量名必须是大写

服务定义说明

服务描述由位于ROS包下的srv文件夹内的.srv文件定义。

一个服务描述文件包含了一个请求和一个回应的消息类型。

之间用---分割。

任意的两个消息类型连接起来,并在中间用---分割都是一个合法的服务描述。

下面是一个非常简单的服务的例子。

这个服务接收一个字符串然后返回一个字符串:

string str
---
string str

当然也可以更加复杂一点(如果你想引用来自同一个软件包内的消息类型,那么你一定不要包含这个软件包的名字):

#request constants
int8 FOO=1
int8 BAR=2
#request fields
int8 foobar
another_pkg/AnotherMessage msg
---
#response constants
uint32 SECRET=123456
#response fields
another_pkg/YetAnotherMessage val
CustomMessageDefinedInThisPackage value
uint32 an_integer

 

不能在一个服务中嵌入另外一个服务。

ros2命令

源代码在这里ros2

https://github.com/ros2/ros2cli

ROS2入门教程-在一个进程中使用多个节点

说明:

介绍如何在同一个进程中使用多个节点

1. ROS 1 - Node 和 Nodelets

在ROS1中你可以写一个节点也可以写一个小节点(Nodelet)。

ROS 1 的节点会被编译成一个可执行文件。

ROS 1的小节点会被编译成一个动态链接库。

当程序运行的时候会被动态的加载到容器进程里面。

2. ROS 2 - 统一API

在ROS2里面,推荐编写小节点——我们称之为组件Component。

这样我们就更容易为已经存在的代码添加一些通用的概念,比如生命周期.

使用不同的API所带来的麻烦完全被ROS2给避免了。

节点和小节点在ROS2中完全使用相同的API。

你也可以继续使用节点的风格的主函数,但是一般是并不推荐的

通过把进程的结构变成一个部署是的选项,用户可以自由的在下面的模式进行选择

在不同的进程中运行多个节点。这样可以使不同的进程独立开。一个崩溃其他可以正常运行。也更方便调试各个节点。

在同一个进程中运行多个节点。这样可以使得通信更加高效。

在未来的roslaunch版本中,会支持配置进程的结构。

3. 编写一个组件

由于一个组件会被编译生成一个共享链接库。

所以它并没有一个主函数入口。(see Talker source code) 组件继承自rclcpp::Node类

// Copyright 2016 Open Source
Robotics Foundation, Inc.
// // Licensed under the Apache License,
Version 2.0 (the "License");
// you may not use this file except
in compliance with the License.
// You may obtain a copy of the License at // // http://www.apache.org
/licenses/LICENSE-2.0
// // Unless required by applicable law
or agreed to in writing, software
// distributed under the License
is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied.
// See the License for the specific
language governing permissions and
// limitations under the License. #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)

由于它并不由一个线程直接控制,所以不要在构造函数里面执行很长时间的任务,甚至是阻塞的任务。

你可以用定时器来实现周期性的提示。

另外它可以创建发布者,订阅者,服务提供者和服务客户端。

为了使这样一个类能够成为一个组件,很重要的一点是使用class_loader软件包注册自己(可以查看最后一行的源代码)。

这样组件就能够在库文件被加载进进程时被发现。

4.使用组件

composition软件包包含了几种不同的使用组件的方式。

最常见的是下面几种

你启动了一个通用的容器进程(1) 然后调用由此容器提供的ROS服务load_node。 这个ROS服务接着会根据传入的软件包名称和组件名称载入对应的组件开始执行。 除了使用程序来调用ROS服务外,你还可以使用命令行工具去传入参数触发ROS服务。

你可以创建一个自定义的可执行文件。这个文件中包含多个节点。 这种方法要求每个组件都有一个头文件。(第一个方法并不需要这样)

5. 运行例子程序

来自composition软件包的程序可以通过下面的指令执行

使用ROS服务的运行时组件(第一种方式)。此组件有发布者和订阅者

使用ROS服务的运行时组件(第一种方式)。此组件有服务提供者和服务客户端

使用ROS服务的编译时组件(第二种方式)

这个例子展示了相同的共享链接库可以重用然后编译出一个使用多个组件的可执行程序。

这个程序包含了以上的四个组件:发布者,订阅者,服务提供者,服务客户端

使用dlopen的运行时组件

这个例子展示了第一种的替代方式。启动一个通用的容器进程,然后不通过ROS接口直接传递给它要载入的库。

这个进程会载入每一个库,然后创建对应的"rclcpp::Node"类示例。

ROS2入门教程-定义自定义接口(消息和服务)

尽管我们鼓励重用已有的标准消息和服务定义。

然而在很多情况下你还是要自己定义消息或者服务。

自定义消息和服务第一步时创建.msg或.srv文件。

定义方式可以参照ROS接口

为了方便起见,.msg文件放置于软件包文件夹下的msg文件夹内。

.srv文件放置于srv文件夹内。

在写完你的.msg或.srv文件后,你需要在你的CmakeLists.txt文件内添加一些代码。

使得代码生成程序能够处理你的定义文件。

先要了解更加详细的教程可以参照pendulum_msgs package,作为一个例子。

你可以在这个包的CMakeLists.txt文件中看到相关的CMake的调用。

ROS2入门教程-ROS 2的接口新功能(消息和服务)

ROS2的接口定义语言和ROS1的非常接近。

基本上所有的ROS1的.msg和.srv文件都可以在ROS2里面重用。

ROS2在1的基础上有新增加了一些功能即

bounded arrays:

ROS1只支持没有限制的数组(比如int32[] foo)和固定大小的数据(比如int32[5] bar), ROS2 支持有限制的数据(int32[<5] bat) 在有些应用场景下是可以给数组的大小定一个上界的,这样可以节省大量的空间。

bounded strings:

同样ROS1也只支持没有限制的字符串。ROS2可以支持有限制的字符串。(string<=5 bar)

default values:

ROS1中支持常量(int32 X=123)但没有默认值, ROS 2 支持默认值(int32 X 123) 当创建一个消息或服务时,如果没有额外设置,则会采用默认值。如果设值则默认值会被覆盖。

注意: 在 beta 1版本中默认值只支持数字类型,数字数组类型,和字符串类型(没有经过转义和编码)。

ROS2入门教程-自定义内存分配器

说明:

介绍如何给发布者和订阅者写一个自定义的内存分配器。

作用:

这样当你的ROS节点程序运行时就会通过你的内存分配器给你的程序分配内存,而不会使用默认的内存分配器。

这个例程的源代码可以在这里获取

1. 背景

假如你想写实时运行的安全可靠的代码,那么你一定听说过使用 new 来实时分配内存时可能造成的种种危险。

因为默认的在各种平台上的内存分配器都是不确定的。

默认情况下。很多标准的C++库数据结构在数据增加的时候都会自动分配内存。

比如std::vector.然而这些数据结构也接收一个"内存分配器"参数。

如果你给其中的一种数据结构指定了内存分配器,那么它就会使用你的内存分配器而不用系统的内存分配器去分配内存。

你的内存分配器可以是一个已经提前分配好的内存栈。这样就更适合于实时运行的程序。

在ROS2 C++客户端程序中(rclcpp),我们和C++标准库有着类似的原则。

发布者订阅者和执行者接受一个内存分配器参数。

这个分配器在运行时控制着整个程序。

2. 编写一个内存分配器

为了写一个和ROS2接口兼容的内存分配器,你的分配器必须兼容C++标准库的内存分配器接口。

C++标准库提供了一个叫做 allocator_traits的东西。

C++标准库的内存分配器只需要实现很少的几个方法就可以按照标准的方式去分配和回收内存。

allocator_traits是一个通用的结构,它提供了通过通用内存分配器编写一个内存分配器所需要的其他参数。

例如,下面的对于一个内存分配器的声明就满足 allocator_traits(当然,你还是需要实现这个声明中的各种函数)

template <class T>
struct custom_allocator {
using
value_type = T; custom_allocator() noexcept; template <class U>
custom_allocator (const
custom_allocator<U>&) noexcept; T* allocate (std::size_t n); void deallocate (T* p, std::size_t n); }; template <class T, class U> constexpr bool operator== (
const
custom_allocator<T>&
, const custom_allocator<U>&) template <class T, class U> constexpr bool operator!=
(
const custom_allocator<T>&
, const custom_allocator<U>&)

然后你可以通过下面的方式来访问由allocator_traits配置的内存分配器内部的各种函数和成员变量:

std::allocator_traits<
custom_allocator<T>>::construct(...)

想要了解allocator_traits的全部功能可以看文档:http://en.cppreference
.com/w/cpp/memory/allocator_traits

然而有些编译器只有部分的C++ 11支持。比如GCC 4.8, 这样就还需要写大量的样板代码来在标准数据结构(比如数据和字符串)中使用. 因为结构并没有在内部使用 allocator_traits。

因此如果你在使用一个只有部分C++11支持的编译器。

你的内存分配器就会需要写成这样:

template<typename T>
struct pointer_traits {
  using reference = T &;
  using const_reference = const T &;
};

// Avoid declaring a reference
to void with an empty specialization template<> struct pointer_traits<void> { }; template<typename T = void> struct MyAllocator : public
pointer_traits<T> { public: using value_type = T; using size_type = std::size_t; using pointer = T *; using const_pointer = const T *; using difference_type =
typename std::pointer_
traits<pointer>::difference_type; MyAllocator() noexcept; ~MyAllocator() noexcept; template<typename U> MyAllocator
(const MyAllocator<U> &) noexcept; T * allocate
(size_t size, const void * = 0); void deallocate(T * ptr, size_t size); template<typename U> struct rebind { typedef MyAllocator<U> other; }; }; template<typename T, typename U> constexpr bool operator
==(const MyAllocator<T> &, const MyAllocator<U> &) noexcept; template<typename T, typename U> constexpr bool operator!
=(const MyAllocator<T> &, const MyAllocator<U> &) noexcept;

3. 写一个主函数例子

当你写了一个内存分配器之后,你必须把它通过一个共享指针传递给你的发布者,订阅者和执行者。

  auto alloc = std::make_shared
<MyAllocator<void>>(); auto publisher = node->create_
publisher<std_msgs::msg::UInt32
>("allocator_example", 10, alloc); auto msg_mem_strat = std::make_shared<rclcpp::
message_memory_strategy::
MessageMemoryStrategy<
std_msgs::msg::UInt32, MyAllocator<>>>(alloc); auto subscriber = node->
create_subscription<std_
msgs::msg::UInt32>( "allocator_example", 10,
callback, nullptr, false
, msg_mem_strat, alloc); std::shared_ptr<rclcpp::
memory_strategy::Memory
Strategy> memory_strategy = std::make_shared<Allocator
Memory
Strategy<MyAllocator<>>>(alloc); rclcpp::executors::Single
ThreadedExecutor executor
(memory_strategy);

在你的代码执行的过程中所传递的消息也需要通过你的内存分配器来分配。

 auto alloc = std::
make_shared<MyAllocator<void>>();

当你已经实例化一个节点,给这个节点添加一个执行者之后,就是spin的时候了

 uint32_t i = 0;
  while (rclcpp::ok()) {
    msg->data = i;
    i++;
    publisher->publish(msg);
    rclcpp::utilities::sleep_for
(std::chrono::milliseconds(1)); executor.spin_some(); }

4. 在进程内传递内存分配器

尽管我们已经在同一个进程中创建了一个发布者和订阅者,我们还是不能在进程内的发布者和订阅者间传递内存分配器。

进程内管理器是一个通常对用户隐藏的类。

但是为了能够传递自定义的内存分配器,我们需要通过rcl context把它暴露出来。

进程内管理器使用了几种标准的数据结构,所以如果没有自定义的内存管理器,它就会使用默认的new。

  auto context = rclcpp::contexts::
default_context::get_global_default_context(); auto ipm_state = std::make_shared<rclcpp::
intra_process_manager::
IntraProcessManagerState<MyAllocator<>>>(); // Constructs the intra-process
manager with a custom allocator.
context->get_sub_context<rclcpp
::intra_process_manager::
IntraProcessManager>(ipm_state); auto node = rclcpp::Node::
make_shared
("allocator_example", true);

 

一定要确保在这样构造节点之后实例化发布者和订阅者。

TLSF内存分配器

ROS2 提供了TLSF(两层分离适应)内存分配器支持。它为了满足实时性要求而被设计出来:

https://github.com/ros2/
realtime_support/tree/master/tlsf_cpp

注意TLSF内存分配器是dual-GPL/LGPL协议的。

下面是一个使用TLSF内存分配器的例子

https://github.com/ros2/realtime_
support/blob/master/tlsf_cpp
/example/allocator_example.cpp

ROS2入门教程-服务质量控制

说明:

介绍如何实现服务质量控制

简介:

ROS2 提供了提供了非常丰富的服务质量控制规则。

利用这些规则你可以优化微调节点间的通信。

合适的服务质量设置可以使得ROS2像TCP协议一样可靠谱或者像UDP协议一样高效。

亦或者在之间的无线可能的状态之中。

在ROS1中,我们只能支持TCP协议。

ROS2则受益于底层的DDS传输可以灵活设置。

对于在一个容易丢失数据的无线网环境下,可以使用一个高效的服务质量规则。

对于在实时计算情况下可以使用高可靠性的服务质量规则。

一组服务质量规则组合在一起就构成了一个服务质量配置文件。

由于在不同的场景中设置合适的服务质量配置文件并不是一个简单的事情。

ROS2预先提供了一些常用情景下的配置文件。

(比如传感器数据) 同时用户也可以更改服务质量的具体配置。

服务质量文件可以专门用来配置发布者,订阅者,服务提供者和客户端。

一个服务质量文件可以独立应用于不同的上面所说的各种实体。

但是如果它们之间使用了不同的服务质量文件那么有可能它们之间会无法建立连接。

ROS2入门教程-客户端程序库

说明:

介绍有那些编程语言实现ROS2接口

1.客户端程序库

客户端程序库是用户在写自己的ROS程序时使用到的ROS API程序。

他们就是用户来访问ROS的基本概念比如节点,主题,服务等等时所使用的程序。

客户端程序库有很多不同语言的实现,这样用户就可以根据他们自己的使用场景灵活的选择最合适的语言。

例如你也许想用Python来写图形程序,因为写起来很方便。但是对于对性能要求比较高的地方,这些程序最好还是用C++来写。

使用不同语言编写的程序之间可以自由的共享信息。

因为所有的客户端程序库都提供了代码生成程序,这些程序为用户提供了能够处理ROS的接口文件的能力。

2. 核心功能:

客户端程序除了提供不同语言特定的通信工具之外,还为用户提供了一些使得ROS更加ROS化的核心功能。

比如,这些就是可以通过客户端程序库操作的核心功能

名称和命名空间
时间(实际的或者模拟的)
参数
终端输出
线程模型
跨进程通信
支持的客户端程序库:

C++ 客户端程序库(rclcpp)和Python客户端程序库(rclpy)都提供了RCL的常用功能。

C++和Python的客户端程序库由 ROS 2 团队维护,ROS2的社区成员同时也支持了以下额外的客户端程序库:

JVM 和 Android
Objective C 和 iOS
C#
Swift
Node.js

3. 通用的功能:RCL

大部分客户端程序库提供的功能并不只是在特定的语言里才有。

比如参数的效果,命名空间的逻辑,在理想的情况下应该在所有的语言下保持一致。

正是因为这一点,与其为每种语言从零开始实现一遍,倒不如使用一个通用的核心ROS客户端程序库接口。

这个接口实现了程序逻辑和ROS中语言无关的功能。

这样就使得ROS客户端程序库更小也更容易开发。

由于这个原因,RCL通用功能暴露出了C的程序接口。

因为C是其他程序语言最容易进行包装的语言。

使用通用的核心库的优点不止可以使得客户端程序更加小型化,同时也使得不同语言的客户端程序库能够保持高度的一致性。

如果通用核心库内的任何功能发生了变化,比如说命名空间,那么所有的客户端程序库的这个功能都会跟着变化。

再者使用通用的核心程序库也意味着当修复bug的时候维护多个客户端程序会更加方便。

RCL 的 API文档可以看这里:http://docs.ros2.org/beta1/api/rcl/

4. 和语言相关的功能

对于和语言相关的功能,并没有在RCL中实现,而是在各个语言的客户端程序库中去实现。

例如,在spin中使用到的线程模型,完全由各语言客户端程序自己实现。

5. 例子

对于一个使用rclpy的发布者和一个使用rclcpp的订阅者之间的消息传递的例子,一些相关的幻灯片
https://roscon.ros.org/2016/
presentations/ROSCon%202016%2
0-%20ROS%202%20Update.pdf

6. 与ROS1相比

在ROS1中所有的客户端程序都是从零开始编写的。

这样可以使Python的客户端程序库完全由Python编写。

这样就有不用编译源代码的好处。

但是命名规则和其他一些特性并不能和其他客户端程序库保持一致。

bug的修复需要在不同的地方重复很多遍。

而且有很多功能只有在特定语言的客户端程序库中才实现。

总结

通过把ROS通用客户端核心程序库抽出来,不同的语言的客户端程序变得更加容易开发也更能保证功能的一致性。

ROS2入门教程-turtlesim和rqt

启动turtlesim

ros2 run turtlesim turtlesim_node

新开终端,启动键盘

ros2 run turtlesim turtle_teleop_key

启动rqt

rqt

使用rqt

选择Plugins > Services > Service Caller

测试spawn service

选择service为spawn

更改name为turtle2 ,更改坐标为x = 1.0 和y = 1.0

效果如图:

点击call之后,会在指定的位置弹出第二个小乌龟

测试set_pen service

更改r, g 和 b的值改变小乌龟的移动轨迹的颜色

效果如下:

remap话题

指定控制第二个小乌龟

ros2 run turtlesim turtle_teleop_key
--ros-args --remap turtle1/cmd_vel:=turtle2

ROS2入门教程-nodes简介

说明:

介绍ros2节点,节点图

概念:

ROS graph 是由ROS 2元素同时处理数据的网络。

如果要全部映射可执行文件并将其可视化,则它包含所有可执行文件及其之间的连接。

ROS中的每个节点应负责一个单一模块目的(例如,一个节点用于控制轮式电机,一个节点用于控制激光测距仪等)。

每个节点都可以通过主题,服务,操作或参数向其他节点发送和接收数据。

完整的机器人系统由许多协同工作的节点组成。

在ROS 2中,单个可执行文件(C ++程序,Python程序等)可以包含一个或多个节点。

1. 运行节点:

安装好turtlesim例子

运行节点: ros2 run <package_name> <executable_name>

例如启动turtlesim:

ros2 run turtlesim turtlesim_node

turtlesim 为包名,turtlesim_node为节点名

2. 列出节点:

列出所有节点命令:ros2 node list

启动键盘

ros2 run turtlesim turtle_teleop_key

效果如下:

$ ros2 node list
/turtlesim
/teleop_turtle

 

发现有两个节点,turtlesim和teleop_turtle

3. 映射

重新设定节点名称

ros2 run turtlesim turtlesim_node --ros-args --remap __node:=my_turtle

则turtlesim的节点名,变成指定的名称my_turtle

例如

$ ros2 node list

/turtlesim
/teleop_turtle
/my_turtle

4. 查看节点信息:

命令:ros2 node info <node_name>

例如执行:

ros2 node info /my_turtle

效果如下:

/my_turtle
  Subscribers:
    /parameter_events: rcl_interface
s/msg/ParameterEvent /turtle1/cmd_vel: geometry_msgs
/msg/Twist Publishers: /parameter_events: rcl_interfaces
/msg/ParameterEvent /rosout: rcl_interfaces/msg/Log /turtle1/color_sensor: turtlesim
/msg/Color /turtle1/pose: turtlesim/msg/Pose Services: /clear: std_srvs/srv/Empty /kill: turtlesim/srv/Kill /reset: std_srvs/srv/Empty /spawn: turtlesim/srv/Spawn /turtle1/set_pen: turtlesim
/srv/SetPen /turtle1/teleport_absolute:
turtlesim/srv/TeleportAbsolute /turtle1/teleport_relative:
turtlesim/srv/TeleportRelative /my_turtle/describe_parameters:
rcl_interfaces/srv/DescribeParameters /my_turtle/get_parameter_types:
rcl_interfaces/srv/GetParameterTypes /my_turtle/get_parameters:
rcl_interfaces/srv/GetParameters /my_turtle/list_parameters:
rcl_interfaces/srv/ListParameters /my_turtle/set_parameters:
rcl_interfaces/srv/SetParameters /my_turtle/set_parameters_
atomically: rcl_interfaces/
srv/SetParametersAtomically Action Servers: /turtle1/rotate_absolute:
turtlesim/action/RotateAbsolute Action Clients:

ROS2入门教程-topics(话题) 简介

说明:

介绍ros2 topic(话题)

概念:

ros2 topic是节点和节点之间进行通讯的桥梁

1. rqt_graph命令:

新开终端,启动turtlesim

ros2 run turtlesim turtlesim_node

新开终端,启动键盘控制

ros2 run turtlesim turtle_teleop_key

rqt_graph显示话题订阅关系

新开终端,执行 rqt_graph

上图显示节点turtlesim和节点teleop_turtle是如何通过话题/turtle1/cmd_vel来进行通讯

2. ros2 topic list命令:

列出所有的话题

$ ros2 topic list
/parameter_events
/rosout
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose

 

列出所有的话题,并显示相应的消息类型

$ ros2 topic list -t
/parameter_events [rcl_
interfaces/msg/ParameterEvent] /rosout [rcl_interfaces/msg/Log] /turtle1/cmd_vel [geometry
_msgs/msg/Twist] /turtle1/color_sensor
[turtlesim/msg/Color] /turtle1/pose [turtlesim
/msg/Pose]

3. ros2 topic echo命令:

显示话题内容:ros2 topic echo <topic_name>

例如:

$ ros2 topic echo /turtle1/cmd_vel

linear:
  x: 2.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 0.0
  ---

4. ros2 topic info命令:

显示话题相关信息,类型,发布和订阅次数

$ ros2 topic info /turtle1/cmd_vel

Type: geometry_msgs/msg/Twist
Publisher count: 1
Subscriber count: 2

5. ros2 interface show命令

通过ros2 topic list -t来获取话题类型

$ ros2 topic list -t
/parameter_events [rcl_
interfaces/msg/ParameterEvent] /rosout [rcl_interfaces
/msg/Log] /turtle1/cmd_vel [geometry
_msgs/msg/Twist] /turtle1/color_sensor
[turtlesim/msg/Color] /turtle1/pose [turtlesim/msg/Pose]

ros2 interface show显示消息接口内容

$ ros2 interface show
geometry_msgs/msg/Twist # This expresses velocity in free
space broken into its
linear and angular parts. Vector3 linear Vector3 angular

 

6. ros2 topic pub命令:

命令格式:

   ros2 topic pub <topic
_name> <msg_type> '<args>'

 

例如发布速度命令

ros2 topic pub --once /turtle1/
cmd_vel geometry_msgs/msg/
Twist "{linear: {x: 2.0, y: 0.0,
z: 0.0}, angular: {x: 0
.0, y: 0.0, z: 1.8}}"

按一定频率发布

ros2 topic pub --once /turtle1/cmd_vel
geometry_msgs/msg/Twist "{linear:
{x: 2.0, y: 0.0, z: 0.0}, angular:
{x: 0.0, y: 0.0, z: 1.8}}"

7. ros2 topic hz命令

显示话题的发布频率:

$ ros2 topic hz /turtle1/pose
average rate: 62.460
    min: 0.015s max: 0.017s
std dev: 0.00036s window: 64 average rate: 62.493 min: 0.015s max: 0.017s
std dev: 0.00036s window: 127 average rate: 62.504 min: 0.015s max: 0.017s
std dev: 0.00037s window: 190 average rate: 62.502 min: 0.014s max: 0.017s
std dev: 0.00037s window: 253

ROS2入门教程-services简介

说明:

介绍ros2 services(服务)

概念:

services(服务)是ROS图上节点通信的另一种方法。

服务基于呼叫响应模型,而不是主题的发布者-订阅者模型。

尽管主题允许节点订阅数据流并获得连续更新,但是服务仅在客户端专门调用它们时才提供数据。

1. ros2 service list命令:

列出所有的服务

$ ros2 service list
/clear
/kill
/reset
/spawn
/teleop_turtle/describe_parameters
/teleop_turtle/get_parameter_types
/teleop_turtle/get_parameters
/teleop_turtle/list_parameters
/teleop_turtle/set_parameters
/teleop_turtle/set_
parameters_atomically /turtle1/set_pen /turtle1/teleport_absolute /turtle1/teleport_relative /turtlesim/describe_parameters /turtlesim/get_parameter_types /turtlesim/get_parameters /turtlesim/list_parameters /turtlesim/set_parameters /turtlesim/set_parameters
_atomically

显示服务及消息类型:

$ ros2 service list -t
/clear [std_srvs/srv/Empty]
/kill [turtlesim/srv/Kill]
/reset [std_srvs/srv/Empty]
/spawn [turtlesim/srv/Spawn]
/teleop_turtle/describe_parameters
[rcl_interfaces/
srv/DescribeParameters] /teleop_turtle/get_parameter_types
[rcl_interfaces/srv/GetParameterTypes] /teleop_turtle/get_parameters
[rcl_interfaces/srv/GetParameters] /teleop_turtle/list_parameters
[rcl_interfaces/srv/ListParameters] /teleop_turtle/set_parameters
[rcl_interfaces/srv/SetParameters] /teleop_turtle/set_parameters
_atomically
[rcl_interfaces/srv/
SetParametersAtomically] /turtle1/set_pen [turtlesim
/srv/SetPen] /turtle1/teleport_absolute
[turtlesim/srv/TeleportAbsolute] /turtle1/teleport_relative
[turtlesim/srv/TeleportRelative] /turtlesim/describe_parameters
[rcl_interfaces/srv/DescribeParameters] /turtlesim/get_parameter_types
[rcl_interfaces/srv/GetParameterTypes] /turtlesim/get_parameters [rcl
_interfaces/srv/GetParameters] /turtlesim/list_parameters
[rcl_interfaces/srv/ListParameters] /turtlesim/set_parameters
[rcl_interfaces/srv/SetParameters] /turtlesim/set_parameters
_atomically [rcl_
interfaces/srv/
SetParametersAtomically]

ros2 service type 命令:

服务接收的消息类型

格式:ros2 service type <service_name>

例子:

$ ros2 service type /clear
std_srvs/srv/Empty

ros2 service find命令:

找到使用某类消息类型的服务

格式:ros2 service find <type_name>

例子:

$ ros2 service find std_srvs/srv/Empty
/clear
/reset

ros2 interface show命令:

显示服务的消息类型具体定义

格式:ros2 interface show <type_name>.srv

例子:

$ ros2 interface show 
std_srvs/srv/Empty.srv --- 例子2: $ ros2 interface show turtle
sim/srv/Spawn.srv float32 x float32 y float32 theta string name # Optional. A unique
name will be created and
returned if this is empty --- string name

 

ros2 service call命令:

调用服务命令

格式:ros2 service call <service_name> <service_type>

例子:

#清除行走轨迹
 ros2 service call /clear std_srvs/srv/Empty

ROS2入门教程-parameters简介

说明:

介绍ros2 parameters(参数)

概念:

参数是节点的配置值。

您可以将参数视为节点设置。

节点可以将参数存储为整数,浮点数,布尔值,字符串和列表。

在ROS 2中,每个节点都维护自己的参数。

所有参数都是可以动态重新配置的,并且是基于ROS 2服务构建的。

1. ros2 param list命令:

列出所有节点的参数名称

例子:

$ ros2 param list
/teleop_turtle:
  scale_angular
  scale_linear
  use_sim_time
/turtlesim:
  background_b
  background_g
  background_r
  use_sim_time

2. ros2 param get命令:

获取参数值

格式:ros2 param get <node_name> <parameter_name>

例子

$ ros2 param get /turtlesim background_g
Integer value is: 86

3. ros2 param set命令:

设置参数值

格式:ros2 param set <node_
name> <parameter_name> <value>

例子:

$ ros2 param set /
turtlesim background_r 150 Set parameter successful

设置背景颜色

4. ros2 param dump命令:

导出参数值

格式:ros2 param dump <node_name>

例子:

$ ros2 param dump /turtlesim
Saving to:  ./turtlesim.yaml

效果:

$ cat turtlesim.yaml 
turtlesim:
  ros__parameters:
    background_b: 255
    background_g: 86
    background_r: 150
    use_sim_time: false

导入参数

格式:ros2 run <package_name> <executable_name> --ros-args --params-file <file_name>

例子:

$ ros2 run turtlesim turtlesim_node 
--ros-args --params-file ./turtlesim.yaml [INFO] [1595309657.037505054]
[turtlesim]: Starting turtlesim
with node name /turtlesim [INFO] [1595309657.040409004]
[turtlesim]: Spawning turtle [turtle1]
at x=[5.544445], y=[5.544445],
theta=[0.000000]

导入后启动turtlesim

ROS2入门教程-actions简介

说明:

介绍ros2 actions(动作)

概念:

动作是ROS 2中用于长时间运行任务的通信类型之一。

它们由三部分组成:目标,结果和反馈。

动作基于话题题和服务。

它们的功能与服务相似,但动作是可抢占的(可以在执行时将其取消)。

与返回单个响应的服务相反,它们还提供稳定的反馈。

操作使用客户端-服务器模型,类似于发布者-订阅者模型(在主题教程中进行了描述)。

“动作客户端”节点将目标发送到“动作服务器”节点,该节点确认该目标并返回反馈和结果流。

ROS2入门教程-rqt_console简介

说明:

介绍ros2 rqt_console日志查看工具

概念:

rqt_console是一个GUI工具,用于自检ROS 2中的日志消息。

通常,日志消息显示在终端中。

使用rqt_console,您可以随着时间的推移收集这些消息,以更有条理的方式仔细查看它们,过滤它们,保存它们,甚至重新加载保存的文件以在不同的时间进行内部检查。

节点使用日志以各种方式输出有关事件和状态的消息。

为了用户的利益,它们的内容通常是信息性的。

日志消息的意图由节点的作者定义,尽管内容可以在运行时编写。

运行:

执行命令:

ros2 run rqt_console rqt_console

ROS2入门教程-创建launch文件

说明:

介绍如何创建launch文件

步骤:

新建目录

mkdir ~/luanch

新建文件

cd ~/luanch
touch turtlesim_mimic_launch.py

 

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='turtlesim',
            namespace='turtlesim1',
            executable='turtlesim_node',
            name='sim'
        ),
        Node(
            package='turtlesim',
            namespace='turtlesim2',
            executable='turtlesim_node',
            name='sim'
        ),
        Node(
            package='turtlesim',
            executable='mimic',
            name='mimic',
            remappings=[
                ('/input/pose', 
'/turtlesim1/turtle1/pose'), ('/output/cmd_vel',
'/turtlesim2/turtle1/cmd_vel'), ] ) ])

 

代码解析

导入launch和node包

from launch import LaunchDescription
from launch_ros.actions import Node

定义launch描述函数

def generate_launch_description():
   return LaunchDescription([

   ])

调用两个节点打开两个turtlesim

Node(
    package='turtlesim',
    namespace='turtlesim1',
    executable='turtlesim_node',
    name='sim'
),
Node(
    package='turtlesim',
    namespace='turtlesim2',
    executable='turtlesim_node',
    name='sim'
),

调用第三个节点,turtlesim2跟随turtlesim1的位置变化而变化

Node(
    package='turtlesim',
    executable='mimic',
    name='mimic',
    remappings=[
      ('/input/pose', '
/turtlesim1/turtle1/pose'), ('/output/cmd_vel',
'/turtlesim2/turtle1/cmd_vel'), ] )

 

ROS2入门教程-rosbag简介

说明:

介绍ros2 rosbag工具

概念:

ros2 bag是一个命令行工具,用于记录系统中有关主题的发布数据。

它累积在任意数量的话题上传递的数据,并将其保存在数据库中。

然后,您可以重播数据以重现测试和实验的结果。

记录话题也是共享您的作品并允许其他人重新创建作品的一种好方法。

记录单个话题

$ ros2 bag record /
turtle1/cmd_vel [INFO] [rosbag2_storage]: Opened database
'rosbag2_2019_10_11-05_18_45'. [INFO] [rosbag2_transport]: Listening for
topics... [INFO] [rosbag2_transport]: Subscribed to
topic '/turtle1/cmd_vel' [INFO] [rosbag2_transport]: All requested
topics are subscribed. Stopping discovery...

 

中止记录,ctrl+c,默认保存格式为rosbag2_year_month_day-hour_minute_second的目录

记录多个话题,并指定保存的目录名,例如:

$ ros2 bag record -o subset /turtle1
/cmd_vel /turtle1/pose [INFO] [rosbag2_storage]: Opened
database 'subset'. [INFO] [rosbag2_transport]:
Listening for topics... [INFO] [rosbag2_transport]:
Subscribed to topic '/turtle1/cmd_vel' [INFO] [rosbag2_transport]:
Subscribed to topic '/turtle1/pose' [INFO] [rosbag2_transport]:
All requested topics
are subscribed. Stopping discovery...

 

查看bag信息

$ ros2 bag info subset 

Files:             subset.db3
Bag size:          228.5 KiB
Storage id:        sqlite3
Duration:          48.47s
Start:             Oct 11
2019 06:09:09.12 (1570799349.12) End Oct 11
2019 06:09:57.60 (1570799397.60) Messages: 3013 Topic information: Topic:
/turtle1/cmd_vel | Type:
geometry_msgs/msg/Twist | Count:
9 | Serialization Format: cdr Topic: /turtle1/pose
| Type: turtlesim/msg/Pose |
Count: 3004 | Serialization Format: cdr

重发bag信息

$ ros2 bag play subset
[INFO] [1595321648.231311289]
[rosbag2_storage]: Opened database
'subset/subset_0.db3' for READ_ONLY.

ROS2入门教程-ros2doctor简介

说明:

介绍ros2 ros2doctor

概念:

当ROS 2安装程序未按预期运行时,可以使用ros2doctor工具检查其设置。

ros2doctor检查ROS 2的所有方面,包括平台,版本,网络,环境,正在运行的系统等,并警告您可能的错误和问题原因。

使用:

执行命令

$ ros2 doctor

生产检测报告

ros2 doctor --report

ROS2入门教程-launch文件在ros1和ros2间的异同

说明:

介绍launch文件在ros1和ros2间的异同,便于从ros1向ros2移植

launch标签:

ros1和ros2相同

node标签:

大部分与ros1相同

ros2下差异:

type 属性变为exec

machine, respawn, respawn_delay, clear_params不再使用

例子:

<launch>
   <node pkg="demo_nodes_
cpp" exec="talker"/> <node pkg="demo_nodes_
cpp" exec="listener"/> </launch>

param标签:

大部分与ros1相同

没有全局参数概念

type, textfile, binfile, executable, command不再使用

rosparam标签:

在ros1有效

在param中使用from来加载

remap标签:

在ros1有效

只能在node中使用

include标签:

在ros1有效

需要在group中使用

不支持ns

arg嵌套在include里面,if和unless标签不起效

env不起效,使用set_env和unset_env替代

clear_params 和pass_all_args 不支持

arg标签:

value 用let替代

doc 用description替代

嵌套include ,if和unless不起效

env标签:

env被set_env和unset_env替代

env只用于嵌套node 和executable 标签下,不支持if和unless标签

set_env 可以嵌套在launch和group 标签下

group标签:

没ns属性,查看新属性push-ros-namespace

clear_params不起效

不能使用remap和param 作为下级标签

machine标签:

未支持

test标签:

未支持

ros2新出现的标签:

set_env and unset_env标签:

push-ros-namespace标签:

let标签:与arg功能类似

executable标签:

include标签:用途和ros1不一样, 需要嵌套在group里

 

 
   
1258 次浏览       19
相关文章

手机软件测试用例设计实践
手机客户端UI测试分析
iPhone消息推送机制实现与探讨
Android手机开发(一)
相关文档

Android_UI官方设计教程
手机开发平台介绍
android拍照及上传功能
Android讲义智能手机开发
相关课程

Android高级移动应用程序
Android系统开发
Android应用开发
手机软件测试

最新活动计划
MBSE(基于模型的系统工程)4-18[北京]
自然语言处理(NLP) 4-25[北京]
基于 UML 和EA进行分析设计 4-29[北京]
以用户为中心的软件界面设计 5-16[北京]
DoDAF规范、模型与实例 5-23[北京]
信息架构建模(基于UML+EA)5-29[北京]
 
 
最新文章
简述Matplotlib
Python三维绘图--Matplotlib
Python数据清洗实践
PyTorch实战指南
Python爬虫与数据可视化
最新课程
Python应用开发最佳实践
Python+数据分析+tensorflow
Python 编程方法和应用开发
人工智能+Python+大数据
Python及数据分析
更多...   
成功案例
某通信设备企业 Python数据分析与挖掘
某银行 人工智能+Python+大数据
某领先数字地图提供商 Python数据分析与机器学习
北京 Python及数据分析
某金融公司 Python编程方法与实践培训
更多...