Home » ROS与Matlab入门教程 » ROS与Matlab语言入门教程-rosbag Logfiles的使用

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)

请输入图片描述

纠错,疑问,交流: 请进入讨论区点击加入Q群

获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号


标签: ros与matlab语言入门教程