百度开源的Apollo自动驾驶项目主要使用C++实现,下面总结其中使用了哪些编程或者C++概念,方便对自动驾驶有兴趣的同学提前学习,在分析代码时能更快深入。
1 设计模式
Apollo使用了单例模式和工厂模式。
单例模式的代表是提供高精地图接口的类HDMapUtil
,它是个静态类,在整个项目中只初始化一次,在所有程序中都能访问。
工厂模式的代表是加载规划子任务的类TaskFactory
。
2 多线程编程
Apollo使用了多线程编程的概念,主要用在运行时间比较长或者运行时间不确定的情况。例如,行车规划模块中生成参考线的函数ReferenceLineProvider::GenerateThread
,还有泊车规划模块中进行轨迹规划的函数OpenSpaceTrajectoryProvider::GenerateTrajectoryThread
。
Apollo使用多线程的方式是对std::async
进行封装然后调用,其中的坑初学者要小心。
此外,还要熟悉mutex
如何加锁和atomic
变量。
3 STL标准模板库
Apollo大量使用STL标准模板库提供的数据类型,例如vector、list、pair、unordered_map、unordered_set等等,初学者可以多多练习,因为你会经常和它们打交道。
与之相关的还有泛型编程,其中使用了std::copy
、std::sort
、std::back_inserter
。
4 lamda表达式
lamda表达式能让程序更简洁,例如这个比较大小的函数:
auto xminmax = std::minmax_element(boundary_points.begin(), boundary_points.end(), [](const Vec2d &a, const Vec2d &b) { return a.x() < b.x(); });
5 智能指针
Apollo中使用了很多智能指针。当然,读者应该首先学习原始指针和引用。
6 序列化
Apollo诞生自ROS,ROS采用自己实现的序列化方法。青出于蓝而胜于蓝,Apollo采用了google提出的protobuf序列化工具实现不同模块间消息的传递。此外,protobuf也被用在配置定义和模块内部的数据传递上。当然,不管多么复杂的消息,经过protobuf序列化得到的始终一串字符串,所以用ROS也可以发送接收,只不过解析还是要用protobuf提供的接口。
7 时间
Apollo虽然是在Linux上设计的,但是使用了与操作系统无关的std::chrono
库实现计时等功能。
总结
虽然C++是世界上最难的编程语言,但Apollo项目没有使用过于复杂难懂的C++编程技巧,大多数都是基本功,所以初学者不要害怕。