robot_lab之robot_lab篇------issac lab时代适合四足的强化学习框架
机器人强化学习控制框架摘要 本文介绍了一个基于Isaac Lab的机器人强化学习扩展库robot_lab,主要用于训练四足、轮式和人形机器人的运动控制能力。项目采用模块化设计,包含场景配置、MDP组件(奖励函数、命令生成、观察空间等)、课程学习和强化学习算法配置。核心功能包括: 环境配置:支持平坦/粗糙地形,可配置物理属性和视觉材料 奖励机制:包含速度跟踪、步态优化、姿态稳定等多目标奖励函数 训练
0. 简介
robot_lab是一个基于IsaacLab的机器人强化学习扩展库。它使您能够在一个独立的环境中进行开发,而无需依赖核心的Isaac Lab代码库。这次我们主要来看rewards.py以及mdp的其他文件,来梳理本身的强化学习数据内容。
1. robot_lab 项目结构与功能解析
根据提供的目录结构和代码片段,这是一个基于 Isaac Lab 强化学习框架的机器人控制项目,主要用于训练不同类型的机器人(四足、轮式、人形等)进行运动控制任务。
1.1 主要文件夹结构
1.1.1 robot_lab
主要源代码目录,包含以下结构:
-
robot_lab/- 主要Python包- init.py - 包初始化文件,注册环境和UI扩展
ui_extension_example.py- UI扩展示例assets/- 资产配置- init.py - 定义数据路径等常量
unitree.py- Unitree系列机器人配置(A1、Go2、B2等)fftai.py- FFTAI系列机器人配置
tasks/- 任务实现locomotion/velocity/- 基于速度的运动控制任务mdp/- MDP(马尔可夫决策过程)组件- rewards.py - 奖励函数定义
- commands.py - 命令生成器
- events.py - 事件处理
- observations.py - 观察空间定义
- curriculums.py - 课程学习组件
config/- 不同机器人配置quadruped/- 四足机器人配置wheeled/- 轮式机器人配置humanoid/- 人形机器人配置
third_party/- 第三方工具和库amp_utils/- Adversarial Motion Priors工具rsl_rl_amp/- RSL RL AMP扩展
-
config/- 扩展配置extension.toml- 扩展元数据配置
-
data/- 机器人数据Robots/- 机器人模型Unitree/- Unitree公司机器人A1/,B2/,Go2/,B2W/,Go2W/- 不同型号
FFTAI/- FFTAI公司机器人
1.1.2 scripts
训练和工具脚本:
-
rsl_rl/- RSL强化学习框架脚本cli_args.py- 命令行参数处理rsl_rl_utils.py- 工具函数amp/- AMP相关脚本play.py- 播放训练模型replay_amp_data.py- 重放AMP数据- train.py - 训练AMP模型
base/- 基础RL训练脚本play.py- 播放训练模型- train.py - 训练基础模型
-
tools/- 工具脚本clean_trash.py- 清理无用日志convert_urdf.py- URDF转USDlist_envs.py- 列出可用环境train_batch.py- 批量训练脚本
1.2 核心模块详解
1.2.1 MDP组件 (tasks/locomotion/velocity/mdp/)
这是项目的核心部分,定义了强化学习环境的关键组件:
rewards.py - 奖励函数
提供各种奖励函数,例如:
track_lin_vel_xy_exp- 奖励跟踪线性速度命令track_ang_vel_z_exp- 奖励跟踪角速度命令feet_air_time- 奖励足部在空中的时间feet_slide- 惩罚足部滑动joint_pos_penalty- 惩罚关节偏离默认位置flat_orientation_l2- 奖励保持平坦姿态GaitReward- 步态奖励类
每个奖励函数针对机器人运动的特定方面,例如姿态稳定性、命令跟踪精度、能量效率等。
commands.py - 命令生成
UniformThresholdVelocityCommand- 从均匀分布生成带阈值的速度命令DiscreteCommandController- 离散命令控制器
这些组件负责生成机器人控制命令,例如目标速度、方向等。
observations.py - 观察空间
定义观察空间函数:
joint_pos_rel_without_wheel- 获取非轮式关节相对位置phase- 计算相位信息
这些函数提供强化学习策略所需的状态信息。
events.py - 事件处理
提供事件处理函数:
randomize_rigid_body_inertia- 随机化刚体惯性randomize_com_positions- 随机化质心位置
这些函数用于环境域随机化,增强策略的鲁棒性。
curriculums.py - 课程学习
command_levels_vel- 基于表现逐步增加命令复杂度terrain_levels_vel- 基于表现逐步增加地形复杂度
2. Unitree B2W 轮式reward和强化学习梳理
2.1 框架概述
这里我们以Unitree B2W 轮式机器人为基础代码,解释如何实现一个基于 Isaac Lab 和强化学习的 Unitree B2W 轮腿式机器人控制系统。通过分析提供的代码文件,可以看到系统采用了模块化的设计,从环境配置到任务定义,再到训练算法,形成了一个完整的强化学习流程。
2.2 文件结构与关系
提供的代码包含以下几个密切相关的文件:
- velocity_env_cfg.py: 基础环境配置文件,定义了通用的运动速度控制环境
- rough_env_cfg.py: B2W机器人在粗糙地形上的特定配置
- flat_env_cfg.py: B2W机器人在平坦地形上的简化配置
- rsl_rl_ppo_cfg.py: PPO强化学习算法的配置
- init.py: 环境注册文件,连接环境配置和学习算法
这些文件构成了继承关系树:
LocomotionVelocityRoughEnvCfg (velocity_env_cfg.py)
└── UnitreeB2WRoughEnvCfg (rough_env_cfg.py)
└── UnitreeB2WFlatEnvCfg (flat_env_cfg.py)
2.3 核心配置解析
2.3.1 基础环境框架 (velocity_env_cfg.py)
这是整个框架的基础,定义了运动控制环境的核心组件:
@configclass
class LocomotionVelocityRoughEnvCfg(ManagerBasedRLEnvCfg):
# 场景设置
scene: MySceneCfg = MySceneCfg(num_envs=4096, env_spacing=2.5)
# 基本设置
observations: ObservationsCfg = ObservationsCfg()
actions: ActionsCfg = ActionsCfg()
commands: CommandsCfg = CommandsCfg()
# MDP 设置
rewards: RewardsCfg = RewardsCfg()
terminations: TerminationsCfg = TerminationsCfg()
events: EventCfg = EventCfg()
curriculum: CurriculumCfg = CurriculumCfg()
核心组件包括:
- Scene: 定义物理场景,包括地形、机器人和传感器
- Observations: 定义机器人状态的观测空间
- Actions: 定义控制动作空间
- Commands: 定义速度指令生成规则
- Rewards: 定义奖励函数
- Terminations: 定义任务终止条件
- Events: 定义随机化事件
- Curriculum: 定义课程学习规则
这个基类实现了强化学习中的马尔可夫决策过程(MDP)框架,为各种机器人提供了通用的运动控制环境。这里面是所有的环境和MDP数据
##
# Scene definition
##
@configclass
class MySceneCfg(InteractiveSceneCfg):
"""配置用于具有腿部机器人的地形场景。"""
# 地面地形
terrain = TerrainImporterCfg(
prim_path="/World/ground", # 地形的原始路径
terrain_type="generator", # 地形类型为生成器
terrain_generator=ROUGH_TERRAINS_CFG, # 使用的地形生成器配置
max_init_terrain_level=5, # 最大初始地形级别
collision_group=-1, # 碰撞组
physics_material=sim_utils.RigidBodyMaterialCfg( # 物理材料配置
friction_combine_mode="multiply", # 摩擦合成模式
restitution_combine_mode="multiply", # 反弹合成模式
static_friction=1.0, # 静态摩擦系数
dynamic_friction=1.0, # 动态摩擦系数
),
visual_material=sim_utils.MdlFileCfg( # 视觉材料配置
mdl_path=f"{ISAACLAB_NUCLEUS_DIR}/Materials/TilesMarbleSpiderWhiteBrickBondHoned/TilesMarbleSpiderWhiteBrickBondHoned.mdl", # 材料模型路径
project_uvw=True, # 是否投影UV坐标
texture_scale=(0.25, 0.25), # 纹理缩放
),
debug_vis=False, # 调试可视化开关
)
# 机器人
robot: ArticulationCfg = MISSING # 机器人配置,缺失时为MISSING
# 传感器
height_scanner = RayCasterCfg( # 高度扫描仪配置
prim_path="{ENV_REGEX_NS}/Robot/base", # 原始路径
offset=RayCasterCfg.OffsetCfg(pos=(0.0, 0.0, 20.0)), # 偏移配置
attach_yaw_only=True, # 仅附加偏航
pattern_cfg=patterns.GridPatternCfg(resolution=0.1, size=[1.6, 1.0]), # 网格模式配置
debug_vis=False, # 调试可视化开关
mesh_prim_paths=["/World/ground"], # 网格原始路径
)
height_scanner_base = RayCasterCfg( # 基础高度扫描仪配置
prim_path="{ENV_REGEX_NS}/Robot/base", # 原始路径
offset=RayCasterCfg.OffsetCfg(pos=(0.0, 0.0, 20.0)), # 偏移配置
attach_yaw_only=True, # 仅附加偏航
pattern_cfg=patterns.GridPatternCfg(resolution=0.05, size=(0.1, 0.1)), # 网格模式配置
debug_vis=False, # 调试可视化开关
mesh_prim_paths=["/World/ground"], # 网格原始路径
)
contact_forces = ContactSensorCfg( # 接触传感器配置
prim_path="{ENV_REGEX_NS}/Robot/.*", # 原始路径
history_length=3, # 历史长度
track_air_time=True # 跟踪空中时间
)
# 灯光
sky_light = AssetBaseCfg( # 天空光源配置
prim_path="/World/skyLight", # 原始路径
spawn=sim_utils.DomeLightCfg( # 圆顶光源配置
intensity=750.0, # 光源强度
texture_file=f"{ISAAC_NUCLEUS_DIR}/Materials/Textures/Skies/PolyHaven/kloofendal_43d_clear_puresky_4k.hdr", # 纹理文件路径
),
)
##
# MDP 设置
##
@configclass
class CommandsCfg:
"""MDP 的命令规范。"""
base_velocity = mdp.UniformThresholdVelocityCommandCfg( # 基础速度命令配置
asset_name="robot", # 资产名称
resampling_time_range=(10.0, 10.0), # 重采样时间范围
rel_standing_envs=0.02, # 相对静止环境
rel_heading_envs=1.0, # 相对朝向环境
heading_command=True, # 启用朝向命令
heading_control_stiffness=0.5, # 朝向控制刚度
debug_vis=True, # 调试可视化开关
ranges=mdp.UniformThresholdVelocityCommandCfg.Ranges( # 速度范围配置
lin_vel_x=(-1.0, 1.0), lin_vel_y=(-1.0, 1.0), ang_vel_z=(-1.0, 1.0), heading=(-math.pi, math.pi)
),
)
@configclass
class ActionsCfg:
"""MDP 的动作规范。"""
joint_pos = mdp.JointPositionActionCfg( # 关节位置动作配置
asset_name="robot", # 资产名称
joint_names=[".*"], # 关节名称
scale=0.5, # 缩放因子
use_default_offset=True, # 使用默认偏移
clip=None, # 剪辑设置
preserve_order=True # 保持顺序
)
@configclass
class ObservationsCfg:
"""MDP 的观察规范。"""
@configclass
class PolicyCfg(ObsGroup):
"""策略组的观察。"""
# 观察项(保持顺序)
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), # 噪声配置
clip=(-100.0, 100.0), # 剪辑范围
scale=1.0, # 缩放因子
)
projected_gravity = ObsTerm( # 投影重力观察项
func=mdp.projected_gravity, # 观察函数
noise=Unoise(n_min=-0.05, n_max=0.05), # 噪声配置
clip=(-100.0, 100.0), # 剪辑范围
scale=1.0, # 缩放因子
)
velocity_commands = ObsTerm( # 速度命令观察项
func=mdp.generated_commands, # 观察函数
params={"command_name": "base_velocity"}, # 参数配置
clip=(-100.0, 100.0), # 剪辑范围
scale=1.0, # 缩放因子
)
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), # 噪声配置
clip=(-100.0, 100.0), # 剪辑范围
scale=1.0, # 缩放因子
)
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), # 噪声配置
clip=(-100.0, 100.0), # 剪辑范围
scale=1.0, # 缩放因子
)
actions = ObsTerm( # 动作观察项
func=mdp.last_action, # 观察函数
clip=(-100.0, 100.0), # 剪辑范围
scale=1.0, # 缩放因子
)
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), # 剪辑范围
scale=1.0, # 缩放因子
)
def __post_init__(self):
self.enable_corruption = True # 启用数据损坏
self.concatenate_terms = True # 连接观察项
@configclass
class CriticCfg(ObsGroup):
"""评论组的观察。"""
# 观察项(保持顺序)
base_lin_vel = ObsTerm( # 基础线速度观察项
func=mdp.base_lin_vel, # 观察函数
clip=(-100.0, 100.0), # 剪辑范围
scale=1.0, # 缩放因子
)
base_ang_vel = ObsTerm( # 基础角速度观察项
func=mdp.base_ang_vel, # 观察函数
clip=(-100.0, 100.0), # 剪辑范围
scale=1.0, # 缩放因子
)
projected_gravity = ObsTerm( # 投影重力观察项
func=mdp.projected_gravity, # 观察函数
clip=(-100.0, 100.0), # 剪辑范围
scale=1.0, # 缩放因子
)
velocity_commands = ObsTerm( # 速度命令观察项
func=mdp.generated_commands, # 观察函数
params={"command_name": "base_velocity"}, # 参数配置
clip=(-100.0, 100.0), # 剪辑范围
scale=1.0, # 缩放因子
)
joint_pos = ObsTerm( # 关节位置观察项
func=mdp.joint_pos_rel, # 观察函数
params={"asset_cfg": SceneEntityCfg("robot", joint_names=".*", preserve_order=True)}, # 参数配置
clip=(-100.0, 100.0), # 剪辑范围
scale=1.0, # 缩放因子
)
joint_vel = ObsTerm( # 关节速度观察项
func=mdp.joint_vel_rel, # 观察函数
params={"asset_cfg": SceneEntityCfg("robot", joint_names=".*", preserve_order=True)}, # 参数配置
clip=(-100.0, 100.0), # 剪辑范围
scale=1.0, # 缩放因子
)
actions = ObsTerm( # 动作观察项
func=mdp.last_action, # 观察函数
clip=(-100.0, 100.0), # 剪辑范围
scale=1.0, # 缩放因子
)
height_scan = ObsTerm( # 高度扫描观察项
func=mdp.height_scan, # 观察函数
params={"sensor_cfg": SceneEntityCfg("height_scanner")}, # 参数配置
clip=(-1.0, 1.0), # 剪辑范围
scale=1.0, # 缩放因子
)
def __post_init__(self):
self.enable_corruption = False # 禁用数据损坏
self.concatenate_terms = True # 连接观察项
# 观察组
policy: PolicyCfg = PolicyCfg() # 策略观察组
critic: CriticCfg = CriticCfg() # 评论观察组
@configclass
class EventCfg:
"""事件的配置。"""
# 启动时的事件配置
randomize_rigid_body_material = EventTerm( # 随机化刚体材料
func=mdp.randomize_rigid_body_material, # 调用的函数
mode="startup", # 事件模式为启动
params={ # 参数配置
"asset_cfg": SceneEntityCfg("robot", body_names=".*"), # 资产配置,选择所有身体部件
"static_friction_range": (0.3, 1.0), # 静态摩擦范围
"dynamic_friction_range": (0.3, 0.8), # 动态摩擦范围
"restitution_range": (0.0, 0.0), # 反弹范围
"num_buckets": 64, # 桶的数量
},
)
randomize_rigid_body_mass = EventTerm( # 随机化刚体质量
func=mdp.randomize_rigid_body_mass, # 调用的函数
mode="startup", # 事件模式为启动
params={ # 参数配置
"asset_cfg": SceneEntityCfg("robot", body_names=""), # 资产配置,选择所有身体部件
"mass_distribution_params": (-3.0, 3.0), # 质量分布参数
"operation": "add", # 操作类型为加法
},
)
randomize_rigid_body_inertia = EventTerm( # 随机化刚体惯性
func=mdp.randomize_rigid_body_inertia, # 调用的函数
mode="startup", # 事件模式为启动
params={ # 参数配置
"asset_cfg": SceneEntityCfg("robot", body_names=".*"), # 资产配置,选择所有身体部件
"inertia_distribution_params": (0.5, 1.5), # 惯性分布参数
"operation": "scale", # 操作类型为缩放
},
)
randomize_com_positions = EventTerm( # 随机化质心位置
func=mdp.randomize_com_positions, # 调用的函数
mode="startup", # 事件模式为启动
params={ # 参数配置
"asset_cfg": SceneEntityCfg("robot", body_names=""), # 资产配置,选择所有身体部件
"com_distribution_params": (-0.1, 0.1), # 质心分布参数
"operation": "add", # 操作类型为加法
},
)
# 重置时的事件配置
randomize_apply_external_force_torque = EventTerm( # 随机化施加外部力和扭矩
func=mdp.apply_external_force_torque, # 调用的函数
mode="reset", # 事件模式为重置
params={ # 参数配置
"asset_cfg": SceneEntityCfg("robot", body_names=""), # 资产配置,选择所有身体部件
"force_range": (-10.0, 10.0), # 力的范围
"torque_range": (-10.0, 10.0), # 扭矩的范围
},
)
randomize_reset_joints = EventTerm( # 随机化重置关节
# func=mdp.reset_joints_by_scale, # 通过缩放重置关节(已注释)
func=mdp.reset_joints_by_offset, # 通过偏移重置关节
mode="reset", # 事件模式为重置
params={ # 参数配置
"position_range": (-0.2, 0.2), # 位置范围
"velocity_range": (-2.5, 2.5), # 速度范围
},
)
randomize_actuator_gains = EventTerm( # 随机化执行器增益
func=mdp.randomize_actuator_gains, # 调用的函数
mode="reset", # 事件模式为重置
params={ # 参数配置
"asset_cfg": SceneEntityCfg("robot", joint_names=".*"), # 资产配置,选择所有关节
"stiffness_distribution_params": (0.5, 2.0), # 刚度分布参数
"damping_distribution_params": (0.5, 2.0), # 阻尼分布参数
"operation": "scale", # 操作类型为缩放
"distribution": "log_uniform", # 分布类型为对数均匀分布
},
)
# randomize_joint_limits = EventTerm( # 随机化关节限制(已注释)
# func=mdp.randomize_joint_parameters,
# mode="reset",
# params={
# "asset_cfg": SceneEntityCfg("robot", joint_names=".*"),
# "lower_limit_distribution_params": (0.00, 0.01),
# "upper_limit_distribution_params": (0.00, 0.01),
# "operation": "add",
# "distribution": "gaussian",
# },
# )
randomize_reset_base = EventTerm( # 随机化重置基座状态
func=mdp.reset_root_state_uniform, # 调用的函数
mode="reset", # 事件模式为重置
params={ # 参数配置
"pose_range": {"x": (-0.5, 0.5), "y": (-0.5, 0.5), "yaw": (-3.14, 3.14)}, # 姿态范围
"velocity_range": { # 速度范围
"x": (-0.5, 0.5),
"y": (-0.5, 0.5),
"z": (-0.5, 0.5),
"roll": (-0.5, 0.5),
"pitch": (-0.5, 0.5),
"yaw": (-0.5, 0.5),
},
},
)
# 间隔事件配置
randomize_push_robot = EventTerm( # 随机化推动机器人
func=mdp.push_by_setting_velocity, # 调用的函数
mode="interval", # 事件模式为间隔
interval_range_s=(10.0, 15.0), # 间隔时间范围
params={"velocity_range": {"x": (-0.5, 0.5), "y": (-0.5, 0.5)}}, # 速度范围参数
)
@configclass
class RewardsCfg:
"""MDP 的奖励项配置。"""
# 一般奖励项
is_terminated = RewTerm(func=mdp.is_terminated, weight=0.0) # 终止状态的奖励项
# 根部惩罚
lin_vel_z_l2 = RewTerm(func=mdp.lin_vel_z_l2, weight=0.0) # Z轴线速度的L2惩罚
ang_vel_xy_l2 = RewTerm(func=mdp.ang_vel_xy_l2, weight=0.0) # XY平面角速度的L2惩罚
flat_orientation_l2 = RewTerm(func=mdp.flat_orientation_l2, weight=0.0) # 平坦方向的L2惩罚
base_height_l2 = RewTerm( # 基座高度的L2惩罚
func=mdp.base_height_l2,
weight=0.0,
params={ # 参数配置
"asset_cfg": SceneEntityCfg("robot", body_names=""), # 资产配置,选择所有身体部件
"sensor_cfg": SceneEntityCfg("height_scanner_base"), # 传感器配置
"target_height": 0.0, # 目标高度
},
)
body_lin_acc_l2 = RewTerm( # 身体线加速度的L2惩罚
func=mdp.body_lin_acc_l2,
weight=0.0,
params={"asset_cfg": SceneEntityCfg("robot", body_names="")}, # 资产配置
)
# 关节惩罚
joint_torques_l2 = RewTerm( # 关节扭矩的L2惩罚
func=mdp.joint_torques_l2, weight=0.0, params={"asset_cfg": SceneEntityCfg("robot", joint_names=".*")}
)
joint_vel_l2 = RewTerm( # 关节速度的L2惩罚
func=mdp.joint_vel_l2, weight=0.0, params={"asset_cfg": SceneEntityCfg("robot", joint_names=".*")}
)
joint_acc_l2 = RewTerm( # 关节加速度的L2惩罚
func=mdp.joint_acc_l2, weight=0.0, params={"asset_cfg": SceneEntityCfg("robot", joint_names=".*")}
)
def create_joint_deviation_l1_rewterm(self, attr_name, weight, joint_names_pattern):
"""创建关节偏差的L1奖励项。"""
rew_term = RewTerm(
func=mdp.joint_deviation_l1, # 调用的函数
weight=weight, # 权重
params={"asset_cfg": SceneEntityCfg("robot", joint_names=joint_names_pattern)}, # 参数配置
)
setattr(self, attr_name, rew_term) # 将奖励项设置为属性
joint_pos_limits = RewTerm( # 关节位置限制的惩罚
func=mdp.joint_pos_limits, weight=0.0, params={"asset_cfg": SceneEntityCfg("robot", joint_names=".*")}
)
joint_vel_limits = RewTerm( # 关节速度限制的惩罚
func=mdp.joint_vel_limits,
weight=0.0,
params={"asset_cfg": SceneEntityCfg("robot", joint_names=".*"), "soft_ratio": 1.0},
)
joint_power = RewTerm( # 关节功率的惩罚
func=mdp.joint_power,
weight=0.0,
params={
"asset_cfg": SceneEntityCfg("robot", joint_names=".*"),
},
)
stand_still_without_cmd = RewTerm( # 无命令时保持静止的惩罚
func=mdp.stand_still_without_cmd,
weight=0.0,
params={
"command_name": "base_velocity", # 命令名称
"command_threshold": 0.1, # 命令阈值
"asset_cfg": SceneEntityCfg("robot", joint_names=".*"), # 资产配置
},
)
joint_pos_penalty = RewTerm( # 关节位置惩罚
func=mdp.joint_pos_penalty,
weight=0.0,
params={
"command_name": "base_velocity", # 命令名称
"asset_cfg": SceneEntityCfg("robot", joint_names=".*"), # 资产配置
"stand_still_scale": 5.0, # 保持静止的缩放因子
"velocity_threshold": 0.5, # 速度阈值
"command_threshold": 0.1, # 命令阈值
},
)
wheel_vel_penalty = RewTerm( # 轮子速度惩罚
func=mdp.wheel_vel_penalty,
weight=0.0,
params={
"asset_cfg": SceneEntityCfg("robot", joint_names=""), # 资产配置
"sensor_cfg": SceneEntityCfg("contact_forces", body_names=""), # 传感器配置
"command_name": "base_velocity", # 命令名称
"velocity_threshold": 0.5, # 速度阈值
"command_threshold": 0.1, # 命令阈值
},
)
joint_mirror = RewTerm( # 关节镜像惩罚
func=mdp.joint_mirror,
weight=0.0,
params={
"asset_cfg": SceneEntityCfg("robot"), # 资产配置
"mirror_joints": [["FR.*", "RL.*"], ["FL.*", "RR.*"]], # 镜像关节配置
},
)
# 动作惩罚
applied_torque_limits = RewTerm( # 应用扭矩限制的惩罚
func=mdp.applied_torque_limits,
weight=0.0,
params={"asset_cfg": SceneEntityCfg("robot", joint_names=".*")},
)
action_rate_l2 = RewTerm(func=mdp.action_rate_l2, weight=0.0) # 动作速率的L2惩罚
# smoothness_1 = RewTerm(func=mdp.smoothness_1, weight=0.0) # 与action_rate_l2相同(已注释)
# smoothness_2 = RewTerm(func=mdp.smoothness_2, weight=0.0) # 目前不可用(已注释)
# 接触传感器
undesired_contacts = RewTerm( # 不希望的接触惩罚
func=mdp.undesired_contacts,
weight=0.0,
params={
"sensor_cfg": SceneEntityCfg("contact_forces", body_names=""), # 传感器配置
"threshold": 1.0, # 阈值
},
)
contact_forces = RewTerm( # 接触力的惩罚
func=mdp.contact_forces,
weight=0.0,
params={"sensor_cfg": SceneEntityCfg("contact_forces", body_names=""), "threshold": 100.0},
)
# 速度跟踪奖励
track_lin_vel_xy_exp = RewTerm( # XY平面线速度期望的跟踪奖励
func=mdp.track_lin_vel_xy_exp, weight=0.0, params={"command_name": "base_velocity", "std": math.sqrt(0.25)}
)
track_ang_vel_z_exp = RewTerm( # Z轴角速度期望的跟踪奖励
func=mdp.track_ang_vel_z_exp, weight=0.0, params={"command_name": "base_velocity", "std": math.sqrt(0.25)}
)
# 其他奖励项
feet_air_time = RewTerm( # 脚在空中的时间奖励
func=mdp.feet_air_time,
weight=0.0,
params={
"command_name": "base_velocity", # 命令名称
"mode_time": 0.3, # 模式时间
"velocity_threshold": 0.5, # 速度阈值
"command_threshold": 0.1, # 命令阈值
"asset_cfg": SceneEntityCfg("robot"), # 资产配置
"sensor_cfg": SceneEntityCfg("contact_forces", body_names=""), # 传感器配置
},
)
feet_gait = RewTerm( # 脚步奖励
func=mdp.GaitReward,
weight=0.0,
params={
"std": math.sqrt(0.5), # 标准差
"command_name": "base_velocity", # 命令名称
"max_err": 0.2, # 最大误差
"velocity_threshold": 0.5, # 速度阈值
"command_threshold": 0.1, # 命令阈值
"synced_feet_pair_names": (("", ""), ("", "")), # 同步脚对名称
"asset_cfg": SceneEntityCfg("robot"), # 资产配置
"sensor_cfg": SceneEntityCfg("contact_forces"), # 传感器配置
},
)
feet_contact = RewTerm( # 脚接触奖励
func=mdp.feet_contact,
weight=0.0,
params={
"sensor_cfg": SceneEntityCfg("contact_forces", body_names=""), # 传感器配置
"command_name": "base_velocity", # 命令名称
"expect_contact_num": 2, # 期望接触数量
},
)
feet_contact_without_cmd = RewTerm( # 无命令时脚接触奖励
func=mdp.feet_contact_without_cmd,
weight=0.0,
params={
"sensor_cfg": SceneEntityCfg("contact_forces", body_names=""), # 传感器配置
"command_name": "base_velocity", # 命令名称
},
)
feet_stumble = RewTerm( # 脚绊倒惩罚
func=mdp.feet_stumble,
weight=0.0,
params={
"sensor_cfg": SceneEntityCfg("contact_forces", body_names=""), # 传感器配置
},
)
feet_slide = RewTerm( # 脚滑动惩罚
func=mdp.feet_slide,
weight=0.0,
params={
"sensor_cfg": SceneEntityCfg("contact_forces", body_names=""), # 传感器配置
"asset_cfg": SceneEntityCfg("robot", body_names=""), # 资产配置
},
)
feet_height = RewTerm( # 脚高度奖励
func=mdp.feet_height,
weight=0.0,
params={
"asset_cfg": SceneEntityCfg("robot", body_names=""), # 资产配置
"tanh_mult": 2.0, # tanh缩放因子
"target_height": 0.05, # 目标高度
"command_name": "base_velocity", # 命令名称
},
)
feet_height_body = RewTerm( # 身体高度奖励
func=mdp.feet_height_body,
weight=0.0,
params={
"asset_cfg": SceneEntityCfg("robot", body_names=""), # 资产配置
"tanh_mult": 2.0, # tanh缩放因子
"target_height": -0.3, # 目标高度
"command_name": "base_velocity", # 命令名称
},
)
feet_distance_y_exp = RewTerm( # Y轴脚距离期望奖励
func=mdp.feet_distance_y_exp,
weight=0.0,
params={
"std": math.sqrt(0.25), # 标准差
"asset_cfg": SceneEntityCfg("robot", body_names=""), # 资产配置
"stance_width": float, # 站立宽度
},
)
# feet_distance_xy_exp = RewTerm( # XY轴脚距离期望奖励(已注释)
# func=mdp.feet_distance_xy_exp,
# weight=0.0,
# params={
# "std": math.sqrt(0.25),
# "asset_cfg": SceneEntityCfg("robot", body_names=""),
# "stance_length": float,
# "stance_width": float,
# },
# )
upward = RewTerm( # 向上的奖励
func=mdp.upward,
weight=0.0,
params={
"std": math.sqrt(0.5), # 标准差
},
)
@configclass
class TerminationsCfg:
"""MDP 的终止条件配置。"""
# MDP 终止条件
time_out = DoneTerm(func=mdp.time_out, time_out=True) # 超时终止条件
# 命令重采样
terrain_out_of_bounds = DoneTerm( # 地形超出边界的终止条件
func=mdp.terrain_out_of_bounds, # 调用的函数
params={"asset_cfg": SceneEntityCfg("robot"), "distance_buffer": 3.0}, # 参数配置
time_out=True, # 设置为超时终止
)
# 接触传感器
illegal_contact = DoneTerm( # 非法接触的终止条件
func=mdp.illegal_contact, # 调用的函数
params={"sensor_cfg": SceneEntityCfg("contact_forces", body_names=""), "threshold": 1.0}, # 参数配置
)
@configclass
class CurriculumCfg:
"""MDP 的课程配置。"""
terrain_levels = CurrTerm(func=mdp.terrain_levels_vel) # 地形级别的课程项
command_levels = CurrTerm( # 命令级别的课程项
func=mdp.command_levels_vel, # 调用的函数
params={ # 参数配置
"reward_term_name": "track_lin_vel_xy_exp", # 奖励项名称
"max_curriculum": 1.5, # 最大课程值
},
)
##
# Environment configuration
##
@configclass
class LocomotionVelocityRoughEnvCfg(ManagerBasedRLEnvCfg):
"""用于运动速度跟踪环境的配置。"""
# 场景设置
scene: MySceneCfg = MySceneCfg(num_envs=4096, env_spacing=2.5) # 创建场景配置,环境数量为4096,环境间距为2.5
# 基本设置
observations: ObservationsCfg = ObservationsCfg() # 观察配置
actions: ActionsCfg = ActionsCfg() # 动作配置
commands: CommandsCfg = CommandsCfg() # 命令配置
# MDP 设置
rewards: RewardsCfg = RewardsCfg() # 奖励配置
terminations: TerminationsCfg = TerminationsCfg() # 终止条件配置
events: EventCfg = EventCfg() # 事件配置
curriculum: CurriculumCfg = CurriculumCfg() # 课程配置
def __post_init__(self):
"""后初始化设置。"""
# 一般设置
self.decimation = 4 # 降采样因子
self.episode_length_s = 20.0 # 每集持续时间为20秒
# 模拟设置
self.sim.dt = 0.005 # 模拟时间步长
self.sim.render_interval = self.decimation # 渲染间隔
self.sim.physics_material = self.scene.terrain.physics_material # 设置物理材料
self.sim.physx.gpu_max_rigid_patch_count = 10 * 2**15 # GPU最大刚体补丁数量
# 更新传感器更新周期
# 所有传感器的更新基于最小更新周期(物理更新周期)
if self.scene.height_scanner is not None:
self.scene.height_scanner.update_period = self.decimation * self.sim.dt # 高度扫描仪更新周期
if self.scene.contact_forces is not None:
self.scene.contact_forces.update_period = self.sim.dt # 接触力传感器更新周期
# 检查地形级别课程是否启用 - 如果启用,则为地形生成器启用课程
# 这将生成难度逐渐增加的地形,有助于训练
if getattr(self.curriculum, "terrain_levels", None) is not None:
if self.scene.terrain.terrain_generator is not None:
self.scene.terrain.terrain_generator.curriculum = True # 启用课程
else:
if self.scene.terrain.terrain_generator is not None:
self.scene.terrain.terrain_generator.curriculum = False # 禁用课程
def disable_zero_weight_rewards(self):
"""如果奖励的权重为0,则将奖励设置为None。"""
for attr in dir(self.rewards): # 遍历奖励属性
if not attr.startswith("__"): # 排除特殊属性
reward_attr = getattr(self.rewards, attr) # 获取奖励属性
if not callable(reward_attr) and reward_attr.weight == 0: # 如果不是可调用且权重为0
setattr(self.rewards, attr, None) # 将奖励设置为None
def create_obsgroup_class(class_name, terms, enable_corruption=False, concatenate_terms=True):
"""
根据给定的配置项动态创建并注册一个 ObsGroup 类。
:param class_name: 配置类的名称。
:param terms: 配置项,一个字典,其中键是项名称,值是项内容。
:param enable_corruption: 是否启用观察组的损坏。默认为 False。
:param concatenate_terms: 是否连接观察项。默认为 True。
:return: 动态创建的类。
"""
# 动态确定模块名称
module_name = inspect.getmodule(inspect.currentframe()).__name__
# 定义后初始化函数
def post_init_wrapper(self):
setattr(self, "enable_corruption", enable_corruption) # 设置启用损坏
setattr(self, "concatenate_terms", concatenate_terms) # 设置连接观察项
# 动态创建类,使用 ObsGroup 作为基类
terms["__post_init__"] = post_init_wrapper # 添加后初始化函数
dynamic_class = configclass(type(class_name, (ObsGroup,), terms)) # 创建动态类
# 自定义序列化和反序列化
def __getstate__(self):
state = self.__dict__.copy() # 复制当前状态
return state
def __setstate__(self, state):
self.__dict__.update(state) # 更新状态
# 将自定义序列化方法添加到类中
dynamic_class.__getstate__ = __getstate__
dynamic_class.__setstate__ = __setstate__
# 将类放入全局命名空间以便访问
globals()[class_name] = dynamic_class
# 在模块字典中注册动态类
if module_name in sys.modules:
sys.modules[module_name].__dict__[class_name] = dynamic_class
else:
raise ImportError(f"模块 {module_name} 未找到。")
# 返回类以供外部实例化
return dynamic_class
2.3.2 B2W 粗糙地形配置 (rough_env_cfg.py)
这个配置继承基础环境,并进行了针对Unitree B2W特性的调整:
@configclass
class UnitreeB2WRoughEnvCfg(LocomotionVelocityRoughEnvCfg):
actions: UnitreeB2WActionsCfg = UnitreeB2WActionsCfg()
rewards: UnitreeB2WRewardsCfg = UnitreeB2WRewardsCfg()
base_link_name = "base_link"
foot_link_name = ".*_foot"
wheel_joint_name = ".*_foot_joint"
关键定制包括:
- 混合动作空间: 同时支持关节位置控制和轮子速度控制
- B2W特定奖励: 调整了奖励权重以适应轮腿机器人特性
- 轮腿结构适配: 通过区分腿部关节和车轮关节的处理方式
…详情请参照古月居
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)