机器人手眼标定

机器人和摄像机的手眼标定问题分为两类构型:app

  • eye-to-hand,摄像机固定,与机器人基坐标系相对位置不变。
  • eye-in-hand,摄像机安装在机器人末端,随着机器人一块儿移动。

所谓手眼系统,就是人眼睛看到一个东西的时候要让手去抓取,就须要大脑知道眼睛和手的坐标关系。若是把大脑比做B,把眼睛比做A,把手比做C,若是A和B的关系知道,B和C的关系知道,那么C和A的关系就知道了,也就是手和眼的坐标关系也就知道了。ide

相机知道的是像素坐标,机械手是空间坐标系,因此手眼标定就是获得像素坐标系和空间机械手坐标系的坐标转化关系。
在实际控制中,相机检测到目标在图像中的像素位置后,经过标定好的坐标转换矩阵将相机的像素坐标变换到机械手的空间坐标系中,而后根据机械手坐标系计算出各个电机该如何运动,从而控制机械手到达指定位置。这个过程当中涉及到了图像标定,图像处理,运动学正逆解,手眼标定等。工具

经常使用的标定方法有:九点标定
九点标定:

九点标定直接创建相机和机械手之间的坐标变换关系。
让机械手的末端去走这就9个点获得在机器人坐标系中的坐标,同时还要用相机识别9个点获得像素坐标。这样就获得了9组对应的坐标。
由下面的式子可知至少须要3个点才能求出标定的矩阵。oop


(1)、标定,Halcon中进行9点标定的算子学习

%前面求出图像坐标
area_center(SortedRegions,Area,Row,Column) %
Column_robot := [275,225,170,280,230,180,295,240,190]
%机器人末端运动到9点的列坐标
Row_robot := [55,50,45,5,0,-5,-50,-50,-50]
%机器人末端运动到9点的行坐标
vector_to_hom_mat2d(Row,Column,Row_robot,Column_robot,HomMat2D)
%求解变换矩阵,HomMat2D是图像坐标和机械手坐标之间的关系

(2)、求解优化

affine_trans_point_2d(HomMat2D,Row2,Column2,Qx,Qy)
%由像素坐标和标定矩阵求出机器人基础坐标系中的坐标

一些特殊状况的解释:
有些状况中咱们看到相机固定在一个地方,而后拍照找到目标,控制机械手去抓取,这种就很好理解。咱们也叫作eye-to-hand
还有一种状况是相机固定在机械手上面,这种状况的标定过程实际上和相机和机械手分离的标定方法是同样的,由于相机拍照时,机械手会运动到相机标定的时候的位置,而后相机拍照,获得目标的坐标,再控制机械手,因此简单的相机固定在末端的手眼系统不少都是采用这种方法,标定的过程和手眼分离系统的标定是能够相同对待的。咱们也叫作eye-in-hand
 this

另有手眼标定的源码以下:spa

Halcon手眼标定例程注释 ——hand_eye_movingcam_calibration.hdev3d

* 
* This example explains how to use the hand eye calibration for the case where
* the camera is attached to the robot tool and the calibration object
* is stationary with respect to the robot. The robot positions the
* camera with respect to the calibration plate.
* In this case, the goal of the hand eye calibration is to determine two unknown poses:
* - the pose of the robot base in the coordinate system
*   of the calibration object (CalObjInBasePose).
* - the pose of the camera in the coordinate system of the
*   tool center point (ToolInCamPose).
* Theoretically, as input the method needs at least 3 poses of the
* calibration object in the camera coordinate system.
* However, it is recommended to use at least 10 Poses.
* The corresponding poses of the robot tool in the robot base coordinate system
* (ToolInBasePose) changes for each calibration image,
* because it describes the pose of the robot moving the camera.
* The poses of the calibration object are obtained from images of the
* calibration object recorded with the camera attached to the robot.
* To obtain good calibration results, it its essential to position
* the camera with respect to the calibration object so that the object appears
* tilted in the image.
* After the hand eye calibration, the computed transformations are
* extracted and used to compute the pose of the calibration object in the
* camera coordinate system.
dev_update_off ()
* Directories with calibration images and data files
*//设置标定图像初始图像名和初始参数文件名,便于遍历读取
ImageNameStart := '3d_machine_vision/hand_eye/movingcam_calib3cm_'
DataNameStart := 'hand_eye/movingcam_'
*//设置标定图像采集次数
**//NumImages := 14
read_image (Image, 'E:/study/科研/机器视觉学习资料/halcon练习/标定实验/标定图像/1.jpg')
dev_close_window ()
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
dev_set_line_width (2)
dev_set_draw ('margin')
dev_display (Image)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
ParamName := ['color_0','color_1','color_2','color_3','color_4','color_5','color_6','alpha_6']
ParamValue := ['red','green','blue','red','green','blue','white',0.7]
* //初始可视化机器人3D位姿中的标签矩阵,Labels for the visualized 3D object models.
tuple_gen_const (7, '', Labels)
Labels[0] := 'Robot\'s Tool'
Labels[3] := 'Robot\'s Base'
* //初始可视化机器人3D位姿中的操做指导信息
Instructions[0] := 'Rotate: Left button'
Instructions[1] := 'Zoom:   Shift + left button'
Instructions[2] := 'Move:   Ctrl  + left button'
*//设置机器人三维位姿示意图中的坐标轴箭头样式 Set size for 3D visualization in [m]
ArrowThickness := 0.005
ArrowLength := 0.05
*生成机器人3D模型,(Thickness of the arrows,Length of the arrows(输入);3D model of the robot's tool.3D model of the robot's Base(输出))
*//OM3DToolOrigin:=
*//OM3DBase:=
gen_robot_tool_and_base_object_model_3d (ArrowThickness, ArrowLength, OM3DToolOrigin, OM3DBase)
* gen_robot_tool_and_base_object_model_3d (ArrowLength, ArrowLength, OM3DToolOrigin1, OM3DBase1)
* Load the calibration plate description file.
* Make sure that the file is in the current directory or
* //设置标定板描述文件路径,便于后面读取标定板描述文件in HALCONROOT/calib, or use an absolute path.
CalTabDescr:='E:/study/科研/机器视觉学习资料/halcon练习/标定实验/caltab.descr'
CalTabFile := CalTabDescr
* 读取相机初始参数或参数文件Read the initial values for the internal camera parameters
*read_cam_par (DataNameStart + 'start_campar.dat', StartCamParam)
*StartCamParam:=['area_scan_division', 0.0117685, -2541.7, 7.32909e-006, 7.4e-006, 323.6, 245.555, 646, 493]
StartCamParam:=['area_scan_polynomial', 0.0058132, 11113.2, 9.66687e+008, -5.98123e+014, 0.279616, 0.535812, 5.60089e-006, 5.6e-006, 322.43, 235.729, 640, 480]
* 创建手眼标定模型 Create the calibration model for the hand eye calibration
* Create the calibration model for the hand eye calibration
* 创建眼随手动的手眼标定模型(标定类型、相机数、标定板数、标定数据代号)where the calibration object is observed with a camera
create_calib_data ('hand_eye_moving_cam', 1, 1, CalibDataID)
* 设置标定相机类型(标定代号、相机代号、相机类型、相机初始参数)Set the camera type used
set_calib_data_cam_param (CalibDataID, 0, [], StartCamParam)
* 设定标定板信息Set the calibration object
set_calib_data_calib_object (CalibDataID, 0, CalTabFile)
* Start the loop over the calibration images
*设定标定数据模型最优化方式Set the optimization method to be used
* ??
set_calib_data (CalibDataID, 'model', 'general', 'optimization_method', 'nonlinear')
disp_message (WindowHandle, 'The calibration data model was created', 'window', 12, 12, 'black', 'true')
* disp_continue_message (WindowHandle, 'black', 'true')
stop ()


dev_open_window (0, Width + 10, Width, Height, 'black', WindowHandleR)
set_display_font (WindowHandleR, 14, 'mono', 'true', 'false')
*遍历处理每一个标定位姿的标定图形
list_files ('E:/study/科研/机器视觉学习资料/halcon练习/标定实验/标定图像', 'files', ImageFiles)
NumImages:=|ImageFiles|
for I := 0 to NumImages - 1 by 1
    dev_set_window (WindowHandle)
    dev_clear_window ()
    *读取不一样相机位姿获取的标定板图像
    read_image (Image, ImageNameStart + I$'02d')
    dev_display (Image)
    * Search for the calibration plate, extract the marks and the
    * pose of it, and store the results in the calibration data
    * The poses are stored in the calibration data model for use by
    * the hand eye calibration and do not have to be set explicitly
   *搜索标定区域并识别标定轮廓和标定点信息
    find_calib_object (Image, CalibDataID, 0, 0, I, [], [])
    *获取标定板轮廓信息
    get_calib_data_observ_contours (Caltab, CalibDataID, 'caltab', 0, 0, I)
    *获取标定板标定点信息
    get_calib_data_observ_points (CalibDataID, 0, 0, I, RCoord, CCoord, Index, PoseForCalibrationPlate)
    * Visualize the extracted calibration marks and the estimated pose (coordinate system)
    dev_set_color ('green')
    dev_display (Image)
    dev_display (Caltab)
    dev_set_color ('yellow')
    *在标定点中心画十字标记
    disp_cross (WindowHandle, RCoord, CCoord, 6, 0)
    dev_set_colored (3)
    *在标定板图像中显示标定板坐标系
    disp_3d_coord_system (WindowHandle, StartCamParam, PoseForCalibrationPlate, 0.01)
    disp_message (WindowHandle, 'Extracting data from calibration image ' + (I + 1) + ' of ' + NumImages, 'window', 12, 12, 'black', 'true')
    * 读取机器人模型的工具坐标系在机器人基坐标系中的变换矩阵,能够从机器人模型中得出。Read pose of tool in robot base coordinates (ToolInBasePose)
    read_pose (DataNameStart + 'robot_pose_' + I$'02d' + '.dat', ToolInBasePose)
    if (I == 0)
        PoseIn := [-0.006,-0.296,12,178,2,270,0]
    else
        PoseIn := PoseOut
    endif
*将工具初始坐标OM3DToolOrigin值经过ToolInBasePose即工具坐标在机器人基坐标中的位姿转换矩阵转换为工具在基坐标下的表示形式 OM3DTool
    rigid_trans_object_model_3d (OM3DToolOrigin, ToolInBasePose, OM3DTool)
    *create_pose (0.1, 0.2, 0.3, 40, 50, 60, 'R(p-T)', 'abg', 'point', Pose)
     *(标准化3D交互显示)可视化交互显示机器人参数的3D模型坐标
    visualize_object_model_3d (WindowHandleR, [OM3DTool,OM3DBase], [], PoseIn, ParamName, ParamValue, 'Position of robot tool coordinate system in robot base coordinate system', Labels, Instructions, PoseOut)
    clear_object_model_3d (OM3DTool)
    * Set the pose tool in robot base coordinates in the calibration data model
    set_calib_data (CalibDataID, 'tool', I, 'tool_in_base_pose', ToolInBasePose)
endfor
dev_set_window (WindowHandleR)
dev_close_window ()
disp_message (WindowHandle, 'All relevant data has been set in the calibration data model', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* Check the input poses for consistency
check_hand_eye_calibration_input_poses (CalibDataID, 0.05, 0.005, Warnings)
if (|Warnings| != 0)
    * There were problem detected in the input poses. Inspect Warnings and
    * remove erroneous poses with remove_calib_data and remove_calib_data_observ.
    dev_inspect_ctrl (Warnings)
    stop ()
endif
* 
* Perform the hand eye calibration and store the results to file
* The calibration of the cameras is done internally prior
* to the hand eye calibration
dev_display (Image)
disp_message (WindowHandle, 'Performing the hand-eye calibration', 'window', 12, 12, 'black', 'true')


***利用前面获取的标定数据进行手眼标定***
calibrate_hand_eye (CalibDataID, Errors)


***从手眼标定结果中获取所需的参数具体数值***
* Query the error of the camera calibration
get_calib_data (CalibDataID, 'model', 'general', 'camera_calib_error', CamCalibError)
* Query the camera parameters and the poses
get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam)
* Get poses computed by the hand eye calibration
get_calib_data (CalibDataID, 'camera', 0, 'tool_in_cam_pose', ToolInCamPose)
get_calib_data (CalibDataID, 'calib_obj', 0, 'obj_in_base_pose', CalObjInBasePose)


* Get the plane in base coordinate system pose by translating the
* CalObjInBasePose by the calibration object's thickness in the
* z-direction.
*//初始标定板位姿CalObjInBasePose在考虑标定板厚度后沿z轴平移变换的标定板在基坐标系中位姿PlaneInBasePose
set_origin_pose (CalObjInBasePose, 0, 0, 0.005, PlaneInBasePose)
dev_get_preferences ('suppress_handled_exceptions_dlg', PreferenceValue)
dev_set_preferences ('suppress_handled_exceptions_dlg', 'true')
try
    * Handle situation where user does not have the permission
    * to write in the current directory.
    * 
    * Store the camera parameters to file
    write_cam_par (CamParam, DataNameStart + 'final_campar.dat')
    * Save the hand eye calibration results to file
    write_pose (ToolInCamPose, DataNameStart + 'final_pose_cam_tool.dat')
    write_pose (CalObjInBasePose, DataNameStart + 'final_pose_base_calplate.dat')
    write_pose (PlaneInBasePose, DataNameStart + 'final_pose_base_plane.dat')
catch (Exception)
    * do nothing
endtry
dev_set_preferences ('suppress_handled_exceptions_dlg', PreferenceValue)
dev_display (Image)
* Display calibration errors
disp_results (WindowHandle, CamCalibError, Errors)
* disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*?? For the given camera, get the corresponding pose indices and calibration object indices
*//query_calib_data_observ_indices( : : CalibDataID, ItemType, ItemIdx : Index1, Index2)
*// Index1 returns a list of calibration object indices and Index2 returns a list of pose indices.
*//Each pair [Index1[I],Index2[I]] represents calibration object pose that are 'observed' by camera ItemIdx.
query_calib_data_observ_indices (CalibDataID, 'camera', 0, CalibObjIdx, PoseIds)
* Compute the pose of the calibration object in the camera coordinate
* system via calibrated poses and the ToolInBasePose and visualize it.
* Set sizes for 3D visualization in [m]
CameraSize := 0.05
CameraConeLength := 0.3
get_calib_data (CalibDataID, 'calib_obj', 0, 'x', PX)
get_calib_data (CalibDataID, 'calib_obj', 0, 'y', PY)
get_calib_data (CalibDataID, 'calib_obj', 0, 'z', PZ)
*//创建标定板标定点的点云
gen_object_model_3d_from_points (PX, PY, PZ, OM3DObjectOrig)
*//将初始标定板位姿OM3DObjectOrig经过标定板与基坐标系之间的转换关系CalObjInBasePose(从标定数据中得到)转换到基坐标系中表示 OM3DObject
rigid_trans_object_model_3d (OM3DObjectOrig, CalObjInBasePose, OM3DObject)
clear_object_model_3d (OM3DObjectOrig)
dev_open_window (0, Width + 10, Width, Height, 'black', WindowHandleR)
set_display_font (WindowHandleR, 14, 'mono', 'true', 'false')
ParamName := ['color_0','color_1','color_2','color_3','color_4','color_5','color_6','color_7','alpha_7','color_8','color_9','color_10','alpha_8','alpha_9','alpha_10','point_size']
ParamValue := ['red','red','green','blue','red','green','blue','white',0.7,'magenta','yellow','white',0.5,0.5,0.5,5]
* Labels for the visualized 3D object models.
tuple_gen_const (11, '', Labels)
Labels[0] := 'Calibration Object'
Labels[1] := 'Robot\'s Tool'
Labels[4] := 'Robot\'s Base'
Labels[8] := 'Camera'
for I := 0 to NumImages - 1 by 1
    dev_set_window (WindowHandle)
    dev_clear_window ()
    read_image (Image, ImageNameStart + I$'02d')
    dev_display (Image)
    * Obtain the pose of the tool in robot base coordinates used in the calibration.
    * The index corresponds to the index of the pose of the observation object.
    get_calib_data (CalibDataID, 'tool', PoseIds[I], 'tool_in_base_pose', ToolInBasePose)
    * Compute the pose of the calibration object relative to the camera
    calc_calplate_pose_movingcam (CalObjInBasePose, ToolInCamPose, ToolInBasePose, CalObjInCamPose)
    * Display the coordinate system
    dev_set_colored (3)
    disp_3d_coord_system (WindowHandle, CamParam, CalObjInCamPose, 0.01)
    Message := 'Using the calibration results to display '
    Message[1] := 'the coordinate system in image ' + (I + 1) + ' of ' + NumImages
    disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
    gen_camera_and_tool_moving_cam_object_model_3d (ToolInCamPose, ToolInBasePose, CameraSize, CameraConeLength, OM3DToolOrigin, CamParam, OM3DCamera, OM3DTool)
    if (I == 0)
        PoseIn := [-0.006,-0.296,12,178,2,270,0]
    else
        PoseIn := PoseOut
    endif
    visualize_object_model_3d (WindowHandleR, [OM3DObject,OM3DTool,OM3DBase,OM3DCamera], [], PoseIn, ParamName, ParamValue, [], Labels, Instructions, PoseOut)
    clear_object_model_3d (OM3DTool)
    clear_object_model_3d (OM3DCamera)
endfor
* Clear the data model
clear_calib_data (CalibDataID)
clear_object_model_3d (OM3DObject)
clear_object_model_3d (OM3DToolOrigin)
clear_object_model_3d (OM3DBase)
dev_set_window (WindowHandleR)
dev_close_window ()
* 
* After the hand-eye calibration the computed pose
* ToolInCamPose can be used in robotic grasping applications.
* To grasp an object with the robot, typically, its pose
* with respect to the camera is determined (which
* is simulated here by setting the object's pose to the
* pose of the calibration object)
ObjInCamPose := CalObjInCamPose
* If the tool coordinate system is placed at the gripper
* and a detected object ObjInCamPose shall be grasped
* (here the calibration object),
* the pose of the detected object relative
* to the robot base coordinate system has to be computed.
pose_invert (ToolInCamPose, CamInToolPose)
pose_compose (ToolInBasePose, CamInToolPose, CamInBasePose)
pose_compose (CamInBasePose, ObjInCamPose, ObjInBasePose)
View Code