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

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

3天内不再提示

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

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

注释表明Stream是个基类,输入输出流IStream和OStream都继承自它。

Stream的成员变量data_是个指针,指向序列化的字节流开始的位置,它的类型是uint8_t。

在Ubuntu系统中,uint8_t的定义是typedef unsigned char uint8_t;

所以uint8_t就是一个字节,可以用size_of()函数检验。data_指向的空间就是保存字节流的。

输出流类OStream用来序列化一个对象,它引用了serialize函数,如下。

struct OStream : public Stream
{
  static const StreamType stream_type = stream_types::Output;
  OStream(uint8_t* data, uint32_t count) : Stream(data, count) {}
  /* Serialize an item to this output stream*/
  template<typename T>
  ROS_FORCE_INLINE void next(const T& t)
{
    serialize(*this, t);
  }
  template<typename T>
  ROS_FORCE_INLINE OStream& operator<<(const T& t)
  {
    serialize(*this, t);
    return *this;
  }
};

输入流类IStream用来反序列化一个字节流,它引用了deserialize函数,如下。

struct ROSCPP_SERIALIZATION_DECL IStream : public Stream
{
  static const StreamType stream_type = stream_types::Input;
  IStream(uint8_t* data, uint32_t count) : Stream(data, count) {}
  /* Deserialize an item from this input stream */
  template<typename T>
  ROS_FORCE_INLINE void next(T& t)
{
    deserialize(*this, t);
  }
  template<typename T>
  ROS_FORCE_INLINE IStream& operator>>(T& t)
  {
    deserialize(*this, t);
    return *this;
  }
};

自然,serialize函数和deserialize函数就是改变数据形式的地方,它们的定义在比较靠前的地方。它们都接收两个模板,都是内联函数,然后里面没什么东西,只是又调用了Serializer类的成员函数write和read。所以,serialize和deserialize函数就是个二道贩子。

// Serialize an object.  Stream here should normally be a ros::serialization::OStream
template<typename T, typename Stream>
inline void serialize(Stream& stream, const T& t)
{
  Serializer

所以,我们来分析Serializer类,如下。我们发现,write和read函数又调用了类型里的serialize函数和deserialize函数。

头别晕,这里的serialize和deserialize函数跟上面的同名函数不是一回事。

注释中说:“Specializing the Serializer class is the only thing you need to do to get the ROS serialization system to work with a type”(要想让ROS的序列化功能适用于其它的某个类型,你唯一需要做的就是特化这个Serializer类)。

这就涉及到的另一个知识点——模板特化(template specialization)。

template<typename T> struct Serializer
{
  // Write an object to the stream.  Normally the stream passed in here will be a ros::serialization::OStream
  template<typename Stream>
  inline static void write(Stream& stream, typename boost::call_traits
{
    t.serialize(stream.getData(), 0);
  }
   // Read an object from the stream.  Normally the stream passed in here will be a ros::serialization::IStream
  template<typename Stream>
  inline static void read(Stream& stream, typename boost::call_traits
{
    t.deserialize(stream.getData());
  }
  // Determine the serialized length of an object.
  inline static uint32_t serializedLength(typename boost::call_traits
{
    return t.serializationLength();
  }
};

接着又定义了一个带参数的宏函数ROS_CREATE_SIMPLE_SERIALIZER(Type),然后把这个宏作用到了ROS中的10种基本数据类型,分别是:uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double。

说明这10种数据类型的处理方式都是类似的。看到这里大家应该明白了,write和read函数都使用了memcpy函数进行数据的移动。

注意宏定义中的template<>语句,这正是模板特化的标志,关键词template后面跟一对尖括号。

关于模板特化可以看这里。

#define ROS_CREATE_SIMPLE_SERIALIZER(Type) \\
  template<> struct Serializer \\
  { \\
    template

对于其它类型的数据,例如bool、std::string、std::vector、ros::Time、ros::Duration、boost::array等等,它们各自的处理方式有细微的不同,所以不再用上面的宏函数,而是用模板特化的方式每种单独定义,这也是为什么serialization.h这个文件这么冗长。

对于int、double这种单个元素的数据,直接用上面特化的Serializer类中的memcpy函数实现序列化。

对于vector、array这种多个元素的数据类型怎么办呢?方法是分成几种情况,对于固定长度简单类型的(fixed-size simple types),还是用各自特化的Serializer类中的memcpy函数实现,没啥太大区别。

对于固定但是类型不简单的(fixed-size non-simple types)或者既不固定也不简单的(non-fixed-size, non-simple types)或者固定但是不简单的(fixed-size, non-simple types),用for循环遍历,一个元素一个元素的单独处理。

那怎么判断一个数据是不是固定是不是简单呢?这是在roscpp_traits文件夹中的message_traits.h完成的。

其中采用了萃取Type Traits,这是相对高级一点的编程技巧了,笔者也不太懂。

对序列化的介绍暂时就到这里了,有一些细节还没讲,等笔者看懂了再补。

2、消息订阅发布

2.1ROS的本质

如果问ROS的本质是什么,或者用一句话概括ROS的核心功能。那么,笔者认为ROS就是个通信库,让不同的程序节点能够相互对话。

很多文章和书籍在介绍ROS是什么的时候,经常使用“ROS是一个通信框架”这种描述。

但是笔者认为这种描述并不是太合适。“框架”是个对初学者非常不友好的抽象词汇,用一个更抽象难懂的概念去解释一个本来就不清楚的概念,对初学者起不到任何帮助。

而且笔者严重怀疑绝大多数作者能对机器人的本质或者软件框架能有什么太深的理解,他们的见解不会比你我深刻多少。

既然提到本质,那我们就深入到最基本的问题。

在接触无穷的细节之前,我们不妨先做一个哲学层面的思考。

那就是,为什么ROS要解决通信问题?

机器人涉及的东西千千万万,机械电子、软件、人工智能无所不包,为什么底层的设计是一套用来通信的程序而不是别的东西。

到目前为止,我还没有看到有人讨论过这个问题。这要回到机器人或者智能的本质。

当我们在谈论机器人的时候,最首要的问题不是硬件设计,而是对信息的处理。一个机器人需要哪些信息,信息从何而来,如何传递,又被谁使用,这些才是最重要的问题。

人类飞不鸟,游不过鱼,跑不过马,力不如牛,为什么却自称万物之灵呢。

因为人有大脑,而且人类大脑处理的信息更多更复杂。

抛开物质,从信息的角度看,人与动物、与机器人存在很多相似的地方。

机器人由许多功能模块组成,它们之间需要协作才能形成一个有用的整体,机器人与机器人之间也需要协作才能形成一个有用的系统,要协作就离不开通信。

需要什么样的信息以及信息从何而来不是ROS首先关心的,因为这取决于机器人的应用场景。

因此,ROS首先要解决的是通信的问题,即如何建立通信、用什么方式通信、通信的格式是什么等等一系列具体问题。

带着这些问题,我们看看ROS是如何设计的。

2.2客户端库

实现通信的代码在ros_comm包中,如下。

其中clients文件夹一共有127个文件,看来是最大的包了。

现在我们来到了ROS最核心的地带。

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

    关注

    206

    文章

    27033

    浏览量

    201400
  • 操作系统
    +关注

    关注

    37

    文章

    6284

    浏览量

    121876
  • ROS
    ROS
    +关注

    关注

    1

    文章

    271

    浏览量

    16680
收藏 人收藏

    评论

    相关推荐

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

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

    机器人操作系统浅析

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

    请问能分享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:41 777次阅读
    <b class='flag-5'>ROS</b><b class='flag-5'>机器人</b><b class='flag-5'>操作系统</b>的<b class='flag-5'>实现</b>原理(上)

    ROS机器人操作系统

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

    一个机器人操作系统(ROS)节点系统

    电子发烧友网站提供《一个机器人操作系统(ROS)节点系统.zip》资料免费下载
    发表于 07-06 10:49 0次下载
    一个<b class='flag-5'>机器人</b><b class='flag-5'>操作系统</b>(<b class='flag-5'>ROS</b>)节点<b class='flag-5'>系统</b>

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

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