找回密码
 会员注册
查看: 32|回复: 0

ROS系列学习教程]rosbagPythonAPI

[复制链接]

2万

主题

0

回帖

6万

积分

超级版主

积分
69864
发表于 2024-9-10 09:24:44 | 显示全部楼层 |阅读模式
ROS系列学习教程(总目录)本文目录1.构造函数与关闭文件2.属性值3.写bag文件内容4.读bag文件内容5.将bag文件缓存写入磁盘6.重建bag文件索引7.获取bag文件的压缩信息8.获取bag文件的消息数量9.获取bag文件记录的起止时间10.获取话题信息与消息类型rosbag的PythonAPI主要位于rosbag包的Bag类中,通过importrosbag导入。Bag类中的常用接口如下:1.构造函数与关闭文件classBag(f:Any,mode:str='r',compression:str=Compression.NONE,chunk_threshold:int=768*1024,allow_unindexed:bool=False,options:Any|None=None,skip_index:bool=False)classCompression:NONE='none'BZ2='bz2'LZ4='lz4'close(self)12345678910111213141516其中,f:bag文件mode:文件操作模式(r,w,a)compression:文件压缩模式,见如上Compression,默认Compression.NONEchunk_threshold:Bag文件中每个块的最大字节数,默认768*1024allow_unindexed:是否允许打开未建立索引的bag文件。说明:在实际使用中,如果你只是想查看或播放bag文件中的所有消息,而不需要基于时间戳进行精确查询,那么你可以将allow_unindexed设置为True。但是,如果你打算对bag文件进行基于时间的查询或其他高级操作,最好先使用rosbagindex命令建立索引,并确保在打开bag文件时allow_unindexed为False(或者简单地省略该参数,因为它默认为False)。options:字典格式,用于统一设置Bag的参数,目前只支持compression和chunk_threshold,源码处理如下:ifoptionsisnotNone:iftype(options)isnotdict: raiseValueError('optionsmustbeoftypedict')if'compression'inoptions: compression=options['compression']if'chunk_threshold'inoptions: chunk_threshold=options['chunk_threshold']1234567skip_index:打开bag文件时是否跳过文件的索引,这可以节省一些内存和加载时间,特别是在处理非常大的bag文件时。然而,这也意味着将无法使用基于索引的高级查询功能,比如按时间戳搜索特定的消息。2.属性值#只能获取options#同上optionsfilename#bag文件名version#rosbag的版本号mode#文件操作模式(r,w,a)size#Bag文件的大小(bytes)#可设置可获取compression#文件压缩模式chunk_threshold#Bag文件中每个块的最大字节数123456789103.写bag文件内容write(self,topic,msg,t=None,raw=False,connection_header=None)1其中,topic:写入的topic名称msg:写入的msgt:时间戳,默认None以当前时间为时间戳raw:是否已原始数据格式写入,通常不推荐这样做。connection_header:连接头信息,通常不需要手动设置。通常用于内部处理,不是常规用法的一部分。代码示例:importrosbagimportrospkgfromstd_msgs.msgimportInt32,Stringrospack=rospkg.RosPack()package_path=rospack.get_path('rosbag_learning')bags_path=package_path+"/bags"bag=rosbag.Bag(bags_path+'/pytest.bag','w')try:s=String()s.string='hello'i=Int32()i.int=42bag.write('/chatter',s)bag.write('/number',i)finally:bag.close()12345678910111213141516171819202122234.读bag文件内容read_messages(self,topics=None,start_time=None,end_time=None,connection_filter=None,raw=False,return_connection_header=False)1234567其中,topics:指定读取的topic,可以是一个topic列表,如果不指定,默认读取全部topic(可选)start_time:通过时间戳过滤消息(消息的最早时间戳,rospy.Time对象)(可选)end_time:通过时间戳过滤消息(消息的最晚时间戳,rospy.Time对象)(可选)connection_filter:一个函数,用于过滤连接。它应该接受一个连接对象并返回一个布尔值,以决定是否保留该连接的消息。如果为None,则不过滤连接。raw:一个布尔值,指定是否以原始字节形式返回消息。如果为True,则返回原始字节数据;如果为False(默认值),则返回解析后的ROS消息对象。return_connection_header:一个布尔值,如果为True,则返回的每条消息都会是一个元组,其中第二个元素是连接头信息。如果为False(默认值),则只返回消息本身。返回值:以(topic,message,timestamp)格式返回代码示例:importrosbagimportrospkgrospack=rospkg.RosPack()package_path=rospack.get_path('rosbag_learning')bags_path=package_path+"/bags"bag=rosbag.Bag(bags_path+'/pytest.bag')fortopic,msg,tinbag.read_messages(topics=['/chatter','/number']):print(f"Receivedmessageontopic{topic}attime{t}:{msg}")bag.close()12345678910111213结果如下:5.将bag文件缓存写入磁盘flush(self)1当你使用write()写入数据到bag文件时,数据可能不会立即被写入磁盘,而是会先被缓存起来以提高性能。调用flush()方法可以强制将这些缓存的数据写入到磁盘中,以确保所有挂起的数据都被写入到bag文件中。它没有参数,并且执行后没有返回值。在以下情况下,可能需要调用flush()方法:确保数据持久化:当你想要确保所有已经写入rosbag.Bag对象的数据都已经持久化到磁盘上时,可以调用flush()。这在你准备关闭bag文件或程序即将退出时特别有用,以确保不会有数据丢失。实时备份:如果你正在实时记录数据到bag文件,并且想要定期备份这些数据,你可以在备份之前调用flush(),以确保备份时所有需要的数据都已经写入到bag文件中。代码示例:importrospyimportrosbagimportrospkgfromstd_msgs.msgimportString,Int32rospy.init_node('bag_writer')rospack=rospkg.RosPack()package_path=rospack.get_path('rosbag_learning')bags_path=package_path+"/bags"#创建一个bag文件用于写入withrosbag.Bag(bags_path+'/flush.bag','w')asbag:#写入一条消息msg=String(data='Hello,ROSbag!')bag.write('/chatter',msg,rospy.Time.now())#在写入更多消息之前调用flush()bag.flush()#这里可以继续写入更多消息msg=Int32(data=25)bag.write('/number',msg,rospy.Time.now())#在退出with块之前,flush()会被自动调用(如果需要的话)123456789101112131415161718192021222324252627查看bag文件信息如下:6.重建bag文件索引reindex(self)1当使用rosbag记录或播放数据时,rosbag会维护一个内部索引,以便能够高效地检索和访问数据。然而,有时索引可能会损坏或变得不一致,这时就需要使用reindex方法来重新构建索引。reindex(self)方法没有参数,它会对当前打开的bag文件执行索引重建操作。重建索引可能需要一些时间,具体取决于bag文件的大小和内容。以下是可能需要使用reindex方法的一些场景:索引损坏:如果你怀疑bag文件的索引已经损坏或不一致,导致无法正常访问数据,你可以尝试使用reindex方法来修复它。添加新数据:如果你在bag文件关闭后向其中添加了新数据,但没有重新构建索引,那么这些新数据将不会被包含在旧的索引中。在这种情况下,你需要调用reindex方法来更新索引,以便能够访问这些新数据。优化性能:有时,即使索引没有损坏,重新构建索引也可能有助于提高访问数据的性能。特别是当bag文件非常大或包含大量数据时,重建索引可以帮助优化数据结构,提高检索速度。代码示例:importrosbagimportrospkgrospack=rospkg.RosPack()package_path=rospack.get_path('rosbag_learning')bags_path=package_path+"/bags"withrosbag.Bag(bags_path+'/pytest.bag','r')asbag:try:fortopic,msg,tinbag.read_messages():print(f"Receivedmessageontopic{topic}attime{t}:{msg}")exceptExceptionase:print(f"Anerroroccurredwhilereadingthebagfile:{e}")print("Reindexingthebagfile...")bag.reindex()#尝试重新索引bag文件print("Reindexingcompleted.")#现在可以正常使用bag文件中的数据了12345678910111213141516171819207.获取bag文件的压缩信息get_compression_info(self)1这个方法返回一个tuple(str,int,int),其中包含了关于bag文件压缩的详细信息,每一位表示如下:tuple[0]:压缩格式,例如none(表示没有压缩)或bz2(表示使用了bzip2压缩)。tuple[1]:未压缩的数据大小(以字节为单位)tuple[2]:压缩后的数据大小(以字节为单位)代码示例:importrosbagimportrospkgrospack=rospkg.RosPack()package_path=rospack.get_path('rosbag_learning')bags_path=package_path+"/bags"#打开一个存在的bag文件withrosbag.Bag(bags_path+'/pytest.bag','r')asbag:#获取压缩信息compression_info=bag.get_compression_info()#打印压缩信息ifcompression_info:print("CompressionType:",compression_info[0])print("UnCompressedSize:",compression_info[1])print("compressedSize:",compression_info[2])else:print("Thebagfileisnotcompressed.")1234567891011121314151617181920218.获取bag文件的消息数量get_message_count(self,topic_filters=None)1这个方法允许你指定一个或多个话题过滤器(topic_filters),以便只计算特定话题的消息数。该参数接收一个字符串或字符串列表,用于指定要计算消息数的话题。如果未提供或设置为None,则计算bag文件中所有话题的消息数。代码示例:importrosbagimportrospkgrospack=rospkg.RosPack()package_path=rospack.get_path('rosbag_learning')bags_path=package_path+"/bags"#打开一个存在的bag文件withrosbag.Bag(bags_path+'/pytest.bag','r')asbag:#定义我们想要计算消息数的话题过滤器列表topic_filters=['/chatter','/number']#获取指定话题的消息数量message_counts=bag.get_message_count(topic_filters=topic_filters)#打印话题的消息数量print(f"MessageCount:{message_counts}")123456789101112131415161718199.获取bag文件记录的起止时间get_start_time(self)get_end_time(self)12get_start_time函数的返回类型是float,表示以秒为单位的时间戳,其中的小数部分,表示秒的分数。代码示例:importrosbagimportrospkgfromdatetimeimportdatetimerospack=rospkg.RosPack()package_path=rospack.get_path('rosbag_learning')bags_path=package_path+"/bags"#打开一个存在的bag文件withrosbag.Bag(bags_path+'/pytest.bag','r')asbag:#获取bag文件的开始结束时间start_time=bag.get_start_time()end_time=bag.get_end_time()#将时间转换为更易读的字符串格式start_time_str=datetime.fromtimestamp(start_time)end_time_str=datetime.fromtimestamp(end_time)#打印开始结束时间print(f"Bagfilestarttime:{start_time_str}")print(f"Bagfileendtime:{end_time_str}")1234567891011121314151617181920212223运行结果如下:10.获取话题信息与消息类型get_type_and_topic_info(self,topic_filters=None)1其中,topic_filters用于过滤指定的话题,如果没有提供,则分析所有话题。函数返回值类型如下:TypesAndTopicsTuple(dict(str,str),dict(str,TopicTuple(str,int,int,float)))12其中各值说明如下:TypesAndTopicsTuple( msg_types{key:typename,val:md5hash},topics{key:topicname,value:TopicTuple(msg_type:msgtype(Ex."std_msgs/String"),message_count:thenumberofmessagesoftheparticulartype,connections:thenumberofconnections,frequency:thedatafrequency)})1234567其中,msg_types:是一个字典,key为msg类型,value为msgMD5值。topics:是一个字典,key为topic名称,value是一个元组,其中:msg_type:该topic的消息类型message_count:该topic的消息数量connections:该topic的连接数量frequency:该topic的数据频率代码示例:importrosbagimportrospkgfromdatetimeimportdatetimerospack=rospkg.RosPack()package_path=rospack.get_path('rosbag_learning')bags_path=package_path+"/bags"#打开一个存在的bag文件withrosbag.Bag(bags_path+'/pytest.bag','r')asbag:topic_filters=['/chatter','/number']msg_types,topics=bag.get_type_and_topic_info(topic_filters)print("MessageTypes:")fortype_name,md5_hashinmsg_types.items():print(f"{type_name}:{md5_hash}")print("Topics:")fortype_name,topic_infointopics.items():print("Topic:{},Type:{},MessageCount:{},Connections:{},Frequency:{}".format(type_name,topic_info.msg_type,topic_info.message_count,topic_info.connections,topic_info.frequency))1234567891011121314151617181920212223242526运行结果:
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-7 05:53 , Processed in 0.446646 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表