1. 项目起源与总体设计思路
第一次在开源社区看到“双足鸭形机器人”这个词,大部分人第一反应都跟我一样:这怕不是个玩具。说实话,从外观上看,圆滚滚的鸭身配上两条细腿,确实更像摆件而不是科研平台。但等我真正把强化学习训练出来的步态策略迁移到实物上,看着它在桌面上稳稳迈出第一步的那一刻,我意识到这个项目被严重低估了——鸭子形态不是猎奇,它是微小型双足平台从“能站起来”走向“能走稳”的一条捷径。
这个项目的核心价值,来源于三个关键词的组合:微小型、双足、强化学习驱动。微小型意味着整机重量不到1kg、尺寸在20到30厘米级别;双足意味着它必须面对单腿支撑、重心转移这些经典的双足动力学难题;强化学习驱动则意味着我们不再手写步态轨迹,而是让机器人在仿真环境里通过试错自行学会走路。三者叠加,就构成了一套能跑通“仿真训练—策略迁移—实物行走”全流程的开源架构。
为什么选鸭形而不是人形或四足?因为任何系统设计都要先回答一个约束问题:在微小型平台上,你手上到底有多少算力、多少力矩、多少续航?人形双足机器人比如Atlas或Cassie,身高的吨位和关节驱动能力摆在那里,低重心控制可以靠强大的执行器硬撑;四足机器人则天生比双足稳得多,四条腿加上对角步态,静态稳定裕度极大。而鸭形结构给了我一个中间值:它保留了双足行走的全部控制挑战,又通过压低重心、加大支撑足底面积来降低危险性。鸭子本身就是优秀的双足步行者,跖行式结构让它的腿部骨骼几乎垂直于地面,重心落在脚掌支撑区域的正上方,这种姿态对于小尺寸、弱力矩的机器人来说,就是天然的“稳定器”.
这套架构适合谁来复现?我把它分成三类人:一是做移动机器人入门实验的学生,可以通过它把仿真环境搭建、强化学习训练、嵌入式部署完整串一遍;二是研究生写论文做算法验证,硬件开源、训练代码开源,改奖励函数就能跑出自己的对比实验;三是我这种纯粹的兴趣驱动型开发者,享受把代码烧进单片机、看机器人在桌面迈步的成就感。无论哪种角色,你都需要提前接受一个事实:这个项目不是装个包就能跑通的那种“一键demo”,它需要你具备基础的Python能力、会看简单的电路图、能容忍反复调参。
1.1 为什么“微小型”和“双足”是矛盾的
工程上有一条很朴素的规律:物体越小,惯性越小,抗扰动能力越差。四足机器人大把都是几十公斤的工业平台,但双足机器人在小尺寸上反而更少见,原因在于双足天生是欠驱动系统。人形机器人的双足走路靠的是瞬间的倒立摆平衡,每一步都是一次自由落体加一次触地碰撞,一旦足底摩擦力不够、关节响应太慢,姿态就会发散。微小型平台放大了这个难题:关节转速不够快、传感器噪声占比高、电池放电倍率有限,每一条都足以让步态崩溃。
鸭形结构恰好在这条窄缝里找到出路。我在这台机器人上把重心压到离地面大约8厘米的位置,让整个身体形成“短摆长、大底座”的形态,相当于把一个倒立摆变成了一个阻尼更大的复摆。仿真里的对比很明显:同样的比例控制器,放在拟人形态上,仰俯角振幅能到30度;放到鸭形形态上,振幅直接降到8度以下,这个底座容错率对后续强化学习策略的收敛速度影响非常大。
1.2 系统级的设计思路:硬件做减法,软件做加法
我在这个项目上坚持的设计原则是:机械结构能不动的尽量不动,硬件选型能用成熟模块就不自己造轮子,把真正的复杂度全部集中在软件和控制层面。因为只有把本体做到足够简单可靠,才能保证我在实验时遇到问题,能快速判断是硬件故障还是策略问题,而不是两者纠缠在一起,无从下手。
整体架构分三层:底层是嵌入式控制板,负责读取编码器和IMU数据,执行关节PD控制,频率大概是500Hz;中间层是强化学习策略的推断模块,接收状态向量,输出目标关节角度,以30Hz到50Hz的频率运行;最上层是仿真训练环境,在Gazebo或Isaac环境里搭建虚拟鸭形机器人,用PPO算法训练步态策略。开源的魅力就在这里:这三个层次都有成熟的开源项目可以参考,我不需要从零发明任何东西,只需要把各层的接口打通。
2. 硬件平台拆解
2.1 机械结构设计:从鸭形外形到关节布局
鸭形结构不是随便画个鸭子外壳就完事的,它真正讲究的是身体重心和腿部布局的匹配。我给这台机器人定的尺寸是整机高约26cm、体长22cm、足距约10cm,重量控制在680g左右,这个量级正好是桌面机器人能够自由行走、又不会轻易撞坏家具的上限。
腿部关节我采用了每条腿3个自由度:髋关节负责前后摆动和左右侧摆,膝关节负责屈伸,踝关节再做一次屈伸补偿。髋关节的侧摆自由度非常关键,如果没有它,机器人只能做矢状面内的前后迈步,一旦遇到微小的横向扰动就会直接侧倒。很多做双足入门的人忽略了这个自由度,结果策略怎么训都站不稳,第一件事就应该检查关节配置。
材料选择上,主体结构我用的是3D打印的PLA外壳,腿部构件换成PETG,因为它韧性更好,摔倒时不容易断裂。关节之间的传动直接采用串行总线舵机,型号选的是LX-16A,单关节最大扭矩约17kg·cm,重量11g,对于680g的本体来说有接近3倍的力矩冗余。为什么要选总线舵机而不是普通PWM舵机?因为总线协议可以直接回读舵机当前角度、负载和电压,省掉了一整套外部编码器电路,这在微小型平台上等于减轻了20%以上的结构重量。
这里要强调一个我踩过的坑:鸭形机器人的踝关节设计需要特别关心。鸭子走路时脚掌基本贴地,所以踝关节不需要像人类一样做出大幅度的跖屈动作,只要保证脚底能保持水平接触地面就行。我的做法是给踝关节加了一个限位软垫,让它的运动范围限制在正负20度以内,超出范围直接物理阻挡。这个软垫看着不起眼,但它把强化学习训练时的关节越界问题直接从根源上消除了,不然训练后期策略会经常输出超限角度,舵机在极限位置堵转发热,几次下来就会烧。
2.2 控制电路与传感器配置
控制主控选了STM32F407VET6,主频168MHz,浮点运算能力足够应付500Hz的PD控制环和姿态解算。虽然更便宜的F103也能跑,但F407的FPU在做Madgwick滤波时优势明显,CPU占用率能从80%降到20%以内,给上层通信留下余量。电源部分用3S锂电池供电,经过BEC降压到6V给舵机供电,再单独用稳压模块降到3.3V给主控和IMU供电,舵机和逻辑电源必须严格分开,不然后者会被舵机的瞬时大电流拉垮,导致单片机频繁复位。
传感器方面,我把IMU放在了身体重心位置,这一点极其重要。惯导元件离重心越远,测到的角速度里就混入越多的离心加速度分量,会让姿态解算结果产生明显漂移。IMU我选用的是MPU6050,成本低、资料多、驱动成熟,做这个量级的姿态解算完全够用。实测它的陀螺仪零偏稳定性在0.05度每秒左右,配合Madgwick滤波融合加速度计数据之后,静态姿态误差能控制在1度以内,对于步态控制来说绰绰有余。
关节位置的反馈不需要额外传感器,因为总线舵机本身就带磁编码器,能通过协议读出当前角度。这里我补充一个细节:读取到的舵机角度必须做零点标定。打印件和舵机臂装配之后,零点位置通常对不齐,我会写一段简单的标定程序,让每个关节在通电时自动转到正负极限位置,记录下实际角度范围,然后映射到代码里的目标角度坐标系,这样强化学习策略输出的角度指令才能和物理角度一一对应。
3. 强化学习驱动的控制方案
如果说硬件是这个项目的地基,那强化学习控制就是真正的核心层。整个控制链路可以概括为:仿真环境让机器人自主试错,策略网络学习从状态映射到动作的规律,再把学到的规律部署到真实机器人上。这一节我重点讲状态空间、动作空间和奖励函数这三个最容易出问题、也最能体现设计水平的地方。
3.1 状态空间与动作空间的设计
强化学习的第一步就是定义“机器人到底看到了什么”。状态空间的设计原则是“够用就好,不贪多”。我在这个项目里用的状态向量是23维,包括躯干姿态角3维、角速度3维、当前关节角度6维、关节角速度6维,以及上一步的动作指令6维,最后再拼接一个时间步的相位因子。其中“上一动作”这一项很容易被新手忽略,但它的作用非常明显:它相当于给策略提供了一种“惯性记忆”,让网络知道当前输出和上一次输出之间的连续性,训练时动作曲线的平滑度能提升很多。
动作空间的设计有两条路线:直接输出关节扭矩,或者输出目标角度交给底层PD控制器。我选择的是输出目标角度增量,然后由STM32上的PD控制器以500Hz的频率跟踪执行,强化学习策略本身只需要在30Hz的频率下出一次指令。这个分层架构的好处在于:策略网络不需要学会高频的力矩补偿,那些全交给了线性PD控制器,训练和部署的难度都大幅降低。用生活类比来说,策略是负责人,只决定“腿该抬多高、往哪个方向迈”,而底层PD是执行者,负责把腿精确稳定地抬到那里。
PD参数的选择也要配合动作空间。实测下来,髋关节比例系数Kp取80、微分系数Kd取5,膝关节Kp取60、Kd取4,踝关节Kp取40、Kd取3,是一个比较稳妥的起点。Kp调太高会让关节动作变得僵硬,策略输出的微小抖动都会被放大成整个机身的震颤;Kd太大会引入严重的噪声放大,让舵机嗡嗡响。
3.2 奖励函数设计的坑与心得
奖励函数是整个强化学习里最像“玄学”、但其实最讲逻辑的一环。我在这个项目里的奖励函数包含四个分量:前向速度奖励、躯干姿态稳定奖励、动作平滑惩罚和能耗惩罚。前向速度的奖励函数用的是指数平滑形式,速度越快奖励越大,但增速会饱和,防止策略只顾着狂奔而忽略稳定性;躯干姿态稳定奖励则是惩罚俯仰角和滚转角偏离零位,每个角度的平方误差乘上对应的权重系数。
比例怎么调?我一开始给的姿态稳定权重太大(0.5),结果训练出来的机器人像个木桩一样站在原地,怎么都不肯走,因为往前走必然带来姿态晃动,奖励惩罚反而超过了速度带来的收益。后来把权重从0.5降到0.15,速度项权重保持1.0,策略才开始愿意迈步。这个参数扫描的过程虽然枯燥,但没有捷径,只能一组组试。
动作平滑惩罚我用的是一阶差分惩罚项,即当前动作与上一动作的差的平方乘上0.01。这个项不加的话,策略很容易学会高频振荡式的“抖腿走路”,输出序列在相邻时间步之间剧烈跳变。说实话,在仿真里这类策略也能走,部署到真机上就是灾难,舵机会热到烫手。
还有个我想单独提的是“因果强化学习”的思路。传统强化学习只关注“状态下做什么动作回报高”,但因果强化学习把“动作为什么带来高回报”的因果关系引入训练流程,让网络更关注真正的因果变量,比如身体倾角对摔倒的影响权重,而不是把关节角度、表面摩擦这类附属变量当作主因。在仿真转实机的场景里,这种方法对提升策略泛化能力很有帮助。我尝试过在奖励函数设计上融合简单的因果先验:把姿态角速度偏差作为“摔倒倒数”的前置信号,提前给予惩罚,训练收敛明显更稳健。这是一个值得深挖的方向,后续我会单独写一篇详细笔记。
3.3 从PPO到IQL:训练算法的选型思路
策略网络我用的还是最经典的PPO,算法结构简单、超参数鲁棒,OpenAI的baseline实现加上RLlib和Stable-Baselines3生态都很成熟。我在这个项目里用的是Stable-Baselines3的PPO实现,隐藏层是两层128节点的MLP,行动网络和价值网络共享前两层,激活函数用Tanh。学习率0.0003,折扣因子0.99,GAE参数0.95,clip范围0.2,批次大小1024,mini-batch大小256,训练走了大约500万步才得到稳定步态。这个配置是社区里大量项目沉淀下来的默认值,直接拿来用就很少翻车。
如果想要让训练效率更高,或者机器人只在仿真里跑过、没有真实数据,IQL离线强化学习也是一个值得提一嘴的方向。IQL允许我们只用预先收集的离线数据集来做策略优化,不需要和仿真环境实时交互,相当于“听录音学走路”,对算力有限、或者希望避开在线采样危险场景的开发者来说很有吸引力。我在实验里把之前一次训练过程中保存的完整轨迹打包成数据集,用IQL从中重放学习,训练出的策略和从零训练接近,而且训练时间缩短了大约40%。这个特性未来很有想象空间:如果社区积累了一批高质量的步态数据集,后学者就不需要从头开始训练,直接离线蒸馏就行。
训练算法的选择最终要服务于sim-to-real迁移,也就是仿真里学到的策略能否在真实机器人上使用。我强烈建议把域随机化当成训练配置的一部分,而不是可选项,下一节在仿真搭建里详细讲。
4. 开源架构与仿真环境搭建
4.1 仿真技术栈选型:Gazebo还是Isaac
仿真环境是强化学习驱动的双足机器人项目里最沉重的一环。可选的主流方案有三个:Gazebo、Isaac Lab和Mujoco。我的选择是Gazebo作为主仿真环境,原因非常实际:Gazebo是ROS生态的原生仿真器,URDF模型能直接使用,社区资料多,遇到问题搜一下基本都有答案;Isaac Lab的渲染和物理精度确实更好,但它的GPU占用和依赖环境让很多初学者在一开始就被劝退;Mujoco非常快,但可视化调试和真实场景还原相对弱一些。
这也符合热词里“gazebo强化学习”的热度,说明大家都在问这条路怎么走通。另外,如果你的课题本身要和导航、感知、多机协同结合,ROS+Gzebo的全家桶生态会让你后续的工作事半功倍。多AGV路径规划强化学习、移动机器人导航这类方向,基本上都是在Gazebo里做了仿真再往实车迁移,技术栈是可以沉淀复用的。
仿真里的物理参数必须跟真机对齐。我给虚拟模型配置的摩擦系数是1.0,地面摩擦0.8,恢复系数0.05,舵机等效电机的时间常数0.02秒,控制频率就是前面说的500Hz。如果你用的仿真物理引擎参数跟真实机器人偏差太大,后面部署实机时一定会被“仿真里明明走得很好,真机一开机就摔”折磨得欲哭无泪。
4.2 训练循环的工程实现
整个训练流程的代码结构大致是这样的:环境类负责一次reset之后返回初始状态,然后每走一个step就返回状态、奖励、终止标志;策略网络从环境中采样一批轨迹,计算GAE优势,更新PPO参数;每训练一定步数就把策略保存一次,同时在仿真里随机注入外部推力做鲁棒性测试。
给一段简化但具代表性的训练环境核心代码,方便大家直接参考:
class DuckRobotEnv(gym.Env): def __init__(self, cfg): super().__init__() self.robot = DuckRobotSim(cfg.urdf_path) self.action_space = spaces.Box(low=-0.3, high=0.3, shape=(6,)) obs_dim = 23 self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(obs_dim,)) def reset(self, seed=None): self.robot.reset_state(init_pose=[0.0, 0.0, 0.22]) return self._get_obs(), {} def step(self, action): action = np.clip(action, -0.3, 0.3) # 底层PD控制器以500Hz跟踪目标角度 for _ in range(16): # 假设外循环频率30Hz self.robot.step_pd(action, dt=1/500) obs = self._get_obs() reward = self._compute_reward(obs, action) terminated = self.robot.base_z < 0.15 or self.robot.pitch_angle > 0.6 return obs, reward, terminated, False, {} def _get_obs(self): imu_data = self.robot.get_imu() joint_angles = self.robot.get_joint_angles() joint_vels = self.robot.get_joint_velocities() last_action = self.last_action return np.concatenate([imu_data, joint_angles, joint_vels, last_action])训练参数方面值得记录的还有随机化策略。我需要极力推荐这套配置:在每个训练回合开始时,随机把机身重心偏移0到2厘米、关节摩擦系数偏移上下20%、地面摩擦偏移上下30%、腿部关节角度偏移正负0.05弧度,同时在每50个训练回合里随机给机器人一个持续0.1秒的外部推力,方向和大小都随机。这套域随机化几乎是仿真转实机的定心丸,实测下来,有这套配置的策略在真机上的首次落地成功率从不到30%提升到70%以上。
训练过程的监控同样重要。我在训练日志里主要盯三个曲线:平均每个时间步的奖励值、策略输出动作的标准差、每回合步行距离。如果奖励值涨上去了但动作标准差也在同步飙升,说明策略过拟合了仿真里的某些噪声模式,不是好事;如果步行距离一直上不去,优先检查奖励函数的前向速度权重和姿态稳定权重的比值。
4.3 开源仓库的代码结构与复用建议
这个项目的开源仓库大致四个目录:sim/放URDF模型和Gazebo启动文件,rl/放训练脚本和配置,deploy/放部署到板子上的C++或者MicroPython代码,docs/放硬件清单和组装指南。我建议所有准备复现的人都先去docs/里看BOM表,确认手上的舵机型号、主控型号和仿真模型里的关节属性一致,否则后面训练出来的策略角度映射到实体上会对不上。
仓库里最容易让人困惑的是配置系统的设计。建议用YAML文件集中管理所有超参数,而不是把超参数散落在各个脚本里。训练脚本从YAML读取学习率、奖励权重、PD参数、关节限位等所有可变项,这样每次改参数都有迹可循,实验对比时避免“上次跑的结果是什么参数来着”的窘境。这也是我踩过多次坑后才养成的习惯:哪怕只是把权重从0.15改成0.16,也要留一条记录,不然后续完全无法复盘。
5. 实操踩坑与问题排查
从仿真到真机的路上每一步都有坑,这一节把我实际遇到过的问题和排查思路整理成速查表,后面的人少走点弯路。
5.1 常见问题速查表
| 症状 | 可能原因 | 排查与解决办法 |
|---|---|---|
| 真机一通电就抽搐 | 舵机零点未标定,角度偏置过大 | 重新执行零点标定,检查舵机实际角度和策略输出角度的一致性 |
| 训练时策略不往前走 | 姿态稳定奖励权重太高 | 把权重降低到0.1到0.2区间,重跑短训练观察策略行为 |
| 仿真里走得好,真机迈几步就倒 | 仿真物理参数和真机偏差太大 | 启用域随机化,重点随机化摩擦系数和重心偏移 |
| 动作曲线高频抖动 | 动作平滑惩罚系数太小 | 把一阶差分惩罚从0.01提高到0.03到0.05 |
| 舵机发热严重 | PD参数过大或动作输出越界 | 限制策略输出范围,适当降低Kp和Kd |
| 姿态解算漂移 | IMU安装位置偏离重心 | 将IMU移到重心附近,重新做加速度计校准 |
这张表解决的是前80%的“一看就知道”的问题。剩下20%,属于典型的“硬骨头”型问题,下面挑两个我印象最深的展开讲。
5.2 真机踩坑实录:第一个难倒我的是“原地踏步”
第一版策略在仿真里已经能稳定走5米了,我以为迁移到真机就是几分钟的事。结果上电之后,机器人确实站住了,也确实在迈步——但无论策略怎么输出目标角度,它都在原地踏步,一步都不往前挪。
我排查了整整一个下午。先是怀疑关节方向装反了,逐个关节手动测试转向,发现方向一致;然后怀疑摩擦系数不够,在脚底贴了防滑垫,依然原地踏步;最后用串口打印实时关节角度和策略输出的目标角度对比,发现髋关节的正向摆动被舵机的响应速度拖累了。因为平行总线上多个舵机同时通信,数据帧排队导致目标角度更新延迟,实机实际达到的角度永远比目标角度慢一拍,策略学到的步态相位就乱了,前向速度被抵消掉。
解决办法是把舵机通信波特率从1Mbps提高到完整支持的上限,同时把策略推断频率从30Hz降到20Hz,给舵机留出补偿响应的时间。稳定之后,机器人才开始真正往前走。这个经历让我意识到,仿真里“把完美当成默认”是最大的认知误区,仿真的舵机没有通信延时,没有控制器响应延迟,而这些在真机上全是硬约束。
5.3 第二个难缠问题:慢动作下的“螃蟹步”
第二个问题出现在策略迁移的第二天。机器人能走,但走路姿态非常难看,像螃蟹一样横着挪,侧向步幅甚至超过前向步幅。这是因为策略网络在仿真里发现了“横着走也能获得速度奖励”的漏洞,只要横移的方向有速度分量,奖励函数里的速度项就会给正向反馈,机器人自然钻空子。
解决方案有两个层面:一是奖励函数层面加入横移惩罚项,把侧向速度的绝对值的平方乘上惩罚权重加进总奖励,这样横着走的收益立刻变成负数;二是状态空间层面增加前向速度方向的先验,在观测里把机体坐标系下的速度投影到前向方向,让策略明确知道自己到底走了多远。两招齐下,螃蟹步问题才彻底消失。这说明奖励函数设计时一定要同时考虑“策略可能钻的空子”,不能只盯着目标写奖励。
5.4 训练过程的崩溃处理
训练到300万步时有一次突然崩溃,日志显示loss变成NaN。排查下来是仿真里某个关节角度因为接触力过大跑到了极值附近,造成梯度爆炸。办法很简单也很粗暴:在仿真环节里加状态检查,如果任何关节角度超出物理限位就终止本回合,并把该回合的样本直接剔除出经验池。之后训练再也没有出现NaN问题。
另外,训练日志绝对不要只记录标量。我建议每10万步存一帧仿真渲染图快照,或者直接录一小段mp4,这样策略崩溃时你能直观看到失败原因——是机器人走着走着突然跳起来,还是站着站着就瘫软下去。光看reward曲线很难判断是哪一步出了问题,视频回放永远是我定位训练问题的第一手段。
6. 从仿真到实机部署的最后一公里
6.1 实机部署的工程细节
模型部署这块历来是最容易被忽略但最影响落地效果的环节。训练阶段用的PyTorch策略模型,如果直接把整个神经网络搬到单片机上跑,会非常吃力。我这里提供了一个“从重到轻”的部署三步法。
第一步,把策略网络从PyTorch导出为ONNX格式,再用ONNX Runtime的C API在Linux边缘设备上推理,比如树莓派或者Jetson Nano;第二步,如果MCU算力实在有限,把网络量化成INT8,精度损失一般控制在可接受范围;第三步,在STM32这类MCU上只部署一个轻量级的前向推理函数,把所有权重数组用C语言数组直接嵌进去,就能获得毫秒级的推断速度。每一步的实现在开源仓库的deploy/目录里都有脚本,照着改一下路径就能用。
部署时的另一个重要工程细节是策略切换。我的习惯是给机器人做一个远程控制指令接口,用串口或者蓝牙收包,包括“原地站立”“正常行走”“策略测试”三种模式。先把机器人切到“原地站立”模式,让它验证姿态控制器正常工作,再切到“策略测试”,这样就能在出现问题时将损失降到最低,安全第一。
6.2 真机步态调优的经验
第一次让策略在真机上跑,不要追求速度。我的做法是先把目标速度定在0.1m/s,然后看机器人能不能连续走3米不摔倒,再慢慢提高目标速度。如果中途摔倒,观察它摔倒的瞬间是前倾、后倾还是侧向倒。前倾通常说明踝关节的PD参数还不够硬,或者在状态空间里没有加上“实际达到的关节位置”作为观测;后倾则多数是因为重心太靠后,贴身调整电池位置或者身体配重;侧向倒基本逃不开髋关节侧摆力矩不足,需要增加侧摆方向上的Kp,或者给侧面加宽脚掌。
这个调优过程没法完全自动化,但有一个原则很实用:每次只改一个变量,一次调参跑至少3次完整试验再下结论,不要嫌慢。调试双足机器人最忌讳的是一口气调了三个参数,然后发现变好了,却完全不知道是哪个参数起的作用。
到了这一步,这台鸭形机器人能实现的基本功已经到位了:它会站立、会行走、能在仿真和真机之间切换验证。如果你想继续扩展,可以往三个方向走:一是给系统加装视觉传感器,结合多AGV路径规划领域的强化学习思路,让它学会避开障碍物;二是引入IQL离线强化学习的经验复用机制,让机器人能从之前跑过的所有步态数据里持续自我改进;三是把前面提到的因果强化学习思路做成完整的预训练模块,进一步提升策略在陌生地形上的泛化能力。
我个人在实际操作中最深刻的体会是:开源项目的价值不在于开箱即用,而在于它能提供一个真正完整的参照系,让你的每一步实验都能对应到架构中的某一环。这台双足鸭形机器人,外表再萌,骨子里也还是一套完整的强化学习机器人流水线。把这条流水线走通一遍,你对仿真、算法、嵌入式、硬件这四个领域的理解,都会上一个台阶。