观测量概述
在 Lite3 强化学习项目中,观测量(Observation)是 Policy 网络的输入,它编码了机器人当前的状态信息。观测量的设计直接影响到策略学习的效果和泛化能力。
重要说明:本文档涵盖两个版本:
- 🔵 Isaac Gym 版本: 基于 NVIDIA Isaac Gym 的 Lite3_rl_training 项目:https://github.com/DeepRoboticsLab/Lite3_rl_training
- 🟢 Isaac Lab 版本: 基于 Isaac Lab 的新版 rl_training 项目:https://github.com/DeepRoboticsLab/rl_training
观测量的作用
观测量 → Policy Network → 动作输出
↓
用于奖励计算
↓
环境状态评估
核心理念:
- ✅ 可观测性:只包含机器人传感器能实际测量的信息
- ✅ 充分性:包含足够的信息支持决策
- ✅ 高效性:维度适中,避免冗余
- ✅ 鲁棒性:考虑传感器噪声和误差
框架对比说明
Isaac Gym vs Isaac Lab
| 特性 | Isaac Gym 版本 | Isaac Lab 版本 |
|---|---|---|
| 仿真引擎 | Isaac Gym | Isaac Lab (基于 Isaac Sim) |
| 配置方式 | 类继承 + 硬编码 | Manager-based + 声明式配置 |
| 观测定义 | compute_observations() 函数 | ObservationsCfg 配置类 |
| 模块化 | 较低 | 高度模块化 |
| 扩展性 | 需修改代码 | 配置文件即可 |
| 版本 | 较早 (2023) | 最新 (2024-2025) |
配置文件位置对比
🔵 Isaac Gym 版本:
Lite3_rl_training/
└── legged_gym/legged_gym/envs/
├── lite3/lite3_config.py # 观测维度配置
└── base/
├── legged_robot.py # compute_observations()
└── legged_robot_config.py # 缩放和噪声
🟢 Isaac Lab 版本:
rl_training/source/rl_training/tasks/
└── manager_based/locomotion/velocity/
├── velocity_env_cfg.py # 基础观测配置
├── mdp/observations.py # 观测函数实现
└── config/quadruped/deeprobotics_lite3/
└── rough_env_cfg.py # Lite3 特定配置
🔵 Isaac Gym 版本
核心观测量详解
1. 速度指令 (Commands)
# 维度: 3
self.commands[:, :3] * self.commands_scale
| 分量 | 含义 | 范围 | 单位 |
|---|---|---|---|
commands[0] | 前后线速度指令 | [-1.0, 1.0] | m/s |
commands[1] | 左右线速度指令 | [-1.0, 1.0] | m/s |
commands[2] | 偏航角速度指令 | [-1.0, 1.0] | rad/s |
作用:
- 告诉 Policy 用户希望机器人以什么速度运动
- 是 Policy 跟踪的目标
- 用于计算跟踪奖励
参与强化学习:
# 奖励计算
tracking_lin_vel_reward = exp(-||v_actual - v_command||^2 / sigma)
tracking_ang_vel_reward = exp(-||w_actual - w_command||^2 / sigma)
2. 身体姿态 (Roll, Pitch, Yaw)
# 维度: 3
self.rpy * self.obs_scales.orientation # 缩放系数: 1.0
| 分量 | 含义 | 物理意义 | 典型值 |
|---|---|---|---|
rpy[0] | Roll (横滚角) | 身体左右倾斜 | [-0.5, 0.5] rad |
rpy[1] | Pitch (俯仰角) | 身体前后倾斜 | [-1.0, 1.0] rad |
rpy[2] | Yaw (偏航角) | 身体旋转方向 | [-π, π] rad |
作用:
- 描述机器人身体在世界坐标系中的朝向
- 用于姿态稳定控制
- 检测机器人是否翻倒
参与强化学习:
# 终止条件
reset_buf = torch.logical_or(
torch.abs(self.rpy[:, 1]) > 1.0, # pitch > 60°
torch.abs(self.rpy[:, 0]) > 0.5 # roll > 30°
)
# 姿态奖励(惩罚倾斜)
orientation_reward = -torch.sum(torch.square(self.rpy[:, :2]))
3. 身体角速度 (Angular Velocity)
# 维度: 3
self.base_ang_vel * self.obs_scales.ang_vel # 缩放系数: 1.0
| 分量 | 含义 | 单位 | 作用 |
|---|---|---|---|
ang_vel[0] | 绕 x 轴角速度 | rad/s | 检测翻滚 |
ang_vel[1] | 绕 y 轴角速度 | rad/s | 检测俯仰 |
ang_vel[2] | 绕 z 轴角速度 | rad/s | 转向控制 |
坐标系:身体坐标系(Body Frame)
作用:
- 提供动态平衡信息
- 用于快速反应控制
- 阻尼不稳定的旋转
参与强化学习:
# 惩罚 xy 平面角速度(抑制翻滚和俯仰)
ang_vel_xy_penalty = -torch.sum(torch.square(self.base_ang_vel[:, :2]))
# z 轴角速度用于跟踪偏航指令
tracking_ang_vel = exp(-||ang_vel_z - command_yaw||^2 / sigma)
4. 关节位置 (Joint Positions)
# 维度: 12 (四足 × 3 关节/腿)
self.dof_pos * self.obs_scales.dof_pos # 缩放系数: 1.0
关节布局 (Lite3):
腿部编号:
FL (前左) FR (前右)
HL (后左) HR (后右)
每条腿 3 个关节:
- HipX (髋关节横向)
- HipY (髋关节纵向)
- Knee (膝关节)
总计: 4 腿 × 3 关节 = 12 DoF
| 关节索引 | 关节名称 | 范围 (rad) | 默认角度 |
|---|---|---|---|
| 0 | FL_HipX | [-0.523, 0.523] | 0.0 |
| 1 | FL_HipY | [-0.314, 3.6] | -1.0 |
| 2 | FL_Knee | [-2.792, -0.524] | 1.8 |
| 3-5 | HL (后左) | 同上 | 同上 |
| 6-8 | FR (前右) | 同上 | 同上 |
| 9-11 | HR (后右) | 同上 | 同上 |
作用:
- 描述机器人当前的肢体形态
- 检测关节极限
- 用于运动学正向计算
参与强化学习:
# 惩罚超出软限位
dof_pos_limits_penalty = torch.sum(
torch.clamp(self.dof_pos - self.dof_pos_limits[:, 1], min=0.) +
torch.clamp(self.dof_pos_limits[:, 0] - self.dof_pos, min=0.)
)
5. 关节速度 (Joint Velocities)
# 维度: 12
self.dof_vel * self.obs_scales.dof_vel # 缩放系数: 0.1
单位: rad/s
作用:
- 提供关节运动的动态信息
- 用于阻尼控制
- 检测异常快速运动
参与强化学习:
# 惩罚过快的关节速度
dof_vel_penalty = -torch.sum(torch.square(self.dof_vel))
# 在 PD 控制器中计算阻尼力矩
torques = Kp * (target - pos) - Kd * vel
6. 上一动作 (Previous Actions)
配置1 (117维) 和配置3 (304维) 不直接包含上一动作,而是包含动作历史。
配置2 (133维) 和配置4 (320维) 包含:
# 维度: 12
self.actions # 上一时刻的动作输出
作用:
- 提供动作连续性信息
- 帮助 Policy 理解自己的控制影响
- 用于动作平滑
历史观测量
仅在 117 和 304 维配置中包含
历史更新机制
# 更新频率控制
if self.history_update_cnt % self.cfg.normalization.dof_history_interval == 0:
self.last_last_actions[:] = self.last_actions[:]
self.last_actions[:] = self.actions[:]
self.last_last_dof_vel[:] = self.last_dof_vel[:]
self.last_dof_vel[:] = self.dof_vel[:]
self.last_last_last_pos[:] = self.last_last_pos[:]
self.last_last_pos[:] = self.last_pos[:]
self.last_pos[:] = self.dof_pos[:]
更新间隔: dof_history_interval = 1 (每步更新)
1. 关节位置历史
# 维度: 36 (12 × 3 时刻)
dof_pos_history = torch.cat(
(self.last_last_last_pos, # t-3
self.last_last_pos, # t-2
self.last_pos), # t-1
dim=-1
)
时间跨度: 3 个历史时刻 (默认每时刻 12ms, 总共 ~36ms)
作用:
- 捕捉关节运动的时序模式
- 帮助 Policy 预测未来状态
- 提供速度和加速度的隐式信息
2. 关节速度历史
# 维度: 24 (12 × 2 时刻)
dof_pos_vel_history = torch.cat(
(self.last_last_dof_vel, # t-2
self.last_dof_vel), # t-1
dim=-1
)
作用:
- 提供关节加速度的隐式信息
- 帮助预测动态趋势
- 用于动作平滑
3. 动作目标历史
# 维度: 24 (12 × 2 时刻)
dof_pos_target_history = torch.cat(
(self.last_last_actions, # t-2
self.last_actions), # t-1
dim=-1
)
作用:
- 记录 Policy 的控制历史
- 用于动作平滑奖励
- 避免抖动
参与强化学习:
# 动作变化率惩罚
action_rate_penalty = -torch.sum(
torch.square(self.actions - self.last_actions)
)
地形感知观测量
仅在 304 和 320 维配置中包含
高度测量 (Height Measurements)
# 维度: 187
heights = torch.clip(
self.root_states[:, 2].unsqueeze(1) -
self.cfg.rewards.base_height_target -
self.measured_heights,
-1, 1.
) * self.obs_scales.height_measurements # 缩放系数: 5.0
测量范围配置:
# 17 × 11 = 187 个测量点
measured_points_x = [
-0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1,
0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8
] # 前后 1.6m
measured_points_y = [
-0.5, -0.4, -0.3, -0.2, -0.1, 0.,
0.1, 0.2, 0.3, 0.4, 0.5
] # 左右 1.0m
测量布局:
机器人周围的高度采样网格 (俯视图):
-0.5y ←→ 0.5y
↑
| ● ● ● ● ● ● ● ● ● ● ●
| ● ● ● ● ● ● ● ● ● ● ●
-0.8| ● ● ● ● ● ● ● ● ● ● ●
| ● ● ● ● ● ● ● ● ● ● ●
x ● ● ● ● ● 🤖 ● ● ● ● ● (机器人位置)
| ● ● ● ● ● ● ● ● ● ● ●
0.8| ● ● ● ● ● ● ● ● ● ● ●
↓ ● ● ● ● ● ● ● ● ● ● ●
● ● ● ● ● ● ● ● ● ● ●
总计: 17 × 11 = 187 个测量点
高度值含义:
- 正值: 前方有凸起(上坡、台阶、障碍物)
- 负值: 前方有凹陷(下坡、坑洞)
- 0 值: 平坦地形
作用:
- 提供局部地形信息
- 用于足点规划
- 避免碰撞和摔倒
参与强化学习:
# 隐式作用:Policy 学习根据地形调整步态
# 例如:检测到台阶时抬高腿部
特权观测量
维度: 54
概念:仅在训练时 Critic 可见,部署时不可获得的信息。
self.privileged_obs_buf = torch.cat(
(contact_states * self.priv_obs_scales.contact_state, # 4
friction_coefficients * self.priv_obs_scales.friction, # 4
external_forces_and_torques * self.priv_obs_scales.external_wrench, # 6
(self.mass_payloads - 6) * self.priv_obs_scales.mass_payload, # 1
self.com_displacements * self.priv_obs_scales.com_displacement, # 3
(self.motor_strengths - 1) * self.priv_obs_scales.motor_strength, # 12
(self.Kp_factors - 1) * self.priv_obs_scales.kp_factor, # 12
(self.Kd_factors - 1) * self.priv_obs_scales.kd_factor, # 12
), dim=1)
# 总计: 4 + 4 + 6 + 1 + 3 + 12 + 12 + 12 = 54
特权观测量分类
| 类别 | 维度 | 内容 | 缩放系数 |
|---|---|---|---|
| 接触状态 | 4 | 四足接触地面标志 | 1.0 |
| 摩擦系数 | 4 | 地面摩擦系数 | 1.0 |
| 外力/外力矩 | 6 | 推力和推力矩 | 1.0 |
| 负载质量 | 1 | 额外载重 | 0.5 |
| 质心偏移 | 3 | 质心位置偏移 | 20.0 |
| 电机强度 | 12 | 电机输出倍率 | 5.0 |
| Kp 因子 | 12 | 位置增益倍率 | 4.0 |
| Kd 因子 | 12 | 速度增益倍率 | 2.0 |
作用:
- 训练更好的 Critic (价值估计)
- 学习对扰动的鲁棒性
- 提高 sim-to-real 迁移能力
观测量在强化学习中的作用
1. Actor 输入
# Actor 网络
obs = compute_observations() # [num_envs, 117/304/...]
actions = policy(obs) # [num_envs, 12]
作用流程:
观测量 → Actor MLP [512-256-128] → 关节动作
2. Critic 输入
# Critic 网络(使用特权观测)
privileged_obs = compute_privileged_observations() # [num_envs, 54]
value = critic(privileged_obs) # [num_envs, 1]
非对称训练:
- 训练: Critic 使用特权观测,准确评估状态价值
- 部署: Actor 仅使用普通观测,无需特权信息
3. 奖励计算
几乎所有观测量都参与奖励计算:
def compute_reward(self):
# 跟踪奖励
rew_tracking_lin_vel = tracking_reward(self.base_lin_vel, self.commands[:, :2])
rew_tracking_ang_vel = tracking_reward(self.base_ang_vel[:, 2], self.commands[:, 2])
# 稳定性奖励
rew_orientation = -torch.sum(torch.square(self.rpy[:, :2]))
rew_ang_vel_xy = -torch.sum(torch.square(self.base_ang_vel[:, :2]))
# 能量效率
rew_torques = -torch.sum(torch.square(self.torques))
rew_dof_vel = -torch.sum(torch.square(self.dof_vel))
# 动作平滑
rew_action_rate = -torch.sum(torch.square(self.actions - self.last_actions))
# 总奖励
total_reward = (
rew_tracking_lin_vel * 1.0 +
rew_tracking_ang_vel * 0.5 +
rew_orientation * -0.2 +
rew_ang_vel_xy * -0.05 +
rew_torques * -0.00001 +
rew_dof_vel * -0.0 +
rew_action_rate * -0.01
)
4. 终止条件
def check_termination(self):
# 姿态倾覆
self.reset_buf = torch.logical_or(
torch.abs(self.rpy[:, 1]) > 1.0, # pitch > 60°
torch.abs(self.rpy[:, 0]) > 0.5 # roll > 30°
)
# 不良接触
self.reset_buf |= torch.any(
torch.norm(self.contact_forces[:, self.termination_contact_indices, :], dim=-1) > 1.,
dim=1
)
# 超时
self.time_out_buf = self.episode_length_buf > self.max_episode_length
self.reset_buf |= self.time_out_buf
🟢 Isaac Lab 版本
观测配置架构
# velocity_env_cfg.py (Isaac Lab 基础配置)
@configclass
class ObservationsCfg:
"""Observation specifications for the MDP."""
@configclass
class PolicyCfg(ObsGroup):
"""Policy 网络的观测 (Actor 输入)"""
# 基础运动观测
base_lin_vel = ObsTerm(
func=mdp.base_lin_vel, # 观测函数
noise=Unoise(n_min=-0.1, n_max=0.1), # 均匀噪声
clip=(-100.0, 100.0), # 裁剪范围
scale=1.0 # 缩放因子
)
base_ang_vel = ObsTerm(func=mdp.base_ang_vel, noise=Unoise(n_min=-0.2, n_max=0.2))
projected_gravity = ObsTerm(func=mdp.projected_gravity, noise=Unoise(n_min=-0.05, n_max=0.05))
# 指令观测
velocity_commands = ObsTerm(
func=mdp.generated_commands,
params={"command_name": "base_velocity"} # 函数参数
)
# 关节观测
joint_pos = ObsTerm(
func=mdp.joint_pos_rel,
params={"asset_cfg": SceneEntityCfg("robot", joint_names=".*", preserve_order=True)},
noise=Unoise(n_min=-0.01, n_max=0.01)
)
joint_vel = ObsTerm(
func=mdp.joint_vel_rel,
params={"asset_cfg": SceneEntityCfg("robot", joint_names=".*", preserve_order=True)},
noise=Unoise(n_min=-1.5, n_max=1.5)
)
# 动作观测
actions = ObsTerm(func=mdp.last_action)
# 地形观测
height_scan = ObsTerm(
func=mdp.height_scan,
params={"sensor_cfg": SceneEntityCfg("height_scanner")},
noise=Unoise(n_min=-0.1, n_max=0.1),
clip=(-1.0, 1.0)
)
def __post_init__(self):
self.enable_corruption = True # 启用噪声
self.concatenate_terms = True # 自动拼接所有观测项
@configclass
class CriticCfg(ObsGroup):
"""Critic 网络的观测 (Value 估计输入)"""
# 与 Policy 相同的观测项,但无噪声干扰
base_lin_vel = ObsTerm(func=mdp.base_lin_vel)
base_ang_vel = ObsTerm(func=mdp.base_ang_vel)
projected_gravity = ObsTerm(func=mdp.projected_gravity)
velocity_commands = ObsTerm(func=mdp.generated_commands, params={"command_name": "base_velocity"})
joint_pos = ObsTerm(func=mdp.joint_pos_rel, params={"asset_cfg": SceneEntityCfg("robot", joint_names=".*")})
joint_vel = ObsTerm(func=mdp.joint_vel_rel, params={"asset_cfg": SceneEntityCfg("robot", joint_names=".*")})
actions = ObsTerm(func=mdp.last_action)
height_scan = ObsTerm(func=mdp.height_scan, params={"sensor_cfg": SceneEntityCfg("height_scanner")})
def __post_init__(self):
self.enable_corruption = False # Critic 不添加噪声
self.concatenate_terms = True
# 观测组配置
policy: PolicyCfg = PolicyCfg()
critic: CriticCfg = CriticCfg()
关键设计:
ObsGroup: 观测组,包含多个观测项ObsTerm: 单个观测项配置func: 指向mdp模块中的观测函数params: 传递给观测函数的参数noise: 噪声模型配置clip: 观测值裁剪范围scale: 观测值缩放因子enable_corruption: 是否启用噪声 (Policy=True, Critic=False)concatenate_terms: 是否自动拼接观测项
ObsTerm 配置说明
ObsTerm(
func=mdp.base_lin_vel, # 观测函数 (来自 mdp 模块)
noise=Unoise(n_min=-0.1, n_max=0.1), # 均匀噪声
clip=(-10.0, 10.0), # 裁剪范围
scale=1.0 # 缩放因子
)
Lite3 在 Isaac Lab 中的观测配置
# rough_env_cfg.py (Lite3 特定配置)
@configclass
class DeeproboticsLite3RoughEnvCfg(LocomotionVelocityRoughEnvCfg):
def __post_init__(self):
super().__post_init__()
# 🔴 禁用某些观测
self.observations.policy.base_lin_vel = None # 禁用线速度 (3维)
self.observations.policy.height_scan = None # 禁用地形扫描 (187维)
# ✏️ 修改观测缩放
self.observations.policy.base_ang_vel.scale = 0.25 # 角速度缩放
self.observations.policy.joint_pos.scale = 1.0 # 关节位置缩放
self.observations.policy.joint_vel.scale = 0.05 # 关节速度缩放 (vs 0.1 in Gym)
# ✏️ 修改动作缩放
self.actions.joint_pos.scale = {
".*_HipX_joint": 0.125, # HipX 关节: 0.125
"^(?!.*_HipX_joint).*": 0.25 # 其他关节: 0.25
}
自定义观测函数
Isaac Lab 支持自定义观测函数:
# observations.py
def joint_pos_rel_without_wheel(env: ManagerBasedRLEnv, asset_cfg: SceneEntityCfg) -> torch.Tensor:
"""关节位置观测 (相对于默认位置,排除轮子关节)"""
asset: Articulation = env.scene[asset_cfg.name]
return asset.data.joint_pos[:, asset_cfg.joint_ids] - asset.data.default_joint_pos[:, asset_cfg.joint_ids]
def phase(env: ManagerBasedRLEnv) -> torch.Tensor:
"""步态相位观测"""
# 自定义步态相位计算逻辑
return env.command_manager.get_term("base_velocity").pos_command_b[:, :2]
代码实现
# velocity_env_cfg.py (配置文件)
@configclass
class PolicyCfg(ObsGroup):
"""仅需声明观测项,Manager 自动处理拼接和噪声"""
velocity_commands = ObsTerm(
func=mdp.generated_commands,
params={"command_name": "base_velocity"}
) # 3维
base_ang_vel = ObsTerm(
func=mdp.base_ang_vel,
noise=Unoise(n_min=-0.2, n_max=0.2),
scale=1.0
) # 3维
projected_gravity = ObsTerm(
func=mdp.projected_gravity,
noise=Unoise(n_min=-0.05, n_max=0.05)
) # 3维
joint_pos = ObsTerm(
func=mdp.joint_pos_rel,
params={"asset_cfg": SceneEntityCfg("robot", joint_names=".*")},
noise=Unoise(n_min=-0.01, n_max=0.01)
) # 12维
joint_vel = ObsTerm(
func=mdp.joint_vel_rel,
params={"asset_cfg": SceneEntityCfg("robot", joint_names=".*")},
noise=Unoise(n_min=-1.5, n_max=1.5),
scale=1.0
) # 12维
actions = ObsTerm(func=mdp.last_action) # 12维
# rough_env_cfg.py (Lite3 定制)
def __post_init__(self):
# 禁用不需要的观测项
self.observations.policy.base_lin_vel = None # 禁用
self.observations.policy.height_scan = None # 禁用
# 修改缩放因子
self.observations.policy.base_ang_vel.scale = 0.25
self.observations.policy.joint_vel.scale = 0.05
Lite3 观测维度分析 (Isaac Lab)
根据 rough_env_cfg.py 和 velocity_env_cfg.py 配置分析:
基础观测配置 (velocity_env_cfg.py)
@configclass
class PolicyCfg(ObsGroup):
base_lin_vel = ObsTerm(...) # 3 维 [vx, vy, vz]
base_ang_vel = ObsTerm(...) # 3 维 [ωx, ωy, ωz]
projected_gravity = ObsTerm(...) # 3 维 [gx, gy, gz]
velocity_commands = ObsTerm(...) # 3 维 [vx_cmd, vy_cmd, ωz_cmd]
joint_pos = ObsTerm(...) # 12 维 (12个关节)
joint_vel = ObsTerm(...) # 12 维 (12个关节)
actions = ObsTerm(...) # 12 维 (上一时刻动作)
height_scan = ObsTerm(...) # 187 维 (17×11地形网格)
基础配置总维度: 3 + 3 + 3 + 3 + 12 + 12 + 12 + 187 = 235 维
Lite3 特定修改 (rough_env_cfg.py)
# 禁用的观测
self.observations.policy.base_lin_vel = None # ❌ -3 维
self.observations.policy.height_scan = None # ❌ -187 维
Lite3 实际 Policy 观测维度: 235 - 3 - 187 = 45 维
Policy 观测详细组成
# Lite3 Policy 观测 (45 维)
base_ang_vel (3) # 身体角速度 [ωx, ωy, ωz]
projected_gravity (3) # 投影重力 [gx, gy, gz]
velocity_commands (3) # 速度指令 [vx_cmd, vy_cmd, ωz_cmd]
joint_pos (12) # 关节位置相对值
joint_vel (12) # 关节速度
actions (12) # 上一时刻动作
# 总计: 3 + 3 + 3 + 12 + 12 + 12 = 45 维
Critic 特权观测组成
# Critic 观测 (基础版,无额外特权信息)
base_lin_vel (3) # 线速度 (Policy中被禁用)
base_ang_vel (3) # 角速度
projected_gravity (3) # 投影重力
velocity_commands (3) # 速度指令
joint_pos (12) # 关节位置
joint_vel (12) # 关节速度
actions (12) # 上一时刻动作
height_scan (187) # 地形扫描 (Policy中被禁用)
# 总计: 3 + 3 + 3 + 3 + 12 + 12 + 12 + 187 = 235 维
注意: Isaac Lab 中 Critic 默认配置与 Policy 相同的观测项,但不禁用任何项,并且没有噪声干扰。
与 Isaac Gym 的维度对比
| 版本 | Policy 维度 | Critic 维度 | 关键差异 |
|---|---|---|---|
| Isaac Gym | 117 | 54 | 包含历史观测(84维) |
| Isaac Lab | 45 | 235 | 无历史观测,Critic包含地形 |
核心区别:
- 🔵 Isaac Gym: 使用历史缓冲(3时刻位置+2时刻速度+2时刻动作) = 84维历史
- 🟢 Isaac Lab: 不使用历史观测,仅使用当前时刻的观测 = 更轻量级
观测量的噪声处理
🔵 Isaac Gym 噪声配置
class noise:
add_noise = True
noise_level = 1.0 # 全局噪声缩放
class noise_scales:
dof_pos = 0.01 # 关节位置噪声
dof_vel = 1.5 # 关节速度噪声
lin_vel = 0.1 # 线速度噪声
ang_vel = 0.2 # 角速度噪声
gravity = 0.05 # 重力方向噪声
height_measurements = 0.1 # 地形高度噪声
orientation = 0.5 # 姿态噪声
噪声添加方式
🔵 Isaac Gym:
if self.add_noise:
# 均匀噪声: U(-noise_scale, +noise_scale)
self.obs_buf += (2 * torch.rand_like(self.obs_buf) - 1) * self.noise_scale_vec
# 地形高度使用高斯噪声
self.obs_buf[:, -187:] += torch.normal(
mean=self.height_noise_mean, # 均值 (可变)
std=0.05, # 标准差
size=(self.obs_buf[:, -187:].shape)
) * self.obs_scales.height_measurements
🟢 Isaac Lab:
# 每个观测项独立配置噪声
ObsTerm(
func=mdp.joint_vel_rel,
noise=Unoise(n_min=-1.5, n_max=1.5), # 均匀噪声 [-1.5, 1.5]
)
# 或使用高斯噪声
ObsTerm(
func=mdp.base_lin_vel,
noise=GaussianNoise(mean=0.0, std=0.1), # 高斯噪声 N(0, 0.1)
)
噪声的作用
- 提高鲁棒性: 模拟真实传感器误差
- 防止过拟合: 避免 Policy 依赖精确值
- Sim-to-Real: 减小仿真与现实的差距
观测量维度总结表
🔵 Isaac Gym 观测维度
| 配置 | 指令 | 姿态 | 角速度 | 关节位置 | 关节速度 | 位置历史 | 速度历史 | 动作历史 | 地形 | 总计 |
|---|---|---|---|---|---|---|---|---|---|---|
| 117 | 3 | 3 | 3 | 12 | 12 | 36 | 24 | 24 | 0 | 117 |
| 304 | 3 | 3 | 3 | 12 | 12 | 36 | 24 | 24 | 187 | 304 |
🟢 Isaac Lab 观测维度
Isaac Lab 的观测维度由配置类动态组合。
Lite3 实际配置
Policy 观测: 45 维
base_ang_vel (3) + projected_gravity (3) + velocity_commands (3) +
joint_pos (12) + joint_vel (12) + actions (12) = 45 维
Critic 观测: 235 维
base_lin_vel (3) + base_ang_vel (3) + projected_gravity (3) + velocity_commands (3) +
joint_pos (12) + joint_vel (12) + actions (12) + height_scan (187) = 235 维
关键特性对比
| 特性 | Isaac Gym (117维) | Isaac Lab (45维) |
|---|---|---|
| 历史观测 | ✅ 84维 (3时刻位置+2时刻速度+2时刻动作) | ❌ 无历史 |
| 当前观测 | 33维 | 45维 |
| 地形扫描 | ❌ 默认关闭 | ✅ Critic启用(187维) |
| 线速度 | ✅ 包含 | ❌ Policy禁用 |
| 维度优势 | 时序信息丰富 | 轻量级,推理快 |
设计理念差异:
- 🔵 Isaac Gym: 通过历史观测隐式提供速度/加速度信息
- 🟢 Isaac Lab: 直接使用当前状态,依赖网络学习动态特性
灵活性: Isaac Lab 可以通过配置轻松调整观测维度,无需修改代码。如需历史观测,可使用 ObservationHistory wrapper 或自定义 MDP 函数。
72

被折叠的 条评论
为什么被折叠?



