0.前言
1.整体介绍
2.系统架构和硬件配置
2.1 系统架构
2.2 硬件配置
3.量产安全规范体系
4.生态体系
5.软件算法分析
5.2 Supercombo模型
5.3 DMS模型
5.4 Localization算法
5.5 Planner/Controls算法
6.后记
0.前言
目前,特斯拉基于纯视觉环视自动驾驶方案,如市场上已经批量生产和产品化的车端自动驾驶方案,如Mobileye的True Redundancy方案,即纯相机方案 雷达和激光雷达方案形成了冗余的自动驾驶方案。这两种方案对移动平台的计算能力要求不容忽视Tesla 2021 AI DAY 公布的FSD chip就达到144TOPS,Mobileye面向L推出4级自动驾驶EyeQ Ultra,其AI算力可以达到176TOPS。虽然两者在TOPS以上都不是最出彩的,但在拼算能力的背后,也有算法模型复杂性不断上升的原因。但是,通过我们今天,我想介绍一款经济实用、性价比高的自动驾驶外装产品Comma.ai 的Openpilot,它只配备了乐视手机和高通骁龙821芯片openpilot software,就能实现L2 自动驾驶。
感谢PerceptionX 本文对蔡老师的大力支持,如有建设性问题,请联系 caizhitian@pjlab.org.cn。自动驾驶团队OpenPerceptionX是上海人工智能实验室的智能驾驶感知团队,致力于探索学术产业感知、整合、端到端算法的前沿,感兴趣的学生请联系小边Hugo maihaoguang@pjlab.org.cn ,我们在招! 上海人工智能实验室位于美丽的徐汇滨江,有学术牛具体指导实习生和新招生;也适合工作多年的社会招聘老板在这里充分展示自己的价值。我们坚信我们可以在这里做到solid impact对标国际一流实验室成果。 PS: 未经许可,禁止擅自转载。
1.整体介绍
What is Openpilot?
在探索基于端到端的自动驾驶过程中,我们遇到了一个偶然的机会Openpilot这个产品是一套成熟的产品基于端到端模型实现的开源项目等待辅助驾驶功能。目前已经卖给消费者,可以适应各种车型,通过简单的安装在自己的车上就可以体验辅助驾驶功能。
相关链接
公司官网:https://comma.ai/
开源项目:https://github.com/commaai/openpilot
Demo视频:https://www.youtube.com/watch?v=XOsa0FsVIsg
Openpilot夜晚效果:https://www.youtube.com/watch?v=aUncj2myFwc
Openpilot vs Tesla Autopilot:https://www.youtube.com/watch?v=YJzvrDBQwOE
第三方评20年消费者使用评0年基于消费者使用评估统计的评估报告。
https://data.consumerreports.org/wp-content/uploads/2020/11/consumer-reports-active-driving-assistance-systems-november-16-2020.pdf
通过以上视频demo以及第三方评估,我们可以看到Openpilot整体产品性能惊人。对于这个产品,我们列出了一些核心产品Keypoints :
- 第一个开源是基于端到端(Perception to Planning)的辅助驾驶系统
- 采用自标模块,相机安装简单
- 整体算法思路很新颖
- 将感知 一个计划model
- 引入时序信息
- 关注最危险的目标/输出速度
- 完善数据系统/生态系统
- 大量数据积累
- 用户可以自己上传数据
- 开源社区共同服务
2.系统架构和硬件配置
2.1 系统架构
如图所示,整个系统架构可分为四个部分
-
- 配置
- 接管
- 物理环境
-
- CommaTwo device
- CAN bus
- Panda(连接CAN和CommaTwo的硬件适配器)
- Stock sensors
- Actuators (执行器,如方向盘steering、油门gas、刹车brake)
-
- Cameras: 前视和舱内两个摄像头
- GPS
-
- Infrastructure
- Communication dependencies
- Selfdrive Core
- Radar
- Planner
- Control
2.2 硬件配置
在前架构图中CommaTwo device根据至于为什么要用乐视手机改装?通过查阅官网资料,了解到因为CommaTwo高通骁龙821芯片,包括乐视3Pro,目前只适合乐视手机。camera如果使用其他型号,则需要自行适应接口camera。以下是该设备的展示
3.量产安全规范体系
Openpilot作为量产的辅助驾驶产品,每次发布上市都要遵循相关法律法规,确保功能安全。Openpilot总体安全规范流程如图所示
- 从图中可以看出Openpilot遵循功能生产ISO26262标准,ASIL安全评级、DFMEA(分析潜在失效模式和效果)NHTSA(美国国家公路安全管理局)FMVSS(美国公路机动车安全标准)
- 对于汽车系统,ASIL安全等级划分为QM、A、B、C、D五个等级,QM代表与安全无关,D最高等级。
- 严重性(Severity of failure,S):致命伤S3
- 可能性(Probability of exposure,E):高可能性E4
- 可控性(Controllability,E):难以控制C3
- Openpilot系统ASIL等级为D=S3 E4 C3
- 对于汽车系统,ASIL安全等级划分为QM、A、B、C、D五个等级,QM代表与安全无关,D最高等级。
- Openpilot基于DMS(Driving Monitor System)系统监控驾驶员状态,遵守FMVSS requirements,同时符合NHTSA发布的标准pertinent documents
- 关于危险等级(Hazard and Risk Analysis)和FMEA/DFMEA, Openpilot主要符合两点设计理念
-
- 人类驾驶员优先级永远最高,如果有任何接管,立即退出openpilot
- 执行器(Actuators)变化不能过快,例如change trajectory需要within reasonable limits.不同车型关于safety module的阈值、case都不太一样,具体参考 https://github.com/commaai/panda/tree/master/board/safety
-
- 在软件功能生产时严格按照编码规范MISRA C:2012 , 该规范由汽车产业软件可靠性协会(MISRA)提出的C语言开发标准,其目的是在增进嵌入式系统的安全性及可移植性。 Openpilot 利用Panda Firmware作为codebase,以及cppcheck模块做代码规范分析,通过panda的safety model保证安全性
- 在每次新版本发布之前,都会经对功能的测试以及进行SIL,HIL,VIL三项测试,具体的流程如图所示。
4.生态体系
下面这幅图展示了Openpilot的解决自动驾驶问题的设计理念-,Openpilot生态体系包括数据体系和开源社区服务,通过积累大量的数据,用于模型训练部署,循环迭代,并以此对标Tesla。
-
- openpilot:https://github.com/commaai/openpilot ,通过Pull request,添加车辆配置,bug reports ,数据Replay/simulation等功能,用于数据存储,离线开发
- explorer:https://github.com/commaai/explorer 网页在线replay功能
-
- Comma10k:https://github.com/commaai/comma10k ,真实场景,10000 png,社区用户标注,模型训练
- Comma2k19:https://github.com/commaai/comma2k19,真实场景,comama EONs采集,Pose&Localization
- Selling:https://github.com/commaai/data-sales ,真实场景,comma twos采集数据
- 众筹数据:https://my.comma.ai/ , 用户将设备数据上传到服务器,标注用户数据,用于模型训练
- challenge比赛:https://github.com/commaai/calib_challenge
Openpilot开源的数据体系包括Comma10k和Comma2k19,其中,Comma10k主要用作像素级分割任务,Comma2k19用于车规控制算法,考虑后续我们基于此数据集进行复现模型,可以持续关注后续更新,这里重点关注Comma2k19这个数据集。
Raw_log
Globalpose from fusion
数据集解析Setup
下载数据解析相关代码
git clone https://github.com/commaai/comma2k19
git submodule update --init --recursive
sudo apt-get install libcurl4-gnutls-dev
sudo apt-get install libghc-gnutls-dev
pip3 install pycurl
cd {PATH}/comma2k19-master && pip3 install -r requirements.txt
解析代码demo:{PATH}/notebooks
(注:需要添加所需模块路径:sys.path.append('{MODULE_PATH}'))
Comma2k19 数据集分 10 个卷,解压后大约 100G。通过踩坑,,然后将数据集挂载到相应目录进行解析数据,可以减少环境依赖。 若对数据格式感兴趣,可以前往Openpilot github
Sample
5.软件算法分析
前面几个部分主要从宏观角度介绍了Openpilot产品性能,系统架构,安全规范体系以及生态体系。对于没有接触到Openpilot这款产品的人,可能不太相信在自动驾驶领域这种采用Percetion to Planning的方案能够work,更神奇的是,它还是一款量产的产品。
Link
针对camera数据流部分,我们主要关注Openpilot设备中camera采集的图像如何从从硬件采集到输出给模型,根据前面硬件设备介绍可知Openpilot设备SOC采用高通的骁龙821,系统采用定制的安卓系统。通过查找源码发现,如图所示,camera底层(kernel)基于linux V4L2视频框和应用层通信,对V4L2具体细节感兴趣的可参考https://deepinout.com/v4l2-tutorials/linux-v4l2-architecture.html。
针对高通平台而言,内核相机驱动在v4l2框架上进行了相应的扩展。首先,创建了一个整体相机控制者的CRM,以节点video0暴露给用户空间,主要用于管理内核中的Session、Request以及子设备,同时各个子模块都实现了各自的v4l2_subdev设备,并且以v4l2_subdev节点暴露给用户空间,暴露子设备的设备节点,在用户空间直接通过标准的字符设备控制接口来控制各个设备。其次,创建了另一个video1设备节点用于同步数据流,保证用户空间和内核空间的buffer能够高效得进行传递。
- Camera init部分
Init部分主要执行系统初始化,分配视频帧内存,源码中预留了4帧数据大小内存
- Camera open部分
根据前面分析的视频框架,V4L2将camera设备节点以设备文件形式映射到用户空间,打开camera也就是打开对应的设备文件节点
- Cameras run
,开启sensor基于i2c通信,发送控制信号,三路camera对应三个线程,,通过poll机制监测road camera对应的文件句柄(video0_fd),执行handle_camera_event处理(图像帧预处理)
根据以上分析可得camera部分函数调用关系
Cameras_init(wide/road/driver camera)
Set camera state
Set camera paramerter(grey_fraction,gain,exposure_time ,etc)
Camera buf init(allocate related mem)
set vipc_server to camerad
allocate 4 frame_size
get_model_yuv_tranform(do a 2x downsize)
vipc_server create buffers for rgb and yuv
Cameras_open(wide/road/driver camera)
Open video0_fd/video1_fd
Open isp
Query icp for MMU handles
Request msg subscribe from video0_fd
Camera_open(wide_cam)
Open v4l2 sensor_fd
Create sessoin
Access sensor
Config isp/CSI PHY
Link devices:start csiphy/isp/sensror
Vipc_server start listen cameras
Camera_run(wide/road/driver camera)
start thread to process road camera
Receive frame_data
Fill frame data and yuv transform
Publish "roadCameraState" msg including frame data
Start devices by send i2c sinnal to sensor
Open poll events to monitor video stream and callback process
Set per frame parameter
- 总结
前面的分析,在load模型前,camera数据流部分按照系统层级划分可分为
硬件层:基于高通骁龙821 SOC,前视采用Sony Imx298,Monitor采用ov8865,camera基于 I2C和处理器通信
驱动层:基于高通定制的V4L2视频框架, 最终camera抽象为video文件节点,供用户层调用
应用层:监测camera数据流变化,通过设备文件读写
通信层:源码中,camera数据流以两种方式和模型层通信,即Client/Server模式和
Subscriber/Publish模式前者主要用于传输图像数据,后者用于消息节点通信
对应的camera流程图如图所示
5.2 Supercombo模型
关于模型分析这部分,我们主要,从宏观上了解Openpilot模型这部分的工作。实际上一个模型从设计到应用于量产产品中,至少包括两个部分,
- 根据设计的模型网络结构,选取合适的数据集,在服务端进行训练,
- 根据训练的模型文件在设备端部署。
因此,更多深入的细节方面,后续我们会单独推出两个系列,重点说明我们在模型复现和模型部署方面的工作。
通过netron将源码中supercombo.onnx模型文件打开,可以看出,整体模型结构还是比较精简的,分为Backone,GRU,Head三部分。
从模型输入可以看出,网络图像Input size: 12, 128(H), 256(W),格式为YUV420,具体转换过程
- 原始输入三通道RGB(256*512*3),每帧RGB转换成6通道YUV格式(6*128*256)
- 取两个连续帧作为模型输入,因此,输入大小为(12*128*256)
网络backbone部分,采用了Google团队的Efficientnet-B2结构(EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks)。该结构采用复合缩放策略,主要特点是效果好,速度快。卷积部分下采样5次,为了减少参数量,有几个conv是采用group conv,激活函数函数采用Elu
网络同时引入了时序结构(GRU),把历史信息encode在 h_t中,输入状态信息(desire)到模型;输出Pose, desire_predict, plan, lead(object), lane等信息,经过我们后续模型复现验证,GRU对整个模型起到了比较重要作用(后续可关注我们的模型复现系列)
Head部分主要输出三部分policy信息,具体地
- 左侧frame policy 出Pose, meta
- 中间temporal policy 出planning, lead信息
- 右侧temporal policy 出lanes信息
接下来,我们来分析一下模型输出数据含义,以及它是如何形成形成输出的message的。
首先,关于损失函数,模型输出了自车多个未来轨迹预测,轨迹预测损失函数采用MPH(Multiple Hypothesis Prediction)方法,此处参考 https://github.com/commaai/openpilot/discussions/19535
这里的MPH方法,可以参考Multimodal Trajectory Predictions for Autonomous Driving using Deep Convolutional Networks
文章中方法和MPH类似,这里的multimodal应该指的自车多个未来轨迹预测
整个模型输出包含自车的plan,lane_lines,road_edge,lead,desire_state,metadata,pose等多个信息,详细的框架图如图所示
- 网络输出到建立消息的过程
- plan的每个group最后一个量表征该plan group的好坏,选择概率最大的一个作为best plan
- lead的每个group最后三个量表征该lead group的好坏,分别对应三个t_offset,对于每个t_offset选择值最大的一个作为该t_offset下的best lead。
- laneline采用x方向的anchor方法,在0-192m设置33个anchor,对应的时间t来自best plan。
- 对plan处理时采用时间t的anchor方法,在0-10s设置33个anchor
综合以上分析,我们可以得到一个比较清晰supercombo模型网络结构框图,
5.3 DMS模型
- 模型输入格式同样为YUV,大小(6*320*160)
- Backbone部分,与supercombo模型类似地,dms模型也采用efficientNet的结构
- Head也分成三个部分,分别为face/eye/summary,值得注意的是,eye head中的前面两个(1,8)结果未放到输出的msg结果中(猜测可能为之前用,现在已经deprecated的descriptor)
整体的网络结构如图所示
- Monitor系统仅在接收到driverState时更新driverMonitoringState
- carState主要提供driver_engaged信息,在driver未操作情况下,
- 首先,在接收到modelV2时更新pose/blink cfactor,作为判断distracted的阈值
- 然后,由driverState的结果计算pose/blink,计算历史所有pose的mean/var
- 最后,计算awareness,给出不同的alerts
- controlsd接收driverMonitoringState的events及awarenessStatus结果,当awarenessStatus<0时,control端会给出强制减速指令
算法流程框架图如图所示
5.4 Localization算法
首先,介绍一下openpilot坐标系
坐标系具体信息可参考: https://github.com/commaai/openpilot/tree/master/common/transformations
为便于理解,大致示意图如下:
- view frame为相机坐标系,右方为X轴,下方为Y轴,前方为Z轴,为示意将其放在右侧
- device frame位于相机坐标处,前方为X轴,右方为Y轴,下方为Z轴
- car frame为device frame下方的在road平面上的坐标系
- calibrated frame为在相机处的,以car frame的pitch/yaw,device frame的roll组成的坐标系,也为model输出帧
localizationd模块部分实现功能
- 接收模型输出cameraOdometry进行在线标定,(实际上为device frame-calibrated/car frame之间的转换关系),此处的标定不考虑roll情况
- 接收ublox gnss结果
- 根据gnss、cameraOdometry、imu等传感器信息通过卡尔曼滤波进行最有状态估计,得到精确定位
- 根据定位及carState对car Params进行更新
- 需满足条件Straight and fast (25km/h)
- Rpy, trans from ModelV2 camera odometry
- 实际上是较简单的加权平均,结合有效性判断
- 实际上不考虑roll
核心代码部分
- 在基本直线运动情况下,根据trans直接计算rpy
- rpys保存至多50个rpy,对rpys和new_rpy进行加权平均(共100个)记录到rpys中,最终rpy结果为前valid_blocks个rpy的均值
- 在update_status()中,对更新的rpy进行有效性判断,并在前valid_blocks个rpy差值过大(2 deg)时,重新reset到前一次的rpy结果
- 接收gps/gyro/accelerator/vEgo/cameraOdometry/liveCalibration,通过KF得到最终的定位结果
- 如果event的时间与kf时间差过大,current_time - filter_time > 10时,reset KF到初始状态
- 除senseEvents中更新时用sensor带的timestamp,其余用sm log对应的monoTime;若sensor time与logMonoTime差大于100ms,舍弃该sensor reading
- 仅在接收到cameraOdometry时发送liveLocationKalman消息
根据以上分析,得到整体的算法流程如图所示
5.5 Planner/Controls算法
- 首先对RadarData中的点进行track以及Kalman Filter的update,再利用fastcluster算法合并邻近的track
- 把modelV2感知模型结果和radar信息融合,具体的融合算法思路
- match_vision_to_cluster()方程中,对模型结果中的lead和clusters,计算d/y/v的laplacian_cdf乘积,选取最大的作为匹配的cluster
- 若有匹配的cluster,则设radar cluster为lead结果;若无则设模型输出的lead为最终结果
- 在v_ego较小且目标cluster较近(yRel<1.5, dRel<25),如果此时比先前得到的lead结果更近时,override先前结果
- modelV2的第一个lead,get_lead()时设置参数low_speed_override=True,第二个设为False
- Plannerd中包含两个方向,即横向和纵向的plan,两者互相独立
- Lateral控制会输入感知模型信息
- Longitudinal控制只有radar信息(但是radarState也有融合结果?)
- MPC(model predictive control)使用ACADO(Automatic Control and Dynamic Optimization) Toolkit进行解算,MPC核心代码参考:controls/lib/lateral_planner.py#L180
- Longitudinal方向采用PID控制
- Lateral方向根据车型,采用不同控制算法,包括PID,LQR,INDI等
- 车辆的控制信号通过CAN发送给车辆控制器
算法流程图
6.后记
本文对Openpilot开源项目进行了整体介绍,包括系统架构,硬件配置,安全规范体系,生态体系等。为了更深入的了解它,我们还重点分析了软件算法,包括camera数据流,感知模型,定位以及规控。后续我们会基于此进行,看实际功能表现如何,并进行和一些,。
参考
https://github.com/commaai
https://blog.comma.ai/end-to-end-lateral-planning/
https://blog.comma.ai/towards-a-superhuman-driving-agent/
https://desosa.nl/projects/openpilot/2020/03/11/from-vision-to-architecture.html
comma AI - 知乎
comma.openpilot 的规划控制 - 知乎
comma.openpilot底盘接口及其实现 - 知乎
https://www.its404.com/article/yufeilongyuan/122217990
https://www.thedrive.com/tech/36604/we-tested-openpilot-the-1199-device-that-adds-entry-level-autonomy-to-your-car
https://medium.com/@chengyao.sh