电脑端命令均在工程根目录执行,采集数据和标定结果保存到 cali/;
板端命令按对应章节进入设备部署目录。
打印文件:tidesense-aprilgrid-a4-6x4-32mm.pdf。 Kalibr 配置:tidesense-aprilgrid-a4-6x4-32mm.yaml。 PNG 仅用于预览,请打印 PDF。
容器构建与自动转换/标定脚本见 Podman / Kalibr 使用说明。 主机不需要安装 ROS 1:
# 仅首次搭建需要构建;当前机器已构建完成。
scripts/calibration/kalibr/build.sh- A4 横向,297 × 210 mm,单页矢量图。
- AprilGrid:6 列 × 4 行,tag36h11,ID 0–23。
- 使用 Kalibr 官方生成器的两格黑边和对称角点黑方块。
- ID 0 在左下角;同一行向右递增,再向上一行。
- 单个标签黑色外边缘之间的边长:32 mm;标签间距:9.6 mm。
tagSize: 0.032(米),tagSpacing: 0.3(9.6 / 32,无单位)。- 标签阵列外边缘范围:240 × 156.8 mm;包含外围角点黑方块:259.2 × 176 mm。
- 图案居中,左右留白 18.9 mm,上下留白 17 mm;文字和尺标位于留白内。
- 选择 A4、横向、实际大小 / 100%。关闭“适合页面”、缩放、海报拼接。
- 使用清晰黑白打印,贴在平整、坚硬的哑光板上,避免翘曲、气泡和反光覆膜。
- 打印后量取底部两刻线间距,应为 100 mm;再检查标签宽、高均为 32 mm。 长距离复核可测整排标签的左右黑边,长度应为 240 mm。
- 如果存在均匀缩放,应重新按原尺寸打印,或把 YAML 的
tagSize改为实测米数; 等比缩放时tagSpacing仍为 0.3。若横纵比例不同或纸张不平,请重新制作。 - 两颗 OV9281 共用这一张板。用实际 VIO 所采用的分辨率、裁剪及固定镜头设置采集标定数据。 让左右相机都有清晰可辨的共同标签,并采集不同位置、倾角和距离,覆盖画面中央与边缘。 A4 的可用距离取决于镜头视场、对焦和图像中标签像素数,不能仅凭 50 mm 基线确定。
- Kalibr 命令中设置
--target为上述 YAML。采集场景中隐藏其他 AprilTag。
前半部分完成双目内参、畸变和外参标定;后面的“相机–IMU 联合标定”章节说明
如何使用 --imu auto 同步录制 IMU,进一步估计相机–IMU 外参和时间偏移。
- 左相机:I2C 7 位地址
0x10、2 lane;右相机:0x60、1 lane;设计基线 50 mm。 - 如果一颗绕光轴倒装 180°,但两颗仍朝向同一方向,Kalibr 可以直接标定一正一倒的图像。 倒装会体现在双目旋转外参中,不需要为了 Kalibr 专门修改寄存器。
- 也可以先把倒装相机的输出转正,再采集标定数据。180° 对应水平和垂直同时翻转, 只翻转一个方向会成为镜像。具体 OV9281 寄存器配置需按手册与驱动确认,本流程不修改寄存器。
- 先选定最终运行时的图像方向、分辨率、裁剪和镜头焦点,再标定。 标定与 SchurVINS 运行必须使用相同图像配置;标定后改方向或裁剪,应重新标定,不能直接沿用旧参数。 Kalibr 支持倒装不代表当前 SchurVINS 的匹配实现已验证支持该安装方式。
以下距离和像素数是针对这张 A4 板、640×400 图像的采集建议起点,不是镜头规格或已实测的有效范围。 尚未给定镜头视场和最近清晰距离,应同时观察左右图像调整:
| 项目 | 建议 |
|---|---|
| 初始位置 | 板面距镜头约 40–60 cm,先正对双目共同视野中央 |
| 远近变化 | 清晰且可见的前提下,尝试约 30–80 cm;太近失焦/出框就后退,太远标签太小就靠近 |
| 图案大小 | 正对时让 240 mm 宽的标签阵列约占画面宽度 50%–80%;不要只拍中央一小块 |
| 标签清晰度 | 单个标签外黑边边长尽量达到 约 30–40 像素或更多,这是操作参考,不是检测器硬阈值;最终看实际角点检测 |
| 倾斜 | 围绕水平轴、竖直轴分别尝试约 ±15°、±30°,再加入画面内旋转;避免侧得太厉害导致标签变窄 |
| 采集时长 | 先用 5 对/秒采集 60–120 秒,约 300–600 对输入;姿态覆盖比重复帧数更重要 |
固定 TideSense,移动标定板。推荐顺序:
- 中央正对,调整距离和照明,让两颗相机都能看到清晰的共同标签。
- 把板缓慢移到画面的左、右、上、下和四角,覆盖两颗相机的边缘区域。 边缘采样可让部分板出框,但需要足够标签可检测,并保留大量两路共同观测。
- 在不同位置加入左右倾斜、上下倾斜和少量画面内旋转;不要全程板面平行于相机。
- 再改变远近距离,重复若干倾斜姿态。移动到一个姿态后短暂停稳约 0.5–1 秒,减少运动模糊。
- 保持均匀照明,避免黑块反光、白纸过曝、手遮住标签或纸板弯曲;背景隐藏其他 AprilTag。
若已知水平视场角 θ,正对时可粗估距离:d ≈ 0.240 / (2 × q × tan(θ/2)),
其中 q 是标签阵列占图像宽度的比例。公式未考虑畸变和倾斜,只帮助找初始位置;
最终以双目预览的清晰度、共同视野和 Kalibr 检测结果为准,不能由 50 mm 基线推算拍摄距离。
以下使用 本机 ROS 2 Humble + micro-ROS Agent 采集,随后在独立的 ROS 1 / Kalibr
环境中处理。主机需已安装 Agent、rqt_image_view、rosbag2 和 rmw_cyclonedds_cpp;
Agent 安装与可选构建说明见 MICRO-ROS.md。
本机与板端通过 USB RNDIS 相通:板端 192.168.123.99,示例本机地址 192.168.123.2。
Agent 地址填写本机的实际 RNDIS IPv4,不是板端 .99。
如尚未构建,在 SDK 根目录执行:
SCHUR_WITH_MICRO_ROS=ON scripts/schurvins/build.sh将生成的 micro-ROS 程序包解压到板端;以下假设程序目录为
/mnt/data/schurvins-gcc11-static-micro-ros,相机配置为 /mnt/data/sensor_cfg.ini。
按实际部署路径修改。两颗相机都必须启用 hw_sync=1,启动前停止其他占用相机的程序。
录制前确认板端时间正确;标定过程中不改相机方向、裁剪和焦点。
以下主机命令使用 SDK 中的 XML;若主机没有 SDK,可改用程序包中同名 XML 的绝对路径。 XML 适用于 Agent、预览和录包在同一台电脑:电脑内 DDS 使用 loopback, 板端 XRCE 使用 RNDIS。主机需允许至少 2 MiB socket 接收缓冲,具体网络要求见 采集模式文档。
本机终端 A(端口 8888 已有 Agent 时直接复用):
source scripts/calibration/ros2-env.sh
export FASTRTPS_DEFAULT_PROFILES_FILE=scripts/schurvins/micro_ros/calibration-agent.xml
ros2 run micro_ros_agent micro_ros_agent udp4 -p 8888SSH 登录板子后,在板端执行:
cd /mnt/data/schurvins-gcc11-static-micro-ros
SCHUR_MICRO_ROS=1 SCHUR_MICRO_ROS_AGENT=192.168.123.2 \
SCHUR_MICRO_ROS_DOMAIN=0 \
./run.sh --calibrate /mnt/data/sensor_cfg.ini --fps 5--fps 是图像对/秒,必填,支持 0.1–20;默认持续运行,Ctrl-C 退出。
相机硬件仍以 FSIN 20 Hz 采集,程序成对抽帧发布;不会启动 VIO,未传 --imu 时不启动 IMU。
如需有限采集并保存原始 VI 时间戳诊断,可改为:
source scripts/calibration/ros2-env.sh终端 B 打开预览;可开两个窗口分别选择左右话题:
ros2 daemon stop
ros2 run rqt_image_view rqt_image_view| 话题 | 相机 | 图像 |
|---|---|---|
/tidesense/left/image_raw |
左,0x10,2 lane | sensor_msgs/msg/Image,mono8,640×400 |
/tidesense/right/image_raw |
右,0x60,1 lane | sensor_msgs/msg/Image,mono8,640×400 |
新终端设置上述 ROS 2 环境后,可分别运行 ros2 topic hz /tidesense/left/image_raw
和 ros2 topic hz /tidesense/right/image_raw 检查接收频率。确认两路持续更新、清晰后录包:
mkdir -p cali
ros2 bag record --storage sqlite3 -o cali/tidesense-stereo-calib \
/tidesense/left/image_raw /tidesense/right/image_raw一键标定双目:
scripts/calibration/kalibr.sh cali/tidesense-stereo-calib \
--output cali/tidesense-stereo-calib-kalibr鱼眼镜头使用 pinhole-equi,两个模型参数分别对应左、右摄像头:
scripts/calibration/kalibr.sh cali/tidesense-stereo-calib \
--models pinhole-equi pinhole-equi \
--output cali/tidesense-stereo-calib-kalibr以上两种模型命令按镜头选择其一。每次录制和标定使用新的输出目录;
更换结果目录时,同步修改下文 --cam 和部署命令中的路径。
结果中为 camera_model: pinhole、distortion_model: equidistant。
后续相机–IMU 联合标定的 --cam 应引用这次生成的 stereo-camchain.yaml,
不再传 --models。模型切换需要重新估计参数,不能直接改旧 YAML 的模型名称。
当前 SchurVINS 自动导出和 OpenVINS 实时配置转换仍只接受 radtan;
鱼眼结果应用到这些入口前需要适配转换脚本。
先完成上述双目标定,保留 camchain-*.yaml。确认板上已经安装 SC7U22 IIO/INT1 内核和
新版 micro-ROS 程序包。Agent 和主机 ROS 2 环境设置沿用前文。
板端运行(推荐图像 20 对/秒、IMU 200 Hz):
cd /mnt/data/schurvins-gcc11-static-micro-ros
SCHUR_MICRO_ROS=1 SCHUR_MICRO_ROS_AGENT=192.168.123.2 \
./run.sh --calibrate /mnt/data/sensor_cfg.ini --fps 20 --imu auto--imu auto 启用 IMU,也可指定 --imu /dev/iio:device0。不加此参数则保持纯双目模式。
--fps 只改变图像发布频率,IMU 固定为 200 Hz。
主机新终端:
source scripts/calibration/ros2-env.sh
mkdir -p cali
ros2 bag record --storage sqlite3 -o cali/tidesense-imucam \
/tidesense/left/image_raw /tidesense/right/image_raw /tidesense/imu这一步固定 AprilGrid,手持整个 TideSense 运动。先从约 40–60 cm 的清晰共同视野开始, 实际距离按前文的画面占比和标签像素大小调整。镜头、图像方向、裁剪与双目标定时保持一致。
- 建议录制约 60–120 秒,开始和结束各留几秒静止数据。
- 在标定板持续可见的前提下,分别绕三个轴做平滑往返旋转,再加入各轴的平移和组合运动。
- 幅度以保持可见、清晰为准,避免只绕一个轴、只做平面运动或全程静止。
- 不要猛烈抖动或撞击;提高均匀照明、减少运动模糊。
20 Hz 图像 / 200 Hz IMU 与多轴激励依据 Kalibr 官方联合标定说明。 上述距离和时长是采集起点,仍需通过角点覆盖和结果报告判断数据质量。
scripts/calibration/kalibr.sh cali/sc7u22-static --allan建议传感器预热后,保持板子和温度稳定,延长静止记录以观察长时间漂移。 Kalibr 官方建议约 15–24 小时静止数据
scripts/calibration/kalibr.sh cali/tidesense-imucam \
--imu-cam \
--cam cali/tidesense-stereo-calib-kalibr/stereo-camchain.yaml \
--imu cali/sc7u22-imu.yaml \
--output cali/tidesense-imucam-kalibr替换 --cam 为双目标定结果、--imu 为已填好实测噪声参数的文件。
相机话题、模型和分辨率从 camchain 读取,IMU 话题从 IMU YAML 的 rostopic 读取;
联合模式不再传 --topics / --models。可用 --target 指定实际打印的标定板。
脚本自动校验并转换 ROS 2 bag,再运行 kalibr_calibrate_imu_camera --imu-models scale-misalignment。
默认固定陀螺加速度敏感项 A 为零;加 --estimate-g-sensitivity 可进行对照。
--imu-models calibrated 仅用于内参已校准的输入。所有新采集均保存标称 SI 数据。
转换保留所有 IMU 样本及 header 时间戳;图像仅保留时间戳精确匹配的左右帧对,
bag 索引时间取各自 header 时间,不取网络接收时间。检查分辨率与已有内参是否一致、
IMU 时间戳递增且与图像重叠,拒绝噪声参数为 null 或非正数的模板。
采集和转换保持 IMU SI 原值;联合拟合估计内参,运行配置在估计器入口应用逆模型。
--imu-cam 联合标定成功后,脚本自动在结果目录生成 schurvins.yaml,
同时保存转换脚本 export_schurvins.py 和日志 schurvins-export.log。
转换在已有 Kalibr 容器内运行,不需要重建镜像。仅双目标定缺少相机–IMU 外参,
不能生成完整 VIO 配置;--allan 和 --convert-only 不生成此文件。
已经标定完成的结果无需重跑,直接在本机执行:
scripts/calibration/kalibr.sh --export-schurvins \
cali/tidesense-imucam-kalibr-20260922-221039该目录必须包含 imucam-camchain-imucam.yaml 和 imucam-imu.yaml。
此模式不需要原始 bag、ROS 或 Podman;本机 Python 3 需要 numpy 和 PyYAML
(Ubuntu 包名 python3-numpy、python3-yaml)。默认写入该目录的 schurvins.yaml。
不覆盖已有文件;如果目录中已有之前转换的配置,可指定另一个输出文件:
scripts/calibration/kalibr.sh --export-schurvins \
cali/tidesense-imucam-kalibr-20260922-221039 \
--output /tmp/tidesense-schurvins.yaml注意:此模式的 --output 是 YAML 文件路径,其父目录需已存在;
标定模式的 --output 仍是新建的结果目录。
| Kalibr 参数 | SchurVINS 参数 / 处理 |
|---|---|
cam0 / cam1 |
cameras[0] / cameras[1];必须分别为左 / 右相机 |
intrinsics: [fx, fy, cx, cy] |
camera.intrinsics.data,顺序不变 |
distortion_coeffs: [k1, k2, p1, p2] |
camera.distortion.parameters.data;radtan 映射到 radial-tangential |
resolution: [width, height] |
image_width / image_height |
每颗相机的 T_cam_imu |
取逆矩阵得到 T_B_C,以行优先展开;B 是 SC7U22 芯片 IMU 坐标系 |
cam0 的 timeshift_cam_imu(秒) |
乘 1e9 四舍五入为 live_camera_time_offset_ns;保留正负号 |
gyroscope_noise_density |
imu_params.sigma_omega_c |
accelerometer_noise_density |
imu_params.sigma_acc_c |
gyroscope_random_walk |
imu_params.sigma_omega_bias_c |
accelerometer_random_walk |
imu_params.sigma_acc_bias_c |
四个噪声参数直接取联合标定输出 imucam-imu.yaml 的 imu0,不额外乘除采样率。
SC7U22 实际测量频率可略低于 200 Hz,转换允许 190–210 Hz,运行配置固定
imu_rate: 200。重力设为 9.80665,量程按当前 ±16g / ±2000°/s 设置。
imu_initialization 的速度与残余偏置初值为零,初始化标准差采用运行入口示例默认值;
这些是启动参数,不是 Kalibr 标定结果。
时间关系为 t_imu = t_cam + shift。实时输入以左相机时间代表同步帧对,
因此只应用 cam0 的时间补偿,保持 delay_imu_cam: 0.0,避免重复修正。
转换日志列出左右相机各自的 shift;差异超过 1 ms 时提示检查同步与标定,
不会分别移动两颗相机的图像。未输出时间标定字段时补偿为零。
转换支持当前 TideSense 的 640×400、双 pinhole-radtan 或 pinhole-equidistant、单 calibrated 或 scale-misalignment IMU。
它检查旋转矩阵、非零基线、双目/IMU 外参一致性、IMU 坐标系和噪声参数。
非有限数、非正噪声、不支持的模型或分辨率会报错;自动转换失败时,已完成的
Kalibr 原始结果仍保留,可检查 schurvins-export.log。转换通过只说明配置符合入口要求,
仍应检查 Kalibr 报告中的重投影误差、惯性残差和运动激励。
相机倒装 180° 已包含在外参中,转换不旋转图像;运行时保持标定时的图像方向、 分辨率和裁剪。不要把物理基线 50 mm 直接写回替代实测外参。
本机复制生成的配置到已安装的程序目录:
scp -O cali/tidesense-imucam-kalibr/schurvins.yaml \
root@192.168.123.99:/mnt/data/schurvins-gcc11-static-micro-ros/tidesense.yaml如果上一步指定了 --output,这里改用对应文件路径。关闭 PFC 实时预览网页并等待
约 3 秒释放 IMU,停止标定发布/其他 IMU 采集程序,然后在板端执行:
cd /mnt/data/schurvins-gcc11-static-micro-ros
export SCHUR_MICRO_ROS=0
./run.sh --vio tidesense.yaml /mnt/data/sensor_cfg.ini auto /tmp/vio-poses.csv 00 表示持续运行,Ctrl-C 停止。开始时保持静止,两颗镜头共同看向有纹理的场景。
位姿先写 /tmp,避免当前 SD 同步写盘影响实时性能;需要保留时在结束后复制出来。
LiveImu 采集标称 SI 数据,运行时仅加载 schurvins.yaml 中的一套 IMU 内参,
不需要额外校准文件或校准环境变量。imu_initialization.acc_bias 和 omega_bias
表示当前运行的残余零偏;导出器不把标定 bag 中拟合的零偏固定为长期偏移。
转换回归测试:
python3 scripts/calibration/kalibr/test_export_schurvins.py编码、位顺序、黑边及角点布局依据 Kalibr 官方生成器。 参数定义见 Kalibr calibration targets。 本目录脚本调整了 A4 页面布局,并加入尺寸核对尺。
安装 PyMuPDF 后可重建:
python3 scripts/calibration/generate_aprilgrid_a4.py已验证:PDF 为单页 A4 横向;300 dpi 渲染后,OpenCV 4.10 的 AprilTag 36h11
检测器(markerBorderBits=2)识别出全部 24 个 ID,且位置与 YAML 的行列顺序一致。
这验证了电子文件,不代表已验证实际打印误差或实拍标定精度。