第四章 视觉定位基础:Mark点识别、基准校正、局部视觉与飞行对中
各位同学,今天咱们聊聊贴片机视觉定位这块硬骨头。说实话,我刚入行那会儿,觉得视觉嘛,不就是拍个照、算个坐标嘛,能有多难?直到第一次调试高速机,看着吸嘴在飞,相机在闪,系统在算,我才意识到——视觉定位是整个贴片机的大脑和眼睛,搞不定它,后面全是白搭。
4.1 Mark点识别——贴片机的“地标”
Mark点是什么?说白了就是PCB上的定位标记。你想想看,PCB在传送带上跑,位置肯定有偏差,没有Mark点,你让机器怎么知道该往哪儿贴?
我见过不少新手,上来就问:“Mark点随便画个圆不就行了?”嗯,没那么简单。Mark点的设计有讲究:
- 形状:实心圆最常见,也有十字形、方形。我个人偏爱实心圆,算法稳定,抗干扰强。
- 尺寸:一般直径1.0mm~3.0mm。太小了相机看不清,太大了占用PCB空间。
- 材质:铜箔裸露或镀金,与背景要有明显对比。我曾经遇到一批PCB,Mark点被绿油覆盖了,相机死活识别不出来,最后只能返工。
- 位置:至少两个,对角线放置。为什么是两个?因为一个只能定位XY,两个才能算出旋转角度。
核心要点:Mark点识别算法通常分三步——图像二值化、轮廓提取、圆心拟合。二值化阈值怎么选?我习惯用自适应阈值,因为不同批次PCB的亮度可能不一样。
// 伪代码:Mark点识别核心逻辑
bool DetectMarkPoint(Image img, Point2f ¢er, float &radius) {
// 1. 高斯滤波去噪
GaussianBlur(img, img, Size(5,5), 1.5);
// 2. 自适应二值化
threshold(img, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
// 3. 找轮廓
vector<vector<Point>> contours;
findContours(binary, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
// 4. 筛选圆形轮廓
for (auto &contour : contours) {
float area = contourArea(contour);
if (area < minArea || area > maxArea) continue;
// 圆度判断
float perimeter = arcLength(contour, true);
float circularity = 4 * PI * area / (perimeter * perimeter);
if (circularity > 0.85) { // 圆度阈值
minEnclosingCircle(contour, center, radius);
return true;
}
}
return false;
}
避坑指南:我曾经遇到过Mark点被焊盘遮挡的情况,导致识别偏移。后来我加了一个“模板匹配”的预处理步骤——先存一个标准Mark点模板,匹配到大致位置后再做精细定位。这样即使部分遮挡,也能稳定识别。
4.2 基准校正——从像素到物理坐标
识别出Mark点只是第一步,关键是怎么把像素坐标换算成贴片头的物理坐标。这里涉及三个坐标系:
| 坐标系 | 原点 | 单位 | 用途 |
|---|---|---|---|
| 图像坐标系 | 图像左上角 | 像素 | Mark点识别结果 |
| 相机坐标系 | 相机光心 | 毫米 | 相机标定后的坐标 |
| 机器坐标系 | 贴片机零点 | 毫米 | 最终运动控制用 |
基准校正说白了就是做坐标变换。我习惯用仿射变换,因为PCB的变形主要是平移和旋转,很少涉及缩放和剪切。
// 仿射变换计算
void ComputeAffineTransform(Point2f mark1_pixel, Point2f mark2_pixel,
Point2f mark1_physical, Point2f mark2_physical,
Mat &affine_matrix) {
// 两个点只能解出平移+旋转+缩放
// 实际项目中建议用3个以上Mark点做最小二乘拟合
Point2f src[] = {mark1_pixel, mark2_pixel};
Point2f dst[] = {mark1_physical, mark2_physical};
affine_matrix = getAffineTransform(src, dst);
}
// 应用变换
Point2f ApplyTransform(Point2f pixel_pt, Mat &affine_matrix) {
Mat pt_mat = (Mat_<double>(3,1) << pixel_pt.x, pixel_pt.y, 1);
Mat result = affine_matrix * pt_mat;
return Point2f(result.at<double>(0), result.at<double>(1));
}
注意:相机标定一定要定期做!我见过一个工厂,三个月没标定,结果贴片偏移量从0.05mm漂到了0.3mm。热胀冷缩、机械磨损都会影响标定参数。建议每周做一次快速验证。
4.3 局部视觉——贴片前的“最后一公里”
基准校正解决的是PCB整体位置偏差,但每个元件的焊盘位置还有局部偏差。这就是局部视觉登场的时候了。
局部视觉,说白了就是在贴片头到达目标位置前,用相机拍一下焊盘区域,做精细定位。我遇到过最头疼的情况是:PCB整体Mark点校正没问题,但某个QFP芯片的焊盘整体偏移了0.1mm。如果不做局部视觉,这个芯片就废了。
局部视觉的流程:
- 根据基准校正结果,粗定位到焊盘区域
- 拍摄局部图像,识别焊盘特征(通常是焊盘角点或中心)
- 计算局部偏移量,修正贴片坐标
- 将修正后的坐标发送给运动控制系统
经验之谈:局部视觉的视场大小怎么选?我一般取焊盘区域的1.5~2倍。太小了容易拍不到特征,太大了干扰多、处理慢。高速机对时间敏感,每多1ms处理时间,产能就下降一截。
4.4 飞行对中——速度与精度的平衡
飞行对中,英文叫“Flying Vision”或“On-the-fly Alignment”。什么意思呢?就是吸嘴吸起元件后,在飞往贴片位置的途中,相机抓拍元件,实时计算偏移和旋转,然后运动控制系统在飞行中完成修正。
这个技术是高速贴片机的核心。你想想看,如果每次都要停下来拍照、计算、调整,那速度就上不去。飞行对中让这些操作并行进行,产能直接翻倍。
飞行对中的关键参数:
| 参数 | 典型值 | 影响 |
|---|---|---|
| 相机曝光时间 | 50~200μs | 太短图像暗,太长运动模糊 |
| 触发延迟 | 0.5~2ms | 影响抓拍位置精度 |
| 图像处理时间 | <5ms | 决定最小修正周期 |
| 运动补偿算法 | 前馈+反馈 | 决定修正平滑度 |
// 飞行对中修正算法(简化版)
void FlyingVisionCorrection(Component &comp, MotionState &state) {
// 1. 相机触发抓拍
Image img = CameraCapture(comp.position);
// 2. 识别元件中心偏移和旋转
Point2f offset;
float angle;
DetectComponentOffset(img, offset, angle);
// 3. 计算修正量(考虑运动速度补偿)
float delta_x = offset.x + state.velocity_x * 0.001; // 1ms前馈
float delta_y = offset.y + state.velocity_y * 0.001;
float delta_theta = angle;
// 4. 发送修正指令到运动控制器
MotionController.CorrectPosition(delta_x, delta_y, delta_theta);
}
避坑指南:我曾经调试一台高速机,飞行对中总是过冲。后来发现是运动补偿没做好——相机抓拍时元件在运动,等图像处理完,元件已经跑了一段距离。解决方案是加入速度前馈,根据当前速度预测元件位置。嗯,这个坑我踩了整整一周才爬出来。
4.5 知识体系总览
说了这么多,咱们用一张图把整个视觉定位的脉络理清楚:
这张图把整个视觉定位的脉络理清楚了。从顶层的视觉定位系统,到四个核心模块,再到每个模块的关键技术,最后汇聚到高速高精度拾放控制这个最终目标。你想想看,任何一个环节出问题,最终贴片质量都会受影响。
总结一下:Mark点识别是基础,基准校正定大局,局部视觉补细节,飞行对中提速度。这四个环节环环相扣,缺一不可。我做了这么多年设备,最大的体会就是——视觉定位没有银弹,每个环节都要精打细磨。