1. 视觉系统概述
大家好,我是老张。做机器人视觉这行十几年了,今天咱们开始聊视觉定位系统与机械臂协同调试。第一节课,我先把最基础的东西理清楚——相机怎么成像的、坐标系怎么定义的、手眼标定到底是个啥。
你可能会问:这些基础概念有必要花一整章讲吗?我的回答是:太有必要了。我在产线上调试时,见过太多人因为坐标系搞混,折腾好几天找不到问题。说白了,视觉引导机械臂,本质上就是坐标系的来回变换。基础不牢,后面全是坑。
1.1 相机成像原理——小孔成像的现代版
相机成像,说白了就是小孔成像的升级版。光线从物体表面反射,穿过镜头,落在传感器上,形成图像。
但这里有个关键问题:三维世界是立体的,传感器是二维的。从3D到2D,信息必然有损失。深度信息没了,这就是所谓的“透视投影”。
核心公式(针孔相机模型):
u = f * (X / Z) + u0
v = f * (Y / Z) + v0
其中 (X, Y, Z) 是空间点坐标,(u, v) 是像素坐标,f 是焦距,(u0, v0) 是光心偏移。
我在项目里遇到过一件事:有个同事用鱼眼镜头做定位,直接套用针孔模型,结果偏差很大。为什么?因为鱼眼镜头的畸变太严重了,必须做畸变校正。嗯,这里要注意:实际镜头都有畸变,径向畸变和切向畸变,标定时必须处理。
我的习惯:拿到新相机,第一件事就是做内参标定。用棋盘格拍20-30张不同角度的照片,跑一遍张正友标定法。别偷懒,这一步省了,后面定位精度全完蛋。
1.2 四大坐标系——你必须要搞清楚的“空间语言”
视觉系统里,有四个坐标系来回倒腾。我刚开始学的时候,也经常搞混。后来总结了一个口诀:“像素看图,图像看面,相机看光心,世界看原点”。
| 坐标系 | 符号 | 维度 | 原点 | 单位 |
|---|---|---|---|---|
| 像素坐标系 | (u, v) | 2D | 图像左上角 | 像素 (pixel) |
| 图像坐标系 | (x, y) | 2D | 图像中心(光轴与像面交点) | 毫米 (mm) |
| 相机坐标系 | (Xc, Yc, Zc) | 3D | 相机光心 | 毫米 (mm) |
| 世界坐标系 | (Xw, Yw, Zw) | 3D | 用户自定义 | 毫米 (mm) |
它们之间的变换关系是这样的:
- 世界 → 相机:刚体变换(旋转 + 平移),也就是外参
- 相机 → 图像:透视投影(除以Z,丢掉深度)
- 图像 → 像素:缩放 + 平移(从毫米变到像素)
你想想看,机械臂要抓一个工件,视觉系统告诉机械臂“工件在像素坐标(320, 240)”,这有用吗?没用!机械臂需要的是世界坐标。所以,坐标变换就是视觉引导的核心。
我曾经踩过的坑:有一次做视觉引导焊接,工件放在传送带上。我忘了把传送带的运动模型加进世界坐标系,结果机械臂每次都焊偏。后来花了整整两天才找到原因——坐标系没考虑传送带的位移。从那以后,我每次做项目都会画一张坐标系变换图,贴在工位上。
1.3 手眼标定基础概念——让眼睛和手“对上话”
手眼标定,说白了就是求相机坐标系和机械臂基坐标系(或工具坐标系)之间的变换关系。眼睛(相机)看到了工件,手(机械臂)要去抓,中间得有个“翻译官”。
手眼系统分两种配置:
- 眼在手上(Eye-in-Hand):相机装在机械臂末端,跟着机械臂动。优点是视野灵活,缺点是标定复杂。
- 眼在手外(Eye-to-Hand):相机固定安装,机械臂在视野内活动。优点是标定相对简单,缺点是视野固定。
| 配置方式 | 相机位置 | 标定方程 | 典型应用 |
|---|---|---|---|
| Eye-in-Hand | 机械臂末端 | AX = XB | 精密装配、焊缝跟踪 |
| Eye-to-Hand | 固定支架 | AX = ZB | 码垛、分拣、上下料 |
标定方程 AX = XB 是什么意思?A 是机械臂两次运动之间的变换,B 是相机两次观测之间的变换,X 就是我们要找的手眼矩阵。说白了,就是让机械臂动一动,相机看一看,通过多组对应关系解出 X。
我的建议:初学者先从 Eye-to-Hand 开始练手。固定相机,放一个标定板在机械臂末端,让机械臂走几个不同的姿态,记录下机械臂位姿和标定板在图像中的位置。用 OpenCV 的 calibrateHandEye() 函数,几分钟就能算出结果。别一上来就搞 Eye-in-Hand,那个坑更多。
好了,这一章的基础概念就讲到这里。下面我用一张图把整个知识体系串起来,方便你理解。
这张图把本章的核心内容串起来了。上面是三大基础模块(相机成像、坐标系、手眼标定),中间是标定方法,下面是完整的调试流程。你把这个框架记在脑子里,后面每一章都是在往这个框架里填细节。
好了,第一章就到这里。记住:坐标系是视觉定位的灵魂,手眼标定是协同调试的桥梁。后面我们会一步步深入,把这些概念变成能跑起来的代码和能调通的系统。