百度经验怎么发布发布Apollo2.5

原文地址:https://blog.csdn.net/jinzhuojun/article/details/80210180我们知道,自动驾驶在学界其实已经是个很老的topic了。而这几年,伴随着以深度学习为主力的第三次AI浪潮,大家似乎看到了自动驾驶商业化的重大机会,于是无论是学界还是工业界都开始将注意力转向该领域。放眼望去,满大街似乎都在搞自动驾驶。前段时间,百度又发布了自动驾驶平台Apollo的2.5版本。要想搭个环境玩一下的话,其实官方文档里挺详细了。这里主要是备忘一下主要流程和一些小坑的解决方法。大体可分为以下几步:docker为了免除环境差异造成的各种问题,apollo运行环境依赖于docker。因此如果还没有安装docker的话,需要先安装docker,可以参考:https://github.com/ApolloAuto/apollo/blob/master/docker/scripts/README.md#install-docker如果之后启动container时遇到下面错误:docker: Error response from daemon: cgroups: cannot find cgroup mount destination: unknown.参考https://github.com/boot2docker/boot2docker/issues/1301,解决方法是执行:sudo mkdir /sys/fs/cgroup/systemd
sudo mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemdApollo首先下载apollo源代码。可以选择直接从github上拉,也可以下载release包。这里选择后者,从https://github.com/ApolloAuto/apollo/releases/tag/v2.5.0 下载代码,然后解压。假设解压后目录为APOLLO_HOME。进入该目录后,运行以下脚本初始化apollo的开发和运行环境。bash docker/scripts/dev_start.sh其中会去从网上拉几个所需的docker image并基于这些image启动container。拉完后用docker images命令可以看到以下的几个新增image:REPOSITORY
TAG
IMAGE ID
CREATED
SIZE
apolloauto/apollo
dev-x86_64-20180413_2000
2d338b6e1942
3 weeks ago
7.17GB
apolloauto/apollo
localization_volume-x86_64-latest
75cf8c77134c
4 weeks ago
6.94MB
apolloauto/apollo
map_volume-sunnyvale_big_loop-latest
9d9581178ffe
6 weeks ago
995MB
apolloauto/apollo
yolo3d_volume-x86_64-latest
562d2b2b5a71
7 weeks ago
70.6MB
apolloauto/apollo
map_volume-sunnyvale_loop-latest
36dc0d1c2551
3 months ago
906MB用docker ps可以看到启动了以下container:0f2a5bccc9f3
apolloauto/apollo
"/bin/bash"
3 hours ago
Up 3 hours
apollo_dev
0c1f64813be2
apolloauto/apollo:yolo3d_volume-x86_64-latest
"/bin/sh"
3 hours ago
Up 3 hours
apollo_yolo3d_volume
b42bfef51984
apolloauto/apollo:localization_volume-x86_64-latest
"/bin/sh"
3 hours ago
Up 3 hours
apollo_localization_volume
5d6ea903455c
apolloauto/apollo:map_volume-sunnyvale_loop-latest
"/bin/bash"
3 hours ago
Up 3 hours
apollo_map_volume-sunnyvale_loop
dc4f8219a2b9
apolloauto/apollo:map_volume-sunnyvale_big_loop-latest
"/bin/sh"
3 hours ago
Up 3 hours
apollo_map_volume-sunnyvale_big_loop接下来就可以通过以下命令进入开发环境了,其实就是进入前面pull下来的dev-x86_64-20180413_2000那个image创建的container(名为apollo_dev)。前面的apollo代码根目录APOLLO_HOME会被映射到container中的/apollo目录下。bash docker/scripts/dev_into.sh然后就可以编译整个系统了。不过由于感知(perception)模块很多依赖于CUDA,所以最好先按下一节中的方法enable CUDA后再编译。等编译完后,根据官方文档How to Launch and Run Apollo就可以用下面命令启动Apollo并运行可视化工具Dreamview:bash scripts/bootstrap.sh正常情况下可以看到“Dreamview is running at http://localhost:8888”的输出,然后用浏览器打开http://localhost:8888 应该就能看到界面了。这里,我们按官方文档先跑下demo。先下载回放数据包:sudo bash docs/demo_guide/rosbag_helper.sh download下载完成后,回放数据位于docs/demo_guide目录下。Apollo基于ROS,而rosbag是其中的数据记录和回放工具。用该命令可以开始回放:rosbag play -l ./docs/demo_guide/demo_2.0.bag从刚才启动的Dreamview中即可看到回放数据的图形化输出了: CUDA通过前面命令进入apollo_dev这个container中,可以看到官方image中自带CUDA 8.0了。但由于没有driver,所以还无法使用GPU进行加速。参考官方文档How to Run Perception Module on Your Local Computer,下载驱动(最好和host装的版本一致,driver版本可以通过nvidia-smi命令查看)和cudnn进行安装。如果直接运行下载的驱动安装文件碰到问题,比如:An NVIDIA kernel module 'nvidia-drm' appears to already be loaded in
your kernel.需要先将图形界面干掉(因为它会使用GPU):sudo service lightdm stop再如果碰到下面问题:nvidia: version magic '4.4.0-116-generic SMP mod_unload modversions ' should be '4.4.0-116-generic SMP mod_unload modversions retpoline '可以参考https://devtalk.nvidia.com/default/topic/1030325/nvidia-driver-installation-v387-26-on-ubuntu-16-04/。亲测有效。另一种安装driver的方法是通过apt-get:sudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt-get update
sudo apt-get install nvidia-384因为安装了驱动,即对原image有了修改,如果不commit的话退出后这些改动都没有了,下次进来还要重新做一遍。因此需要通过以下命令commit改动(假设commit后的image tag为v1.0):docker commit CONTAINER_ID apolloauto/apollo:v1.0其中CONTAINER_ID可以通过docker ps
grep apollo_dev查看。命令执行后再用docker images命令应该可以看到新增的image:apolloauto/apollo
v1.0
3812b26eb3c8
41 hours ago
8.11GB之后就可以用以下命令就可以基于改动后的image创建container:./docker/scripts/dev_start.sh -l -t v1.0然后可以试下CUDA是不是正常工作。在container中进入/usr/local/cuda/samples/1_Utilities/deviceQuery目录,执行:sudo make
sudo ./deviceQuery如果看到GPU信息就说明OK了。还不放心的再在samples目录里随便挑几个编译运行试试。接下来可以编译apollo系统了:./apollo.sh build_opt_gpuapollo系统使用的编译系统是bazel(就是TensorFlow用的那个)。编译完后的binary都放在/apollo/bazel-bin目录下。让我们随意找个test试一下,比如用yolo神经网络模型进行物体检测的测试:./bazel-bin/modules/perception/obstacle/camera/detector/yolo_camera_detector/yolo_camera_detector_test输出结果:...
I0506 18:23:41.356957
218 util.cc:54] Supported types:
I0506 18:23:41.356976
218 util.cc:62]
VEHICLE
I0506 18:23:41.356989
218 util.cc:62]
BICYCLE
I0506 18:23:41.356993
218 util.cc:62]
PEDESTRIAN
I0506 18:23:41.357002
218 util.cc:62]
UNKNOWN_UNMOVABLE
I0506 18:23:41.357015
218 util.cc:64]
4 in total.
E0506 18:23:41.369910
218 yolo_camera_detector.cc:256] 'objects' is a null pointer.
I0506 18:23:41.372014
218 yolo_camera_detector.cc:303] Pre-processing: 2.01507 ms
I0506 18:23:41.408946
218 yolo_camera_detector.cc:309] Running detection: 36.8999 ms
I0506 18:23:41.409906
218 yolo_camera_detector.cc:356] Post-processing: 0.927424 ms
I0506 18:23:41.409914
218 yolo_camera_detector.cc:357] Number of detected obstacles: 1
[
OK ] YoloCameraDetectorTest.multi_task_test (315 ms)
[----------] 3 tests from YoloCameraDetectorTest (1398 ms total)
[----------] Global test environment tear-down
[==========] 3 tests from 1 test case ran. (1399 ms total)
[
PASSED
] 3 tests.
文章来源:解析百度Apollo自动驾驶平台-阿里云开发者社区最近对百度的自动驾驶平台Apollo项目做了一些了解。下面将我所了解到的一些信息分享给大家。Apollo项目介绍阿波罗(Apollo)是百度发布的面向汽车行业及自动驾驶领域的合作伙伴提供的软件平台。发布时间是2017年4月19日,旨在向汽车行业及自动驾驶领域的合作伙伴提供一个开放、完整、安全的软件平台,帮助他们结合车辆和硬件系统,快速搭建一套属于自己的完整的自动驾驶系统。而将这个计划命名为“Apollo”计划,就是借用了阿波罗登月计划的含义。可以在这里感受一下Apollo的实车驾车体验:CES 2018 百度Apollo 2.0无人车美国桑尼维尔试乘。SAE Level对于自动驾驶,SAE(Society of Automotive Engineers,美国汽车工程师学会) International于2014年发布了从全手动系统到全自动系统六个不同级别的分类系统,这6个级别的描述如下:SAE LevelNameSystem capabilityDriver involvement阿波罗项目的官网地址如下:http://apollo.auto在阿波罗项目的官网,介绍了该项目有如下特点:开放能力:Apollo(阿波罗)是一个开放的、完整的、安全的平台,将帮助汽车行业及自动驾驶领域的合作伙伴结合车辆和硬件系统,快速搭建一套属于自己的自动驾驶系统。共享资源、加速创新:Apollo开放平台,为你提供技术领先、覆盖广、高自动化的高精地图服务;全球唯一开放,拥有海量数据的仿真引擎;全球开放数据量第一,基于深度学习自动驾驶算法End-to-End。持续共赢:Apollo开放平台,你可以更快地研发、测试和部署自动驾驶车辆。参与者越多,积累的行驶数据就越多。与封闭的系统相比,Apollo能以更快的速度成熟,让每个参与者得到更多的受益,同时Apollo平台也将在你的参与之下变得更好!目前,其官网上列出的合作伙伴已经接近100家。阿波罗项目的蓝图如下:2017-07:封闭场地的自动驾驶能力2017-12:在城市简单路况下的自动驾驶能力2020-12:高速公路和普通城市道路上的全自动驾驶最新发布的Apollo 2.5版本主要目标是L2级自动驾驶。详细的Apollo版本演进信息如下图所示:源码可以在这里获取到阿波罗项目的源码:https://github.com/ApolloAuto。这个路径中包含了5个开源项目:apollo:Apollo自动驾驶平台的源码。apollo-platform:Apollo项目基于Robot Operating System (ROS),这里是相关代码。目前发布的源码基于ROS Indigo。apollo-DuerOS:Apollo-DuerOS是一套与Apollo相关的远程信息处理产品,这其中包含了几个开源产品。关于DuerOS,请看这里:DuerOS。apollo-kernel:Apollo项目的Linux内核。http://ApolloAuto.github.io:Apollo相关文档,可以访通过https://apolloauto.github.io访问这些文档。编译和运行关于如何编译和运行阿波罗项目请参见这里:https://apolloauto.github.io。执行该任务需要Ubuntu和Docker环境。编译完成之后,可以在电脑上通过该项目提供的Dreamview功能来熟悉环境,Dreamview通过浏览器访问,其界面看起来是这个样子:关于Dreamview的更多说明,请参见这里:Dreamview Usage Table开发阿布罗平台的开发包含下面几个步骤:了解离线模拟引擎Dreamviewer和ApolloAuto核心软件模块了解算法如何在汽车上运作不需要使用真正的汽车或硬件,就立即开始开发核心模块集成Location模块Perception模块:(支持第三方解决方案,如基于Mobileye ES4芯片的摄像头,用于L2开发)处理来自Lidar的点云数据,并根据请求返回分段对象信息。Planning模块:计算微调路径,为路径服务的路径段提供汽车动态控制信息。Routine模块:通过Navigator接口查找路径段的本地实现。高清地图。L4级别的自动驾驶需要高清地图。由于自动驾驶汽车需要在系统中重建3D世界,因此参考对象坐标在重新定位地图和现实世界中的自动驾驶方面发挥着重要作用。基于云的在线仿真驱动场景引擎和数据中心。作为百度的合作伙伴,将被授予Docker证书来提交新图像并重播你在云上开发的算法。创建和管理复杂的场景以模拟真实世界的驾驶体验Apollo与ROSROS全称是Robot Operating System。它包含了一套开源的软件库和工具,专门用来构建机器人应用。其官网地址在这里:http://www.ros.org。在一个ROS系统中,包含了一系列的独立节点(nodes)。这些节点之间,通过发布/订阅的消息模型进行通信。例如,某个传感器的驱动可以实现为一个节点,然后以发布消息的形式对外发送传感器数据。这些数据可以被多个其他节点接收,例如:过滤器,日志系统等等。ROS系统中的节点可能位于不同的主机上,例如:在一个Arduino设备上发布消息,一台笔记本电脑订阅这些消息,一个Android手机也监测这些消息。ROS系统中包含了一个主(Master)节点。主节点使得其他节点可以查询彼此以进行通讯。所有节点都需要在主节点上进行注册,然后就可以与其他节点通讯了。如下图所示:熟悉Android系统的人可能很容易发现,这和Binder中的ServiceManager的作用是类似的。节点之间通过发布和订阅主题(Topics)进行通讯。例如,在某个机器人系统中,位于机器人上有一个相机模块可以获取图像数据。另外在机器人上有一个图像处理模块需要获取图像数据,与此同时还有另外一个位于个人PC上的模块也需要这些图像数据。那么,相机模块可以发布/image_data这个主题供其他两个模块来订阅。其结构如下图所示:Apollo项目基于ROS,但是对其进行了改造,主要包括下面三个方面:通信性能优化去中心化网络拓扑数据兼容性扩展通信性能优化自动驾驶车辆中包含了大量的传感器,这些传感器可能以非常高频的速度产生数据,所以整个系统对于数据传输效率要求很高。在ROS系统中,从数据的发布到订阅节点之间需要进行数据的拷贝。在数据量很大的情况下,很显然这会影响数据的传输效率。所以Apollo项目对于ROS第一个改造就是将通过共享内存来减少数据拷贝,以提升通信性能。如下图所示:去中心化网络拓扑前文我们提到,ROS系统中包含了一个通信的主节点,所有其他节点都要借助于这个节点来进行通信。所以,很显然的,假如这个节点发生了通信故障,就会影响整个系统的通信。并且,整个结构还缺乏异常恢复机制。所以Apollo项目对于ROS的第二个改造就是去除这种中心化的网络结构。Apollo使用RTPS(Real-Time Publish-Subscribe)服务发现协议实现完全的P2P网络拓扑。整个通信过程包含下面四个步骤:关于RTPS详见这里:Real-Time Publish-Subscribe数据兼容性扩展Apollo项目对于ROS最后一个较大的改进就是对于数据格式的调整。在ROS系统中,使用msg描述文件定义模块间的消息接口。但不幸的是,接口升级之后不同的版本的模块难以兼容。因此,Apollo选择了Google的Protocol Buffers格式数据来解决这个问题。Protocol Buffers,是Google公司开发的一种数据描述语言,类似于XML能够将结构化数据序列化,可用于数据存储、通信协议等方面。它不依赖于语言和平台并且可扩展性极强。现阶段官方支持C++、JAVA、Python三种编程语言,但可以找到大量的几乎涵盖所有语言的第三方拓展包。注:如果你查看了Apollo项目的源码,可以看到很多名称为“proto”的文件夹,这些文件夹中包含的就是Protocol Buffers(简称protobuf)格式的数据结构。硬件架构Apollo 2.5上必须的硬件如下表所示:外设包括下面这些:硬件架构如下图所示:软件架构Apollo平台的软件架构如下图所示:在Apollo上,运行的核心软件模块包括:Perception:感知模块识别自动车辆周围的世界。在Perception模块中有两个重要的子模块:障碍物检测和交通灯检测。Prediction:Prediction模块预测未来的感知障碍物的运动轨迹。Routing:Routing模块告诉自动车辆如何通过一系列车道或道路到达目的地。Planning:Planning模块计划自主车辆的时空轨迹。Control:Control模块通过生成诸如节流阀,制动器和转向的控制命令来执行计划的时空轨迹。CanBus:CanBus将控制命令传递给车辆硬件的接口。它还将机架信息传递给软件系统。HD-Map:提供有关道路特定结构化的信息。Localization:该模块利用各种信息来源,例如GPS,LiDAR和IMU来估计自动车辆所在的位置。这些模块的交互结构如下图所示:每个模块都作为独立的基于CarOS的ROS节点运行。每个模块节点都会发布和订阅某些主题。订阅的主题用作数据输入,而发布的主题用作数据输出。关于Apollo平台的系统架构可以阅读这篇文档:HOW TO UNDERSTAND ARCHITECTURE AND WORKFLOW。从这篇文档中我们看到:自动驾驶车辆由规划引擎通过CAN总线(Controller Area Network bus)来进行控制。为了计算效率,Location模块,Perception模块,Planning模块作为独立的输入源和输出源通过P2P一起工作。通过阅读源码${MODULE_NAME}/conf目录下的配置文件,我们可以获得有关模块订阅和发布的主题的基本信息。每个模块通过触发 Init 接口和注册回调开始。所有模块都会在下面这个点上注册:AdapterManager::Init。该函数部分代码片段如下:void AdapterManager::Init(const AdapterManagerConfig &configs) {
if (Initialized()) {
return;
}
instance()->initialized_ = true;
if (configs.is_ros()) {
instance()->node_handle_.reset(new ros::NodeHandle());
}
for (const auto &config : configs.config()) {
switch (config.type()) {
case AdapterConfig::POINT_CLOUD:
EnablePointCloud(FLAGS_pointcloud_topic, config);
break;
case AdapterConfig::GPS:
EnableGps(FLAGS_gps_topic, config);
break;
case AdapterConfig::IMU:
EnableImu(FLAGS_imu_topic, config);
break;
case AdapterConfig::RAW_IMU:
EnableRawImu(FLAGS_raw_imu_topic, config);
break;
case AdapterConfig::CHASSIS:
EnableChassis(FLAGS_chassis_topic, config);
break;
case AdapterConfig::LOCALIZATION:
EnableLocalization(FLAGS_localization_topic, config);
break;
case AdapterConfig::PERCEPTION_OBSTACLES:
EnablePerceptionObstacles(FLAGS_perception_obstacle_topic, config);
break;
case AdapterConfig::TRAFFIC_LIGHT_DETECTION:
EnableTrafficLightDetection(FLAGS_traffic_light_detection_topic,
config);
...下面是对系统中主要的核心模块的一些解析。核心模块apollo/modules/中包含了系统中的各个模块的源码。阅读这些源码会发现,这些核心模块的类都继承自一个公共基类ApolloApp,相关结构如下图所示:ApolloApp类的结构如下图所示:该类中的主要函数说明如下:在apollo_app.h这个头文件中,还包含了一个宏以方便每个模块声明main函数,相关代码如下:#define APOLLO_MAIN(APP)
\
int main(int argc, char **argv) {
\
google::InitGoogleLogging(argv[0]);
\
google::ParseCommandLineFlags(&argc, &argv, true);
\
signal(SIGINT, apollo::common::apollo_app_sigint_handler); \
APP apollo_app_;
\
ros::init(argc, argv, apollo_app_.Name());
\
apollo_app_.Spin();
\
return 0;
\
}每个模块的根目录都包含了一个README.md文件,是对这个模块的说明。我们可以以此为入口来了解模块的实现。Perception(感知)模块介绍自动驾驶车辆通过前置摄像头和雷达与最近的车辆(closest in-path vehicle,简称CIPV)保持距离。子模块还预测障碍物运动和位置信息(例如,航向和速度)。Apollo 2.5支持高速公路上的高速自动驾驶,无需任何地图。深度网络算法已经学会处理图像数据。随着收集更多数据,深度网络的性能将随着时间的推移而提高。模块输入:雷达数据图像数据雷达传感器校准的外部参数(来自YAML文件)前置相机校准的外部和内部参数(来自YAML文件)车辆的速度和角速度模块输出:3D障碍物跟踪航向,速度和分类信息带有拟合曲线参数的车道标记信息,空间信息以及语义信息模块解析Perception模块需要根据输入信息快速的解析出两类信息,即:道路和物体。其中的深入网络基于YOLO算法[1][2]。Apollo 2.5不支持高曲率,没有车道标志的道路,包括当地道路和交叉路口。感知模块基于使用具有有限数据的深度网络的视觉检测。因此,在发布更好的网络之前,驾驶员在驾驶时应小心谨慎,并始终准备好通过将车轮转向正确的方向来解除自主驾驶。推荐道路两侧清晰的白色车道线不推荐道路高曲率的道路没有车道线标记的道路路口对接点或虚线车道线公共道路而对于物体来说,又分为静态物体和动态物体。静态物体包括道路和交通灯等。动态物体包括机动车,自行车,行人,动物等。为了保持车辆在车道上,需要一系列模块的配合,相关流程图如下所示:Perception模块在Init函数中会注册一系列类以完成模块启动后的正常工作,相关代码如下:void Perception::RegistAllOnboardClass() {
/// regist sharedata
RegisterFactoryLidarObjectData();
RegisterFactoryRadarObjectData();
RegisterFactoryCameraObjectData();
RegisterFactoryCameraSharedData();
RegisterFactoryCIPVObjectData();
RegisterFactoryLaneSharedData();
RegisterFactoryFusionSharedData();
traffic_light::RegisterFactoryTLPreprocessingData();
/// regist subnode
RegisterFactoryLidarProcessSubnode();
RegisterFactoryRadarProcessSubnode();
RegisterFactoryCameraProcessSubnode();
RegisterFactoryCIPVSubnode();
RegisterFactoryLanePostProcessingSubnode();
RegisterFactoryAsyncFusionSubnode();
RegisterFactoryFusionSubnode();
RegisterFactoryMotionService();
lowcostvisualizer::RegisterFactoryVisualizationSubnode();
traffic_light::RegisterFactoryTLPreprocessorSubnode();
traffic_light::RegisterFactoryTLProcSubnode();
}我们可以以这里为入口了解各个子模块的逻辑。以RegisterFactoryLidarProcessSubnode为例。代码中其实并不存在RegisterFactoryLidarProcessSubnode这个函数,该函数的定义其实是由宏完成的。相关代码如下:Lidar(也称之为LIDAR,LiDAR,或LADAR)的全称是Light Detection And Ranging,即激光探测与测量。// /modules/perception/onboard/subnode.h
#define REGISTER_SUBNODE(name) REGISTER_CLASS(Subnode, name)
// /modules/perception/lib/base/registerer.h
#define REGISTER_CLASS(clazz, name)
\
class ObjectFactory##name : public apollo::perception::ObjectFactory {
\
public:
\
virtual ~ObjectFactory##name() {}
\
virtual perception::Any NewInstance() {
\
return perception::Any(new name());
\
}
\
};
\
inline void RegisterFactory##name() {
\
perception::FactoryMap &map = perception::GlobalFactoryMap()[#clazz];
\
if (map.find(#name) == map.end()) map[#name] = new ObjectFactory##name(); \
}而在lidar_process_subnode.h中使用了上面这个宏。REGISTER_SUBNODE(LidarProcessSubnode);于是就会生成一个名称为ObjectFactoryLidarProcessSubnode的类,该类继承自apollo::perception::ObjectFactory,并且其中包含了名称为RegisterFactoryLidarProcessSubnode的函数。Prediction(预测)模块介绍Prediction模块从Perception模块接受障碍物信息。该模块需要的信息包括位置,航向,速度,加速度,并产生具有障碍概率的预测轨迹。模块输入:来自Prediction模块的障碍物信息来自Localizaton模块的位置信息模块输出:障碍物的预测轨迹模块解析Prediction的Init函数中添加了三个回调用来从其他模块获取信息的更新:AdapterManager::AddLocalizationCallback(&Prediction::OnLocalization, this);
AdapterManager::AddPlanningCallback(&Prediction::OnPlanning, this);
AdapterManager::AddPerceptionObstaclesCallback(&Prediction::RunOnce, this);这里最重要的就是Prediction::RunOnce这个函数。这个函数中包含了Prediction模块的主要逻辑,它会在接收到一个新的障碍物消息时触发。Prediction模块中有三类重要的子模块。第一类是Container,用来存储从订阅频道获取的数据。包括:感到到的障碍物信息车辆位置信息车辆计划信息第二类是Evaluator,用来针对指定的障碍物预测路线和速度。目前有三类Evaluator,包括:Cost evaluator:通过一组代价函数来计算可能性MLP evaluator:通过MLP模型来计算可能性RNN evaluator:通过RNN模型来计算可能性Evaluator通过EvaluatorManager类管理,Evaluator类结构如下图所示:Prediction模块中第三类重要的子模块就是Predictor。它用来预测障碍物的轨迹。不同的障碍物运动的轨迹会不一样,因此实现中包含了很多个类型的Predictor,它们的结构如下图所示。类似的,会有一个PredictorManager来管理Predictor。Routing(路由)模块介绍Routing模块根据请求生成导航信息。模块输入:地图数据请求,包括:开始和结束位置模块输出:路由导航信息模块解析Routing模块的内部结构如下图所示:Routing模块的输入是地图数据和导航请求,因此其Init函数就是围绕这个逻辑的:apollo::common::Status Routing::Init() {
const auto routing_map_file = apollo::hdmap::RoutingMapFile();
AINFO << "Use routing topology graph path: " << routing_map_file;
navigator_ptr_.reset(new Navigator(routing_map_file));
CHECK(common::util::GetProtoFromFile(FLAGS_routing_conf_file, &routing_conf_))
<< "Unable to load routing conf file: " + FLAGS_routing_conf_file;
AINFO << "Conf file: " << FLAGS_routing_conf_file << " is loaded.";
hdmap_ = apollo::hdmap::HDMapUtil::BaseMapPtr();
CHECK(hdmap_) << "Failed to load map file:" << apollo::hdmap::BaseMapFile();
AdapterManager::Init(FLAGS_routing_adapter_config_filename);
AdapterManager::AddRoutingRequestCallback(&Routing::OnRoutingRequest, this);
return apollo::common::Status::OK();
}这段代码的重点是下面三个地方:apollo::hdmap::RoutingMapFile()包含了HD地图数据。Navigator负责导航,我们很容易想到这个类应当是该模块的核心。Routing::OnRoutingRequest是接收导航请求的回调函数。在Routing::OnRoutingRequest中,最主要的就是通过Navigator::SearchRoute来搜索导航路径。void Routing::OnRoutingRequest(const RoutingRequest& routing_request) {
AINFO << "Get new routing request:" << routing_request.DebugString();
RoutingResponse routing_response;
apollo::common::monitor::MonitorLogBuffer buffer(&monitor_logger_);
const auto& fixed_request = FillLaneInfoIfMissing(routing_request);
if (!navigator_ptr_->SearchRoute(fixed_request, &routing_response)) {
AERROR << "Failed to search route with navigator.";
buffer.WARN("Routing failed! " + routing_response.status().msg());
return;
}
buffer.INFO("Routing success!");
AdapterManager::PublishRoutingResponse(routing_response);
return;
}目前,Apollo 2.5版本中的导航基于A*算法。这是一种在图形平面上,有多个节点的路径,求出最低通过成本的算法。该算法综合了Best-First Search和Dijkstra算法的优点:在进行启发式搜索提高算法效率的同时,可以保证找到一条最优路径(基于评估函数)。在A*算法计算的过程中,会尝试多条路径。一旦遇到障碍物,便将该路径上的点标记为不需要继续探索(图中的实心点)。继续以剩下的空心点为基础探索。最终求得最优路径。下图动态描述了A*算法查找目标路径的算法过程。Planing(计划)模块介绍Planing模块根据定位信息,车辆状态(位置,速度,加速度,底盘),地图,路线,感知和预测,计算出安全和舒适的形式线路让控制器执行。目前的系统实现中包含了四种计划器:RTKReplayPlanner(自Apollo 1.0以来):RTK重放计划器首先在初始化时加载记录的轨迹,并根据当前系统时间和车辆位置发送适当的轨迹段。EMPlanner(自Apollo1.5以来。EM是Expectation Maximization的缩写):EM计划器,会根据地图,路线和障碍物计算驾驶决策和线路。基于动态规划(Dynamic programming,简称DP)的方法首先用于确定原始路径和速度曲线,然后使用基于二次规划(Quadratic programming,简称QP)的方法来进一步优化路径和速度曲线以获得平滑的轨迹。LatticePlanner:网格计划器NaviPlanner:这是一个基于实时相对地图的计划器。它使用车辆的FLU(Front-Left-Up)坐标系来完成巡航,跟随,超车,接近,变道和停车任务。模块输入:RTK重放计划器:Localization记录的RTK轨迹EM计划器:LocalizationPerceptionPredictionHD MapRouting模块输出:无碰撞和舒适的轨迹让控制模块的执行模块解析Planing模块在初始化的Init函数中,这里面会注册所有的计划器,然后根据配置文件中的配置确定当前所使用的计划器。目前,配置文件中配置的是EM计划器。Planing模块在Start函数中设定了一个Timer用来完成定时任务:Status Planning::Start() {
timer_ = AdapterManager::CreateTimer(
ros::Duration(1.0 / FLAGS_planning_loop_rate), &Planning::OnTimer, this);
...Planning::OnTimer最主要的就是调用RunOnce(),而后者包含了Planing模块的核心逻辑。目前,FLAGS_planning_loop_rate值是10。也就是说,Planing模块运行的频度是每秒钟10次。在Planning::Plan函数中,更通过配置的计划器进行路线的计算,然后将结果对外发布。关键代码如下:Status Planning::Plan(const double current_time_stamp,
const std::vector<TrajectoryPoint>& stitching_trajectory,
ADCTrajectory* trajectory_pb) {
auto* ptr_debug = trajectory_pb->mutable_debug();
if (FLAGS_enable_record_debug) {
ptr_debug->mutable_planning_data()->mutable_init_point()->CopyFrom(
stitching_trajectory.back());
}
auto status = planner_->Plan(stitching_trajectory.back(), frame_.get());
ExportReferenceLineDebug(ptr_debug);
const auto* best_ref_info = frame_->FindDriveReferenceLineInfo();
if (!best_ref_info) {
std::string msg("planner failed to make a driving plan");
AERROR << msg;
if (last_publishable_trajectory_) {
last_publishable_trajectory_->Clear();
}
return Status(ErrorCode::PLANNING_ERROR, msg);
}
ptr_debug->MergeFrom(best_ref_info->debug());
trajectory_pb->mutable_latency_stats()->MergeFrom(
best_ref_info->latency_stats());
// set right of way status
trajectory_pb->set_right_of_way_status(best_ref_info->GetRightOfWayStatus());
for (const auto& id : best_ref_info->TargetLaneId()) {
trajectory_pb->add_lane_id()->CopyFrom(id);
}
best_ref_info->ExportDecision(trajectory_pb->mutable_decision());
...
last_publishable_trajectory_->PrependTrajectoryPoints(
stitching_trajectory.begin(), stitching_trajectory.end() - 1);
for (size_t i = 0; i < last_publishable_trajectory_->NumOfPoints(); ++i) {
if (last_publishable_trajectory_->TrajectoryPointAt(i).relative_time() >
FLAGS_trajectory_time_high_density_period) {
break;
}
ADEBUG << last_publishable_trajectory_->TrajectoryPointAt(i)
.ShortDebugString();
}
last_publishable_trajectory_->PopulateTrajectoryProtobuf(trajectory_pb);
best_ref_info->ExportEngageAdvice(trajectory_pb->mutable_engage_advice());
return status;
}Control(控制)模块介绍控制模块根据计划和当前的汽车状态,使用不同的控制算法来生成舒适的驾驶体验。控制模块可以在正常模式和导航模式下工作。模块输入:计划的线路车辆状态定位信息Dreamview AUTO模式更改请求模块输出:控制命令(转向,油门,刹车)到底盘模块解析Control模块的主体逻辑也是通过Timer定时执行的。在定时触发的函数Control::OnTimer中,会生成命令然后派发出去:void Control::OnTimer(const ros::TimerEvent &) {
double start_timestamp = Clock::NowInSeconds();
if (FLAGS_is_control_test_mode && FLAGS_control_test_duration > 0 &&
(start_timestamp - init_time_) > FLAGS_control_test_duration) {
AERROR << "Control finished testing. exit";
ros::shutdown();
}
ControlCommand control_command;
Status status = ProduceControlCommand(&control_command);
AERROR_IF(!status.ok()) << "Failed to produce control command:"
<< status.error_message();
double end_timestamp = Clock::NowInSeconds();
if (pad_received_) {
control_command.mutable_pad_msg()->CopyFrom(pad_msg_);
pad_received_ = false;
}
const double time_diff_ms = (end_timestamp - start_timestamp) * 1000;
control_command.mutable_latency_stats()->set_total_time_ms(time_diff_ms);
control_command.mutable_latency_stats()->set_total_time_exceeded(
time_diff_ms < control_conf_.control_period());
ADEBUG << "control cycle time is: " << time_diff_ms << " ms.";
status.Save(control_command.mutable_header()->mutable_status());
SendCmd(&control_command);
}Control模块内置了三个控制器,它们的结构和说明如下:LatController:基于LQR的横向控制器,计算转向目标。详见:Vehicle Dynamics and Control。LonController:纵向控制器,计算制动/油门值。MPCController:MPC控制器,组合了横向和纵向控制器。结束语本文主要以Apollo项目2.5版本为基础做了一些调查分析。上文中我们也提到,目前的2.5版本仅仅是针对L2级自动驾驶的,而百度计划在2019年实现L3级自动驾驶,2021年实现L4级自动驾驶。可见,这个项目接下来的时间里将会非常高速的发展。另外,今年我刚好有机会参加了上海的CES展。在展会上也看到了百度展出的两款自动驾驶车型:一款是小型巴士。还有一款是小型物流车。今后我也会继续保持对该项目的关注,如果有更多的信息会继续分享给大家。
前言对新手来说要啃下一个大公司的顶级项目是很吃力的,特别是在没有前辈带着的情况下。所以我希望这个系列教程可以帮助更多的开发者理清百度的Apollo系统,文章会比较偏技术向(软件),所以很多套话和简介之类的教程中就不再提及了,而且因为本身能力精力有限所以有错误希望大家积极指出。这些文章会尽量跟着Apollo的版本不断更新并尽可能地保持简洁,有些不太适合用中文表达的会直接用英文方便大家对照。如有引用或借鉴请注明出处,谢谢!Apollo版本此图为百度官方给出的版本图,此时处于2019.7这个版本。下面会列出所有的版本,笔者建议主要关注1.0(初始版)、3.0(老架构终极版)、3.5(新架构初始版),其他版本主要都是一些功能的完善。Apollo 1.0初版的Apollo,只能在封闭场景(测试车道,停车场)中完成Automatic GPS Waypoint Following等简单任务,现在这个版本可以用来测试Apollo和车的兼容性。主要硬件:工业电脑(IPC),GPS,IMU,控域网(CAN)卡软件:基于Linux 4.4.32内核的Apollo Linux内核Apollo 1.5这一版加入了LiDAR,下图黄色处为更新或新加的模块。有了LiDAR感知能力得到了增强,所以在完成fixed lane cruising等任务时更加可靠了。新增的硬件:LiDAR,GTX1080 GPU软件:GPU驱动Apollo 2.0这个版本做了很多常用的自动驾驶任务。车可以在简单的城市道路上运行了,并且可以完成避障,识别交通信号灯,变道等任务。新增硬件:摄像头(主要用于识别信号灯),RadarApollo 2.5这个版本主要是2.0的优化,车可以在有防护的高速公路上运行了。新增硬件:多了一个摄像头。Apollo 3.02.5和3.0版本主要都是上层功能算法的优化完善,3.0算是原版Apollo的终极形态,它提供了一些应用场景(在Apollo官网上挂着的案例就是):Minibus,Valet Parking等,并且做出了一些集成的硬件平台产品。新增硬件:超声波传感器,Apollo传感器Unit,Apollo硬件开发平台软件:守护程序,监视器,新的硬件平台驱动Apollo 3.5需要重点关注的版本,Apollo发布了自己的Runtime Framework:Cyber RT,整体的软件组织更加有序和清晰。这个版本车已经可以在更加复杂的住宅和小镇区域行驶了,换上了360度全方位感知系统后感知能力大大增加。至此,Apollo系统算是进入了新的发展阶段,已经具备了基本的软件架构雏形以及硬件方案。新增硬件:更高档的各式传感器,Apollo Extension Unit (AXU)软件:基于新传感系统更新了算法,Cyber RTApollo 5.0主要是软件方面的更新,可以看到3.5版本基本就是硬件定型版本,5.0主要是针对数据层面定义了内部的数据格式和通信方式,并且也提供了很多前期积累的驾驶数据与模拟器数据。软件:Data Pipeline, Apollo Synthetic Data Set, 算法更新Apollo 软硬件架构Hardware/ Vehicle OverviewHardware Connection OverviewSoftware Overview - Navigation Mode预备知识这里列举一些学习Apollo系统的预备知识,随着Apollo的更新,这些也会有所变化。这些知识分为2类,一类是只需要理解概念和理念,另一类需要开发者会使用。这里针对的是普通开发者,读者需要根据实际情况学习自己所需的知识。理解ROS:Cyber RT中很多设计都借鉴了ROS传感器基础知识,比如LiDAR、Radar、IMU都是什么:理解上层算法的基础常见的自动驾驶算法(非算法开发者),比如计算机视觉、高清地图构建、PID控制等:理解系统是如何决策和运作的掌握C++:需要比较高阶的知识,比如知道C++11的特性,会使用高级的数据结构,能理解面向对象编程,熟悉并发编程VSCode:官方钦定的调试工具Dreamland, Dreamview:官方模拟器环境工具Bazel:Apollo使用的编译工具Google Protocol Buffer:Apollo使用的“通信协议”Docker:Apollo系统运行在容器环境Ubuntu:基础的Linux使用Apollo主要代码结构cyber 消息中间件,相当于ROS作用docker 容器环境搭建的脚本等modules 不同的功能模块
canbus 通讯总线common 日志,数学库等辅助代码drivers 雷达摄像头等的驱动tools 工具v2x 车和其他实体的交互data 数据control 控制模块transform 原型为ros/tf2库,用来坐标转换guardian 守护程序其余模块主要都是自动驾驶会用到的功能scripts 脚本third_party 第三方库后续初章主要是搬运和总结百度官方的介绍,之后会逐渐深入理解Apollo的代码结构。系列文章不会关注具体的算法实现或优化,主要是带读者理解整体运行流程和架构。注:本着开源精神,本专栏的文章都能自由查阅,但不定时有些新的文章会被设置成vip可见,别慌,那些文章因为还没完全写好或者突然发现有一些错误所以暂时隐藏,后续完全改好以后就会正常发出,当然心急的同学可以先睹为快参考链接大部分内容可以在官方github找到。百度Apollo项目技术文档Apollo Github项目地址使用Docker Build装载运行代码结构

我要回帖

更多关于 百度经验怎么发布 的文章

 

随机推荐