0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

ROS机器人操作系统的实现原理(上)

jf_78858299 来源:古月居 作者:robinvista 2023-05-19 17:41 次阅读

本文介绍ROS机器人操作系统(Robot Operating System)的实现原理,从最底层分析ROS代码是如何实现的。

1、序列化

通信的内容(也就是消息message)序列化是通信的基础,所以我们先研究序列化。

尽管笔者从事机器人学习和研发很长时间了,但是在研究ROS的过程中,“序列化”这个词还是这辈子第一次听到。

所以可想而知很多人在看到“把一个消息序列化”这样的描述时是如何一脸懵逼。

但其实序列化是一个比较常见的概念,你虽然不知道它但一定接触过它。

下面我们先介绍“序列化”的一些常识,然后解释ROS里的序列化是怎么做的?

1.1什么是序列化?

“序列化”(Serialization )的意思是将一个对象转化为字节流。

这里说的对象可以理解为“面向对象”里的那个对象,具体的就是存储在内存中的对象数据。

与之相反的过程是“反序列化”(Deserialization )。

虽然挂着机器人的羊头,但是后面的介绍全部是计算机知识,跟机器人一丁点关系都没有,序列化就是一个纯粹的计算机概念。

序列化的英文Serialize就有把一个东西变成一串连续的东西之意。

形象的描述,数据对象是一团面,序列化就是将面团拉成一根面条,反序列化就将面条捏回面团。

另一个形象的类比是我们在对话或者打电话时,一个人的思想转换成一维的语音,然后在另一个人的头脑里重新变成结构化的思想,这也是一种序列化。

图片

面对序列化,很多人心中可能会有很多疑问。

首先,为什么要序列化?或者更具体的说,既然对象的信息本来就是以字节的形式储存在内存中,那为什么要多此一举把一些字节数据转换成另一种形式的、一维的、连续的字节数据呢?

如果我们的程序在内存中存储了一个数字,比如25。那要怎么传递25这个数字给别的程序节点或者把这个数字永久存储起来呢?

很简单,直接传递25这个数字(的字节表示,即0X19,当然最终会变成二进制表示11001以高低电平传输存储)或者直接把这个数字(的字节表示)写进硬盘里即可。

所以,对于本来就是连续的、一维的、一连串的数据(例如字符串),序列化并不需要做太多东西,其本质是就是由内存向其它地方拷贝数据而已。

所以,如果你在一个序列化库里看到memcpy函数不用觉得奇怪,因为你知道序列化最底层不过就是在操作内存数据而已(还有些库使用了流的ostream.rdbuf()->sputn函数)。

可是实际程序操作的对象很少是这么简单的形式,大多数时候我们面对的是包含不同数据类型(int、double、string)的复杂数据结构(比如vector、list),它们很可能在内存中是不连续存储的而是分散在各处。比如ROS的很多消息都包含向量。

数据中还有各种指针和引用。而且,如果数据要在运行于不同架构的计算机之上的、由不同编程语言所编写的节点程序之间传递,那问题就更复杂了,它们的字节顺序endianness规定有可能不一样,基本数据类型(比如int)的长度也不一样(有的int是4个字节、有的是8个字节)。

这些都不是通过简单地、原封不动地复制粘贴原始数据就能解决的。这时候就需要序列化和反序列化了。

所以在程序之间需要通信时(ROS恰好就是这种情况),或者希望保存程序的中间运算结果时,序列化就登场了。

另外,在某种程度上,序列化还起到统一标准的作用。

图片

我们把被序列化的东西叫object(对象),它可以是任意的数据结构或者对象:结构体、数组、类的实例等等。

把序列化后得到的东西叫archive,它既可以是人类可读的文本形式,也可以是二进制形式。

前者比如JSON和XML,这两个是网络应用里最常用的序列化格式,通过记事本就能打开阅读;

后者就是原始的二进制文件,比如后缀名是bin的文件,人类是没办法直接阅读一堆的0101或者0XC9D23E72的。

序列化算是一个比较常用的功能,所以大多数编程语言(比如C++PythonJava等)都会附带用于序列化的库,不需要你再去造轮子。

以C++为例,虽然标准STL库没有提供序列化功能,但是第三方库Boost提供了[ 2 ]谷歌的protobuf也是一个序列化库,还有Fast-CDR,以及不太知名的Cereal,Java自带序列化函数,python可以使用第三方的pickle模块实现。

总之,序列化没有什么神秘的,用户可以看看这些开源的序列化库代码,或者自己写个小程序试试简单数据的序列化,例如这个例子,或者这个,有助于更好地理解ROS中的实现。

1.2ROS中的序列化实现

理解了序列化,再回到ROS。我们发现,ROS没有采用第三方的序列化工具,而是选择自己实现,代码在roscpp_core项目下的roscpp_serialization中,见下图。这个功能涉及的代码量不是很多。

为什么ROS不使用现成的序列化工具或者库呢?可能ROS诞生的时候(2007年),有些序列化库可能还不存在(protobuf诞生于2008年),更有可能是ROS的创造者认为当时没有合适的工具。

1.2.1serialization.h

核心的函数都在serialization.h里,简而言之,里面使用了C语言标准库的memcpy函数把消息拷贝到流中。

下面来看一下具体的实现。

序列化功能的特点是要处理很多种数据类型,针对每种具体的类型都要实现相应的序列化函数。

为了尽量减少代码量,ROS使用了模板的概念,所以代码里有一堆的template。

从后往前梳理,先看Stream这个结构体吧。在C++里结构体和类基本没什么区别,结构体里也可以定义函数。

Stream翻译为流,流是一个计算机中的抽象概念,前面我们提到过字节流,它是什么意思呢?

在需要传输数据的时候,我们可以把数据想象成传送带上连续排列的一个个被传送的物体,它们就是一个流。

更形象的,可以想象磁带或者图灵机里连续的纸带。在文件读写、使用串口、网络Socket通信等领域,流经常被使用。例如我们常用的输入输出流:

cout<<"helllo"; 由于使用很多,流的概念也在演变。想了解更多可以看这里。

struct Stream
{
  // Returns a pointer to the current position of the stream
  inline uint8_t* getData() { return data_; }
  // Advances the stream, checking bounds, and returns a pointer to the position before it was advanced.
  // \\throws StreamOverrunException if len would take this stream past the end of its buffer
  ROS_FORCE_INLINE uint8_t* advance(uint32_t len)
{
    uint8_t* old_data = data_;
    data_ += len;
    if (data_ > end_)
    {
      // Throwing directly here causes a significant speed hit due to the extra code generated for the throw statement
      throwStreamOverrun();
    }
    return old_data;
  }
  // Returns the amount of space left in the stream
  inline uint32_t getLength() { return static_cast<uint32_t>(end_ - data_); }
  
protected:
  Stream(uint8_t* _data, uint32_t _count) : data_(_data), end_(_data + _count) {}


private:
  uint8_t* data_;
  uint8_t* end_;
};
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 机器人
    +关注

    关注

    206

    文章

    27033

    浏览量

    201404
  • 操作系统
    +关注

    关注

    37

    文章

    6284

    浏览量

    121877
  • ROS
    ROS
    +关注

    关注

    1

    文章

    271

    浏览量

    16680
收藏 人收藏

    评论

    相关推荐

    【IntoRobot Atom试用体验】解决Atom搭建机器人操作系统问题(二)

    根据一篇文章解决Atom搭建机器人操作系统问题(一),在做库移植的时候会遇到以下问题。。。。/main.cpp:1:17: fatal error: ros.h: No such f
    发表于 04-07 22:00

    机器人操作系统浅析

    机器人操作系统浅析
    发表于 09-28 11:43

    辰汉-如何实现服务机器人的运算与控制

    的能力。红外模块可以实现对一些外部电器的操控,电池和电池管理模块给整个机器人的运转提供能量。辰汉-硬件结构是实现服务机器人运算和控制的基础,在高性能嵌入式处理器
    发表于 06-09 17:18

    请问能分享ROS机器人操作系统的一些资料吗?

    菜鸟想要学习ROS机器人操作系统,但是没能找到系统的资料,请问有哪位大神研究过,可以分享一些资料吗?跪谢了!!!!!!!!!
    发表于 02-19 23:14

    创龙TL5728-EasyEVM-A4开发板如何移植ros机器人操作系统?

    创龙TL5728-EasyEVM-A4开发板如何移植ros机器人操作系统?
    发表于 01-02 09:32

    ROS 2 Crystal Clemmys版机器人操作系统补充说明

    ROS 2 Crystal Clemmys版机器人操作系统补充说明
    发表于 06-10 11:29

    ROS RIKIBOT基础--使用系列 第一章节】ROS机器人硬件系统 精选资料分享

    主控制器ROS控制器采用树莓派4B或者Jetson Nano,运行运行Ubuntu Mate18.04或Ubuntu18.04系统,具体型号有差异。系统安装有ROS
    发表于 07-30 06:59

    怎样将微型ROS移植到机器人的RA MCU中呢

    。两家公司宣布,用于 RA MCU 的瑞萨电子 EK-RA6M5 评估套件是 micro-ROS 开发框架的官方支持硬件平台。所述微ROS框架,作为业界机器人操作系统针对MCU,允许标
    发表于 02-11 06:19

    ROS机器人开发更便捷,基于RK3568J+Debian系统发布!

    ROS系统是什么 ROS(Robot Operating System)是一个适用于机器人的开源的元操作系统。它提供了
    发表于 11-30 16:01

    ROS的含义与机器人操作系统ROS的介绍

    Operating System 的缩写,原本是斯坦福大学的一个机器人项目,后来由 WillowGarage 公司发展,目前由 OSRF(Open Source Robotics Foundation,Inc)公司维护的开源项目。 1、首先是一个操作系统 根据 wiki
    发表于 09-26 14:08 12次下载

    机器人操作系统ROS详细介绍

    机器人操作系统ROS详细介绍 ROS机器人 操作系统,RobotOperatingSyste
    发表于 11-18 18:09 1889次阅读

    ROS机器人操作系统实现原理解析

    首先用Rate的构造函数实例化一个对象loop_rate。调用的构造函数如下。可见,构造函数使用输入完成了对三个参数的初始化。
    发表于 01-03 10:56 517次阅读

    ROS机器人操作系统实现原理(下)

    本文介绍ROS机器人操作系统(Robot Operating System)的实现原理,从最底层分析ROS代码是如何
    的头像 发表于 05-19 17:42 866次阅读

    ROS机器人操作系统

    可能很多初学者听到机器人操作系统,就被“操作系统”几个字吓住了。其实简单点说,**ROS就是一个分布式的通信框架,帮助程序进程之间更方便地通信。
    的头像 发表于 05-19 17:46 1595次阅读
    <b class='flag-5'>ROS</b><b class='flag-5'>机器人</b><b class='flag-5'>操作系统</b>

    ROS机器人操作系统实现原理

    面对序列化,很多人心中可能会有很多疑问。 首先,为什么要序列化?或者更具体的说,既然对象的信息本来就是以字节的形式储存在内存中,那为什么要多此一举把一些字节数据转换成另一种形式的、一维的、连续的字节数据呢?
    的头像 发表于 04-27 02:39 340次阅读
    <b class='flag-5'>ROS</b><b class='flag-5'>机器人</b><b class='flag-5'>操作系统</b>的<b class='flag-5'>实现</b>原理