【Apollo源码分析】系列的第一部分【common】
源码分析
Apollo 整体上由13个模块构成,分别是
canbus -汽车CAN总线控制模块
common - 公有的源码模块
control -控制模块
decision -决策模块
dreamview -可视化模块
drivers -驱动模块
hmi -人机交互模块
localization-定位模块
monitor -监控模块
perception -感知模块
planning -运动规划模块
prediction -预测模块
tools -通用监控与可视化工具
Apollo采用bazel 作为代码编译构建工具。
每个源码文件夹下有一个BUILD文件,作用是按照bazel的格式来编译代码。
关于如何使用bazel编译c++代码,可以查看以下网址:
【1】https://docs.bazel.build/versions/master/tutorial/cpp.html
【2】https://docs.bazel.build/versions/master/tutorial/cpp-use-cases.html
ok。现在开始分析源码。系列文章的第一篇,首先分析modules/common目录下面的源码。
modules/common/macro.h
宏定义 DISALLOW_COPY_AND_ASSIGN:
#define DISALLOW_COPY_AND_ASSIGN(classname) \
private: \
classname(const classname &); \
classname &operator=(const classname &);
用于在C++中禁止class的拷贝构造函数和赋值构造函数,良好的c++代码应该主动管理这2个操作符。
在caffe和cartographer或者其他的著名库中均有类似的操作。
宏定义 DISALLOW_IMPLICIT_CONSTRUCTORS:
#define DISALLOW_IMPLICIT_CONSTRUCTORS(classname) \
private: \
classname(); \
DISALLOW_COPY_AND_ASSIGN(classname);
禁止class的无参构造函数。
宏定义 DECLARE_SINGLETON:
#define DECLARE_SINGLETON(classname) \
public: \
static classname *instance() { \
static classname instance; \
return &instance; \
} \
DISALLOW_IMPLICIT_CONSTRUCTORS(classname) \
单例类定义,instance() 返回指向同一个class对象的指针。禁止拷贝/赋值运算符。
modules/common/log.h
apollo内部使用谷歌的glog作为日志库。
有5个日志级别,分别是DEBUG,INFO,WARNING,ERROR,FATAL。
#include "glog/logging.h"
#define ADEBUG VLOG(4) << "[DEBUG] "
#define AINFO VLOG(3) << "[INFO] "
#define AWARN LOG(WARNING)
#define AERROR LOG(ERROR)
#define AFATAL LOG(FATAL)
modules/common/time/time.h
apollo内部使用c++ 11的 chrono库作为时间管理工具。默认精度是纳秒(1e-9).
std::chrono::duration 表示时间间隔大小。
std::chrono::time_point 表示时间中的一个点。
定义2个别名:
- Duration,1纳秒,1e-9s。
- Timestamp,以纳秒ns为单位的时间点。
全局函数:
- int64_t AsInt64(const Duration &duration)
将纳秒ns转换为以PrecisionDuration为精度单位计的int64整数。
- int64_t AsInt64(const Timestamp ×tamp) :
将Timestamp(时间点)转换为64位整数表示。
- double ToSecond(const Duration &duration) :
将纳秒ns转换为秒s。
- inline double ToSecond(const Timestamp ×tamp) :
将以纳秒表示的时间点ns转换为秒s
- Timestamp FromInt64(int64_t timestamp_value) :
将以PrecisionDuration为精度计的int64整数转换为Timestamp(时间点)。
- Timestamp From(double timestamp_value):
将秒s转换为时间点Timestamp。即FromInt64的特化版本:先将时间转换为ns计的64位整数nanos_value,再转换为Timestamp。
Clock 类:
Clock是封装c++ 11 chrono后抽象的时钟计时类class。
是线程安全的单例模式(c++ 11的语法可确保)。
数据成员:
bool is_system_clock_; true表示系统时间,false表示模拟时间
Timestamp mock_now_; 模拟时间的当前值。
为啥要标记模拟时间?:为了仿真训练。多次仿真,反复训练。
Clock类没有公有的构造函数。私有构造函数初始化为使用cpu的系统时间。
Clock提供4个static 公有函数:
static Timestamp Now()
返回当前时间的最新值。
static void UseSystemClock(bool is_system_clock)
设置是否使用模拟时间。
static bool IsSystemClock()
返回是否使用系统时间。
static void SetNow(const Duration &duration)
当Clock使用mock时间时,将系统时间设定为给定值。
否则抛出运行时错误。(只有模拟时间才可调整值,系统时间不可调整)
modules/common/time/time_test.cc
Duration duration = std::chrono::milliseconds(12); //12ms
EXPECT_EQ(12000, AsInt64<micros>(duration)); //==121000us
Duration duration = std::chrono::microseconds(1234567);//1234567us
EXPECT_EQ(1234, AsInt64<millis>(duration)); //==1234ms
Duration duration = std::chrono::microseconds(123 456 789 012);//123...us
EXPECT_FLOAT_EQ(123456.789012, ToSecond(duration)); //123456(s)
...略.
EXPECT_TRUE(Clock::IsSystemClock()); //默认是cpu系统时间
Clock::UseSystemClock(false); //修改。
EXPECT_FALSE(Clock::IsSystemClock());
EXPECT_EQ(0, AsInt64<micros>(Clock::Now())); //模拟时间的初值是0.
Clock::SetNow(micros(123)); //修改为123 (us)
EXPECT_EQ(123, AsInt64<micros>(Clock::Now()));
modules/common/util/util.h
函数原型:
bool EndWith(const std::string &original, const std::string &pattern);
-
当original字符串以 pattern 结尾时,返回true
-
测试代码,util_test.cc:
EXPECT_TRUE(EndWith("abc.def", "def"));
EXPECT_TRUE(EndWith("abc.def", ".def"));
EXPECT_FALSE(EndWith("abc.def", "abc"));
EXPECT_FALSE(EndWith("abc.def", "de"));
modules/common/util/file.h
file.h提供了多个关于操作文件(关于protobuf文件的读,写,删)的函数。
都是模板类函数:
template <typename MessageType>
- (1). 将message存储到filename中,以ascii格式存储.
bool SetProtoToASCIIFile(const MessageType &message,
const