资讯动态

清扫机器人强化学习:10项复合奖励函数让训练从100分涨到778分

发布时间:2026/10/17 5:11:29 来源:尧图企业网站定制
前阵子我把清扫机器人项目的强化学习训练分数从 100 分抬到了 778 分网络结构没动算力没加甚至训练集都没扩大唯一的变量是奖励函数。这件事让我彻底相信在复杂的机器人任务里奖励工程的优先级往往比算法选型更高。清扫看似简单实际是个典型的多步决策问题——机器人要决定往哪走、扫不扫、扫完去哪每一个动作都要在时间和能耗上精打细算。用最基础的稀疏奖励等于让机器人从一句“干得好”里自己悟出所有步骤太难了。我梳理了从 100 分到 778 分背后的一整套奖励工程实践核心就是 10 项复合奖励下面逐个拆开讲。不管你做的是扫地机、机械臂抓取还是机器人导航这份经验应该都用得上。1. 清扫任务为什么会卡在稀疏奖励上1.1 清扫任务的双重难点目标稀疏与动作长程强化学习要能跑通最关键的是让智能体在一个多步决策过程中不断获得“信号”来修正策略。清扫机器人尤其考验这一点因为它的状态空间是连续的机器人当前位姿、障碍物分布、已经覆盖过的栅格区域、剩余未覆盖区域每一个维度都在变。而动作空间也是连续的我这边用的是差分驱动底盘输出是线速度和角速度。在这样一个连续空间里如果只告诉机器人“最后扫干净了就奖励”它根本没法把一个长期目标拆解到每个时刻的微小动作上。举个更直观的例子一个刚出生的孩子如果家长从不说话、不指路只在二十年后说一句“你会不会整理房间”那他一辈子也不可能学会整理。稀疏奖励就是这个效果——任务完成信号离单步动作太远梯度几乎传不回来。清扫任务的目标尤其稀疏因为“清扫干净”是一个整体状态几乎没有中间反馈。机器人扫过一格新区域时它其实不知道这算不算做对了只有在回合结束时看到一个覆盖率分数这时才有一点信号但早不知道是哪一步的功劳了。1.2 稀疏奖励的失败曲线100分是个什么概念我这个项目的评估方式很简单自定义一个综合分由三部分构成——栅格地图的最终覆盖率乘 100 作为主要得分每步时间惩罚扣一点每次碰撞再扣一点。我用这个综合分作为报告用的指标也用来判断一个奖励函数到底好不好用。一开始我用的就是最朴素的稀疏奖励清扫完成且覆盖率超过 90% 时给 1 分其余时刻奖励为 0。这个设置下训练了 100 万步综合分始终在 100 分附近震荡。那“100 分”具体是个什么状态就是机器人从头到尾几乎没扫出有效覆盖路径基本是随机游走一会儿撞墙一会儿原地转圈回合结束时覆盖率可能只有 8% 到 15%。由于碰撞扣分和时间扣分的存在勉强把分数压在 100 分上下。这其实不是机器人蠢而是梯度信号太弱PPO 在这种反馈下学到的策略和一个随机策略没什么区别。我以为加一个最终完成奖励就够了后来才发现清扫任务里的“大目标”必须被拆碎才能让机器人看得见摸得着。2. 我最初的奖励函数是怎么把训练带进死胡同的2.1 第一版奖励函数的组成与直觉被稀疏奖励教育之后我的第一反应是常见的做法加几个密集型奖励让机器人每一步都能收到反馈。当时我设计了这样一套奖励奖励项表达式权重设计意图覆盖面积增量每新扫一个栅格0.05/格鼓励多扫清扫电机开启开启清扫电机且移动0.02/步确保机器人边动边扫时间惩罚每步-0.01/步提高效率碰撞惩罚每次碰撞-0.1/次避免撞墙完成奖励覆盖率大于90%1.0/次任务完成刚上手时训练曲线确实涨了一波从 100 分爬到了 150 分左右。但再往后就卡住了而且卡得很诡异覆盖率停在 30% 出头epsode 长度越来越长机器人看起来忙忙碌碌但扫过的区域始终只有那么一小块。我把训练日志调出来看发现了一个典型的“奖励钻空子”问题——机器人学会了原地抖动。2.2 卡住的原因奖励分量之间的冲突与漏洞问题出在“清扫电机开启 移动”这个持续奖励上。机器人在墙角附近来回磨蹭轮子在转电机在开但它实际上反复压着同一小片区域新覆盖几乎没有增加。因为这组动作既能吃到电机开启奖励又不会因为碰撞被扣太多分时间惩罚的力度又不足以压过这个收益。于是策略收敛到了一种“伪勤奋”状态有动作、有移动、有清扫声就是不干活。另一个问题是覆盖面积增量的权重太轻。假设一个新栅格只有 0.05 分而原地抖动每步能拿 0.02 分只要抖上三步就超过扫一个新格的收益。更麻烦的是实际清扫中每扫一个新格需要跨越一段距离这段距离里没有任何奖励只有时间扣分。这让机器人更倾向于“短周期高频率的小动作”而不是“长距离高效清扫”。第一版奖励的坑在于我奖励的是“行为过程的表面特征”而不是“清扫目标的行为结构”。每个拆出来的奖励项都依赖一个具体可观测的信号但如果信号本身可以被廉价伪造策略就会去伪造信号。所以后来我做了一个决定不再单纯堆正奖励而是把“清扫覆盖率”“动作连贯性”“路径效率”和“安全性”拆成一组互相牵制的复合奖励让每一项都对应一个不能轻易钻空子的行为指标。3. 10 项复合奖励的拆解与设计动机3.1 设计总原则每一项都要能独立被观测、被问责复合奖励不是简单地把很多小奖励加起来而是要设计一套“互相补位、互相约束”的体系。我在设计时给自己立了三条规矩每一项奖励都必须能准确计算出数值而且这个数值不能被机器人通过高频重复动作刷爆。每一项奖励的期望贡献要设一个上限不允许某一项在梯度中占据绝对主导地位。每一项奖励都要对应一个我真正关心的行为覆盖新区域、避免重复、保持连贯、保证安全、尽快收工。基于这三条我把最终版本梳理成 10 项分为四个维度覆盖率、路径效率、安全约束、任务完成。下面先把完整清单列出来再逐个讲我为什么这么设计。3.2 最终版 10 项复合奖励清单编号奖励项计算方式建议权重作用R1覆盖新网格奖励每新增一个被清扫的栅格0.3/格直接推动覆盖率提升R2覆盖保持奖励当前覆盖率与上一步覆盖率之差0.8 × Δcoverage让覆盖率上升趋势本身成为信号R3区域探索奖励机器人首次进入一个宏观子区域1.0/次鼓励去远的地方避免局部过扫R4重复覆盖惩罚每压过一次已覆盖栅格-0.02/格阻断原地蹭奖励的路径R5清扫效率奖励单位时间新覆盖面积 ≥ 阈值时0.05/步平衡速度与清扫效果R6急转弯惩罚角速度绝对值超过阈值-0.2/次防止原地转圈和抖动R7碰撞惩罚发生碰撞-0.5/次训练避障能力R8贴近边界惩罚与障碍物或墙体距离小于安全距离-0.1 × (1 - d/d_safe)让机器人能沿着墙走但不硬贴R9任务完成奖励覆盖率首次达到 95%10.0/次强化完整清扫的收尾行为R10时间惩罚每个仿真步-0.001/步保持基本效率但不做主导你可能已经发现了这套奖励里没有“清扫电机开启”这种过程性奖励。我刻意删掉了所有“做了某个动作就给分”的设计转而只奖励“产生了某个可验证的结果”。比如 R1 奖励新增的栅格这必须是真的扫到了之前没扫过的地方R5 奖励效率要求新覆盖面积对照行驶距离不能太低。这些信号机器人不容易伪造因为它要同时满足多个条件才能拿到奖励。3.3 每项奖励到底在牵制什么行为R1 和 R4 是一对天然的对抗组合。R1 鼓励去没扫过的地方R4 惩罚扫过的地方合在一起机器人就不会在原地反复磨蹭因为原地动作不仅没有新覆盖还会因为重复覆盖被倒扣分。R4 的权重不能太大否则机器人会为了不重复覆盖而刻意避开一些必须经过的路径导致覆盖率永远上不去。我的 R4 权重从 -0.05 一路试到 -0.02最终在覆盖率上限和重复行为之间找到了平衡。R3 是为了解决一个很隐蔽的问题覆盖率奖励容易让机器人只扫入口附近的一片区域因为那里起点近、风险低扫起来“性价比高”。如果没有区域探索奖励它永远不会主动离开舒适区。我在地图上预先划分了一些宏观子区域只要机器人第一次进入某个子区域就给一个一次性奖励。这个奖励不需要很大但它能在早期训练中非常有效地把机器人“推”向远方。R6 和 R5 共同压制动作抖动。急转弯惩罚直接给角速度绝对值设了一个物理上的“红线”一旦超过阈值就扣分。在连续控制任务里很多策略都会出现高频抖动这在物理仿真里看起来是“微操”实际上完全是噪声。急转弯惩罚把这种噪声的收益压成负数倒逼策略输出平滑的角速度命令。R7 和 R8 是安全礼仪。碰撞惩罚用于训练基本的避障反射但光有碰撞惩罚不够因为机器人可以离墙一毫米前进不碰墙但视野全被墙挡住。R8 的贴近边界惩罚让它和墙体、障碍物保持一个合理的距离这样既不会撞又能留出清扫通道。这两个奖励合起来能稳定避免“贴着墙走但不扫墙边”的行为。R9 的单次奖励很大但只在覆盖率首次达到 95% 时触发。这个值不能设得太低否则机器人学到的策略是“扫个八九成就收工”也不能设得太高比如超过 100%那几乎永远拿不到形同虚设。95% 是我测试下来比较合适的完成线既能让机器人有动力去覆盖边边角角又不至于因为地图上某几个不可达栅格而一直卡着完成不了。4. 权重标定让每一项奖励都“可感知、不打架”4.1 单个奖励项的量纲必须单独标定10 项复合奖励的坑点不是“项太多”而是“每一项的量纲和量级完全不同”。R1 是每格 0.3R4 是每格 -0.02R6 是每次 -0.2R9 是一次 10。如果直接全开梯度一定会被 R9 和其他高频奖励之间的数量级差距搅乱。更麻烦的是同一个项在不同训练阶段出现的频率不一样早年间可能一次回合只扫 20 个新格后期能扫 200 个新格所以同一个权重在早晚期的贡献占比是动态变化的。我的做法是先做“单因子标定”把除某一项之外的所有奖励全部关掉只保留这一项然后用同一个环境跑 10 万步观察机器人会收敛成什么行为。比如只开 R1机器人会向远处冲因为远处新栅格多只开 R4机器人会原地一动不动因为不动就不会重复覆盖只开 R6机器人会直直地走直线因为连续直行角速度为零。这个实验虽然原始但非常直观地告诉我每一项的“能力上限”和“副作用区间”。4.2 用奖励预算控制每个维度的贡献比例在单因子标定之后我把每一项在“成功清扫一个完整回合”中的理论最大贡献算了一遍。一个成功回合大约需要 1000 步覆盖 2800 个栅格走过大约 15 米路径碰撞 0 次。我按这个成功轨迹估算各项的最大累计奖励R1 新网格2800 × 0.3 840R2 覆盖保持覆盖率从 0 到 95%总差大约 0.95 × 1200 1140取决于我设定的覆盖区域总数R4 重复覆盖惩罚如果只在必要路径上重复约 -30R9 任务完成10R10 时间惩罚-1这样一看R1 和 R2 加在一起占据了整场奖励的绝大部分这符合“清扫覆盖率是主目标”的定位。但 R3、R5、R7、R8 加起来也不能完全忽略它们负责约束行为边界。我给自己定的规则是非覆盖率类奖励的总预算不超过 15%。如果某次训练发现探索奖励的总贡献快要追上覆盖率奖励了就说明探索奖励权重太高机器人会为了探路而忘了清扫需要调低。4.3 权重调整的实操经验在权重试错阶段我踩过一个典型的坑把 R1 从 0.3 调到 1.5以为“覆盖率动力更足”结果训练反而更差了。原因是覆盖率栅格传感器存在边缘噪声机器人反复移动会让某些边界栅格被重复判定为“新增”它学会了利用这个噪声刷 R1。后来我把权重调回 0.3同时把 R4 的惩罚力度从 -0.01 调到 -0.02才把这个投机行为压制住。我还发现R8 贴近边界惩罚最好配合 R5 效率奖励一起调。如果只加 R8机器人会离墙太远扫不到墙角如果只加 R5它会为了效率指标专门挑空旷区域跑把墙角全留给未覆盖状态。最后我的组合是R8 权重 0.1R5 权重 0.05让机器人在“离墙近一点”和“单位时间覆盖面积达标”之间自己找一个折中策略。这个折中结果比较接近人类扫地的方式沿着边缘扫但不死贴。5. 分阶段课程训练从“会走路”到“会扫地”再到“扫得划算”5.1 为什么要分阶段而不是一次性全量奖励10 项复合奖励一次性全开会让 PPO 的策略网络在刚开始训练时面对一个过于复杂的目标函数。前 30 万步里机器人连“不撞墙”都还没学会就要同时考虑“覆盖率增量”“重复惩罚”“探索奖励”和“任务完成”结果样样都想要样样都学不好。我在实验里对比过两种打开方式全项从 0 万步开始和前 50 万步只开部分项、之后逐步加项。第二个方案的综合分不仅最终更高而且训练曲线的方差明显更小。这其实就是课程学习最简单的应用把任务难度按阶段拆开。清扫任务的难度阶梯在我看来是——先保证能安全移动再学会覆盖新区域最后优化路径重复和效率。每个阶段只改变一到两个奖励项让策略网络在相对稳定的目标下收敛而不是频繁被新增的梯度方向打断。5.2 三个阶段的具体划分与分数里程碑阶段 A基础运动与避障0 到 50 万步。这个阶段只开 R6、R7、R8、R10。目标是让机器人知道“移动是安全的但有代价碰撞和急转要尽量避免”。评估指标不是覆盖率而是单个回合中平均累计碰撞次数、平均移动距离和任务完成时间。大约 20 万步后机器人已经能稳定地在一片空地图里绕圈走不撞墙单回合平均移动距离从十米提升到五十米。在这个阶段结束时我测过综合分已经在 220 分左右了因为覆盖率虽然还是不高但碰撞扣分大幅减少时间惩罚也降了下来。阶段 B学习清扫覆盖50 万到 150 万步。在阶段 A 的基础上打开 R1、R2、R9。R9 的任务完成奖励从阶段 B 开始就存在因为此时机器人已经能安全移动应该开始理解“完成一个清扫任务”是什么概念。这一阶段的训练目标是让覆盖率从 30% 爬到 70% 以上。150 万步结束时单回合平均覆盖率能到 78%综合分爬到 430 分左右。但这时候路径效率很糟会出现大量“回头路”把一个地方扫干净后又要绕个圈子再回到未覆盖区域时间浪费明显。阶段 C优化路径效率与行为细节150 万到 300 万步。最后打开 R3、R4、R5并把 R1、R2 的权重保持住。这一阶段重点惩罚重复覆盖和过远绕行同时用 R3 鼓励探索新子区域。训练曲线在阶段 C 开始后的前 20 万步有过一次小回退综合分从 430 掉到 380 左右原因是 R4 的出现让机器人暂时“不敢动”了——它害怕走过已覆盖区域被扣分。我把 R4 的权重在过渡期做成了线性上升先 0.0用 5 万步慢慢升到 -0.02。这样策略有时间适应新约束。阶段 C 后半段覆盖率开始稳定在 90% 以上单回合碰撞几乎归零综合分最终爬到 778 分并且稳定住了。5.3 阶段切换的过渡技巧阶段切换不是直接改奖励函数那样会让策略突然面对一个完全不同的目标函数很容易发生灾难性遗忘。我用了“权重线性插值”的方式假设阶段 B 的 R4 权重是 0阶段 C 的目标权重是 -0.02那么我让它在 5 万步内从 0 线性变化到 -0.02。同理R3、R5 也是线性引入。这个方法效果很好策略没有出现明显的崩溃只有短时间的适应波动。每个阶段结束后我会冻结当前权重多跑 2 万步做一次评估确保分数不是偶然结果。如果两次评估的差值超过 20 分我就要检查是不是某个奖励项的观测值有噪声或者权重设定过于极端。稳定性的价值在奖励工程里被很多人低估一次偶然的高分不值得信任必须连续多次采样取平均。6. 训练配置、可复现代码与奖励钻空子的围堵6.1 环境、算法与超参数我用的仿真环境是自己搭的 2D 栅格清扫环境一个 20m × 20m 的房间里面有固定障碍物机器人是一个差分驱动小车车头装了一个可以检测“当前栅格是否已被清扫”的传感器。状态向量包含机器人位姿、当前时刻已覆盖栅格的位置索引压缩成一个小的网格矩阵、近程激光雷达测距值。动作是二维连续向量线速度范围 [-0.5, 0.5] m/s角速度范围 [-1.5, 1.5] rad/s。算法用的是 PPO因为它在连续控制任务里最稳定调参空间不大。网络结构很简单两层 MLP每层 256 个神经元没有用 LSTM。超参数如下参数值γ0.99GAE λ0.95学习率3e-4n_steps2048batch size64clip range0.2训练步数300 万这个配置不是我拍脑袋定的而是从大量网格搜索里选出来的。学习率 3e-4 是 PPO 比较稳的起点batch size 太小容易让奖励方差变大太大又会让策略更新太慢。我没有刻意调网络宽度因为奖励工程已经是主要优化点网络只要能把状态映射到动作就行复杂结构反而容易过拟合到奖励噪声上。6.2 核心奖励函数代码示例下面是我在环境 step 中计算 10 项奖励的核心代码省略了部分环境内部函数但奖励逻辑是完整可读的def compute_reward(robot_state, env_state, action, prev_state): 返回 reward, info 其中 prev_state 记录了上一帧的覆盖率信息用于计算增量 reward 0.0 info {} # 环境提供的信息 coverage_now env_state[coverage_ratio] # 当前覆盖率 0-1 new_covered_grids env_state[new_covered_grids] # 本步新增覆盖栅格数 repeated_grids env_state[repeated_grids] # 本步重复覆盖栅格数 collision env_state[collision] # 本步是否碰撞 min_dist_to_obstacle env_state[min_dist_to_obstacle] angular_velocity action[1] moved_distance env_state[moved_distance] step_cost env_config[step_cost] # R1: 覆盖新网格奖励 r1 0.3 * new_covered_grids reward r1 info[r1_new_grid] r1 # R2: 覆盖保持奖励覆盖率上升的增量 delta_coverage coverage_now - prev_state[coverage_ratio] r2 0.8 * max(0.0, delta_coverage) reward r2 info[r2_coverage_hold] r2 # R3: 区域探索奖励首次进入新子区域 r3 0.0 if env_state[enter_new_subregion]: r3 1.0 reward r3 info[r3_explore] r3 # R4: 重复覆盖惩罚 r4 -0.02 * repeated_grids reward r4 info[r4_repeat] r4 # R5: 清扫效率奖励单位距离新覆盖面积不低于阈值 r5 0.0 if moved_distance 0 and new_covered_grids / moved_distance 0.5: r5 0.05 reward r5 info[r5_efficiency] r5 # R6: 急转弯惩罚 r6 0.0 if abs(angular_velocity) 0.8: r6 -0.2 reward r6 info[r6_sharp_turn] r6 # R7: 碰撞惩罚 r7 -0.5 if collision else 0.0 reward r7 info[r7_collision] r7 # R8: 贴近边界惩罚 r8 0.0 safe_dist 0.3 if min_dist_to_obstacle safe_dist: r8 -0.1 * (1 - min_dist_to_obstacle / safe_dist) reward r8 info[r8_near_wall] r8 # R9: 任务完成奖励 r9 0.0 if coverage_now 0.95 and not prev_state[task_done]: r9 10.0 reward r9 info[r9_task_done] r9 # R10: 时间惩罚 r10 -step_cost reward r10 info[r10_time] r10 return reward, info这个函数在实际训练里会放在环境的 step 里每个仿真步调用一次。建议每次调用后把 info 里的各个分量都塞进 TensorBoard而不是只看总 reward。因为总 reward 会掩盖单个分量的异常只有把每个 r1 到 r10 拆开看才能知道策略到底在钻哪个空子。6.3 我遇到的三次奖励钻空子事件及围堵手段第一次是刷探索奖励。阶段 C 引入 R3 后机器人学会了在地图上沿子区域边界来回横跳一只脚踏进新子区域拿奖励马上退回来再踏进去再拿奖励。我一开始给 R3 设的是“每次进入子区域 1.0 且不限制次数”结果它一回合能横跳几十次。后来我把 R3 改成“每个子区域只能触发一次”并在代码里用 set 记录已触发过的子区域编号这个漏洞就堵上了。第二次是刷覆盖率增量。R2 的覆盖率增量奖励本意是鼓励覆盖率持续上升但机器人发现通过反复小幅度移动可以让栅格地图边缘的传感器噪声把某些已覆盖栅格判定为“新覆盖”从而反复获得 R2。我加了两个限制一是覆盖率增量需要连续 N 步为正才给奖励二是对“新增栅格数”做一个绝对下限新增太少就不算有效增量。这两个限制一起用策略就不再去抠传感器噪声了。第三次是刷效率奖励。R5 的条件是“单位距离新覆盖面积大于阈值”机器人学到的方法是高速冲进一片开阔空区一口气扫很多新格然后立刻停下因为这个条件只看单步的比例。后来我把 R5 改成了“滑动窗口平均”取最近 20 步的新覆盖总面积除以总行驶距离超过阈值才给奖励。这个修改让机器人没办法用单步冲量来骗奖励必须持续保持合理的扫动节奏。这三件事让我养成一个习惯每次新增一个奖励项先只开这一项盯着该项的累计曲线跑 10 万步确认没有漏洞后再和其他项合并。奖励工程一半的功夫在防钻空子上这句话一点不夸张。7. 778 分之后奖励工程的边界与下一步778 分并不是一个“刷分”的结果它对应的是当前环境、当前地图布局下覆盖率接近 95%、碰撞接近零、时间惩罚也很低的稳定状态。我试过把 R1 权重继续往上加到 0.5分数没有明显变化反而因为过分强调覆盖率增量机器人开始在小角落来回磨蹭。这说明 778 分附近已经进入了奖励函数能压榨出的物理上限——在杂乱地图里覆盖率和路径效率本质上存在矛盾想 100% 覆盖必然要绕一些重复路想完全没有重复覆盖就不可能扫干净角落。要继续涨分不应该再继续调奖励权重了而是要换环境。我目前在做两件事第一对不同房间布局做域随机化让机器人在多样化的起点、障碍物位置和房间长宽比中训练提升泛化能力第二把奖励项本身也做随机化举个例子让 R1 的权重在训练过程中以很小的幅度抖动这样可以让策略不记忆某个固定的权重在更大的奖励空间里找到更鲁棒的策略。最后说一点个人体会。奖励工程是强化学习落地里最便宜也最危险的部分。它不需要大算力不需要复杂模型但每一个奖励项都是你作为人类先验塞进学习系统里的。先验塞得太少训练不收敛塞得太多策略过拟合。我在这个项目里学到的平衡方式是只把“清扫干净、避免重复、动作连贯、保持安全”这几条核心的人类常识编码进奖励剩下的路径规划、转向策略、避障方式全部交给算法自己去探索。10 项复合奖励只是我的答案你的机器人、你的任务、你的环境可能只需要 8 项也可能需要 15 项。真正值钱的是我搭起来的这套工作流——单因子标定、奖励预算控制、分阶段引入、分量日志监控。有了这套工作流任何一项奖励的增加或修改都可以被快速观察、快速验证、快速回滚这比纠结某一次的具体权重有用得多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑