基于halcon的眼在手外(Eye-to-Hand)标定

news2024/11/13 10:43:48

前言

        上个月写了一个《基于halcon的眼在手上(Eye-in-Hand)标定》的文章,通过官方的示例代码进行了简单的叙述,想学习的小伙伴可以点击链接进行学习。之前博主认为眼在手上(Eye-in-Hand)的案例更多,或者说是使用场景更多的。但是,最近在学习机械臂的运动规划方向的内容后,发现对于机械臂避障这一块,眼在手上的实施方式是不太可能实现避障的。主要问题在于,眼在手上这种方式,只能看到机械臂前端的物体,而忽略机械臂周围的物体,没有周围物体的位置,那么机械臂在运动过程中,就难以保证机械臂不会碰撞。而眼在手外则可以看到机械臂和机械臂周围的物体,减小机械臂与周围物体碰撞的概率。

        (emmm。。这里得提一下,对机械臂的运动规划这一部分内容通常是在Moveit!中进行的,当然肯定会有在该平台下的手眼标定方案,需要的小伙伴请自行学习。由于我感觉halcon的手眼标定精度是不错的,所以还是记录一下啦~)

halcon示例代码

halcon示例代码

* 
* This example explains how to use the hand eye calibration for the case where
* the camera is stationary with respect to the robot and the calibration
* object is attached to the robot arm.
* 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 camera (BaseInCamPose).
* - the pose of the calibration object in the coordinate system of the
*   tool (CalObjInToolPose)
* Theoretically, as input the method needs at least 3 poses of the
* calibration object in the camera coordinate system and the corresponding
* poses of the robot tool in the coordinate system of the
* robot base. However it is recommended
* to use at least 10 Poses.
* The poses of the calibration object are obtained from images of the
* calibration object recorded with the stationary camera.
* The calibration object is moved by the robot with respect to the camera.
* To obtain good calibration results, it its essential to position
* the calibration object with respect to the camera 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/stationarycam_calib3cm_'
DataNameStart := 'hand_eye/stationarycam_'
NumImages := 17
* Read image
read_image (Image, ImageNameStart + '00')
get_image_size (Image, Width, Height)
* Open window
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
dev_set_line_width (2)
dev_set_draw ('margin')
dev_display (Image)
* Set font
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
* Load the calibration plate description file.
* Make sure that the file is in the current directory,
* the HALCONROOT/calib directory, or use an absolut path
CalTabFile := 'caltab_30mm.descr'
* Read the initial values for the internal camera parameters
read_cam_par (DataNameStart + 'start_campar.dat', StartCamParam)
* Create the calibration model for the hand eye calibration
create_calib_data ('hand_eye_stationary_cam', 1, 1, CalibDataID)
set_calib_data_cam_param (CalibDataID, 0, [], StartCamParam)
set_calib_data_calib_object (CalibDataID, 0, CalTabFile)
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 ()
* Start the loop over the calibration images
for I := 0 to NumImages - 1 by 1
    read_image (Image, ImageNameStart + I$'02d')
    * Search for the calibration plate, extract the marks and the
    * pose of it, and store the results in the calibration data model of the
    * hand-eye calibration
    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, CalObjInCamPose)
    * 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, CalObjInCamPose, 0.01)
    * Read pose of tool in robot base coordinates (ToolInBasePose)
    read_pose (DataNameStart + 'robot_pose_' + I$'02d' + '.dat', ToolInBasePose)
    * Set the pose tool in robot base coordinates in the calibration data model
    set_calib_data (CalibDataID, 'tool', I, 'tool_in_base_pose', ToolInBasePose)
    * Uncomment to inspect visualization
*     disp_message (WindowHandle, 'Extracting data from calibration image ' + (I + 1) + ' of ' + NumImages, 'window', 12, 12, 'black', 'true')
*     disp_continue_message (WindowHandle, 'black', 'true')
*     stop ()
endfor
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 hand-eye calibration
* Internally before performing the hand-eye calibration the cameras are calibrated
* and the calibrated poses of the calibration object in the camera are used.
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, 'base_in_cam_pose', BaseInCamPose)
get_calib_data (CalibDataID, 'calib_obj', 0, 'obj_in_tool_pose', ObjInToolPose)
try
    * Store the camera parameters to file
    write_cam_par (CamParam, DataNameStart + 'final_campar.dat')
    * Save the hand eye calibration results to file
    write_pose (BaseInCamPose, DataNameStart + 'final_pose_cam_base.dat')
    write_pose (ObjInToolPose, DataNameStart + 'final_pose_tool_calplate.dat')
catch (Exception)
    * Do nothing
endtry
* Display calibration errors of the hand-eye calibration
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, '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.
for I := 0 to NumImages - 1 by 1
    read_image (Image, ImageNameStart + I$'02d')
    * 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)
    dev_display (Image)
    * Compute the pose of the calibration plate with respect to the camera
    * and visualize it
    calc_calplate_pose_stationarycam (ObjInToolPose, BaseInCamPose, ToolInBasePose, CalObjInCamPose)
    dev_set_colored (3)
    disp_3d_coord_system (WindowHandle, CamParam, CalObjInCamPose, 0.01)
    Message := 'Using the calibration results to display the'
    Message[1] := 'coordinate system in image ' + (I + 1) + ' of ' + NumImages
    disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
    if (I < NumImages - 1)
        disp_continue_message (WindowHandle, 'black', 'true')
        stop ()
    endif
endfor
* Clear the data model
clear_calib_data (CalibDataID)
* 
* After the hand-eye calibration, the computed pose
* BaseInCamPose 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 an object detected at ObjInCamPose shall be grasped,
* the pose of the detected object relative
* to the robot base coordinate system has to be computed.
pose_invert (BaseInCamPose, CamInBasePose)
pose_compose (CamInBasePose, ObjInCamPose, ObjInBasePose)

解析

        和眼在手上一致,眼在手外的标定代码前面部分也是一些参数配置。比如:ImageNameStart和DataNameStart是文件地址起始部分路径(文件名相同部分)、NumImages为图像数量。

创建、设置标定模型

下面代码主要是用于创建标定模型:

* Read the initial values for the internal camera parameters
read_cam_par (DataNameStart + 'start_campar.dat', StartCamParam)
* Create the calibration model for the hand eye calibration
create_calib_data ('hand_eye_stationary_cam', 1, 1, CalibDataID)
set_calib_data_cam_param (CalibDataID, 0, [], StartCamParam)
set_calib_data_calib_object (CalibDataID, 0, CalTabFile)
set_calib_data (CalibDataID, 'model', 'general', 'optimization_method', 'nonlinear')

read_cam_par        读取相机内参;

create_calib_data        创建标定模型;

set_calib_data_cam_param        将相机内参设置到标定模型中;

set_calib_data_calib_object        获取标定板的描述文件;

set_calib_data        设置标定的一些参数;

读取标定图像

下面是for循环中的内容,主要功能为读取标定图像:

read_image (Image, ImageNameStart + I$'02d')
* Search for the calibration plate, extract the marks and the
* pose of it, and store the results in the calibration data model of the
* hand-eye calibration
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, CalObjInCamPose)

read_image        读取图像;

find_calib_object        寻找标定板;

get_calib_data_observ_contours        找到标定板,然后画轮廓;

get_calib_data_observ_points        找到标定板,然后画标定点;

读取工具坐标系位姿

每一张图像对应着一个机械臂末端夹具(工具坐标系)在机械臂基坐标系下的位姿

* Read pose of tool in robot base coordinates (ToolInBasePose)
read_pose (DataNameStart + 'robot_pose_' + I$'02d' + '.dat', ToolInBasePose)
* Set the pose tool in robot base coordinates in the calibration data model
set_calib_data (CalibDataID, 'tool', I, 'tool_in_base_pose', ToolInBasePose)

read_pose        读取工具坐标系在机械臂基坐标系下的位姿;

set_calib_data        将读取的结果设置到标定模型中;

手眼标定

参数读取和设置都完成之后,结下来就是手眼标定啦~

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, 'base_in_cam_pose', BaseInCamPose)
get_calib_data (CalibDataID, 'calib_obj', 0, 'obj_in_tool_pose', ObjInToolPose)

calibrate_hand_eye        手眼标定;

get_calib_data         获取一些标定数据,这个算子有点特别,里面包含很多参数选择,这里就不进行叙述了。想要了解的小伙伴可以去halcon算子里面进行学习;

到这里标定就结束了。下面是保存参数。

write_cam_par (CamParam, DataNameStart + 'final_campar.dat')
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')

验证    

        在这里就不对验证进行解释了,简单来说就是根据以下三个坐标系进行转换:标定板坐标系相对于基座标系的转换关系、工具坐标系相对于相机坐标系的转换关系、工具坐标系相对于机械臂基座标的转换关系。这里进行一些数学计算,就能获得标定板坐标系在相机坐标系下的位置和姿态。注意这里不是识别标定板的结果,而是根据结果进行验证。

下面是一个比较好的结果(halcon示例结果):

可以看到坐标系和标定板的中心和姿态基本上是吻合的。这就是一个好的结果。  

-------------------------2024.06.27        留个坑,等我有空实验一下--------------

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1870360.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java笔记】Flyway数据库管理工具的基本原理

文章目录 1. 工作流程2. 版本号校验算法3. 锁机制3.1 为什么数据库管理工具需要锁3.2 flyway的锁机制 Reference 最近实习做的几个项目都用到了Flyway来做数据库的版本管理&#xff0c;顺便了解了下基本原理&#xff0c;做个记录。 详细的使用就不写了&#xff0c;网上教程很多…

【财经研究】并购重组的“不可能三角”

伴随着沪深IPO景气度下滑后&#xff0c;并购重组正受到市场的关注。 近期监管层正频频为并购重组发声 6月20日&#xff0c;证监会主席吴清在陆家嘴论坛上指出&#xff1a;“支持上市公司运用各种资本市场工具增强核心竞争力&#xff0c;特别是要发挥好资本市场并购重组主渠道作…

干涉阵型成图参数记录【robust】

robust 这个玩意经常忘记&#xff0c;就是取2的时候是更加显示大尺度的结构&#xff0c;取-2更加显示小尺度结果&#xff0c;一般取0就是正常就好了

高效同步的PWM升压DC/DC转换器 SD6201/SD6201-AF

SD6201是高效同步的PWM升压DC/DC转换器优化为介质提供高效的解决方案电力系统。这些设备在输入电压介于0.9V和4.4V之间&#xff0c;带有1.4MHz固定频率切换。这些功能通过允许使用小型、薄型电感器以及陶瓷电容器。自动PWM/PFM轻负载下的模式切换可节省电力提高了效率。电压在2…

IMU坐标系与自定义坐标系转化

1.首先示例图为例&#xff1a; 虚线黑色角度为IMU的坐标系&#xff1b;实线为自定义坐标系&#xff1b; 矫正&#xff1a;&#xff08;默认angleyaw为IMU采的数据角度&#xff09; angleyaw_pt angleyaw-25;if(-180<angleyaw&&angleyaw<-155) // 角度跳变问…

GuiLite C语言实现版本

简介 本项目是idea4good/GuiLite的C语言实现版本&#xff0c;基于2024-06-20节点的版本&#xff08;提交ID&#xff1a;e9c4b57&#xff09;。 本项目仓库&#xff1a;GuiLite_C 需求说明 作为芯片从业人员&#xff0c;国产芯片普遍资源有限&#xff08;ROM和RAM比较少-都是…

Str.format()方法

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 在Python2.6之后&#xff0c;提供了字符串的format()方法对字符串进行格式化操作。format()功能非常强大&#xff0c;格式也比较复杂&…

深度学习论文撰写实验对比分析时复现其它论文方法的问题

&#x1f4aa; 专业从事且热爱图像处理&#xff0c;图像处理专栏更新如下&#x1f447;&#xff1a; &#x1f4dd;《图像去噪》 &#x1f4dd;《超分辨率重建》 &#x1f4dd;《语义分割》 &#x1f4dd;《风格迁移》 &#x1f4dd;《目标检测》 &#x1f4dd;《暗光增强》 &a…

BERT论文略读

《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》 &#xff08;https://arxiv.org/abs/1810.04805&#xff09; 摘要&#xff1a;前人优秀工作仅用了单向信息且不能很好的应用到各类下游任务&#xff0c;本文提出一种基于Transformer的双…

如何理解AKM?

关于Wi-Fi的加密认证过程&#xff0c;我们前面已经讲解&#xff1a;WLAN数据加密机制_tls加密wifi-CSDN博客 今天我们来理解下AKM&#xff0c;AKM&#xff08;Authentication and Key Management&#xff09;在Wi-Fi安全中是指认证和密钥管理协议。它是用于确定Wi-Fi网络中的认…

【Linux】Linux下使用套接字进行网络编程

&#x1f525;博客主页&#xff1a; 我要成为C领域大神&#x1f3a5;系列专栏&#xff1a;【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 ​ 用于网络应用开…

揭秘数据合并的秘密:一文掌握一对一、多对一、多对多合并技巧与实战!

使用pd.merge()合并 类似 MySQL 中表和表直接的合并merge与concat的区别在于,merge需要依据某一共同的行或列来进行合并使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并每一列元素的顺序不要求一致1. 一对一合并 df1 = pd.DataFrame({"…

搜维尔科技:SenseGlove Nova2国内首款支持手掌心力回馈手套开售

《SenseGlove Nova 2》现正全球发行中! 搜维尔科技独家代理最新上市的 SenseGlove Nova 2 是世上首款&#xff0c;也是目前市面上唯一一款提供手掌力回馈的无缐VR力回馈手套&#xff0c;它结合了三种最先进的反馈技术&#xff0c;包括主动反馈、强力反馈及震动反馈&#xff0c…

k8s学习笔记(一)

configMap 一般用来存储配置信息 创建configMap 从文件中获取信息创建&#xff1a;kubectl create configmap my-config --from-file/tmp/k8s/user.txt 直接指定信息&#xff1a; kubectl create configmap my-config01 --from-literalkey1config1 --from-literalkey2confi…

小九首度回应与小水分手传闻揭秘

#小九首度回应&#xff01;与小水分手传闻揭秘#近日&#xff0c;泰国娱乐圈掀起了一股热议的狂潮&#xff01;传闻中的“金童玉女”组合——“小水”平采娜与“小九”NINE疑似分手的消息&#xff0c;如同巨石投入平静的湖面&#xff0c;激起了千层浪花。而在这股狂潮中&#xf…

CesiumJS【Basic】- #020 加载glb/gltf文件(Primitive方式)

文章目录 加载glb/gltf文件(Primitive方式)1 目标2 代码实现3 资源文件加载glb/gltf文件(Primitive方式) 1 目标 使用Primitive方式加载glb/gltf文件 2 代码实现 import * as Cesium from "cesium";const viewer = new Cesium.Viewer

x264 码率控制 VBV 算法原理:数学模型与数据流转

x264 码率控制 VBV 算法原理 关于 VBV原理的分析可以参考:x264 码率控制 VBV 原理。关于 VBV 算法的源码分析可以参考:x264 码率控制中实现 VBV 算法源码分析。VBV算法介绍 x264中的VBV(Video Buffering Verifier)算法是H.264编码标准的一部分,主要用于码率控制,确保视频…

C语言实战 | “俄罗斯方块”游戏重构

之前的游戏中,为了方便大家掌握框架,在“贪吃蛇”游戏中使用了大量的全局变量。全局变量空间利用率不高,全局变量在程序的执行过程中一直占用存储单元,而不是仅在需要时才开辟单元。另外,全局变量降低了通用性,程序执行时还需要依赖全局变量。例如,显示“食物”和“球”…

计算机的错误计算(十四)

摘要 解读 GPU和CPU计算上的精度差异&#xff1a;GPU 的 3个输出的相对误差分别高达 62.5%、50%、62.5%。 例1. 计算下列两个矩阵的乘积&#xff1a; 显然&#xff0c;其结果为第一列&#xff1a; 这个结果是准确的。 例2. 已知上面 3 个矩阵是由下面代码产生或输出&…

Zynq7000系列FPGA中的定时器详细介绍

每个Cortex-A9处理器都有自己的专用32位定时器和32位看门狗定时器。两个处理器共享一个全局64位定时器。这些定时器总是以CPU频率&#xff08;CPU_3x2x&#xff09;的1/2进行计时。 在系统级&#xff0c;有一个24位看门狗定时器和两个16位三重定时器/计数器。 系统看门狗定时器…