具身智能:零基础入门睿尔曼机械臂(七)—— 衔接开源代码!机械臂手眼标定实操

简介: 本文详解睿尔曼机械臂手眼标定全流程,涵盖环境搭建、设备准备、眼在手上/外的标定步骤、常见问题解决及标定结果在视觉抓取中的应用,助你实现精准视觉引导操作。

@[TOC]

前言

在上一篇博客中,我们详细拆解了睿尔曼开源手眼标定代码库的核心代码逻辑。今天,我们将聚焦实操层面,从环境搭建、设备准备,到具体的标定流程(眼在手上/眼在手外)、常见问题解决,再到标定结果的实际应用,带大家完整走通机械臂手眼标定的全流程。

注:文章部分图以及代码来自睿尔曼科技官方博客 链接如下:
https://develop.realman-robotics.com/AI/developerGuide/hand/

一、标定前期准备

在开始标定前,我们需要完成环境配置和设备准备两大核心工作,这一步直接影响后续标定的顺利程度和结果精度。

1.1 环境要求与配置

手眼标定依赖特定的操作系统和Python环境,建议严格按照以下版本要求配置,避免因版本兼容问题踩坑。

1.1.1 基础环境准备

项目 版本要求
操作系统 Ubuntu / Windows
Python 3.9 及以上

1.1.2 Python依赖包安装

标定程序需要依赖多个Python科学计算和计算机视觉库,具体版本要求如下:

包名 版本要求
numpy 2.0.2
opencv-python 4.10.0.84
pyrealsense2 2.55.1.6486
scipy 1.13.1

最便捷的安装方式是使用代码库中的requirements.txt文件,在Python环境中执行以下命令即可一键安装所有依赖:


pip install -r requirements.txt

1.2 设备准备

确保以下设备齐全且能正常工作,设备的稳定性直接影响标定精度:

  • 机械臂:支持睿尔曼RM75、RM65、RM63、GEN72型号

  • 相机:Intel RealSense Depth Camera D435(含专用数据线)

  • 网络设备:网线(用于连接电脑与机械臂)

  • 标定板:1号或2号标定板(可打印纸质版,或在淘宝搜索“标定板棋盘格”购买成品)

1.png

二、详细标定流程

手眼标定主要分为“眼在手上”和“眼在手外”两种场景,核心区别在于相机的安装位置:眼在手上是相机固定在机械臂末端,随机械臂运动;眼在手外是相机固定不动,标定板随机械臂运动。两种场景的标定流程略有差异,我们分别详细讲解。

2.1 通用步骤:参数配置

无论哪种场景,在采集数据前都需要先配置标定板参数,步骤如下:

  1. 找到代码库中的配置文件config.yaml

  2. 根据实际使用的标定板,修改以下三个核心参数:

2.png

- xx:标定板横向角点数(长边格子数减1),默认11(例:长边12个格子,角点数为11);

- YY:标定板纵向角点数(短边格子数减1),默认8(例:短边9个格子,角点数为8);

- L:标定板单个方格的实际尺寸(单位:米),默认0.03米。

2.2 场景一:眼在手上(相机随机械臂运动)

核心逻辑:标定板固定,相机随机械臂末端运动,采集不同姿态下的标定板图像,计算相机相对于机械臂末端的位姿。

3.png

2.2.1 采集数据

  1. 连接设备:用相机专用数据线连接电脑与D435相机,用网线连接电脑与机械臂;

  2. 配置IP:将电脑IP与机械臂设置为同一网段(机械臂IP为192.168.1.18时,电脑设为1网段;IP为192.168.10.18时,电脑设为10网段);

4.png

  1. 放置标定板:将标定板固定在机械臂工作区内的平面上,确保相机(机械臂末端)能从不同视角观测到,标定期间不得移动标定板;

  2. 运行采集脚本:执行collect_data.py,会弹出相机视野弹窗;

  3. 调整姿态与采集:拖动机械臂末端,使标定板在弹窗中清晰、完整显示,且标定板与相机镜面呈一定角度(避免正对,正对为错误姿势);将光标放在弹窗上,按键盘s键采集数据;

5.png
6.png

  1. 重复采集:移动机械臂15-20次,每次移动时旋转角度尽量大于30°,确保在X、Y、Z三个轴上都有足够的旋转变化(建议先绕末端Z轴旋转,再绕X轴旋转),共采集15-20张不同姿态的图像。

7.png

2.2.2 计算标定结果

采集完成后,运行以下脚本即可得到标定结果:


python compute_in_hand.py

运行成功后,会输出相机坐标系相对于机械臂末端坐标系的旋转矩阵平移向量(平移向量单位:米)。

2.3 场景二:眼在手外(相机固定不动)

核心逻辑:相机固定,标定板固定在机械臂末端随机械臂运动,采集不同姿态下的标定板图像,计算相机相对于机械臂基坐标系的位姿。

8.png

2.3.1 采集数据

  1. 连接设备:同眼在手上场景,用数据线连接相机与电脑,网线连接机械臂与电脑;

  2. 配置IP:同眼在手上场景,确保电脑与机械臂同一网段;
    9.png

  1. 安装标定板与固定相机:将标定板(打印纸质较小的板子,方便固定)固定在机械臂末端,相机固定不动,移动机械臂末端,使标定板出现在相机视野里。
    标定过程中,标定板安装在机械臂末端执行器上并随机械臂移动。可以直接固定在工具法兰上或由夹具固定安装,安装的确切位置不重要,因为不必知道标定板和末端执行器的相对位姿。重要的是标定板在运动过程中不会出现相对于工具法兰或夹具的位移,它必须被良好地固定住或被夹具紧紧地抓住。建议使用由刚性材料制成的安装支架。

  2. 运行采集脚本:执行collect_data.py,弹出相机视野弹窗;

  3. 调整姿态与采集:拖动机械臂末端,使标定板在弹窗中清晰、完整显示,且与相机镜面呈一定角度;按键盘s键采集数据;

  4. 重复采集:同眼在手上场景,移动机械臂15-20次,每次旋转角度大于30°,覆盖X、Y、Z三轴旋转变化,采集15-20张图像。

2.3.2 计算标定结果

采集完成后,运行以下脚本得到标定结果:


python compute_to_hand.py

运行成功后,会输出相机坐标系相对于机械臂基坐标系的旋转矩阵平移向量(平移向量单位:米)。

2.4 误差范围说明

标定结果的精度受采集图像质量影响,正常情况下,平移向量与实际值的差距应控制在1cm之内。若误差过大,需检查图像采集质量(如标定板是否清晰、姿态变化是否充足),重新采集数据进行标定。

三、标定过程常见问题与解决方案

在执行标定计算脚本时,最常见的问题是“运动信息不足”导致标定失败,我们针对性解决:

问题1:标定失败,报错“Not enough informative motions”

问题描述

执行compute_in_hand.pycompute_to_hand.py时,报错:


[ERROR:0@1.418] global calibration_handeye.cpp:335 calibrateHandEyeTsai Hand-eye calibration failed! Not enough informative motions--include larger rotations.

问题原因

采集数据时,机械臂的旋转运动不足,尤其是缺少足够大的旋转角度变化,导致标定算法无法准确计算手眼关系。

解决方案

  • 增加旋转运动:确保机械臂在X、Y、Z三个轴上的旋转角度均超过30°,提供丰富的运动信息;

  • 多样化姿态:避免机械臂只在小范围平移或只绕单一轴旋转,增加姿态多样性;

  • 增加采集次数:确保采集的图像数量不少于15张,更多样本能提升标定稳定性和准确性。

四、标定结果的实际应用:机械臂抓取

手眼标定的核心目的是实现“视觉引导抓取”——通过相机识别物体位姿,结合标定结果将物体位姿转换为机械臂可识别的基坐标系位姿,进而控制机械臂完成抓取。以下分两种场景讲解具体应用(含代码)。

4.1 场景一:眼在手上的抓取应用

核心逻辑

物体位姿转换流程:
物体在相机坐标系位姿 →(标定结果)→ 物体在机械臂末端坐标系位姿 →(机械臂API)→ 物体在机械臂基坐标系位姿

机械臂通过基坐标系下的物体位姿,计算末端执行器的运动轨迹,完成抓取。

10.png

应用代码

以下代码分别实现“物体为3D点”和“物体为完整位姿”两种情况下的坐标转换(需将代码中的旋转矩阵和平移向量替换为你的标定结果)。

情况1:物体在相机坐标系为3D点(x,y,z)


import numpy as np
from scipy.spatial.transform import Rotation as R

# 相机坐标系到机械臂末端坐标系的旋转矩阵和平移向量(手眼标定得到)
rotation_matrix = np.array([[-0.00235395 , 0.99988123 ,-0.01523124],
                            [-0.99998543, -0.00227965, 0.0048937],
                            [0.00485839, 0.01524254, 0.99987202]])
translation_vector = np.array([-0.09321419, 0.03625434, 0.02420657])

def convert(x, y, z, x1, y1, z1, rx, ry, rz):
    """
    计算物体相对于机械臂基座的位姿(x, y, z)
    参数:
        x,y,z: 深度相机识别的物体坐标(相机坐标系)
        x1,y1,z1,rx,ry,rz: 机械臂末端位姿(基坐标系,弧度)
    返回:
        obj_base_coordinates: 物体在机械臂基坐标系的坐标
    """
    # 深度相机识别物体返回的坐标
    obj_camera_coordinates = np.array([x, y, z])

    # 机械臂末端的位姿转换为齐次变换矩阵
    position = np.array([x1, y1, z1])
    orientation = R.from_euler('xyz', [rx, ry, rz], degrees=False).as_matrix()
    T_base_to_end_effector = np.eye(4)
    T_base_to_end_effector[:3, :3] = orientation
    T_base_to_end_effector[:3, 3] = position

    # 相机到末端的齐次变换矩阵(标定结果)
    T_camera_to_end_effector = np.eye(4)
    T_camera_to_end_effector[:3, :3] = rotation_matrix
    T_camera_to_end_effector[:3, 3] = translation_vector

    # 齐次坐标转换:相机坐标系 → 末端坐标系 → 基坐标系
    obj_camera_coordinates_homo = np.append(obj_camera_coordinates, [1])
    obj_end_effector_coordinates_homo = T_camera_to_end_effector.dot(obj_camera_coordinates_homo)
    obj_base_coordinates_homo = T_base_to_end_effector.dot(obj_end_effector_coordinates_homo)

    # 提取非齐次坐标
    obj_base_coordinates = list(obj_base_coordinates_homo[:3])
    return obj_base_coordinates

情况2:物体在相机坐标系为完整位姿(x,y,z,rx,ry,rz)


import numpy as np
from scipy.spatial.transform import Rotation as R

# 相机坐标系到机械臂末端坐标系的旋转矩阵和平移向量(手眼标定得到)
rotation_matrix = np.array([[-0.00235395 , 0.99988123 ,-0.01523124],
                            [-0.99998543, -0.00227965, 0.0048937],
                            [0.00485839, 0.01524254, 0.99987202]])
translation_vector = np.array([-0.09321419, 0.03625434, 0.02420657])

def decompose_transform(matrix):
    """将齐次变换矩阵分解为平移向量和欧拉角(rx, ry, rz)"""
    translation = matrix[:3, 3]
    rotation = matrix[:3, :3]

    sy = np.sqrt(rotation[0, 0] ** 2 + rotation[1, 0] ** 2)
    singular = sy < 1e-6

    if not singular:
        rx = np.arctan2(rotation[2, 1], rotation[2, 2])
        ry = np.arctan2(-rotation[2, 0], sy)
        rz = np.arctan2(rotation[1, 0], rotation[0, 0])
    else:
        rx = np.arctan2(-rotation[1, 2], rotation[1, 1])
        ry = np.arctan2(-rotation[2, 0], sy)
        rz = 0
    return translation, rx, ry, rz

def convert(x,y,z,rx,ry,rz,x1,y1,z1,rx1,ry1,rz1):
    """
    计算物体相对于机械臂基座的完整位姿
    参数:
        x,y,z,rx,ry,rz: 机械臂末端位姿(基坐标系,弧度)
        x1,y1,z1,rx1,ry1,rz1: 深度相机识别的物体位姿(相机坐标系)
    返回:
        result: 物体在基坐标系的位姿(平移向量 + 欧拉角)
    """
    # 机械臂末端位姿转换为齐次变换矩阵
    end_position = np.array([x, y, z])
    end_orientation = R.from_euler('xyz', [rx, ry, rz], degrees=False).as_matrix()
    T_end_to_base = np.eye(4)
    T_end_to_base[:3, :3] = end_orientation
    T_end_to_base[:3, 3] = end_position

    # 相机到末端的齐次变换矩阵(标定结果)
    T_camera_to_end = np.eye(4)
    T_camera_to_end[:3, :3] = rotation_matrix
    T_camera_to_end[:3, 3] = translation_vector

    # 物体在相机坐标系的位姿转换为齐次变换矩阵
    obj_position = np.array([x1, y1, z1])
    obj_orientation = R.from_euler('xyz', [rx1, ry1, rz1], degrees=False).as_matrix()
    T_object_to_camera = np.eye(4)
    T_object_to_camera[:3, :3] = obj_orientation
    T_object_to_camera[:3, 3] = obj_position

    # 齐次坐标转换:物体 → 相机 → 末端 → 基坐标系
    obj_end_coords_homo = T_camera_to_end.dot(T_object_to_camera)
    obj_base_coords = T_end_to_base.dot(obj_end_coords_homo)

    # 分解得到最终位姿
    result = decompose_transform(obj_base_coords)
    return result

4.2 场景二:眼在手外的抓取应用

核心逻辑

物体位姿转换流程:
物体在相机坐标系位姿 →(标定结果)→ 物体在机械臂基坐标系位姿

因相机固定,标定结果直接给出相机与基坐标系的关系,无需经过末端坐标系转换,流程更简洁。

11.png

应用代码

以下代码同样分“3D点”和“完整位姿”两种情况,需替换为眼在手外的标定结果。

情况1:物体在相机坐标系为3D点(x,y,z)


import numpy as np

# 相机坐标系到机械臂基坐标系的旋转矩阵和平移向量(手眼标定得到)
rotation_matrix = np.array([[-0.00235395 , 0.99988123 ,-0.01523124],
                            [-0.99998543, -0.00227965, 0.0048937],
                            [0.00485839, 0.01524254, 0.99987202]])
translation_vector = np.array([-0.09321419, 0.03625434, 0.02420657])

def convert(x, y, z):
    """
    计算物体相对于机械臂基座的坐标
    参数:
        x,y,z: 深度相机识别的物体坐标(相机坐标系)
    返回:
        obj_base_coordinates: 物体在基坐标系的坐标
    """
    obj_camera_coordinates = np.array([x, y, z])

    # 相机到基坐标系的齐次变换矩阵(标定结果)
    T_camera_to_base = np.eye(4)
    T_camera_to_base[:3, :3] = rotation_matrix
    T_camera_to_base[:3, 3] = translation_vector

    # 齐次坐标转换
    obj_camera_coords_homo = np.append(obj_camera_coordinates, [1])
    obj_base_coords_homo = T_camera_to_base.dot(obj_camera_coords_homo)
    obj_base_coordinates = list(obj_base_coords_homo[:3])
    return obj_base_coordinates

情况2:物体在相机坐标系为完整位姿(x,y,z,rx,ry,rz)


import numpy as np
from scipy.spatial.transform import Rotation as R

# 相机坐标系到机械臂基坐标系的旋转矩阵和平移向量(手眼标定得到)
rotation_matrix = np.array([[-0.00235395 , 0.99988123 ,-0.01523124],
                            [-0.99998543, -0.00227965, 0.0048937],
                            [0.00485839, 0.01524254, 0.99987202]])
translation_vector = np.array([-0.09321419, 0.03625434, 0.02420657])

def decompose_transform(matrix):
    """将齐次变换矩阵分解为平移向量和欧拉角"""
    translation = matrix[:3, 3]
    rotation = matrix[:3, :3]

    sy = np.sqrt(rotation[0, 0] ** 2 + rotation[1, 0] ** 2)
    singular = sy < 1e-6

    if not singular:
        rx = np.arctan2(rotation[2, 1], rotation[2, 2])
        ry = np.arctan2(-rotation[2, 0], sy)
        rz = np.arctan2(rotation[1, 0], rotation[0, 0])
    else:
        rx = np.arctan2(-rotation[1, 2], rotation[1, 1])
        ry = np.arctan2(-rotation[2, 0], sy)
        rz = 0
    return translation, rx, ry, rz

def convert(x, y, z, rx, ry, rz):
    """
    计算物体相对于机械臂基座的完整位姿
    参数:
        x,y,z,rx,ry,rz: 深度相机识别的物体位姿(相机坐标系)
    返回:
        result: 物体在基坐标系的位姿(平移向量 + 欧拉角)
    """
    # 物体在相机坐标系的位姿转换为齐次变换矩阵
    obj_position = np.array([x, y, z])
    obj_orientation = R.from_euler('xyz', [rx, ry, rz], degrees=False).as_matrix()
    T_object_to_camera = np.eye(4)
    T_object_to_camera[:3, :3] = obj_orientation
    T_object_to_camera[:3, 3] = obj_position

    # 相机到基坐标系的齐次变换矩阵(标定结果)
    T_camera_to_base = np.eye(4)
    T_camera_to_base[:3, :3] = rotation_matrix
    T_camera_to_base[:3, 3] = translation_vector

    # 齐次坐标转换:物体 → 相机 → 基坐标系
    obj_base_coords = T_camera_to_base.dot(T_object_to_camera)
    result = decompose_transform(obj_base_coords)
    return result

五、总结

本文详细讲解了基于睿尔曼开源代码库的机械臂手眼标定全流程,包括前期环境与设备准备、两种核心场景(眼在手上/手外)的标定步骤、常见问题解决,以及标定结果在视觉引导抓取中的实际应用。核心要点可总结为:

  • 环境配置需严格匹配版本要求,避免兼容问题;

  • 数据采集的关键是“姿态多样化”,旋转角度需足够大(>30°);

  • 标定结果的核心是旋转矩阵和平移向量,需根据安装场景(眼在手上/外)正确应用于坐标转换;

  • 若标定失败,优先检查运动姿态是否充足,重新采集数据即可解决大部分问题。

掌握手眼标定后,你可以进一步探索机械臂的视觉引导分拣、精准装配等高级功能。如果在实操过程中有其他问题,欢迎在评论区交流

目录
相关文章
|
30天前
|
存储 数据采集 算法
具身智能:零基础入门睿尔曼机械臂(六)——手眼标定代码库详解,从原理到实践
本文详解睿尔曼手眼标定代码库,涵盖眼在手上与眼在手外两种模式的实现原理及核心代码解析。内容包括数据采集、位姿处理、相机标定与手眼矩阵求解全流程,结合OpenCV的Tsai算法实现高精度坐标转换,助力机器人视觉精准抓取应用开发。
204 2
|
1月前
|
数据采集 算法 机器人
具身智能:零基础入门睿尔曼机械臂(五)—— 手眼标定核心原理与数学求解
本文系统讲解手眼标定技术,涵盖Eye-in-Hand与Eye-to-Hand两种架构,深入推导AX=XB方程的数学原理与求解方法,结合实际应用场景和操作步骤,为机器人视觉开发者提供从理论到实践的完整指南。
300 9
|
机器学习/深度学习 算法
低光图像增强
这篇摘要讨论了低光照图像增强技术,涉及HDRNet、GAN、轻量化伪影、语义分割网络和Retinex等方法。核心任务是提升图像亮度和细节。方法包括分布映射(如伽马矫正、直方图均衡化)、模型优化(Retinex理论)和深度学习(亮度增强与噪声去除)。传统方法不依赖数据,但可能产生伪影;深度学习方法需大量训练数据,无监督学习更优。不足之处在于缺乏成对数据集和精确标签。
525 1
|
30天前
|
人工智能 安全 前端开发
写单元测试太痛苦?教你用DeepSeek/通义千问一键生成高质量测试代码
单元测试难写且枯燥?本文分享一套经过验证的AI生成指令,将DeepSeek/通义千问化身为10年经验的测试专家。支持自动Mock、全场景覆盖和参数化测试,让代码质量保障从"体力活"变成高效的"指挥活"。
373 3
|
JavaScript Java 关系型数据库
基于 SpringBoot+vue的地方美食系统(Java 毕业设计)上
基于 SpringBoot+vue的地方美食系统(Java 毕业设计)
|
1月前
|
网络协议 搜索推荐 API
具身智能:零基础入门睿尔曼机械臂(二)——从API例程到Python实操全解析
本文详解睿尔曼第三代机械臂的Python控制入门,涵盖连接配置、多型号适配与核心运动指令(movej/movel/movec),通过解析例程代码,帮助零基础用户快速掌握机械臂基础控制逻辑并实现实操运行。
195 0
|
1月前
|
传感器 机器学习/深度学习 人工智能
具身智能——机械臂全解析:从技术原理到产业生态,解锁智能执行新范式
机械臂作为“智能执行终端”,融合机械、电子、控制与AI技术,已从替代人工迈向价值共创。本文系统解析其结构、控制原理、产业现状与多领域应用,展现国产化崛起与智能化升级的全貌。
611 0
|
1月前
|
Linux 开发工具 Python
具身智能:零基础入门睿尔曼机械臂(三)——夹爪抓取与释放控制全解析
本文详解睿尔曼第三代机械臂电动夹爪的Python SDK控制方法,聚焦`set_gripper_pick_on`与`set_gripper_release`核心函数,拆解速度、力度、阻塞等参数含义,结合“运动+抓取+释放”完整流程代码,手把手实现夹爪抓放实操,助力零基础用户快速掌握从代码到动作的全流程控制。
199 13
|
26天前
|
人工智能 JSON 文字识别
从读图到懂图,AI+金融理解力新升级
OCR要落伍了?多模态大模型凭借端到端的图像识别与语义理解能力,正在颠覆传统 OCR 的应用逻辑,预示着图像识别与理解正迈向新一代的技术范式。
142 0
|
前端开发 JavaScript UED
React 图标库使用指南
本文详细介绍如何在 React 项目中使用 `react-icons` 等图标库,涵盖环境搭建、基础使用、常见问题与易错点、高级用法等内容,并通过代码案例进行说明。适合初学者和进阶开发者参考。
1038 8