Skip to content

Overview for PAL Kangaroo Velocity Task


1. System Architecture

┌─────────────────────────────────────────────┐
│              mjlab (Framework)              │
│  - Environment Management                   │
│  - Observation / Action / Reward Manager    │
│  - Domain Randomization                     │
│  - RSL-RL Integration                       │
└─────────────────────────────────────────────┘
                    ↓
┌─────────────────────────────────────────────┐
│          MuJoCo Warp (GPU Backend)          │
│  - GPU-accelerated Physics                  │
│  - 8192 parallel environments on GPU        │
└─────────────────────────────────────────────┘
                    ↓
┌─────────────────────────────────────────────┐
│              MuJoCo (Physics)               │
│  - Contact Dynamics                         │
│  - Actuator Models                          │
│  - Constraint Solver                        │
└─────────────────────────────────────────────┘

2. Observation Space

Policy Group (Shape: 86)

Term Dim Description Noise
base_ang_vel 3 Root-link angular velocity ±0.2
joint_pos 26 Joint positions relative to default pose ±0.01
joint_vel 26 Joint velocities ±1.5
actions 22 Last actions (22 actuators) –
command 3 [vx_cmd, vy_cmd, wz_cmd] –
imu_projected_gravity 3 Gravity vector from IMU ±0.5
base_lin_acc 3 Linear acceleration from IMU ±0.5

base_lin_vel and projected_gravity are disabled in the policy.

Critic Group (Shape: 104)

Policy terms (without noise) + privileged information:

Term Dim Critic only
base_lin_vel 3 ✓
projected_gravity 3 ✓
foot_height 2 ✓
foot_air_time 2 ✓
foot_contact 2 ✓
foot_contact_forces 6 ✓

The critic receives no noise – it always sees the true values.

Observation Normalization

Both networks normalize their observations independently using running statistics:

ToDo: Running statistics could be problematic. We may want to get rid of it!

mean_t = β × mean_{t-1} + (1-β) × x_t
var_t  = β × var_{t-1}  + (1-β) × (x_t - mean_t)²

normalized_obs = (obs - mean) / sqrt(var + 1e-8)
  • actor_normalizer: EmpiricalNormalization(86)
  • critic_normalizer: EmpiricalNormalization(104)

3. Network Architecture

Network Architecture Parameters Activation
Policy 86→512→256→128→22 ~211K ELU
Critic 104→512→256→128→1 ~218K ELU

4. Action Pipeline

Todo: check whether clip() is a tanh?

NN Output  ∈ (−∞, +∞)
    ↓  clip(−1, +1)
a_clipped  ∈ [−1, +1]
    ↓  × action_scale
motor_target
    ↓  PD-Regler
τ = kp × (motor_target − q) + kd × (0 − q̇)
    ↓  clip(−effort_limit, +effort_limit)
τ_actual → MuJoCo

action_scale derivation (arm/torso motors):

action_scale = 0.25 × effort_limit / stiffness


5. Actuators – Motor Types

Global constants

NATURAL_FREQ  = 62.83 rad/s  (10 Hz)
DAMPING_RATIO = 2.0
FACTOR        = 0.05

S_PLUS Motor (Arm Joint 1–2, Pelvis)

gear_ratio    = 121
motor_inertia = 1.728×10⁻⁵ kg·m²
armature      = FACTOR × motor_inertia × gear_ratio² = 0.01264
stiffness     = armature × NATURAL_FREQ²             ≈ 50.0
damping       = 2 × DAMPING_RATIO × armature × NATURAL_FREQ ≈ 1.593

S_MINUS Motor (Arm Joint 3–4)

gear_ratio    = 101
motor_inertia = 1.3×10⁻⁵ kg·m²
armature      = 0.05 × 1.3e-5 × 101² = 0.00656
stiffness     ≈ 25.9
damping       ≈ 0.825

LEG Motor (direct parameterization, no gearbox model)

armature = 0.01 (fest)
damping  = 2 × DAMPING_RATIO × stiffness / NATURAL_FREQ

6. All 22 Actuators

Leg joints (12 joints, 6 per leg)

Joint kp kd Effort Armature Action Scale
leg_*/1_joint (hip abduction) 100.0 25.133 80 Nm 0.002540 0.200
leg_*/2_joint (hip pitch) 100.0 25.133 230 Nm 0.002540 0.575
leg_*/3_joint (hip roll) 100.0 25.133 139 Nm 0.002540 0.348
leg_*/4_joint (knee) 30.0 13.746 140 Nm 0.000762 1.167
leg_*/5_joint (ankle) 30.0 13.746 82 Nm 0.000762 0.683
leg_*/length_joint (telescopic) 1600.0 401.070 1100 Nm 0.040640 0.172

Arm joints (8 joints, 4 per arm)

Joint Motor kp kd Effort Armature Action Scale
arm_*/1_joint S_PLUS 578.962 288.506 43 Nm 0.014706 0.019
arm_*/2_joint S_PLUS 578.962 288.506 43 Nm 0.014706 0.019
arm_*/3_joint S_MINUS 399.425 199.174 43 Nm 0.010143 0.027
arm_*/4_joint S_MINUS 399.425 199.174 43 Nm 0.010143 0.027

Torso / pelvis (2 joints)

Joint Motor kp kd Effort Armature Action Scale
pelvis_1_joint S_PLUS 578.962 288.506 100 Nm 0.014706 0.043
pelvis_2_joint S_PLUS 578.962 288.506 100 Nm 0.014706 0.043

7. Joints – Overall

TOTAL: 26 joints
    ├─ 22 actuated joints  (controllable by the policy)
    └─  4 passive joints   (visible to the policy, but NOT controllable)

Passive joints:

  • leg_left_femur_joint
  • leg_left_knee_joint
  • leg_right_femur_joint
  • leg_right_knee_joint

The policy sees joint_pos and joint_vel for all 26 joints and therefore learns the kinematic coupling between active and passive joints.

8. Command Ranges & Curriculum

Stage Iterations lin_vel_x ang_vel_z
0 Start [−1.0, 1.0] m/s [−0.5, 0.5] rad/s
1 5 000 × 24 [−1.5, 2.0] m/s [−0.7, 0.7] rad/s
2 10 000 × 24 [−2.0, 3.0] m/s –

9. Reward Structure

Positive Rewards

Term Weight Formula
track_linear_velocity +2.0 exp(−‖v − v_cmd‖² / (2×0.5²))
track_angular_velocity +2.0 exp(−‖ω_z − ω_cmd‖² / (2×0.707²))
upright +1.0 exp(−(g_x² + g_y²) / 0.2)
default_pose +1.0 exp(−‖q − q_default‖² / (2σ²))
air_time +0.25 Rewards air time of 0.05–0.5 s (only for v_cmd > 0.5 m/s)

Negative Costs (Penalties)

Term Weight Description
joint_limits −1.0 Approaching soft limits (90% of hard limits)
action_rate_l2 −0.1 ‖a_t − a_{t-1}‖² – smooth actions
foot_clearance −2.0 Feet scraping the ground (target: 0.1 m height)
foot_swing_height −0.25 Swing motion too low
foot_slip −0.1 Slipping during ground contact
soft_landing −1e-5 Hard landings (high contact forces)
self_collisions −1.0 Self-collisions in the base_link subtree
body_ang_vel −0.05 ω_x² + ω_y² (yaw is not penalized)
angular_momentum −0.02 ‖L‖² (total angular momentum)
convex_hull_joint_limits_hip −10.0 Hip (pitch+roll) outside convex hull
convex_hull_joint_limits_ankle −10.0 Ankle (pitch+roll) outside convex hull

Adaptive Rewards (velocity-dependent)

cmd_vel Active additional rewards
= 0.0 Only tracking + upright + tight pose (standing)
0.05–0.5 m/s + foot_clearance, foot_slip, foot_swing
0.5–1.5 m/s + air_time
> 1.5 m/s Looser pose tolerances (running)

Pose Tolerances (velocity-dependent)

Mode Condition Tolerance σ
Standing v_cmd < 0.05 m/s all joints: 0.05 (tight)
Walking 0.05 ≤ v < 1.5 m/s legs: 0.1–0.3, torso: 0.08–0.2
Running v ≥ 1.5 m/s legs: 0.15–0.5, torso: 0.08–0.3

10. Termination Conditions

Condition Criterion
time_out 1000 control steps = 20 seconds (timestep: 0.002 s, decimation: 10)
fell_over Tilt > 70°: \|arccos(−g_z)\| > 1.222 rad
illegal_contact Femur or knee touches the ground → immediate termination
NaN/Inf Invalid physics state → automatic

11. Domain Randomization

Startup (once per episode)

ToDo: Is this once per epsiode or once per env?

Event Field Range
foot_friction geom_friction [0.3, 1.2]
joint_friction dof_frictionloss ±0.008 Nm
mass body_mass ±0.2 kg (pelvis_2_link)
base_com body_ipos ±0.025 m (XY), ±0.03 m (Z)
encoder_bias all joints except leg_length ±0.015 rad (≈ ±0.86°)
leg_length_encoder_bias leg_*/length_joint ±0.005 rad (≈ ±0.29°)

Reset (at every episode start)

Event Range
reset_base Position: ±0.5 m (XY), yaw: [−π, π]
reset_robot_joints Default pose, velocity = 0

Interval (every 1–3 seconds during the episode)

Event Linear Angular
push_robot ±0.5 m/s (X, Y, Z) ±0.52 rad/s (roll/pitch), ±0.78 rad/s (yaw)

push_robot is disabled in play mode.

Batch Parallelization

model_field[environment_id, entity_id, axis]

8192 environments run in parallel on the GPU, each with independently sampled parameters.


12. PPO Training

Hyperparameters

Parameter Value
learning_rate 1e-3
schedule adaptive (KL-based)
clip_param (ε) 0.2
num_learning_epochs 5
num_mini_batches 4
gamma (discount) 0.99
lam (GAE λ) 0.95
value_loss_coef 1.0
entropy_coef 0.01
max_grad_norm 1.0
desired_kl 0.01
num_steps_per_env 24
num_envs 8192
max_iterations 30 000

Training Scale

Steps per Update = 24 × 8192        = 196 608
Mini-Batch Size  = 196608 / 4       =  49 152
Total Steps      = 30000 × 196608   ≈ 5.9 Mrd.

PPO Loss

L(θ) = L^CLIP − value_loss_coef × L^VF + entropy_coef × L^ENT
     = L^CLIP − 1.0 × L^VF + 0.01 × L^ENT

Policy Loss (Clipped Surrogate):

r_t(θ) = π_θ(a|s) / π_θ_old(a|s)
L^CLIP  = −E[min(r_t × A_t, clip(r_t, 1−ε, 1+ε) × A_t)]

Value Loss:

V_clipped = V_old + clip(V_θ − V_old, −ε, +ε)
L^VF      = E[max((V_θ − R_t)², (V_clipped − R_t)²)]

Entropy Bonus:

L^ENT = −E[H(π_θ)] = −E[Σ π_θ(a|s) × log(π_θ(a|s))]

Generalized Advantage Estimation (GAE)

δ_t = r_t + γ × V(s_{t+1}) × (1 − done) − V(s_t)
A_t = Σ_{l=0}^∞ (γλ)^l × δ_{t+l}
R_t = A_t + V(s_t)
λ Property
0 Low variance, high bias (1-step TD)
1 High variance, low bias (Monte Carlo)
0.95 Good compromise

Adaptive Learning Rate

if   KL > 2 × desired_kl:   lr × 0.5   (decrease)
elif KL < desired_kl / 2:   lr × 2.0   (increase)

lr = clip(lr, 1e-5, 1e-3)