ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

机械臂强化学习实战:仿真训练、奖励设计到真机迁移全流程指南

机械臂强化学习实战:仿真训练、奖励设计到真机迁移全流程指南

机械臂配上强化学习,这几年是我见过的话题度最高的机器人方向之一。随便打开一个招聘网站搜“机械臂算法”,十有八九都写着“熟悉强化学习者优先”。但真上手做过的人都知道,这个组合听着高大上,实际训练起来那叫一个一言难尽——环境装三天、奖励跑飞、网络不收敛、仿真转真机各种翻车,都是家常便饭。

我自己从最早在仿真里用强化学习控制一个三轴机械臂夹方块,到后来折腾七轴协作臂的插孔、抓取任务,中间踩过的坑足够写一本书。今天这篇就仔仔细细把“机械臂+强化学习”这件事从头到尾捋一遍:从环境搭建、状态动作设计、奖励函数怎么写,到算法怎么选、训练有什么坑、仿真怎么往真机迁移,全部按实际操作的顺序来。文章适合两类人看:一类是刚入门、想用强化学习让机械臂学会某个动作的研究生或工程师,另一类是已经训过一阵子但总觉得结果不稳定的老手。不管你现在卡在哪一步,这篇内容应该能帮你省下至少一个月的试错时间。

1. 项目整体认知与前置判断

1.1 这个方向到底在解决什么问题

机械臂的传统控制走的是“建模-规划-跟踪”这条路:先建立运动学和动力学模型,再用规划算法算出一条从起点到终点的轨迹,最后用PID或更高级的控制律去跟踪它。这套体系在结构化场景里非常成熟,工业线上成千上万的机械臂就是这么工作的。但它有一个天生的短板——只要任务环境稍微复杂一点,比如目标物体的位置会变、抓取时接触力不好建模、或者末端要做的操作本身难以用解析式描述,传统方法就会很吃力。

强化学习解决的是另一类问题:我不直接告诉你机械臂该怎么动,而是定义清楚“什么状态是好的、什么动作会得到什么样的反馈”,然后让算法在一次次尝试中自己摸索出策略。机械臂在这种范式下不再是一个被精确控制的执行器,而是一个“会试错、会学习”的智能体。它能处理非结构化场景,能自适应环境变化,甚至能学会一些人类很难手工编程的灵巧操作。

说白了,机械臂+强化学习不是要取代传统控制,而是去补传统控制够不到的那块短板。项目定位上你要先想清楚:你的任务到底适不适合用强化学习?如果任务能精确建模、环境稳定不变,PID和MPC又快又稳,没必要上RL。但如果任务有不确定性、有接触、有组合操作,强化学习才有用武之地。

1.2 传统方法与强化学习的边界在哪

我见过很多入门的同学一上来就恨不得把机械臂的所有动作都交给RL去学,这是一个方向性错误。我的经验是,分界线主要看三件事:

第一,能不能写出显式的规则或者代价函数。比如“从A点到B点走直线”,这用传统方法分分钟搞定。但“把螺丝拧进孔里再转三圈”,这种任务涉及接触状态变化,很难预先把所有情况写成规则,RL就有优势了。

第二,环境模型是否精确。传统控制极度依赖模型精度,但如果你的机械臂要抓取的是一堆颜色形状各异、摆放位置随机的物体,想在仿真里精确建立每个物体的动力学模型,工程量是灾难级的。这时候让RL直接学RGB图像到动作的映射,反而是更务实的方案。

第三,任务是否允许试错。RL训练的本质是试错,这决定了它天然适合先在仿真里把策略学出来,再迁移到真机。如果你的任务是安全敏感、不许出错的高精度产线操作,那就得慎重评估了。

想清楚这三点,你就知道自己手上的项目到底该不该用强化学习,该用在哪个环节。

1.3 需要具备的知识储备

这部分给新人一个参考,我按重要程度排个序:

  • Python是必须的,所有主流RL库都是Python生态;
  • 线性代数和概率论最好不要太生疏,理解状态转移、策略、奖励这些概念用得上;
  • 机械臂的运动学和动力学至少知道基本概念,不会算可以,但不能连DH参数、雅可比矩阵是什么都不知道;
  • 有一点深度学习的底子,知道神经网络怎么训练、梯度下降是怎么回事;
  • 如果涉及真实机械臂,还需要了解基本控制接口(位置控制、力矩控制),但这一步可以后面再补。

不需要一开始就是专家,但以上知识缺了哪个,学习过程中都会卡壳。我的建议是:先跑通一个最简单的仿真任务(哪怕是倒立摆),再去碰机械臂,否则你很难分辨报错到底是环境问题、算法问题还是模型问题。

2. 仿真环境搭建与工具选型

2.1 仿真引擎怎么选

做机械臂RL,仿真环境是第一个大决策。十几年前得自己写物理引擎,现在选择已经很多了,我实测下来几个主流选项各有长短:

仿真器渲染与物理官方机器人支持速度适合做什么
开源物理引擎A刚体物理稳,渲染一般内置多款机械臂URDF快,可批量并行机械臂抓取、操作类RL
开源物理引擎B功能全面,支持软体/流体生态广,社区扩展多中等需要复杂接触或自定义环境的场景
商业级仿真平台物理精度最高,带传感器噪声模型工业级模型齐全慢仿真到真机迁移前的高保真验证

我的建议很直接:如果你刚入坑,就用开源物理引擎A配合它自带的机械臂模型跑通全流程,不要一上来就追求高保真。高保真仿真计算量大、环境配置复杂,前期阶段它带来的精度优势对你的学习效率没有任何帮助——你还没学会走呢,先别急着买车。等策略在低保真环境里能收敛了,再换高保真平台做验证。

2.2 URDF模型处理与注意事项

仿真环境里要做的第一件事,就是把机械臂的URDF模型加载进去。URDF(Unified Robot Description Format)是机器人描述文件,定义了机械臂的各连杆长度、关节位置、质量、惯性等参数。很多同学直接从厂家官网下载一个URDF扔进仿真器,结果关节转起来像没有重力一样、或者碰撞检测完全失效,排错排到怀疑人生。

我踩过的坑主要有这么几个:

第一个是惯性参数缺失。不少开源URDF里某个link的质量和惯性矩阵是空的,仿真器自动给一个默认值。这个默认值通常很不合理,会导致动力学行为完全失真。你训练出来的策略在仿真里看着还行,一上真机就抖成筛子。处理办法就是逐个link检查URDF里是否有<inertial>标签,没有就得补。

第二个是碰撞几何简化。URDF里的<collision>元素决定碰撞检测的几何体,很多人直接把整个光滑的网格mesh放进去。这样做计算量巨大,而且碰撞检测容易不稳定。正确做法是用简单的几何体(圆柱、长方体)近似每个link的外形,训练速度能快好几倍。

第三个是关节摩擦和阻尼参数。URDF里默认摩擦系数往往是0,但真实机械臂的关节里是有减速器摩擦的,这会导致仿真里的机械臂比真机“顺滑”太多。想提升sim2real迁移成功率,这里就要开始埋下伏笔——给关节加一点摩擦和阻尼,让仿真里的动力学表现尽量贴近真机。

2.3 训练环境接口设计

把URDF加载好之后,你需要把环境封装成强化学习算法能吃的接口形式,核心就是几步:

  • reset():把机械臂复位到初始位形,重新随机化目标物体的位置;
  • step(action):把算法输出的动作解析成关节位置或力矩指令,驱动仿真推进一个时间步,返回新的观测、奖励、是否结束;
  • 获取观测:从仿真器里读出关节角度、角速度、末端位姿、目标位置等信息。

听起来简单,但有一个细节很重要:动作接口选什么控制模式。很多RL库默认用关节位置控制,即算法直接输出目标关节角,然后靠仿真器内部的PD控制器去跟踪。优点是稳定,缺点是学出来的策略依赖PD参数,迁移到真机时如果真机控制频率跟不上,效果会打折扣。后期如果想做更精细的操作,可以考虑用关节力矩控制代替位置控制。

这里还要强调一个高频踩雷点:仿真器的控制频率。机械臂运动速度很快,如果控制频率太低(比如每步50ms),末端运动会出现明显的滞后和不连续。我一般会把步长调到2ms~5ms,每4~8个仿真步执行一次策略动作,保证单位时间内有足够的反馈。不要为了图快盲目加大步长,训练出来的策略会像喝醉酒一样摇摇晃晃。

3. 状态、动作与奖励函数拆解

3.1 观测空间设计的核心思路

强化学习里有一句老话:Garbage in, garbage out。观测空间的设计直接决定策略能学成什么样。机械臂任务里观测空间可以很简单,也可以很复杂,关键看你需要什么信息。

最简单的观测就是本体感知:各关节的角度、角速度。这套观测够学“伸展到某个位置”这种基础动作。稍复杂一点的任务就得加上末端执行器信息:末端的三维位置、姿态(四元数)、末端速度。如果是抓取任务,还要把目标物体的位置甚至形状信息加进来。

我用过一个比较经典的设计是:关节角度+关节角速度+末端位置+目标位置,维度一般在20~30之间,实际效果已经很不错。如果任务还涉及视觉输入,就需要把图像加进来,这时候通常会用两个分支网络:图像走卷积层提取特征,状态向量走全连接层,最后合并。

有个非常容易被忽视的点:要不要把关节角速度加进观测。看起来是废话,但很多照抄代码的同学漏掉它,导致策略只能学到位置控制却对动态过程毫无感知,动作一快就失控。记住,观测里一定要包含能让网络推断出“当前正在怎么运动”的信息。

还有一个点:观测空间的特征尺度问题。关节角度范围是-π到π,末端位置可能是几十厘米,两者直接拼在一起,数值尺度差异会让网络训练很不稳定。必须对每一个观测维度做归一化。我踩过这个坑之后养成了习惯,所有观测在封装进环境时就统一归一化到[-1,1],训练稳定性立刻提升一个档次。

3.2 动作空间设计与执行频率

动作空间中一个决定性的选择是:用连续控制还是离散控制。机械臂是高维连续运动系统,理论上应该用连续动作空间,事实也确实如此。但很多初学者会截图类似“把关节角分成30个离散档位,每个关节输出一个档位”的做法,这在我来看是一个很糟糕的选择——离散化会丢失精细控制能力,而且动作空间维度随档位数量爆炸式增长。

连续动作空间主流有两种:关节空间动作和末端笛卡尔空间动作。关节空间动作就是直接输出每个关节的目标角度或力矩增量,灵活通用,但是学出来的动作往往不够“直观”,需要反复约束才不至于扭出奇怪的姿态。末端笛卡尔空间动作是直接给末端一个速度或者位置偏移,好处是动作更直观,便于约束末端轨迹,缺点是机械臂有奇异位形,有些笛卡尔空间的指令在运动学上不可达,需要额外处理。

此外还要留一个心眼:动作的平滑性。如果策略直接输出关节位置目标,相邻两步之间目标角变化过大,机械臂就会表现得很“毛糙”。往往需要加一个简单的低通滤波器或者动作变化率惩罚,这个直接在奖励函数里做就行,后面细说。

3.3 奖励函数塑形:稀疏还是稠密

奖励函数是机械臂RL里最玄学、也最影响训练效果的部分。我见过的失败案例,绝大多数是奖励设计出了问题。

稀疏奖励是最“政治正确”但最难学的设计:任务成功给一个正奖励,其余时候都是0。比如“末端到达目标位置5cm内给+10奖励”,这个设置非常干净,不会误导智能体,但问题是探索困难——机械臂初始随机乱动几乎不可能碰巧抵达目标点,算法连“哪个方向是对的”都学不到,更别提收敛了。纯稀疏奖励在机械臂任务里基本寸步难行。

于是大部分人改用稠密奖励:根据当前状态与目标状态的“距离”实时给一个负向的小奖励,推动智能体逐步接近目标。最简单的就是“当前末端到目标的距离”取负值。这个思路方向对,但有一个隐患:只奖励距离缩短,算法很容易钻空子——比如末端离目标还有20cm,策略学到“猛一下往前够”,但过程中可能撞到障碍物、或者姿态变得很奇怪。因为奖励函数只关心距离,这些“副作用”完全没有被惩罚。

我现在的做法是分阶段、分优先级设计:

  1. 任务成功给一个大的正奖励,比如+50;
  2. 每一步给一个小的距离惩罚,鼓励靠近目标;
  3. 动作变化率惩罚,惩罚单位时间内的动作突变,抑制抖动;
  4. 超出关节极限或碰撞时给一个较大的负奖励并提前终止。

这一套设计看起来简单,但每一项都是必要的,少了哪一条都会出现一种奇怪的失败模式。举个例子:没有动作变化率惩罚,学出来的策略通常会高频抖动,末端轨迹像得了帕金森一样;没有碰撞惩罚,机械臂会从任何姿势绕过去“够”到目标,根本不管中间过程。

4. 算法选型与关键实现

4.1 PPO、SAC、DDPG横向对比

选算法这个问题,我的答案经历过一个从“全都要试”到“看场景而定”的过程。现在市面上机械臂RL用得最多的三个算法是PPO、SAC和DDPG,我用表格做个对比:

算法类型样本效率稳定性超参敏感度适合场景
PPO在线策略低高低策略优化稳定,大多数机械臂任务的保险选择
SAC离线策略高中中样本采集贵、想充分用历史数据的场景
DDPG离线策略高低高动作维度很高、连续控制类场景

我的建议非常明确:通用机械臂任务,优先试PPO。原因很简单——PPO对超参数的鲁棒性最好,clip机制限制了更新步长,不容易“训飞”,特别适合新手。而SAC的熵正则化让它探索性更强,适合复杂操作任务,但调起参来麻烦,需要对温度系数和网络结构有点感觉。DDPG我相对不推荐,它对网络初始化和超参数极其敏感,我身边用DDPG训机械臂的,十有八九都只活在论文里,现实中复现一直不太稳。

不过如果你是做“策略最终部署到真机”的项目,我真心建议你PPO和SAC都跑一下,选效果更好的。二者原理差异决定了在同一个任务上可能会呈现不同的行为风格:PPO的会小心谨慎一些,SAC的会更敢探索,最终策略的平滑度可能不同。

4.2 网络结构与训练超参数

机械臂RL的网络结构不需要花哨,核心是一个“状态输入-隐藏层-动作/价值输出”的多层感知机。隐藏层我一般用两层256或三层[256,256,128],激活函数用ReLU。做视觉输入的任务再加一层卷积特征提取,但前期别碰,先把手上的状态观测任务跑通。

几个关键超参数,我直接给一套可以抄作业的默认值:

  • 学习率:actor和critic都设为3e-4。学习率太高是最常见的训练发散原因,调参时每次减半试。
  • batch size:256~4096之间,太小的batch会让更新过于频繁、方差大。
  • 经验回放池大小(如果是SAC/DDPG):100万条起步,太小了样本多样性不够。
  • 折扣因子gamma:0.99,任务时间尺度长就0.995。
  • 熵系数(SAC):自动调节,别手动设死。

这里有一个经验之谈:机械臂任务里,gamma千万别设太低,比如0.9。gamma低意味着智能体只看重眼前的奖励,而一个成功动作的奖励往往在最后几步才到来,前面的导向性距离惩罚又都很小,很容易让智能体变得短视。我在一个插孔任务里吃过这个亏,gamma调到0.99之后收敛速度明显提升。

4.3 一个可以照抄的训练流程骨架

我把自己常用的训练循环写出来,不算完整代码,但流程足够清晰:

  1. 每轮开始,reset环境,随机化机械臂初始姿态和目标位置;
  2. 用当前策略在环境里跑episode,收集轨迹数据(观测、动作、奖励、结束标志);
  3. 对轨迹计算advantage估计(GAE),这里lambda我一般取0.95;
  4. 把数据塞给PPO更新actor和critic网络,更新轮数4~8次;
  5. 每隔若干轮评估一次当前策略:固定初始条件跑几个episode,记录成功率;
  6. 存模型、存日志,继续下一轮。

别小看这个骨架,很多朋友看我代码觉得简单,但自己写的时候会漏掉“评估”这一环。没有评估环节,你永远不知道训练到哪一步策略真的能用了,只能凭训练曲线瞎猜。我习惯每10轮评估100个固定初始条件的episode,统计成功率变化,这是判断训练是否收敛的最可靠指标。

5. 实操记录:从零训练一个点到点动作任务

5.1 任务定义与仿真布置

为方便说明,我用一个具体的任务来走一遍全流程:一个六轴机械臂,学“末端从任意起始姿态移动到三维空间中的一个随机目标点,并在目标点保持稳定”。这个任务虽然简化,但包含了机械臂RL的全部核心要素,值得认真做一遍。真机项目里很多更复杂的任务,本质上都是这个任务的加料版。

仿真布置上,我在开源物理引擎里加载六轴机械臂URDF,目标点用一个固定的小球表示,每轮reset时在机械臂工作空间内随机采样一个三维坐标。观测定义为“当前末端位置相对目标点的差值+各关节角度+关节角速度”。动作定义为关节位置增量(上一步关节角基础上加一个小偏移),这个做法比直接输出绝对关节角更自然,连续性和平滑性都好一些。

5.2 训练代码骨架

写一段关键代码给大家参考,这里不是完整工程,但核心逻辑是完整的:

import numpy as np class ReachingEnv: def __init__(self, robot): self.robot = robot self.dist_threshold = 0.05 def reset(self): self.robot.reset_joints(np.random.uniform(-0.5, 0.5, 6)) self.target = self.robot.sample_target_in_workspace() return self._get_obs() def step(self, action): # action: 6维关节角度增量 target_qpos = self.robot.get_joint_angles() + np.clip(action, -0.1, 0.1) self.robot.set_joint_positions(target_qpos) self.robot.advance_simulation(0.1) # 推进几个仿真步 obs = self._get_obs() distance = np.linalg.norm(self.robot.get_ee_pos() - self.target) # 奖励塑形 reward = -distance # 距离惩罚 if distance < self.dist_threshold: reward += 50 # 成功奖励 done = True else: done = False return obs, reward, done, {}

这段代码把奖励设计的思路直接落地了。注意我特意没用复杂的终止逻辑,真实项目里你可以再加“步数超过N就结束”的早停,避免无效轨迹拖慢训练。

5.3 训练过程曲线与判断方法

跑起来之后训练曲线会呈现一种典型的形态:最开始几百轮成功率接近0,奖励在-1附近徘徊(因为末端离目标远,距离惩罚大);接着会有一个漫长的不涨平台期,大概持续几百到一千轮,这是策略正在积累有效经验,别慌;然后成功率会突然开始上扬,往往一个晚上过去,成功率从10%蹿到80%。

为什么会有这种“突变”?因为策略网络从一个随机初始化状态到达一个临界点后,开始稳定地找到“末端靠近目标”的梯度方向,一旦锁定方向,剩下就是微调。那种每天看曲线就觉得“没救了”的心态,我太理解了——但只要曲线没有出现上下剧烈震荡、奖励在整体趋势上缓慢上升,就有戏。

判断训练是否收敛也有一些硬指标:成功率稳定在95%以上、末端轨迹平滑、奖励曲线不再有大的波动。到这个程度,基本可以宣布策略学出来了。

6. 训练中常见的坑与排查技巧

6.1 奖励一直不涨,问题出在哪

这是被问得最多的一个问题。我的排查顺序是固定的:

第一步,先确认奖励信号确实能区分好坏。单独用一个随机策略跑几百个episode,统计成功率和平均奖励。如果随机策略都偶尔能成功,说明任务本身不是不可能,那问题在算法或网络;如果随机策略成功率是0,先别急着调参,看看奖励是否太稀疏,要不要给更多引导。

第二步,确认观测归一化做好没有。我之前排查过一个项目,奖励一直在-0.9到-0.7之间上不去,检查半天发现末端位置数值是0.3~0.6米,但关节角是弧度值(-3~3),拼在一起之后网络被大数值的关节维度主导,距离信号被淹没了。归一化之后第二天就涨起来了。

第三步,检查更新是否过于频繁、学习率是不是太大。PPO的训练如果loss变成NaN,那一定是学习率太高或者advantage估计有异常值。

6.2 动作震荡与末端抖动

策略训好后部署时会出现一个很典型的问题:末端一直在目标点附近高频抖动,无法稳定停留。这个问题九成的原因是奖励函数里缺少对动作变化率的惩罚,或者控制频率太低导致反馈延迟。

解决办法有两个:一是加动作平滑项,比如-0.01 * sum((action_now - action_prev)**2),强迫策略不要做突变;二是在训练环境里加一个小的一阶低通滤波器,把动作平滑后再送入执行器,仿真和真机都这样做。注意平滑系数不要调太大,否则动作响应变慢,任务成功率会下降。

6.3 仿真到真机迁移差距大

这是机械臂RL落地最核心的坎。仿真里精准到达目标,真机上末端偏了5厘米,这种差距绝大多数情况下不是算法的问题,是“仿真和真机的物理差异”被算法放大了。

我目前的应对方案,按重要程度排序是这样:

  • 域随机化:训练时随机化目标位置、机械臂质量、关节摩擦、控制延迟等参数,让策略学到的不是一个精确值,而是一个鲁棒策略;
  • 动力学参数校准:把真机的摩擦、惯性参数测出来写进仿真器,至少保证接近;
  • 使用真实控制频率:仿真里的控制频率尽量跟真机控制器一致,不要仿真里跑500Hz,真机只支持100Hz,训练时就得按100Hz来;
  • 先在低难度下测试:迁移前先在低速、小范围的任务里测试,确认末端大致能对上,再逐步加快,别一上来就满速跑。

6.4 训练速度太慢怎么办

机械臂RL样本效率低是出了名的,一晚上训练跑几百万步是常态。提高速度有两条路:一条是堆并行,多个仿真环境同时跑;另一条是降低单步的计算量。并行这一块,现代开源RL库都支持vectorized environments,一个GPU上跑几十个环境同时采样,训练速度能提升一个数量级。另一个容易被忽略的点:物理仿真器的步长能放宽就放宽,有些细节对任务结果影响不大,但计算量差别很大。

还有一个小技巧:先降低渲染负荷。如果你不开可视化窗口,很多仿真器默认用offscreen渲染甚至无渲染模式,速度差三五倍很常见。我跑大规模训练时从来不开可视化,只在评估时才打开看一眼,这也是一种成熟的做法。

6.5 问题排查速查表

现象优先检查项处理建议
全程无进展奖励是否信号过于稀疏增加引导性距离惩罚
loss变成NaN学习率过高 或 advantage估计异常学习率减半,检查观测是否有inf/nan
训练曲线剧烈震荡batch过小 或 gamma过低增大batch,gamma调0.99
末端抖动动作变化惩罚缺失加动作平滑项或低通滤波
真机偏差过大仿真与真机物理差异域随机化训练
收敛到错误姿态奖励函数未约束关节极限/碰撞加约束惩罚项
训练速度慢渲染没关 或 并行环境少关渲染,开多环境并行

7. 一些真心话:做这个项目需要注意什么

最后说点实战体会。机械臂+强化学习这个方向,技术上确实有门槛,但真正让它劝退很多人的不是算法本身,而是“目标定得太高、路径定得太短”。我见过太多人一上来就要做一个“能自己抓取任意物体的通用机械臂智能体”,结果训练了几个月还在原地打转。这是正常的——一个看似简单的“把物体从A拿到B”,中间涉及视觉识别、抓取姿态预测、运动规划、力控,每一个子问题单独拿出来都是一个研究方向。

我个人比较推荐的做法是“小步快跑”。先做一个只学“末端动到某个位置”的点到点任务,确认整个仿真+训练+评估的流程彻底跑通了,再往里面叠加目标识别、移动到目标物上方、抓取、放置等环节。每一步都等策略真的学出来、评估指标稳定了,再往前推进。不是你不聪明,而是这个领域天然就是复杂系统,直接一步到位谁都会崩。

工具和库的选择上也不用太纠结。市面上现成的RL库已经帮你把算法实现这类底层工作都做了,你要做的核心工作其实是环境搭建和奖励设计。与其纠结一个SAC的系数调不好,不如多检查仿真环境里机械臂的物理参数是不是合理。我调试过的项目里,环境写错的占比远远大于算法写错的。

最后建议你从头到尾认真跑一个小项目,哪怕它很简单,也要走完“仿真训练-曲线分析-问题排查-(如果有条件)真机迁移”的完整闭环。一次完整闭环带来的经验,胜过看一百篇文章。真到了你能熟练诊断“这个现象是环境问题还是算法问题”的时候,机械臂+强化学习对你来说就不再是个噱头,而是一个真正可以被你驾驭的工程工具了。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进