[132GS MIPI双目相机][RDK X5][如何自行标定相机]

相机:132GS MIPI双目相机

平台:RDK X5

问题:请问如何获取原始图像并自行标定相机,然后在run_stereo的时候载入本地标定参数

132gs 模组双目深度问题
RDK X5 视频、扫描,建模,为什么显示满屏距离标识,没有物体识别呢?正常建模应该是怎么样的
RDK X5 视频、扫描,建模,为什么显示满屏距离标识,没有物体识别呢?正常建模应该是怎么样的
132gs 模组双目深度问题
RDK X5 视频、扫描,建模,为什么显示满屏距离标识,没有物体识别呢?正常建模应该是怎么样的
132gs 模组双目深度问题
RDK X5 视频、扫描,建模,为什么显示满屏距离标识,没有物体识别呢?正常建模应该是怎么样的
RDK X5 视频、扫描,建模,为什么显示满屏距离标识,没有物体识别呢?正常建模应该是怎么样的
RDK X5 视频、扫描,建模,为什么显示满屏距离标识,没有物体识别呢?正常建模应该是怎么样的
132gs 模组双目深度问题
132gs 模组双目深度问题
132gs 模组双目深度问题
132gs 模组双目深度问题
132gs 模组双目深度问题
132gs 模组双目深度问题
RDK X5 视频、扫描,建模,为什么显示满屏距离标识,没有物体识别呢?正常建模应该是怎么样的
132gs 模组双目深度问题
132gs 模组双目深度问题
132gs 模组双目深度问题
132gs 模组双目深度问题
132gs 模组双目深度问题
132gs 模组双目深度问题
132gs 模组双目深度问题
132gs 模组双目深度问题
132gs 模组双目深度问题
132gs 模组双目深度问题
132gs 模组双目深度问题
RDK GS130WI和SLAM算法
132gs 模组双目深度问题
GS130WI外参疑问
RDK X5 视频、扫描,建模,为什么显示满屏距离标识,没有物体识别呢?正常建模应该是怎么样的
RDK X5 视频、扫描,建模,为什么显示满屏距离标识,没有物体识别呢?正常建模应该是怎么样的
RDK X5 视频、扫描,建模,为什么显示满屏距离标识,没有物体识别呢?正常建模应该是怎么样的
RDK X5 视频、扫描,建模,为什么显示满屏距离标识,没有物体识别呢?正常建模应该是怎么样的
RDK X5 视频、扫描,建模,为什么显示满屏距离标识,没有物体识别呢?正常建模应该是怎么样的

可以尝试使用 ROS2 官方工具 camera_calibration 包,采集棋盘格数据并生成 .yaml 标定文件。

然后修改相机驱动节点的启动配置文件(通常是 .launch.py.yaml 参数文件),将标定文件路径指向你生成的本地文件。

但是执行run_camera.sh发布的图像topic都是nv12的,不被标定工具支持

针对 NV12 格式不被 ROS2 camera_calibration 支持的问题,核心思路是:在标定前将图像从 NV12 转换为 RGB8/mono8

RDK X5 上 MIPI 相机默认输出 NV12 是为了节省带宽和方便硬件编解码,但标定工具需要未压缩的像素格式。以下是三种解决方案,按推荐程度排序:


:white_check_mark: 方案一:使用 image_proc 或自定义节点做格式转换(推荐)

在相机驱动和标定工具之间加一个图像格式转换节点,将 NV12 转为 RGB8 或 mono8。

步骤:

  1. 确认当前图像 topic 和格式

    ros2 topic echo /camera/image_raw --field encoding
    # 应输出: nv12
    
  2. 创建格式转换节点(Python 示例):

    # nv12_to_rgb.py
    import rclpy
    from rclpy.node import Node
    from sensor_msgs.msg import Image
    from cv_bridge import CvBridge
    import cv2
    import numpy as np
    
    class Nv12ToRgb(Node):
        def __init__(self):
            super().__init__('nv12_to_rgb')
            self.sub = self.create_subscription(Image, '/camera/image_raw', self.callback, 10)
            self.pub = self.create_publisher(Image, '/camera/image_rgb', 10)
            self.bridge = CvBridge()
    
        def callback(self, msg):
            # NV12 数据解析
            h, w = msg.height, msg.width
            nv12_data = np.frombuffer(msg.data, dtype=np.uint8)
            nv12_data = nv12_data.reshape((h * 3 // 2, w))
            bgr = cv2.cvtColor(nv12_data, cv2.COLOR_YUV420sp2BGR)
            rgb_msg = self.bridge.cv2_to_imgmsg(bgr, encoding='rgb8')
            rgb_msg.header = msg.header
            self.pub.publish(rgb_msg)
    
    if __name__ == '__main__':
        rclpy.init()
        rclpy.spin(Nv12ToRgb())
    
  3. 运行转换节点

    source /opt/tros/setup.bash
    ros2 run your_package nv12_to_rgb
    
  4. 使用转换后的 topic 进行标定

    ros2 run camera_calibration cameracalibrator.py \
      --size 8x6 \
      --square 0.025 \
      image:=/camera/image_rgb \
      camera:=/camera
    

:white_check_mark: 方案二:修改相机驱动配置,直接输出 RGB8(如果支持)

部分 MIPI 相机驱动支持配置输出格式。检查相机驱动的 .yaml.launch.py 文件:

  1. 查找相机参数文件(通常在 /opt/tros/share/hobot_mipi_cam/ 或类似路径):

    find /opt/tros -name "*.yaml" | xargs grep -l "format\|encoding"
    
  2. 修改输出格式(如果驱动支持):

    # 示例:hobot_mipi_cam 参数
    pixel_format: rgb8  # 或 mono8
    # 原值可能是: nv12
    
  3. 重启相机节点

    ros2 launch hobot_mipi_cam hobot_mipi_cam.launch.py
    

:warning: 注意:不是所有相机驱动都支持直接输出 RGB8,NV12 是 MIPI CSI-2 的标准格式,强制转 RGB8 可能增加 CPU 负载或降低帧率。


:white_check_mark: 方案三:使用 GStreamer 管道做实时转换(进阶)

如果相机驱动支持 GStreamer,可以用管道直接转换:

gst-launch-1.0 v4l2src device=/dev/video0 ! \
  video/x-raw,format=NV12 ! \
  videoconvert ! \
  video/x-raw,format=RGB ! \
  ros2_image_publisher

:pushpin: 标定后如何载入本地参数?

标定完成后会生成 .yaml 文件(如 ost.yaml),修改相机驱动的启动配置:

# 在 .launch.py 文件中
Node(
    package='hobot_mipi_cam',
    executable='hobot_mipi_cam_node',
    parameters=[{
        'camera_info_url': 'file:///home/your_user/calibration/ost.yaml',
        # 或
        'calibration_file': '/home/your_user/calibration/ost.yaml'
    }]
)

:magnifying_glass_tilted_left: 排查建议

如果上述方案都不可行,请提供:

  1. ros2 topic list 输出
  2. ros2 topic echo /camera/image_raw --field encoding,width,height
  3. 相机驱动包名(ros2 pkg list | grep cam

这样可以进一步定位驱动是否支持格式切换。


总结:优先用方案一(加转换节点),简单可靠;如果驱动支持,方案二更直接。标定完成后记得修改驱动配置载入本地 .yaml 文件。

run_camera.sh里的out_format改成bgr8即可解决

太好了!:tada: 你找到了最直接的解决方案。

修改 run_camera.sh 中的 out_format 确实是最简单的办法,比加转换节点更省事。


:white_check_mark: 确认你的解决方案

# 编辑 run_camera.sh 或相关配置文件
# 找到类似这样的行:
out_format=nv12  # 改为
out_format=bgr8  # 或 rgb8

这样相机驱动直接输出 BGR8/RGB8,camera_calibration 就能直接用了。


:pushpin: 后续标定步骤提醒

  1. 采集标定数据

    source /opt/tros/setup.bash
    ros2 run camera_calibration cameracalibrator.py \
      --size 8x6 \
      --square 0.025 \
      image:=/camera/image_raw \
      camera:=/camera
    
  2. 保存标定文件

    • 标定完成后点击 “SAVE”,生成 ost.yaml
  3. 载入标定参数到 run_stereo

    # 修改 stereo 节点的启动配置,添加参数:
    camera_info_url: "file:///path/to/your/ost.yaml"
    

:warning: 注意事项

项目 说明
带宽 BGR8 比 NV12 数据量大 1.5 倍,确认 MIPI 带宽足够
帧率 格式转换可能影响帧率,观察是否降帧
CPU 驱动内转换比后处理节点更高效

:light_bulb: 建议

建议在原帖子中把你的解决方案更新一下,帮助其他遇到同样问题的开发者:

更新:直接修改 run_camera.sh 中的 out_format=bgr8 即可输出标定工具支持的格式,无需额外转换节点。

这样社区其他人搜索时就能快速找到答案了 :+1:

标定过程中有任何问题随时问!

请问需要的标定结果.yaml文件的格式是什么,外参和内参都支持本地导入吗

针对你的问题,RDK X5 的 run_stereo.sh (StereoNet) 支持的标定文件格式主要有两种,取决于你使用的 标定模式 (calib_method)

1. 标定文件格式

模式 A:使用 ROS 标准格式 (calib_method=ros 或默认)

这是最通用的格式,由 ROS2 camera_calibration 包直接生成(即 ost.yaml)。StereoNet 节点会通过订阅 /camera_info Topic 自动获取内参。

文件结构示例 (ost.yaml):

image_width: 1280
image_height: 720
camera_name: "left_camera"
camera_matrix:
  rows: 3
  cols: 3
  data: [fx, 0, cx, 0, fy, cy, 0, 0, 1]  # 内参矩阵
distortion_model: "plumb_bob"
distortion_coefficients:
  rows: 1
  cols: 5
  data: [k1, k2, p1, p2, k3]  # 畸变系数
rectification_matrix:
  rows: 3
  cols: 3
  data: [1, 0, 0, 0, 1, 0, 0, 0, 1]  # 矫正矩阵(单目标定为单位阵)
projection_matrix:
  rows: 3
  cols: 4
  data: [fx, 0, cx, Tx, 0, fy, cy, Ty, 0, 0, 1, 0] # 投影矩阵
  • 支持内容:主要包含单目内参 (Intrinsic) 和 畸变系数
  • 外参处理:ROS 标准单目标定文件不包含双目外参(基线 Baseline、旋转 R、平移 T)。双目外参通常需要通过立体标定单独计算,并填入 projection_matrixTx/Ty 或通过其他机制注入。

模式 B:使用 StereoNet 自定义格式 (calib_method=custom)

如果你需要直接加载包含双目外参的完整文件,需使用 StereoNet 特定的 JSON/YAML 格式。这是 run_stereo.shstereo_calib_file_path 参数指向的文件。

文件结构示例 (custom_calib.yaml.json):
根据社区案例和报错信息,该格式通常需要包含左右目的完整参数及相互关系:

# 这是一个概念结构,具体字段名需参考 hobot_stereonet 源码或最新文档
left_camera:
  intrinsics: [fx, fy, cx, cy]
  distortion: [k1, k2, p1, p2, k3]
right_camera:
  intrinsics: [fx, fy, cx, cy]
  distortion: [k1, k2, p1, p2, k3]
stereo_params:
  baseline: 0.12        # 基线距离 (米)
  rotation: [r1, r2, ...] # 旋转矩阵 (9个元素)
  translation: [tx, ty, tz] # 平移向量
  • 注意:社区中有反馈 (topic:34849) 直接使用 custom 模式加载外部 YAML 可能存在稳定性问题(段错误),建议优先尝试通过 ROS Topic 注入参数。

2. 内参与外参的导入方式

参数类型 是否支持本地导入 推荐导入方式 说明
内参 (Intrinsic) :white_check_mark: 支持 ROS Topic 注入 标定生成的 ost.yaml 通过 camera_info_publisher 发布到 /camera_info Topic,StereoNet 自动订阅使用。这是最稳妥的方式。
畸变 (Distortion) :white_check_mark: 支持 ROS Topic 注入 同上,包含在 ost.yaml 中。若开启 GDC 硬件去畸变 (mipi_gdc_enable=True),则需将参数填入驱动层的 YAML。
外参 (Extrinsic) :warning: 部分支持 手动指定参数 run_stereo.sh 脚本提供了显式参数来覆盖外参,推荐直接使用脚本参数而不是依赖文件解析:
--baseline 0.12 (基线)
--camera_cx, --camera_cy

3. 最佳实践方案

为了避免文件格式解析错误(如段错误)并灵活使用自标定参数,建议采用 “ROS Topic 内参 + 脚本参数外参” 的组合方式:

步骤 1:发布内参 (使用 ROS 标准 ost.yaml)

使用 camera_calibration 生成 left_ost.yamlright_ost.yaml,然后启动发布节点:

# 启动相机内参发布器
ros2 run camera_calibration camera_info_publisher \
  --ros-args -p url:=file:///path/to/your/left_ost.yaml \
  -p frame_id:=camera_link \
  -p camera_name:=left_camera
# 对右目重复操作,确保 topic 名称匹配 stereo 节点订阅

步骤 2:运行 StereoNet 并注入外参

修改 run_stereo.sh 或在命令行直接传递外参参数,不依赖 stereo_calib_file_path (或设为空):

bash run_stereo.sh \
  --calib_method ros \
  --stereo_calib_file_path "" \
  --baseline 0.120 \          # 你的双目基线 (米)
  --camera_fx 900.0 \         # 可选:覆盖内参
  --camera_fy 900.0 \
  --camera_cx 640.0 \
  --camera_cy 360.0

总结

  1. 文件格式:优先使用 ROS2 camera_calibration 生成的 ost.yaml (标准格式)。
  2. 内参:通过 ROS Topic (/camera_info) 自动加载,支持
  3. 外参:建议通过 run_stereo.sh命令行参数 (--baseline 等) 直接传入,支持且更稳定。
  4. 避坑:尽量避免使用 calib_method=custom 直接加载复杂的自定义 YAML 文件,目前社区反馈该方式可能存在解析 Bug。

请问如何可视化校正后的图像(即运行run_stereo.sh后的/rectify_left_image话题),直接使用rviz或者rqt_image_view会提示不支持nv12格式

针对 run_stereo.sh 输出的校正图像(如 /rectify_left_image)是 NV12 格式,而 rviz2rqt_image_view 默认不支持直接显示 NV12 的问题,这里有三种解决方案,按推荐程度排序:


:white_check_mark: 方案一:修改 StereoNet 启动参数,直接输出 BGR8/RGB8(最推荐)

run_stereo.sh 脚本支持配置输出图像的编码格式。你只需要在启动时添加或修改 codec_in_format 参数。

操作步骤:

  1. 编辑 run_stereo.sh 脚本,找到 codec_in_format 参数行:

    # 原值可能是:
    codec_in_format=bgr8  # 或者 nv12
    

    确保它被设置为 bgr8rgb8

  2. 或者在命令行启动时直接覆盖参数

    bash run_stereo.sh \
      --codec_in_format bgr8 \
      --publish_rectify_bgr True
    

    注意:publish_rectify_bgr=True 确保发布的是 BGR 格式的校正图。

  3. 验证 Topic 格式

    ros2 topic echo /rectify_left_image --field encoding
    # 应输出: bgr8 或 rgb8
    
  4. 现在可以直接用 RViz2 查看

    rviz2
    # 添加 Image 显示,Topic 选择 /rectify_left_image
    

:white_check_mark: 方案二:使用 image_transport 或转换节点(如果方案一无效)

如果 StereoNet 节点强制输出 NV12,可以在中间加一个格式转换节点。

快速转换节点(Python):

# nv12_to_rgb_display.py
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2
import numpy as np

class Nv12ToRgb(Node):
    def __init__(self):
        super().__init__('nv12_to_rgb_display')
        # 订阅 NV12 的校正图
        self.sub = self.create_subscription(Image, '/rectify_left_image', self.callback, 10)
        # 发布 RGB8 的校正图
        self.pub = self.create_publisher(Image, '/rectify_left_image_rgb', 10)
        self.bridge = CvBridge()

    def callback(self, msg):
        if msg.encoding != 'nv12':
            self.pub.publish(msg)  # 已经是 RGB,直接转发
            return
        
        h, w = msg.height, msg.width
        # NV12 数据解析:Y 平面 + UV 平面
        nv12_data = np.frombuffer(msg.data, dtype=np.uint8)
        nv12_data = nv12_data.reshape((h * 3 // 2, w))
        
        # 转换为 BGR
        bgr = cv2.cvtColor(nv12_data, cv2.COLOR_YUV420sp2BGR)
        
        # 转为 ROS Image 消息
        rgb_msg = self.bridge.cv2_to_imgmsg(bgr, encoding='bgr8')
        rgb_msg.header = msg.header
        self.pub.publish(rgb_msg)

if __name__ == '__main__':
    rclpy.init()
    rclpy.spin(Nv12ToRgb())

运行转换节点

source /opt/tros/setup.bash
python3 nv12_to_rgb_display.py

在 RViz2 中订阅新 Topic

  • Topic: /rectify_left_image_rgb

:white_check_mark: 方案三:使用 rqt_image_view 的插件(如果支持)

部分 rqt_image_view 版本支持通过插件解码 NV12,但 RDK 的 TROS 环境可能未默认安装。

尝试安装:

sudo apt install ros-humble-rqt-image-view

如果仍不支持,请优先使用方案一


:pushpin: 验证步骤

  1. 确认当前 Topic 格式

    ros2 topic info /rectify_left_image -v
    # 查看 Published message type 和 encoding 字段
    
  2. 如果格式是 nv12

    • 使用方案一修改启动参数
    • 或使用方案二添加转换节点
  3. 在 RViz2 中显示

    • 添加 Image 显示
    • Topic 选择 /rectify_left_image(如果已转为 BGR8)或 /rectify_left_image_rgb

:warning: 注意事项

项目 说明
性能 直接修改 codec_in_format 比后处理转换节点更高效
带宽 BGR8 数据量比 NV12 大 1.5 倍,确认网络/显示带宽足够
兼容性 RViz2 在 ARM 平台上对 NV12 支持有限,建议统一转 BGR8

:light_bulb: 建议

建议优先尝试 方案一,直接在 run_stereo.sh 中设置 --codec_in_format bgr8,这是最干净的解决方案。如果遇到问题,再考虑方案二的转换节点。

转换成功后,欢迎在原帖子更新解决方案,帮助其他开发者!

我仔细对比了一下/rectify_left_image和/origin_left_image,感觉除了被resize以外,似乎没有看到畸变校正的效果?是不是run_stereo.sh里有参数没设置正确导致实际没有进行校正

你的观察非常敏锐!如果 /rectify_left_image/origin_left_image 看起来除了分辨率不同外,畸变效果没有明显区别,说明畸变校正(Undistortion)实际上并没有生效

这通常是因为 run_stereo.sh 的标定模式配置不正确,导致节点没有加载你的标定参数,而是使用了默认的空参数(相当于无校正)。

以下是排查和解决步骤:


:magnifying_glass_tilted_left: 核心原因分析

在 RDK X5 的 StereoNet 流程中,畸变校正通常由两个环节之一完成:

  1. 硬件 GDC 校正:在相机驱动层(hobot_mipi_cam)完成,输出已经是无畸变图像。
  2. 软件 StereoNet 校正:StereoNet 节点读取标定文件,在内部进行极线校正和去畸变。

如果你的标定文件没有正确加载,节点会 fallback 到“无畸变”模式,导致输出的 rectify 图像和原图看起来一样(仅做了 Resize)。


:white_check_mark: 解决方案:检查并修正启动参数

请重点检查 run_stereo.sh 中的以下几个关键参数:

1. 确认标定模式 (calib_method)

这是最关键的一步。如果你使用的是 ROS camera_calibration 生成的 ost.yaml不能直接用 calib_method=custom 加载文件路径,而应该使用 calib_method=ros 并通过 Topic 注入。

修改建议:

# 错误用法(容易崩溃或无效):
# calib_method=custom
# stereo_calib_file_path=/path/to/ost.yaml

# ✅ 正确用法(推荐):
calib_method=ros
stereo_calib_file_path=""  # 留空,不直接加载文件

2. 确认相机驱动层是否已去畸变

如果你希望 StereoNet 处理畸变,必须确保相机驱动没有预先做一遍 GDC 校正,或者 StereoNet 知道原始畸变参数。

检查 mipi_gdc_enable 参数:

  • 情况 A:mipi_gdc_enable=True (默认)

    • 相机驱动已经输出了去畸变后的图像。
    • 此时 StereoNet 的 rectify 操作主要是做极线对齐 (Rectification),而不是去畸变。
    • 现象:如果原图已经无畸变,rectify 图看起来确实和原图很像。
    • 验证方法:观察棋盘格直线。如果 /origin_left_image 里的直线已经是直的,说明驱动层已经处理了。
  • 情况 B:mipi_gdc_enable=False

    • 相机输出原始畸变图像
    • StereoNet 必须加载正确的内参才能去畸变。
    • 操作:此时必须确保 ROS Topic /camera_info 中发布了正确的畸变系数 (distortion_coefficients)。

3. 验证标定参数是否注入成功

在运行 run_stereo.sh 的同时,在另一个终端检查相机内参 Topic:

# 查看左目内参
ros2 topic echo /image_combine_raw/left/camera_info

# 或者根据你的脚本配置,可能是 /left_camera/camera_info
# 重点检查以下字段是否为 0 或默认值:
# distortion_coefficients: [0.0, 0.0, 0.0, 0.0, 0.0]  <-- 如果全为 0,说明没加载成功!
# camera_matrix: [fx, 0, cx, ...] <-- 检查 fx, fy, cx, cy 是否是你标定的值

如果 distortion_coefficients 全为 0,说明 StereoNet 没有读到你的标定文件。


:hammer_and_wrench: 推荐的操作流程

为了确保标定生效,请按以下标准流程操作:

第一步:发布标定文件 (ost.yaml)

不要依赖 run_stereo.sh 直接读文件,而是启动一个独立的节点发布标定参数。

# 终端 1: 发布左目内参
ros2 run camera_calibration camera_info_publisher \
  --ros-args \
  -p url:=file:///home/your_user/calibration/left_ost.yaml \
  -p frame_id:=camera_link \
  -p camera_name:=left_camera \
  --remap camera_info:=/image_combine_raw/left/camera_info

# 终端 2: 发布右目内参 (如果有单独的右目标定文件)
ros2 run camera_calibration camera_info_publisher \
  --ros-args \
  -p url:=file:///home/your_user/calibration/right_ost.yaml \
  -p frame_id:=camera_link \
  -p camera_name:=right_camera \
  --remap camera_info:=/image_combine_raw/right/camera_info

(注意:--remap 后的 topic 名称必须与 run_stereo.sh 中订阅的 left_camera_info_topiccamera_info_topic 一致)

第二步:修改并运行 run_stereo.sh

编辑脚本,确保以下参数设置正确:

# 关键参数设置
calib_method=ros                # 使用 ROS Topic 获取内参
stereo_calib_file_path=""       # 不要指定文件路径,避免解析错误
mipi_gdc_enable=False           # 【重要】如果想让 StereoNet 做去畸变,建议关闭驱动层 GDC
                                # 如果保持 True,则 StereoNet 只做极线校正

# 外参参数(如果是双目,必须手动指定基线,因为 ROS 单目标定文件不含基线)
baseline=0.120                  # 填入你实测的双目基线距离 (米)
camera_cx=640.0                 # 可选:如果 Topic 里没覆盖,可在这里强制指定
camera_cy=360.0
camera_fx=900.0
camera_fy=900.0

运行脚本:

bash run_stereo.sh

第三步:再次验证

  1. 检查 Topic 数据
    ros2 topic echo /image_combine_raw/left/camera_info
    # 确认 distortion_coefficients 不为 0
    
  2. 可视化对比
    • 在 RViz2 中同时添加 /origin_left_image/rectify_left_image
    • 找一个有明显畸变的场景(如靠近摄像头的棋盘格或直线墙壁)。
    • 预期结果
      • /origin_left_image:直线弯曲(如果 mipi_gdc_enable=False)。
      • /rectify_left_image:直线变直,且左右目同一水平线上的像素对齐。

:light_bulb: 总结排查清单

现象 可能原因 解决方法
rectify 和 origin 看起来一样 1. distortion_coefficients 为 0
2. 驱动层已去畸变 (mipi_gdc_enable=True)
1. 检查 camera_info Topic 是否有数据
2. 尝试关闭 mipi_gdc_enable 测试
节点崩溃 (exit code -11) calib_method=custom 解析文件失败 改用 calib_method=ros + camera_info_publisher
深度图全黑或测距为 0 基线 (baseline) 为 0 或外参错误 在启动脚本中手动传入 --baseline 0.12
直线不直 标定数据未生效 确认 camera_info_publisher 已启动且 Topic 名称匹配

建议先执行“第三步”中的 ros2 topic echo 命令,这是判断标定参数是否加载成功的最直接证据。如果 distortion_coefficients 全是 0,那无论怎么跑,图像都不会有去畸变效果。

run_cam.sh怎么设置才能直接输出去畸变后的图

要在 run_cam.sh (或 hobot_mipi_cam 启动配置) 中直接输出已去畸变的图像,核心是启用 GDC (Geometry Distortion Correction) 硬件模块并加载正确的标定文件。

RDK X5 的去畸变通常在相机驱动层完成,而不是在 StereoNet 层。

:white_check_mark: 解决方案:修改相机启动配置

你需要修改相机驱动节点的启动参数,启用 GDC 并指向你的标定文件。

1. 准备标定文件 (.yaml.bin)

GDC 模块需要特定的标定文件格式。

  • 如果你已有 .yaml (ROS 标准格式):通常可以直接使用,但需确认字段匹配。
  • 如果你需要生成 GDC 专用的 .bin:需使用地平线提供的 GDC Tool (Windows) 将内参转换为映射表。
    • 注:对于快速验证,通常 .yaml 也能被驱动加载,具体取决于 SDK 版本。

将你的标定文件重命名或放置在驱动默认读取的路径,例如:
/opt/tros/share/hobot_mipi_cam/config/132GS_calibration.yaml (文件名需与驱动配置匹配)。

2. 修改 run_cam.sh.launch.py

找到启动相机节点的脚本(通常是 run_cam.sh 或其调用的 hobot_mipi_cam.launch.py),修改以下参数:

关键参数设置:

参数名 推荐值 说明
mipi_gdc_enable True 核心开关:启用硬件去畸变
camera_calibration_file /path/to/your/calib.yaml 指向你的标定文件路径
out_format bgr8 建议输出 BGR8 以便直接查看 (之前已解决)

修改示例 (run_cam.sh 或启动命令):

# 方式 A: 如果脚本支持直接传参
bash run_cam.sh \
  --mipi_gdc_enable True \
  --camera_calibration_file /home/your_user/calibration/132GS_calibration.yaml \
  --out_format bgr8

# 方式 B: 如果是修改 .launch.py 文件 (查找 hobot_mipi_cam 节点)
# 在 Python 文件中修改参数声明:
Node(
    package='hobot_mipi_cam',
    executable='hobot_mipi_cam_node',
    parameters=[{
        'mipi_gdc_enable': True,              # 开启 GDC
        'camera_calibration_file': '/home/your_user/calibration/132GS_calibration.yaml', # 标定文件路径
        'pixel_format': 'bgr8',               # 输出格式
        # 其他参数...
    }]
)

3. 验证去畸变效果

启动相机后,订阅图像话题并观察:

# 1. 确认话题图像格式
ros2 topic echo /camera/image_raw --field encoding
# 应输出: bgr8

# 2. 使用 rqt_image_view 或 rviz2 查看
rqt_image_view /camera/image_raw
# 或使用之前设置的 /rectify_left_image (如果 stereo 节点也订阅了驱动输出的话)

观察标准

  • 将棋盘格或直线物体靠近相机边缘。
  • 未去畸变:直线弯曲(桶形畸变)。
  • 已去畸变:直线变直。

:warning: 常见问题排查

问题 原因 解决方法
GDC 开启后黑屏/报错 标定文件路径错误或格式不匹配 检查日志 ros2 launch ... 输出,确认 camera_calibration_file 路径正确且文件存在
图像依然有畸变 标定文件内参不准或未生效 检查日志中是否有 GDC init success 字样;确认 distortion_coefficients 不为 0
帧率下降 GDC 占用硬件资源 X5 的 GDC 是硬件加速,通常不影响帧率,检查是否同时进行了其他重负载操作
找不到标定文件 默认路径不对 显式在 launch 文件中指定绝对路径,不要依赖相对路径

:light_bulb: 推荐流程总结

  1. 标定:用 camera_calibration 生成 ost.yaml
  2. 转换 (可选):如果驱动不直接支持 ost.yaml,使用 GDC Tool 转为 .bin (咨询官方文档确认是否必须)。
  3. 配置:修改 run_cam.sh,设置 mipi_gdc_enable=Truecamera_calibration_file 路径。
  4. 验证:启动相机,观察边缘直线是否变直。

提示:如果你之前修改过 out_format=bgr8 解决了标定问题,那么现在只需在此基础上增加 mipi_gdc_enable=True 和标定文件路径即可直接获得去畸变图像,无需再经过 StereoNet 处理。

执行run_cam.sh,gdc_enable=True,log也打印了加载成功自己的calib.yaml文件,也打印了执行gdc,但是echo camera_info发现distortion里都是0,并且打印的内参数值也不是我calib.yaml里的值

你遇到的现象非常典型:GDC 硬件去畸变已生效(日志打印成功),但 ROS camera_info Topic 里的参数却是默认的(畸变系数为 0,内参不匹配)。

:magnifying_glass_tilted_left: 核心原因

这是 RDK X5 相机驱动的一个设计特性(或者说是“行为不一致”):

  1. GDC 硬件层:读取了你的 .yaml 文件,并成功应用了去畸变算法(所以图像直了)。
  2. ROS 驱动层 (hobot_mipi_cam)并没有自动将你加载的 .yaml 文件里的参数填充到发布的 camera_info Topic 中。
    • 默认情况下,如果驱动没有显式配置“发布标定参数”,它会发布一套默认的空参数(畸变为 0,内参为理想值)。
    • 这就导致了“图像已经去畸变,但告诉下游节点‘我没畸变’”的矛盾状态。

:white_check_mark: 解决方案

既然驱动不自动发布,你需要手动发布正确的 camera_info,或者修改驱动配置让它发布。

方案一:使用 camera_info_publisher 手动注入(最推荐,最稳定)

不要依赖相机驱动发布内参,而是启动一个独立的节点,把你标定好的 ost.yaml 发布出去。这样无论驱动内部怎么变,下游拿到的参数永远是你标定的。

步骤:

  1. 确保你有 ROS 标准的 ost.yaml(由 camera_calibration 生成)。
  2. 启动相机节点(保持 mipi_gdc_enable=True):
    bash run_cam.sh --mipi_gdc_enable True --out_format bgr8
    
  3. 在另一个终端启动参数发布器
    source /opt/tros/setup.bash
    
    # 发布左目内参 (注意 remap 到相机驱动实际发布的 topic 名称)
    ros2 run camera_calibration camera_info_publisher \
      --ros-args \
      -p url:=file:///home/你的用户/标定目录/left_ost.yaml \
      -p frame_id:=camera_link \
      -p camera_name:=left_camera \
      --remap camera_info:=/camera/left/camera_info  # 关键:需匹配 run_cam.sh 发布的 topic
    
    (注:如果是双目,需要分别发布左右目,topic 名称通常是 /camera/left/camera_info/camera/right/camera_info,请用 ros2 topic list 确认)

效果

  • 图像:由 GDC 硬件去畸变(直)。
  • Topic:由你手动发布的节点提供正确的内参和畸变系数(即使畸变系数不为 0,下游算法如 StereoNet 也会知道原始畸变情况,或者你可以手动将 yaml 中的畸变系数改为 0 以匹配“已去畸变”的图像)。

:light_bulb: 重要提示:如果你开启 GDC 后图像已经无畸变,但 camera_info 里还有畸变系数,某些算法(如 StereoNet)可能会二次去畸变导致图像错误。
最佳实践:如果 GDC 已去畸变,建议在发布的 ost.yaml 中将 distortion_coefficients 全改为 0.0,但保留正确的 camera_matrix (内参)。

方案二:修改相机驱动 Launch 文件(一劳永逸)

如果你希望相机驱动自动发布正确的参数,需要修改 .launch.py 文件。

  1. 找到启动文件
    通常在 /opt/tros/share/hobot_mipi_cam/launch/hobot_mipi_cam.launch.py 或类似路径。
  2. 添加/修改参数
    Node 定义中,添加 camera_info_url 参数:
    Node(
        package='hobot_mipi_cam',
        executable='hobot_mipi_cam_node',
        parameters=[{
            'mipi_gdc_enable': True,
            'camera_calibration_file': '/home/你的用户/标定目录/132GS_calibration.yaml',
            'camera_info_url': 'file:///home/你的用户/标定目录/ost.yaml',  # 新增这行
            # 其他参数...
        }]
    )
    
  3. 重启相机

注意:部分旧版本驱动可能不支持 camera_info_url 参数,如果无效请回退到方案一。

方案三:检查 YAML 格式是否匹配

如果驱动确实尝试读取但读错了,可能是 YAML 格式问题。

  • GDC 用的 yaml:可能包含特定字段(如 lens_distortion 等)。
  • ROS camera_info 用的 yaml:必须是标准 ROS 格式(包含 camera_matrix, distortion_coefficients 等)。

确认你的 calib.yaml 包含以下标准字段

image_width: 1280
image_height: 720
camera_name: "camera"
camera_matrix:
  rows: 3
  cols: 3
  data: [fx, 0, cx, 0, fy, cy, 0, 0, 1]
distortion_model: "plumb_bob"
distortion_coefficients:
  rows: 1
  cols: 5
  data: [k1, k2, p1, p2, k3]

如果字段名不对,驱动会静默失败并使用默认值。


:rocket: 总结建议

  1. 验证图像:既然日志显示 GDC 成功,且你肉眼观察图像直线变直,说明硬件去畸变已生效
  2. 解决 Topic 问题
    • 最快方法:使用 方案一,启动一个 camera_info_publisher 节点,强行覆盖 Topic 数据。
    • 数据修正:在发布的 YAML 中,将 distortion_coefficients 设为 [0, 0, 0, 0, 0](因为图像已经由 GDC 去畸变了),但保留正确的 camera_matrix (fx, fy, cx, cy)。
  3. 后续 StereoNet 配置
    • 运行 run_stereo.sh 时,设置 mipi_gdc_enable=True(告诉它图像已经处理过)。
    • 设置 calib_method=ros,让它订阅你手动发布的那个正确的 camera_info

这样就能保证:图像是直的,参数是对的,深度计算也是准的。

echo camera_info怎么突然没任何输出了

camera_info 突然没输出,说明相机节点可能没有正常发布该 Topic。按以下步骤快速排查:


:magnifying_glass_tilted_left: 第一步:确认 Topic 是否存在

# 1. 列出所有包含 camera_info 的 topic
ros2 topic list | grep camera_info

# 2. 列出所有包含 camera 的 topic
ros2 topic list | grep camera

常见 Topic 名称(根据你的启动方式可能不同):

启动方式 可能的 camera_info topic
run_cam.sh (单目) /camera/camera_info/camera_info
run_cam.sh (双目) /camera/left/camera_info + /camera/right/camera_info
run_stereo.sh /image_combine_raw/left/camera_info + /image_combine_raw/right/camera_info

:magnifying_glass_tilted_left: 第二步:检查相机节点是否正常运行

# 1. 查看节点列表
ros2 node list | grep cam

# 2. 查看节点状态
ros2 node info /mipi_cam  # 或你的节点名称

# 3. 查看图像 topic 是否有数据
ros2 topic hz /camera/image_raw  # 替换为你实际的图像 topic

如果图像 topic 也没有数据 → 相机节点启动失败,检查日志。


:magnifying_glass_tilted_left: 第三步:查看启动日志

重新运行 run_cam.sh,观察日志中是否有以下关键信息:

bash run_cam.sh --mipi_gdc_enable True --out_format bgr8

关键日志检查:

日志内容 含义
GDC init success GDC 硬件初始化成功
camera_calibration_file loaded 标定文件加载成功
publish camera_info 正在发布 camera_info
ERROR / Failed 有错误,需要关注具体信息

:magnifying_glass_tilted_left: 第四步:确认 launch 文件配置

如果之前能输出现在不能,可能是配置被修改了。检查 run_cam.sh.launch.py 中是否有以下参数:

# 在 .launch.py 中确认是否有 camera_info 相关配置
parameters=[{
    'mipi_gdc_enable': True,
    'camera_calibration_file': '/path/to/calib.yaml',
    'publish_camera_info': True,  # 确认这个参数是否存在且为 True
}]

:hammer_and_wrench: 快速修复方案

方案 A:使用独立的 camera_info_publisher(推荐)

不依赖相机驱动发布,自己启动一个发布节点:

# 终端 1: 启动相机
bash run_cam.sh --mipi_gdc_enable True --out_format bgr8

# 终端 2: 发布标定参数
ros2 run camera_calibration camera_info_publisher \
  --ros-args \
  -p url:=file:///home/你的用户/标定目录/ost.yaml \
  -p frame_id:=camera_link \
  --remap camera_info:=/camera/camera_info  # 替换为实际 topic 名称

方案 B:检查是否被之前的进程占用

# 查看是否有残留的相机进程
ps aux | grep mipi_cam

# 如果有,杀掉后重启
killall -9 mipi_cam_node
# 然后重新运行 run_cam.sh

:clipboard: 请提供以下信息以便进一步诊断

如果上述步骤无法解决,请提供:

# 1. topic 列表
ros2 topic list | grep -E "camera|image"

# 2. 节点列表
ros2 node list | grep cam

# 3. run_cam.sh 启动时的完整日志(最后 20 行)

# 4. 你 echo 的具体命令
echo /xxx/camera_info  # 你用的是哪个 topic 名称?

这样我可以帮你精确定位问题所在。

[WARN] [1779270905.584900072] [mipi_node]:
node params:
config_path: /opt/tros/humble/lib/mipi_cam/config/
video_device_name:
channel: 2
channel2: 0
camera_info_url:
camera_calibration_file_path: /userdata/rdk_cam/SC132gs_dual_calibration.yaml
out_format_name: bgr8
gdc_bin_file:
image_width: 1280
image_height: 1088
sub_image_width: 960
sub_image_height: 540
framerate: 10
rotation: 90.000000
device_mode: dual
dual_combine: 1
lpwm_enable: true
gdc_enable: true
frame_ts_type: realtime
frame_id: default_cam
link_type: 0
link_port: 0
io_method_name: ros
cal_alpha: 0.000
[WARN] [1779270905.585438113] [mipi_factory]: This is’t support device type(), start defaule capture.

[INFO] [1779270905.586788236] [mipi_cap]: this board support mipi:
[INFO] [1779270905.586837486] [mipi_cap]: host 0
[INFO] [1779270905.586865736] [mipi_cap]: host 2
[INFO] [1779270905.587111611] [mipi_cam]: cal_file:/userdata/rdk_cam/SC132gs_dual_calibration.yaml
[INFO] [1779270905.587924652] [mipi_cam]: Camera calibration file did not specify distortion model, assuming plumb bob
index: 0 sensor_name: sc230ai-30fps config_file:linear_1920x1080_raw10_30fps_1lane.c
index: 1 sensor_name: sc132gs-1280p config_file:linear_1088x1280_raw10_30fps_1lane.c
index: 2 sensor_name: ov5647 config_file:linear_1920x1080_raw10_30fps_2lane.c
index: 3 sensor_name: imx219-30fps config_file:linear_1920x1080_raw10_30fps_2lane.c
index: 4 sensor_name: imx477-1920x1080-50fps config_file:linear_1920x1080_raw12_50fps_2lane.c
index: 5 sensor_name: imx415-20fps-2lane config_file:linear_3840x2160_raw10_30fps_2lane.c
Searching camera sensor on device: /proc/device-tree/soc/cam/vcon@0 i2c bus: 6 mipi rx phy: 0
WARN: Sensor Name: sc230ai-30fps, Expected Chip ID: 0xCB34, Actual Chip ID Read: 0x00
WARN: Sensor Name: sc230ai-30fps, Expected Chip ID: 0xCB34, Actual Chip ID Read: 0x132
WARN: Sensor Name: sc132gs-1280p, Expected Chip ID: 0x132, Actual Chip ID Read: 0x00
INFO: vp_sensor_detect_2 Support sensor index:0, sensor_name:sc132gs-1280p on mipi rx csi 0, i2c addr 0x32, config_file:linear_1088x1280_raw10_30fps_1lane.c
Searching camera sensor on device: /proc/device-tree/soc/cam/vcon@2 i2c bus: 4 mipi rx phy: 2
WARN: Sensor Name: sc230ai-30fps, Expected Chip ID: 0xCB34, Actual Chip ID Read: 0x00
WARN: Sensor Name: sc230ai-30fps, Expected Chip ID: 0xCB34, Actual Chip ID Read: 0x00
WARN: Sensor Name: sc132gs-1280p, Expected Chip ID: 0x132, Actual Chip ID Read: 0x00
WARN: Sensor Name: sc132gs-1280p, Expected Chip ID: 0x132, Actual Chip ID Read: 0x00
INFO: vp_sensor_detect_2 Support sensor index:2, sensor_name:sc132gs-1280p on mipi rx csi 2, i2c addr 0x33, config_file:linear_1088x1280_raw10_30fps_1lane.c
Searching camera sensor on device: /proc/device-tree/soc/cam/vcon@0 i2c bus: 6 mipi rx phy: 0
WARN: Sensor Name: sc132gs-1280p, Expected Chip ID: 0x132, Actual Chip ID Read: 0x00
INFO: vp_sensor_fixed_mipi_host_1 Found sensor_name:sc132gs-1280p on mipi rx csi 0, i2c addr 0x32, config_file:linear_1088x1280_raw10_30fps_1lane.c
[WARN] [1779270906.475218220] [mipi_cap]: i2c bus: 4, EEPROM FLAG: SZYGSJKJ

[INFO] [1779270906.477199885] [mipi_cap]: ====EepromDrobotHead======

bus: 4

flag: SZYGSJKJ
camType: 1
cal_tpye: 0
ver_main: 1
ver_min: 1
angle: 1
d_num: 8

[INFO] [1779270906.506208768] [mipi_cap]: ====m_d_info_l======

width: 1280

height: 1088
fx: 668.227722
fx: 668.227722
fy: 668.109619
cy: 541.561401

[INFO] [1779270906.506423393] [mipi_cap]: ====m_d_info_r======

width: 1280

height: 1088
fx: 658.154358
fx: 658.154358
fy: 658.159058
cy: 541.673401

[INFO] [1779270906.506489851] [mipi_cap]: ====r_t_info======

r11: 0.999988

r12: 0.004470
r13: 0.001999
r21: -0.004469
r22: 0.999990
r23: -0.000624
r31: -0.002002
r32: 0.000615
r33: 0.999998
tx: -79.939400
ty: 0.461299
tz: 0.277197

[WARN] [1779270906.506907517] [mipi_cap]: => ================== left awb otp data ==================

[WARN] [1779270906.506947226] [mipi_cap]: left_awb_otp_data_.awb_golden_data[0].rg_ratio: 1401
[WARN] [1779270906.506979142] [mipi_cap]: left_awb_otp_data_.awb_golden_data[0].bg_ratio: 340
[WARN] [1779270906.507008226] [mipi_cap]: left_awb_otp_data_.awb_golden_data[1].rg_ratio: 1094
[WARN] [1779270906.507035892] [mipi_cap]: left_awb_otp_data_.awb_golden_data[1].bg_ratio: 403
[WARN] [1779270906.507063934] [mipi_cap]: left_awb_otp_data_.awb_golden_data[2].rg_ratio: 880
[WARN] [1779270906.507091309] [mipi_cap]: left_awb_otp_data_.awb_golden_data[2].bg_ratio: 548
[WARN] [1779270906.507120267] [mipi_cap]: left_awb_otp_data_.awb_data[0].rg_ratio: 1416
[WARN] [1779270906.507147559] [mipi_cap]: left_awb_otp_data_.awb_data[0].bg_ratio: 334
[WARN] [1779270906.507175309] [mipi_cap]: left_awb_otp_data_.awb_data[1].rg_ratio: 1106
[WARN] [1779270906.507203059] [mipi_cap]: left_awb_otp_data_.awb_data[1].bg_ratio: 395
[WARN] [1779270906.507232392] [mipi_cap]: left_awb_otp_data_.awb_data[2].rg_ratio: 889
[WARN] [1779270906.507259934] [mipi_cap]: left_awb_otp_data_.awb_data[2].bg_ratio: 535
[WARN] [1779270906.507346975] [mipi_cap]: => ================== right awb otp data ==================
[WARN] [1779270906.507377517] [mipi_cap]: right_awb_otp_data_.awb_golden_data[0].rg_ratio: 1401
[WARN] [1779270906.507405767] [mipi_cap]: right_awb_otp_data_.awb_golden_data[0].bg_ratio: 340
[WARN] [1779270906.507433308] [mipi_cap]: right_awb_otp_data_.awb_golden_data[1].rg_ratio: 1094
[WARN] [1779270906.507460475] [mipi_cap]: right_awb_otp_data_.awb_golden_data[1].bg_ratio: 403
[WARN] [1779270906.507488183] [mipi_cap]: right_awb_otp_data_.awb_golden_data[2].rg_ratio: 880
[WARN] [1779270906.507514933] [mipi_cap]: right_awb_otp_data_.awb_golden_data[2].bg_ratio: 548
[WARN] [1779270906.507806058] [mipi_cap]: right_awb_otp_data_.awb_data[0].rg_ratio: 1432
[WARN] [1779270906.507840350] [mipi_cap]: right_awb_otp_data_.awb_data[0].bg_ratio: 348
[WARN] [1779270906.507869475] [mipi_cap]: right_awb_otp_data_.awb_data[1].rg_ratio: 1120
[WARN] [1779270906.507897558] [mipi_cap]: right_awb_otp_data_.awb_data[1].bg_ratio: 410
[WARN] [1779270906.507925100] [mipi_cap]: right_awb_otp_data_.awb_data[2].rg_ratio: 900
[WARN] [1779270906.507953391] [mipi_cap]: right_awb_otp_data_.awb_data[2].bg_ratio: 559
[WARN] [1779270906.507980183] [mipi_cap]: => ========================================================
[INFO] [1779270906.522123333] [mipi_cap]: ===stetreo calibration===
gdc_width_scale : 1
gdc_height_scale : 1
Kl :
[656.7575224009456, 0, 636.3995967335052;
0, 656.3766938297126, 540.4756754786636;
0, 0, 1]
Dl :
[-0.3299087609588053, 0.1366269992103298, -0.000135318131175941, -9.84710031787936e-05, -0.02937890519777009, 0.0001405065239949476, 4.560677311111928e-05, 4.667085000242849e-05]
Kr :
[659.0957261498398, 0, 632.5403313828651;
0, 658.9494113212542, 539.3174440945205;
0, 0, 1]
Dr :
[-0.3364821198808888, 0.1464031938938395, -9.945169177922777e-06, -0.0002291888331273915, -0.03406702140405501, -4.29001168046378e-05, -0.0002310372582815102, 0.0001254511419107697]
R_rl :
[0.9999953142616191, -0.002907409016669017, 0.0009583462919259559;
0.002906859188535815, 0.9999956099808883, 0.0005746204042934068;
-0.0009600127413120272, -0.0005718319340480337, 0.9999993756916929]
t_rl :
[-0.079168011922606;
0.0002710668686210687;
0.00333092179027396]

[WARN] [1779270906.523189749] [mipi_cap]: Target FOV 0.00° out of valid range [85.79°, 132.42°]

[WARN] [1779270906.523366749] [mipi_cap]: Use default alpha=0.0 (target FOV invalid)
[INFO] [1779270906.557143502] [mipi_cap]: ===Corrected parameters===
Rl :
[0.999135942994594, -0.006301666912573564, -0.04108109553585833;
0.006314730227134835, 0.9999800441762919, 0.0001882321424095503;
0.04107908955249437, -0.0004474855348523314, 0.9991557977403895]
Rr :
[0.9991102129125855, -0.003420897787433496, -0.04203664962976757;
0.003407530032672816, 0.9999941184384002, -0.0003896507192395557;
0.04203773534390663, 0.0002460628669746228, 0.9991159933962729]
Pl :
[688.8245310324257, 0, 687.7464141845703, 0;
0, 688.8245310324257, 540.0140228271484, 0;
0, 0, 1, 0]
Pr :
[688.8245310324257, 0, 687.7464141845703, -54.58143454102571;
0, 688.8245310324257, 540.0140228271484, 0;
0, 0, 1, 0]

[INFO] [1779270906.684268690] [mipi_cap]: left_camera_gdc bin_buf_size = 9220

[INFO] [1779270906.785651282] [mipi_cap]: right_camera_gdc bin_buf_size = 9364

[INFO] [1779270906.786256365] [mipi_cap]: ===Corrected stetreo calibration ===

Kl :
[656.7575224009456, 0, 636.3995967335052;
0, 656.3766938297126, 540.4756754786636;
0, 0, 1]
Dl :
[-0.3299087609588053, 0.1366269992103298, -0.000135318131175941, -9.84710031787936e-05, -0.02937890519777009, 0.0001405065239949476, 4.560677311111928e-05, 4.667085000242849e-05]
Kr :
[659.0957261498398, 0, 632.5403313828651;
0, 658.9494113212542, 539.3174440945205;
0, 0, 1]
Dr :
[-0.3364821198808888, 0.1464031938938395, -9.945169177922777e-06, -0.0002291888331273915, -0.03406702140405501, -4.29001168046378e-05, -0.0002310372582815102, 0.0001254511419107697]
R_rl :
[0.9999953142616191, -0.002907409016669017, 0.0009583462919259559;
0.002906859188535815, 0.9999956099808883, 0.0005746204042934068;
-0.0009600127413120272, -0.0005718319340480337, 0.9999993756916929]
t_rl :
[-0.079168011922606;
0.0002710668686210687;
0.00333092179027396]
calib file width, height : 1280,1088
gdc_width_scale, gdc_height_scale : 1, 1
rectify [f, cx, cy, baseline]: [688.825, 687.746, 540.014, 0.0792385]

[INFO] [1779270906.802108013] [mipi_cap]: csi0 ignore mclk ex attr, because not config mclk.

[INFO] [1779270906.802816471] [mipi_cap]: lpwm_enable: 1

[INFO] [1779270906.802889179] [mipi_cap]: lpwm_index: 0, trigger_source: 0, trigger_mode: 0, period: 100000, offset: 10, duty_time: 100, threshold: 0, adjust_step: 0

[INFO] [1779270906.803017345] [mipi_cap]: lpwm_index: 1, trigger_source: 0, trigger_mode: 0, period: 100000, offset: 10, duty_time: 100, threshold: 0, adjust_step: 0

[INFO] [1779270906.803059345] [mipi_cap]: lpwm_index: 2, trigger_source: 0, trigger_mode: 0, period: 100000, offset: 10, duty_time: 100, threshold: 0, adjust_step: 0

[INFO] [1779270906.803094262] [mipi_cap]: lpwm_index: 3, trigger_source: 0, trigger_mode: 0, period: 100000, offset: 10, duty_time: 100, threshold: 0, adjust_step: 0

[WARN] [1779270906.813351417] [mipi_cap]: X5 start gdc rotation and cal.

Searching camera sensor on device: /proc/device-tree/soc/cam/vcon@2 i2c bus: 4 mipi rx phy: 2
WARN: Sensor Name: sc132gs-1280p, Expected Chip ID: 0x132, Actual Chip ID Read: 0x00
WARN: Sensor Name: sc132gs-1280p, Expected Chip ID: 0x132, Actual Chip ID Read: 0x00
INFO: vp_sensor_fixed_mipi_host_1 Found sensor_name:sc132gs-1280p on mipi rx csi 2, i2c addr 0x33, config_file:linear_1088x1280_raw10_30fps_1lane.c
[INFO] [1779270907.624063948] [mipi_cap]: csi2 ignore mclk ex attr, because not config mclk.

[INFO] [1779270907.624591155] [mipi_cap]: lpwm_enable: 1

[INFO] [1779270907.624632822] [mipi_cap]: lpwm_index: 0, trigger_source: 0, trigger_mode: 0, period: 100000, offset: 10, duty_time: 100, threshold: 0, adjust_step: 0

[INFO] [1779270907.624668364] [mipi_cap]: lpwm_index: 1, trigger_source: 0, trigger_mode: 0, period: 100000, offset: 10, duty_time: 100, threshold: 0, adjust_step: 0

[INFO] [1779270907.624701322] [mipi_cap]: lpwm_index: 2, trigger_source: 0, trigger_mode: 0, period: 100000, offset: 10, duty_time: 100, threshold: 0, adjust_step: 0

[INFO] [1779270907.624734322] [mipi_cap]: lpwm_index: 3, trigger_source: 0, trigger_mode: 0, period: 100000, offset: 10, duty_time: 100, threshold: 0, adjust_step: 0

[WARN] [1779270907.632198855] [mipi_cap]: X5 start gdc rotation and cal.

[WARN] [1779270908.283946067] [mipi_cam]: [init]->cap sc132gs-1280p init success.

[INFO] [1779270908.284144317] [mipi_node]: [MipiCamNode::init]->Initing ‘/opt/tros/humble/lib/mipi_cam/config/’ at 1280x1088 via ros at 10 FPS
[INFO] [1779270908.284239150] [mipi_cap]: get calibration camera info
[INFO] [1779270908.291772767] [mipi_cap]: get calibration camera info
[INFO] [1779270908.305515709] [mipi_cam]: [start]->w:h=1280:1088.

[INFO] [1779270908.306426208] [mipi_node]: starting timer 100

=== Detected IIO Devices ===

Device: iio:device0 | Name: 34190000.adc

[INFO] [1779270908.337337798] [mipi_cap]: capture a frame, handle: 493413, id: 0, timestamps: 24193.896891, current uptime: 24193.810954, sys_timestamps: 1779270908.304047, HW timestamp: 24198.947293, trig timestamp: 24198.937433,current timestamp: 1779270908.337277, laps ms: 33.229589ms, exposure_time: 9.860000ms.
[INFO] [1779270908.355352611] [mipi_cam]: publish laps ms= 51
[INFO] [1779270908.355678944] [mipi_cam]: getImage channel=left, enc=bgr8, width=1280, height=1088, step=3840, ts=1779270908.304047, laps ms=49
[INFO] [1779270908.437987266] [mipi_cap]: capture a frame, handle: 493413, id: 1, timestamps: 24193.995593, current uptime: 24193.911632, sys_timestamps: 1779270908.402750, HW timestamp: 24199.047293, trig timestamp: 24199.037434,current timestamp: 1779270908.437954, laps ms: 35.204172ms, exposure_time: 9.859000ms.
[INFO] [1779270908.443616135] [mipi_cap]: capture a frame, handle: 231269, id: 0, timestamps: 24193.996905, current uptime: 24193.917271, sys_timestamps: 1779270908.404061, HW timestamp: 24199.047294, trig timestamp: 24199.037434,current timestamp: 1779270908.443594, laps ms: 39.532423ms, exposure_time: 9.860000ms.
[INFO] [1779270908.452195417] [mipi_cam]: publish laps ms= 50
[INFO] [1779270908.452433833] [mipi_cam]: getImage channel=left, enc=bgr8, width=1280, height=1088, step=3840, ts=1779270908.402750, laps ms=86
[INFO] [1779270908.537599319] [mipi_cap]: capture a frame, handle: 231269, id: 1, timestamps: 24194.095594, current uptime: 24194.011254, sys_timestamps: 1779270908.502750, HW timestamp: 24199.147294, trig timestamp: 24199.137435,current timestamp: 1779270908.537577, laps ms: 34.826517ms, exposure_time: 9.859000ms.
[INFO] [1779270908.541372356] [mipi_cap]: capture a frame, handle: 493413, id: 2, timestamps: 24194.095948, current uptime: 24194.015030, sys_timestamps: 1779270908.502747, HW timestamp: 24199.147651, trig timestamp: 24199.137435,current timestamp: 1779270908.541352, laps ms: 38.604975ms, exposure_time: 10.216000ms.
[INFO] [1779270908.553143093] [mipi_cam]: publish laps ms= 51
[INFO] [1779270908.553516967] [mipi_cam]: getImage channel=left, enc=bgr8, width=1280, height=1088, step=3840, ts=1779270908.502747, laps ms=96
[INFO] [1779270908.637684538] [mipi_cap]: capture a frame, handle: 231269, id: 2, timestamps: 24194.195952, current uptime: 24194.111339, sys_timestamps: 1779270908.602751, HW timestamp: 24199.247652, trig timestamp: 24199.237436,current timestamp: 1779270908.637662, laps ms: 34.910440ms, exposure_time: 10.216000ms.
[INFO] [1779270908.641388367] [mipi_cap]: capture a frame, handle: 493413, id: 3, timestamps: 24194.195995, current uptime: 24194.115049, sys_timestamps: 1779270908.602794, HW timestamp: 24199.247652, trig timestamp: 24199.237436,current timestamp: 1779270908.641371, laps ms: 38.577318ms, exposure_time: 10.216000ms.

这是我的log信息,请帮我分析为什么/image_combine_raw的图像还是没去畸变的

根据你提供的日志,我发现了关键问题

:magnifying_glass_tilted_left: 问题分析

1. GDC 硬件去畸变已启用 :white_check_mark:

从日志可以看到:

[INFO] [mipi_cap]: left_camera_gdc bin_buf_size = 9220
[INFO] [mipi_cap]: right_camera_gdc bin_buf_size = 9364
[WARN] [mipi_cap]: X5 start gdc rotation and cal.

GDC 确实初始化成功了,标定参数也从 EEPROM 读取了。

2. 但 camera_info_url 是空的 :cross_mark:

node params:
config_path: /opt/tros/humble/lib/mipi_cam/config/
camera_info_url:              # ← 这里是空的!
camera_calibration_file_path: /userdata/rdk_cam/SC132gs_dual_calibration.yaml

这就是 camera_info topic 没有输出的原因 —— 驱动没有配置发布标定参数的路径。

3. 关键:你可能订阅了错误的 Topic :warning:

日志显示你运行的是 run_cam.sh(相机驱动),但你说检查的是 /image_combine_raw —— 这个 topic 是 run_stereo.sh (StereoNet) 发布的,不是相机驱动直接发布的。


:white_check_mark: 解决方案

第一步:确认你实际订阅的 Topic

# 列出所有相机相关的 topic
ros2 topic list | grep -E "camera|image"

# 确认 run_cam.sh 实际发布的 topic 名称
ros2 topic list | grep image_raw

run_cam.sh 通常发布的 topic

  • /camera/image_raw/camera/left/image_raw + /camera/right/image_raw
  • /camera/camera_info/camera/left/camera_info + /camera/right/camera_info

/image_combine_raw 是 StereoNet 处理后的 topic,需要运行 run_stereo.sh 才会有。


第二步:验证 GDC 去畸变是否真的生效

不要依赖 camera_info,直接视觉验证

# 1. 找到相机驱动实际发布的图像 topic
ros2 topic list | grep image_raw

# 2. 用 rqt_image_view 查看
rqt_image_view /camera/left/image_raw  # 替换为你实际的 topic

# 3. 拿棋盘格或直线物体靠近相机边缘观察
# 如果直线是直的 = GDC 生效
# 如果直线是弯的 = GDC 未生效

第三步:修复 camera_info 不发布的问题

既然 camera_info_url 是空的,有两种方案:

方案 A:修改启动参数(推荐)

编辑 run_cam.sh 或其调用的 .launch.py 文件,添加 camera_info_url 参数:

# 在 run_cam.sh 中添加参数
bash run_cam.sh \
  --mipi_gdc_enable True \
  --out_format bgr8 \
  --camera_info_url file:///userdata/rdk_cam/SC132gs_dual_calibration.yaml

或者修改 launch 文件(/opt/tros/humble/lib/mipi_cam/launch/ 下):

parameters=[{
    'mipi_gdc_enable': True,
    'camera_calibration_file_path': '/userdata/rdk_cam/SC132gs_dual_calibration.yaml',
    'camera_info_url': 'file:///userdata/rdk_cam/SC132gs_dual_calibration.yaml',  # 新增
    'out_format_name': 'bgr8',
}]

方案 B:独立发布 camera_info(最稳定)

# 终端 1: 运行相机
bash run_cam.sh --mipi_gdc_enable True --out_format bgr8

# 终端 2: 独立发布标定参数
ros2 run camera_calibration camera_info_publisher \
  --ros-args \
  -p url:=file:///userdata/rdk_cam/SC132gs_dual_calibration.yaml \
  -p frame_id:=camera_link \
  --remap camera_info:=/camera/left/camera_info  # 替换为实际 topic 名称

第四步:如果你需要 /image_combine_raw(StereoNet 输出)

你需要运行 run_stereo.sh 而不是 run_cam.sh

bash run_stereo.sh \
  --mipi_gdc_enable True \
  --calib_method ros \
  --publish_rectify_bgr True \
  --codec_in_format bgr8

然后订阅:

ros2 topic echo /image_combine_raw/left/camera_info
rqt_image_view /image_combine_raw/left/rectify_image

:clipboard: 快速诊断命令

请执行以下命令并提供结果:

# 1. 确认当前运行的节点
ros2 node list | grep -E "cam|stereo"

# 2. 确认所有图像 topic
ros2 topic list | grep image

# 3. 确认图像 topic 是否有数据
ros2 topic hz /camera/left/image_raw  # 替换为你实际的 topic

# 4. 确认 camera_info topic
ros2 topic list | grep camera_info

:light_bulb: 总结

现象 原因 解决
camera_info 无输出 camera_info_url 参数为空 添加该参数或用独立节点发布
/image_combine_raw 无数据 这是 StereoNet 的 topic,run_cam.sh 不发布 运行 run_stereo.sh 或订阅相机驱动的原始 topic
图像看起来没去畸变 可能订阅了错误的 topic,或 GDC 参数未正确应用 视觉验证 + 确认 topic 名称

先确认你实际订阅的 topic 名称是否正确,这是最关键的一步!