免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

从EtherCAT到MoveIt2:六轴机械臂完整控制链路搭建实战

从EtherCAT到MoveIt2:六轴机械臂完整控制链路搭建实战 最近帮人调一台EtherCAT总线的六轴机械臂从硬件上电到能在MoveIt2里拖拽规划整整折腾了三天。网上资料不是零散就是版本对不上很多教程只讲到“单独跑通EtherCAT”或者“单独演示MoveIt2”真正把ROS2 Control、EtherCAT主站、伺服驱动器和MoveIt2串成完整链路的内容特别少。这篇文章就把我从底层启动到运动规划的完整过程写下来包括每一步为什么要这么做、命令怎么敲、坑踩在哪里。适合已经接触过ROS2基础概念但第一次要把真实机械臂接进MoveIt2的开发者参考如果你用的是自己的六轴机械臂哪怕不是同一款驱动器思路也完全通用。1. 先把整个系统拆清楚1.1 三层架构每层各干一件事一套能跑运动规划的机械臂系统从下往上其实是三层EtherCAT主站负责和伺服驱动器交换数据ROS2 Control负责把EtherCAT收上来的裸数据变成ROS里的关节状态和指令接口MoveIt2负责算轨迹、做碰撞检测。三层各司其职中间用话题和Action连接起来。我见过很多刚接触的人容易犯一个错误就是觉得MoveIt2可以直接控制伺服。实际上MoveIt2只是一个“大脑”它算出来的是关节角度序列也就是轨迹真正把这些角度写进驱动器让电机转起来的是ROS2 Control里的controller而controller又是通过硬件接口hardware_interface去调用EtherCAT主站完成通讯。所以整个链路是MoveIt2规划轨迹 - joint_trajectory_controller接收轨迹 - 读取硬件接口的指令接口 - EtherCAT主站周期性发送位置命令 - 伺服驱动器执行 - 编码器读数通过EtherCAT返回 - 硬件接口更新状态接口 - /joint_states发布 - MoveIt2和RViz显示实际位姿。每一层都有自己独立的问题域。EtherCAT层考虑的是实时同步和报文能不能稳定收发ROS2 Control层考虑的是接口怎么抽象、复用MoveIt2层考虑的是运动学求解和路径规划。调试时最大的忌讳是把这三层混在一起找问题后面我单独会用一节讲如何分层排查。1.2 为什么选EtherCAT而不是CANopen或Modbus现在工业机器人上最主流的总线方案基本就是EtherCAT原因就两个速度快、同步精度高。CANopen能做到1ms左右的周期已经是极限了而EtherCAT在六轴机械臂这种场景下跑1ms非常轻松很多配置甚至能把周期压到500us或者250us。EtherCAT的分布式时钟DC能保证所有轴在同一个时刻采样和输出这对多轴联动非常关键否则就会出现轨迹畸变甚至机构别劲。对比Modbus TCP这种非实时的方案EtherCAT用的是主站发一帧数据所有从站在这一帧里同时读写下自己的数据然后帧再传回主站的机制时延极低。机械臂在运动过程中每一个周期都要同步刷新六个关节的目标位置任何一轴的抖动都会被放大到末端所以数据同步能力是刚需。如果你自己搭机械臂选EtherCAT驱动器的成本现在也下来了。国产伺服厂商基本都把EtherCAT作为标配功能价格比传统脉冲型驱动器高不了太多省去了单独拉脉冲线和编码器线的麻烦控制柜走线也清爽很多。1.3 版本选型与兼容性组合我的目标平台是Ubuntu 22.04对应的ROS2发行版是HumbleMoveIt2和ros2_control在Humble下都有稳定的二进制包。这个组合是目前最推荐的原因不是“新”而是生态最完整。ROS2的版本节奏比较快Iron以上版本确实更新但很多第三方库和教程还停留在Humble遇到问题能查到的资料多踩坑成本低。EtherCAT主站这块有两个方向一个是内核态的IGHEtherLab稳定性和实时性更好但内核版本一升级驱动模块经常要重新编译对新手不友好另一个是用户态的SOEMSimple Open EtherCAT Master部署简单不依赖内核模块适合快速验证和教学。如果你做的是产线级设备我建议用IGH如果是为了把系统跑通、跑完再决定要不要换IGHSOEM完全够用。我最后用的是IGH加Humble的组合下面就按这个组合来写。如果你用的是SOEM整体流程类似差别主要在EtherCAT主站的启动方式上。2. 环境准备Ubuntu22.04上的全套工具链2.1 实时性处理与EtherCAT主站安装先说明一下很多人上来就在普通内核上跑IGH结果发现控制周期只要到1ms系统就各种卡顿。EtherCAT主站虽然是内核态驱动但控制线程还是跑在用户态的如果系统调度不给力周期抖动会非常大。所以我强烈建议至少在工控机上安装一个实时内核比如linux-rt或者带PREEMPT_RT补丁的内核。Ubuntu上可以通过安装linux-image-rt-amd64这类包来获得实时内核。IGH的安装属于整个链路里最容易卡住的环节因为不同内核版本要打不同的补丁。我直接说一个我试验过能用的流程先拿到和你当前内核版本匹配的IGH源码一般直接下1.5.2版本就可以在编译之前检查一下补丁是否需要编译时用./configure --prefix/opt/etherlab然后make sudo make install。安装完成之后需要把从站描述文件放到IGH能找到的位置然后配置网卡的MAC地址。在/etc/ethercat.conf里核心配置就两个一个是指定主站绑定的网卡设备名另一个是设置设备驱动模块。大部分Linux自带网卡驱动都还行Intel和Realtek的千兆网卡踩坑最少。如果ethercat slaves扫描不到从站先不要怀疑软件先查网线连接是不是OKEtherCAT对线序和连接器质量很敏感。2.2 安装ROS2 Humble、MoveIt2、ros2_control假设你已经装好了Ubuntu 22.04和ROS2 Humble的base环境接下来几条命令搞定核心依赖sudo apt install ros-humble-ros-base sudo apt install ros-humble-moveit ros-humble-moveit-setup-assistant sudo apt install ros-humble-ros2-control ros-humble-ros2-controllers sudo apt install ros-humble-joint-state-broadcaster ros-humble-joint-trajectory-controllerMoveIt2在Humble下建议直接装二进制包源码编译适合你想改MoveIt2内部实现的情况。对于绝大多数人二进制的版本已经够用而且省时间。ros2-controllers这个包里包含了我们后面要用到的joint_trajectory_controller、joint_state_broadcaster等标准控制器。这里有一个经验装好之后先跑一下ros2 pkg list | grep moveit确认版本再跑ros2 control list_controllers看看能不能正常操作。先让ROS侧的工具链处于一个“确认可用”的状态再和EtherCAT对接可以省掉很多问题排查时间。2.3 验证软件栈基本可用一个非常推荐的验证方法在还没有接真实机械臂之前先用URDF加fake hardware把MoveIt2和ros2_control这一层跑通。fake hardware的意思是模拟一块硬件接口读取指令接口的数据然后原样写回状态接口相当于假装电机能响应。ROS2 Control里内置了fake_components你只需要在URDF的ros2_control标签里把type配置成fake_components/GenericSystem即可。跑通fake硬件有什么好处呢你可以在没有机械臂的情况下验证MoveIt2生成的轨迹能不能被joint_trajectory_controller正确接收RViz里的机器人能不能动起来MoveIt2的规划结果和实际执行的状态反馈能不能对上。这一层通了后面接真实硬件遇到问题时就能大概率确定问题出在EtherCAT这一侧而不是MoveIt2配置侧。3. EtherCAT总线调试从扫描从站到伺服使能3.1 线缆拓扑与主站配置EtherCAT的拓扑是菊花链式也就是一个从站接着一个从站串下去最后一个从站不再往下接。机械臂控制柜里六个伺服驱动器和一个耦合器如果需要的话就是按这种链路串起来的。启动EtherCAT主站之后它会在每个周期发送报文从站收到报文后取出自己需要的数据插入自己的数据再往下传。最后一个从站如果不接回主站叫开环拓扑报文不会再回到主站但实际调试中绝大多数系统并不会把最后一个从站再连回主站而是依赖从站的“看门狗”和主站的心跳机制来确认链路状态。确认主站配置正确之后启动主站sudo /etc/init.d/ethercat start ethercat slaves如果你的从站都上电且线缆正常这里会列出所有从站的厂商ID、产品码和名字。如果只能扫到一个或者完全扫描不到优先查网线、从站电源、最后一个从站的终端电阻设置这三个是EtherCAT前期最常出问题的点。扫描到从站之后可以用ethercat slaves -v看到每个从站的详细信息和SMSyncManager配置。SM是EtherCAT从站里用于邮箱通信和过程数据交换的内存管理单元我们后续要配置的PDO映射最终就是要落到SM的通道里。3.2 PDO映射与FMMU/SM是什么关系这里必须把PDO、FMMU和SM这三个概念讲清楚否则后面配置的时候很容易一头雾水。SM是每一个从站内部的同步管理器负责管理输入输出过程数据的交换FMMU是主站内存里面的一个映射单元主站通过FMMU把一个逻辑地址范围映射到从站的物理地址然后每个从站就知道这一帧报文里哪一段是自己的数据。简单理解主站和从站之间跑的是一辆固定路线的班车FMMU相当于给每个从站划定了“在第几站下车、在第几站上车”SM相当于告诉从站“这个站点的货物应该放到你心里的哪个仓库”。PDO映射就是把伺服驱动器里的目标位置、控制字、状态字、实际位置这些参数塞到这个站点仓库的指定货架上。在IGH里配置从站的PDO是通过ethercat命令或编写SII描述文件来完成的。如果你用的是现成的驱动器厂商一般会提供ESI文件IGH会从从站的EEPROM里读取这些信息大部分情况下主站能自动识别出默认PDO映射。但需要验证映射是否满足你的需求。我在配置中经常遇到的一个情况是驱动器默认PDO只包含部分对象字典项比如可能只有实际位置和控制字但没有实际速度。这种情况需要用SDO或者PDO映射命令把缺失的对象字典项加进去。常用的PDO对象字典项包括控制字6040h控制伺服使能、运行、停止等状态状态字6041h读取伺服当前状态机的状态目标位置607Ah位置模式下控制器下发的目标位置实际位置6064h编码器反馈的实际位置目标速度60FFh和实际速度606Ch速度模式使用操作模式6060h和操作模式显示6061h选择位置/速度/扭矩模式3.3 用ethercat命令验证通信并完成伺服使能在ROS2 Control接入之前一定要先用ethercat命令直接对伺服进行操作确认每条指令能发出去编码器反馈能读回来。这一步不要跳过因为如果跳过后面ROS2 Control一旦出问题你根本不知道是ROS这一侧的问题还是底层总线的问题。先用这个命令看PDO映射是否完整ethercat pdos然后进入周期数据预览模式可以实时看到主站和从站交换的数据ethercat pdos -v看到数据在更新之后再用SDO读写验证伺服状态ethercat sdo read 0x6060 # 读取操作模式 ethercat sdo write 0x6060 0x08 /dev/null # 切换到CSP模式 ethercat sdo read 0x6041 # 读取状态字这里我建议使用CSPCyclic Synchronous Position模式也就是循环同步位置模式。为什么用CSP而不是老老实实走PpProfile Position模式因为CSP模式下每个周期主站都下发一个目标位置伺服内部会做位置环和速度环的插补这样多个轴之间的同步由主站周期协调非常适合六轴机械臂这种多轴联动场景。Pp模式下每个轴执行轮廓曲线时的插补逻辑是驱动器自己的同步效果跨轴会差一些。伺服使能的过程就是按照CiA402的标准状态机一步一步把状态字从“Switch on disabled”推到“Operation enabled”。手动用SDO写控制字也能使能但实际操作中我更推荐直接靠ROS2 Control的硬件接口来控制控制字这样使能逻辑和ROS节点生命周期连在一起更安全。当然第一次测试时用ethercat sdo write 0x6040 0x06 0x80这种命令手动使能也是可以的确认驱动器和抱闸逻辑没有问题了再转到ROS侧。4. ROS2 Control硬件接口让机械臂进入ROS世界4.1 在URDF里接上ros2_control现在开始到了ROS2 Control的关键环节。URDF里要加ros2_control标签这个标签描述的是机械臂每个关节的“接口能力”有哪些command interface和state interface。对于机械臂关节状态接口一般要三个position、velocity、effort指令接口一般只需要position或velocity。一个标准的关节定义大致长这样ros2_control nameRealArm typesystem hardware pluginmy_ethercat_hardware/EthercatSystem/plugin /hardware joint namejoint1 command_interface nameposition param namemin-3.14/param param namemax3.14/param /command_interface state_interface nameposition/ state_interface namevelocity/ /joint !-- joint2 ~ joint6 同理 -- /ros2_control注意这里的type是system对应我们自定义的硬件插件。ROS2 Control提供了SystemInterface系统级硬件接口和ActuatorInterface致动器级硬件接口两种基类。对机械臂这种每个关节都有独立伺服驱动器的场景我推荐用SystemInterface因为你可以把整条EtherCAT总线的管理逻辑放在一个地方统一处理而不需要为每个关节单独分配一个硬件实例。4.2 写一个SystemInterface硬件插件写硬件插件是实现整个系统里最核心的动作。你需要在C中继承hardware_interface::SystemInterface并实现若干关键方法。核心要理解的是这两个方法on_read在每个控制周期从EtherCAT主站读取所有从站的反馈数据并写到state interfaces里。on_write在每个控制周期把所有command interfaces里要下发的目标值写到对应的EtherCAT报文数据区里。为什么必须用这两个方法因为ros2_control_node的实时控制循环会周期性调用它们这个周期就是我们之前配置的1ms或者更小。为了满足实时性on_read和on_write里不能有动态内存分配、不能有Mutex锁等可能阻塞的操作要尽量保证确定性执行。我实现时的做法是在on_init阶段建立EtherCAT主站连接、初始化PDO映射、将各关节的编码器零点偏置都读出来在on_activate阶段把伺服使能写控制字走状态机同时做好位置单位换算在read和write里只做数值转换和报文读写。数值转换这块很容易漏ROS2 Control内部用的单位是弧度rad和服务器的弧度每秒而驱动器通常使用脉冲counts或用户自定义单位。假设编码器一圈是65536个脉冲减速比为100那么写目标位置时要把弧度值乘以100*65536/2π换算成脉冲读实际位置时反过来除以这个系数。// 只贴关键循环 return_value EthercatSystem::on_write(const rclcpp_lifecycle::State /*state*/) { for (size_t i 0; i num_joints_; i) { double target_rad hw_commands_[i]; int32_t target_counts static_castint32_t(target_rad * kRadToCounts); ecat_slaves_[i].set_target_position(target_counts); } // 实际调用IGH的周期发送函数 ec_master_send(master_); return OK; }写完插件后别忘了在plugin.xml里声明并在package.xml里加依赖。然后重新编译你的包确保没有编译错误再继续。4.3 启动controller_manager并验证关节状态硬件插件写好后先别着急接MoveIt2先把controller_manager跑起来验证最基本的关节状态能不能发布。启动机器人的launch文件一般需要做三件事加载URDF、启动robot_state_publisher、启动controller_manager。在launch里可以直接用命令行参数把URDF传给robot_state_publisher然后加载下面两个控制器joint_state_broadcaster发布所有关节状态到/joint_states话题joint_trajectory_controller提供follow_joint_trajectory的Action服务供MoveIt2使用启动后验证一下ros2 controller list ros2 topic hz /joint_states ros2 topic echo /joint_states --once如果/joint_states里的position数据随机械臂转动而变化说明EtherCAT和ROS2 Control这一层已经通了。此时如果你想手动让某个关节动一下可以直接用ros2 action或ros2 topic往joint_trajectory_controller发一个简单轨迹确认伺服能按照指令转动。这一步是整条链路中“从硬件到软件”的第一次闭环如果走到这里后面的MoveIt2基本上就只是配置问题了。5. MoveIt2运动规划让机械臂看懂目标点5.1 用MoveIt Setup Assistant生成配置先运行MoveIt Setup Assistant生成moveit_config包ros2 run moveit_setup_assistant moveit_setup_assistant在助手界面里加载你的URDF然后配置几个东西设置自碰撞矩阵Self-Collision一般让助手自动生成默认矩阵就好后续可以在RViz里显示碰撞检测结果。定义Planning Group比如一个叫arm的规划组包含从基座到末端的六个活动关节。注意这一步决定了MoveIt2在运动学求解时把哪些关节纳入考虑。设置预定义姿态Pre-defined Poses比如home、vertical等方便后面快速切换。配置Controllers这一步决定了MoveIt2怎么把规划出来的轨迹发给controller_manager。在生成的controllers.yaml里把MoveIt2的controller名称设定为joint_trajectory_controlleraction_ns对应follow_joint_trajectory即可。其中最关键也是新手容易漏掉的是在Setup Assistant里正确关联URDF中的ros2_control关节和MoveIt2的规划组。MoveIt2只知道规划组不知道底层用什么controller执行它只关心有没有一个符合FollowJointTrajectory规范的Action服务存在。所以如果controller_manager里加载了joint_trajectory_controllerMoveIt2就能通过action_ns找到它。5.2 打通MoveIt2和joint_trajectory_controller这里有一个非常隐蔽的点joint_trajectory_controller默认要求收到的轨迹中每个轨迹点都带时间戳时间戳必须单调递增而且第一个点必须和目标状态兼容。MoveIt2生成的轨迹是满足这些要求的但如果你手动发一些不带时间戳的测试轨迹常常会看到controller拒绝了你的指令。这一点在调试时特别容易误导人要留意。另一个容易踩的坑是MoveIt2默认从/joint_states话题读取当前状态如果joint_state_broadcaster没有启动MoveIt2就会一直等待初始状态看起来好像“卡住了”。所以启动顺序里一定要先保证/joint_states有高频数据发出来然后才启动move_group节点。检查MoveIt2和controller的连接是否正常可以观察move_group的日志。启动之后在RViz里设置目标位姿并点击Plan如果计划成功日志里会显示求解用时和碰撞检测信息点击Execute之后joint_trajectory_controller会开始按轨迹执行机械臂开始运动。5.3 从开机到运动规划的完整启动顺序到这里整条链路已经通了。我把最终的启动顺序整理一下方便你以后调试时直接参考给控制柜上电等待伺服驱动器完成初始化EtherCAT链路建立。启动EtherCAT主站并确认能从站扫描完整。启动机器人的URDF驱动节点这个节点内部会初始化EtherCAT主站、加载硬件接口插件、启动controller_manager并加载controller。确认/joint_states有数据确认controller_manager里joint_trajectory_controller已经active。启动move_group节点和RViz加载MoveIt2配置。在RViz里设定目标位姿执行Plan检查轨迹和机械臂动作。这套顺序的核心思想是先让底层稳定再让上层介入每一层都有明确的验证标准。不要图快跳步一次排查时就要多花几个小时。6. 常见问题速查与调参心得6.1 高频坑与解决对照表下面这张表是我在调这类系统时遇到最多的问题按出现频率排序基本覆盖了80%以上的场景。现象可能原因处理方法ethercat slaves扫描不到从站网卡未绑定、从站没上电、终端电阻不对用dmesg检查IGH网卡绑定情况逐段检查网线和电源ethercat slaves能扫到但PDO数据不更新SM映射错误、从站EEPROM配置被改写用ethercat pdos -v看详细映射必要时写回备份的EEPROMROS2 Control加载硬件接口失败插件未正确注册、URDF标签写错检查plugin.xml、package.xml用ros2 pkg prefix确认插件路径伺服能使能但位置不刷新单位换算错误、编码器方向设反手动转轴看实际位置变化方向和指令方向对比MoveIt2一直等待/joint_statesjoint_state_broadcaster没启动或没active检查ros2 controller list确认状态话题频率Plan成功但Execute后机械臂不动follow_joint_trajectory服务没连上或者controller不接受轨迹检查action_ns配置用ros2 action list确认服务名关节运动时抖动明显控制周期不稳、位置环增益过高、同步模式没开先优化实时内核和主站周期再调低伺服增益个别关节使能后会掉使能限位未设置、抱闸没打开、报警未清除看驱动器报警码检查硬限位信号和抱闸电源6.2 调试顺序建议如果你遇到问题且一时拿不准在哪一层我的习惯是从底层往上排查每层只验证一个关键点。EtherCAT层先确认ethercat slaves输出稳定再用ethercat pdos -v看数据是否在变化最后用ethercat sdo write控制字手动使能验证伺服电机本身没问题。ROS2 Control层只看/joint_states的数值是否跟随机械臂运动不关心EtherCAT的细节。MoveIt2层只看规划日志和轨迹执行状态。每层都验证通过之后再往上一层走不要在某一层还没稳定时就急着去调上层。我见过太多人一边调整MoveIt2的参数一边怀疑EtherCAT掉线结果最后发现其实是网卡驱动在多核中断绑定上出了问题导致EtherCAT周期不稳。底层不稳上层怎么调都是白费。6.3 一些底层参数调优经验EtherCAT主站周期建议先用1ms跑通稳定后再尝试500us或者更低。周期越小对CPU实时性要求越高如果发现周期抖动加大优先检查IGH的中断绑定是不是被系统调度到了不同的CPU核上然后确认实时内核是不是真的生效。伺服侧参数里位置环增益和速度环增益建议先从驱动器厂商给的默认值开始不要上来就追求高速响应。响应太快在机械结构刚性不足时会激发出共振表现出来就是关节发尖啸或者抖动。我一般会先用很慢的轨迹跑一遍全行程确认机械和伺服没有问题再逐步提高速度和加速度限制。最后再提一个小技巧在MoveIt2里做首次规划前先把规划时间限制设大一些比如10秒并选择RRTConnect这类规划器。首次运行时运动学求解可能需要更长时间来构建规划场景不要一看到几秒钟没出结果就以为是死循环。调通之后再根据实际需求把参数收紧。我在实际操作中还发现控制柜里的接地和屏蔽对EtherCAT稳定性影响非常大。伺服驱动器的动力线如果和EtherCAT网线绑在同一个线槽里干扰会直接反映在主站的掉线计数上。我花了一整天才意识到是线缆走线导致的干扰换了屏蔽网线、把动力线和通讯线分槽走之后问题彻底消失。建议你第一次布线时就把这个问题考虑进去后面会省很多麻烦。
返回列表