https://www.hackster.io/agilexrobotics/train-a-dual-arm-nero-reach-task-in-isaac-lab-33bfe5

We integrate the AgileX Dual-Arm Nero into Isaac Lab, enabling fast RL training and validation of robust dual-arm manipulation policies.
我们将 AgileX 双臂 Nero 集成到 Isaac Lab 中,从而能够快速进行强化学习训练,并验证稳健的双臂操作策略。

Beginner
Full instructions provided
1 hour
51

初学者完整操作说明 1 小时 51
Things used in this project
本项目使用的物料
Hardware components 硬件组件
NERO
× 1
Software apps and online services
软件应用与在线服务
Isaac Lab
Story 故事
Robotic manipulation remains one of the most important research directions in embodied AI. While traditional kinematics-based controllers provide stable motion execution, they often struggle in unstructured environments where adaptability is required.
机器人操作仍然是具身智能中最重要的研究方向之一。虽然传统的基于运动学的控制器能够提供稳定的运动执行,但在需要适应性的非结构化环境中,它们往往力不从心。

Recent advances in Reinforcement Learning (RL) have enabled robotic arms to learn task-oriented behaviors directly from interaction, making it possible to achieve robust control policies without manually designing every motion strategy.
强化学习(RL)的最新进展使机械臂能够直接从交互中学习面向任务的行为,从而无需手动设计每一个运动策略即可实现稳健的控制策略。

In this project, we extend the original SO-ARM101 Isaac Lab implementation by integrating the AgileX Dual-Arm Nero Manipulator, allowing developers to quickly train and validate dual-arm RL policies using NVIDIA Isaac Lab.
在本项目中,我们扩展了原始的 SO-ARM101 Isaac Lab 实现,集成了 AgileX 双臂 Nero 机械臂,使开发者能够使用 NVIDIA Isaac Lab 快速训练和验证双臂强化学习策略。

Reposity 代码仓库
Open-source implementation:
开源实现:

https://github.com/smalleha/isaac_so_arm101.git

Project Structure 项目结构

├── robots

│   ├── dual_nero

│   │   ├── dual_nero.py

│   │   ├── __init__.py

│   │   ├── meshes

│   │   └── urdf

│   │       └── dual_nero.urdf

├── scripts

│   ├── rl_games

│   │   ├── play.py

│   │   └── train.py

│   └── zero_agent.py

├── tasks

│   ├── __init__.py

│   └── reach

│       ├── agents

│       ├── dual_nero_joint_pos_env_cfg.py

│       ├── dual_nero_reach_env_cfg.py

│       ├── __init__.py

│       └── mdp

└── ui_extension_example.py

Key additions include: 主要新增内容包括:

  1. Importing the Robot into Isaac Lab
  2. 将机器人导入 Isaac Lab
    3.1 Preparing the URDF 3.1 准备 URDF
    Before importing the robot into Isaac Lab, mesh references inside the URDF should be converted to relative paths.
    在将机器人导入 Isaac Lab 之前,应将 URDF 中的网格引用转换为相对路径。

For example: 例如:

<inertial>

  <origin rpy="0 0 0" xyz="-0.0592395620981769 -0.068642440505388 0.0562764736144042"/>

  <mass value="4.46524857458863"/>

  <inertia ixx="0.0608289280191989" ixy="-2.54649959130438E-06" ixz="1.11851948046933E-07" iyy="0.0218722514454004" iyz="-0.000689477252402357" izz="0.0680524540174318"/>

</inertial>

<visual>

  <origin rpy="0 0 0" xyz="0 0 0"/>

  <geometry>

    <mesh filename="../meshes/base_link.dae"/>

  </geometry>

  <material name="">

    <color rgba="0.776470588235294 0.756862745098039 0.737254901960784 1"/>

  </material>

</visual>

<collision>

  <origin rpy="0 0 0" xyz="0 0 0"/>

  <geometry>

    <mesh filename="../meshes/base_link.dae"/>

  </geometry>

</collision>
This ensures that the asset loader can correctly locate mesh resources during simulation. 这确保了资源加载器在仿真过程中能够正确定位网格资源。

3.2 Creating the Robot Configuration
3.2 创建机器人配置
Next, create a robot configuration file:
接下来,创建一个机器人配置文件:

isaac_so_arm101/robots/dual_nero/dual_nero.py
This file defines: 该文件定义了:

Robot articulation properties
机器人关节属性
Joint stiffness and damping
关节刚度与阻尼
Actuator configuration 执行器配置
Initial joint states 初始关节状态
Gripper settings 夹爪设置
The resulting DUAL_NERO_CFG object becomes the robot asset used by Isaac Lab during training.
生成的 DUAL_NERO_CFG 对象成为 Isaac Lab 在训练期间使用的机器人资源。

from pathlib import Path

import isaaclab.sim as sim_utils
from isaaclab.actuators import ImplicitActuatorCfg
from isaaclab.assets.articulation import ArticulationCfg

TEMPLATE_ASSETS_DATA_DIR = Path(file).resolve().parent

DUAL_NERO_CFG = ArticulationCfg(
spawn=sim_utils.UrdfFileCfg(
fix_base=True,
merge_fixed_joints=False,
replace_cylinders_with_capsules=True,
asset_path=f"{TEMPLATE_ASSETS_DATA_DIR}/urdf/dual_nero.urdf",
activate_contact_sensors=False, # set as false while waiting for capsule implementation
rigid_props=sim_utils.RigidBodyPropertiesCfg(
disable_gravity=False,
max_depenetration_velocity=5.0,
),
articulation_props=sim_utils.ArticulationRootPropertiesCfg(
enabled_self_collisions=True,
solver_position_iteration_count=8,
solver_velocity_iteration_count=0,
),
joint_drive=sim_utils.UrdfConverterCfg.JointDriveCfg(
gains=sim_utils.UrdfConverterCfg.JointDriveCfg.PDGainsCfg(stiffness=0, damping=0)
),
),
init_state=ArticulationCfg.InitialStateCfg(
rot=(1.0, 0.0, 0.0, 0.0),
joint_pos={
“left_joint.": 0.0,
"right_joint.
”: 0.0,
“left_gripper_joint.": 0.0,
"right_gripper_joint.
”: 0.0,
},
# Set initial joint velocities to zero
joint_vel={“.": 0.0},
),
actuators={
“arm”: ImplicitActuatorCfg(
joint_names_expr=["left_joint.
”, “right_joint.*”],
effort_limit=25.0,
velocity_limit=1.5,

            stiffness={
                "left_joint1": 200.0, 
                "left_joint2": 170.0,
                "left_joint3": 120.0,
                "left_joint4": 80.0,
                "left_joint5": 50.0,
                "left_joint6": 20.0,
                "left_joint7": 10.0,
                "right_joint1": 200.0, 
                "right_joint2": 170.0,
                "right_joint3": 120.0,
                "right_joint4": 80.0,
                "right_joint5": 50.0,
                "right_joint6": 20.0,
                "right_joint7": 10.0
            },
           
            damping={
                "left_joint1": 100.0,
                "left_joint2": 60.0,
                "left_joint3": 70.0,
                "left_joint4": 24.0,
                "left_joint5": 20.0,
                "left_joint6": 10.0,
                "left_joint7": 5,
                "right_joint1": 100.0,
                "right_joint2": 60.0,
                "right_joint3": 70.0,
                "right_joint4": 24.0,
                "right_joint5": 20.0,
                "right_joint6": 10.0,
                "right_joint7": 5,
            },
        ),
    "gripper": ImplicitActuatorCfg(
        joint_names_expr=["left_gripper_joint.*","right_gripper_joint.*"],
        effort_limit_sim=22,  # Increased from 1.9 to 2.5 for stronger grip
        velocity_limit_sim=1.5,
        stiffness=800.0,  # Increased from 25.0 to 60.0 for more reliable closing
        damping=20.0,  # Increased from 10.0 to 20.0 for stability
    ),

    },
soft_joint_pos_limit_factor=0.9,

)
Create an init.py file inside the dual_nero directory so that Python recognizes it as a package.
在 dual_nero 目录内创建一个 init.py 文件,以便 Python 将其识别为一个包。

  1. Building the Reach Environment
  2. 构建到达环境
    Two environment configuration files are required:
    需要两个环境配置文件:

tasks/reach/

├── dual_nero_joint_pos_env_cfg.py

└── dual_nero_reach_env_cfg.py
4.1 Joint Position Environment Configuration
4.1 关节位置环境配置

dual_nero_joint_pos_env_cfg.py specifies: dual_nero_joint_pos_env_cfg.py 指定:

Controlled joints 受控关节
End-effector links 末端执行器连杆
Action spaces 动作空间
Command targets 指令目标
import math

import isaaclab_tasks.manager_based.manipulation.reach.mdp as mdp
from isaaclab.utils import configclass
from isaac_so_arm101.robots import DUAL_NERO_CFG # noqa: F401
from isaac_so_arm101.tasks.reach.dual_nero_reach_env_cfg import Dual_NeroReachEnvCfg
from isaaclab.assets.articulation import ArticulationCfg

@configclass
class Dual_Nero_ReachEnvCfg(Dual_NeroReachEnvCfg):
def post_init(self):
# post init of parent
super().post_init()

    # switch robot to OpenArm
    self.scene.robot = DUAL_NERO_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot",)

    # override rewards
    self.rewards.left_end_effector_position_tracking.params["asset_cfg"].body_names = ["left_gripper_base"]
    self.rewards.left_end_effector_position_tracking_fine_grained.params["asset_cfg"].body_names = [
        "left_gripper_base"
    ]
    self.rewards.left_end_effector_orientation_tracking.params["asset_cfg"].body_names = ["left_gripper_base"]

    self.rewards.right_end_effector_position_tracking.params["asset_cfg"].body_names = ["right_gripper_base"]
    self.rewards.right_end_effector_position_tracking_fine_grained.params["asset_cfg"].body_names = [
        "right_gripper_base"
    ]
    self.rewards.right_end_effector_orientation_tracking.params["asset_cfg"].body_names = ["right_gripper_base"]

    # override actions
    self.actions.left_arm_action = mdp.JointPositionActionCfg(
        asset_name="robot",
        joint_names=[
            "left_joint.*",
        ],
        scale=0.5,
        use_default_offset=True,
    )

    self.actions.right_arm_action = mdp.JointPositionActionCfg(
        asset_name="robot",
        joint_names=[
            "right_joint.*",
        ],
        scale=0.5,
        use_default_offset=True,
    )
    # override command generator body
    # end-effector is along z-direction
    self.commands.left_ee_pose.body_name = "left_gripper_base"
    self.commands.right_ee_pose.body_name = "right_gripper_base"

@configclass
class Dual_Nero_ReachEnvCfg_PLAY(Dual_Nero_ReachEnvCfg):
def post_init(self):
# post init of parent
super().post_init()
# make a smaller scene for play
self.scene.num_envs = 50
self.scene.env_spacing = 2.5
# disable randomization for play
self.observations.policy.enable_corruption = False
4.2 Reach Task Definition
4.2 到达任务定义
dual_nero_reach_env_cfg.py contains the full RL environment definition.
dual_nero_reach_env_cfg.py 包含完整的强化学习环境定义。

This includes: 这包括:

1.Scene Configuration 1. 场景配置

Ground plane 地面平面
Lighting 光照
Robot asset 机器人资源
2.Command Generation 2. 命令生成

3.Observation Space 3. 观测空间

4.Reward Design 4. 奖励设计

5.Curriculum Learning 5. 课程学习

6.Episode Settings 6. 回合设置

import math
from dataclasses import MISSING

import isaaclab.sim as sim_utils
from isaaclab.assets import ArticulationCfg, AssetBaseCfg
from isaaclab.envs import ManagerBasedRLEnvCfg
from isaaclab.managers import ActionTermCfg as ActionTerm
from isaaclab.managers import CurriculumTermCfg as CurrTerm
from isaaclab.managers import EventTermCfg as EventTerm
from isaaclab.managers import ObservationGroupCfg as ObsGroup
from isaaclab.managers import ObservationTermCfg as ObsTerm
from isaaclab.managers import RewardTermCfg as RewTerm
from isaaclab.managers import SceneEntityCfg
from isaaclab.managers import TerminationTermCfg as DoneTerm
from isaaclab.scene import InteractiveSceneCfg
from isaaclab.utils import configclass
from isaaclab.utils.noise import AdditiveUniformNoiseCfg as Unoise

import isaaclab_tasks.manager_based.manipulation.reach.mdp as mdp

Scene definition

@configclass
class Dual_NeroReachSceneCfg(InteractiveSceneCfg):
“”“Configuration for the scene with a robotic arm.”“”

# world
ground = AssetBaseCfg(
    prim_path="/World/ground",
    spawn=sim_utils.GroundPlaneCfg(),
    init_state=AssetBaseCfg.InitialStateCfg(pos=(0.0, 0.0, 0)),
)

# robots
robot: ArticulationCfg = MISSING

# lights
light = AssetBaseCfg(
    prim_path="/World/light",
    spawn=sim_utils.DomeLightCfg(color=(0.75, 0.75, 0.75), intensity=2500.0),
)

MDP settings

@configclass
class CommandsCfg:
“”“Command terms for the MDP.”“”

left_ee_pose = mdp.UniformPoseCommandCfg(
    asset_name="robot",
    body_name=MISSING,
    resampling_time_range=(4.0, 4.0),
    debug_vis=True,
    ranges=mdp.UniformPoseCommandCfg.Ranges(
        pos_x=(0.5, 0.5),
        pos_y=(0.15, 0.25),
        pos_z=(0.3, 0.5),
        roll=(-math.pi / 6, math.pi / 6),
        pitch=(3 * math.pi / 2, 3 * math.pi / 2),
        yaw=(8 * math.pi / 9, 10 * math.pi / 9),
    ),
)

right_ee_pose = mdp.UniformPoseCommandCfg(
    asset_name="robot",
    body_name=MISSING,
    resampling_time_range=(4.0, 4.0),
    debug_vis=True,
    ranges=mdp.UniformPoseCommandCfg.Ranges(
        pos_x=(0.5, 0.5),
        pos_y=(-0.25, -0.15),
        pos_z=(0.3, 0.5),
        roll=(-math.pi / 6, math.pi / 6),
        pitch=(3 * math.pi / 2, 3 * math.pi / 2),
        yaw=(8 * math.pi / 9, 10 * math.pi / 9),
    ),
)

@configclass
class ActionsCfg:
“”“Action specifications for the MDP.”“”
left_arm_action: ActionTerm = MISSING
right_arm_action: ActionTerm = MISSING
@configclass
class ObservationsCfg:
“”“Observation specifications for the MDP.”“”

@configclass
class PolicyCfg(ObsGroup):
    """Observations for policy group."""

    # observation terms (order preserved)
    left_joint_pos = ObsTerm(
        func=mdp.joint_pos_rel,
        params={
            "asset_cfg": SceneEntityCfg(
                "robot",
                joint_names=[
                    "left_joint.*",
                ],
            )
        },
        noise=Unoise(n_min=-0.01, n_max=0.01),
    )

    right_joint_pos = ObsTerm(
        func=mdp.joint_pos_rel,
        params={
            "asset_cfg": SceneEntityCfg(
                "robot",
                joint_names=[
                    "right_joint.*",
                ],
            )
        },
        noise=Unoise(n_min=-0.01, n_max=0.01),
    )

    left_joint_vel = ObsTerm(
        func=mdp.joint_vel_rel,
        params={
            "asset_cfg": SceneEntityCfg(
                "robot",
                joint_names=[
                    "left_joint.*",
                ],
            )
        },
        noise=Unoise(n_min=-0.01, n_max=0.01),
    )
    right_joint_vel = ObsTerm(
        func=mdp.joint_vel_rel,
        params={
            "asset_cfg": SceneEntityCfg(
                "robot",
                joint_names=[
                    "right_joint.*",
                ],
            )
        },
        noise=Unoise(n_min=-0.01, n_max=0.01),
    )
    left_pose_command = ObsTerm(func=mdp.generated_commands, params={"command_name": "left_ee_pose"})
    right_pose_command = ObsTerm(func=mdp.generated_commands, params={"command_name": "right_ee_pose"})
    left_actions = ObsTerm(func=mdp.last_action, params={"action_name": "left_arm_action"})
    right_actions = ObsTerm(func=mdp.last_action, params={"action_name": "right_arm_action"})

    def __post_init__(self):
        self.enable_corruption = True
        self.concatenate_terms = True

# observation groups
policy: PolicyCfg = PolicyCfg()

@configclass
class EventCfg:
“”“Configuration for events.”“”

reset_robot_joints = EventTerm(
    func=mdp.reset_joints_by_scale,
    mode="reset",
    params={
        "position_range": (0.5, 1.5),
        "velocity_range": (0.0, 0.0),
    },
)

@configclass
class RewardsCfg:
“”“Reward terms for the MDP.”“”
left_end_effector_position_tracking = RewTerm(
func=mdp.position_command_error,
weight=-0.2,
params={
“asset_cfg”: SceneEntityCfg(“robot”, body_names=MISSING),
“command_name”: “left_ee_pose”,
},
)
right_end_effector_position_tracking = RewTerm(
func=mdp.position_command_error,
weight=-0.25,
params={
“asset_cfg”: SceneEntityCfg(“robot”, body_names=MISSING),
“command_name”: “right_ee_pose”,
},
)
left_end_effector_position_tracking_fine_grained = RewTerm(
func=mdp.position_command_error_tanh,
weight=0.1,
params={
“asset_cfg”: SceneEntityCfg(“robot”, body_names=MISSING),
“std”: 0.1,
“command_name”: “left_ee_pose”,
},
)
right_end_effector_position_tracking_fine_grained = RewTerm(
func=mdp.position_command_error_tanh,
weight=0.2,
params={
“asset_cfg”: SceneEntityCfg(“robot”, body_names=MISSING),
“std”: 0.1,
“command_name”: “right_ee_pose”,
},
)
left_end_effector_orientation_tracking = RewTerm(
func=mdp.orientation_command_error,
weight=-0.1,
params={
“asset_cfg”: SceneEntityCfg(“robot”, body_names=MISSING),
“command_name”: “left_ee_pose”,
},
)

right_end_effector_orientation_tracking = RewTerm(
    func=mdp.orientation_command_error,
    weight=-0.1,
    params={
        "asset_cfg": SceneEntityCfg("robot", body_names=MISSING),
        "command_name": "right_ee_pose",
    },
)
# action penalty
action_rate = RewTerm(func=mdp.action_rate_l2, weight=-0.0001)
left_joint_vel = RewTerm(
    func=mdp.joint_vel_l2,
    weight=-0.0001,
    params={
        "asset_cfg": SceneEntityCfg(
            "robot",
            joint_names=[
                "left_joint.*",
            ],
        )
    },
)
right_joint_vel = RewTerm(
    func=mdp.joint_vel_l2,
    weight=-0.0001,
    params={
        "asset_cfg": SceneEntityCfg(
            "robot",
            joint_names=[
                "right_joint.*",
            ],
        )
    },
)

@configclass
class TerminationsCfg:
“”“Termination terms for the MDP.”“”
time_out = DoneTerm(func=mdp.time_out, time_out=True)
@configclass
class CurriculumCfg:
“”“Curriculum terms for the MDP.”“”
action_rate = CurrTerm(
func=mdp.modify_reward_weight,
params={“term_name”: “action_rate”, “weight”: -0.005, “num_steps”: 4500},
)

left_joint_vel = CurrTerm(
    func=mdp.modify_reward_weight,
    params={"term_name": "left_joint_vel", "weight": -0.001, "num_steps": 4500},
)

right_joint_vel = CurrTerm(
    func=mdp.modify_reward_weight,
    params={"term_name": "right_joint_vel", "weight": -0.001, "num_steps": 4500},
)

Environment configuration

@configclass
class Dual_NeroReachEnvCfg(ManagerBasedRLEnvCfg):
“”“Configuration for the reach end-effector pose tracking environment.”“”
# Scene settings
scene: Dual_NeroReachSceneCfg = Dual_NeroReachSceneCfg(num_envs=4096, env_spacing=2.5)
# Basic settings
observations: ObservationsCfg = ObservationsCfg()
actions: ActionsCfg = ActionsCfg()
commands: CommandsCfg = CommandsCfg()
# MDP settings
rewards: RewardsCfg = RewardsCfg()
terminations: TerminationsCfg = TerminationsCfg()
events: EventCfg = EventCfg()
curriculum: CurriculumCfg = CurriculumCfg()

def __post_init__(self):
    """Post initialization."""
    # general settings
    self.decimation = 2
    self.sim.render_interval = self.decimation
    self.episode_length_s = 24.0
    self.viewer.eye = (3.5, 3.5, 3.5)
    # simulation settings
    self.sim.dt = 1.0 / 60.0

```

### 4.3 Registering the Environment

Register the task inside:`src/isaac_so_arm101/tasks/reach/_init_.py`

```PYTHON

gym.register(

id="Isaac-Dual-Nero-Reach-v0",

entry_point="isaaclab.envs:ManagerBasedRLEnv",

kwargs={

    "env_cfg_entry_point":f"{\__name_\_}.dual_nero_joint_pos_env_cfg:Dual_Nero_ReachEnvCfg",

    "rsl_rl_cfg_entry_point": f"{agents.\__name_\_}.rsl_rl_ppo_cfg:ReachPPORunnerCfg",

    "rl_games_cfg_entry_point": f"{agents.\__name_\_}:rl_games_ppo_cfg.yaml",



},

disable_env_checker=True,

)
5. Training the Reach Policy
5. 训练到达策略
Step 1.Activate the Isaac Lab Environment
第 1 步:激活 Isaac Lab 环境

conda activate env_isaaclab
Step 2.Navigate to the project directory:
第 2 步:导航到项目目录:

cd isaac_so_arm101
Step 3.Train the whole project
第 3 步:训练整个项目

Option 1:RSL-RL 选项 1:RSL-RL

Train: 训练:
uv run train \

--task Isaac-Dual-Nero-Reach-v0 \

--headless

Evaluate: 评估:
uv run play \

--task Isaac-Dual-Nero-Reach-v0

Training result: 训练结果:
dual_nero_rsl_rl.gif
Option 2: RL-Games 选项 2:RL-Games

Train: 训练:
python3 scripts/rl_games/train.py
–task Isaac-Dual-Nero-Reach-v0
–headless
Evaluate: 评估:
python3 scripts/rl_games/play.py
–task Isaac-Dual-Nero-Reach-v0
Training result: 训练结果:
dual_nero_rl_games.gif
6. Results and Observations
6. 结果与观察
Both frameworks successfully learn the dual-arm reaching task.
两个框架均成功学习了双臂伸展任务。

However, in our experiments:
然而,在我们的实验中:

RL-Games converges faster
RL-Games 收敛速度更快
Motion trajectories appear smoother
运动轨迹看起来更平滑
Final reaching accuracy is generally higher
最终到达精度通常更高
For relatively complex robot morphologies such as dual-arm manipulators, RL-Games currently provides more stable performance and is recommended as the default training backend.
对于双臂机械臂等相对复杂的机器人形态,RL-Games 目前提供更稳定的性能,建议作为默认训练后端。

FAQ 常见问题解答
Q1: Why is my Dual-Nero robot collapsing or shaking violently after loading the URDF?
Q1:为什么我的双 Nero 机器人在加载 URDF 后会出现倒塌或剧烈抖动?

This is usually caused by incorrect actuator parameters or unrealistic inertial properties.
这通常是由不正确的执行器 Parameter 或不符合实际的惯性属性引起的。

Common causes include: 常见原因包括:

Joint stiffness set too high
关节刚度设置过高
Damping values too low 阻尼值过低
Incorrect mass distribution in the URDF
URDF 中的质量分布不正确
Self-collision configuration issues
自碰撞配置问题
Unstable simulation timestep
不稳定的仿真时间步长
Before starting RL training, verify that the robot can remain stable under gravity using only PD control.
在开始强化学习训练之前,请验证机器人仅使用 PD 控制能否在重力作用下保持稳定。

Quick check: If the robot cannot stand still without RL, the issue is likely in the robot model rather than the training algorithm.
快速检查:如果机器人在没有强化学习的情况下无法保持静止,问题很可能出在机器人模型上,而非训练算法。

Q2: Why does the reward improve, but the robot never reaches the target accurately?
Q2:为什么奖励在提升,但机器人从未准确到达目标?

A rising reward does not always indicate successful task completion.
奖励的上升并不总是意味着任务成功完成。

Typical reasons include: 常见原因包括:

Reward weights are unbalanced
奖励权重不平衡
Orientation rewards dominate position rewards
方向奖励主导了位置奖励
Action penalties are too strong
动作惩罚过强
Command sampling range is too large
指令采样范围过大
End-effector link is incorrectly configured
末端执行器连杆配置错误
In most reach tasks, incorrect reward shaping is the primary reason for poor final accuracy.
在大多数到达任务中,错误的奖励塑形是导致最终精度不佳的主要原因。

Q3: How do I verify that the end-effector link is configured correctly?
问题 3:如何验证末端执行器链接配置正确?

One of the most common mistakes in Isaac Lab reach tasks is assigning the wrong end-effector body.
在 Isaac Lab 到达任务中,最常见的错误之一是指定了错误的末端执行器主体。

For Dual-Nero, the target link should be:
对于双 Nero,目标链接应为:

left_gripper_base

right_gripper_base
Symptoms of an incorrect configuration include:
配置错误的表现包括:

Reward remains low 奖励值持续偏低
Robot moves randomly 机器人随机移动
Training appears to converge but fails visually
训练看似收敛,但实际效果不佳
End-effector does not move toward the target marker
末端执行器未朝目标标记移动
Always verify the body name in Isaac Sim before launching large-scale training.
在启动大规模训练之前,务必在 Isaac Sim 中验证主体名称。

Q4: Why does RL-Games perform better than RSL-RL for this task?
问题 4:为什么 RL-Games 在此任务中表现优于 RSL-RL?

Both frameworks are PPO-based, but their implementations differ.
两个框架均基于 PPO,但它们的实现方式有所不同。

For large-scale manipulation environments:
对于大规模操作环境:

RL-Games generally scales better with thousands of parallel environments
RL-Games 通常能更好地扩展到数千个并行环境

PPO updates are often more stable
PPO 更新通常更稳定

Training throughput is higher on modern GPUs
在现代 GPU 上训练吞吐量更高

For Dual-Nero reach experiments, RL-Games typically achieves smoother trajectories and faster convergence.
对于双 Nero 到达实验,RL-Games 通常能实现更平滑的轨迹和更快的收敛。

However, results may vary depending on reward design and task complexity.
然而,结果可能因奖励设计和任务复杂度而有所不同。

Q5: My policy works in simulation but fails on the real robot. Why?
问题 5:我的策略在仿真中有效,但在真实机器人上失败。为什么?

This is the most common Sim-to-Real issue.
这是最常见的仿真到现实迁移问题。

Possible causes include: 可能的原因包括:

Joint friction mismatch 关节摩擦力不匹配
Encoder noise 编码器噪声
Latency differences Latency 差异
Payload variations 负载变化
Inaccurate motor models 不准确的电机模型
Unmodeled cable effects 未建模的线缆效应
To improve transfer performance:
为提升迁移性能:

Apply domain randomization
应用域随机化
Add observation noise 添加观测噪声
Randomize dynamics parameters
随机化动力学参数
Validate trajectories at low speed first
先在低速下验证轨迹
Successful simulation training is only the first step toward real-world deployment.
成功的仿真训练只是迈向真实世界部署的第一步。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐