ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从仿真到实机:RM65六自由度机械臂MoveIt三种控制模式详解

从仿真到实机:RM65六自由度机械臂MoveIt三种控制模式详解 拿到RM65之后的第一周我一直被一个问题卡着同样是让这台六自由度协作臂动起来网上资料却指向了完全不同的路子。有人在Gazebo里拖拽滑块有人已经把MoveIt规划好的轨迹发到实机上跑码垛还有人直接通过SDK在高频下发关节力矩做力控。说实话同一台臂三种玩法底层逻辑完全不同最开始确实容易绕晕。我花了两周时间把三条路都走了一遍从纯仿真到实机轨迹跟随再到绕过MoveIt直接关节控制。这篇文章就围绕MoveIt控制RM65的3种控制模式展开把每条路径的完整链路、关键配置和实际测试数据写清楚顺便把踩过的坑也一并交代。打算用RM65做二次开发、又准备接MoveIt的同学可以直接把这篇当参考。1. 先说清楚RM65这台臂和MoveIt的配合底子1.1 RM65的关节结构与接口特点睿尔曼RM65是典型的六自由度轻量协作臂有效负载5kg工作半径610mm左右重复定位精度标称±0.05mm。整机重量大约7.5kg属于桌面级安装和移动底盘都能扛得住的规格。关节方面用的是谐波减速器配合无框力矩电机的方案六个关节都内置驱动器外部可以通过TCP/IP、Modbus、CAN等接口访问。这里有个很关键的技术特点RM65的关节端本身就具备位置、速度、力矩三种控制模式。这意味着你在上层选择走MoveIt的规划路径还是绕过MoveIt直接对关节下发指令硬件层面都不存在障碍。真正要设计的其实是软件层面的控制架构。我这次测试用的固件版本是RM65在2024年中的一版通讯周期外部通过Ethernet访问时能做到1ms甚至更低的指令周期。这个数字在后面对比三种控制模式时会直接影响到安全性表现建议提前记住。1.2 MoveIt适配包与驱动节点的准备RM65官方提供了一套基于ROS的驱动包里面包含URDF模型文件、MoveIt配置包、以及一个负责将上层运动指令转发到机械臂控制器的驱动节点。URDF模型我是直接用的官方版本但如果你需要把RM65装到自己的底盘或者自定义基座上记得把基座的坐标系加进去否则MoveIt的规划场景和实机安装位置对不上。驱动节点的作用简单说就是把MoveIt规划好的关节轨迹通过ROS的Action或者话题接口接收下来再转换成RM65控制器的指令格式下发给实机。在实际项目中官方的驱动节点一般够用我自己做非标集成时倾向于写一个桥接层把轨迹的起点校验、超时保护、急停联动逻辑都放在这个桥接层里。安装时还需要确认MoveIt版本和ROS发行版的匹配。我是Ubuntu 20.04配NoeticMoveIt用的1.1.x版本整体兼容性没问题。如果你用的是Ubuntu 22.04加HumbleROS 2版本的接口会有差异但整体控制思路一致。1.3 零位与坐标系校准绕不开的第一道坎仿真环境里所有关节角度都是从零位开始推算的实机也一样。但RM65出厂后的零位和MoveIt模型里的零位是否对齐必须要实际验证一次。我踩过的第一个坑就在这仿真里规划了一条轨迹发到实机以后机械臂的末端姿态和RViz里显示的差了大概十几度。查了半天发现是URDF模型里关节的零点定义和实机控制器里保存的零点没有校准。解决办法是先将机械臂手动运动到一个已知姿态比如竖直零位然后对比MoveIt中该姿态对应的关节角是否一致不一致就把URDF中对应关节的origin偏移修正掉或者重新标定控制器零点。这一步做完之后务必再检查一遍坐标系方向。RM65的基座坐标系默认Z轴向上末端工具坐标系需要根据实际安装的夹爪或者吸盘另外配置。MoveIt的规划是在规划场景里做的如果TCP定义错了后面所有笛卡尔空间规划全都会偏。2. 控制模式一MoveIt加Gazebo纯仿真适合验证算法而不是复现实机2.1 仿真管线的真正分工模式一的核心是MoveIt负责规划Gazebo负责物理仿真两者通过ros_control连接起来。很多人以为仿真就是为了省一台机械臂的钱我实际用下来觉得这个理解太窄了。仿真最大的价值是让你在写上层算法时有一个随时可以重置、不会撞坏、可以随意灌入异常状态的实验环境。MoveIt在仿真模式下做的事情和实机模式几乎一样维护规划场景、进行碰撞检测、生成关节轨迹。区别在于轨迹的执行端变成了Gazebo里的虚拟机械臂而不是真实硬件。MoveIt本身不直接和Gazebo通信中间必须经过ros_control的joint_trajectory_controller这条链路如果不通仿真里MoveIt规划完的轨迹会一直停在“执行中”状态机械臂一动不动。2.2 让仿真不飘的四个关键配置这套仿真要跑得稳我总结下来有四个配置必须检查。第一URDF中的惯性参数。官方URDF里每个link的惯性数值如果给的是近似值在Gazebo中高加速度运动时会出现末端抖动。我在测试中发现RM65四五轴在快速摆动时仿真里的关节力矩会出现明显振荡后来把惯性矩阵里的数值按质量分布重新估算了一遍才好转。第二ros_control的关节控制器要选对。RM65的关节是位置接口仿真里应该用PositionJointInterface配合joint_trajectory_controller不要误用EffortJointInterface。很多教程里默认用effort接口但RM65驱动模式下关节本身提供的是位置闭环仿真里硬要用力矩接口反而会失调。第三joint_limits.yaml要和实机保持一致。MoveIt配置包里默认的关节限位通常偏保守或者偏理想你需要把RM65每个关节的实际运动范围和速度上限读出来填进去。否则仿真里能规划的轨迹实机上可能直接触发关节超限保护。第四仿真时间缩放。Gazebo默认real time factor如果掉到0.5以下MoveIt规划好的轨迹执行时间会和仿真时间对不上表现为机械臂动作变慢或者轨迹曲线失真。优先降低仿真里的物理迭代步长至1ms以内并关闭不必要的传感器渲染。2.3 仿真模式能验证什么验证不了什么仿真模式最适合验证的是路径规划的可行性、避障逻辑、抓取策略、时序逻辑。比如你写了一个视觉抓取的流程先在仿真里把相机模型、识别节点、手眼标定、规划抓取整条链路跑通这个价值极高因为可以无限次重置实验环境。但仿真验证不了的是实际关节伺服的响应特性、真实摩擦力、机械臂带负载时的动态变形、以及通讯延迟带来的轨迹跟踪误差。RM65在Gazebo里表现得非常“听话”轨迹跟踪几乎完美但实机上由于减速器摩擦、电机温升、负载变化等因素轨迹末端可能出现几十毫秒的跟随延迟甚至抖动。所以仿真里跑通的应用代码上实机前一定要调整一个东西速度缩放系数。仿真里用1.0的缩放可能很顺滑实机上我会从0.5开始试。3. 控制模式二MoveIt规划加实机轨迹跟随90%项目走这条路3.1 从规划到执行的完整链路模式二是目前工业项目里最主流的用法MoveIt负责规划实机负责执行两者之间通过FollowJointTrajectory的Action接口协同。整条链路是MoveIt的move_group节点加载URDF、SRDF、joint_limits配置维护规划场景。上层应用发送规划请求move_group调用OMPL或者其他规划器生成关节空间轨迹。轨迹发布到/joint_trajectory_controller/follow_joint_trajectory这个Action Server。桥接节点或官方驱动节点接收goal将轨迹点逐一下发到RM65控制器。RM65底层关节伺服完成实际运动。这条链路里最容易忽略的是Action接口的异步特性。MoveIt调用FollowJointTrajectory时发送goal之后会立即返回accepted状态但此时机械臂其实才开始执行。如果你紧接着又发了一条新的轨迹controller会在切换时出现轨迹衔接问题轻则停顿重则抖动。我自己的做法是在桥接层里加一个互斥锁只有当上一条轨迹的result返回成功之后才接收下一条轨迹。这样牺牲了一点吞吐量但换来的是实机上极其稳定的执行表现。3.2 Python端发送轨迹的Action调用要点用Python通过MoveIt接口向RM65发送轨迹核心代码其实很简洁。下面是一个可以直接参考的示例作用是规划到目标位姿并执行import rospy import actionlib from control_msgs.msg import FollowJointTrajectoryAction, FollowJointTrajectoryGoal from trajectory_msgs.msg import JointTrajectoryPoint from moveit_commander import MoveGroupCommander rospy.init_node(send_trajectory_demo) move_group MoveGroupCommander(arm_group) # 设置目标关节角度 joint_goal [0.0, -0.785, 0.785, 0.0, 0.785, 0.0] move_group.set_joint_value_target(joint_goal) # 执行规划并获取轨迹 plan move_group.plan() if not plan: rospy.logerr(Plan failed) exit(-1) # 通过Action发送轨迹到实机 client actionlib.SimpleActionClient( /joint_trajectory_controller/follow_joint_trajectory, FollowJointTrajectoryAction ) rospy.loginfo(Waiting for action server...) if not client.wait_for_server(timeoutrospy.Duration(5)): rospy.logerr(Action server not available) exit(-1) goal FollowJointTrajectoryGoal() goal.trajectory.joint_names move_group.get_active_joints() for point in plan.joint_trajectory.points: wp JointTrajectoryPoint() wp.positions point.positions wp.velocities point.velocities wp.accelerations point.accelerations wp.time_from_start point.time_from_start goal.trajectory.points.append(wp) goal.trajectory.header.stamp rospy.Time.now() client.send_goal(goal) client.wait_for_result() rospy.loginfo(Execution finished: %s, client.get_result())这段代码有几个细节值得注意。plan返回的对象里包含joint_trajectory但如果用的是move_group.plan()接口返回结构在不同MoveIt版本里略有差异建议打印一下再取字段。另外若move_group配置的不是planning_group而是别的名字move_group.get_active_joints()的顺序必须和URDF里的关节顺序一致否则轨迹点会错位。3.3 速度缩放与轨迹平滑MoveIt规划的轨迹默认带velocities和accelerations字段但实际下发给RM65时如果你不显式设置速度缩放可能会按照规划阶段的默认值执行最常见的现象就是机械臂慢得让人怀疑人生。MoveIt里有个set_max_velocity_scaling_factor接口值域0到1。仿真里我经常用1.0但实机上我会根据载重调整。空载的时候0.7到0.8的速度缩放能让轨迹执行顺畅且不触发抖动负载接近5kg时我一般降到0.4以下否则第三个关节在启停瞬间会出现明显的过冲。另外一个很容易被忽视的点是轨迹的起止速度。MoveIt规划出的轨迹起点和终点速度通常已经归零但如果你手动构造JointTrajectoryPoint记得要把首末点的速度设为0否则机械臂在启停瞬间会有一个速度跳变长期运行对减速器寿命影响很大。4. 控制模式三绕过MoveIt规划层直接关节伺服与力矩控制4.1 什么时候需要绕过规划层第三种模式和前两种有本质区别MoveIt在整条链路里退化成辅助工具甚至完全不参与实时控制。你直接对RM65的关节发出位置、速度或者力矩指令让底层伺服完成闭环。这个需求通常出现在四类场景里需要高频动态响应的时候、需要做力控打磨或者装配的时候、需要实现拖拽示教的时候、以及需要把机械臂接入自有实时控制系统的时候。比如做力位混合控制时MoveIt的规划周期通常在几十毫秒级别对力矩环来说完全不够用必须绕过规划层直接和关节伺服通信。说得直白一点MoveIt本质上是离线规划器加场景管理工具它并不擅长“实时反馈控制”这件事。RM65的关节伺服周期是毫秒级而MoveIt规划加执行的回环延迟很容易到几十毫秒甚至上百毫秒所以需要力控或者精确动态交互时模式三几乎是唯一选择。4.2 位置、速度指令下发的实现方式绕过MoveIt之后最直接的控制方式是使用RM65官方SDK通过TCP或者CAN连接控制器然后以固定周期下发关节角度或者关节速度。我给一个伪代码级别的参考import rm_api robot rm_api.RM65(192.168.1.18, port8080) while True: # 获取当前关节角度 current_q robot.get_joint_position() # 根据算法计算目标关节角度比如插值或视觉伺服 target_q sensor_feedback_controller(current_q) # 下发位置指令 robot.move_joint(target_q, speed10) time.sleep(0.005)这种方式下MoveIt依然可以做“参谋”——先用MoveIt离线规划一条安全轨迹然后把它只作为参考输入给你自己的实时控制器最终下发到实机的并不是MoveIt的原始轨迹而是你经过实时修正之后的轨迹。如果走速度指令RM65的每个关节都支持速度模式你可以直接下发关节角速度。速度模式的好处是轨迹插值不用你操心机械臂内部会平滑处理坏处是位置精度会受到影响适合视觉伺服这类的动态跟踪场景不适合需要严格走固定轨迹的场合。4.3 力矩控制模式与重力补偿第三种模式里最“硬核”的是直接关节力矩控制。RM65每个关节都支持力矩/电流前馈指令但这里有一个绕不过去的坎重力补偿。机械臂在自由空间中保持静止靠的是关节力矩平衡重力。如果你直接下发零力矩机械臂会直接砸下来。所以做力矩控制的第一件事是把重力矩模型算准。方法有两种一种是用URDF和DH参数推导出实时的重力矩矩阵另一种是在实机上做一个标定流程让机械臂自动运动到多个姿态并记录关节力矩拟合出重力和关节角的映射关系。下面是一段很简化的重力补偿示意代码import numpy as np def gravity_compensation(q_values, mass_links): # q_values: 当前关节角 # mass_links: 各连杆质量和质心位置 g np.array([0, 0, -9.81]) torque_comp np.zeros(6) # 根据DH模型计算雅可比和力雅可比求补偿力矩 J compute_jacobian(q_values) wrench np.zeros(6) for idx, link in enumerate(mass_links): # 每个连杆的重力换算到基座坐标系 wrench link.compute_gravity_wrench(g) torque_comp np.dot(J.T, wrench) return torque_comp实际测试中RM65在力矩模式下配合良好的重力补偿能够实现非常柔顺的拖拽示教效果。用人手握住末端轻轻拉动机械臂会顺着力的方向运动这就是力矩控制最典型的应用。不过注意力矩模式对通讯延迟极其敏感如果通过外部TCP以1kHz频率下发指令延迟稍微波动大一点整个系统就会开始抖动。我建议在力矩模式下使用实时内核配置或者把力矩控制做在控制器内部外部只发上层指令。还有一点必须提醒做力矩控制实验时速度一定要从非常低开始最好先在仿真里把所有安全逻辑验证一遍再上实机。我之前做重力补偿时因为补偿力矩计算里一个坐标变换符号写反了机械臂直接向反方向加速如果不是及时按下急停后果很严重。5. 三种模式的实际对比与选型逻辑5.1 关键指标横向对比对比维度模式一纯仿真模式二MoveIt规划实机跟随模式三直接关节伺服/力矩控制控制链路MoveIt→Gazebo→虚拟关节MoveIt→控制器→实机关节伺服用户程序→控制器→实机关节伺服指令周期仿真时间不敏感几十毫秒级毫秒级甚至亚毫秒级末端精度依赖模型精度可达±0.05mm量级可达±0.05mm量级部署成本低中等中高动态响应很慢无实时性中等适合点位运动快适合力控和动态交互碰撞安全无风险依赖轨迹规划和保护逻辑依赖力矩限制和急停适合场景算法验证、流程验证上下料、码垛、喷涂、装配力控打磨、拖拽示教、动态避障这个表格看起来有点“教科书”但我确实是按实际体验画的。模式一和模式二之间差距最大的是“真实感”仿真里跑得很顺的轨迹接上实机后通常需要重新调速度缩放和安全距离。模式二和模式三之间差距最大的是“响应速度”做点位运动时模式二完全够用但只要有连续力交互需求模式三几乎是必选项。5.2 不同场景下的选型建议如果让我给一个普通项目做技术选型我的判断逻辑基本是这样的做科研、做算法演示、做视觉抓取系统原型选模式一就够了。先仿真别急着上实机把流程跑通再切换到模式二。做工业应用落地或者做移动操作机器人的底盘加机械臂集成默认选模式二。MoveIt提供碰撞检测和轨迹规划能力RM65提供稳定的轨迹跟踪两者配合基本能满足90%的场景需求。但要处理传感器反馈形成闭环比如视觉伺服的实时纠偏、力控打磨、复杂装配里的人机协作那就在模式三的基础上做甚至可以把模式二和模式三混合使用MoveIt做全局规划下发一条参考轨迹同时开一条高频直接伺服通路让力矩反馈修正轨迹细节。混合模式是我个人最推荐的做法。前期开发时用MoveIt生成基准轨迹后期调试时通过底层伺服修正某些关键路径点既保证安全又保证灵活性。6. 实机调试中踩过的坑与后续扩展方向6.1 几个有代表性的坑第一个坑是规划场景碰撞模型和实机对不上。MoveIt的碰撞检测是在Planning Scene里做的如果你只是加载了官方URDF而没有把实际安装在机械臂末端的夹爪、吸盘、传感器加入碰撞模型那么MoveIt规划的轨迹很可能在实机上会撞到这些附加物体。我后来做的方法是先把末端工具的STL模型加进URDF和SRDF再单独标记成“attached collision object”这样MoveIt执行前就会自动检测。第二个坑是轨迹执行中断后的状态恢复。机械臂在跑轨迹的过程中如果触发急停或者错误MoveIt那边可能并不知道实机当前的关节角已经变了还认为机器人停在轨迹上的某个点。下次规划时就会基于一个错误的关节状态导致轨迹起点跳变。解决办法是在桥接层中实时订阅实机关节状态并且每次规划前强制同步规划场景的当前状态。第三个坑是RM65在位置模式下的系统辨识问题。做轨迹跟踪时如果发现某些高频轨迹实机跟踪不上不要急着改控制参数先用录波工具对比规划轨迹和实际关节角的误差曲线。RM65的关节在低速时摩擦力比较明显轨迹里如果有频繁的加减速末端会有一个滞后这时候在MoveIt里适当降低加速度上限比调伺服参数更有效。6.2 从三条路继续延伸的方向当我走完这三种控制模式以后最大的体会是MoveIt提供的是一套完整抽象但它永远不会替你做实时控制。RM65这颗“执行肌肉”到底怎么动取决于你把它接入哪条“神经回路”。如果后续要做更复杂的应用可以沿着这三个方向继续深挖一是把模式二和视觉传感器结合起来做视觉引导的抓取和分拣二是把模式三和力传感器结合做力控打磨、精密装配三是把RM65装到AGV上做移动操作平台这时候模式二加模式三的混合控制几乎是标配。反正对我来说把三种控制模式各自在什么场景下用、各自的接口在哪、各有什么坑彻底搞明白了之后RM65才真正算是我手上一台“可编程的机械臂”而不是一个只能按预置点运动的封闭设备。这套东西越往后用越能感觉到架构设计的重要性。希望这篇文章也能让你的RM65少走点弯路。
返回列表