2026/8/3 2:08:34

Reachy Mini Lite机械臂开发指南:从ROS 2连接到视觉伺服实战

Reachy Mini Lite机械臂开发指南:从ROS 2连接到视觉伺服实战 1. 项目概述为什么选择Reachy Mini Lite最近在工作室捣鼓机器人不少朋友看到我桌上那个“小胳膊”都会好奇地问“这是个啥看起来挺酷的。” 这就是我们今天要聊的主角——Reachy Mini Lite。它不是一个成品玩具而是一个开源的、模块化的机器人开发平台核心就是一个高精度的7自由度机械臂。如果你对机器人学、ROS机器人操作系统、或者想找一个能真实模拟工业场景但又没那么昂贵的实验平台感兴趣那Reachy Mini Lite绝对值得你花时间研究。简单来说Reachy Mini Lite解决了一个很实际的问题让开发者、研究者甚至是有热情的爱好者能够在一个成本可控、软件生态成熟、硬件开箱即用的环境里快速验证机器人算法、进行人机交互实验或者开发新的应用。它不像动辄几十上百万的工业机械臂那样令人望而却步也不像一些玩具级产品那样精度和扩展性都捉襟见肘。它定位在中间提供了一个非常扎实的“ playground”。我选择它的原因很直接我需要一个能稳定运行ROS 2、关节反馈精度高、并且有活跃社区支持的机械臂来测试我们团队在轨迹规划和人机协作方面的一些新想法。Reachy Mini Lite的官方SDK和URDF模型做得相当规范省去了自己从零建模和驱动开发的巨大工作量让我能把精力集中在算法本身。接下来我就从开箱到让它“活”起来详细拆解整个过程并分享一些我踩过的坑和总结的经验。2. 开箱与硬件初印象不只是“迷你”当你拿到Reachy Mini Lite的箱子第一感觉可能是“比想象中小巧”。但千万别被“Mini”这个名字误导它的“Lite”主要体现在去除了一些高级传感器如力觉传感器和更复杂的末端执行器专注于提供核心的机械臂运动能力。开箱后你会看到以下几个核心部件机械臂本体一个7自由度的机械臂通常包括肩部3个关节、肘部1个关节、腕部3个关节这是它的核心。关节采用的是高精度的直流无刷电机搭配谐波减速器这是保证运动平稳性和位置精度的关键。外壳是3D打印的通常是PLA或ABS材质你可以清晰地看到内部的走线和部分结构这种开源硬件常见的“裸露”风格反而方便你观察和理解其机械结构。控制箱一个集成了电源、电机驱动板和主控计算机的小盒子。最新版的Reachy通常内置了一台搭载了Ubuntu和ROS 2的微型电脑如Intel NUC或类似规格的工控机这意味着它是一台“自带大脑”的机器人你只需要通过网线或Wi-Fi连接到它就可以开始编程和控制无需额外配置一台主机。电源适配器为整个系统供电。必要的线缆连接机械臂和控制箱的线束通常是一条多芯的航空插头线负责传输电力、电机控制信号和编码器反馈。硬件上的几个关键点需要注意关节限位在初次上电前务必手动检查每个关节的活动范围确保没有任何线缆被机械结构挤压或缠绕。虽然软件里有软限位但养成先进行物理检查的习惯能避免很多不必要的风险。供电安全使用原装电源适配器。机械臂在启动和急停时电流可能较大劣质电源可能导致驱动板不稳定甚至损坏。安装固定机械臂底座有标准的法兰孔。我强烈建议你为它准备一个坚固、沉重的底座比如一块厚重的铝板或直接固定在实验台上。在高速运动或承载末端工具时一个稳定的基座是安全性和精度的基础。我最初把它放在一张普通的办公桌上结果在进行快速点到点运动时整个桌子都在微微共振严重影响了末端定位的重复精度。注意首次通电时机械臂可能会执行一个“回零”或自检动作发出一些电机运转的声音。这是正常现象。请确保机械臂周围有足够的空间建议半径1米内无障碍物并保持警惕随时准备按下急停开关如果控制箱配备的话。3. 软件环境搭建与首次连接Reachy Mini Lite的软件核心是ROS 2。官方通常已经预装了Ubuntu操作系统和ROS 2 Humble或Iron版本并安装了Reachy专用的SDK。你的开发机可以是另一台Ubuntu电脑也可以是Windows/Mac通过一些方式需要与Reachy建立通信。3.1 网络配置最稳定的方式是使用网线直连或者将Reachy和你的开发机连接到同一个局域网Wi-Fi或交换机。假设Reachy的IP地址是192.168.1.100你的电脑IP是192.168.1.50。查找Reachy的IP如果不知道IP通常可以在Reachy的屏幕上看到如果它有屏幕或者通过路由器后台查看连接设备列表。更“机器人”的方式是先用键盘和显示器直接接入Reachy的控制箱在终端里输入ip addr命令查看。配置主机名解析可选但推荐为了避免记忆IP可以在你的开发机的/etc/hosts文件中添加一行192.168.1.100 reachy。这样以后你就可以用reachy这个主机名来代替IP地址。配置ROS 2环境变量这是ROS 2多机通信的关键。在你的开发机终端里你需要设置ROS_DOMAIN_ID并指定Reachy的地址。# 在你的开发机上操作 export ROS_DOMAIN_ID0 # 确保Reachy和你的电脑使用相同的DOMAIN_ID默认为0 export ROS_MASTER_URIhttp://reachy:11311 # 如果使用ROS 1的桥接或部分工具可能需要 # 对于ROS 2更关键的是设置RMW实现和发现 export RMW_IMPLEMENTATIONrmw_cyclonedds_cpp # 使用CycloneDDS跨子网能力更强 export CYCLONEDDS_URIpath_to_your_config_file # 可以配置网络发现最简单初学的方式是使用ROS_DOMAIN_ID。确保Reachy控制箱里的ROS 2也设置了相同的ROS_DOMAIN_ID通常已在镜像中预设。这样在同一个局域网内它们就能自动发现彼此。3.2 安装Reachy SDK在开发机上即使Reachy本体有了SDK你在自己的开发机上也需要安装客户端库以便编写和运行控制程序。# 假设你使用Ubuntu和ROS 2 Humble sudo apt update # 安装Python3的reachy SDK包 pip3 install reachy2-sdk # 或者如果你想从源码安装以获得最新特性推荐给深度开发者 mkdir -p ~/reachy_ws/src cd ~/reachy_ws/src git clone https://github.com/pollen-robotics/reachy2_sdk.git cd ~/reachy_ws rosdep install --from-paths src --ignore-src -r -y colcon build --symlink-install source install/setup.bash3.3 首次连接测试安装好SDK后就可以尝试连接了。创建一个简单的Python测试脚本test_connection.py#!/usr/bin/env python3 import asyncio from reachy2_sdk import ReachySDK async def main(): # 连接到Reachy使用它的主机名或IP reachy await ReachySDK.connect(hostreachy) # 或者 host192.168.1.100 # 打印机器人信息 print(fConnected to Reachy: {reachy.name}) print(fRobot has {len(reachy.arms)} arm(s)) # 获取右臂对象Reachy Mini Lite通常被配置为右臂 right_arm reachy.r_arm print(fRight arm joints: {[joint.name for joint in right_arm.joints]}) # 读取当前所有关节位置 current_positions [joint.present_position for joint in right_arm.joints] print(fCurrent joint positions: {current_positions}) # 让机械臂稍微动一下例如肘关节轻微弯曲 # 先切换到位置控制模式 await right_arm.turn_on() # 设置目标位置弧度制这里让肘关节通常索引为3的关节弯曲30度 import math target_positions current_positions.copy() target_positions[3] math.radians(30) # 增加30度 # 平滑移动到目标位置 await right_arm.goto( goal_positionstarget_positions, duration2.0 # 用2秒时间完成动作 ) # 关闭连接 await reachy.disconnect() if __name__ __main__: asyncio.run(main())运行这个脚本python3 test_connection.py。如果一切顺利你会看到终端打印出关节信息并且机械臂的肘关节会缓慢地弯曲一个角度。恭喜这说明你的软硬件连接已经成功实操心得防火墙首次连接失败十有八九是防火墙问题。确保你的开发机和Reachy的防火墙放行了ROS 2使用的端口默认是UDP 7400-7600左右的一系列端口。一个简单的测试方法是ping reachy和ros2 node list在设置好环境变量后看是否能发现对方。异步编程Reachy SDK大量使用了Python的asyncio库。如果你不熟悉异步编程会觉得代码写法有点别扭。记住核心使用async/await并通过asyncio.run()来启动主函数。所有涉及机器人动作的调用基本都是异步的。关节索引不同版本的SDK或URDF模型关节顺序可能略有差异。最可靠的方式是打印出joint.name来确认每个关节对应的索引而不是硬编码数字。比如可能是r_shoulder_pitch,r_shoulder_roll,r_arm_yaw,r_elbow_pitch,r_wrist_pitch,r_wrist_roll,r_wrist_yaw。4. 核心控制模式与编程实践连接成功只是第一步真正驾驭Reachy Mini Lite在于理解其控制模式。它主要提供了几种不同层级的控制方式适用于不同场景。4.1 关节空间位置控制这是最基础的控制方式直接给每个关节设定一个目标角度弧度。上面的测试脚本就是这种模式。关键在于goto函数你可以指定目标位置列表、运动时间duration或运动速度velocity。我强烈建议在初期始终使用duration参数来控制运动时间而不是直接指定速度这样更容易预测机器人的运动过程避免速度过快产生冲击。async def joint_space_move(): reachy await ReachySDK.connect(hostreachy) arm reachy.r_arm await arm.turn_on() # 定义几个关键姿势的关节角度单位弧度 # 姿势A伸展状态 (示例值需根据实际校准) pose_a [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] # 姿势B准备抓取姿态 pose_b [math.radians(30), math.radians(-20), math.radians(10), math.radians(-90), math.radians(0), math.radians(0), math.radians(0)] # 缓慢移动到姿势A await arm.goto(goal_positionspose_a, duration3.0) await asyncio.sleep(1) # 等待1秒 # 缓慢移动到姿势B await arm.goto(goal_positionspose_b, duration3.0) await reachy.disconnect()4.2 笛卡尔空间末端控制这是更直观、也更常用的控制方式。你不需要关心每个关节怎么转只需要告诉机器人“末端执行器要移动到空间中的哪个点X, Y, Z并且保持什么姿态Roll, Pitch, Yaw”。SDK会自动进行逆运动学IK解算求出对应的关节角度。async def cartesian_move(): reachy await ReachySDK.connect(hostreachy) arm reachy.r_arm await arm.turn_on() # 获取当前末端位姿相对于基座标系 current_pose arm.forward_kinematics() print(fCurrent end-effector pose: Pos{current_pose.pos}, Rot{current_pose.rot}) # 定义目标位置单位米和姿态四元数或欧拉角 # 例如让末端在X方向移动0.1米Z方向降低0.05米保持当前姿态 from reachy2_sdk.math import Pose, Rotation target_position [ current_pose.pos[0] 0.1, # X current_pose.pos[1], # Y 不变 current_pose.pos[2] - 0.05, # Z ] # 保持原有旋转单位四元数 target_rotation current_pose.rot target_pose Pose(target_position, target_rotation) # 使用逆运动学移动到目标位姿 # 这里需要先进行IK解算检查是否可达 ik_solution arm.inverse_kinematics(target_pose) if ik_solution is not None: # 如果解算成功则移动到对应的关节角度 await arm.goto(goal_positionsik_solution, duration2.0) else: print(目标位姿不可达) await reachy.disconnect()注意事项奇异性当机械臂完全伸直或处于某些特殊构型时逆运动学解可能不存在或不稳定雅可比矩阵秩缺失。在编写笛卡尔空间控制代码时必须加入IK解算成功的判断否则机器人可能会尝试移动到无法到达的位置导致关节剧烈抖动或报错。姿态表示机器人学中姿态可以用旋转矩阵、四元数、欧拉角等多种方式表示。Reachy SDK内部通常使用四元数x, y, z, w。如果你更熟悉欧拉角Roll, Pitch, Yaw需要进行转换。Python的scipy.spatial.transform.Rotation库是处理这类转换的利器。轨迹规划简单的goto是点到点的运动末端轨迹不一定是直线。如果你需要末端精确走一条直线直线插补或圆弧需要在外部进行轨迹规划生成一系列中间点路径点然后让机械臂依次运动。ROS 2中的moveit2框架可以很好地完成这个工作但集成需要额外配置。4.3 力控与导纳控制模拟Reachy Mini Lite是“Lite”版本通常不配备直接的力/力矩传感器。但是你可以通过电机的电流反馈来间接估计关节端的输出力矩从而实现简单的力交互或导纳控制。这属于进阶应用。其原理是电机电流与输出扭矩成正比在稳态下。通过SDK可以读取每个关节的present_current或present_load。当你在末端轻轻推拉机械臂时关节电机会抵抗这个运动电流会发生变化。你可以编写一个控制循环检测到这个电流变化即外力然后根据一个虚拟的“弹簧-阻尼”模型导纳模型计算出机器人应该产生的补偿运动。async def simple_impedance_control(): reachy await ReachySDK.connect(hostreachy) arm reachy.r_arm await arm.turn_on() # 设置一个虚拟的导纳参数质量(M)、阻尼(B)、刚度(K) # 这里简化处理只对某个关节进行模拟 M, B, K 0.1, 5.0, 50.0 # 示例值需要精细调整 joint_index 3 # 肘关节 initial_position arm.joints[joint_index].present_position target_position initial_position velocity 0.0 try: while True: # 1. 读取当前关节位置和估计的负载与电流/力矩相关 current_pos arm.joints[joint_index].present_position # 注意present_load 可能需要根据型号确认有些版本用 current current_load arm.joints[joint_index].present_current # 或 present_load # 2. 将负载电流转换为估计的外力矩需要校准系数 # 假设一个简单的比例关系系数k需要实验标定 k 0.001 # 示例系数完全不准必须自己标定 estimated_torque current_load * k # 3. 导纳模型计算 M * a B * v K * (x - x0) F_ext # 其中 a 是加速度v 是速度x是当前位置x0是平衡位置F_ext是外力 # 我们离散化处理计算目标位置的偏移 stiffness_force K * (current_pos - target_position) damping_force B * velocity # 根据 F_ext M*a 忽略加速度项简化计算直接由力差产生位置修正 position_delta (estimated_torque - damping_force - stiffness_force) / K * 0.01 # 加上一个小增益 new_target_position target_position position_delta # 4. 更新速度和目标位置非常简化的积分 velocity position_delta / 0.01 # 假设循环周期0.01秒 target_position new_target_position # 5. 发送新的目标位置给关节只控制一个关节作为示例 goal_positions [jp for jp in arm.present_position] # 获取所有关节当前位置 goal_positions[joint_index] new_target_position # 使用一个非常短的时间实现“柔顺”的效果 await arm.goto(goal_positionsgoal_positions, duration0.05) await asyncio.sleep(0.01) # 控制循环周期 except KeyboardInterrupt: print(Impedance control stopped.) finally: await reachy.disconnect()重要警告上面的代码是一个极度简化的概念演示绝对不要直接用于真实机器人而不进行严格的安全检查和参数标定不恰当的参数可能导致机器人剧烈振荡甚至损坏。真正的力控实现需要精确的关节力矩标定建立电流与扭矩的准确关系。考虑重力补偿机械臂自身的重力会产生持续的关节力矩。更稳定和精确的控制循环通常需要实时内核。完善的安全边界和急停逻辑。5. 常见应用场景与项目实例有了基本的控制能力Reachy Mini Lite能做什么它的应用场景非常广泛尤其适合算法验证和原型开发。5.1 视觉伺服Visual Servoing这是机器人领域一个经典课题。结合一个摄像头可以安装在末端也可以是固定的全局相机让机器人根据视觉反馈自动调整位置。例如让机械臂末端去对准一个彩色小球。硬件在Reachy的末端安装一个USB摄像头或者在工作台上方固定一个相机。软件使用OpenCV处理图像。在ROS 2中你可以使用cv_bridge将图像消息转换为OpenCV格式或者直接用rclpy配合OpenCV。流程相机捕捉图像识别目标比如通过颜色阈值找到小球的像素中心。计算目标在图像中的位置与图像中心的位置偏差像素误差。将这个像素误差通过一个相机模型标定好的内参转换到相机坐标系下的空间误差可能需要深度信息如果是单目则需其他假设或传感器融合。将空间误差转换到机器人基座标系。根据误差生成机器人末端的运动速度或增量位移指令比例控制。循环执行直到误差小于阈值。# 伪代码/简化流程示意 async def visual_servoing(): # 初始化机器人、摄像头 reachy await ReachySDK.connect(...) cap cv2.VideoCapture(0) # 或订阅ROS图像话题 while True: ret, frame cap.read() # 图像处理找到目标 target_pixel_x, target_pixel_y find_red_ball_center(frame) # 计算图像中心与目标中心的像素偏差 img_center_x, img_center_y frame.shape[1]//2, frame.shape[0]//2 error_x target_pixel_x - img_center_x error_y target_pixel_y - img_center_y # 将像素偏差转换为空间运动指令简化假设一个比例增益和固定的深度 # 这里需要一个相机标定矩阵 [fx, 0, cx; 0, fy, cy] gain 0.001 move_x -error_y * gain # 注意图像Y轴对应机器人-Z轴俯仰是常见的 move_y -error_x * gain # 图像X轴对应机器人-Y轴偏航 # 获取当前末端位姿 current_pose arm.forward_kinematics() # 生成新的目标位姿只在X,Y方向微调 new_position [ current_pose.pos[0], current_pose.pos[1] move_y, current_pose.pos[2] move_x, ] new_pose Pose(new_position, current_pose.rot) # IK解算并运动 ik_solution arm.inverse_kinematics(new_pose) if ik_solution: await arm.goto(goal_positionsik_solution, duration0.1) # 快速小幅度调整 if abs(error_x) 5 and abs(error_y) 5: # 像素误差足够小 print(Target centered!) break5.2 模仿学习Imitation Learning通过“手把手”教导机器人学习动作。一种简单的方法是“示教再现”。记录示教轨迹你可以用手轻轻地拖动Reachy的机械臂在电机通电但处于“松弛”模式或低刚度模式下让它经过一系列路径点。同时以高频率如100Hz记录下每个关节的角度或末端位姿。轨迹平滑与泛化记录的原始数据可能包含抖动。你需要对数据进行滤波如低通滤波或Savitzky-Golay滤波和平滑处理。然后你可以用多项式、样条曲线等方式对轨迹进行参数化。再现与泛化让机器人根据参数化后的轨迹模型重新运动。你还可以调整参数来改变轨迹的速度、幅度甚至将轨迹应用到不同的起始点通过坐标变换。Reachy SDK可能提供“零力”或“低刚度”模式方便拖动。如果没有你可以通过设置一个非常低的关节刚度K和阻尼B的导纳控制来实现类似效果。5.3 与其他传感器的集成Reachy Mini Lite的ROS 2架构使其能轻松与其他传感器节点集成。例如语音控制使用ROS 2的语音识别包如ros2_humble_audio_common结合Vosk等离线引擎将语音指令转换为运动命令。Leap Motion/手势控制通过Leap Motion传感器捕捉手部姿态映射到机器人末端姿态实现隔空操控。脑机接口BCI实验将脑电信号EEG通过ROS 2话题发布编写一个节点解析特定脑电模式如想象左手运动触发机器人执行抓取动作。这在人机交互和康复机器人研究中是常见课题。6. 故障排查与维护心得在使用过程中你肯定会遇到各种问题。下面是我总结的一些常见问题及其解决方法。问题现象可能原因排查步骤与解决方案无法连接到Reachy1. 网络不通。2. ROS_DOMAIN_ID不匹配。3. 防火墙阻挡。4. Reachy服务未启动。1.ping reachy_ip测试连通性。2. 检查双方echo $ROS_DOMAIN_ID。3. 暂时关闭防火墙测试sudo ufw disable测试后记得重新开启并配置规则。4. 通过显示器直接登录Reachy检查ros2 daemon是否运行以及reachy_sdk_server节点是否启动。机械臂不动但代码无报错1. 未调用turn_on()。2. 目标位置与当前位置过于接近。3. 关节处于错误状态如过流保护。1. 确保在goto前执行了await arm.turn_on()。2. 打印目标位置和当前位置看是否有显著差异。3. 通过SDK检查关节状态joint.is_error或joint.present_current是否异常高。尝试重启机器人。运动过程中抖动或异响1. 轨迹速度或加速度设置过高。2. 机械结构有干涉或螺丝松动。3. 控制参数PID不匹配。1. 增加goto的duration参数降低运动速度。2.立即停止运动仔细检查各关节连接处、线缆是否被拉扯所有螺丝是否紧固。3. 如果是官方镜像PID参数通常是调好的。如果是自己编译的SDK可能需要检查参数。异响持续需联系技术支持。逆运动学IK解算失败1. 目标位姿超出工作空间。2. 目标姿态存在奇异性。3. IK求解器数值问题。1. 手动估算目标点是否在臂展范围内。从简单、可达的位置开始测试。2. 尝试微调目标姿态特别是Roll/Pitch/Yaw避免完全伸直等奇异构型。3. 检查URDF模型是否正确加载。可以尝试其他IK求解器如TRAC-IK但集成需要工作量。Python脚本报asyncio相关错误1. 未在异步函数内调用await。2. 事件循环冲突如在Jupyter Notebook中。3. SDK版本与Python版本不兼容。1. 确保所有与Reachy交互的函数都是async def并用await调用。2. 在Jupyter中尝试使用nest_asyncio.apply()。对于脚本确保用asyncio.run(main())。3. 查看官方文档确认支持的Python版本通常是3.8。维护心得定期检查每隔一段时间检查一下机械臂的线缆是否有磨损关节处的螺丝是否松动。谐波减速器虽然寿命长但连接件可能因振动而松动。清洁使用气吹或软毛刷清理3D打印外壳缝隙里的灰尘避免进入电机或编码器。软件更新关注官方GitHub仓库的更新特别是SDK和固件。更新前务必阅读Release Notes并在测试环境中先验证。我曾因为跳过一个次要版本更新导致API不兼容浪费了半天时间回退。社区Pollen Robotics的Discord或论坛是宝贵的资源。遇到奇怪的问题先去搜索一下很可能别人已经遇到过并解决了。提问时尽量提供详细的错误日志、你的代码片段和系统环境信息。最后我想说的是Reachy Mini Lite是一个强大的工具但它更是一个学习平台。不要指望一开始就写出完美的、鲁棒的代码。从最简单的单关节运动开始逐步增加复杂度多写测试脚本多用print()输出中间状态。机器人编程是“动手”的学问很多理解是在调试和失败中获得的。当你看到自己写的代码让机械臂流畅地完成一个任务时那种成就感是无与伦比的。