Nvidia Isaac Lab 7 - 在 Isaac Lab 中,训练第一个机器人 - 8. 分析代码
本节将分析代码,将 MDP 框架的思想与 Isaac Lab 的 Manager-based 工作流联系起来,同时讲述一些对训练过程有用的数学内容。这些概念与“Manager”都通过 Python @configclass 定义。
打开以下 Python 文件,仔细查看如何在代码中定义 MDP 元素:source/Cartpole/Cartpole/tasks/manager_based/cartpole/cartpole_env_cfg.py
1. 终止
训练回合何时结束?当小车距离其起始位置过远或超时时,将终止当前训练回合。在某个时刻,如果本回合结果偏离得太远,最好进入下一个回合。
@configclass
class TerminationsCfg:
"""Termination terms for the MDP."""
# (1) Time out
time_out = DoneTerm(func=mdp.time_out, time_out=True)
# (2) Cart out of bounds
cart_out_of_bounds = DoneTerm(
func=mdp.joint_pos_out_of_manual_limit,
params={"asset_cfg": SceneEntityCfg("robot", joint_names=["slider_to_cart"]), "bounds": (-3.0, 3.0)},
)2. 动作
小车可以施加力,使小车向左或向右移动。
@configclass
class ActionsCfg:
"""Action specifications for the MDP."""
joint_effort = mdp.JointEffortActionCfg(asset_name="robot", joint_names=["slider_to_cart"], scale=100.0)3. 观测
同时观测小车的位置和速度。
@configclass
class ObservationsCfg:
"""Observation specifications for the MDP."""
@configclass
class PolicyCfg(ObsGroup):
"""Observations for policy group."""
# observation terms (order preserved)
joint_pos_rel = ObsTerm(func=mdp.joint_pos_rel)
joint_vel_rel = ObsTerm(func=mdp.joint_vel_rel)4. 奖励
我们对多个方面给予奖励,并且为它们设置不同的权重。在继续阅读前,可以花一点时间思考:如何用物理术语描述平衡?如果不确定也没关系,下面将对此进行解释。
以下是对该任务有效的奖励项:
- 奖励机器人维持训练过程。保持平衡是连续任务,不像将球投入桶中那样有明确的结束点。
- 对终止行为给予较大的惩罚。小车飞出屏幕范围,就是不好的结果。
- 奖励杆子保持直立,对于该机械结构而言,就是尽量接近目标位置 “0.0”。
- 奖励较低的小车速度。换句话说,就是鼓励慢速移动,保持平衡。
- 奖励较低的杆子速度。
@configclass
class RewardsCfg:
"""Reward terms for the MDP."""
# (1) Constant running reward
alive = RewTerm(func=mdp.is_alive, weight=1.0)
# (2) Failure penalty
terminating = RewTerm(func=mdp.is_terminated, weight=-2.0)
# (3) Primary task: keep pole upright
pole_pos = RewTerm(
func=mdp.joint_pos_target_l2,
weight=-1.0,
params={"asset_cfg": SceneEntityCfg("robot", joint_names=["cart_to_pole"]), "target": 0.0},
)
# (4) Shaping tasks: lower cart velocity
cart_vel = RewTerm(
func=mdp.joint_vel_l1,
weight=-0.01,
params={"asset_cfg": SceneEntityCfg("robot", joint_names=["slider_to_cart"])},
)
# (5) Shaping tasks: lower pole angular velocity
pole_vel = RewTerm(
func=mdp.joint_vel_l1,
weight=-0.005,
params={"asset_cfg": SceneEntityCfg("robot", joint_names=["cart_to_pole"])},
)在“Manager 工作流” 中,通过 func 参数传入实际计算奖励的函数。可以查看 mdp/rewards.py,或继续阅读,了解该函数的更多信息。
下面查看用于 joint_position 的奖励函数。关键在于,该函数不是只为一个环境计算奖励,而是为所有环境计算奖励!实际上,Isaac Lab 利用 PyTorch 张量,同时训练多个 Cartpole。
该函数内部的步骤如下:
- 从场景中获取 Articulation。Articulation 是定义 Cartpole 机械结构的一组物理关节。
- 将关节位置包裹到 -pi 到 pi 弧度范围内。
- 使用距离公式
(joint_pos - target)^2,返回输入张量中所有元素的总和。张量是可以在一个或多个维度中保存数值的数据容器。
注意
仔细观察,可以注意到有多个奖励函数,但只有一个在 rewards.py 中显式定义。为什么?
这是因为 Isaac Lab 提供若干通用奖励函数,因此无需在不同项目中重复定义。这些函数来自 mdp 包。点此查看可用函数的完整列表。
def joint_pos_target_l2(env: ManagerBasedRLEnv, target: float, asset_cfg: SceneEntityCfg) -> torch.Tensor:
"""Penalize joint position deviation from a target value."""
# extract the used quantities (to enable type-hinting)
asset: Articulation = env.scene[asset_cfg.name]
# wrap the joint positions to (-pi, pi)
joint_pos = wrap_to_pi(asset.data.joint_pos[:, asset_cfg.joint_ids])
# compute the reward
return torch.sum(torch.square(joint_pos - target), dim=1)5. 场景和环境配置
前面已经分别介绍主要组件:Manager 以及奖励函数背后的数学原理。下面看这些内容如何组合成训练场景。
首先是场景配置。
在此处,可以看到如何设置训练环境,从地平面,到机器人,再到穹顶灯。Isaac Lab 支持自定义训练环境本身,因此无需将灯光或其他仅在本次训练中需要的元素直接放到机器人的 USD 文件中。如果训练需要其他道具,比如要抓取的物体,也可以用类似的方式在这里添加。
@configclass
class CartpoleSceneCfg(InteractiveSceneCfg):
"""Configuration for a cart-pole scene."""
# ground plane
ground = AssetBaseCfg(
prim_path="/World/ground",
spawn=sim_utils.GroundPlaneCfg(size=(100.0, 100.0)),
)
# robot
robot: ArticulationCfg = CARTPOLE_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
# lights
dome_light = AssetBaseCfg(
prim_path="/World/DomeLight",
spawn=sim_utils.DomeLightCfg(color=(0.9, 0.9, 0.9), intensity=500.0),
)最后,在环境配置中汇集所有内容。
上面定义的所有 Manager 都将在此处被实例化。此外,此处还配置仿真器、抽取设置、时间设置以及回合长度。重点留意,Isaac Lab 如何控制 Isaac Sim 的部分功能,执行训练。
##
# Environment configuration
##
@configclass
class CartpoleEnvCfg(ManagerBasedRLEnvCfg):
# Scene settings
scene: CartpoleSceneCfg = CartpoleSceneCfg(num_envs=4096, env_spacing=4.0)
# Basic settings
observations: ObservationsCfg = ObservationsCfg()
actions: ActionsCfg = ActionsCfg()
events: EventCfg = EventCfg()
# MDP settings
rewards: RewardsCfg = RewardsCfg()
terminations: TerminationsCfg = TerminationsCfg()
# Post initialization
def __post_init__(self) -> None:
"""Post initialization."""
# general settings
self.decimation = 2
self.episode_length_s = 5
# viewer settings
self.viewer.eye = (8.0, 0.0, 5.0)
# simulation settings
self.sim.dt = 1 / 120
self.sim.render_interval = self.decimation由于 Isaac Lab 控制仿真器,因此我们拥有按时间“步进”仿真的特殊能力。仿真不是自由运行,而是可以暂停,执行一些工作,然后再步进一定时间,重复这一过程。