如何将ROS bag记录的数据转换为csv文件

如何将ROS bag记录的数据转换为csv文件

今天记录一下,如何利用Python将rosbag 的数据转换为csv文件,省的以后再找~

01 必要性

有的时候,可能是为了log,可能是画图,可能是想上天,总会有一种冲动想要将rosbag里面的数据换成csv。

02 基于python将rosbag的数据转换为csv

需要准备:python, 需要转换的csv

需要的python library : rosbag, sys, csv, time, string, os, shutil (这些库我并没有特别的去装,感觉在装ROS的时候,应该是默认都装了进去)

虽然感觉python的版本没啥关系,我用了python2。

作者是McGill大学的Nick Speal。是一个软件打通关的软件工程师。

下面是原文件。使用方法也比较简单。

虽然,看下面代码也可以看出来,先简单介绍一下。python文件有两种输入方式。一种是通过

python bag_to_csv.py xxxxx.bag

另一种是

python bag_to_csv.py xxxx.bag xxxx2.bag xxxx3.bag

区别就是,第一个是只转换一个.bag文件,第二个是转换多个.bag文件。

文件本身没啥好改的,唯一我认为需要修改的就是得将最下面69行左右的

filename = folder + '/' + string.replace(topicName, '/', '_slash_') + '.csv'

这部分按照自身需要改下。特别是各种“-slash-”真的不太好看。建议“-slash-”直接改成'-', 看着会舒服很多。

这个文件如有需要,直接复制,粘贴到自身电脑上,然后更改下使用权限

sudo chmod u+x bag2csv.py

后,通过

python csv2bag.py xxx.bag

命令,开始csv文件夹生成。

#!/usr/bin/python
'''
This script saves each topic in a bagfile as a csv.

Accepts a filename as an optional argument. Operates on all bagfiles in current directory if no argument provided

Written by Nick Speal in May 2013 at McGill University's Aerospace Mechatronics Laboratory
www.speal.ca

Supervised by Professor Inna Sharf, Professor Meyer Nahon 

'''

import rosbag, sys, csv
import time
import string
import os #for file management make directory
import shutil #for file management, copy file

#verify correct input arguments: 1 or 2
if (len(sys.argv) > 2):
	print "invalid number of arguments:   " + str(len(sys.argv))
	print "should be 2: 'bag2csv.py' and 'bagName'"
	print "or just 1  : 'bag2csv.py'"
	sys.exit(1)
elif (len(sys.argv) == 2):
	listOfBagFiles = [sys.argv[1]]
	numberOfFiles = "1"
	print "reading only 1 bagfile: " + str(listOfBagFiles[0])
elif (len(sys.argv) == 1):
	listOfBagFiles = [f for f in os.listdir(".") if f[-4:] == ".bag"]	#get list of only bag files in current dir.
	numberOfFiles = str(len(listOfBagFiles))
	print "reading all " + numberOfFiles + " bagfiles in current directory: \n"
	for f in listOfBagFiles:
		print f
	print "\n press ctrl+c in the next 10 seconds to cancel \n"
	time.sleep(10)
else:
	print "bad argument(s): " + str(sys.argv)	#shouldnt really come up
	sys.exit(1)

count = 0
for bagFile in listOfBagFiles:
	count += 1
	print "reading file " + str(count) + " of  " + numberOfFiles + ": " + bagFile
	#access bag
	bag = rosbag.Bag(bagFile)
	bagContents = bag.read_messages()
	bagName = bag.filename


	#create a new directory
	folder = string.rstrip(bagName, ".bag")
	try:	#else already exists
		os.makedirs(folder)
	except:
		pass
	shutil.copyfile(bagName, folder + '/' + bagName)


	#get list of topics from the bag
	listOfTopics = []
	for topic, msg, t in bagContents:
		if topic not in listOfTopics:
			listOfTopics.append(topic)


	for topicName in listOfTopics:
		#Create a new CSV file for each topic
		filename = folder + '/' + string.replace(topicName, '/', '_slash_') + '.csv'
		with open(filename, 'w+') as csvfile:
			filewriter = csv.writer(csvfile, delimiter = ',')
			firstIteration = True	#allows header row
			for subtopic, msg, t in bag.read_messages(topicName):	# for each instant in time that has data for topicName
				#parse data from this instant, which is of the form of multiple lines of "Name: value\n"
				#	- put it in the form of a list of 2-element lists
				msgString = str(msg)
				msgList = string.split(msgString, '\n')
				instantaneousListOfData = []
				for nameValuePair in msgList:
					splitPair = string.split(nameValuePair, ':')
					for i in range(len(splitPair)):	#should be 0 to 1
						splitPair[i] = string.strip(splitPair[i])
					instantaneousListOfData.append(splitPair)
				#write the first row from the first element of each pair
				if firstIteration:	# header
					headers = ["rosbagTimestamp"]	#first column header
					for pair in instantaneousListOfData:
						headers.append(pair[0])
					filewriter.writerow(headers)
					firstIteration = False
				# write the value from each pair to the file
				values = [str(t)]	#first column will have rosbag timestamp
				for pair in instantaneousListOfData:
					if len(pair) > 1:
						values.append(pair[1])
				filewriter.writerow(values)
	bag.close()
print "Done reading all " + numberOfFiles + " bag files."

最后生成后,会生成最左边的文件夹,文件夹名字是.bag文件,去除.bag后的名字。

进入文件夹之后,就可以看见很多.csv文件。每个topic对应一个文件。

比如/scan和 /odometery/filtered topic的csv文件内容就是下图所示这样。(打开的时候,要选择separator字符是comma。(下面打开的文件,感觉有些的列串了,应该是读取分割字符或者是其他参数没设定明白。。)

/scan topic
/odometery/filtered topic

03 总结

简单记录一下bag2csv.py的使用方法,防止以后忘和找。

191213 研究室


点个赞,关个注,天天学习有神助~

发布于 2019-12-13 14:38