type
Post
status
Published
date
Jan 21, 2026
slug
summary
tags
isaaclab
robotics
仿真
category
技术
icon
password
文本

基础结构

环境注册

  • 文件:config/anymal_c/__init__.py
  • 理解:环境如何注册到 Gymnasium
 

环境配置

  • 文件:config/anymal_c/navigation_env_cfg.py
  • 理解:各个配置类的作用(Actions, Observations, Rewards, Commands, Terminations)
配置类 (Configuration Class)
作用 (Function)
关键点 (Key Points)
ActionsCfg
定义 RL Agent 可输出的动作空间及执行方式。
1. pre_trained_policy_action: 采用分层控制,动作不是直接驱动电机,而是作为信号输入给预训练的低级行走策略。 2. low_level_decimation=4: 高级策略频率较低,每 4 个物理步决策一次。
ObservationsCfg
定义策略网络(Agent)的输入状态信息(State)。
1. pose_command核心输入,告知 Agent 当前的目标位置和方向。2. base_lin_vel & projected_gravity: 感知自身速度与姿态(平衡状态)。
RewardsCfg
定义奖励函数,指导 Agent 学习“好”的行为。
1. position_tracking: 正向奖励,距离目标越近得分越高(使用 tanh 平滑)。2. orientation_tracking: 负向奖励(惩罚),约束机器人朝向目标。 3. termination_penalty重罚 (-400),机器人摔倒或非法接触时给予巨大惩罚。
CommandsCfg
负责生成任务目标(Goal),如位置和航向。
1. UniformPose2dCommandCfg: 在 2D 平面上随机生成目标点。范围: 3m x 3m 区域内随机。 2. resampling_time_range=(8.0, 8.0): 每 8 秒重置一次新目标,训练连续适应能力。
TerminationsCfg
定义 Episode(一局游戏)何时结束。
1. base_contact失败判定,检测基座(躯干)是否触地,触地即视为摔倒/失败。 2. time_out: 超时强制结束。
EventCfg
定义环境重置(Reset)时的状态初始化和随机化。
1. reset_base: 虽然名为 reset,实际上包含域随机化。每次重置时,机器人的初始位置和朝向在小范围内随机扰动,防止过拟合。

预训练策略动作

  • 文件:`mdp/pre_trained_policy_action.py
  • 理解:层次化控制的实现原理

1. PreTrainedPolicyActionCfg (配置类)

这个类定义了构建层次化动作所需的参数,是静态配置。
参数
解释
asset_name
要控制的机器人实体名称。
policy_path
低级策略模型路径 (.pt 文件)。这是预先训练好、会走路的大脑。
low_level_decimation
频率倍数。例如=4,意味着高级策略每思考1次,低级策略要执行4次动作。
low_level_actions
低级策略原本的动作配置(如关节位置控制)。
low_level_observations
低级策略需要的输入(Obs)配置。

2.PreTrainedPolicyAction

1. 初始化 (__init__) 作用:初始化动作项,加载神经网络模型,并建立观测数据的“重定向”机制。
  • 加载模型:载入 .pt 预训练网络。
  • 重映射输入:通过 lambda 将低级策略的观测(动作历史、速度指令)强制指向当前类缓存的变量,实现接管控制。
  • 初始化管理器:创建专属的动作与观测管理器。
 
2. 接收指令 (process_actions)
作用接收高级指令。每当高级策略决策一次(比如每 0.1秒),这个函数被调用一次。
  • 缓存:接收高级策略输出的 Tensor(速度指令),存入 _raw_actions 备用。
3. 执行控制 (apply_actions) 作用执行控制循环。在每一个物理仿真步(Simulation Step,比如每 0.005秒)都会被调用
  • 降频:通过 counter 实现频率分频(Decimation)。
  • 推理:达到触发频率时,使用新指令计算观测 -> 喂给 Policy 网络 -> 得到关节目标。
  • 驱动:调用底层 _low_level_action_term 应用关节控制信号。
4. 属性访问 (Properties)
action_dim(self) -> int
作用:定义暴露给高级策略的动作维度。
  • 实现方式:返回 3。因为对于高级策略来说,它只需要输出 [vx, vy, yaw_rate] (X轴速度, Y轴速度, 偏航角速度) 这三个数,而不需要关心机器人的 12 个关节具体怎么动。
raw_actions(self) & processed_actions(self)
作用:提供对当前存储的高级指令的访问接口。
  • 实现方式:直接返回内部存储的 Tensor self._raw_actions
5. 调试与可视化 (Debug Visualization)
这部分用于在仿真画面中画出箭头,帮助开发者判断指令是否被执行。
_set_debug_vis_impl(self, debug_vis: bool)
作用:开启或关闭可视化工具。
  • 实现方式
    • 实例化 VisualizationMarkers 类。
    • 创建两个可视化器:
      • 绿色箭头 (Goal):代表高级策略想要的速度(velocity_goal)。
      • 蓝色箭头 (Current):代表机器人当前的实际速度(velocity_current)。
_debug_vis_callback(self, event)
作用:每一帧更新箭头的状态。
  • 实现方式
      1. 获取机器人当前的基座位置 root_pos_w
      1. 调用 _resolve_xy_velocity_to_arrow 将二维速度变为箭头的旋转和缩放。
          • 高级指令 -> 绿色箭头。
          • 实际速度 -> 蓝色箭头。
      1. 调用 visualize 在 3D 场景中绘制。
      1. 目的:如果绿箭头和蓝箭头重合度高,说明低级策略执行能力强;如果绿箭头指东,蓝箭头往西,说明控制失效。
_resolve_xy_velocity_to_arrow(self, xy_velocity: torch.Tensor)
作用:辅助函数,将 2D 速度向量 (vx, vy) 转换为 3D 箭头的 缩放比例 (Scale) 和 旋转四元数 (Quaternion)
  • 实现方式
    • 长度:速度越大,箭头拉伸得越长 (norm * 3.0)。
    • 方向:使用 atan2(vy, vx) 算出角度,转为四元数,并叠加上机器人当前的基座朝向(因为通常指令是在机身坐标系下发出的,需要转
到世界坐标系显示)。

奖励函数

  • 文件:`mdp/rewards.py`
  • 理解:如何计算位置和朝向跟踪奖励

1. 步态诱导类 (Gait Shaping)

这些奖励函数旨在“教会”机器人怎么走步子。如果没有它们,机器人可能只会像溜冰一样在地板上滑行,因为那样也是一种移动方式。
feet_air_time (重要)
  • 作用腾空时间奖励。鼓励机器人在每一步中把脚抬起来并在空中停留足够长的时间。
  • 实现逻辑
      1. 检测此帧每一个脚是否刚落地 (first_contact)。
      1. 如果是刚落地,就回看这只脚在空中呆了多久 (last_air_time)。
      1. 如果呆的时间超过了阈值 (threshold),就给分。呆得越久分越高。
      1. 关键条件:如果目前的速度指令很小(command < 0.1,即让它站着不动),这分就不给了。防止机器人原地踏步骗分。
  • 目的:这是训练出**Trot(小跑)**步态的关键。
feet_air_time_positive_biped
  • 作用双足腾空时间奖励。这是给双足机器人(如 H1, Casssie)专用的。
  • 实现逻辑
      1. 检查有多少只脚着地 (single_stance)。
      1. 对于双足机器人,理想的步态是单脚支撑相(一次只有一只脚着地)。
      1. 如果是单脚支撑,就根据支撑时间或腾空时间给予奖励,但设置了上限 (threshold)。
  • 目的:强迫双足机器人交替迈步,而不是双脚跳(Hopping)。
feet_slide
  • 作用脚底打滑惩罚
  • 实现逻辑
      1. 检测脚是否触地 (contacts)。
      1. 检测脚底是否有水平速度 (body_vel)。
      1. 如果脚触地了,但速度不为0(说明在滑),就根据速度大小进行惩罚。
  • 目的:消除“溜冰鞋”效应(Ice-skating),增加仿真的真实感,确保机器人是靠摩擦力在走。

2. 速度追踪变体 (Tracking Variants)

这些是核心库中 tracking 函数的改良版,处理坐标系转换。
track_lin_vel_xy_yaw_frame_exp
  • 作用航向坐标系下的速度追踪
  • 背景:机器人的根节点坐标系(Base Frame)会随着身体抖动(Roll/Pitch)而倾斜。直接用 Base Frame 测速有时不准。
  • 实现逻辑
    • 构造一个虚拟的“航向坐标系”(Yaw-aligned Frame):Z 轴永远垂直向上(重力反方向),只保留机器人的 Yaw 旋转。
    • 把世界坐标系下的速度投影到这个虚拟坐标系中。
    • 计算与指令的误差并指数奖励。
  • 目的:让速度追踪不受身体侧倾或俯仰的影响,更加鲁棒。
track_ang_vel_z_world_exp
  • 作用世界坐标系下的角速度追踪
  • 实现逻辑:直接对比世界坐标系下的角速度 Z 分量与指令。
  • 通常用途:大多数时候用机身坐标系更好,但在某些特殊构型或某些特定的任务定义下,使用世界坐标系可能更直观。

3. 静止约束 (Stillness Constraint)

stand_still_joint_deviation_l1
  • 作用静止时的姿态惩罚
  • 实现逻辑
      1. 检查当前的指令是否接近 0(command < threshold)。
      1. 如果是(此时应该站着不动),就惩罚关节偏离默认位置的程度 (joint_deviation_l1)。
  • 目的
    • 当没有速度指令时,机器人应该乖乖且优雅地站好。
    • 防止机器人在待机时出现奇怪的扭曲姿势或不必要的动作。
    • 相当于对 joint_deviation_l1 加了一个“仅在低速时生效”的开关。

低层环境配置

  • 文件:`locomotion/velocity/config/anymal_c/flat_env_cfg.py`
  • 理解:低层策略需要什么观测和动作
观测
关节位置 (Pos)、关节速度 (Vel)、基座姿态 (Projected Gravity)、基座速度 (Lin/Ang Vel)。
动作Joint Position Control:输出 12 个关节的目标角度。这是最底层的驱动信号。
 

深入理解

研究低层策略

查看低层策略的输入输出

1. 动作输出 (Actions)
代码位于 velocity_env_cfg.py 的 ActionsCfg 类中:
  • 输出内容: 12 个关节的目标位置(关节角度)。
  • 控制方式: PD 控制(位置控制)。
2. 观测输入 (Observations)
代码位于 velocity_env_cfg.py 的 ObservationsCfg.PolicyCfg 类中:

理解为什么需要 low_level_decimation

low_level_decimation 实际上是用更少的大脑(RL)计算换取更稳定的物理表现和更高效的训练
1. 时间尺度的本质差异
  • 控制层 (Low Level): 需要极高的频率(例如 200Hz - 1000Hz)来保证物理仿真的稳定性和电机控制的平滑性。如果控制频率太低,机器人会抖动、不稳定甚至飞出物理世界。
  • 决策层 (High Level): 往往只需要较低的频率(例如 10Hz - 50Hz)。人类决定“往左转”可能只需要 0.5 秒思考一次,并不需要每毫秒都重新决定一次“往左转”。
2. 为什么不让决策层也跑 200Hz?
如果强行让 RL 策略和物理仿真跑得一样快(Decimation = 1),会有以下坏处:
  • 训练极其困难 (Sample Inefficiency):
    • 如果策略是 200Hz,那么做 1 秒钟的动作需要 200 步决策。
    • 强化学习算法(如 PPO)很难关联第 1 步的动作和第 200 步后的奖励(Credit Assignment Problem)。"远水救不了近火",步数越多,奖励传递越难。
  • 计算浪费:
    • 大部分时候,相邻两毫秒的决策(Status)几乎是一模一样的。让神经网络重复计算几乎相同的输入输出,是对算力的巨大浪费。
  • 动作抖动:
    • 高频决策容易导致策略输出高频噪声。通过降频(Hold Action),相当于天然加了一个“零阶保持器”(Zero-Order Hold),让动作更连贯平滑。

修改奖励函数

navigation_env_cfg.py
  • 尝试不同的奖励权重
  • 理解奖励函数对训练的影响
notion image

修改命令生成

navigation_env_cfg.py
  • 改变目标位置范围
  • 修改命令重采样时间
notion image

周报内容

为什么需要层次化控制?

层次化控制(Hierarchical Control)就像是一个军队的指挥体系
  1. 分而治之,降低复杂度
      • 高层(指挥官/Agent):只关心战术目标(“向北走 5 米”),不用管具体的腿怎么迈。这减少了它的搜索空间,训练起来更快。
      • 低层(士兵/Locomotion Controller):只关心怎么稳稳地迈步子(保持平衡、不摔倒)。它不用知道要去哪,只需要把“走”这件事做好。
  1. 复用性(Reusability)
      • 会走的腿(低层策略)一旦练好了,可以被拿去教它“巡逻”、“踢球”、“甚至搬运”。如果用端到端(End-to-End)的方法,每换一个任务可能就要重新学一遍怎么走路。
  1. Sim-to-Real 的稳定性
      • 低层策略通常经过了大量的物理扰动训练,非常鲁棒(Robust)。有了这层保护,高层策略即使偶尔发出了不完美的指令,低层控制器也会尽力在物理上“圆”回来,不至于让机器人直接翻车。

low_level_decimation 的作用是什么?

low_level_decimation(低层降频/Sub-stepping)是连接高层与低层两个不同时间世界的变速齿轮
  1. 时间尺度的匹配
      • 控制层 (低层) 需要极快(如 200Hz,即每 5ms 一次)来响应地面的微小变化,防止摔倒。
      • 决策层 (高层) 思考不需要那么快(如 50Hz,即每 20ms 一次)。如果你每 5ms 就改一次主意说“往左”、“往右”,机器人会像得了帕金森一样抖动。
  1. 更稳定的动作
      • low_level_decimation = 4 意味着:高层说一句话,低层执行 4 遍。这天然地让动作指令保持了一段时间(Zero-Order Hold),使得运动更加连贯平滑。
  1. 计算效率
      • 高层网络通常比较大(因为它要处理任务逻辑)。让它少跑几次(降频),可以显著节省算力,让训练更快。

低层策略的观测从哪里来?

  • 大部分来自真实物理状态
    • 机器人的关节位置 (Joint Pos)关节速度 (Joint Vel)基座速度 (Base Vel)重力向量等。这些都是从环境 (env.scene) 里实时读取的,代表了机器人当下的身体状况。
  • 关键部分被“劫持” (Hijacked)
    • 低层策略原本在训练时有一个输入叫“速度指令 (Velocity Command)”(即告诉它往哪走)。
    • 在层次化架构中,我们通过 lambda 函数把这个输入源强行替换成了高层策略刚刚输出的动作
    • 代码证据(pre_trained_policy_action.py):

如何修改目标位置范围?

输出一个episode完整数据流的示意图

notion image