自动驾驶系统包括障碍物检测、行为决策、路径规划等一系列复杂的工程模块,同时还要支持激光雷达、相机、GPS等一系列传感器的实时数据收集和实时处理。如何将这些功能模块相互独立又相互交互集成一起,构建成一个稳定的自动驾驶系统是一个巨大的挑战,也是自动驾驶计算框架所承载的基本功能。
什么是ROS?
ROS 是一个强大而比较灵活的机器人编程框架,从软件架构的层面来说,它是一种基于消息传递的分布式多进程框架,开发者可以根据功能把软件拆分成独立的子模块,子模块通过不断的组合能够建立起比较复杂的系统来完成复杂的功能。使用比较广泛。
ROS特征:
ROS核心概念:
几个概念之间的相互关系:
松耦合在此有两种体现:
Node 1和Node2两者之间的启动没有先后关系。
当通信链路建立之后,RosMaster的功能就暂时完成了。
节点常用命令:
Rosnode list:可以列出当前系统里面所存在的节点。
Rosnode info:查看某一节点的具体的一些信息。
Topic常用命令:
Rostopic list:可以查看所存在Topic的一些列表。
Rostopic info:可以查看到发送这个Topic的发送方,订阅这个Topic的订阅方。
Rostopic type:查看Topic内部所使用的MSG的数据结构。
Rostopic pub:调试计算节点模块的一些基本功能。
+’/'代表变量域是全局变量
启动Roscore:通过一个简单的命令行Roscore就可以启动一个节点管理器。不需要进行任何参数的传入,也不需要进行任何配置。
如果有很多个节点启动的时候,会使用Roslaunch。Roslaunch就是把所有启动节点的行为放到统一的描述文件里,在启动的时候会在描述文件里找到定义的各个节点的位置,然后启动节点。
Roslaunch启动会先检测是否有Roscore的存在:
Talker就是一个发送节点的程序。
单独启动一个节点,除了Roscore启动之外,其它的节点启动ROS提供了一个Rosrun命令。Rosrun,前面是Package包,后面是实际的可执行文件。
通过这样简单的一个命令可以直接启动一个Talker。
当启动这个节点之后,用Rosnode list,见第一个图有名叫Talker的Node文件,还有一个Rosout的程序节点。
Rosout:Roscore默认启动的时候启动了一个隐藏节点,它是一个记录日志相关的节点,所有节点发生的Log都会被Roscore启动的Rosout所订阅,订阅完之后会根据一些特定的规则把这些Log分级,然后分模块、分文件打印到对应的模块日志里。
Rosnode info查看Talker相关的一些节点,Talker发送的Topic以及它发送的Service。
见第二图,它有两个Service:Setlogger、Getlogger。这两个是每一个节点都会默认启动的两个Service,这两个Service的作用是设置这一个节点里面的日志层级,如果日志层级是INFO,那么它打印的Debug信息就不会记录在Roscore的Rosout节点里面。
Rostopic info,通过这个命令我们能看到Topic的发送方和接收方。见第三个图。
Rostopic type是查看Topic的一个Message的消息类型。
Rostopic echo是相当于起了一个Listener节点,去展示Talker发的Topic包含的具体信息。
Rostopic还提供了HZ和BW功能:
例如自动驾驶车系统里面每一个传感器有一定的频率,激光雷达是十赫兹,一秒钟发十帧点云图像。可以通过Rostopic HZ去检测Topic是不是一秒钟发送十赫兹,如果低于十赫兹,说明当前系统肯定是有异常,要么是激光雷达扫描的过程受到影响,要么是顶层的Driver节点在处理激光雷达顶层信息的时候中间出现了一些故障。
启动Listener节点之后整个拓扑会有一个比较明显的变化,Listener启动向Roscore发送一个注册信息,同时会订阅Topic。
Roscore会发送一个通知信息给Listener:在它发送注册信息之前已经有一个节点启动了。此时,Listener会向Talker发送消息请求通信连接,Listener收到消息之后会在Listener和Talker两个节点中间建立一个基于TCP的实时通信链路。T建立起来之后Talker就持续不断的发送信息,Listener接到信息之后去做回调处理供实际的决策和执行。
通过Rosnode list看到它包含了一个完整的拓扑:包含发送节点和接收节点。
ROS是基于Cmake编写的Catkin编译系统。
如何建立一个工程包:
src:用来放源文件的一些目录。
build,devel:这两个是在Catkin build的过程当中产生的临时文件夹。
想重编译的话可以直接Catkin build,如果环境里面有一些冲突,可以通过Catkin clean 简单的去把编译产生的临时文件和之前的一些产出文件直接清除掉。
Catkin config指定了命令行编译的一些方式,这些方式可以在Cmakelists里面进行编写。Cmakelists里面指定了这个文件编译过程当中所依赖的一些库、产出的一些可执行文件和这些可执行文件链接了一些什么库。
Roslaunch是一个Shell脚本文件,Shell脚本文件里面根据语言定义的一些Xml格式去找到运行的一系列节点所在的位置然后执行它。它的执行格式是前面加上Package Name,后面加上实际的Launch文件。
Launch文件:
ROS提供了仿真功能Gazebo,定义的节点在里面是实体的存在,通过控制一些参数和变量去模拟他们之间的一些交互,去验证算法在实际的运行中是否按预期进行表现。
ROS在实际的自动驾驶工程化需求面前有很多明显不足:
进行通信优化的原因:
Apollo ROS做了一个基于共享内存的通信机制来减少数据的复制次数,从而提升这种通信模式的效率。
左侧是ROS原生的通讯框架,一个数据从发送方到接收方经历四次数据复制:
右侧是Apollo ROS优化后的框架,它基于共享内存改进,可以减少两次数据拷贝:
数据进行传输的时候,他必须是一个二进制相关的流式数据,所以再发送节点发送数据之前会进行一个序列化,接收节点从内核态接收消息后会进行反序列化成一个结构化的信息,同时对这个结构化的信息做一些回调处理。
对于有多个订阅节点的情况,例如Camera下游会有很多订阅节点,如果是三个节点,会有三条通信链路,分别是四次的内存拷贝,也就是12次数据拷贝。而在基于共享内存的通信方式下,每一条链路内存拷贝的次数只需要两次,三条链路只需要六次。