目录

1. easy hand_eye2介绍

2.环境

3.项目构建

3.1克隆aruco_ros

3.2克隆easy_handeye2 手眼标定工具包

3.3标定板打印

4.aruco_ros配置

4.1 修改remappings,为camera发布的topic

4.2修改 marker_id,为生成的marker ID

4.3修改 marker_size,为生成的marker尺寸

4.4编译colcon build

5.创建标定Launch文件

5.1创建标定评估launch文件

6.运行程序

6.1 rqt中选择/aruco_single/result话题可以看见二维码及其坐标系

6.2标定数据采集

6.3标定数据样本数据精度评估(二次标定)​编辑

6.4可以得到标定结果

7.标定结果发布


0. 项目推荐(新增)

      推荐moveit2官方示例,手眼标定Hand-Eye Calibration,新手本人提供了步骤参考:

https://laixiaolai.blog.csdn.net/article/details/154538798?fromshare=blogdetail&sharetype=blogdetail&sharerId=154538798&sharerefer=PC&sharesource=qq_70851292&sharefrom=from_linkhttps://laixiaolai.blog.csdn.net/article/details/154538798?fromshare=blogdetail&sharetype=blogdetail&sharerId=154538798&sharerefer=PC&sharesource=qq_70851292&sharefrom=from_link

        强力推荐,二次重标定误差小,精度可达1mm

1. easy hand_eye2介绍

       easy_handeye2 是一个为ROS2设计的自动化、硬件无关的Hand-Eye标定工具。它提供了一个功能丰富且易于使用的GUI,用于执行机器人标定过程。项目的主要目标是简化Hand-Eye标定流程。
       easy_handeye2 基于ROS2框架,利用OpenCV库的hand-eye标定算法(例如Tsai-Lenz算法)进行标定计算。它支持以下功能:
       通过tf采样机器人位置和跟踪系统输出。 计算眼在基座(eye-on-base)或眼在手部(eye-in-hand)的标定矩阵。
       计算眼在基座(eye-on-base)或眼在手部(eye-in-hand)的标定矩阵。
存储和发布标定结果。
评估标定矩阵的准确性。

2.环境

  • Ubuntu22.04

  • ros2 humble

  • realsense camera

3.项目构建

3.1克隆aruco_ros

mkdir -p ~/realsense_ws/src # 创建工作空间
cd ~/realsense_ws/src
# 克隆分支; https://mirror.ghproxy.com为github代理
git clone https://mirror.ghproxy.com/https://github.com/pal-robotics/aruco_ros.git -b humble-devel

3.2克隆easy_handeye2 手眼标定工具包

cd ~/realsense_ws/src
git clone https://github.com/marcoesposito1988/easy_handeye2

3.3标定板打印

标定板打印

选择Original ArUco ,ID选择582 大小尺寸选择50mm,原尺寸打印

4.aruco_ros配置

文件位置:aruco_ros/aruco_ros/launch/single.launch.py

4.1 修改aruco_single_params

注意:

        'reference_frame': LaunchConfiguration('reference_frame'),
        'camera_frame': LaunchConfiguration('reference_frame'),

    aruco_single_params = {
        'image_is_rectified': True,
        'marker_size': LaunchConfiguration('marker_size'),
        'marker_id': LaunchConfiguration('marker_id'),
        'reference_frame': LaunchConfiguration('reference_frame'),
        'camera_frame': LaunchConfiguration('reference_frame'),
        'marker_frame': LaunchConfiguration('marker_frame'),
        'corner_refinement': LaunchConfiguration('corner_refinement'),
    }

4.2 修改remappings,为camera发布的topic(根据自己的修改)

aruco_single = Node( package='aruco_ros', 
                     executable='single',
                     parameters=[aruco_single_params], 
                     remappings=[('/camera_info', 
                    '/camera/camera/color/camera_info'),
                     ('/image', '/camera/camera/color/image_raw')], )

4.3修改 marker_id,为生成的marker ID

marker_id_arg = DeclareLaunchArgument( 'marker_id', default_value='582',             
                                        description='Marker ID. ' )

4.4修改 marker_size,为生成的marker尺寸(上面自定义)

marker_size_arg = DeclareLaunchArgument( 'marker_size', default_value='0.05',         
                                         description='Marker size in m. ' )

4.5修改 reference_frame ,对应相机的颜色帧

    reference_frame = DeclareLaunchArgument(
        'reference_frame', default_value='camera_color_optical_frame',
        description='Reference frame. '
        'Leave it empty and the pose will be published wrt param parent_name. '
    )

4.6编译colcon build

cd ~/realsense_ws/ 
colcon build 
source install/setup.bash

4.7 single.launch.py修改参考

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, OpaqueFunction
from launch.substitutions import LaunchConfiguration
from launch.utilities import perform_substitutions
from launch_ros.actions import Node


def launch_setup(context, *args, **kwargs):

    eye = perform_substitutions(context, [LaunchConfiguration('eye')])

    aruco_single_params = {
        'image_is_rectified': True,
        'marker_size': LaunchConfiguration('marker_size'),
        'marker_id': LaunchConfiguration('marker_id'),
        'reference_frame': LaunchConfiguration('reference_frame'),
        'camera_frame': LaunchConfiguration('reference_frame'),
        'marker_frame': LaunchConfiguration('marker_frame'),
        'corner_refinement': LaunchConfiguration('corner_refinement'),
    }
    aruco_single = Node(
        package='aruco_ros',
        executable='single',
        parameters=[aruco_single_params],
        remappings=[('/camera_info', '/camera/color/camera_info'),
                ('/image', '/camera/color/image_raw')],
    )

    return [aruco_single]


def generate_launch_description():

    marker_id_arg = DeclareLaunchArgument(
        'marker_id', default_value='582',
        description='Marker ID. '
    )

    marker_size_arg = DeclareLaunchArgument(
        'marker_size', default_value='0.049',
        description='Marker size in m. '
    )

    eye_arg = DeclareLaunchArgument(
        'eye', default_value='left',
        description='Eye. ',
        choices=['left', 'right'],
    )

    marker_frame_arg = DeclareLaunchArgument(
        'marker_frame', default_value='camera_marker',
        description='Frame in which the marker pose will be refered. '
    )

    reference_frame = DeclareLaunchArgument(
        'reference_frame', default_value='camera_color_optical_frame',
        description='Reference frame. '
        'Leave it empty and the pose will be published wrt param parent_name. '
    )

    corner_refinement_arg = DeclareLaunchArgument(
        'corner_refinement', default_value='LINES',
        description='Corner Refinement. ',
        choices=['NONE', 'HARRIS', 'LINES', 'SUBPIX'],
    )

    # Create the launch description and populate
    ld = LaunchDescription()

    ld.add_action(marker_id_arg)
    ld.add_action(marker_size_arg)
    ld.add_action(eye_arg)
    ld.add_action(marker_frame_arg)
    ld.add_action(reference_frame)
    ld.add_action(corner_refinement_arg)

    ld.add_action(OpaqueFunction(function=launch_setup))

    return ld

5.创建标定Launch文件

handeye_calibrate.launch.py

确定是否眼在手上

机械臂的基坐标系'robot_base_frame': 'base_link',
机械臂末端系 'robot_effector_frame': 'Link6',           
相机坐标系 'tracking_base_frame': 'camera_link',           
二维码坐标系  'tracking_marker_frame': 'camera_marker'     

参数修改需根据实际情况如机械臂的基坐标系,末端,相机坐标系

from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription, DeclareLaunchArgument
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import PathJoinSubstitution, LaunchConfiguration
from launch_ros.substitutions import FindPackageShare
from launch.conditions import LaunchConfigurationEquals
from launch_ros.actions import Node

def generate_launch_description():
                                                                                      
    # 声明参数(可选,若需要从命令行动态传入)
    calibration_type = DeclareLaunchArgument(
        'calibration_type', default_value='eye_in_hand',
        description='Calibration type: eye_in_hand or eye_on_base'
    )
    name = DeclareLaunchArgument(
        'name', default_value='my_eih_calib',
        description='Unique identifier for the calibration'
    )

    # 包含easy_handeye2的标定Launch文件
    handeye_calibration = IncludeLaunchDescription(
        PythonLaunchDescriptionSource([
            PathJoinSubstitution([
                FindPackageShare('easy_handeye2'),
                'launch/calibrate.launch.py'
            ])
        ]),
        launch_arguments={
            'calibration_type': LaunchConfiguration('calibration_type'),
            'name': LaunchConfiguration('name'),
            'robot_base_frame': 'base_link',
            'robot_effector_frame': 'Link6',
            'tracking_base_frame': 'camera_link',
            'tracking_marker_frame': 'camera_marker'
        }.items()
    )

    return LaunchDescription([
        calibration_type,
        name,
        handeye_calibration
    ])

5.1创建标定评估launch文件

check_evaluate.launch.py 

from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription, DeclareLaunchArgument
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import PathJoinSubstitution, LaunchConfiguration
from launch_ros.substitutions import FindPackageShare

def generate_launch_description():
      
    # 声明参数(可选,若需要从命令行动态传入)
    name = DeclareLaunchArgument(
        'name', default_value='my_eih_calib',
        description='Unique identifier for the calibration'
    )

    handeye_calibration_evaluate = IncludeLaunchDescription(
        PythonLaunchDescriptionSource([
            PathJoinSubstitution([
                FindPackageShare('easy_handeye2'),
                'launch/evaluate.launch.py'
            ])
        ]),
        launch_arguments={
            'name': LaunchConfiguration('name'),
        }.items()
    )
    
    return LaunchDescription([
        name,
        handeye_calibration_evaluate
    ])

6.运行程序

启动相机(ROS2 )

相机ros2包省略,需要自己下载对应的相机ros2包,如D435的ros2包等,然后启动相机的launch.py

启动aruco_ros 二维码检测ros2 launch aruco_ros single.launch.py 

启动标定程序ros2 launch easy_handeye2 handeye_calibrate.launch.py 

启动标定过程精度评估(第二次标定才有用,标定精度可视化)ros2 launch easy_handeye2 check_evaluate.launch.py 

# 1.启动相机launch
ros2 launch aruco_ros single.launch.py  # 2.二维码识别
ros2 launch easy_handeye2 handeye_calibrate.launch.py # 3.标定
ros2 launch easy_handeye2 check_evaluate.launch.py #第二次(标定精度可视化)

6.1 rqt中选择/aruco_single/result话题可以看见二维码及其坐标系

6.2标定数据采集

手动rviz中拖动机械臂进行标定,基本采取20组数据

不同位置以及旋转姿态

20组后可以从result中自动得到计算结果

6.3标定数据样本数据精度评估(二次标定)

6.4可以得到标定结果

parameters:
  name: my_eih_calib
  calibration_type: eye_in_hand
  robot_base_frame: base_link
  robot_effector_frame: tool0
  tracking_base_frame: camera_link
  tracking_marker_frame: camera_marker
  freehand_robot_movement: true
  move_group_namespace: /
  move_group: manipulator
transform:
  translation:
    x: -0.014886304991426357
    y: -0.08066943337079086
    z: -0.07400519777878578
  rotation:
    x: 0.5135594765100884
    y: -0.49636114981552804
    z: 0.5009814794054358
    w: 0.48877380283034

7.标定结果发布

publish.launch.py

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node

def generate_launch_description():
    name = DeclareLaunchArgument(
        'name', default_value='my_eih_calib',
        description='Unique identifier for the calibration'
    )

    handeye_publisher = Node(package='easy_handeye2', executable='handeye_publisher', name='handeye_publisher', parameters=[{
        'name': LaunchConfiguration('name'),
    }])

    return LaunchDescription([
        name,
        handeye_publisher,
    ])

Logo

立足具身智能前沿赛道,致力于搭建全球化、开源化、全栈式技术交流与实践共创平台。

更多推荐