ROS2 easy hand_eye2手眼标定
目录
4.1 修改remappings,为camera发布的topic
4.3修改 marker_size,为生成的marker尺寸
6.1 rqt中选择/aruco_single/result话题可以看见二维码及其坐标系
0. 项目推荐(新增)
推荐moveit2官方示例,手眼标定Hand-Eye Calibration,新手本人提供了步骤参考:
强力推荐,二次重标定误差小,精度可达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,
])
更多推荐
所有评论(0)