对于标定来说,一般常见的有用于测量的线性与非线性标定,另一类就是和运动相关的标定,手眼标定。
勇哥写过许多epson机器人的手眼标定,也有halcon仿制这种方式的实现方法。
但是halcon有自己的手眼标定。
CalibObjDescr := 'calibrate_hand_eye_scara_setup_01_calplate.cpd'
CalibrationPlateThickness := 0.003
gen_cam_par_area_scan_division (0.0165251, -642.277, 4.65521e-006, 4.65e-006, 595.817, 521.75, 1280, 1024, CameraParam)
ObjectThickness := 0.001
dev_close_window ()
dev_open_window_fit_size (0, 0, 1280, 1024, 640, -1, WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
dev_update_off ()
//创建标定模型,注意这个地方第一个参数输入的是手眼标定固定相机模式
create_calib_data ('hand_eye_scara_stationary_cam', 1, 1, CalibDataID)
//设置相机参数和相机类型为area_scan_division,这里是面扫,同时相机输入参数为CameraParam
set_calib_data_cam_param (CalibDataID, 0, [], CameraParam)
//在标定模型中指定标定板所使用的标定板描述文件
set_calib_data_calib_object (CalibDataID, 0, CalibObjDescr)
for Index := 1 to 10 by 1
read_image (CalibImage, '3d_machine_vision/hand_eye/scara_stationary_cam_setup_01_calib_' + Index$'02')
//读取每一次拍照时机械手的姿态,机械手携带标定板在不同的角度拍照
read_pose ('scara_stationary_cam_setup_01_tool_in_base_pose_' + Index$'02' + '.dat', ToolInBasePose)
//设置标定模型中的标定数据,其实是设置机械手未端参数信息,
//这个信息是从上面那个函数读取进来的。
set_calib_data (CalibDataID, 'tool', Index, 'tool_in_base_pose', ToolInBasePose)
//找到标定对象
find_calib_object (CalibImage, CalibDataID, 0, 0, Index, [], [])
dev_display (CalibImage)
//从标定数据模型中得到标定对象姿态信息
get_calib_data_observ_pose (CalibDataID, 0, 0, Index, ObjInCameraPose)
//显示标定内容
disp_caltab (WindowHandle, CalibObjDescr, CameraParam, ObjInCameraPose, 1)
disp_message (WindowHandle, 'Calibration image ' + Index + ' of 10', 'window', 12, 12, 'black', 'true')
wait_seconds (0.2)
endfor
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
check_hand_eye_calibration_input_poses (CalibDataID, 0.05, 0.005, Warnings)
if (|Warnings| != 0)
dev_inspect_ctrl (Warnings)
stop ()
endif
//创建一个手眼标定
calibrate_hand_eye (CalibDataID, Errors)
//得到相机外参数,也就是CCD坐标系和机械手基础坐标系之间在的关系。
//即旋转矩阵和平移矢量,就是在CCD坐标系下机械手的姿态,
//这也是我们手眼标定要得到的参数,有了各个坐标系之间的这种转换关系
//就可以算出将来识别目标在机械手坐标系下的坐标。
get_calib_data (CalibDataID, 'camera', 0, 'base_in_cam_pose', BaseInCamPosePre)
disp_preliminary_result (WindowHandle, BaseInCamPosePre, Errors)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
read_image (ImageRef, '3d_machine_vision/hand_eye/scara_stationary_cam_setup_01_calib_ref')
//得到标定姿态
get_calib_plate_pose (ImageRef, CameraParam, CalibObjDescr, ObjInCamPoseRef)
//读取此时机械手的姿态数据
read_pose ('scara_stationary_cam_setup_01_tool_in_base_pose_ref.dat', ToolInBasePoseRef)
//确定读入标定板目标Z方向的值
fix_scara_ambiguity_stationary_cam (BaseInCamPosePre, ToolInBasePoseRef, ObjInCamPoseRef, ZCorrection)
//设置3D坐标原点,BaseInCamPose为新的3D位置,也就是在CCD坐标系下
//机械手基础坐标系的姿态
set_origin_pose (BaseInCamPosePre, 0, 0, ZCorrection, BaseInCamPose)
disp_final_results (WindowHandle, BaseInCamPosePre, BaseInCamPose)
disp_end_of_program_message (WindowHandle, 'black', 'true')
//姿态转换函数,因为前面求解的是机械手在CCD坐标系下的位置,这里
//转换成CCD在机械坐标下的姿态,并且赋值给变量CamInBasePse
pose_invert (BaseInCamPose, CamInBasePose)
//创建目标在CCD坐标系下的姿态信息
create_pose (0.0035, -0.0128, 0.7981, 1.345, 356.158, 180.194, 'Rp+T', 'gba', 'point', ObjInCamPose)
//根据CCD在机械手基础坐标系下的姿态和目标在CCD坐标系下的姿态求解目标
//在机械手基础坐标系下的姿态,有了这个姿态就可以控制机械手去抓取这个目标
//这就是我们要进行手眼标下的最终目的
pose_compose (CamInBasePose, ObjInCamPose, ObjInBasePose)
//设置3D坐标原点,MPInCamPose为新的3D位置,也就是在CCD坐标系下
//测量板的姿态
set_origin_pose (ObjInCamPoseRef, 0, 0, CalibrationPlateThickness - ObjectThickness, MPInCamPose)
//保存在机械手下CCD的姿态
write_pose (CamInBasePose, 'cam_in_base_pose.dat')
//保存相机的内参
write_cam_par (CameraParam, 'camera_parameters.dat')
//保存在CCD坐标系下的测量板的姿态
write_pose (MPInCamPose, 'measurement_plane_in_cam_pose.dat')
可以看到,板定板的类型不是halcon那种玻璃标定板。
关于标定板的支持什么样的类型,还值得再研究一下。
2020.5.22 勇哥注:
halcon12开始支持下图所示的蜂窝标定板。
之前和之后的的halcon版本都支持阵列标定板。
即halcon12之后都支持两种类型的标定板。
#转载请注明出处 www.skcircle.com 《少有人走的路》勇哥的工业自动化技术网站。如果需要本贴图片源码等资源,请向勇哥索取。