Extracting raw data from ros topics
Recently, I needed to extract raw data that we had collected from the PR2 robot. It's easy to collect data from topics, using the rosbag tool. You can collect data from multiple topics in one bag at a time.
Here's an example command that collects data from the robot:
rosbag record -b 1024 "/joint_states" -e "(/.*)_scan$" "torso_lift_imu/data" "/base_odometry/odom" "/camera/rgb/image_rect_color" "/camera/depth_registered/image_rect" --duration=1m --split -O /removable/recordings/20130403_1218_navtest_data.bag
The rosbag then looks like this:
[ankur@localhost bag-test]$ rosbag info 20130403_1218_navtest_data_0.bag
path: 20130403_1218_navtest_data_0.bag
version: 2.0
duration: 58.8s
start: Apr 03 2013 15:40:18.91 (1364964018.91)
end: Apr 03 2013 15:41:17.68 (1364964077.68)
size: 3.3 GB
messages: 17035
compression: none [3295/3295 chunks]
types: nav_msgs/Odometry [cd5e73d190d741a2f92e81eda573aca7]
sensor_msgs/Image [060021388200f6f0f447d0fcd9c64743]
sensor_msgs/JointState [3066dcd76a6cfaef579bd0f34173e9fd]
sensor_msgs/LaserScan [90c7ef2dc6895d81024acba2ac42f369]
topics: /base_odometry/odom 5516 msgs : nav_msgs/Odometry
/base_scan 1176 msgs : sensor_msgs/LaserScan
/camera/depth_registered/image_rect 1640 msgs : sensor_msgs/Image
/camera/rgb/image_rect_color 1653 msgs : sensor_msgs/Image
/joint_states 5875 msgs : sensor_msgs/JointState
/tilt_scan 1175 msgs : sensor_msgs/LaserScan
[ankur@localhost bag-test]$
You can also filter out individual topics into individual bags with the tool:
[ankur@localhost bag-test]$ rosbag filter --help
Usage: rosbag filter [options] INBAG OUTBAG EXPRESSION
EXPRESSION can be any Python-legal expression.
The following variables are available:
* topic: name of topic
* m: message
* t: time of message (t.secs, t.nsecs)
Filter the contents of the bag.
Options:
-h, --help show this help message and exit
-p PRINT-EXPRESSION, --print=PRINT-EXPRESSION
Python expression to print for verbose debugging. Uses
same variables as filter-expression
[ankur@localhost bag-test]$
Various other tools are available to visualize the data. With groovy, you have rqt_bag
Since I needed the raw messages, I had to hack up a python script using the rosbag API.
#!/usr/bin/python
# Copyright 2010 Ankur Sinha
# Author: Ankur Sinha
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# File : extractRawInfo.py
#
import rosbag
import sys
import os
import pickle
# Global variable for input file name
def run():
"""
Main run method. Calls other helper methods to get work done
"""
if len(sys.argv) != 2:
sys.stderr.write('[ERROR] This script only takes input bag file as argument.n')
else:
inputFileName = sys.argv[1]
print "[OK] Found bag: %s" % inputFileName
bag = rosbag.Bag(inputFileName)
topicList = readBagTopicList(bag)
while True:
if len(topicList) == 0:
print "No topics in list. Exiting"
break
selection = menu(topicList)
if selection == -92:
print "[OK] Printing them all"
for topic in topicList:
extract_data(bag, topic, inputFileName)
break
elif selection == -45:
break
else:
topic = topicList[selection]
extract_data(bag, topic, inputFileName)
topicList.remove(topicList[selection])
bag.close()
def extract_data (bag, topic, inputFileName):
"""
Spew messages to a file
args:
topic -> topic to extract and print to txt file
"""
outputFileName = os.path.splitext(os.path.split(inputFileName)[1])[0] + topic.replace("/","-") + ".txt"
print "[OK] Printing %s" % topic
print "[OK] Output file will be called %s." % outputFileName
outputFh = open(outputFileName, "w")
for topic, msg, t in bag.read_messages(topics=topic):
pickle.dump(msg,outputFh)
outputFh.close()
print "[OK] DONE"
def menu (topicList):
"""
Print the user menu and take input
args:
topicList: tuple containing list of topics
returns:
selection: user selection as integer
"""
i = 0
for topic in topicList:
print '[{0}] {1}'.format(i, topic)
i = i+1
if len(topicList) > 1:
print '[{0}] Extract all'.format(len(topicList))
print '[{0}] Exit'.format(len(topicList) + 1)
else:
print '[{0}] Exit'.format(len(topicList))
while True:
print 'Enter a topic number to extract raw data from:'
selection = raw_input('>>>')
if int(selection) == len(topicList):
return -92 # print all
elif int(selection) == (len(topicList) +1):
return -45 # exit
elif (int(selection) < len(topicList)) and (int(selection) >= 0):
return int(selection)
else:
print "[ERROR] Invalid input"
def readBagTopicList(bag):
"""
Read and save the initial topic list from bag
"""
print "[OK] Reading topics in this bag. Can take a while.."
topicList = []
for topic, msg, t in bag.read_messages():
if topicList.count(topic) == 0:
topicList.append (topic)
print '{0} topics found:'.format(len(topicList))
return topicList
if __name__ == "__main__":
run()
I've hosted it on my github repository. It'll be easier to read/download it from there if you need to.
Comments