免费获取学习方案
ARTICLE DETAIL

资讯详情

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

强化学习机器人从GPU仿真到RK3566边缘部署全流程解析

强化学习机器人从GPU仿真到RK3566边缘部署全流程解析 1. 项目背景与整体方案为什么会有一台25厘米的强化学习机器人大概是在半年前我在整理仓库的时候翻出了一块吃灰很久的RK3566开发板。这块板子原本是打算做边缘计算网关用的后来项目砍了就一直躺在防静电袋里。同期我手头正好在跑一批基于英伟达GPU的强化学习仿真实验训练对象是一个25厘米高的小型双足机器人。当时的想法很直接仿真里已经跑得很稳的策略能不能搬到这块性能远不如GPU服务器的国产ARM板子上让它真正站起来、走起来这个问题的答案并不像想象中那么理所当然。强化学习训练和部署是两套完全不同的工程逻辑。训练阶段依赖GPU的大规模并行计算动辄几百万次环境交互而部署阶段尤其是嵌入式实机部署拼的是延迟控制、算力预算和系统稳定性。Microduck这个名字是当时给这台25厘米机器人起的内部代号——duck是因为它走路摇摇晃晃的样子像只小鸭子Micro则是对标那些动辄几十公斤的大型机器人强调它的小尺寸和低成本。整体技术方案其实很直白在英伟达GPU上用仿真环境训练强化学习策略训练完成后把策略网络导出部署到RK3566上运行推理通过机器人操作系统控制电机和传感器。但具体的坑从训练场景的仿真参数调整到模型量化后精度损失再到实机上各种传感器噪声每一步都踩了一遍。这篇文章把我从GPU到RK3566的全过程记录下来希望能给正在做类似“仿真训练、边缘部署”项目的朋友省点时间。先说结论这套方案完全可行。在RK3566上用INT8量化后的模型做推理单帧控制延迟可以压到10毫秒以内完全满足25厘米级机器人的实时控制需求。但这个过程需要处理好几个关键问题比如训练与部署的算力差异、模型压缩带来的精度损失、实机部署时的资源争抢。下面按我实际操作的顺序把整个流程拆开讲。2. 环境准备与硬件选型训练端和部署端各需要什么2.1 英伟达侧的模拟训练环境搭建训练端我用的是一台双卡英伟达GPU服务器具体型号是RTX 4090。强化学习训练不像大模型训练那样需要极高的显存带宽但需要大量的环境交互采样所以CPU核心数和内存频率的影响反而比GPU更大。我当时在仿真环境里跑了并行采样如果CPU核心数不够GPU利用率会很低训练速度会被严重拖慢。仿真环境选的是MuJoCo这是目前强化学习机器人领域最常用的物理仿真器之一。它的一大优势是支持在训练过程中进行高度并行的环境采样配合RL的PPO算法可以在较短时间内在桌面级GPU上完成训练。我在项目里用的是PPO因为它在连续控制任务中表现稳定调参相对容易而且对超参数的敏感度没有SAC那么高。训练环境里还有一个关键点就是观测空间和动作空间的设计这个我在后面“训练细节”部分会详细展开。MuJoCo的安装和使用本身不复杂但有两个容易踩的坑MuJoCo的许可证模式和版本兼容性新版本用的是Apache 2.0开源协议但部分老版本的代码接口不兼容初学者容易在版本上翻车。渲染模式对Python环境的依赖如果用的是新版本MuJoCo渲染需要OpenGL相关的库服务器上如果没有图形界面要安装EGL相关的虚拟显示支持否则没法离线渲染视频查看训练效果。2.2 RK3566侧的系统与基础依赖RK3566是一颗四核Cortex-A55处理器主频最高2.0GHz还带了一颗0.8TOPS算力的NPU。说实话这个算力跑大模型肯定不行但跑一个几MB的强化学习策略网络完全够用。它还有很强的IO扩展能力带了不少UART、I2C、SPI接口这对机器人控制来说非常友好。部署端的系统我选了Ubuntu 22.04内核版本5.10这是RK3566常用的系统配置。如果你用的是其他开发板比如香橙派、微雪或者其他RK3566板卡系统镜像可能略有差异但部署流程基本一致。系统装好后有几个基础依赖需要提前装好sudo apt update sudo apt install -y python3-pip python3-venv git cmake sudo apt install -y robotframework-os # 这个是内部封装的机器人基础库实际项目可用其他替代Python环境我建议用虚拟环境隔离配合systemd服务管理开机自启避免污染系统Python环境。RK3566的存储一般是eMMC8GB到64GB不等如果你的板子空间紧张建议把虚拟环境和模型文件放在外部存储上比如SD卡或USB存储。2.3 通信链路与开发调试方式RK3566通常只有一个千兆网口我调试时主要用SSH连接。这里有个实用技巧直接用网线连接开发板和路由器配置静态IP再配合VS Code的Remote SSH插件远程开发体验和本地开发几乎一样。为了避免USB串口和网口冲突建议把系统日志输出配置到串口方便在系统崩溃看不到网络时仍然能拿到内核日志。还有一个容易被忽略的点RK3566的供电设计。开发板的电源输入一般是12V或5V DC但机器人上的电机、舵机、传感器如果直接从开发板取电很容易造成电压跌落导致系统掉电重启。我踩过这个坑后面在“电源与发热”部分单独讲。强烈建议给电机和主控分开供电主控用单独的稳压模块电机用电池直驱共地即可。3. 训练阶段的细节从仿真到策略收敛GPU算力怎么花在刀刃上3.1 观测空间、动作空间与奖励函数的设计强化学习策略网络的效果很大程度上取决于观测空间和动作空间的设计。Microduck是一个25厘米高的小型双足机器人每条腿有3个自由度髋关节、膝关节、踝关节左右对称共6个电机。观测空间由这几部分组成机体姿态IMU提供的俯仰角、横滚角、偏航角9维包含四元数或欧拉角的转换结果关节角度6个电机各自的绝对角度6维关节角速度6个电机的角速度6维上一时刻的动作输出6维目标速度指令2维前进速度和转向速度加起来一共29维观测空间。动作空间则是6个电机的目标位置增量范围控制在[-0.4, 0.4]弧度之间这样可以避免策略在初期输出超大动作导致仿真发散。奖励函数我采用了“稀疏奖励 形状奖励”的混合设计。稀疏奖励是当机器人摔倒时给一个大的负奖励-10当机器人走完一段距离时给正奖励1形状奖励则是让机器人尽量保持直立姿态俯仰角、横滚角接近0时给正奖励同时尽量降低关节力矩的平方和避免策略学到高频抖动的控制策略。这里有个实际经验奖励函数的权重不能拍脑袋设比例需要根据训练效果调整。我一开始把姿态奖励设得过高导致策略网络学会了“僵硬站立”而不愿意前进——因为站着不动奖励也高。这个就是典型的奖励黑客问题策略找到了奖励函数设计上的漏洞。3.2 仿真到现实的差距怎么补仿真环境再逼真和真实物理世界之间总有差异。这些差异主要来自电机动力学模型的简化仿真里力矩响应是瞬时的实机有延迟和饱和摩擦力模型不准仿真里摩擦系数是固定的实机地面材质和温度都会影响传感器噪声模型仿真里的IMU数据是干净的实机有漂移和高频噪声我认为最有效的方法不是追求仿真绝对精确而是把策略训练得足够鲁棒。具体操作有两条路线域随机化在仿真环境中给每个物理参数加上随机扰动让策略在参数不确定的情况下仍然表现稳定。我在项目里对电机力矩、摩擦系数、质心位置、IMU噪声都加了随机范围幅度从5%到20%不等。这样训练出来的策略在实机上往往不需要任何微调就能直接部署。在训练过程中加入延迟和噪声的模拟实机上从传感器读取到执行指令必然存在延迟我在训练环境中人为加入了10-20毫秒的执行延迟和对观测空间的噪声让策略学会在“不完美信息”下做决策。这两条路线组合使用的效果非常好。训练完成后策略在仿真中的成功率不摔倒且能走完目标距离大概在95%左右。直接搬到实机上第一次就能站起来当然走几步还是会摇晃但比我想象的强太多。3.3 训练配置和收敛策略训练的超参数我按通用PPO配置设置但有两个参数值得单独拿出来说num_envs并行环境数在4090上我设成4096这个值需要根据显存和CPU核心数调优太高会导致CPU成为瓶颈太低则GPU利用率上不去。实测4096-8192是一个比较合理的区间超过这个值时训练速度提升有限。clip_rangePPO裁剪范围默认0.2对于小规模任务可以适当放宽到0.3让策略每轮更新幅度更大收敛更快。但放太宽会导致策略不稳定需要警惕策略崩溃的情况。训练时我建议开启随机种子固定和周期性模型保存。随机种子固定方便复现周期性保存可以避免训练后期策略突然崩溃这种情况在强化学习里还挺常见的导致白训。我每500万步保存一次checkpoint保留最近的5份模型这样即使后期训练出问题也能回退到表现最好的模型继续调试。还有一个值得注意的坑训练过程中GPU利用率并不总是100%。如果发现GPU利用率低大概率是CPU采样的速度跟不上。解决方法是看环境交互的并行度设置以及Python的多进程环境数量。我当时加了torch.set_num_threads(1)来减少CPU争抢并对环境采样进程做了CPU亲和性绑定训练速度直接提升了接近一倍。4. 实机部署的关键工程问题模型裁剪、推理延迟与系统资源分配4.1 模型导出与量化压缩训练阶段用的模型是PyTorch格式参数规模大概在几万级别FP32精度下也只有几十MB的参数量。部署在RK3566上完全没问题但为了让推理延迟更低、占用内存更少我还是做了模型压缩和量化。量化选的是INT8量化把权重和激活值从FP32压缩到INT8。这里有个概念要厘清RK3566的NPU对INT8的支持最好CPU也可以跑INT8但加速效果有限。由于我的策略网络结构简单两层MLP每层256个神经元模型参数总量很小我干脆在CPU上直接跑FP32推理延迟已经能控制在2毫秒以内。但为了给图像处理或将来扩展功能留余量我还是加了NPU推理的版本用了RKNN-Toolkit2做转换。模型导出的流程在训练环境中把PyTorch模型导出为ONNX格式。用RKNN-Toolkit2的Python接口加载ONNX模型设置量化数据集一般用训练时的观测数据采样几百条就行配置目标平台为rk3566。转换后生成RKNN格式的模型文件部署到板子上用rknn的Python接口或C接口加载推理。这里有个坑ONNX导出时如果不固定输入输出维度RKNN转换时可能报错。要把动态轴固定成静态输入形状。比如我的观测空间是29维就在导出时把输入形状固定为(1, 29)。还有一个更隐蔽的坑RKNN-Toolkit2的版本要和板子上的NPU驱动版本匹配。我最初用的工具链版本太新生成的模型在旧驱动上加载失败报了一串看不懂的NPU错误。后来查文档才发现需要在生成模型时指定对应的平台版本或者在板子上更新NPU驱动两者保持一致。4.2 决策与控制频率分配这一步最容易被忽略机器人控制系统中频率分配是决定稳定性的关键。我最初设计时把推理频率、IMU读取频率、电机控制频率都设在100Hz结果实机上发现IMU读取偶尔会丢数据电机控制偶尔也会产生抖动。分析后发现CPU在100Hz的周期内要同时完成IMU数据读取、姿态解算、策略推理、电机控制指令下发四个任务但每个任务耗时不等有些任务在某个周期内会超过10毫秒造成任务堆积和延迟抖动。解决办法是把不同任务放在不同的频率等级IMU读取和姿态解算200Hz因为这个环节是控制环路的输入频率越高延迟越小。策略推理50Hz强化学习策略不需要像传统控制那样高频运行50Hz足够保证动作的平滑性。电机控制指令下发100Hz和电机驱动器的通信频率对齐。这样分配后CPU的负载被平摊到不同的时间片不再出现单个周期内任务堆积的情况。给个实测数据均匀负载分配后单帧最大延迟从原来的18毫秒降到了9毫秒。4.3 RK3566上的系统资源分配与实时性优化RK3566虽然有4个Cortex-A55核心但部署了Ubuntu之后系统后台任务蓝牙、Wi-Fi、桌面服务等会抢占CPU导致推理和控制任务无法保证实时性。我的优化方案关闭不需要的后台服务比如蓝牙、Wi-Fi的自动连接、系统的自动更新。用systemctl逐个检查并禁用不必要的服务。把推理和控制任务绑定到专用CPU核心上。用taskset命令把Python或C进程绑定到CPU核心2和核心3让核心0和核心1处理系统中断和其他杂务。提升控制进程的调度优先级。用chrt -f 80把控制进程设置为SCHED_FIFO实时调度策略优先级80。这样即使系统负载高控制进程也能优先获得CPU时间片。这些操作看起来简单但对系统的稳定性提升非常明显。我测试过不绑核的情况在Wi-Fi重连或后台有编译任务时控制延迟会飙升到100毫秒以上机器人直接摔倒。绑核加优先级调整之后最差情况下的延迟也能稳定在15毫秒以内。注意使用实时调度策略时需要小心如果控制进程陷入死循环系统会卡死因为没有任何其他进程可以抢占它。建议在代码里加看门狗比如控制循环每200毫秒必须输出一个心跳包否则系统自动重启控制进程。5. 实机调试与踩坑记录从站不起来到稳定行走的完整链路5.1 第一次上电连站都站不起来第一次把训练好的模型部署到Microduck上我满怀期待地通电结果机器人根本站不起来刚通电几秒就向左侧歪倒。当时第一反应是模型压缩出了问题模型精度损失导致控制策略失效。排查过程是这样的先在板子上用CPU推理FP32模型确认模型本身没问题——结果还是站不起来。那我怀疑是观测数据的问题。用Python脚本打印实机IMU数据和仿真环境的数值对比发现IMU数据范围差异不大但噪声比仿真大得多。但噪声大不至于站都站不起来。我继续查发现电机角度反馈的读取逻辑有bug——我读的是电机编码器的绝对位置但代码里处理成了相对位置的增量导致关节角度的观测数据是错的。这个bug修完之后机器人能站住了但站起来后双腿不停地小幅度抖动像在颤抖。这个抖动根源在于控制频率和策略频率不同步策略输出是50Hz电机控制是100Hz在两次策略输出之间电机控制模块使用的是同一个目标动作但每次控制时都做一次位置闭环相当于在50Hz的参考信号上叠加了一个100Hz的跟踪控制如果增益设置不当就会产生高频抖动。解决办法是把策略输出值直接当作电机的位置指令在相邻两次策略输出之间做线性插值让指令平滑变化。5.2 仿真到现实的转移差异为什么域随机化救了我当机器人能站立并开始走路后行走姿态和仿真里差异还是很大。仿真里策略学到的是大步流星的姿势实机上则是小碎步而且走两步就重心偏移。这个问题的本质是仿真和实机之间仍然存在未建模的差异。我逐个排查了质心位置机器人装配时电池位置靠后质心比仿真模型偏后约1厘米。修正方式是在仿真模型里调整质心位置参数。地面摩擦室内瓷砖地面摩擦系数低于仿真里的默认值导致脚步打滑。我在仿真里对摩擦系数加了更宽的随机范围0.3到1.2。电机响应延迟实机的电机响应有明显的纯延迟大约10毫秒。这个延迟会导致策略根据当前状态做的决策滞后于实际状态。域随机化的价值就在于即使无法精确建模所有差异只要把随机范围设置得足够宽策略就会学到对参数变化不敏感的鲁棒控制策略。修改这些之后重新训练再上实机行走姿态明显改善了很多。5.3 电源系统的坑掉电重启与电压跌落这个问题是最折腾人的。机器人运行几分钟后RK3566就会随机重启。一开始以为是过热改了散热片加了风扇问题依旧。后来查看内核日志发现重启前有电压骤降的记录才意识到是供电不稳。电源设计缺陷在于我给电机和主控用的是同一路12V电源电机启动瞬间的电流峰值能到3A以上导致12V电压跌落到9V以下而RK3566开发板的电源模块对输入电压范围有要求通常12V±10%电压过低就会触发欠压保护重启。解决方案电机和主控完全分开供电电机用独立的12V电池或稳压电源。主控端加一个宽压输入的DC-DC稳压模块比如12V转5V的降压模块同时加大输入端的电容器用一个大容量的电解电容吸收瞬态压降。在软件层面给控制系统加一个低压监测检测到电压低于阈值时先停电机再保护关机而不是直接硬重启。这一套弄完之后掉电重启的问题彻底解决。极端的压降场景下比如两个电机同时过载系统也能优雅降级先保护数据再关机。5.4 日志与离线回放调试的第三只眼实机调试有一个很痛苦的地方机器人运行中的状态数据瞬息万变只靠肉眼观察很难定位问题。所以我写了一套轻量的日志系统把IMU数据、关节角度、策略输出、控制指令全部记录到本地文件系统中。这里有个很关键的工程细节日志采样频率要与传感器采样频率对齐否则分析时会发现数据对不上。我最后用时间戳做索引每一条日志都记录系统时间微秒精度后续分析时按时间戳对齐。收集到日志后我用Python写了一个离线回放工具把传感器数据和控制指令回放到仿真环境里观察策略在“实机数据”上会输出什么样的动作再对比实际日志里的动作输出就能判断控制指令是否被正确执行。这个方法在很多复杂问题上都帮了大忙比如上面提到的电机角度bug就是靠回放发现观测数据不符的。6. 部署到实机后的优化与最终效果评估6.1 推理延迟与整体控制环路的最终数据经过上面这一轮优化Microduck在RK3566上的最终性能指标是这样的指标数值说明策略模型大小18KBINT8量化后原始FP32大约70KB但INT8更适合NPUCPU单帧推理延迟1.2毫秒FP32精度下CPU推理NPU单帧推理延迟0.6毫秒INT8量化后NPU推理单帧控制总延迟8.5毫秒含IMU读取、解算、推理、电机指令下发最大运行时间连续2小时以上电池供电状态无重启站立成功率100%50次测试在平整地面上行走成功率92%连续5米距离有轻微干扰时会失衡但基本能恢复这个数据放到真实产品里不算优秀但作为一套从零开始搭建的仿真到部署全链路效果已经超过了我的预期。6.2 后续可以扩展的方向部署流程跑通后这个方案的可扩展性其实很高。我这里列三个我实际思考过的扩展方向多策略切换RK3566的存储空间可以放多个不同任务的策略模型比如走路、转身、爬坡、跌倒恢复运行时根据场景动态切换。代价是切换时的观测状态保持问题需要在模型结构上做一些共享抽取处理这个我还在实验。边缘端在线学习实机采集的数据回传服务器在GPU上周期性微调策略再更新到RK3566上。这就是一个简单版本的持续学习闭环对策略探索新环境、新地形会有明显帮助。更轻量的传感器融合目前用的是IMU加关节角度如果加上脚底压力传感器可以进一步提高步态的稳定性。RK3566有足够的ADC接口扩展成本很低。7. 总结与个人经验体会从英伟达GPU到RK3566从仿真训练到实机部署这个项目让我对强化学习在机器人领域的落地有了更清晰的认知。最深的体会是强化学习的核心门槛不在算法而在工程。算法本身是相对标准化的工具PPO、SAC这些成熟算法拿来就能用但要把策略模型部署到真实机器人上并保证长期稳定运行需要考虑的因素非常多。几个我认为最重要的经验仿真环境的域随机化要尽早做随机范围宁大勿小这比追求仿真精度更有价值。模型量化和推理优化要做但不要过度优化先跑通全链路再回头抠性能。日志系统一定要从一开始就建立很多问题在实机上肉眼根本看不出来。电源设计是机器人的生命线供电不稳会让所有上层工作白费。写到这里回头再看这个项目25厘米的Microduck不算大RK3566也不算高性能但它完整串起了现代机器人开发中“仿真训练边缘部署”这条最核心的链路。如果这套流程对你在做的项目有一点点参考价值这篇文章就没有白写。
返回列表