当前位置:网站首页>[贴装专题] 贴装流程中涉及到的位置关系计算
[贴装专题] 贴装流程中涉及到的位置关系计算
2022-08-09 10:00:00 【丶布布】
- 博客主页:https://blog.csdn.net/weixin_43197380
- 欢迎点赞 收藏 留言 如有错误敬请指正!
- 本文由 Loewen丶原创,首发于 CSDN,转载注明出处
- 现在的付出,都会是一种沉淀,只为让你成为更好的人
前言
这里假定已经完成标定,计算出了上视相机和下视相机的像素当量,不了解贴装流程和贴装涉及到的标定可以参考我的博文:
贴装流程是下视相机拍照固定位置B,计算出其中心坐标和定位相机中心的偏差,以及角度。然后吸嘴吸取产品A移至上视相机上方第一次拍照,旋转吸嘴校正计算出的产品A与固定位置B处的角度偏差,然后进行第二次拍照验证角度校正是否到位,若不到位,继续旋转吸嘴校正角度。若到位,则计算出产品A与吸嘴之间的偏差,通过前面已知的固定位置B的中心坐标,移动吸嘴,使产品A贴合至固定位置B处。下面说一下在这个贴装过程中需要用到那些数据信息以及如何进行计算:
贴装动作流程以及涉及到的位置计算
- 下视相机拍照固定位置B时,求出固定位置B中心和下视相机中心的偏差->在通过固定位置B与吸嘴之间的间距,计算处固定位置B的中心物理坐标和角度。
- 上视相机拍照产品A时,计算产品A的中心物理坐标和角度,以及产品A中心和吸嘴中心的实际偏差。
一次全拍流程:
这套贴装流程针对固定位置B和产品A分别可以被下视相机和上视相机整个拍下。
动作1:定位相机移至固定位置B中心处拍照
1、匹配结果-定位:计算下视相机图像中固定位置B(环形黑框)的中心与图像中心的像素偏差、固定位置B的角度
//m_SingelResult和m_DoubleResult为匹配计算到的固定位置B黑框左上和右下顶点
HTuple hv_centerRow = (m_DoubleResultRow + m_SingelResultRow) / 2;
HTuple hv_centerCol = (m_DoubleResultCol + m_SingelResultCol) / 2;
m_resultMatchOutLocalParam.m_localx = (double)(hv_centerCol - hv_ImgWidth.D() / 2.000);
m_resultMatchOutLocalParam.m_localy = (double)(hv_centerRow - hv_ImgHeight.D() / 2.000);
//求基板或盖子对角线连线与x轴正方向的夹角
HTuple angel, angelDeg;
HTuple offsetX = m_DoubleResultCol - m_SingelResultCol;
HTuple offsetY = m_DoubleResultRow - m_SingelResultRow;
TupleAtan2(offsetY, offsetX, &angel);
TupleDeg(angel, &angelDeg);
m_resultMatchOutLocalParam.m_rotate = 180 - angelDeg.D();
pointLocateCenter.m_u = m_resultMatchOutLocalParam.m_rotate;
2、匹配结果-定位:固定位置B的中心与图像中心的像素偏差转换成机械坐标偏差
QPointF deviationLocateMark;
deviationLocateMark1 = CameraCalibrateManager::getInstance()->getLocateCameraCaliPtr()->
transformImageDeltaToWorldDelta(QPointF(m_resultLocateMark1->m_localx, m_resultLocateMark1->m_localy));
3、匹配结果-定位:固定位置B物理中心坐标:拍照位置(即吸嘴中心位置-控制器读出) + 吸嘴中心与下视相机中心之间的安装距离(标定) + 下视相机图像中的固定位置B的中心与图像中心实际偏差(步骤2已求):
QPointF imageToWorldLocateMark1(snapLocateMark1Pos.nXCoord + ShiftCameraToPickerX + deviationLocateMark1.x(),
snapLocateMark1Pos.nYCoord + ShiftCameraToPickerY + deviationLocateMark1.y());
动作2:吸嘴吸取产品A移至上视相机处拍照
1、匹配结果-uplook:计算上视相机图像中产品A(环形黑框)的像素中心与图像像素中心的像素偏差、产品A的角度
//m_SingelResult和m_DoubleResult为匹配计算到的产品A黑框左上和右下顶点
HTuple hv_centerRow = (m_DoubleResultRow + m_SingelResultRow) / 2;
HTuple hv_centerCol = (m_DoubleResultCol + m_SingelResultCol) / 2;
m_resultMatchOutLocalParam.m_localx = -(double)(hv_centerCol - hv_ImgWidth.D() / 2.000);
m_resultMatchOutLocalParam.m_localy = -(double)(hv_centerRow - hv_ImgHeight.D() / 2.000);
//求基板或盖子对角线连线与x轴正方向的夹角
HTuple angel, angelDeg;
HTuple offsetX = m_DoubleResultCol - m_SingelResultCol;
HTuple offsetY = m_DoubleResultRow - m_SingelResultRow;
TupleAtan2(offsetY, offsetX, &angel);
TupleDeg(angel, &angelDeg);
m_resultMatchOutLocalParam.m_rotate = 180 - angelDeg.D();
pointUpLookCenter.m_u = m_resultMatchOutLocalParam.m_rotate;
注:这里加“-”是因为上视相机与下视相机安装方向相反
2、匹配结果-uplook:将产品A的像素中心与图像像素中心的偏差转换成实际机械坐标偏差
//m_resultUpLookMark1->m_localx:视觉传给软件的像素中心X方向偏差结果值
//m_resultUpLookMark1->m_localy:视觉传给软件的像素中心y方向偏差结果值
//CameraCalibrateManager::getInstance()->getUpLookCameraCaliPtr():标定的像素当量值
QPointF deviationUpLookMark1;
deviationUpLookMark1 = CameraCalibrateManager::getInstance()->getUpLookCameraCaliPtr()->
transformImageDeltaToWorldDelta(QPointF(m_resultUpLookMark1->m_localx, m_resultUpLookMark1->m_localy));
3、匹配结果-uplook:相机在上视相机处拍照位置+产品A的中心与图像中心的实际偏差(步骤2)
QPointF imageToWorldUplookMark1;
imageToWorldUplookMark1.setX(m_configure->getCalibrateParam().m_uplookCenter.centerPos.nXCoord
+ deviationUpLookMark1.x());
imageToWorldUplookMark1.setY(m_configure->getCalibrateParam().m_uplookCenter.centerPos.nYCoord
+ deviationUpLookMark1.y());
动作3:吸嘴吸取产品A贴合至固定位置B处
1、旋转吸嘴:校正固定位置B与产品A的角度偏差(pointLocateCenter.m_u和pointUpLookCenter.m_u分别由动作1-1,动作2-1计算得出)
//弧度制 负:顺时针旋转 正:逆时针旋转 _angleTowCameras为上视相机与下视相机的安装偏差
double TargetAngle = pointLocateCenter.m_u - pointUpLookCenter.m_u + _angleTowCameras;
2、移动吸嘴:计算吸嘴移至固定位置B需要移动的距离
由动作1-3计算出固定位置B的中心实际坐标、吸嘴在上视相机处旋转做完角度校正之后,可知此时吸嘴中心的实际坐标(由控制其读出),那么只要求出产品A中心与吸嘴中心的实际偏差值,补偿到吸嘴上中心的实际坐标上,即可计算出吸嘴到固定位置B处需要移动的距离,从而完成动作3的准确贴合。
1)固定位置B的中心实际坐标(由动作1-3计算得出)
pointLocateCenter.m_x = imageToWorldLocateMark1.x();
pointLocateCenter.m_y = imageToWorldLocateMark1.y();
2)下视相机与吸嘴之间的距离(标定得到)
double ShiftCameraToPickerX = _offsetCameraToPicker.m_x;
double ShiftCameraToPickerY = _offsetCameraToPicker.m_y;
3)产品A中心的实际物理坐标:上视相机中心物理坐标(标定得到)+ 上视相机中心物理坐标与产品A中心的实际偏差(动作2-2计算得出)
lidMarkCenterPos.m_x = m_uplookCenter.centerPos.nXCoord + deviationUpLookMark1.x();
lidMarkCenterPos.m_y = m_uplookCenter.centerPos.nYCoord + deviationUpLookMark1.y();
4)产品A中心与吸嘴中心的实际偏差值:产品A中心 - 吸嘴中心(吸嘴在上视相机的拍照位置,控制器读出)
double x_lidOffset = lidMarkCenterPos.m_x - x_lidCameraPos;
double y_lidOffset = lidMarkCenterPos.m_y - y_lidCameraPos;
5)吸嘴将产品A贴合至固定位置B处的需要移动的距离:固定位置B中心 - 产品A中心与吸嘴中心的偏差
double TargetX = pointLocateCenter.m_x - x_lidOffset;
double TargetY = pointLocateCenter.m_y - y_lidOffset;
注:如果吸嘴恰好吸住了产品A的中心,那么最终贴合位置坐标就是:固定位置B中心。但是,实际情况是产品A中心与吸嘴中心存在偏差的,所以需要将这部分的偏差值补偿进去。
二次全拍流程:
这套贴装流程针对固定位置B和产品A由于太大,没办法被下视相机和上视相机整体拍下,所以采用拍照下视相机和上视相机分别拍固定位置B和产品A的左上角和右下角的方式来计算最终贴合位置的。
动作1:定位相机移至固定位置B左上角和右下角拍照
1、匹配结果-定位:计算固定位置B处的中心物理坐标和角度
//匹配结果-下视相机 —— 模板和图像 像素偏差(转换成机械坐标偏差)
QPointF deviationLocateMark1, deviationLocateMark2;
deviationLocateMark1 = CameraCalibrateManager::getInstance()->getLocateCameraCaliPtr()->
transformImageDeltaToWorldDelta(QPointF(m_resultLocateMark1->m_localx, m_resultLocateMark1->m_localy));
if (task.isDoublePosMark) {
deviationLocateMark2 = CameraCalibrateManager::getInstance()->getLocateCameraCaliPtr()->
transformImageDeltaToWorldDelta(QPointF(m_resultLocateMark2->m_localx, m_resultLocateMark2->m_localy));
}
//匹配结果-下视相机 —— 模板和图像 像素偏差 + 拍照位置
QPointF imageToWorldLocateMark1(snapLocateMark1Pos.nXCoord + deviationLocateMark1.x(),
snapLocateMark1Pos.nYCoord + deviationLocateMark1.y());
QPointF imageToWorldLocateMark2(snapLocateMark2Pos.nXCoord + deviationLocateMark2.x(),
snapLocateMark2Pos.nYCoord + deviationLocateMark2.y());
//匹配结果-下视相机 —— 产品A中心点坐标及与机械x轴角度(x1+x2 / 2),(y1+y2 / 2),0,arcTan((y2-y1)/(x2-x1))
MS_DevicePoint4D pointLocateCenter;
if (task.isDoublePosMark) {
pointLocateCenter.m_x = (imageToWorldLocateMark1.x() + imageToWorldLocateMark2.x()) / 2;
pointLocateCenter.m_y = (imageToWorldLocateMark1.y() + imageToWorldLocateMark2.y()) / 2;
pointLocateCenter.m_z = 0;
pointLocateCenter.m_u = qAtan((imageToWorldLocateMark2.y() - imageToWorldLocateMark1.y())
/ (imageToWorldLocateMark2.x() - imageToWorldLocateMark1.x())) + PI;
pointLocateCenter.m_u = (pointLocateCenter.m_u * 180) / PI;
}
动作2:吸嘴吸取产品A移至上视相机处,相机分别拍产品A的左上角和右下角
//匹配结果-uplook —— 模板和图像 像素偏差(转换成机械坐标偏差)
QPointF deviationUpLookMark1, deviationUplookMark2;
deviationUpLookMark1 = CameraCalibrateManager::getInstance()->getUpLookCameraCaliPtr()->
transformImageDeltaToWorldDelta(QPointF(m_resultUpLookMark1->m_localx, m_resultUpLookMark1->m_localy));
if (task.isDoubleUpLookMark) {
deviationUplookMark2 = CameraCalibrateManager::getInstance()->getUpLookCameraCaliPtr()->
transformImageDeltaToWorldDelta(QPointF(m_resultUpLookMark2->m_localx, m_resultUpLookMark2->m_localy));
}
//匹配结果-uplook —— 模板和图像 像素偏差 + 拍照位置
MS_DevicePoint lidUplookMark1Pos;
MS_DevicePoint lidUplookMark2Pos;
if (task.isDoubleUpLookMark)
{
lidUplookMark1Pos.m_x = m_configure->getCalibrateParam().m_uplookCenter.centerPos.nXCoord
+ deviationUpLookMark1.x());
lidUplookMark1Pos.m_y = (m_configure->getCalibrateParam().m_uplookCenter.centerPos.nYCoord
+ deviationUpLookMark1.y());
lidUplookMark2Pos.m_x = (m_configure->getCalibrateParam().m_uplookCenter.centerPos.nXCoord
+ deviationUplookMark2.x());
lidUplookMark2Pos.m_y = (m_configure->getCalibrateParam().m_uplookCenter.centerPos.nYCoord
+ deviationUplookMark2.y());
}
//计算产品A和固定位置B的角度偏差并旋转吸嘴校正
//pointLocateCenter.m_u:固定位置B的角度 task.UCompensateValue:角度补偿值(固定)
pointLocateCenter.m_u = pointLocateCenter.m_u - task.UCompensateValue;
getTargetMotorAngel(pointLocateCenter, lidUplookMark1Pos, lidUplookMark2Pos, uplookSnapPos1, uplookSnapPos2, 0, targetMotorPos))
{
//产品A-Mark1(左上角、先拍)实际坐标
double x_lidMarkPos_1 = lidUplookMark1Pos.m_x;
double y_lidMarkPos_1 = lidUplookMark1Pos.m_y;
//产品A-Mark2(右下角、后拍)实际坐标
double x_lidMarkPos_2 = lidUplookMark2Pos.m_x;
double y_lidMarkPos_2 = lidUplookMark2Pos.m_y;
//产品A左上角的拍照位置(吸嘴位置1,控制器读出)
double x_lidCameraPos_1 = uplookSnapPos1.m_x;
double y_lidCameraPos_1 = uplookSnapPos1.m_y;
//产品A右下角的拍照位置(吸嘴位置2,控制器读出)
double x_lidCameraPos_2 = uplookSnapPos2.m_x;
double y_lidCameraPos_2 = uplookSnapPos2.m_y;
//产品A移至拍照位置2(拍右下角)后,其左上角新的坐标位置
double x_lidMarkPosNew_1 = _lidMarkPos_1.m_x + x_lidCameraPos_2 - x_lidCameraPos_1;
double y_lidMarkPosNew_1 = _lidMarkPos_1.m_y + y_lidCameraPos_2 - y_lidCameraPos_1;
//产品A两角点连线与X轴方向的角度
double angle_lidCenter = qAtan((y_lidMarkPos_2 - y_lidMarkPosNew_1) / (x_lidMarkPos_2 - x_lidMarkPosNew_1)) + 3.1415926;
//计算吸嘴需要旋转的角度偏差弧度转角度
angle_lidCenter = (angle_lidCenter / 3.1415926) * 180;
double TargetAngle = pointLocateCenter.m_u - angle_lidCenter + _angleTowCameras;
}
动作3:旋转吸嘴,校正角度偏差,并计算最终贴合位置
//相机中心-吸嘴中心间距(标定)
MS_DevicePoint cameraSubtractSuck;
cameraSubtractSuck.m_x = m_configure->getCalibrateParam().m_suckCenter.deviationX;
cameraSubtractSuck.m_y = m_configure->getCalibrateParam().m_suckCenter.deviationY;
//参数0指的是上视相机和下视相机安装角度偏差
getTargetMotorPos(pointLocateCenter,lidUplookMark1Pos, lidUplookMark2Pos,uplookSnapPos1, uplookSnapPos2,cameraSubtractSuck, 0, targetMotorPos);
{
//相机与吸嘴的安装位置差
double ShiftCameraToPickerX = cameraSubtractSuck.m_x;
double ShiftCameraToPickerY = cameraSubtractSuck.m_y;
//UpLook Mark1的拍照位置(吸嘴位置1,控制器读出)
double x_lidCameraPos_1 = _lidCameraPos_1.m_x;
double y_lidCameraPos_1 = _lidCameraPos_1.m_y;
//UpLook Mark2的拍照位置(吸嘴位置2,控制器读出)
double x_lidCameraPos_2 = _lidCameraPos_2.m_x;
double y_lidCameraPos_2 = _lidCameraPos_2.m_y;
//产品A-Mark1(左上角、先拍)实际坐标
double x_lidMarkPos_1 = _lidMarkPos_1.m_x;
double y_lidMarkPos_1 = _lidMarkPos_1.m_y;
//产品A-Mark2(左上角、先拍)实际坐标
double x_lidMarkPos_2 = _lidMarkPos_2.m_x;
double y_lidMarkPos_2 = _lidMarkPos_2.m_y;
//产品A有拍照位置1(左上角)移至拍照位置2(拍右下角)后,其产品-Mark1新的实际坐标位置
double x_lidMarkPosNew_1 = _lidMarkPos_1.m_x + x_lidCameraPos_2 - x_lidCameraPos_1;
double y_lidMarkPosNew_1 = _lidMarkPos_1.m_y + y_lidCameraPos_2 - y_lidCameraPos_1;
//计算产品A中心点实际坐标与角度
HTuple hv_ModelAngle;
double x_lidCenter = (x_lidMarkPosNew_1 + x_lidMarkPos_2) / 2;
double y_lidCenter = (y_lidMarkPosNew_1 + y_lidMarkPos_2) / 2;
//在Mark2位置,此时吸嘴的位置
double x_PickerPos = x_lidCameraPos_2;
double y_PickerPos = y_lidCameraPos_2;
//产品A中心与吸嘴中心的偏差
double x_lidOffset = x_lidCenter - x_PickerPos;
double y_lidOffset = y_lidCenter - y_PickerPos;
//最终贴装位置
double TargetX = _substrateMotorPos.m_x + ShiftCameraToPickerX - x_lidOffset;
double TargetY = _substrateMotorPos.m_y + ShiftCameraToPickerY - y_lidOffset;
_targetMotorPos.m_x = TargetX;
_targetMotorPos.m_y = TargetY;
}
戳戳小手帮忙点个免费的赞和关注吧,嘿嘿。 |
边栏推荐
- Cisco common basic configuration of common commands
- 蓄电池建模、分析与优化(Matlab代码实现)
- Ontology development diary 04 - to try to understand some aspects of protege
- 5.Set interface and implementation class
- 拿下跨界C1轮投资,本土Tier 1高阶智能驾驶系统迅速“出圈”
- Arrays.toString( )打印二维数组
- nacos从下载到安装集群的
- 通过程序发送 Gmail 邮件
- 【 size_t is unsigned integer (1 > 10) - > 1.
- 图表示学习(Graph Representation Learning)笔记
猜你喜欢
LeetCode147:对链表进行插入排序 画图分析 思路清晰!
electron 应用开发优秀实践
多线程(基础)
LeetCode148:排序链表 归并排序,思路清晰,C语言练习看过来!
快速解决MySQL插入中文数据时报错或乱码问题
【八大排序④】归并排序、不基于比较的排序(计数排序、基数排序、桶排序)
A Practical Guide to Building OWL Ontologies using Protege4 and CO-ODE Tools - Version 1.3 (7.4 Annotation Properties - Annotation Properties)
文件操作
Quick sort eight sorts (3) 】 【 (dynamic figure deduction Hoare, digging holes, front and rear pointer method)
.ts 音频文件转换成 .mp3 文件
随机推荐
5.Set interface and implementation class
公里周日
Golang Protobuf 处理
6.Map interface and implementation class
socket实现TCP/IP通信
收到人生第一笔五位数工资
[Machine Learning] Basics of Data Science - Basic Practice of Machine Learning (2)
Browser error classification
MySQ事务控制语言-TCL,进来学习!
LeetCode(剑指 Offer)- 25. 合并两个排序的链表
7.Collections tool class
8. Recursively traverse and delete cases
EndNote使用指南
【八大排序①】插入排序(直接插入排序、希尔排序)
Super detailed MySQL basic operations
Ontology Development Diary 03 - When debugging is in progress
抛出一个问题? Mysql环境下进行Count操作执行的时候速度很慢_需手动给主键添加索引---MySql优化001
KMP& sunday
【八大排序③】快速排序(动图演绎Hoare法、挖坑法、前后指针法)
Arrays.toString( )打印二维数组