ubuntu播放rosbag包(可鼠标交互)

发布于:2025-07-13 ⋅ 阅读:(23) ⋅ 点赞:(0)

1 前言

众所周知,ubuntu中播放bag包最主要的工具是rviz,然而rviz有一个无法忍受的缺陷就是不支持鼠标回滚,并且显示的时间的ros时间,不是世界时间,因此在遇到相关bug时不能与对应的世界时间对应。基于以上,解决方案如下:

2 依托工具

foxglove,这个工具可以实现bag包的播放,相关安装下载的可以网上搜索一下,相关资料很多。

3 相关修改

fox-glove是一个很好用的工具,但是对于ros1不是很友好,对于点云格式为pointcloud的消息不能显示,要想显示有两种方式,一是写一个foxglove的插件,二是将pointcloud转换为pointcloud2格式,写插件相对复杂,因此选用更方便的改写方式,python脚本如下:

#!/usr/bin/env python3
import rosbag
from sensor_msgs.msg import PointCloud, PointCloud2, PointField
import struct
import sys
import time

def convert_pointcloud_to_pointcloud2(pc_msg):
    """将 PointCloud 消息转换为 PointCloud2 格式"""
    # 创建 PointCloud2 消息
    pc2_msg = PointCloud2()
    
    # 复制头信息
    pc2_msg.header = pc_msg.header
    
    # 设置点云属性
    pc2_msg.height = 1  # 无序点云
    pc2_msg.width = len(pc_msg.points)  # 点的数量
    pc2_msg.is_dense = True  # 所有点都有效
    pc2_msg.is_bigendian = False  # 小端字节序
    
    # 设置字段(x, y, z)
    pc2_msg.fields = [
        PointField(name='x', offset=0, datatype=PointField.FLOAT32, count=1),
        PointField(name='y', offset=4, datatype=PointField.FLOAT32, count=1),
        PointField(name='z', offset=8, datatype=PointField.FLOAT32, count=1),
    ]
    
    # 计算每个点的大小
    pc2_msg.point_step = 16  # 4 bytes * 4 (x, y, z, 填充字段)
    pc2_msg.row_step = pc2_msg.point_step * pc2_msg.width
    
    # 构建点云数据缓冲区
    buffer = bytearray()
    for point in pc_msg.points:
        # 打包每个点的坐标 (x, y, z)
        buffer += struct.pack('fff', point.x, point.y, point.z)
        # 添加填充字段 (通常用于颜色或强度数据)
        buffer += struct.pack('f', 0.0)
    
    pc2_msg.data = bytes(buffer)
    return pc2_msg

def convert_bag(input_bag_path, output_bag_path):
    """转换整个 bag 文件"""
    print(f"开始转换: {input_bag_path} -> {output_bag_path}")
    start_time = time.time()
    
    # 跟踪转换进度
    pointcloud_topics = set()
    converted_messages = 0
    
    with rosbag.Bag(input_bag_path, 'r') as in_bag, \
         rosbag.Bag(output_bag_path, 'w') as out_bag:
        
        # 读取并转换消息
        total_messages = in_bag.get_message_count()
        processed_messages = 0
        
        for topic, msg, t in in_bag.read_messages():
            processed_messages += 1
            if processed_messages % 100 == 0:
                percent = (processed_messages / total_messages) * 100
                print(f"进度: {percent:.1f}% ({processed_messages}/{total_messages})")
            
            if msg._type == 'sensor_msgs/PointCloud':
                # 转换点云消息
                pc2_msg = convert_pointcloud_to_pointcloud2(msg)
                new_topic = f"{topic}_pc2"  # 使用新话题名称
                out_bag.write(new_topic, pc2_msg, t)
                pointcloud_topics.add(topic)
                converted_messages += 1
            else:
                # 其他类型消息直接复制
                out_bag.write(topic, msg, t)
    
    end_time = time.time()
    print(f"\n转换完成! 耗时: {end_time - start_time:.2f}秒")
    print(f"转换了 {converted_messages} 条 PointCloud 消息")
    print("包含 PointCloud 的话题:")
    for topic in pointcloud_topics:
        print(f"  - {topic} -> {topic}_pc2")

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("用法: python3 convert_pointcloud_to_pointcloud2.py 输入.bag 输出.bag")
        print("示例: python3 convert_pointcloud_to_pointcloud2.py new.bag converted.bag")
        sys.exit(1)
    
    input_bag = sys.argv[1]
    output_bag = sys.argv[2]
    
    try:
        convert_bag(input_bag, output_bag)
        print("\n请使用以下命令验证转换结果:")
        print(f"rosbag info {output_bag} | grep PointCloud")
        print(f"rosbag play {output_bag}")
    except Exception as e:
        print(f"转换出错: {e}")
        sys.exit(1)

转换完的bag包就可以使用fox-glove播放了,为了更方便的播放,写相关shell脚本如下:

#!/usr/bin/env bash
set -e

# 脚本入参:原始bag路径
BAG_PATH="$1"

# 判断是否传入参数
if [ -z "$BAG_PATH" ]; then
    echo "Usage: $0 <bag_path>"
    exit 1
fi

# 判断文件是否存在
if [ ! -f "$BAG_PATH" ]; then
    echo "Error: Bag file '$BAG_PATH' does not exist."
    exit 1
fi

# 提取不带后缀的文件名
BAG_DIR=$(dirname "$BAG_PATH")
BAG_BASE=$(basename "$BAG_PATH" .bag)

# 定义新的bag文件名
NEW_BAG_PATH="${BAG_DIR}/${BAG_BASE}_converted.bag"

echo "Starting conversion:"
echo "  Input bag: $BAG_PATH"
echo "  Output bag: $NEW_BAG_PATH"
#bagconvert是上述的py脚本使用pyinstaller打包成的可执行文件,相关资料也很多,实在不会的直接下载我打包好的
bagconvert "$BAG_PATH" "$NEW_BAG_PATH"
echo "Opening with foxglove-studio: $NEW_BAG_PATH"

rm -f "$BAG_PATH"
foxglove-studio $NEW_BAG_PATH

网站公告

今日签到

点亮在社区的每一天
去签到