cleaning up to keep changes minimal

This commit is contained in:
Maxime Ellerbach
2026-07-23 15:46:14 +00:00
parent a19730768f
commit 6399803b66
3 changed files with 8 additions and 132 deletions
+1 -84
View File
@@ -252,93 +252,10 @@ def test_create_inference_engine_sync():
# ---------------------------------------------------------------------------
# Observation feature-spec consistency (sync vs RTC)
#
# ``build_dataset_frame`` orders the ``observation.state`` vector by the ``names``
# list of the feature spec it is handed. Sync uses ``dataset_features`` (joint
# layout AFTER ``robot_observation_processor``); RTC must use the SAME spec, not the
# raw-hardware layout, or its state vector desyncs from sync — corrupting both the
# normalizer's per-joint stats and the relative-action anchor, which sends the arm
# to systematically wrong absolute targets.
# RTC action-key ordering and prefix padding
# ---------------------------------------------------------------------------
def test_build_dataset_frame_state_layout_depends_on_feature_spec():
"""A reordered feature spec yields a reordered ``observation.state`` vector."""
import numpy as np
from lerobot.utils.feature_utils import build_dataset_frame, hw_to_dataset_features
# Raw hardware joint order.
obs_hw = {"shoulder.pos": float, "elbow.pos": float, "wrist.pos": float, "gripper.pos": float}
hw_features = hw_to_dataset_features(obs_hw, "observation")
# What a ``robot_observation_processor`` that reorders state keys would produce
# (e.g. gripper moved to the front). Same keys, different order.
dataset_features = {
"observation.state": {
"dtype": "float32",
"shape": (4,),
"names": ["gripper.pos", "shoulder.pos", "elbow.pos", "wrist.pos"],
}
}
values = {"shoulder.pos": 10.0, "elbow.pos": 20.0, "wrist.pos": 30.0, "gripper.pos": 40.0}
hw_state = build_dataset_frame(hw_features, values, prefix="observation")["observation.state"]
ds_state = build_dataset_frame(dataset_features, values, prefix="observation")["observation.state"]
np.testing.assert_array_equal(hw_state, [10.0, 20.0, 30.0, 40.0])
np.testing.assert_array_equal(ds_state, [40.0, 10.0, 20.0, 30.0])
# The two layouts genuinely differ: this is the sync/RTC divergence the fix removes.
assert not np.array_equal(hw_state, ds_state)
def test_create_inference_engine_rtc_uses_dataset_features():
"""The RTC engine must build observations from ``dataset_features`` (sync's spec),
not the raw-hardware ``hw_features`` — so its ``observation.state`` matches sync."""
from lerobot.rollout import RTCInferenceConfig, RTCInferenceEngine, create_inference_engine
dataset_features = {
"observation.state": {
"dtype": "float32",
"shape": (4,),
"names": ["gripper.pos", "shoulder.pos", "elbow.pos", "wrist.pos"],
}
}
# Deliberately different order to prove the engine ignores it.
hw_features = {
"observation.state": {
"dtype": "float32",
"shape": (4,),
"names": ["shoulder.pos", "elbow.pos", "wrist.pos", "gripper.pos"],
}
}
engine = create_inference_engine(
RTCInferenceConfig(),
policy=MagicMock(),
# No relative/normalizer steps => __init__ introspection stays trivial.
preprocessor=MagicMock(steps=[]),
postprocessor=MagicMock(steps=[]),
robot_wrapper=MagicMock(robot_type="mock"),
hw_features=hw_features,
dataset_features=dataset_features,
ordered_action_keys=["k"],
task="test",
fps=30.0,
device="cpu",
)
assert isinstance(engine, RTCInferenceEngine)
assert engine._obs_features is dataset_features
assert engine._obs_features["observation.state"]["names"] == [
"gripper.pos",
"shoulder.pos",
"elbow.pos",
"wrist.pos",
]
def test_rtc_get_action_remaps_model_order_to_ordered_action_keys():
"""RTC must remap the model-order action vector to ``ordered_action_keys`` by NAME
before returning — matching sync. Otherwise the strategy maps model outputs onto the