Main Content

Work with rosbag Logfiles

This example enables you to load a rosbag, and learn how to select and retrieve the contained messages.

A rosbag or bag is a file format in ROS for storing message data. These bags are often created by subscribing to one or more ROS topics, and storing the received message data in an efficient file structure. MATLAB® can read these rosbag files and help with filtering and extracting message data. See ROS Log Files (rosbags) for more information about rosbag support in MATLAB.

Prerequisites: Work with Basic ROS Messages

Load a rosbag

Load an example file using the rosbag command.

bag = rosbag("ex_multiple_topics.bag")
bag = 
  BagSelection with properties:

           FilePath: 'C:\Users\csalzber\OneDrive - MathWorks\Documents\MATLAB\Examples\ros-ex71482057\ex_multiple_topics.bag'
          StartTime: 201.3400
            EndTime: 321.3400
        NumMessages: 36963
    AvailableTopics: [4×3 table]
    AvailableFrames: {0×1 cell}
        MessageList: [36963×4 table]

The object returned from the rosbag call is a BagSelection object, which is a representation of all the messages in the rosbag.

The object display shows details about how many messages are contained in the file (NumMessages) and the time when the first (StartTime) and the last (EndTime) message were recorded.

Evaluate the AvailableTopics property to see more information about the topics and message types that are recorded in the bag:

bag.AvailableTopics
ans=4×3 table
                           NumMessages         MessageType                                                                                                                                                                                                                                                                                                           MessageDefinition                                                                                                                                                                                                                                                                                                  
                           ___________    ______________________    ____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

    /clock                    12001       rosgraph_msgs/Clock       {0×0 char                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          }
    /gazebo/link_states       11999       gazebo_msgs/LinkStates    {'geometry_msgs/Pose[] Pose↵  geometry_msgs/Point Position↵    double X↵    double Y↵    double Z↵  geometry_msgs/Quaternion Orientation↵    double X↵    double Y↵    double Z↵    double W↵geometry_msgs/Twist[] Twist↵  geometry_msgs/Vector3 Linear↵    double X↵    double Y↵    double Z↵  geometry_msgs/Vector3 Angular↵    double X↵    double Y↵    double Z↵'                                                                                                                                                                                                                                }
    /odom                     11998       nav_msgs/Odometry         {'  uint32 Seq↵  Time Stamp↵  char FrameId↵char ChildFrameId↵geometry_msgs/PoseWithCovariance Pose↵  geometry_msgs/Pose Pose↵    geometry_msgs/Point Position↵      double X↵      double Y↵      double Z↵    geometry_msgs/Quaternion Orientation↵      double X↵      double Y↵      double Z↵      double W↵  double[36] Covariance↵geometry_msgs/TwistWithCovariance Twist↵  geometry_msgs/Twist Twist↵    geometry_msgs/Vector3 Linear↵      double X↵      double Y↵      double Z↵    geometry_msgs/Vector3 Angular↵      double X↵      double Y↵      double Z↵  double[36] Covariance↵'}
    /scan                       965       sensor_msgs/LaserScan     {'  uint32 Seq↵  Time Stamp↵  char FrameId↵single AngleMin↵single AngleMax↵single AngleIncrement↵single TimeIncrement↵single ScanTime↵single RangeMin↵single RangeMax↵single[] Ranges↵single[] Intensities↵'                                                                                                                                                                                                                                                                                                                                                                                               }

The AvailableTopics table contains the sorted list of topics that are included in the rosbag. The table stores the number of messages, the message type, and the message definition for the topic. For more information on the MATLAB table data type and what operations you can perform on it, see the documentation for Tables.

Initially the rosbag is only indexed by MATLAB and no actual message data is read.

You might want to filter and narrow the selection of messages as much as possible based on this index before any messages are loaded into MATLAB memory.

Select Messages

Before you retrieve any message data, you must select a set of messages based on criteria such as time stamp, topic name, and message type.

You can examine all the messages in the current selection:

bag.MessageList
ans=36963×4 table
     Time            Topic                MessageType          FileOffset
    ______    ___________________    ______________________    __________

    201.34    /gazebo/link_states    gazebo_msgs/LinkStates       9866   
    201.34    /odom                  nav_msgs/Odometry            7666   
    201.34    /clock                 rosgraph_msgs/Clock          4524   
    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    /gazebo/link_states    gazebo_msgs/LinkStates      12930   
    201.36    /odom                  nav_msgs/Odometry           14026   
    201.37    /odom                  nav_msgs/Odometry           14844   
    201.37    /gazebo/link_states    gazebo_msgs/LinkStates      15608   
    201.37    /clock                 rosgraph_msgs/Clock         14790   
    201.38    /clock                 rosgraph_msgs/Clock         16704   
    201.38    /gazebo/link_states    gazebo_msgs/LinkStates      16758   
    201.38    /odom                  nav_msgs/Odometry           17854   
    201.39    /gazebo/link_states    gazebo_msgs/LinkStates      18672   
      ⋮

The MessageList table contains one row for each message in the bag (there are over 30,000 rows for the bag in this example). The rows are sorted by time stamp in the first column, which represents the time (in seconds) that the message was recorded.

Since the list is very large, you can also display a selection of rows with the familiar row and column selection syntax:

bag.MessageList(500:505,:)
ans=6×4 table
    Time           Topic                MessageType          FileOffset
    ____    ___________________    ______________________    __________

    203     /clock                 rosgraph_msgs/Clock         339384  
    203     /gazebo/link_states    gazebo_msgs/LinkStates      331944  
    203     /gazebo/link_states    gazebo_msgs/LinkStates      333040  
    203     /gazebo/link_states    gazebo_msgs/LinkStates      334136  
    203     /gazebo/link_states    gazebo_msgs/LinkStates      335232  
    203     /odom                  nav_msgs/Odometry           336328  

Use the select function to narrow the selection of messages. The select function operates on the bag object.

You can filter the message list by time, topic name, message type, or any combination of the three.

To select all messages that were published on the /odom topic, use the following select command:

bagselect1 = select(bag,"Topic","/odom")
bagselect1 = 
  BagSelection with properties:

           FilePath: 'C:\Users\csalzber\OneDrive - MathWorks\Documents\MATLAB\Examples\ros-ex71482057\ex_multiple_topics.bag'
          StartTime: 201.3400
            EndTime: 321.3300
        NumMessages: 11998
    AvailableTopics: [1×3 table]
    AvailableFrames: {0×1 cell}
        MessageList: [11998×4 table]

Calls to the select function return another BagSelection object, which can be used to make further selections or retrieve message data. All selection objects are independent of each other, so you can clear them from the workspace once you are done.

You can make a different selection that combines two criteria. To get the list of messages that were recorded within the first 30 seconds of the rosbag and published on the /odom topic, enter the following command:

start = bag.StartTime
start = 201.3400
bagselect2 = select(bag,"Time",[start start + 30],"Topic","/odom")
bagselect2 = 
  BagSelection with properties:

           FilePath: 'C:\Users\csalzber\OneDrive - MathWorks\Documents\MATLAB\Examples\ros-ex71482057\ex_multiple_topics.bag'
          StartTime: 201.3400
            EndTime: 231.3200
        NumMessages: 2997
    AvailableTopics: [1×3 table]
    AvailableFrames: {0×1 cell}
        MessageList: [2997×4 table]

Use the last selection to narrow down the time window even further:

bagselect3 = select(bagselect2,"Time",[205 206])
bagselect3 = 
  BagSelection with properties:

           FilePath: 'C:\Users\csalzber\OneDrive - MathWorks\Documents\MATLAB\Examples\ros-ex71482057\ex_multiple_topics.bag'
          StartTime: 205.0200
            EndTime: 205.9900
        NumMessages: 101
    AvailableTopics: [1×3 table]
    AvailableFrames: {0×1 cell}
        MessageList: [101×4 table]

The selection in this last step operated on the existing bagselect2 selection and returned a new bagselect3 object.

If you want to save a set of selection options, store the selection elements in a cell array and then re-use it later as an input to the select function:

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: 'C:\Users\csalzber\OneDrive - MathWorks\Documents\MATLAB\Examples\ros-ex71482057\ex_multiple_topics.bag'
          StartTime: 201.3400
            EndTime: 207.3300
        NumMessages: 209
    AvailableTopics: [2×3 table]
    AvailableFrames: {0×1 cell}
        MessageList: [209×4 table]

Read Selected Message Data

After you narrow your message selection, you might want to read the actual message data into MATLAB. Depending on the size of your selection, this can take a long time and consume a lot of your computer's memory. To improve time efficiency, read the messages from the rosbag in structure format.

To retrieve the messages in you selection as a cell array, use the readMessages function:

msgs = readMessages(bagselect3,"DataFormat","struct");
size(msgs)
ans = 1×2

   101     1

The resulting cell array contains as many elements as indicated in the NumMessages property of the selection object.

In reading message data, you can also be more selective and only retrieve messages at specific indices. Here is an example of retrieving 4 messages:

msgs = readMessages(bagselect3,[1 2 3 7],"DataFormat","struct")
msgs=4×1 cell array
    {1×1 struct}
    {1×1 struct}
    {1×1 struct}
    {1×1 struct}

msgs{2}
ans = struct with fields:
     MessageType: 'nav_msgs/Odometry'
          Header: [1×1 struct]
    ChildFrameId: 'base_footprint'
            Pose: [1×1 struct]
           Twist: [1×1 struct]

Each message in the cell array is a standard MATLAB ROS message structure. For more information on messages, see the Work with Basic ROS Messages example.

Extract Message Data as Time Series

Sometimes you are not interested in the complete messages, but only in specific properties that are common to all the messages in a selection. In this case, it is helpful to retrieve the message data as a time series instead. A time series is a data vector that is sampled over time and represents the time evolution of one or more dynamic properties. For more information on the MATLAB time series support, see the documentation for Time Series.

In the case of ROS messages within a rosbag, a time series can help to express the change in particular message elements through time. You can extract this information through the timeseries function. This is memory-efficient, since the complete messages do not have to be stored in memory.

Use the same selection, but use the timeseries function to only extract the properties for x-position and z-axis angular velocity:

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: [1x1 tsdata.timemetadata]
            Data: [101x2 double]
        DataInfo: [1x1 tsdata.datametadata]

  More properties, Methods

The return of this call is a timeseries object that can be used for further analysis or processing.

Note that this method of extracting data is only supported if the current selection contains a single topic with a single message type.

To see the data contained within the time series, access the Data property:

ts.Data
ans = 101×2

    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
      ⋮

There are many other possible ways to work with the time series data. Calculate the mean of the data columns:

mean(ts)
ans = 1×2
10-3 ×

    0.3213   -0.4616

You can also plot the data of the time series:

figure
plot(ts,"LineWidth",3)