ROS的序列化设计

    这篇文章主要讲ROS如何做消息的序列化设计:

1, ROS如何做消息的多类型适配。(MessageFormat,MessageAdapter)

2, C++的模板和智能指针在ROS消息模块的应用。(shared_ptr)

3, 如何通过去除序列化和反序列化来增强ROS的实时性。(自定义allocator)

 

消息的多类型适配

         ROS提供基本类型( uint8_t, uint16_t, uint32_t, double ,float)外,还提供duration,Time等自定义的定长类型。此外Header,String,Array这种变长类型的消息。

       为什么需要typename,因为在引用时,编译器需要知道class::typename 到底是嵌套类型,还是静态函数或成员变量。

       Serializer<T>::write/read接口的设计把模板的能力发挥的恰到好处,对每个基础类型的数据implement一个对应的序列化(write)/反序列化(read)操作函数。符合类型根据类型T,去找到对应的函数模板类型去Ser/deSer。

      大多数的库包括Adaptive AutoSar,DDS都是按照类似的思路完成这种操作。C++的STL编程模式在处理Serialization/DeSerialization这类功能时特别常见。

     ROS的*.msg生成的头文件中带有该类型的序列化/反序列化入口。该入口将调用serialization<T>中的函数对每个成员做序列化/反序列化。

     在回调的时候,为了适配多个参数类型,也带有Message Adapter这个类。

 

ROS中智能指针的使用

ROS中使用了weak_ptr,unique_ptr,shared_ptr, 其中shared_ptr在进程内通信的publish接口中使用了。进程内通信利用shared_ptr可以有效减少多线程数据的申请释放问题带来的bug。

ROS的实时性改造

事实上,ROS1.0实时性存在很大问题。主要来源于:1,内存的频繁动态申请,包括STL。2,事件通知(condition_variable,mutex)引起的线程切换。

序列化本身只是memcpy和对应类型的赋值操作,其时间是可以有上界的。为了让用户编程方便,内部会有较多的临时堆内存,内存申请引发的page fault会是一个让车载应用不放心的地方。

另外linux本身的cfs调度是一个动态调度机制,它虽然试图给每个应用程序均分CPU时间片。但因为系统负载和应用程序之间本身的逻辑(比如通知,阻塞,抢占,同步)会导致完成一个具体的任务(比如通信任务)时间上界不可知。在不同场景下处理同一个任务的时间抖动范围也不是平稳的。

如果要确保一个Safety-Critical的应用,要从应用层面和中间件层面以及操作系统层面上都要满足时延的可预测能力。具体要解决的问题就是:内存要静态申请,阻塞任务要有超时机制,调度的时间片要完全可控。这些问题也是要求,适用到所有软件层面。

发表评论

电子邮件地址不会被公开。 必填项已用*标注