concepts
坐标系与符号约定
这一节是整个系统里最容易出错、也最不能含糊的地方。约定先定死,再写代码。
这是最重要的一节。 视觉与运动结合的项目,一大半的诡异问题最后都查到「符号搞反了」 或者「两边对坐标系的理解不一样」。所以约定必须写死、写在文档里、所有人照抄。
四个坐标系
世界坐标系 W 台面,右手系,单位 mm
├── 机械坐标系 M 各轴的机械零点(回零后的原点)
├── 工件坐标系 P 工件/载具上的基准,通常由基准点(fiducial)定义
└── 图像坐标系 I 像素,原点在左上角,u 向右、v 向下,单位 px
└── 相机坐标系 C 光心为原点,Z 沿光轴向外
约定(照抄,不要自己发挥)
| 项 | 约定 |
|---|---|
| 世界系手性 | 右手系。X 向右,Y 向后(远离操作者),Z 向上 |
| 旋转正方向 | 绕轴逆时针为正(从轴正方向往原点看) |
| 图像 v 轴 | 向下为正(这是所有相机 SDK 的习惯,别改) |
| 角度单位 | 内部一律 rad,只在界面上显示 deg |
| 长度单位 | 内部一律 mm,像元尺寸用 µm 标注但内部换算成 mm |
| 变换记法 | T_A_B 表示「把 B 系中的点变到 A 系」,即 p_A = T_A_B · p_B |
| 复合顺序 | T_A_C = T_A_B · T_B_C,下标首尾相接,看一眼就知道对不对 |
图像 Y 向下带来的坑
图像里 v 向下、世界里 Y 向后,这两个方向是相反的。 所以从图像到世界的 2D 相似变换里必然出现一个符号翻转:
[x_W] [ s·cosθ s·sinθ ] [ u ] [tx]
[y_W] = [ s·sinθ -s·cosθ ] [ v ] + [ty]
↑
这个负号不是笔误
【坑】 如果你把这个负号漏了,标定仍然会「收敛」,残差看起来也不大, 但 Y 方向的运动会整体反向。症状是:X 对得上,Y 越走越远。 遇到这个症状,先回来看这个负号,不要去怀疑相机。
手眼:两种构型
| 构型 | 相机装在哪 | 要标的是 | 典型场景 |
|---|---|---|---|
| 眼在手上(eye-in-hand) | 装在运动轴上,跟着动 | T_Tool_Cam |
相机跟随 Z 轴上下找焦 |
| 眼看手(eye-to-hand) | 固定在机架上 | T_World_Cam |
固定工位上方俯拍 |
【坑】 两种构型的求解公式不同,而且用错了不会报错—— 它会给你一个残差很小但完全错误的结果。标定向导里第一步就要你选构型,别点快了。
判断符号对不对的土办法
不要靠推公式,靠做一次实验:
- 让 X 轴走
+10 mm; - 看图像里标记点往哪边移动了多少像素;
- 用你的变换把这个像素位移换算回 mm,看是不是
+10。
对不上就是符号反了或者轴映射错了。这一步在虚拟设备上做,一分钟就能验完, 在真机上做要半小时并且有撞机风险。
命名规范
代码里变量名必须带坐标系后缀,不允许出现裸的 x、pos:
var pTargetW = new Point2d(120.5, 80.0); // 世界系,mm
var pTargetI = new Point2d(1204.0, 768.0); // 图像系,px
var tWorldCam = calib.Get<Transform2d>("T_World_Cam");
var pMeasuredW = tWorldCam * pMeasuredI; // 一眼能看出下标接得上这条规矩看起来啰嗦,但它让「符号搞反」这类问题在代码评审阶段就能被发现, 而不是等到机器撞上去。
最后更新: 2026/9/21
这页有帮助吗?