Skip to content

Issue: Rosbags recorded by OrbbecViewer cannot be parsed using ROS1 rosbag Python API "rosbag.read_messages" #195

@Johnson3176

Description

@Johnson3176

Describe the bug
Hi, I encountered a problem when trying to process rosbag files recorded by OrbbecViewer.

After recording a .bag file using OrbbecViewer, I attempted to parse it in a ROS1 environment using the Python rosbag library (rosbag.Bag.read_messages). However, the following error occurs:

Image

It seems that when parsing the /cam0/color_raw topic, the bag file generated by OrbbecViewer contains an abnormal message type [uint64_t] that is not part of the ROS1 sensor_msgs package, causing the parser to fail.

Reproduction Steps
1.Use OrbbecViewer 1.8.3 (Windows version) to connect to an Orbbec Gemini device and record a rosbag.
Image

2.Copy the recorded .bag file to a Linux machine (Ubuntu 20.04, ROS1 Noetic, 6-core CPU, 16GB RAM).

3.Parse the bag on Linux using the ROS1 rosbag Python API with the following script:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import cv2
import numpy as np
import rosbag
import rospy
from sensor_msgs.msg import CompressedImage
from pathlib import Path

# -------------------------- 手动设置 ROS 环境变量(关键修复)--------------------------
# 替换为你的 ROS 版本(如 noetic/melodic)和用户名
ROS_VERSION = "noetic"
USER_NAME = "rm"  # 例如 "ubuntu"

# 强制设置 ROS_PACKAGE_PATH(系统 ROS 路径 + 工作空间路径)
os.environ["ROS_PACKAGE_PATH"] = f"/home/{USER_NAME}/catkin_ws/src:/opt/ros/{ROS_VERSION}/share"
# 强制设置 PYTHONPATH(确保 ROS Python 库能被找到)
os.environ["PYTHONPATH"] = f"/opt/ros/{ROS_VERSION}/lib/python3/dist-packages:/home/{USER_NAME}/project/catkin_ws/devel/lib/python3/dist-packages:$PYTHONPATH"



def main():
    # 初始化 ROS 节点(必须在最前面)
    rospy.init_node('bag2mp4_node', anonymous=True)
    rospy.loginfo("=== Bag to MP4 ROS Node Started ===")

    # -------------------------- 从 ROS 参数读取配置(支持.launch文件配置)--------------------------
    BAG_FOLDER = rospy.get_param('~bag_folder', "rosbag")  # 输入文件夹(默认rosbag)
    OUTPUT_FOLDER = rospy.get_param('~output_folder', "output")  # 输出文件夹(默认output)
    TOPIC = rospy.get_param('~topic', "/cam0/color_raw")  # 目标话题(默认/cam0/color_raw)
    FPS = rospy.get_param('~fps', 30)  # 输出帧率(默认30)
    VIDEO_CODEC = rospy.get_param('~video_codec', "mp4v")  # 视频编码(默认mp4v)
    # ------------------------------------------------------------------------------------------

    # 打印配置信息
    rospy.loginfo(f"配置参数:")
    rospy.loginfo(f"  输入文件夹:{os.path.abspath(BAG_FOLDER)}")
    rospy.loginfo(f"  输出文件夹:{os.path.abspath(OUTPUT_FOLDER)}")
    rospy.loginfo(f"  目标话题:{TOPIC}")
    rospy.loginfo(f"  输出帧率:{FPS}fps")
    rospy.loginfo(f"  视频编码:{VIDEO_CODEC}")

    # 创建输出文件夹
    Path(OUTPUT_FOLDER).mkdir(parents=True, exist_ok=True)
    rospy.loginfo(f"输出文件夹已准备:{os.path.abspath(OUTPUT_FOLDER)}")

    # 遍历所有.bag文件
    bag_files = []
    for root, dirs, files in os.walk(BAG_FOLDER):
        for file in files:
            if file.endswith(".bag"):
                bag_path = os.path.abspath(os.path.join(root, file))
                bag_files.append(bag_path)
    
    if not bag_files:
        rospy.logerr(f"在 {BAG_FOLDER} 中未找到任何.bag文件!")
        return
    rospy.loginfo(f"找到 {len(bag_files)} 个bag文件:{[os.path.basename(f) for f in bag_files]}")

    # 逐个处理bag文件
    for bag_path in bag_files:
        bag_filename = os.path.basename(bag_path)
        mp4_filename = os.path.splitext(bag_filename)[0] + ".mp4"
        mp4_save_path = os.path.join(OUTPUT_FOLDER, mp4_filename)

        # 打开bag文件
        try:
            bag = rosbag.Bag(bag_path, "r")
        except Exception as e:
            rospy.logerr(f"打开bag文件失败 {bag_filename}:{str(e)}")
            continue
        # 统计话题消息数
        msg_count = bag.get_message_count(topic_filters=[TOPIC])
        if msg_count == 0:
            rospy.logwarn(f"{bag_filename} 中未找到话题 {TOPIC},跳过")
            bag.close()
            continue
        rospy.loginfo(f"\n处理 {bag_filename}:共 {msg_count} 帧图像")

        video_writer = None
        frame_idx = 0
        print(f'bag:{bag}')
        try:
            for topic, msg, t in bag.read_messages(topics=['/cam0/color_raw']):
                # 解码CompressedImage
                try:
                    np_arr = np.frombuffer(msg.data, np.uint8)
                    frame = cv2.imdecode(np_arr, cv2.IMREAD_COLOR)
                    if frame is None:
                        rospy.logwarn(f"{bag_filename}:第 {frame_idx} 帧解码失败,跳过")
                        frame_idx += 1
                        continue
                except Exception as e:
                    rospy.logwarn(f"{bag_filename}:第 {frame_idx} 帧解析失败:{str(e)},跳过")
                    frame_idx += 1
                    continue
                # 初始化视频写入器
                if video_writer is None:
                    height, width = frame.shape[:2]
                    fourcc = cv2.VideoWriter_fourcc(*VIDEO_CODEC)
                    video_writer = cv2.VideoWriter(mp4_save_path, fourcc, FPS, (width, height))
                    rospy.loginfo(f"视频参数:{width}x{height} @ {FPS}fps,编码 {VIDEO_CODEC}")
                # 写入帧
                video_writer.write(frame)
                frame_idx += 1
                # 打印进度
                if frame_idx % 100 == 0 or frame_idx == msg_count:
                    progress = (frame_idx / msg_count) * 100
                    rospy.loginfo(f"  进度:{frame_idx}/{msg_count} 帧 ({progress:.1f}%)")

        except Exception as e:
            rospy.logerr(f"处理 {bag_filename} 时出错:{str(e)}")
        finally:
            if video_writer is not None:
                video_writer.release()
            bag.close()

        # 验证输出文件
        if os.path.exists(mp4_save_path) and os.path.getsize(mp4_save_path) > 0:
            rospy.loginfo(f"✅ 成功保存 MP4:{mp4_save_path}")
        else:
            rospy.logerr(f"❌ {mp4_save_path} 生成失败或文件为空")

    rospy.loginfo("\n🎉 所有bag文件处理完成!")

if __name__ == "__main__":
    try:
        main()
    except rospy.ROSInterruptException:
        rospy.loginfo("节点被中断,退出程序")
    except Exception as e:
        rospy.logerr(f"程序异常终止:{str(e)}")

Expected behavior

Image

Additional context

From the error message, it appears that two problems occur simultaneously:

  1. The message type uint64_t cannot be located
  2. And the sensor_msgs package is reported as “unknown package [sensor_msgs] on search path [{}]” by the python rosbag parser

However, in my ROS1 Noetic environment:

  • Running rosmsg package sensor_msgs correctly lists the sensor_msgs package and all its message definitions.
  • The system also correctly recognizes that UInt64 belongs to std_msgs.

This leads to a contradiction:
ROS1 standard message definitions do not include any message type named uint64_t (the valid type is UInt64 under std_msgs). Therefore, it seems that the rosbag recorded by OrbbecViewer may contain non-standard or malformed message definitions, specifically a field typed as uint64_t, which does not exist in the ROS1 message specification.

I would like to understand:

  • Why does the rosbag parser report that sensor_msgs cannot be located when reading /cam0/color_raw?
  • Why does the bag recorded by OrbbecViewer include a message field with type uint64_t, which is not a valid ROS1 message type?

This abnormal message type seems to prevent ROS1 rosbag from loading standard message packages during parsing, causing the read operation to fail.

Any clarification on how OrbbecViewer generates message definitions inside the rosbag—and whether this is intended or a bug—would be very helpful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions