Skip to content

Commit 1d6fbf2

Browse files
committed
feat: G1 per-joint kp/kd domain randomization (issue #129)
1 parent 9215af0 commit 1d6fbf2

6 files changed

Lines changed: 43 additions & 14 deletions

File tree

‎conf/offpolicy/task/sac/g1_sac/motrix.yaml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ algo:
1111
algo_params:
1212
alpha_init: 0.001
1313
target_entropy_ratio: 0.0
14+
env:
15+
domain_rand:
16+
randomize_kp: false
17+
randomize_kd: false
1418
reward:
1519
scales:
1620
tracking_lin_vel: 2.2

‎conf/ppo/task/g1_joystick/motrix.yaml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ algo:
1616
entropy_coef: 5.0e-3
1717
env:
1818
iterations: 3
19+
domain_rand:
20+
randomize_kp: false
21+
randomize_kd: false
1922
control_config:
2023
action_scale: 0.5
2124
commands:

‎src/unilab/base/backend/mujoco_backend.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,12 @@ def _translate_reset_randomization(
467467

468468
return translated or None
469469

470+
def get_actuator_gains(self) -> tuple[np.ndarray, np.ndarray]:
471+
"""Return per-joint (kp, kd) arrays read from the current model state."""
472+
kp = np.asarray(self._model.actuator_gainprm[:, 0], dtype=np.float64).copy()
473+
kd = np.asarray(-self._model.actuator_biasprm[:, 2], dtype=np.float64).copy()
474+
return kp, kd
475+
470476
def _apply_position_actuator_gains_to_model(
471477
self,
472478
model,

‎src/unilab/dr/dr_utils.py‎

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,24 @@ def build_common_reset_randomization(env: Any, num_reset: int) -> ResetRandomiza
3333
payload.base_com_offset = base_com_offset
3434

3535
num_actuators = getattr(env, "_num_action", None)
36-
if num_actuators is not None and getattr(domain_rand, "randomize_kp", False):
37-
low, high = domain_rand.kp_multiplier_range
38-
kp_multiplier = np.random.uniform(low, high, size=(num_reset, 1))
39-
base_kp = float(env.cfg.control_config.Kp)
40-
payload.kp = np.broadcast_to(base_kp * kp_multiplier, (num_reset, num_actuators)).copy()
41-
42-
if num_actuators is not None and getattr(domain_rand, "randomize_kd", False):
43-
low, high = domain_rand.kd_multiplier_range
44-
kd_multiplier = np.random.uniform(low, high, size=(num_reset, 1))
45-
base_kd = float(env.cfg.control_config.Kd)
46-
payload.kd = np.broadcast_to(base_kd * kd_multiplier, (num_reset, num_actuators)).copy()
36+
need_kp = num_actuators is not None and getattr(domain_rand, "randomize_kp", False)
37+
need_kd = num_actuators is not None and getattr(domain_rand, "randomize_kd", False)
38+
39+
if need_kp or need_kd:
40+
backend = getattr(env, "_backend", None)
41+
if backend is not None and hasattr(backend, "get_actuator_gains"):
42+
base_kp, base_kd = backend.get_actuator_gains()
43+
else:
44+
base_kp = np.full(num_actuators, float(env.cfg.control_config.Kp))
45+
base_kd = np.full(num_actuators, float(env.cfg.control_config.Kd))
46+
47+
if need_kp:
48+
low, high = domain_rand.kp_multiplier_range
49+
payload.kp = (base_kp * np.random.uniform(low, high, (num_reset, 1))).astype(np.float64)
50+
51+
if need_kd:
52+
low, high = domain_rand.kd_multiplier_range
53+
payload.kd = (base_kd * np.random.uniform(low, high, (num_reset, 1))).astype(np.float64)
4754

4855
return None if payload.is_empty() else payload
4956

‎src/unilab/envs/locomotion/g1/joystick.py‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@
2222
from unilab.envs.locomotion.g1.base import G1BaseCfg, G1BaseEnv
2323

2424

25+
@dataclass
26+
class G1DomainRandConfig(DomainRandConfig):
27+
randomize_kp: bool = True
28+
kp_multiplier_range: list[float] = field(default_factory=lambda: [0.9, 1.1])
29+
30+
randomize_kd: bool = True
31+
kd_multiplier_range: list[float] = field(default_factory=lambda: [0.9, 1.1])
32+
33+
2534
@dataclass
2635
class InitState:
2736
pos = [0.0, 0.0, 0.754]
@@ -107,7 +116,7 @@ class G1JoystickPPOCfg(G1BaseCfg):
107116
init_state: InitState = field(default_factory=InitState)
108117
commands: Commands = field(default_factory=Commands)
109118
reward_config: RewardConfigPPO | None = None
110-
domain_rand: DomainRandConfig = field(default_factory=DomainRandConfig)
119+
domain_rand: G1DomainRandConfig = field(default_factory=G1DomainRandConfig)
111120
gait_phase_init_mode: str = "offset_phase"
112121
reset_base_qvel_limit: float = 0.5
113122

‎src/unilab/envs/locomotion/g1/joystick_sac.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
from unilab.base.dtype_config import get_global_dtype
1515
from unilab.envs.locomotion.common import rewards
1616
from unilab.envs.locomotion.common.commands import Commands
17-
from unilab.envs.locomotion.common.domain_rand import DomainRandConfig
1817
from unilab.envs.locomotion.common.rewards import RewardContext
1918
from unilab.envs.locomotion.g1.base import G1BaseCfg, G1BaseEnv
2019
from unilab.envs.locomotion.g1.joystick import (
20+
G1DomainRandConfig,
2121
G1JoystickDomainRandomizationProvider,
2222
G1JoystickPPO,
2323
InitState,
@@ -55,7 +55,7 @@ class G1JoystickSACCfg(G1BaseCfg):
5555
init_state: InitState = field(default_factory=InitState)
5656
commands: Commands = field(default_factory=Commands)
5757
control_config: ControlConfigSAC = field(default_factory=ControlConfigSAC) # type: ignore[assignment]
58-
domain_rand: DomainRandConfig = field(default_factory=DomainRandConfig)
58+
domain_rand: G1DomainRandConfig = field(default_factory=G1DomainRandConfig)
5959
gait_phase_init_mode: str = "offset_phase"
6060
reset_base_qvel_limit: float = 0.5
6161

0 commit comments

Comments
 (0)