[ROS 系列学习教程] rosbag Python API

ROS 系列学习教程(总目录)

本文目录

  • 1. 构造函数与关闭文件
  • 2. 属性值
  • 3. 写bag文件内容
  • 4. 读bag文件内容
  • 5. 将bag文件缓存写入磁盘
  • 6. 重建 bag 文件索引
  • 7. 获取bag文件的压缩信息
  • 8. 获取bag文件的消息数量
  • 9. 获取bag文件记录的起止时间
  • 10. 获取话题信息与消息类型

rosbag 的 Python API 主要位于 rosbag 包的 Bag 类中,通过 import rosbag 导入。

Bag 类中的常用接口如下:

1. 构造函数与关闭文件

class Bag(
    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
)

class Compression:
    NONE = 'none'
    BZ2  = 'bz2'
    LZ4  = 'lz4'
    
close(self)

其中,

  • f:bag文件

  • mode:文件操作模式(r, w, a)

  • compression:文件压缩模式,见如上 Compression ,默认Compression.NONE

  • chunk_threshold:Bag 文件中每个块的最大字节数,默认 768 * 1024

  • allow_unindexed:是否允许打开未建立索引的bag文件。说明:在实际使用中,如果你只是想查看或播放bag文件中的所有消息,而不需要基于时间戳进行精确查询,那么你可以将 allow_unindexed 设置为 True。但是,如果你打算对bag文件进行基于时间的查询或其他高级操作,最好先使用 rosbag index 命令建立索引,并确保在打开bag文件时 allow_unindexedFalse(或者简单地省略该参数,因为它默认为 False)。

  • options:字典格式,用于统一设置 Bag 的参数,目前只支持 compressionchunk_threshold ,源码处理如下:

    •   if options is not None:
            if type(options) is not dict:
            	raise ValueError('options must be of type dict')                
            if 'compression' in options:
            	compression = options['compression']
            if 'chunk_threshold' in options:
            	chunk_threshold = options['chunk_threshold']
      
  • skip_index:打开bag文件时是否跳过文件的索引,这可以节省一些内存和加载时间,特别是在处理非常大的bag文件时。然而,这也意味着将无法使用基于索引的高级查询功能,比如按时间戳搜索特定的消息。

2. 属性值

# 只能获取
options # 同上options
filename # bag文件名
version # rosbag的版本号
mode # 文件操作模式(r, w, a)
size # Bag文件的大小(bytes)

# 可设置可获取
compression # 文件压缩模式
chunk_threshold # Bag 文件中每个块的最大字节数

3. 写bag文件内容

write(self, topic, msg, t=None, raw=False, connection_header=None)

其中,

  • topic:写入的topic名称
  • msg:写入的msg
  • t:时间戳,默认None以当前时间为时间戳
  • raw:是否已原始数据格式写入,通常不推荐这样做。
  • connection_header:连接头信息,通常不需要手动设置。通常用于内部处理,不是常规用法的一部分。

代码示例:

import rosbag
import rospkg
from std_msgs.msg import Int32, String


rospack = 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 = 42

    bag.write('/chatter', s)
    bag.write('/number', i)

finally:
    bag.close()

4. 读bag文件内容

read_messages(self, 
              topics=None, 
              start_time=None, 
              end_time=None, 
              connection_filter=None, 
              raw=False, 
              return_connection_header=False)

其中,

  • 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)格式返回

代码示例:

import rosbag
import rospkg

rospack = rospkg.RosPack()
package_path = rospack.get_path('rosbag_learning')
bags_path = package_path + "/bags"

bag = rosbag.Bag(bags_path+'/pytest.bag')

for topic, msg, t in bag.read_messages(topics=['/chatter', '/number']):
    print(f"Received message on topic {topic} at time {t}: {msg}")

bag.close()

结果如下:

在这里插入图片描述

5. 将bag文件缓存写入磁盘

flush(self)

当你使用 write() 写入数据到 bag 文件时,数据可能不会立即被写入磁盘,而是会先被缓存起来以提高性能。调用 flush() 方法可以强制将这些缓存的数据写入到磁盘中,以确保所有挂起的数据都被写入到 bag 文件中。

它没有参数,并且执行后没有返回值。

在以下情况下,可能需要调用 flush() 方法:

  • 确保数据持久化:当你想要确保所有已经写入 rosbag.Bag 对象的数据都已经持久化到磁盘上时,可以调用 flush()。这在你准备关闭 bag 文件或程序即将退出时特别有用,以确保不会有数据丢失。

  • 实时备份:如果你正在实时记录数据到 bag 文件,并且想要定期备份这些数据,你可以在备份之前调用 flush(),以确保备份时所有需要的数据都已经写入到 bag 文件中。

代码示例:

import rospy
import rosbag
import rospkg
from std_msgs.msg import String, Int32


rospy.init_node('bag_writer')  

rospack = rospkg.RosPack()
package_path = rospack.get_path('rosbag_learning')
bags_path = package_path + "/bags"

# 创建一个bag文件用于写入
with rosbag.Bag(bags_path + '/flush.bag', 'w') as bag:

    # 写入一条消息
    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()会被自动调用(如果需要的话)

查看bag文件信息如下:

在这里插入图片描述

6. 重建 bag 文件索引

reindex(self)

当使用 rosbag 记录或播放数据时,rosbag 会维护一个内部索引,以便能够高效地检索和访问数据。然而,有时索引可能会损坏或变得不一致,这时就需要使用 reindex 方法来重新构建索引。

reindex(self) 方法没有参数,它会对当前打开的 bag 文件执行索引重建操作。重建索引可能需要一些时间,具体取决于 bag 文件的大小和内容。

以下是可能需要使用 reindex 方法的一些场景:

  • 索引损坏:如果你怀疑 bag 文件的索引已经损坏或不一致,导致无法正常访问数据,你可以尝试使用 reindex 方法来修复它。

  • 添加新数据:如果你在 bag 文件关闭后向其中添加了新数据,但没有重新构建索引,那么这些新数据将不会被包含在旧的索引中。在这种情况下,你需要调用 reindex 方法来更新索引,以便能够访问这些新数据。

  • 优化性能:有时,即使索引没有损坏,重新构建索引也可能有助于提高访问数据的性能。特别是当 bag 文件非常大或包含大量数据时,重建索引可以帮助优化数据结构,提高检索速度。

代码示例:

import rosbag
import rospkg


rospack = rospkg.RosPack()
package_path = rospack.get_path('rosbag_learning')
bags_path = package_path + "/bags"

with rosbag.Bag(bags_path+'/pytest.bag', 'r') as bag:
    try:
        for topic, msg, t in bag.read_messages():
            print(f"Received message on topic {topic} at time {t}: {msg}")

    except Exception as e:
        print(f"An error occurred while reading the bag file: {e}")
        print("Reindexing the bag file...")
        bag.reindex()  # 尝试重新索引 bag 文件
        print("Reindexing completed.")

    # 现在可以正常使用 bag 文件中的数据了

7. 获取bag文件的压缩信息

get_compression_info(self)

这个方法返回一个tuple(str, int, int),其中包含了关于 bag 文件压缩的详细信息,每一位表示如下:

  • tuple[0]:压缩格式,例如 none(表示没有压缩)或 bz2(表示使用了 bzip2 压缩)。
  • tuple[1]:未压缩的数据大小(以字节为单位)
  • tuple[2]:压缩后的数据大小(以字节为单位)

代码示例:

import rosbag
import rospkg 


rospack = rospkg.RosPack()
package_path = rospack.get_path('rosbag_learning')
bags_path = package_path + "/bags"

# 打开一个存在的 bag 文件
with rosbag.Bag(bags_path+'/pytest.bag', 'r') as bag:

    # 获取压缩信息
    compression_info = bag.get_compression_info()

    # 打印压缩信息
    if compression_info:
        print("Compression Type:", compression_info[0])
        print("UnCompressed Size:", compression_info[1])
        print("compressed Size:", compression_info[2])
    else:
        print("The bag file is not compressed.")

8. 获取bag文件的消息数量

get_message_count(self, topic_filters=None)

这个方法允许你指定一个或多个话题过滤器(topic_filters),以便只计算特定话题的消息数。该参数接收一个字符串或字符串列表,用于指定要计算消息数的话题。如果未提供或设置为 None,则计算 bag 文件中所有话题的消息数。

代码示例:

import rosbag
import rospkg 


rospack = rospkg.RosPack()
package_path = rospack.get_path('rosbag_learning')
bags_path = package_path + "/bags"

# 打开一个存在的 bag 文件
with rosbag.Bag(bags_path+'/pytest.bag', 'r') as bag:

    # 定义我们想要计算消息数的话题过滤器列表
    topic_filters = ['/chatter', '/number']

    # 获取指定话题的消息数量
    message_counts = bag.get_message_count(topic_filters=topic_filters)
      
    # 打印话题的消息数量
    print(f"Message Count: {message_counts}")

9. 获取bag文件记录的起止时间

get_start_time(self)
get_end_time(self)

get_start_time 函数的返回类型是 float,表示以秒为单位的时间戳,其中的小数部分,表示秒的分数。

代码示例:

import rosbag
import rospkg
from datetime import datetime


rospack = rospkg.RosPack()
package_path = rospack.get_path('rosbag_learning')
bags_path = package_path + "/bags"

# 打开一个存在的 bag 文件
with rosbag.Bag(bags_path+'/pytest.bag', 'r') as bag:

    # 获取 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"Bag file start time: {start_time_str}")
    print(f"Bag file end   time: {end_time_str}")

运行结果如下:

在这里插入图片描述

10. 获取话题信息与消息类型

get_type_and_topic_info(self, topic_filters=None)

其中,topic_filters 用于过滤指定的话题,如果没有提供,则分析所有话题。

函数返回值类型如下:

TypesAndTopicsTuple(dict(str, str), 
                    dict(str, TopicTuple(str, int, int, float)))

其中各值说明如下:

TypesAndTopicsTuple(
    		msg_types{key:type name, val: md5hash}, 
            topics{key: topic name, 
                   value: TopicTuple(msg_type: msg type (Ex. "std_msgs/String"),
                   message_count: the number of messages of the particular type,
                   connections: the number of connections,
                   frequency: the data frequency)})

其中,

  • msg_types:是一个字典,key为msg类型,value为msgMD5值。
  • topics:是一个字典,key为topic名称,value是一个元组,其中:
    • msg_type:该topic的消息类型
    • message_count:该topic的消息数量
    • connections:该topic的连接数量
    • frequency:该topic的数据频率

代码示例:

import rosbag
import rospkg
from datetime import datetime


rospack = rospkg.RosPack()
package_path = rospack.get_path('rosbag_learning')
bags_path = package_path + "/bags"

# 打开一个存在的 bag 文件
with rosbag.Bag(bags_path+'/pytest.bag', 'r') as bag:

    topic_filters = ['/chatter', '/number']
    msg_types, topics = bag.get_type_and_topic_info(topic_filters)
    print("Message Types:")
    for type_name, md5_hash in msg_types.items():
        print(f"  {type_name}: {md5_hash}")

    print("Topics:")
    for type_name, topic_info in topics.items():
        print("  Topic: {}, Type: {}, MessageCount: {}, Connections: {}, Frequency: {}".format(
            type_name, 
            topic_info.msg_type, 
            topic_info.message_count, 
            topic_info.connections,
            topic_info.frequency))

运行结果:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/463868.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Java探索之旅】运算符解密 位运算,移位运算

🎥 屿小夏 : 个人主页 🔥个人专栏 : Java入门到精通 🌄 莫道桑榆晚,为霞尚满天! 文章目录 📑前言一、位运算符1.1 按位与 &1.2 按位或 |1.3 按位取反 ~1.4 按位异或^ 二、移位运…

快速排序算法,简洁,易懂

目录 代码实现(java): 一、首元素作为基准值 图: ​编辑 基本思路: 代码: 代码补充说明: 二、中间元素作为基准值 代码: 参考学习文章: 今天我们不刷力扣了,…

Java Web项目—餐饮管理系统Day07-套餐管理(二)

文章目录 1. 套餐的分页查询2. 更新套餐![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/209298cf3b4349c5a2fed56a3d33350e.png)第一步, 依据套餐id查询到套餐的基本信息以及关联菜品信息.第2步, 将请求数据进行保存(更新). 3. 批量的停售启售 这部分开发剩下的部分…

CSS Module

CSS Module的作用:将CSS样式作用域限制在特定的组件范围内,以避免全局样式污染和命名冲突。 Vue中如何实现样式模块…

SVN修改已提交版本的注释

目录 一、需求分析 二、问题分析 三、解决办法 一、需求分析 ​开发过程中,在SVN提交文件后,发现注释写的不完整或不够明确,想再修改之前的注释文字​。 使用环境: SVN服务器操作系统:Ubuntu 20.04.6 LTS SVN版本&…

物理隔离条件下,如何安全高效地进行内外网文件导入导出?

内外网文件导入导出通常指的是在内部网络(内网)和外部网络(外网)之间传输文件的过程。这在企业环境中尤其常见,因为内部网络通常包含敏感数据,而外部网络(如互联网)则允许更广泛的访…

计算机网络实验——学习记录

1. tun/tap模块:为Linux系统提供网络虚拟功能,tun位于网络OSI模型的三层(网络层),tap位于网络的二层(数据链路层)。 1.1 验证是否包含tun/tap模块:modinfo tun; 1.2 验…

8:00面试,8:06就出来了,问的问题有点变态。。。

从小厂出来,没想到在另一家公司又寄了。 到这家公司开始上班,加班是每天必不可少的,看在钱给的比较多的份上,就不太计较了。没想到9月一纸通知,所有人不准加班,加班费不仅没有了,薪资还要降40%…

echarts散点图自定义tooltip,鼠标放上去展示多行数据

先放效果图 如图,就是鼠标悬停在散点上(这里的散点我替换成了图片,具体做法参考这篇文章:echarts散点图的散点用自定义图片替代-CSDN博客)时,可以展示多行数据。之前查找资料的时候,很多用字符串…

封装哈希表

本文旨在讲解哈希表的封装,我们以哈希桶的结构来进行封装unorderedmap/set。要想实现封装哈希表,我们首先得先将哈希表的结构给搭建出来,然后再根据哈希桶的结构进一步封装unorderedmap/set! 下面我们先来实现哈希桶的结构&#x…

12_Linux内核结构

Linux内核结构 1.内核的主要组成部分 Linux 内核主要的 5 个部分:进程调度、内存管理、虚拟文件系统、网络接口、进程通信。在系统移植的时候,它们是内核的基本元素,这 5 个部分之间的关系,如图所示: 进程调度&#…

V-JEPA模型,非LLM另外的选择,AGI的未来:迈向Yann LeCun先进机器智能(AMI)愿景的下一步

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

小怂爱水洼DFS

分析: 非常明显的搜索问题,当时我在写的时候遇到了两个问题,就一直没过。 1.忘记判断临界条件,x,t不能越界的问题; 2.最后有两个案例一直不能过,就是因为我用的int型的接受结果范围太小了&#…

前端学习从0到1第一天:初见html

阅读须知: 探索者安全团队技术文章仅供参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作,由于传播、利用本公众号所提供的技术和信息而造成的任何直接或者间接的后果及损失,均由使用者 本人负责,作者不为此承担任何责任,如…

【C++中日期类的实现】

一路,一路,一路从泥泞到风景............................................................................................... 目录 前言 一、【什么是日期类】 二、【代码实现】 1.【Date.h】部分: 2.【Date.cpp】部分:…

关于ffmpeg height not divisible by 2的错误

在我们线上视频生产过程中,我们用ffmpeg对视频做了resize,讲原有的分辨率resize到1280p,使用了参数 -vf "scale1280:-1",作用是将原始视频宽度缩放成1280,-1是指高度等比例缩放。 之前一直运行的好好的&…

储能技术发展

一、政策背景 “十三五”是我国储能产业化发展的起点。自“十四五”之后,各类储能支持政策更是以极快的速度不断更新完善。 2023年1月17日,工业和信息化部等六部门发布了《关于推动能源电子产业发展的指导意见》,其中明确提出要在2025年实现…

吴恩达prompt 笔记2:迭代提示开发(Iterative Prompt Develelopment)

1 前言 我们很难在初次尝试中就设计出最佳的提示,因此需要根据ChatGPT的反馈进行分析,分析输出具体在哪里不符合期望,然后不断思考和优化提示。如果有条件的话,最好是利用批量的样本来改善提示,这样可以对你的优化结…

代码随想录阅读笔记-哈希表【三数之和】

题目 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a b c 0 ?请你找出所有满足条件且不重复的三元组。 注意: 答案中不可以包含重复的三元组。 示例: 给定数…

Python之Web开发中级教程----搭建虚拟环境

Python之Web开发中级教程----搭建Web框架二 搭建虚拟环境 虚拟环境的作用 虚拟环境可以搭建独立的python运行环境, 使得单个项目的运行环境与其它项目互不影响. 搭建虚拟环境 (1)安装 sudo pip install virtualenv sudo pip install virtualenvwra…