ROS与Matlab语言入门教程-rosbag Logfiles的使用
“rosbag”或“bag”是ROS中存储消息数据的文件格式,这些包通常是通过订阅一个或多个ROS话题创建的,并用一种高效的文件结构存储接收到的消息数据。MATLAB可以读取rosbag文件,并有助于过滤和提取消息数据。本例,用户将会载入rosbag文件并学习如何选择并恢复包含的消息。
预备知识:1.5 基本ROS消息的使用。
载入rosbag
使用“rosbag”指令载入示例文件,采取绝对路径或者相对路径的方式指定记录文件的路径:
filepath = fullfile(fileparts(which('ROSWorkingWithRosbagsExample')), 'data', 'ex_multiple_topics.bag');
bag = rosbag(filepath)
bag =
BagSelection with properties:
FilePath: '/mathworks/devel/bat/BR2015ad/build/matlab/toolbox/r...'
StartTime: 201.3400
EndTime: 321.3400
NumMessages: 36963
AvailableTopics: [4x3 table]
MessageList: [36963x4 table]
调用“rosbag”返回的对象是“BagSelection”,“rosbag”文件中的所有信息都在该对象里。
对象的属性显示了文件包含多少消息(NumMessages)、记录第一个(StartTime)和最后一个(EndTime)消息的时间等详细信息。
获取“AvailableTopics”属性值,查看记录文件中有关话题和消息类型的更多消息。
bag.AvailableTopics
ans =
NumMessages MessageType MessageDefinition
___________ ______________________ _________________
/clock 12001 rosgraph_msgs/Clock [1x185 char]
/gazebo/link_states 11999 gazebo_msgs/LinkStates [1x1247 char]
/odom 11998 nav_msgs/Odometry [1x2918 char]
/scan 965 sensor_msgs/LaserScan [1x2123 char]
“AvailableTopics”属性将包含在“rosbag”文件中的话题做成列表,该列表存储了消息的数量、消息的类型和为话题定义的消息。初始化“rosbag”文件仅仅是MATLAB建立了索引,并没有读取任何实际的消息。
在消息载入MATLAB内存之前,用户可能想要基于索引尽可能的滤除和筛选需要的消息。
选择消息
在恢复任何消息之前,用户必须基于时间戳、话题名称或消息类型选择一系列的消息。
用户可以查看当前选择的所有消息:
bag.MessageList
ans =
Time Topic MessageType FileOffset
______ ___________________ ______________________ __________
201.34 /clock rosgraph_msgs/Clock 4524
201.34 /odom nav_msgs/Odometry 7666
201.34 /gazebo/link_states gazebo_msgs/LinkStates 9866
201.35 /clock rosgraph_msgs/Clock 10962
201.35 /clock rosgraph_msgs/Clock 12876
201.35 /odom nav_msgs/Odometry 12112
201.35 /gazebo/link_states gazebo_msgs/LinkStates 11016
201.36 /odom nav_msgs/Odometry 14026
201.36 /gazebo/link_states gazebo_msgs/LinkStates 12930
201.37 /clock rosgraph_msgs/Clock 14790
201.37 /odom nav_msgs/Odometry 14844
201.37 /gazebo/link_states gazebo_msgs/LinkStates 15608
201.38 /clock rosgraph_msgs/Clock 16704
201.38 /odom nav_msgs/Odometry 17854
201.38 /gazebo/link_states gazebo_msgs/LinkStates 16758
201.39 /clock rosgraph_msgs/Clock 18618
201.39 /gazebo/link_states gazebo_msgs/LinkStates 18672
201.4 /clock rosgraph_msgs/Clock 19768
201.4 /gazebo/link_states gazebo_msgs/LinkStates 19822
201.41 /clock rosgraph_msgs/Clock 20918
201.41 /odom nav_msgs/Odometry 22068
201.41 /odom nav_msgs/Odometry 22832
201.41 /odom nav_msgs/Odometry 23596
201.41 /gazebo/link_states gazebo_msgs/LinkStates 20972
...
“MessageList”列表的每一行包含着记录包里的每一条消息(本例中共有超过3000条消息),列表中的每一行按照消息记录的时间戳排序,时间戳存放在每一行的第一列。
由于列表非常大,用户可以根据熟悉的选择行和列的方法选择感兴趣的部分进行显示:
bag.MessageList(500:505,:)
ans =
Time Topic MessageType FileOffset
____ ___________________ ______________________ __________
203 /clock rosgraph_msgs/Clock 339384
203 /odom nav_msgs/Odometry 336328
203 /odom nav_msgs/Odometry 337092
203 /odom nav_msgs/Odometry 337856
203 /odom nav_msgs/Odometry 338620
203 /gazebo/link_states gazebo_msgs/LinkStates 331944
使用“select”函数筛选消息,“select”函数作用于“bag”对象。用户可以通过时间、话题名称、消息类型或三者的任意组合筛选消息。
使用如下的“select”指令,选择所有发布到“/odom”话题的消息:
bagselect1 = select(bag, 'Topic', '/odom')
bagselect1 =
BagSelection with properties:
FilePath: '/mathworks/devel/bat/BR2015ad/build/matlab/toolbox/r...'
StartTime: 201.3400
EndTime: 321.3300
NumMessages: 11998
AvailableTopics: [1x3 table]
MessageList: [11998x4 table]
调用“select”函数返回另一个“BagSelection”对象,可用于进一步的选择或者恢复消息数据。所有选中的消息之间相互独立,所以用户在完成处理后可以从工作空间中清除它们。
用户可以结合两种标准筛选,为了获得记录文件中,前30秒发布到“/odom”话题的消息列表,使用如下的指令:
start = bag.StartTime
bagselect2 = select(bag, 'Time', [start start + 30], 'Topic', '/odom')
start =
201.3400
bagselect2 =
BagSelection with properties:
FilePath: '/mathworks/devel/bat/BR2015ad/build/matlab/toolbox/r...'
StartTime: 201.3400
EndTime: 231.3200
NumMessages: 2997
AvailableTopics: [1x3 table]
MessageList: [2997x4 table]
使用最后的一个筛选规则更进一步地缩小时间窗口。
bagselect3 = select(bagselect2, 'Time', [205 206])
bagselect3 =
BagSelection with properties:
FilePath: '/mathworks/devel/bat/BR2015ad/build/matlab/toolbox/r...'
StartTime: 205.0200
EndTime: 205.9900
NumMessages: 101
AvailableTopics: [1x3 table]
MessageList: [101x4 table]
最后步骤的筛选对“bagselect2”进行操作,并返回一个新的“bagselect3”对象。
用户还可以将筛选的选项保存到阵列中,并作为“select”函数的输入:
selectOptions = {'Time', [start, start+1; start+5, start+6], 'MessageType', {'sensor_msgs/LaserScan', 'nav_msgs/Odometry'}};
bagselect4 = select(bag, selectOptions{:})
bagselect4 =
BagSelection with properties:
FilePath: '/mathworks/devel/bat/BR2015ad/build/matlab/toolbox/r...'
StartTime: 201.3400
EndTime: 207.3300
NumMessages: 209
AvailableTopics: [2x3 table]
MessageList: [209x4 table]
读取选择的消息数据
在筛选完消息之后,用户可以在MATLAB中真正的读取消息数据,根据用户选择的消息的大小,读取消息数据可能需要很长时间或者消耗很多的计算机内存。
使用“readMessages”函数,恢复用户选择的消息并存储到单元阵列中:
msgs = readMessages(bagselect3);
size(msgs)
ans =
101 1
结果阵列中包含的元素的数量与选择的对象的“NumMessages”属性指示的数量相等。
在读取消息数据过程中,用户可以有选择性的恢复指定目录的消息,下面的例子恢复了四个消息:
msgs = readMessages(bagselect3, [1 2 3 7])
msgs{2}
msgs =
[1x1 Odometry]
[1x1 Odometry]
[1x1 Odometry]
[1x1 Odometry]
ans =
ROS Odometry message with properties:
MessageType: 'nav_msgs/Odometry'
Header: [1x1 Header]
ChildFrameId: 'base_footprint'
Pose: [1x1 PoseWithCovariance]
Twist: [1x1 TwistWithCovariance]
单元阵列中的每个消息都是标准的MATLAB ROS消息对象,有关消息的更多信息,查看基本ROS消息的使用的例子。
按时间序列提取消息数据
用户有时对完整的消息不感兴趣,仅对所有选中的消息中共有的指定的属性感兴趣。在这种情况下,使用时间序列的方式恢复消息数据将会是很有帮助的。时间序列是根据时间采样数据向量,代表随时间演变的一个或多个动态特性。有关MATLAB时间序列支持的更多消息,请参阅Time Series文档。
对于“rosbag”文件中的ROS消息,时间序列帮助表达某个消息元素随时间的变化过程,用户可以通过“timeseries”函数提取该信息。这是一种节省存储空间的方式,因为并没有存储完整的消息数据。
ts = timeseries(bagselect3, 'Pose.Pose.Position.X', 'Twist.Twist.Angular.Z')
timeseries
Timeseries contains duplicate times.
Common Properties:
Name: '/odom Properties'
Time: [101x1 double]
TimeInfo: tsdata.timemetadata
Data: [101x2 double]
DataInfo: tsdata.datametadata
返回值是一个“timeseries”对象,可用于进一步的分析和处理。注意,这种提取数据的方法,仅当当前选择包含单个的话题且只有一种消息类型。
访问“Data”属性可以查看消息序列中包含的数据:
ts.Data
ans =
0.0003 0.0003
0.0003 0.0003
0.0003 -0.0006
0.0003 -0.0006
0.0003 -0.0010
0.0003 -0.0010
0.0003 -0.0003
0.0003 -0.0003
0.0003 -0.0003
0.0003 -0.0003
0.0003 -0.0016
0.0003 -0.0016
0.0003 -0.0001
0.0003 -0.0001
0.0003 0.0003
0.0003 0.0003
0.0003 -0.0006
0.0003 -0.0006
0.0003 -0.0010
0.0003 -0.0010
0.0003 -0.0003
0.0003 -0.0003
0.0003 -0.0003
0.0003 -0.0003
0.0003 -0.0016
0.0003 -0.0016
0.0003 -0.0005
...
还有很多种方法处理时间序列数据,例如计算数据列的均值:
mean(ts)
ans =
1.0e-03 *
0.3213 -0.4616
或者可以画出时间序列数据:
figure
plot(ts, 'LineWidth', 3)
获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号