apollo学习笔记十五:apollo ROS(上)

背景介绍

在这里插入图片描述
自动驾驶系统包括障碍物检测、行为决策、路径规划等一系列复杂的工程模块,同时还要支持激光雷达、相机、GPS等一系列传感器的实时数据收集和实时处理。如何将这些功能模块相互独立又相互交互集成一起,构建成一个稳定的自动驾驶系统是一个巨大的挑战,也是自动驾驶计算框架所承载的基本功能。

  • 对框架的要求:
    • 高效的开发支持
    • 模块灵活配置
    • 丰富的调试工具
      ROS的优点如下图所示:
      在这里插入图片描述
      自动驾驶底层通信框架选择ROS,主要有三个方面的原因:
      (1)ROS是一个比较强大、灵活的机器人编程框架。从软件架构的层面来说,它是一个基于消息传递的分布式多进程框架,很早就被机器人行业广泛使用。很多著名的机器人开发框架,如基于四元数的坐标转换、3D点预处理驱动、定位算法、SLAM等都是基于ROS开发的开源的现成方案。
      (2)ROS基于消息机制,开发者可以根据功能把软件拆分成独立的子模块,子模块通过不断的组合能够建立起比较复杂的系统来完成复杂的功能。
      (3)ROS是学术界广泛使用的一个框架,对实验各种新算法提供了一些支持。

ROS概述

ROS基本特征

(1)点对点:两个Node之间进行消息通讯是一个点对点的行为
(2)支持分布式:在部署多机之间的消息通讯时,ROS提供了一个天然的支持。
(3)跨语言,它并不关注每个节点之间是用什么语言来写的。你只需要按照ROS提供的一些接口完成消息的订阅和分发即可以完成一个消息之间的通信
(4)一个轻量级的ROS程序,用户只需要关注自己核心模块的算法逻辑,不需要关注底层是如何通信、如何断开通信、如何进行Service和Param之间的一些交互的
(5)开源的框架,大家都可以往ROS里面贡献自己的一些想法和代码。

ROS核心概念

(1)松耦合:ROS是一个松耦合的框架,松耦合就是各个节点之间的通信是一个解耦合的关系。
(2)节点:一个算法模块,比如自动驾驶系统里面的感知模块、定位模块、决策模块或者控制模块,这些模块就是一个简单的算法集合,在ROS里面被称为一个节点。
(3)节点管理器(Roscore):在ROS里面被定义为Master,用来集中式管理各个独立的、松耦合、无序节点之间的逻辑关系,它是轻量级的介入,当各个节点启动完成以后,他们在通信连接完成之前起到中转也就是类似于交换机的作用
(4)Topic:两个节点之间的通信主题。Topic内部使用的数据格式是Message。Message是一系统简单的数据类型或者是一些自定义的复杂数据类型,所组装成的一个描述文件。

相互关系:

(1)感知模块Perception,感知车辆周围的一些障碍物信息,用CNN或者RNN算法将障碍物信息提取出来,即Obstacle。再将这些信息输出给下游Planning节点。这两个节点之间的通信连接就需要Roscore,即节点管理器。
(2)Perception、Planning在启动的时候没有先后关系,这是松耦合的一个具体体现。Perception先启动并向Roscore发送一个注册信息,同时会订阅名为Obstacle的Topic;Planning节点启动后也向Roscore发送一个注册信息,同时会订阅名为Obstacle的Topic;在这种情况下,Roscore会发送一个通知信息给Planning,在它发送注册信息之前已经有一个节点启动了。此时Planning会向Perception发送消息请求通信连接,Planning收到消息之后会在Planning和Perception两个节点中间建立一个实时通信链路。当通信链路建立之后,Roscore的功能就暂时完成了。
(3)松耦合在此有两种体现:

  • Perception和Planning两者之间的启动没有先后关系。
  • 当通信链路建立之后,Roscore的功能就暂时完成了。
    在这里插入图片描述

ROS基本概念

  • Roscore:启动一个节点管理器。

  • 节点常用命令:

    • Rosnode list:可以列出当前系统里面所存在的节点。
    • Rosnode info:查看某一节点的具体的一些信息。
  • Topic常用命令:

    • Rostopic list:可以查看所存在Topic的一些列表。
    • Rostopic info:可以查看到发送这个Topic的发送方,订阅这个Topic的订阅方。
    • Rostopic type:查看Topic内部所使用的MSG的数据结构。
    • Rostopic pub:调试计算节点模块的一些基本功能。

ROS实践1:启动Roscore

在这里插入图片描述

(1)rosrun
(2)启动Roscore,通过一个简单的命令行Roscore就可以启动一个节点管理器。不需要进行任何参数的传入,也不需要进行任何配置。
(3)如果有很多个节点启动的时候,会使用Roslaunch。Roslaunch就是把所有启动节点的行为放到统一的描述文件里,在启动的时候会在描述文件里找到定义的各个节点的位置,然后启动节点。

ROS实践2:启动一个简单的Talker程序

在这里插入图片描述

(1)rosrun roscpp_tutprials talker
(2)Talker就是一个发送节点的程序。
(3)单独启动一个节点,除了Roscore启动之外,其它的节点启动ROS提供了一个Rosrun命令。
(4)Rosrun,前面是Package包,后面是实际的可执行文件。
(5)通过这样简单的一个命令可以直接启动一个Talker。

ROS实践3:通过命令查看Talker node

在这里插入图片描述
(1)当启动这个节点之后,用Rosnode list,见上图Talker的Node文件,还有一个Rosout的程序节点。Roscore默认启动的时候启动了一个隐藏节点,它是一个记录日志相关的节点,所有节点发生的Log都会被Roscore启动的Rosout所订阅,订阅完之后会根据一些特定的规则把这些Log分级,然后分模块、分文件打印到对应的模块日志里。
(2)Rosnode info查看Talker相关的一些节点,Talker发送的Topic以及它发送的Service。它有两个Service:Setlogger、Getlogger。这两个是每一个节点都会默认启动的两个Service,这两个Service的作用是设置这一个节点里面的日志层级,如果日志层级是INFO,那么它打印的Debug信息就不会记录在Roscore的Rosout节点里面。
(3)Rostopic info,通过这个命令我们能看到Topic的发送方和接收方。

在这里插入图片描述

(4)Rostopic type是查看Topic的一个Message的消息类型。
(5)Rostopic echo是相当于起了一个Listener节点,去展示Talker发的Topic包含的具体信息。
(6)Rostopic还提供了HZ和BW功能,HZ是统计Talker节点发送Obstacle topic的频率,根据此频率能简单的探测系统是否按照我们所预期的方向来执行,例如自动驾驶整个车系统里面每一个传感器有一定的频率,激光雷达是十赫兹,即一秒钟转十圈,会发十帧点云图像,我们可以通过Rostopic HZ去检测Topic是不是一秒钟发送十赫兹,如果低于十赫兹,说明当前系统肯定是有异常,要么是激光雷达扫描的过程受到影响,要么是顶层的Driver节点在处理激光雷达顶层信息的时候中间出现了一些故障,此时我们就需要具体探测问题出现在哪个地方。

ROS实践4:启动一个Listener节点

在这里插入图片描述

(1)现在启动一个Listener节点,启动Listener节点之后整个拓扑会有一个比较明显的变化,Listener启动向Roscore发送一个注册信息,同时会订阅Topic,Roscore会发送一个通知信息给Listener:在它发送注册信息之前已经有一个节点启动了。
(2)此时,Listener会向Talker发送消息请求通信连接,Listener收到消息之后会在Listener和Talker两个节点中间建立一个实时通信链路。
(3)这个通信链路是基于TCP的,TCP建立起来之后Talker就持续不断的发送信息,Listener接到信息之后去做回调处理供实际的决策和执行。

ROS实践5:再次通过命令查看Node

在这里插入图片描述

在启动Talker节点之后,通过Rosnode list看到增加的一个节点就是Listener,它包含了一个完整的拓扑:包含发送节点和接收节点。

ROS的Catkin编译系统

在这里插入图片描述

  • ROS是基于Cmake编写的Catkin编译系统。

  • 建立一个工程包,在ROS里面写一个节点,通过Catkin create 可以简单创建一个文件夹,这个文件夹里面会预先设置一些文件目录,通过Catkin build编译建立软件包的过程。

  • Catkin build执行之后,里面会多两个文件夹:DEVEL、BUILD 。BUILD是编译中间过程产生的文件。

  • 编译完成之后,通过Source devel下面的Setup bash就可以把自己编写的节点程序给Source到ROS的环境里面,然后去执行我们节点里面的一些基本功能。

  • 三个比较重要的文件夹
    在这里插入图片描述

    • src用来放源文件的一些目录
    • 第二个是build
    • 第三个是devel
  • build和devel是在Catkin build的过程当中产生的临时文件夹。想重编译的话可以直接Catkin build,如果环境里面有一些冲突,可以通过Catkin clean 简单的去把编译产生的临时文件和之前的一些产出文件直接清除掉。

  • Catkin config指定了命令行编译的一些方式,这些方式可以在Cmakelists里面进行编写。
    在这里插入图片描述

  • Cmakelists里面指定了这个文件编译过程当中所依赖的一些库、产出的一些可执行文件和这些可执行文件链接了一些什么库,Cmakelists里面都有一些很清晰的定义。

  • 在启动节点的时候使用了Roslaunch,Roslaunch是一个Shell脚本文件,Shell脚本文件里面根据语言定义的一些Xml格式去找到运行的一系列节点所在的位置然后执行它。它的执行格式是前面加上Package Name,后面加上实际的Launch文件。
    在这里插入图片描述

ROS的仿真工具Gazebo

在这里插入图片描述
在实际进行开发,不管是机器人还是自动驾驶相关的一些具体功能的时候,我们不可能就是开发一个功能然后到实体的机器人或者是自动驾驶的汽车上去进行模拟实验。ROS提供了仿真功能Gazebo,我们定义的节点在里面是实体的存在,通过控制一些参数和变量去模拟他们之间的一些交互,去验证算法在实际的运行中是否按预期进行表现。

Apollo ROS原理-1

ROS的不足

  • 大数据量传输性能瓶颈
    • 实验性项目里面采用的Topic是Message,数据量是比较小的,可能只有几K或者最多1~2MHZ,但在实际自动驾驶场景里面数据量非常大
    • ROS的时延很高
    • 目前ROS无法满足自动驾驶实际的工程需求
  • 单中心的网络存在单点风险
    • 中心化的网络存在明显的单点风险,整个ROS虽然是一个松耦合的架构,它包含一个节点管理器,节点管理器介入的时候,只是在节点建立通信之前有一个简单的拓扑映射,这种关系虽说极大程度释放了各个节点之间开发的耦合,但同时也带来了比较大的风险。
    • 如果Roscore存在一些故障退出,而节点之间使用了需要不定时的交互方式,像Service 、Parem进行数据交互的时候就会存在一定的风险。
    • 对于分布式系统, Roscore只存在于一台机器上,Roscore如果出现故障,两台机器之间通信就处于一个不可信的状态。
  • 数据格式缺乏后向兼容
    • ROS是基于Message的分发和订阅的消息通讯框架,使用Message需要提前设置Message包含哪些类型的数据。把这个模块放到一个更复杂的系统里面的时候,要格外注意Message之间的数据兼容。
    • 我们根据实际的场景需求,在定义的Obstacle信息里面加一段文字,那么相应的下游所有订阅此Obstacle的节点都要去做对应的适配,同时基于之前的Message所录制的一些实验数据,想在新的框架下使用也都需要一个批量的转化。
    • ROS现有的数据格式缺少后向兼容,此问题在Apollo ROS里面得到解决。

apollo ROS对ROS的改进

在这里插入图片描述
(1)通信性能的优化:

  • 通信性能优化原因

    • 自动驾驶大量使用传感器引发很大的传输带宽需求。自动驾驶使用大量的传感器,这些传感器的数据量非常庞大。大量数据在目前ROS的通讯架构里面会带来比较高的延迟或是丢帧。节点之间通信是一帧一帧进行的,如果上一帧消息高延迟时,下一帧消息的发送就需要等待。ROS提供了这种消息丢弃的机制,如果等待时间长会丢弃一些数据,数据丢弃在实际自动驾驶系统中会造成比较大的风险。
    • 单路传感器消息有多个消费者时负载成倍增长。自动驾驶系统发送传感器数据是一对一进行的。例如Lidar向自动驾驶系统发送数据时,如果只有一个订阅节点,传输的数据量是7M乘以10HZ,也就是70MB/S。自动驾驶系统是一个比较复杂的拓扑结构,一个传感器数据可能会有很多的下游订阅节点。例如感知的障碍物检测、通过视觉定位的模块、用红绿灯识别等都会订阅Camera信息。在单点的情况下是一对一,如果是一对多,传输的数据会被复制多次,造成网络负载成倍增加。
      在这里插入图片描述
  • 共享内存
    在这里插入图片描述

    • 左侧是ROS原生的通讯框架,一个数据从发送方到接收方经历四次数据复制。第一次是从节点到用户内存的数据复制,第二次是从发送方到内核的数据复制,第三次是经过TCP连接,从内核再向接收节点用户态空间的复制,第四次是接收节点拿到这个信息之后,通过反序列化把信息取出来组成一个结构变化的信息。
    • 右侧是Apollo ROS优化后的框架,它基于共享内存改进,可以减少两次数据拷贝。第一次是发送节点把消息序列化成流式数据,第二次是接收节点直接从共享内存里面取相应的消息指针,把共享内存消息取出来进行反序列化成结构化信息进行使用。减少了从用户到内核态以及从内核态到用户的两次数据拷贝。
  • 对于有多个订阅节点的情况,例如Camera下游会有很多订阅节点,如果是三个节点,会有三条通信链路,分别是四次的内存拷贝,也就是12次数据拷贝。而在基于共享内存的通信方式下,每一条链路内存拷贝的次数只需要两次,三条链路只需要六次。
    在这里插入图片描述

  • 消息通信延时:随着消息逐渐增大,基于共享内存通信延时比基于原声ROS Socket的通信延时降低一半。以5M数据为例,传送一帧5M大小的数据,基于ROS Socket大概需要四毫秒左右的时间,基于共享内存通信只需要两毫秒左右。

  • 吞吐量:整个自动驾驶系统的网络拓扑结构非常复杂,数据流向的拓扑结构也比较复杂。在一些极端的情况下,整机数据量会增加。在一些多车道,路面状况比较复杂,车辆较多的情况下,感知和Planning模块,或者和其它模块之间的数据流就会成倍增加,所以在测试一些极端情况下,系统吞吐量也是自动驾驶需要考虑的一个重要方面。

  • CPU资源占用率:CPU资源占用率在共享内存通信情况下降低约30%, 主要是因为减少了多次内存复制。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值