记住一个很关键的点:我们最终求的是base 和Object之间的关系,无论是eye to hand 还是 eye in hand ,找不变的关系,推导中间量,最后推导base 和Object之间的关系。

一、eye to hand

二、eye in hand

halcon 手眼标定坐标系及坐标系之间的转换关系_WarGames_dc的博客-CSDN博客_halcon坐标系转换

三、手眼标定的坐标转换

这个是面试的时候经常问到的,我面了几家机器的还有新能源的,每次都问,要手推,还带说出为啥。

没事我们从头再来。这里涉及到的坐标系有四个:机器人基坐标系base、法兰上的工具坐标系tool、相机坐标系camera和标定板坐标系cal;此外,涉及到了四个关键的4x4齐次转换矩阵

eye  to  hand

* Calibration 01: Code generated by Calibration 01
CameraParameters := [0.038072,0.772143,3.75091e-006,3.75e-006,1042.63,770.207,2048,1536]
CameraPose := [-0.0116375,-0.0128823,0.491131,358.368,1.90647,39.3723,0]
*write_cam_par (CameraParameters,'D:/halcon/eyetohand/pose/CameraParameters.dat')stop ()
* Image Acquisition 01: Code generated by Image Acquisition 01
list_files ('D:/halcon/eyetohand', ['files','follow_links','recursive'], ImageFiles)
tuple_regexp_select (ImageFiles, ['\\.(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima|hobj)$','ignore_case'], ImageFiles)poseFiles := []
poseFiles[0] := 'D:/halcon/eyetohand/pose/campose_01.dat'
poseFiles[1] := 'D:/halcon/eyetohand/pose/campose_02.dat'
poseFiles[2] := 'D:/halcon/eyetohand/pose/campose_03.dat'
poseFiles[3] := 'D:/halcon/eyetohand/pose/campose_04.dat'
poseFiles[4] := 'D:/halcon/eyetohand/pose/campose_05.dat'
poseFiles[5] := 'D:/halcon/eyetohand/pose/campose_06.dat'
poseFiles[6] := 'D:/halcon/eyetohand/pose/campose_07.dat'
poseFiles[7] := 'D:/halcon/eyetohand/pose/campose_08.dat'
poseFiles[8] := 'D:/halcon/eyetohand/pose/campose_09.dat'
poseFiles[9] := 'D:/halcon/eyetohand/pose/campose_10.dat'
poseFiles[10] :='D:/halcon/eyetohand/pose/campose_11.dat'
poseFiles[11] :='D:/halcon/eyetohand/pose/campose_12.dat'
poseFiles[12] :='D:/halcon/eyetohand/pose/campose_13.dat'
poseFiles[13] :='D:/halcon/eyetohand/pose/campose_14.dat'TmpCtrl_ReferenceIndex := 0
TmpCtrl_PlateDescription := 'D:/halcon/eyetohand/caltab.descr'
TmpCtrl_FindCalObjParNames := ['gap_tolerance','alpha','skip_find_caltab']
TmpCtrl_FindCalObjParValues := [1,0.78,'false']
*以下是手眼标定
create_calib_data ('hand_eye_scara_stationary_cam', 1, 1, CalibHandle)
set_calib_data_cam_param (CalibHandle, 0, 'area_scan_division', CameraParameters)
set_calib_data_calib_object (CalibHandle, 0, TmpCtrl_PlateDescription)* set_calib_data (CalibHandle, 'model', 'general', 'optimization_method', 'nonlinear')
Pose1:=[]
Num:=|ImageFiles|-1
for I := 0 to 13 by 1read_image (Image, ImageFiles[I])find_calib_object (Image, CalibHandle, 0, 0, I, TmpCtrl_FindCalObjParNames, TmpCtrl_FindCalObjParValues)get_calib_data_observ_contours (Caltab, CalibHandle, 'caltab', 0, 0, I)get_calib_data_observ_points (CalibHandle, 0, 0, I, RCoord, CCoord, Index, PoseForCalibrationPlate)dev_set_color ('green')dev_display (Image)dev_display (Caltab)dev_set_color ('yellow')disp_cross (3600, RCoord, CCoord, 6, 0)dev_set_colored (3)  disp_3d_coord_system (3600, CameraParameters, PoseForCalibrationPlate, 0.01)read_pose (poseFiles[I], Pose)Pose1:=[Pose1,Pose]set_calib_data (CalibHandle, 'tool',I, 'tool_in_base_pose',Pose)
endfor
stop ()
calibrate_hand_eye (CalibHandle, Errors)
get_calib_data (CalibHandle, 'camera', 0, 'base_in_cam_pose', BaseInCamPosePre)* try
*     write_cam_par (CameraParameters,'C:/Users/86188/Desktop/Theendcamer3/CameraParameters.dat')
*     write_pose (ToolInCamPose, 'C:/Users/86188/Desktop/Theendcamer3/ToolInCamPose.dat')
*     write_pose (CalObjInBasePose,'C:/Users/86188/Desktop/Theendcamer3/CalObjInBasePose.dat')
* catch (Exception)* do nothing
* endtry
* get_calib_data (CalibHandle, 'calib_obj_pose', [0, TmpCtrl_ReferenceIndex], 'pose', CameraPose)
dev_get_preferences ('suppress_handled_exceptions_dlg', PreferenceValue)
dev_set_preferences ('suppress_handled_exceptions_dlg', 'true')
* 显示误差值
dev_set_preferences ('suppress_handled_exceptions_dlg', PreferenceValue)
dev_display (Image)
Message := 'Quality of the results:      root mean square    maximum'
Message[1] := 'Translation part in meter:      ' + Errors[0]$'6.4f' + '           ' + Errors[2]$'6.4f'
Message[2] := 'Rotation part in degree:        ' + Errors[1]$'6.4f' + '           ' + Errors[3]$'6.4f'
disp_message (3600, Message, 'window', 12, 12, 'black', 'true')
*识别
* Image Acquisition 01: Code generated by Image Acquisition 01* open_framegrabber ('KsjCamera_MT_x86', 1, 1, 0, 0, 0, 0, 'progressive', 8, 'default', -1, 'false', 'default', '1', 0, -1, AcqHandle)
* grab_image_start (AcqHandle, -1)
* while (true)
*     grab_image_async (Image, AcqHandle, -1)
*     rgb1_to_gray (Image, GrayImage)
*     scale_image (GrayImage, ImageScaled, 3.86364, -62)
*     threshold (ImageScaled, Regions, 84, 255)
*     connection (Regions, ConnectedRegions)
*     select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 6261.18, 115385)
*     area_center (SelectedRegions, Area, Row, Column)*先转世界
*     image_points_to_world_plane  (CameraParameters,CameraPose, Row, Column, 'm', X, Y)
*     pose_invert (BaseInCamPosePre, CamInBasePosePre)
*     pose_compose (CamInBasePosePre, CameraPose, ObjInBase)
*     pose_to_hom_mat3d (ObjInBase, ObjInBaseHomMat3D)
*     affine_trans_point_3d (ObjInBaseHomMat3D, X, Y, 0, Qx, Qy, Qz)* endwhile
* close_framegrabber (AcqHandle)

eye in hand:


CameraParameters := [0.00540942,-772.779,3.19882e-006,3.2e-006,995.629,706.461,2048,1536]
CameraPose := [-0.000755431,8.62376e-006,0.0876035,0.653457,359.717,272.888,0]list_files ('D:/halcon/eyeinhand1205/images', ['files','follow_links','recursive'], ImageFiles)
tuple_regexp_select (ImageFiles, ['\\.(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima|hobj)$','ignore_case'], ImageFiles)
num:=|ImageFiles|
* 将所有的pose文件都提出来放到  poseFiles 的数组中
poseFiles := []
poseFiles[0] := 'D:/halcon/eyeinhand1205/pose/campose_01.dat'
poseFiles[1] := 'D:/halcon/eyeinhand1205/pose/campose_02.dat'
poseFiles[2] := 'D:/halcon/eyeinhand1205/pose/campose_03.dat'
poseFiles[3] := 'D:/halcon/eyeinhand1205/pose/campose_04.dat'
poseFiles[4] := 'D:/halcon/eyeinhand1205/pose/campose_05.dat'
poseFiles[5] := 'D:/halcon/eyeinhand1205/pose/campose_06.dat'
poseFiles[6] := 'D:/halcon/eyeinhand1205/pose/campose_07.dat'
poseFiles[7] := 'D:/halcon/eyeinhand1205/pose/campose_08.dat'
poseFiles[8] := 'D:/halcon/eyeinhand1205/pose/campose_09.dat'
poseFiles[9] := 'D:/halcon/eyeinhand1205/pose/campose_10.dat'
poseFiles[10] :='D:/halcon/eyeinhand1205/pose/campose_11.dat'
poseFiles[11] :='D:/halcon/eyeinhand1205/pose/campose_12.dat'* 设置参考位置 一般默认是第一张图的位置
TmpCtrl_ReferenceIndex:=0
* 设置第一步的标定板的描述文件
TmpCtrl_PlateDescription:='D:/halcon/eyeinhand1205/caltab.descr'
* 设置在标定的图像中找到标定板的参数
TmpCtrl_FindCalObjParNames := ['gap_tolerance','alpha','skip_find_caltab']
* TmpCtrl_FindCalObjParNames  对应的值
TmpCtrl_FindCalObjParValues := [1,1,'false']
* TmpCtrl_FindCalObjParNames 和TmpCtrl_FindCalObjParValues 在find_calib_object 的时候使用
* ==========================================================================================
* 创建手眼标定的模板* 第一个参数表示是手在眼上还是手在眼外  这个是手在眼上 所以 'hand_eye_scara_moving_cam'* 第二个参数:相机的个数* 第三个参数:标定板的个数* 最后一个参数表示这个的句柄
create_calib_data ('hand_eye_scara_moving_cam', 1, 1, CalibDataID)
* 设置标定模型中相机的参数* 第一个参数表示的是标定模型的句柄* 表示设定标定板中的相机的索引* 第三个参数:表示是相机的类型,是面阵相机还是线阵相机 area_scan_division 表示面阵相机* 最后一个参数表示 设置的标定模型中相机的什么参数:这里设定的是内参即CameraParameters
set_calib_data_cam_param (CalibDataID, 0, 'area_scan_division', CameraParameters)
* 设置标定板的资料* 第一个参数表示的是标定模型的句柄* 表示设定标定板中的标定板的索引* 第三个参数:是标定板的描述文件
set_calib_data_calib_object (CalibDataID, 0, TmpCtrl_PlateDescription)
Pose1:=[]
* 从标定的12张图像中找到相对于的标定的的轮廓和mark标定
for I := 0 to |ImageFiles|-1 by 1read_image (Image, ImageFiles[I])* 在采集的图像姿态中找到标定板* Image* 标定模型的句柄* 标定模型中相机的索引* 标定模型中标定板的索引* I 这个是读入图像姿态的索引* TmpCtrl_FindCalObjParNames  :标定板的参数 的参数,是多个值可以根据不同的情况自己设定* TmpCtrl_FindCalObjParValues  TmpCtrl_FindCalObjParNames对应的值find_calib_object (Image, CalibDataID, 0, 0, I, TmpCtrl_FindCalObjParNames, TmpCtrl_FindCalObjParValues)* 从读入的标定图像中得到对应的轮廓信息* 得到标定的轮廓* 标定模型的句柄* marks 标定,像得到什么的, 这里是得到  标定板的* 相机索引* 标定板的索引* 读入标定图像姿态的索引get_calib_data_observ_contours (Caltab, CalibDataID, 'caltab', 0, 0, I)* 得到 标定板中黑点对应的坐标:输出一个pose* 标定模型的句柄* 相机索引* 标定板的索引  * 读入标定图像姿态的索引* 黑点的横坐标 * 黑点的纵坐标* 黑点的索引* 输出每一张标定板姿态  [0.00826224, -0.0502468, 3.42284, 2.30472, 0.84261, 264.306, 0]get_calib_data_observ_points (CalibDataID, 0, 0, I, RCoord, CCoord, Index, PoseForCalibrationPlate)dev_set_color ('green')dev_display (Image)dev_display (Caltab)dev_set_color ('yellow')disp_cross (3600, RCoord, CCoord, 6, 0)dev_set_colored (3)  disp_3d_coord_system (3600, CameraParameters, PoseForCalibrationPlate, 0.01)*从生成的.dat文件即 poseFiles 读出每对应的pose文件read_pose (poseFiles[I], Pose) * 将每一个新的pose 添加到新的数组中Pose1:=[Pose1,Pose]* 下面的这句是很重要的 表示的是要生产的姿态的方式:从***到*** 的姿态set_calib_data (CalibDataID, 'tool',I, 'tool_in_base_pose',Pose)endfor
*  标定
calibrate_hand_eye (CalibDataID, Errors)
*  从标定模型 得到tc的关系,这个就是我们辛辛苦苦要得到的数据  tool->Carmer 的姿态
get_calib_data (CalibDataID, 'camera', 0, 'tool_in_cam_pose', Tool_CameraPose)
*  从标定模型中(获取参考(世界)坐标系)相对于机械手基础坐标系的关系
get_calib_data (CalibDataID, 'calib_obj', 0, 'obj_in_base_pose', Object_BasePose)
stop ()dev_get_preferences ('suppress_handled_exceptions_dlg', PreferenceValue)
dev_set_preferences ('suppress_handled_exceptions_dlg', 'true')
* 显示误差值
dev_set_preferences ('suppress_handled_exceptions_dlg', PreferenceValue)
dev_display (Image)
Message := 'Quality of the results:      root mean square    maximum'
Message[1] := 'Translation part in meter:      ' + Errors[0]$'6.4f' + '           ' + Errors[2]$'6.4f'
Message[2] := 'Rotation part in degree:        ' + Errors[1]$'6.4f' + '           ' + Errors[3]$'6.4f'
disp_message (3600, Message, 'window', 12, 12, 'black', 'true')stop ()create_pose (0.250595,0.05462,-0.058648,0,0,-80.111, 'Rp+T', 'gba', 'point', ToolInBasePose)
* 相机标定的外参
Obj_in_camera :=  [-0.000755431,8.62376e-006,0.0876035,0.653457,359.717,272.888,0]pose_invert (Tool_CameraPose, CamInToolPose)
pose_compose (ToolInBasePose, CamInToolPose, CamerInBase)
pose_compose (CamerInBase, Obj_in_camera, ObjectInBase)
stop ()* Image Acquisition 01: Code generated by Image Acquisition 01
open_framegrabber ('KsjCamera_MT_x64', 1, 1, 0, 0, 0, 0, 'progressive', 8, 'default', -1, 'false', 'default', '4', 0, -1, AcqHandle)
grab_image_start (AcqHandle, -1)grab_image_async (Image, AcqHandle, -1)
* Image Acquisition 01: Do somethingrgb1_to_gray (Image, GrayImage)threshold (GrayImage, Regions, 9, 27)connection (Regions, ConnectedRegions)select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 207890, 425975)area_center (SelectedRegions, Area, Row, Column)* read_cam_par ('C:/Users/admin/Desktop/epson_eye_in_hand/param/cameraParam.cal', CameraParam)
* 通过相机的内外参,将特征点的像素坐标转换成相应的世界坐标image_points_to_world_plane  (CameraParameters,Obj_in_camera,  Row, Column, 'm', X, Y)
* write_cam_par (CameraParameters, 'C:/Users/86188/Desktop/campar.dat')
* write_pose (Obj_in_camera, 'C:/Users/86188/Desktop/campose.dat')
* 通过世界坐标系相对于机械手基础坐标系的关系,计算出变换矩阵
pose_to_hom_mat3d (Object_BasePose, base_H_obj)
* Z := [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
affine_trans_point_3d (base_H_obj, X, Y, 0, Qx, Qy, Qz)
close_framegrabber (AcqHandle)* 识别
* Image Acquisition 01: Code generated by Image Acquisition 01

上面这个是去年7月份在公司做的,现在没有机器人,等有了重新做一个标定,这个对三维理解太重要了

halcon 手眼标定原理推导相关推荐

  1. 遨博协作机器人ROS开发 - 机器人手眼标定原理

    目录 一.简介 二.环境版本 三.学习目标 四.知识储备 五.课堂小结 六.课后练习 一.简介 大家好,欢迎关注遨博学院带来的系列技术分享文章(协作机器人ROS开发),在前面课程中我们讲解了Intel ...

  2. 标定学习笔记(六)-- Halcon手眼标定例程:Hand-eye-Calibration with a stationary cam

    1  问题概述 本例程演示了如何对一个 Eye-to-Hand 问题进行手眼标定,即相机与机器人基座是固定不动的,用于进行标定的标定板则固定于机械手末端的夹具上. 在本例程中,手眼标定的目的是为了解出 ...

  3. 相机标定和双目相机标定标定原理推导及效果展示

    文章目录 前言 一.相机标定 1.相机的四个坐标系 2.相机的畸变 二.张正友标定法 1.求解内参矩阵与外参矩阵的积 2.求解内参矩阵 3.求解外参矩阵 4.标定相机的畸变参数 5.双目标定 6.极线 ...

  4. 手眼标定eye-in-hand(一)AX=XB方程推导

    1. 前言 本文主要介绍eye-in-hand的手眼标定,引用OpenCV的文档原话和原图1:"The following picture describes the Hand-Eye ca ...

  5. 物体位姿估计精度验证实验(涉及位姿估计,手眼标定,机械臂运动)

    物体位姿估计精度验证实验(涉及位姿估计,手眼标定,机械臂运动) 1.位姿估计 2.手眼标定 Opencv 手眼标定函数calibrateHandEye() (1)Eye in Hand (1)Eye ...

  6. (已修正精度 1mm左右)Realsense d435i深度相机+Aruco+棋盘格+OpenCV手眼标定全过程记录

    文章目录 2023.5更新 ------------------下面为原文--------------------- 一.前期准备 1.1 手眼标定原理 1.2 Aruco返回位姿的原理 1.3 生成 ...

  7. 手眼标定算法Tsai-Lenz代码实现(Python、C++、Matlab)

    你好,我是小智. 上一节介绍了手眼标定算法Tsai的原理,这一节介绍算法的代码实现,分别有Python.C++.Matlab版本的算法实现方式. 该算法适用于将相机装在手抓上和将相机装在外部两种情况 ...

  8. 机械臂手眼标定-使用AUBO机械臂自动标定

    机械臂手眼标定-使用AUBO机械臂自动标定 你好,我是小智,通过上两节的我们已经知道怎么使用已经获取的坐标数据进行计算手眼位姿,以及怎么获取标记物在相机中的位姿了,这一节我们来讲一下怎么使用AUBO的 ...

  9. 基于ROS的机械臂手眼标定-基础使用

    机械臂手眼标定-基础使用 你好,我是小智,前一段时间折腾了一段时间的机械臂的手眼标定,相关资料挺多的,但使用起来都比较复杂,新手一般比较难搞懂.于是想做一个比较简单易懂易用的手眼标定程序. 程序都是C ...

最新文章

  1. Visual Studio 在根目录下运行文件系统站点 [ Visual Studio | 文件系统 | WebDev.WebServer.EXE ]...
  2. matlab imfilter函数,Matlab的imfilter函数用法详解
  3. C# Socket编程(3)编码和解码
  4. 圆方圆学院零基础入门学习Python(绝对干货,值得学习)
  5. 浏览器显示无法解析服务器的DNS地址,使用搜狗浏览器时突然弹出无法解析服务器的DNS地址该如何处理...
  6. The 2020 ICPC Asia Macau Regional Contest A. Accelerator(分治+NTT)
  7. 容器编排技术 -- Kubernetes kubectl run 命令详解
  8. cdoj 1252 24点游戏 dfs
  9. 7-1 查找整数 (10 分)
  10. pandas.DataFrame对根据某些列对某些列进行修改
  11. Android测试驱动开发实践2
  12. linux驱动_设备驱动_问题定位_vivo_pd1932_音量键
  13. 数据库 使用 笛卡尔积两表联查 查询sql语句
  14. 【编程实践】复杂网络的基本知识及实现
  15. html中点重置和提交没反应,网页点提交按钮没反应 js提交表单,点击按钮无反应...
  16. python初学之字符串、列表与元组小练习
  17. 第四章 软件总体设计
  18. 上市公司环境投资数据(2009-2020年 )
  19. 物联网卡怎么激活 如何计费
  20. 耿丹计科16-2大家庭

热门文章

  1. 【Codeforces 1083A】The Fair Nut and the Best Path
  2. 2022-数据结构复习
  3. 什么是颜色深度(色深)
  4. MySQL 表的建立与多表联结查询
  5. 一个简单答题系统的设计与实现(二)
  6. 知+是什么,知乎知+怎么开通?
  7. LocalDatetimeUtils
  8. 立国之本——制造业,云计算、大数据助推升级中
  9. Mac软件打不开的解决方法
  10. 数据源的配置简单介绍