Apollo学习之rosbag_storage总体介绍
rosbag_storage模块主要实现了ros bag的读写等一系列操作。也就是说前面介绍的rosbag录制和播放模块读写bag包,底层都是调用rosbag_storage接口。因此这里我们有必要对rosbag_storage做一个分析。
附赠自动驾驶最全的学习资料和量产经验:链接
目录
rosbag_storage的源码在ros_comm\tools\rosbag_storage
中,目录结构如下:
aes_encryptor.h // aes加密
bag.h // bag读取保存接口 ---主要
bag_player.h // bag包播放器
buffer.h // 缓存
chunked_file.h // 块文件 ---主要
constants.h // 常量 ---主要
encryptor.h // 加密
exceptions.h // 异常
gpgme_utils.h // gpgme库
macros.h
message_instance.h // 消息实例 ---主要
no_encryptor.h // 不加密
query.h // 查询接口 ---主要
stream.h // 文件流,用于读写文件 ---主要
structures.h // 一些结构
view.h // bag包查看器 ---主要
可以把上述文件分为3类。
-
bag包和格式:bag.h、constants.h
-
bag包查看:message_instance.h、query.h、view.h
-
bag包文件读写:chunked_file.h、stream.h
接下来我们将分3个部分介绍这几个功能。
bag包格式
bag的格式可以参考,根据官方文档我们做了更加直观的介绍。
Ros Bag格式
一个Bag包都是以字符串#ROSBAG V2.0
开头,后面接上N个record。每个record由4部分组成:header_len、header、data_len、data。
这里最复杂的就是header了,它又由N个field组成,其中op属性的field是每个record必须的,其它一些field是可选的,通过op field可以指定record的类型,一共有6种不同的op field属性,对应6种不同的record。注意每种record除了op field之外,还包括自己特定的field,后面我们会介绍。
-
Bag header。存储有关整个包的信息,例如到第一个索引数据记录的偏移量,以及块和连接的数量。
-
Chunk。存储(可能是压缩的)连接和消息记录。
-
Connection。存储 ROS 连接的头信息,包括主题名称和消息定义的全文。
-
Message data。使用连接的 ID 存储序列化的消息数据(可以是零长度)。
-
Index data。在前一个块的单个连接中存储消息索引。
-
Chunk info。将有关消息的信息存储在一个块中。
接下来我们详细介绍这6种类型。
1. Bag header
包头记录做为第一个record出现。以下字段保证出现在包头记录中(op=0x03)。
-
index_pos。 块部分后第一条记录的偏移量。
-
conn_count。 文件中唯一连接的数量。
-
chunk_count。 文件中的块记录数。
包头record格式
包头记录先用0x20填充,包头总长度为4096 Bytes(header_len+data_len)。之所以先填充的原因为在写入后面的数据后,可以方便的修改包头记录。
2. Chunk
以下字段保证出现在块记录中(op=0x05)。
-
compression。 数据的压缩类型。
-
size。 未压缩块的字节大小。
支持的压缩类型为“none”和“bz2”。 块的压缩大小可以在record的data_len字段中找到。
3. Connection
以下字段保证出现在块记录中(op=0x07)。
-
conn**。** 唯一连接 ID。
-
topic**。** 存储消息的主题。
数据由一个字符串组成,该字符串包含与包记录头格式相同的连接头。 以下字段必须出现在连接头中:topic、type、md5sum、message_definition。 可选字段包括:callerid、latching。
4. Message data
以下字段保证出现在消息数据头 (op=0x02) 中。
-
conn。 消息到达的连接ID。
-
time。 收到消息的时间。
这些记录中的数据是ROS序列化消息数据。
5. Index data
以下字段保证出现在索引数据头中 (op=0x04):
-
ver。 索引数据记录版本。
-
conn。 连接ID。
-
count。 前一个块中 conn 上的消息数。
如果版本号为1,还包括以下字段。
-
time。 收到消息的时间。
-
offset。 未压缩块数据中消息数据记录的偏移量。
6. Chunk info
以下字段保证出现在块信息头中(op=0x06)。
-
ver。块信息记录版本。
-
chunk_pos。块记录的偏移量。
-
start_time。块中最早消息的时间戳。
-
end_time。块中最新消息的时间戳。
-
count。块中的连接数。
如果版本号为1,还包括以下字段。
-
conn。 连接ID。
-
count。 块中到达此连接的消息数。
至此6种不同的record就介绍完毕了,bag包的代码实现在bag.h中,由于内容比较多,我们将在下一个章节单独介绍。
constants
Bag包中一些常量在constants.h文件中申明,包括OP字段类型,文件头长度和压缩类型等。
// Current "op" field values,对应record的类型
static const unsigned char OP_MSG_DATA = 0x02;
static const unsigned char OP_FILE_HEADER = 0x03;
static const unsigned char OP_INDEX_DATA = 0x04;
static const unsigned char OP_CHUNK = 0x05;
static const unsigned char OP_CHUNK_INFO = 0x06;
static const unsigned char OP_CONNECTION = 0x07;
// Legacy "op" field values
static const unsigned char OP_MSG_DEF = 0x01;
// Bytes reserved for file header record (4KB) bag header的预留大小
static const uint32_t FILE_HEADER_LENGTH = 4 * 1024;
// Compression types 压缩类型
static const std::string COMPRESSION_NONE = "none";
static const std::string COMPRESSION_BZ2 = "bz2";
static const std::string COMPRESSION_LZ4 = "lz4";
总结
rosbag_storage和它的名字一样主要实现了bag包的读取和保存接口,并且提供给其它接口调用。