mirror of
https://github.com/huggingface/lerobot.git
synced 2026-07-29 20:49:42 +00:00
restore gravity_compensation
This commit is contained in:
@@ -83,6 +83,9 @@ class UnitreeG1Config(RobotConfig):
|
|||||||
# Cameras (ZMQ-based remote cameras)
|
# Cameras (ZMQ-based remote cameras)
|
||||||
cameras: dict[str, CameraConfig] = field(default_factory=dict)
|
cameras: dict[str, CameraConfig] = field(default_factory=dict)
|
||||||
|
|
||||||
|
# Compensates for gravity on the unitree's arms using the arm ik solver
|
||||||
|
gravity_compensation: bool = False
|
||||||
|
|
||||||
# When False, connect() does not start the background controller thread, so a
|
# When False, connect() does not start the background controller thread, so a
|
||||||
# caller can drive the controller synchronously (one decode per fed action),
|
# caller can drive the controller synchronously (one decode per fed action),
|
||||||
# reproducing the deploy's single 50Hz control clock for faithful replay.
|
# reproducing the deploy's single 50Hz control clock for faithful replay.
|
||||||
|
|||||||
@@ -99,11 +99,6 @@ REMOTE_AXES = ("remote.lx", "remote.ly", "remote.rx", "remote.ry")
|
|||||||
REMOTE_BUTTONS = tuple(f"remote.button.{i}" for i in range(16))
|
REMOTE_BUTTONS = tuple(f"remote.button.{i}" for i in range(16))
|
||||||
REMOTE_KEYS = REMOTE_AXES + REMOTE_BUTTONS
|
REMOTE_KEYS = REMOTE_AXES + REMOTE_BUTTONS
|
||||||
|
|
||||||
# Reserved action-dict field used to forward the set of currently-pressed keyboard
|
|
||||||
# keys from a KeyboardTeleop through the standard action pipeline to a controller.
|
|
||||||
KEYBOARD_KEYS_FIELD = "keyboard.keys"
|
|
||||||
|
|
||||||
|
|
||||||
def default_remote_input() -> dict[str, float]:
|
def default_remote_input() -> dict[str, float]:
|
||||||
"""Return a zeroed-out remote input dict (axes + buttons)."""
|
"""Return a zeroed-out remote input dict (axes + buttons)."""
|
||||||
return dict.fromkeys(REMOTE_KEYS, 0.0)
|
return dict.fromkeys(REMOTE_KEYS, 0.0)
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ from lerobot.utils.import_utils import _unitree_sdk_available, require_package
|
|||||||
|
|
||||||
from ..robot import Robot
|
from ..robot import Robot
|
||||||
from .config_unitree_g1 import UnitreeG1Config
|
from .config_unitree_g1 import UnitreeG1Config
|
||||||
|
from .g1_kinematics import G1_29_ArmIK
|
||||||
from .g1_utils import (
|
from .g1_utils import (
|
||||||
KEYBOARD_KEYS_FIELD,
|
|
||||||
REMOTE_AXES,
|
REMOTE_AXES,
|
||||||
G1_29_JointArmIndex,
|
G1_29_JointArmIndex,
|
||||||
G1_29_JointIndex,
|
G1_29_JointIndex,
|
||||||
@@ -161,6 +161,9 @@ class UnitreeG1(Robot):
|
|||||||
self._client_state_latest: dict[str, float] = {}
|
self._client_state_latest: dict[str, float] = {}
|
||||||
self._client_caps: dict | None = None
|
self._client_caps: dict | None = None
|
||||||
|
|
||||||
|
# Optional arm gravity compensation (feed-forward torque via the arm IK solver).
|
||||||
|
self.arm_ik = G1_29_ArmIK() if config.gravity_compensation else None
|
||||||
|
|
||||||
# Initialize state variables
|
# Initialize state variables
|
||||||
self.sim_env = None
|
self.sim_env = None
|
||||||
self._env_wrapper = None
|
self._env_wrapper = None
|
||||||
@@ -815,30 +818,34 @@ class UnitreeG1(Robot):
|
|||||||
if key.endswith(".q") and key.startswith(arm_prefixes)
|
if key.endswith(".q") and key.startswith(arm_prefixes)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.publish_lowcmd(action_to_publish)
|
tau = None
|
||||||
|
if self.config.gravity_compensation and self.arm_ik is not None:
|
||||||
|
tau = np.zeros(29, dtype=np.float32)
|
||||||
|
action_np = np.array(
|
||||||
|
[
|
||||||
|
action_to_publish.get(f"{joint.name}.q", self.msg.motor_cmd[joint.value].q)
|
||||||
|
for joint in G1_29_JointArmIndex
|
||||||
|
],
|
||||||
|
dtype=np.float32,
|
||||||
|
)
|
||||||
|
arm_tau = self.arm_ik.solve_tau(action_np)
|
||||||
|
arm_start_idx = G1_29_JointArmIndex.kLeftShoulderPitch.value
|
||||||
|
for joint in G1_29_JointArmIndex:
|
||||||
|
local_idx = joint.value - arm_start_idx
|
||||||
|
tau[joint.value] = arm_tau[local_idx]
|
||||||
|
|
||||||
|
self.publish_lowcmd(action_to_publish, tau=tau)
|
||||||
return action
|
return action
|
||||||
|
|
||||||
def _update_controller_action(self, action: RobotAction) -> None:
|
def _update_controller_action(self, action: RobotAction) -> None:
|
||||||
"""Update controller input state from an incoming teleop action.
|
"""Update controller input state from an incoming teleop action.
|
||||||
|
|
||||||
Controller-agnostic: every value-carrying key is forwarded verbatim into
|
Controller-agnostic: every value-carrying key (e.g. locomotion ``remote.*``
|
||||||
``controller_input`` (whole-body ``wb.{i}.pos`` from a 34-D VLA, or whatever a
|
axes/buttons) is forwarded verbatim into ``controller_input`` and each
|
||||||
future controller expects), and each controller extracts only the keys it
|
controller extracts only the keys it understands. The robot deliberately does
|
||||||
understands. The robot deliberately does not enumerate any controller's key
|
not enumerate any controller's key schema here.
|
||||||
schema here.
|
|
||||||
|
|
||||||
KeyboardTeleop is the one special case: it emits the currently-pressed keys as
|
|
||||||
bare action keys with a ``None`` value (``dict.fromkeys(pressed, None)``), so
|
|
||||||
those are collected into a single held-key set under ``KEYBOARD_KEYS_FIELD``,
|
|
||||||
rebuilt each tick so releases clear. Special keys arrive as pynput objects and
|
|
||||||
are normalised to their name ("space", ...).
|
|
||||||
"""
|
"""
|
||||||
with self._controller_action_lock:
|
with self._controller_action_lock:
|
||||||
self.controller_input[KEYBOARD_KEYS_FIELD] = {
|
|
||||||
(k if isinstance(k, str) else getattr(k, "name", str(k)))
|
|
||||||
for k, value in action.items()
|
|
||||||
if value is None
|
|
||||||
}
|
|
||||||
for key, value in action.items():
|
for key, value in action.items():
|
||||||
if isinstance(key, str) and value is not None:
|
if isinstance(key, str) and value is not None:
|
||||||
self.controller_input[key] = value
|
self.controller_input[key] = value
|
||||||
|
|||||||
Reference in New Issue
Block a user