1.4训练第一个任务
训练第一个小任务:UR10 回到固定关节目标
一、任务目标
当前已经完成了:
- 新建 Isaac Lab 外部项目
- 将模板中的 Cartpole 替换成 UR10
- 让 UR10 环境能够正常启动和训练
接下来训练的第一个小任务是:
让 UR10 回到一组固定的目标关节角
这个任务的优点是:
- 不需要先处理末端坐标系
- 不需要先找末端 link
- 不需要先做逆运动学
- 只基于 6 个关节角就可以定义任务
二、任务思路
这个任务的核心逻辑很简单:
- 给 UR10 设定一组固定目标关节角
- 读取当前机械臂的 6 个关节角
- 计算当前关节角和目标关节角之间的误差
- 误差越小,奖励越高
- 通过训练,让机械臂逐渐靠近这组固定目标关节角
三、需要修改的文件
这一步主要修改 3 个地方:
1. mdp/rewards.py
2. mdp/__init__.py
3. ur10e_ocs_2_env_cfg.py四、修改 mdp/rewards.py
1. 作用
在这个文件里新增一个奖励函数,用来计算:
当前关节角和目标关节角之间的距离
距离越小,奖励越大。
2. 修改后的完整 mdp/rewards.py
# Copyright (c) 2022-2025, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import torch
from typing import TYPE_CHECKING
from isaaclab.assets import Articulation
from isaaclab.managers import SceneEntityCfg
from isaaclab.utils.math import wrap_to_pi
if TYPE_CHECKING:
from isaaclab.envs import ManagerBasedRLEnv
def joint_pos_target_l2(env: ManagerBasedRLEnv, target: float, asset_cfg: SceneEntityCfg) -> torch.Tensor:
"""惩罚关节位置偏离目标值的程度。"""
# 提取机器人对象
asset: Articulation = env.scene[asset_cfg.name]
# 将关节角限制到 (-pi, pi) 范围内
joint_pos = wrap_to_pi(asset.data.joint_pos[:, asset_cfg.joint_ids])
# 计算与目标值之间的平方误差和
return torch.sum(torch.square(joint_pos - target), dim=1)
def joint_pos_target_reward(
env: ManagerBasedRLEnv,
asset_cfg: SceneEntityCfg,
target: list[float],
) -> torch.Tensor:
"""根据机械臂当前关节角与固定目标关节角的接近程度给奖励。
说明:
- 当前关节角越接近目标关节角,误差越小
- 误差越小,返回的奖励越大
- 这里采用“负的平方误差和”作为奖励
"""
# 提取机器人对象
asset: Articulation = env.scene[asset_cfg.name]
# 读取当前选中关节的关节角
# shape: [num_envs, num_joints]
joint_pos = asset.data.joint_pos[:, asset_cfg.joint_ids]
# 将目标关节角列表转换成 tensor,并放到和 joint_pos 相同的设备上
target_tensor = torch.tensor(
target,
device=joint_pos.device,
dtype=joint_pos.dtype,
).unsqueeze(0)
# 计算每个环境中“当前关节角 - 目标关节角”的平方误差和
error = torch.sum(torch.square(joint_pos - target_tensor), dim=1)
# 误差越小越好,因此奖励取负值
return -error五、修改 mdp/__init__.py
1. 作用
为了让 ur10e_ocs_2_env_cfg.py 能够通过 mdp.xxx 的形式调用刚刚新增的奖励函数,需要把 rewards.py 中的内容导出。
2. 修改后的内容
至少有以下一条
from .rewards import *六、修改 ur10e_ocs_2_env_cfg.py
1. 修改 RewardsCfg
这里定义当前任务的奖励项。
当前第一个小任务只保留两个奖励项:
alive:基础存活奖励joint_target:核心任务奖励,鼓励机械臂接近目标关节角
修改为:
@configclass
class RewardsCfg:
"""MDP 的奖励项配置。"""
# 存活奖励:让环境保持一个基础奖励项
alive = RewTerm(func=mdp.is_alive, weight=0.2)
# 核心任务奖励:让 UR10 尽量接近固定目标关节角
joint_target = RewTerm(
func=mdp.joint_pos_target_reward,
weight=1.0,
params={
"asset_cfg": SceneEntityCfg(
"robot",
joint_names=[
"shoulder_pan_joint",
"shoulder_lift_joint",
"elbow_joint",
"wrist_1_joint",
"wrist_2_joint",
"wrist_3_joint",
],
),
"target": [0.0, -1.57, 1.57, -1.57, 0.0, 0.0],
},
)2. 修改 TerminationsCfg
当前阶段先不加复杂终止条件,只保留超时结束。
@configclass
class TerminationsCfg:
"""MDP 的终止条件配置。"""
# 超时结束
time_out = DoneTerm(func=mdp.time_out, time_out=True)3. EventCfg 保持 UR10 的 reset 逻辑
当前可以继续使用已经改好的 UR10 六关节 reset:
@configclass
class EventCfg:
"""环境事件配置。"""
reset_robot_joints = EventTerm(
func=mdp.reset_joints_by_offset,
mode="reset",
params={
"asset_cfg": SceneEntityCfg(
"robot",
joint_names=[
"shoulder_pan_joint",
"shoulder_lift_joint",
"elbow_joint",
"wrist_1_joint",
"wrist_2_joint",
"wrist_3_joint",
],
),
"position_range": (-0.1, 0.1),
"velocity_range": (-0.1, 0.1),
},
)4. ObservationsCfg 先保持不变
当前任务先使用关节位置和关节速度作为观测即可:
@configclass
class ObservationsCfg:
"""观测配置。"""
@configclass
class PolicyCfg(ObsGroup):
"""策略网络使用的观测。"""
# 关节相对位置
joint_pos_rel = ObsTerm(func=mdp.joint_pos_rel)
# 关节相对速度
joint_vel_rel = ObsTerm(func=mdp.joint_vel_rel)
def __post_init__(self) -> None:
self.enable_corruption = False
self.concatenate_terms = True
policy: PolicyCfg = PolicyCfg()七、固定目标关节角
当前任务设定的固定目标关节角为:
[0.0, -1.57, 1.57, -1.57, 0.0, 0.0]这组角度表示一个较为自然的机械臂弯曲姿态。
训练的目标就是让 UR10 尽量回到这一姿态。
八、运行前要检查的地方
开始训练前,需要先确认以下内容是否正确。
1. 检查 mdp/rewards.py
确认已经新增:
def joint_pos_target_reward(...)2. 检查 mdp/__init__.py
确认有:
from .rewards import *3. 检查 RewardsCfg
确认已经包含两个奖励项:
alivejoint_target
4. 检查 TerminationsCfg
确认当前只有:
time_out
九、运行指令
1. 先运行环境检查
先进入项目目录:
cd /home/isst/Action/04lab_example/ur10e_ocs_2然后运行随机策略检查环境:
python scripts/random_agent.py --task Template-Ur10e-Ocs-2-v0 --num_envs 64这一步的目的不是训练,而是确认:
- 环境能否正常启动
- 机械臂能否正常显示
- Reward Manager 是否已经识别
joint_target
2. 查看 Reward Manager 是否识别 joint_target
在环境启动日志中,找到 Reward Manager 表格。
理想情况下应该看到类似内容:
Reward Manager: contains 2 active terms
alive
joint_target如果日志中能看到:
alivejoint_target
说明奖励项已经正确接入环境。
3. 开始训练
确认环境正常后,开始训练:
python scripts/skrl/train.py --task Template-Ur10e-Ocs-2-v0 --num_envs 64十、训练结束后要查看的内容
训练结束后,主要看两部分:
1. 终端是否正常结束
如果训练完整跑完,通常会看到类似:
100% | 4800/4800
Simulation App Shutting Down如果只是最后有黄色 warning,但没有 traceback 和 error,一般属于正常结束。
2. TensorBoard 曲线
使用 TensorBoard 查看曲线:
tensorboard --logdir logs/skrl然后浏览器打开:
http://localhost:6006重点观察下面几类曲线:
Reward / Total reward (mean)Reward / Total reward (min)Reward / Total reward (max)Reward / Instantaneous reward (mean)Reward / Instantaneous reward (min)Reward / Instantaneous reward (max)
十一、如何判断训练是否有效
当前 reward 的核心是“负的关节误差”。
因此:
- reward 越接近 0,说明越接近目标关节角
- 如果 total reward 逐渐上升,说明机械臂在往目标关节角靠近
例如:
- 从
-33左右上升到-27左右
这就说明:
reward 已经在起作用,训练是有效的
但如果波动仍然很大,则说明:
- 训练时间还比较短
- 策略还不稳定
- 当前还只是初步学到一点方向
十二、训练结束后查看 checkpoint 的指令
1. 查找模型文件
find logs/skrl -name "*.pt"2. 查找最优模型
find logs/skrl -name "best_agent.pt"十三、回放训练结果
找到 best_agent.pt 后,可以用下面的方式回放:
python scripts/skrl/play.py --task Template-Ur10e-Ocs-2-v0 --num_envs 1 --checkpoint后跟best_agent.pt相对路径。
例如:
python scripts/skrl/play.py --task Template-Ur10e-Ocs-2-v0 --num_envs 1 --checkpoint logs/skrl/cartpole_direct/2026-04-02_19-16-52_ppo_torch/checkpoints/best_agent.pt十四、当前第一个小任务的结论
通过这一步,已经完成了:
- 搭建 UR10 最小可运行环境
- 为固定目标关节角定义奖励函数
- 成功启动训练
- 成功观察到 total reward 上升
- 成功得到第一个可回放的小任务结果
这说明:
第一个小任务已经成立,UR10 已经开始学习回到固定目标关节姿态。
