模型、协议、运动学都对了,抓取为什么还会差几毫米到几厘米?因为从"电"到"眼"的每一层都有出厂偏置。本专题按五步走:① 机械臂零位标定 → ② TCP 标定(四点法)→ ③ 相机内参标定 → ④ 手眼标定 → ⑤ 抓取验证——全部对应本仓库 ros2_ws 里现成的工具、配置与讲义步骤,每部分配一个可调交互,最后把 5mm、>85% 这些散落数字串成一条合格链。
教学目标:拿到"抓偏了"的反馈时,能先分类再动手——是零点漂了、工具点没算对、尺子错了,还是"眼"装的位置想错了。
| 症状 | 像什么 | 归属象限 | 对应部分 |
|---|---|---|---|
| 发"全零"指令臂不笔直/不水平 | 整臂系统性歪一个固定角 | ① 电零位 | 第 1 部分 · 机械臂零位标定 |
| 换个姿态抓,落点方向跟着绕圈偏 | 固定方向准、换姿态就画圆 | ② 工具点(TCP) | 第 2 部分 · TCP 标定(四点法) |
| 视觉算出的目标随距离越远越偏 | 近处还行、远处越抓越歪 | ③ 光学内参 | 第 3 部分 · 相机内参标定 |
| 不同观察姿态下整片区域平移偏 | 换个姿势看,偏移方向跟着变 | ④ 空间外参(手眼) | 第 4 部分 · 手眼标定 |
| 单项都"应该"好了,真机还是抓不稳 | 流程/时序/统计层面的问题 | — 系统级 | 第 5 部分 · 抓取验证 |
| 部分 | 教学目标 | 案例(工具/出处) | 可视化 / 交互方案 | 衔接 |
|---|---|---|---|---|
| 1 机械臂零位标定 | 理解"电中位≠机械中位",会跑 servo_calib 五步并解释 offset 生效边界 | calibration/servo_calib_gui.py + servo_offsets.yaml(PWM−1500);讲义实验3 步骤3c |
J2/J3 零位偏移滑块 → 侧视连杆"指令目标 vs 实际姿态"对比,Apply 校准一键对齐 | EXP-05 §08 · §10 |
| 2 TCP 标定(四点法) | 明白 TCP 是"法兰之后的等效工具点";会用四姿态顶同一尖点解出偏移;解释 FINGERTIP 0.033 的来历 | kinematics/config.py+transform.py:FINGERTIP_OFFSET_Z=0.033 / Y_TCP=0.215mm / TCP_OFFSET_Z=0.0762;讲义实验5 标定工具清单 |
四姿态法兰位姿示意 + Δ 偏移滑块 → 尖点弥散圈实时 mm 读数;"四点法求解"最小二乘一键塌缩到同一点 | EXP-06 §07 · 原理 M5 |
| 3 相机内参标定 | 读懂 K 矩阵每个数的物理含义;会评估"内参错了多少、抓取点偏多少" | HP60C 出厂 K(fx=fy=614, cx=320, cy=240)+ PLUMB_BOB(CameraPublisher.cpp);讲义实验7 7.2.2 |
针孔俯视图 + Δfx 误差注入滑块 → 同一像素在 0.3/0.6/1.0m 处的落点偏差直读(mm) | EXP-07 §07 · 原理 M6 |
| 4 手眼标定 | 说清 eye-in-hand 要解的 X 是什么;懂 14 姿态怎么设计;会跑 采集→求解→验证→接入 四步 | eye_hand_calibration 全流程(AprilTag/PnP、Tsai-Lenz、14 姿态 yaml、验收 5mm);讲义实验7 步骤4"未接入"警告 |
位姿配对变换链示意;旋转多样性/姿态数滑块 → n(n−1)/2 配对数与条件评分;深度 scale·d+offset 拟合台;接入两条路 | EXP-07 §08 · 原理 M1 |
| 5 抓取验证 | 把零位→TCP→内参→手眼→真机成功率串成一次可执行的验收流程;知道何时该重标哪一层 | joint_command 归零 / 尖点重合 / camera_info+卷尺 / verify(5mm) / EXP-07 基线(>85%) | 五步验收清单(勾选推进度条)→ 全绿输出结论卡 + "何时重标"事件速查表 | EXP-04 §08 · EXP-07 §08 |
教学目标:① 解释装配后"电零点"系统性偏移的成因与症状;② 跑通 servo_calib 五步流程;③ 明白 offset 写进 yaml 后的生效边界;④ 掌握"粗调→精调"迭代与回滚。
ros2 launch calibration servo_calib.launch.py 打开 5 关节面板 → 拖 PWM 滑块找到关节"机械中位"(如大臂真水平时 PWM=1585,而非 1500)→ Save 把 当前 PWM − 1500 = offset 写入 servo_offsets.yaml → 发全零 joint_command 验证归零笔直。讲义口径:校准是渐进的,先粗后精多轮;改前备份 cp servo_offsets.yaml servo_offsets.yaml.bak。
出处:ros2_ws/.../calibration/calibration/servo_calib_gui.py("保存偏移:当前 PWM 与中心 1500 的偏差")+ 讲义实验3 · 步骤3c(含坑表:SSH 无显示、Apply 需 arm_controller 在线)。
joint_states 实时显示。config/servo_offsets.yaml(src 与 install 两份)。/arm_controller/joint_command 全零,看臂是否笔直(讲义明确:用 joint_command 而不是 target_pose)。cp servo_offsets.yaml.bak servo_offsets.yaml 恢复。servo_offsets.yaml 只被 calibration 包的 GUI/服务读写,arm 控制链(arm_controller / kinematics)并不自动加载它——所以① GUI 里的 Apply 是"会话内补偿";② 长期生效要回到第 4 步"归零验证 + 各链路各自偏置";③ 这正是讲义坑表"校准后仍不齐 → 多轮迭代"的深层原因。教学目标:① 理解 TCP(Tool Center Point)= 法兰坐标系之后的等效工具点,不标 = 换姿态就画圆;② 掌握四点法原理与最少条件(≥4 组不同姿态、同一尖点);③ 会做四点法的最小二乘解算与弥散验收;④ 看懂仓库里 0.033 / 0.215 这些 TCP 常数从哪来。
FINGERTIP_OFFSET_Z = 0.033(实测值:指尖在 tcp_link 下方 33 mm)、TCP_OFFSET_Z = 0.0762(实测 76.25 mm)、Y_TCP = 0.215 mm(IK 里那个 asin 补偿的真身)。注意别把它们和 gripper_depth 混为一谈:33 mm 是"指尖比 tcp_link 低多少"的几何常数;gripper_depth 是"抓取点相对检测面再挪多少"的运行参数(yaml 实配 −0.040 是抬高 40 mm)。两者单位都是米,含义完全不同——很多同学会以为 −0.033 就是来自这 33 mm,那是巧合,不是因果。讲义实验5 的标定工具清单:刻度标定尺、水平仪——四点法只需再加一支可固定的尖笔/锥销,把它顶在同一纸上小孔里转四个姿态即可。
出处:ros2_ws/.../arm/kinematics/kinematics/config.py(LEVEL3_SUMMARY 称其 "Robot Calibration Parameters")+ TESTING_GUIDE.md"指尖位于 tcp_link 下方 33mm";讲义实验5·1.3 实验环境标定工具行。
p_i + R_i·t = c(c 未知、是同一个尖点)——两两相减消 c,最小二乘解工具偏移 t = (t_x, t_z, t_y),写回 config 的 TCP 常数。FINGERTIP_OFFSET_Z 这类常数后,EXP-06 下探 z−gripper_depth 才真正落到物体表面;不标 TCP,六阶段里"下探"深度全靠运气。gripper_depth 滑块在 EXP-06 §07 参数调优台。教学目标:① 读懂 K 矩阵每个数的物理含义(fx/fy 焦距、cx/cy 光心);② 明白出厂标定的边界(何时必须重标);③ 能算"内参偏了 Δ,抓取点偏多少"——把抽象误差变成毫米。
CameraPublisher.cpp 出厂即发布 camera_info:K = [614, 0, 320; 0, 614, 240](640×480、PLUMB_BOB 五畸变系数);抓取链读它做反投影,AprilTag 检测还用畸变系数做 PnP(第 4 部分手眼的前置)。验证读法:ros2 topic echo /camera/color/camera_info --once。
出处:ros2_ws/.../examples/camera/HP60C/src/ascamera/src/CameraPublisher.cpp(distortion_model=PLUMB_BOB);讲义实验7 步骤3 反投影公式与"内参从 camera_info 的 K 矩阵获得"。
| 距离 | 真值 X | 误用后 X′ | 偏差 |
|---|
camera_calibration 包最小二乘解 K+畸变 → 写回驱动或 camera_info。本车 K 为出厂值,日常只做"读取 + 距离合理性复核"(第 5 部分卷尺抽查互为印证)。教学目标:① 说清 eye-in-hand 下待求的 X = T_cam_ee 是什么、方程怎么成立;② 理解 14 个采集姿态为什么那样设计(旋转多样性);③ 跑通 采集→求解→验证→接入 全流程,并知道讲义"未接入"的坑怎么填。
calibration_poses.yaml:pitch 3.14/2.80/2.44 三档、左右 ±6cm、高低错落;注释原话"AX=XB 需要足够的旋转多样性 >60°,相邻 >15°",ALL_PAIRS 全配对、最小旋转 8°、有效位姿 ≥10)→ compute_hand_eye_transform 解方程(Tsai-Lenz 默认 / Horaud,顺带拟合深度 scale·d+offset)→ verify_calibration 换个位置放板报 3D 误差,合格阈值默认 5.0mm。⚠ 讲义原话:标定会话与深度校正"当前未接入抓取链路",visual_grasp 默认仍走 URDF 固定外参。
出处:eye_hand_calibration 的 hand_eye_solver.py(AX=XB 定义与算法)、calibration_poses.yaml(姿态设计)、verify_calibration.launch.py(pass_threshold_mm=5.0)、apply_correction.launch.py;讲义实验7 步骤4 第 5 条。
ros2 launch eye_hand_calibration collect_data.launch.py——臂按 14 姿态逐个到位(settle 2s),每位姿记录 T_ee_base(TF/关节正解)与 T_tag_cam(AprilTag PnP),存会话 ~/.ros/eye_hand_calib/calibration_*。ros2 run eye_hand_calibration compute_hand_eye_transform——位姿两两配对构 A、B,解 A·X = X·B 得 X = T_cam_ee;同会话顺带拟合深度线性校正(免费副产物)。ros2 launch eye_hand_calibration verify_calibration.launch.py——换新位置放 tag,/eye_hand_calib/verify/report 出 3D 误差,<5mm 合格。apply_correction.launch.py 重发布话题并把 visual_grasp remap 过去。不接入 = 白标。| 真值(卷尺) | raw 读数 | 校正后 | 残差 |
|---|
apply_correction 并把深度话题 remap 到校正输出。标完不接 = 第 4 部分只完成一半。教学目标:把前四部分与全课散落的数字(残余<1°、尖点重合、K=614、5mm、>85%)按依赖顺序串成一次可执行的验收——任何一环不过,后面的数字都不可信;并会用"何时重标"表应对日后变动。
joint_command 全零,五关节笔直/水平(水平仪,残余 <1° ≈ δ<42μs)。不过 → 回部分 1 再精调一轮。test_fk_ik 记录闭环残差(几何把关,不在此标定)。camera_info 确认 K=614 与分辨率一致;近/中/远三点(0.3/0.5/1.0m)看落点与深度——远端先偏即回部分 3。verify_calibration 换位放 AprilTag,报告 < 5mm(pass_threshold_mm=5.0);并确认接入生效(静态 TF / 深度 remap 已切换)。| 变动事件 | 重标 | 只需复核 |
|---|---|---|
| 舵机拆装/更换、撞后不齐 | 部分 1 零位 | ② 闭环 |
| 更换夹爪/工具/尖笔位置变了 | 部分 2 TCP 四点 | ⑤ 抽测一次 |
| 相机跌落、镜头松动/对焦变、出图分辨率改 | 部分 3 内参(厂家/棋盘格) | ③ 远端三点 |
| 相机支架/腕部拆装、换相机安装位 | 部分 4 手眼全流程 | ⑤ 真机复测 |
| 只搬动底座位置(安装关系没变) | — | ① 全零 + ⑤ 抽测 |
| 换机械臂杆件(几何变) | 超出本专题 → 几何标定 | (需毫米级量具) |