机器人~ur5-kinect2自动手眼标定

我们使用Universal Robots公司的UR5工业机器人和Microsoft公司的Kinect v2搭建了一个机械手臂抓取统,这是一个典型的eye to hand结构。为了实现抓取功能,我们首先要对这个系统进行手眼标定,这个标定的目的是确定相机和机器人的相对位置和姿态,从而实现将相机拍到的物品位姿转换到机器人坐标系下进行抓取。

技术总览

在机械臂抓取的过程中,关键的技术是机器视觉,主要分为三个部分^{[1]}

  • 物体识别(Object Recognition):在图像中检测到物体类型等,这跟 CV 的研究有很大一部分交叉;
  • 位姿估计(Pose Estimation):计算出物体在摄像机坐标系下的位置和姿态,对于机器人而言,需要抓取东西,不仅要知道这是什么,也需要知道它具体在哪里;
  • 相机标定(Camera Calibration):因为上面做的只是计算了物体在相机坐标系下的坐标,我们还需要确定相机跟机器人的相对位置和姿态,这样才可以将物体位姿转换到机器人位姿。

手眼标定在理论上讲是一个被研究地非常成熟的问题,根据相机位置的不同,它主要又分为两种,分别是:

  • Eye to Hand:相机与机器人极坐标系固连,不随机械臂运动而运动
  • Eye in Hand:相机固连在机械臂上,随机械臂运动而运动

上面的引用[1]在理论上对手眼标定进行了一个非常详细的表述,所以我们不再赘述。在这篇文章中,我们主要是从实践的角度出发,具体地看看如何在一个真实的eye to hand机器人系统中进行手眼标定。


软硬件依赖

硬件:

  1. UR5工业机器人
  2. Kinect V2

软件:

  1. ros-kinetic-visp
  2. vision_visp
  3. aruco_ros
  4. easy_handeye

安装步骤

安装ros-kinetic-visp包:

$ sudo apt-get install ros-kinetic-visp

安装vision_visp包

catkin_ws/src$ git clone -b kinetic-devel https://github.com/lagadic/vision_visp.git
catkin_ws$ catkin_make --pkg visp_hand2eye_calibration

安装aruco_ros

catkin_ws/src$ git clone -b kinetic-devel https://github.com/pal-robotics/aruco_ros
catkin_ws$ catkin_make

安装easy_handeye

catkin_ws/src$ git clone https://github.com/IFL-CAMP/easy_handeye
catkin_ws$ catkin_make

编写启动文件并启动

为了能够同时启动UR5,Kinect和标定程序来进行实际的标定任务,我们需要写一个launch文件。为了保持简单,我们直接在easy_handeye作者所给的样例文件上按照自己的情况进行修改就好。

下面是我的launch文件:

<!-- filename: calibrate.launch -->

<launch>
    <arg name="namespace_prefix" default="chessbot_calibration" />
 
    <arg name="robot_ip" doc="The IP address of the UR5 robot" />
        <!--<arg name="marker_frame" default="aruco_marker_frame"/>-->
    <arg name="marker_size" doc="Size of the ArUco marker used, in meters" default="0.1" />
    <arg name="marker_id" doc="The ID of the ArUco marker used" default="100" />
    <!-- start the Kinect -->
    <include file="$(find kinect2_bridge)/launch/kinect2_bridge.launch" />
    <!--    <arg name="depth_registration" value="true" />
    </include>-->
 
    <!-- start ArUco -->
    <node name="aruco_tracker" pkg="aruco_ros" type="single">
        <remap from="/camera_info" to="/kinect2/hd/camera_info" />
        <remap from="/image" to="/kinect2/hd/image_color_rect" />
        <param name="image_is_rectified" value="true"/>
        <param name="marker_size"        value="$(arg marker_size)"/>
        <param name="marker_id"          value="$(arg marker_id)"/>
        <param name="reference_frame"    value="kinect2_rgb_optical_frame"/>
        <param name="camera_frame"       value="kinect2_rgb_optical_frame"/>
        <param name="marker_frame"       value="camera_marker" />
    </node>
 
    <!-- start the robot -->
    <include file="$(find ur_modern_driver)/launch/ur5_bringup.launch">
        <arg name="limited" value="true" />
        <arg name="robot_ip" value="192.168.199.106" />
    </include>
    <include file="$(find ur5_moveit_config)/launch/ur5_moveit_planning_execution.launch">
        <arg name="limited" value="true" />
    </include>
 
    <!-- start easy_handeye -->
    <include file="$(find easy_handeye)/launch/calibrate.launch" >
        <arg name="namespace_prefix" value="$(arg namespace_prefix)" />
        <arg name="eye_on_hand" value="false" />
 
        <arg name="tracking_base_frame" value="kinect2_rgb_optical_frame" />
        <arg name="tracking_marker_frame" value="camera_marker" />
        <arg name="robot_base_frame" value="base_link" />
        <arg name="robot_effector_frame" value="wrist_3_link" />
 
        <arg name="freehand_robot_movement" value="false" />
        <arg name="robot_velocity_scaling" value="0.5" />
        <arg name="robot_acceleration_scaling" value="0.2" />
    </include>
</launch>

需要注意的是,由于我要制作一个下象棋的机器人,所以在这里我将我的机器人命名为chessbot,大家可以按照自己的情况自由修改。

我们有了启动文件,还差一个标定板,我找到了一个非常好的网页可以在线生成aruco marker,我们要注意的是生成时输入的参数必须和我们在上面的文件中设置的一样,生成好之后直接用浏览器的打印菜单打印到A4纸上即可(可以用尺子量一下尺寸是否正确)。

在启动这个文件之前,还要知道我的机械臂的抓手(或者叫end effector)的坐标和标定板坐标系的变换关系我们还不知道,这要求我们自己设置机器人的TCP。这部分请自行查阅机器人的文档。

好,我们来运行上面的launch文件:

roslaunch chessbot_calibration calibrate.launch

如果成功的话,我们会看到三个窗口跳出来,分别是:

标定窗口1-rziv
标定窗口2-rqt_easy_handeye
标定窗口3-plan

我们还需要在标定窗口1中订阅相机拍到的图片/aruco_tracker/result进行显示,显示后的效果如下:

标定窗口1-rziv打开图片

在打开的图片中,我们可以清楚地看到标定系统已经成功地对标定板进行了识别,到这里我们就可以真正地进入自动标定的环节了。

标定程序

为了安全流畅地操作,我们先在rviz的Motion Planning界面中将机械臂的速度和加速度都设为0.1,并将标定板固定在机械臂上面,移动到相机视野的中心位置。再检查图3中是否显示0/17,如果不是就按check starting pose

一切都正常设置之后,我们分三步来进行标定:

  1. 在图3界面点击next pose,再点击plan,出现绿色就当前位姿可以达到,最后点击execute;如果出现红色则表示当前点不可用,继续点击next pose,重复操作,直至出现绿色;
  2. 返回图2界面点击take sample。重复(1)(2)操作,直到17个点全部采集完;
  3. 返回图2界面,点击compute,得到一组7个解的变换矩阵(四元数表示),点save

上面计算的结果保存在~/.ros/easy_handeye/xxx.yaml这个文件里面,接下来我们发布变换,如果使用easy_handey自带的publish.launch一般是会报错的,因为我们在上面的calibrate.launch文件中对保存四元数的yaml文件进行了自定义。这里我们再创建一个publish.launch文件,内容如下:

<!-- filename: publish.launch -->

<?xml version="1.0"?>
<launch>
    <arg name="eye_on_hand" doc="eye-on-hand instead of eye-on-base" default="false" />
    <arg name="namespace_prefix" default="chessbot_calibration" />
    <arg if="$(arg eye_on_hand)" name="namespace" value="$(arg namespace_prefix)_eye_on_hand" />
    <arg unless="$(arg eye_on_hand)" name="namespace" value="$(arg namespace_prefix)_eye_on_base" />

    <!--it is possible to override the link names saved in the yaml file in case of name clashes, for example-->
    <arg if="$(arg eye_on_hand)" name="robot_effector_frame" default="" />
    <arg unless="$(arg eye_on_hand)" name="robot_base_frame" default="" />
    <arg name="tracking_base_frame" default="" />
    
    <arg name="inverse" default="false" />
    
    <!--publish hand-eye calibration-->
    <group ns="$(arg namespace)">
        <param name="eye_on_hand" value="$(arg eye_on_hand)" />
        <param unless="$(arg eye_on_hand)" name="robot_base_frame" value="$(arg robot_base_frame)" />
        <param if="$(arg eye_on_hand)" name="robot_effector_frame" value="$(arg robot_effector_frame)" />
        <param name="tracking_base_frame" value="$(arg tracking_base_frame)" />
        <param name="inverse" value="$(arg inverse)" />
        <node name="$(anon handeye_publisher)" pkg="easy_handeye" type="publish.py" output="screen"/>
    </group>
</launch>

查看标定结果

为了查看标定结果,我们需要编写另外个launch文件,通过它将我们的机械臂、kinect、moveit模块启动起来,并发布坐标变换。

<!-- filename: start.launch -->

<launch>
    <!-- start the robot -->
    <include file="$(find ur_modern_driver)/launch/ur5_bringup.launch">
        <arg name="limited" value="true" />
        <arg name="robot_ip" value="192.168.199.106" />
    </include>

    <include file="$(find chessbot_moveit_config)/launch/ur5_moveit_planning_execution.launch">
        <arg name="limited" value="true" />
    </include>
 
    <include file="$(find chessbot_moveit_config)/launch/moveit_rviz.launch">
        <arg name="config" value="true" />
    </include>

    <include file="$(find kinect2_bridge)/launch/kinect2_bridge.launch" />
 
    <include file="$(find chessbot_calibration)/launch/publish.launch" />

</launch>

另外,为了显示点云的octomap,我们还得添加一个点云配置文件sensors_kinect.yaml,放到chessbot_moveit_confit下面,这个chessbot_moveit_config包是我拷贝的ur5_moveit_config包,因为我不想改变原来的文件,当然我们也可以使用moveit_setup_assistant工具自建moveit_config包。sensors_kinect.yaml文件的内容为:

sensors:
  - sensor_plugin: occupancy_map_monitor/PointCloudOctomapUpdater
    point_cloud_topic: /kinect2/qhd/points
    max_range: 5.0
    point_subsample: 1
    padding_offset: 0.1
    padding_scale: 1.0
    max_update_rate: 1.0
    filtered_cloud_topic: filtered_cloud

注意点云所使用的topic应当按照具体情况做对应的修改。然后我们打开chessbot_moveit_config/launch文件夹下面的sensor_manager.launch.xml文件做相应的修改来使用上面的sensors_kinect.yaml文件。其实就是在后面添加

  <rosparam command="load" file="$(find chessbot_moveit_config)/config/sensors_kinect.yaml" />
  <param name="octomap_frame" type="string" value="odom_combined" />
  <param name="octomap_resolution" type="double" value="0.05" />
  <param name="max_range" type="double" value="5.0" />

用来载入octomap

好了,现在万事俱备,只欠东风了。在终端输入以下命令启动launch文件:

roslaunch chess_demo start.launch
八叉图

这就是初步的标定结果了,现在我们就可以使用moveit心情地让我们的机械臂有外界交流了。

如果我们还想查看点云,可以先关闭八叉图的server,然后在打开的rviz窗口中,我们添加DepthCloud插件,并订阅kinect2/qhd/image_depth_rectkinect2/qhd/image_color_rect两个topic,这样我们就看到了以下的结果:

点云

到这里,外参的标定基本上就非常详细地讲完了,谢谢各位阅读!愿为中国机器人的发展有所贡献!


备注:
这篇文章重度依赖于另外一篇博客,我是照着该作者的方法自己进行了改进,在此表示感谢!

引用:
[1]. https://www.aiimooc.com/article/show-htm-itemid-34.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容