✨ update motor friction
This commit is contained in:
@@ -6,11 +6,14 @@ urdf: rotary_cartpole.urdf
|
|||||||
actuators:
|
actuators:
|
||||||
- joint: motor_joint
|
- joint: motor_joint
|
||||||
type: motor # direct torque control
|
type: motor # direct torque control
|
||||||
gear: 0.1 # torque multiplier (was 0.5 — too weak, caused bang-bang)
|
gear: 0.064 # stall torque @ 58.8% PWM: 0.108 × 150/255 = 0.064 N·m
|
||||||
ctrl_range: [-1.0, 1.0]
|
ctrl_range: [-1.0, 1.0]
|
||||||
damping: 0.02 # motor friction / back-EMF (was 0.1 — ate torque budget)
|
damping: 0.003 # viscous back-EMF only (small)
|
||||||
filter_tau: 0.18 # 1st-order filter ~180ms (models motor inertia)
|
filter_tau: 0.03 # mechanical time constant ~30ms (37mm gearmotor)
|
||||||
|
|
||||||
joints:
|
joints:
|
||||||
|
motor_joint:
|
||||||
|
armature: 0.0001 # reflected rotor inertia: ~1e-7 × 30² = 9e-5 kg·m²
|
||||||
|
frictionloss: 0.03 # disabled — may slow MJX (constraint-based solver)
|
||||||
pendulum_joint:
|
pendulum_joint:
|
||||||
damping: 0.0001 # bearing friction
|
damping: 0.0001 # bearing friction
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ class ActuatorConfig:
|
|||||||
class JointConfig:
|
class JointConfig:
|
||||||
"""Per-joint overrides applied on top of the URDF values."""
|
"""Per-joint overrides applied on top of the URDF values."""
|
||||||
damping: float | None = None
|
damping: float | None = None
|
||||||
|
armature: float | None = None # reflected rotor inertia (kg·m²)
|
||||||
|
frictionloss: float | None = None # Coulomb/dry friction torque (N·m)
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
|
|||||||
@@ -132,14 +132,17 @@ class MJXRunner(BaseRunner[MJXRunnerConfig]):
|
|||||||
# ── Batched step (N substeps per call) ──────────────────────
|
# ── Batched step (N substeps per call) ──────────────────────
|
||||||
@jax.jit
|
@jax.jit
|
||||||
def step_fn(data):
|
def step_fn(data):
|
||||||
|
# Software limit switch: clamp ctrl once before substeps.
|
||||||
|
# Armature + default joint limits prevent significant overshoot
|
||||||
|
# within the substep window, so per-substep clamping isn't needed.
|
||||||
|
pos = data.qpos[:, act_jnt_ids]
|
||||||
|
ctrl = data.ctrl
|
||||||
|
at_hi = act_limited & (pos >= act_hi) & (act_gs * ctrl > 0)
|
||||||
|
at_lo = act_limited & (pos <= act_lo) & (act_gs * ctrl < 0)
|
||||||
|
clamped = jnp.where(at_hi | at_lo, 0.0, ctrl)
|
||||||
|
data = data.replace(ctrl=clamped)
|
||||||
|
|
||||||
def body(_, d):
|
def body(_, d):
|
||||||
# Software limit switch: zero ctrl pushing past joint limits
|
|
||||||
pos = d.qpos[:, act_jnt_ids] # (num_envs, nu)
|
|
||||||
ctrl = d.ctrl
|
|
||||||
at_hi = act_limited & (pos >= act_hi) & (act_gs * ctrl > 0)
|
|
||||||
at_lo = act_limited & (pos <= act_lo) & (act_gs * ctrl < 0)
|
|
||||||
clamped = jnp.where(at_hi | at_lo, 0.0, ctrl)
|
|
||||||
d = d.replace(ctrl=clamped)
|
|
||||||
return jax.vmap(mjx.step, in_axes=(None, 0))(model, d)
|
return jax.vmap(mjx.step, in_axes=(None, 0))(model, d)
|
||||||
|
|
||||||
return jax.lax.fori_loop(0, substeps, body, data)
|
return jax.lax.fori_loop(0, substeps, body, data)
|
||||||
|
|||||||
@@ -146,15 +146,25 @@ class MuJoCoRunner(BaseRunner[MuJoCoRunnerConfig]):
|
|||||||
# ── Apply joint overrides from robot.yaml ───────────────
|
# ── Apply joint overrides from robot.yaml ───────────────
|
||||||
# Merge actuator damping + explicit joint overrides
|
# Merge actuator damping + explicit joint overrides
|
||||||
joint_damping = {a.joint: a.damping for a in robot.actuators}
|
joint_damping = {a.joint: a.damping for a in robot.actuators}
|
||||||
|
joint_armature: dict[str, float] = {}
|
||||||
|
joint_frictionloss: dict[str, float] = {}
|
||||||
for name, jcfg in robot.joints.items():
|
for name, jcfg in robot.joints.items():
|
||||||
if jcfg.damping is not None:
|
if jcfg.damping is not None:
|
||||||
joint_damping[name] = jcfg.damping
|
joint_damping[name] = jcfg.damping
|
||||||
|
if jcfg.armature is not None:
|
||||||
|
joint_armature[name] = jcfg.armature
|
||||||
|
if jcfg.frictionloss is not None:
|
||||||
|
joint_frictionloss[name] = jcfg.frictionloss
|
||||||
|
|
||||||
for body in root.iter("body"):
|
for body in root.iter("body"):
|
||||||
for jnt in body.findall("joint"):
|
for jnt in body.findall("joint"):
|
||||||
name = jnt.get("name")
|
name = jnt.get("name")
|
||||||
if name in joint_damping:
|
if name in joint_damping:
|
||||||
jnt.set("damping", str(joint_damping[name]))
|
jnt.set("damping", str(joint_damping[name]))
|
||||||
|
if name in joint_armature:
|
||||||
|
jnt.set("armature", str(joint_armature[name]))
|
||||||
|
if name in joint_frictionloss:
|
||||||
|
jnt.set("frictionloss", str(joint_frictionloss[name]))
|
||||||
|
|
||||||
# Disable self-collision on all geoms.
|
# Disable self-collision on all geoms.
|
||||||
# URDF mesh convex hulls often overlap at joints (especially
|
# URDF mesh convex hulls often overlap at joints (especially
|
||||||
@@ -164,14 +174,10 @@ class MuJoCoRunner(BaseRunner[MuJoCoRunnerConfig]):
|
|||||||
geom.set("contype", "0")
|
geom.set("contype", "0")
|
||||||
geom.set("conaffinity", "0")
|
geom.set("conaffinity", "0")
|
||||||
|
|
||||||
# Harden joint limits: MuJoCo's default soft limits are too
|
# Joint limits use MuJoCo's default solver settings.
|
||||||
# weak and allow overshoot. Negative solref = hard constraint
|
# The software limit switch (zeroing ctrl at limits) + armature
|
||||||
# (direct stiffness/damping instead of impedance match).
|
# prevent overshoot without needing ultra-stiff solref that
|
||||||
for body in root.iter("body"):
|
# kills MJX GPU solver performance.
|
||||||
for jnt in body.findall("joint"):
|
|
||||||
if jnt.get("limited") == "true" or jnt.get("range"):
|
|
||||||
jnt.set("solreflimit", "-100000 -10000")
|
|
||||||
jnt.set("solimplimit", "0.99 0.999 0.001")
|
|
||||||
|
|
||||||
# Step 4: Write modified MJCF and reload from file path
|
# Step 4: Write modified MJCF and reload from file path
|
||||||
# (from_xml_path resolves mesh paths relative to the file location)
|
# (from_xml_path resolves mesh paths relative to the file location)
|
||||||
|
|||||||
Reference in New Issue
Block a user