[skip ci] feat: implement rerun v0.1

This commit is contained in:
Steven Palma 2025-03-24 17:11:59 +01:00
parent 1f7ddc1d76
commit 4f3eaff2bd
No known key found for this signature in database
3 changed files with 191 additions and 0 deletions

View File

@ -0,0 +1,31 @@
# Copyright 2024 The HuggingFace Inc. team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from dataclasses import dataclass, field
from lerobot.common.cameras.configs import CameraConfig
from lerobot.common.cameras.opencv.configuration_opencv import OpenCVCameraConfig
from lerobot.common.robots.config import RobotConfig
@RobotConfig.register_subclass("dummy")
@dataclass
class DummyConfig(RobotConfig):
id = "dummy"
cameras: dict[str, CameraConfig] = field(
default_factory=lambda: {
"cam": OpenCVCameraConfig(camera_index=0, fps=30, width=1280, height=720),
}
)

View File

@ -0,0 +1,101 @@
# Copyright 2024 The HuggingFace Inc. team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import numpy as np
from lerobot.common.cameras.utils import make_cameras_from_configs
from lerobot.common.constants import OBS_STATE
from lerobot.common.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError
from ..robot import Robot
from .configuration_dummy import DummyConfig
class Dummy(Robot):
config_class = DummyConfig
name = "dummy"
def __init__(self, config: DummyConfig):
super().__init__(config)
self.cameras = make_cameras_from_configs(config.cameras)
self.is_connected = False
@property
def state_feature(self) -> dict:
logging.warning("Dummy has nothing to send.")
@property
def action_feature(self) -> dict:
logging.warning("Dummy has nothing to send.")
@property
def camera_features(self) -> dict[str, dict]:
cam_ft = {
"cam": {
"shape": (480, 640, 3),
"names": ["height", "width", "channels"],
"info": None,
},
}
return cam_ft
def connect(self) -> None:
if self.is_connected:
raise DeviceAlreadyConnectedError(
"Dummy is already connected. Do not run `robot.connect()` twice."
)
logging.info("Connecting cameras.")
for cam in self.cameras.values():
cam.connect()
self.is_connected = True
def calibrate(self) -> None:
logging.warning("Dummy has nothing to calibrate.")
return
def get_observation(self) -> dict[str, np.ndarray]:
if not self.is_connected:
raise DeviceNotConnectedError("Dummy is not connected. You need to run `robot.connect()`.")
obs_dict = {}
for cam_key, cam in self.cameras.items():
frame = cam.async_read()
obs_dict[f"{OBS_STATE}.{cam_key}"] = frame
return obs_dict
def send_action(self, action: np.ndarray) -> np.ndarray:
logging.warning("Dummy has nothing to send.")
def print_logs(self):
pass
def disconnect(self):
if not self.is_connected:
raise DeviceNotConnectedError(
"Dummy is not connected. You need to run `robot.connect()` before disconnecting."
)
for cam in self.cameras.values():
cam.disconnect()
self.is_connected = False
def __del__(self):
if getattr(self, "is_connected", False):
self.disconnect()

View File

@ -0,0 +1,59 @@
# Copyright 2024 The HuggingFace Inc. team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import rerun as rr
from lerobot.common.robots.dummy.configuration_dummy import DummyConfig
from lerobot.common.robots.dummy.dummy import Dummy
from lerobot.common.teleoperators.so100 import SO100Teleop, SO100TeleopConfig
def main():
logging.info("Configuring Devices")
leader_arm_config = SO100TeleopConfig(port="/dev/tty.usbmodem58760434171")
leader_arm = SO100Teleop(leader_arm_config)
robot_config = DummyConfig()
robot = Dummy(robot_config)
logging.info("Connecting SO100 Devices")
leader_arm.connect()
logging.info("Connecting Dummy")
robot.connect()
rr.init("rerun_dummy_data")
rr.spawn(memory_limit="50%") # add a bluprint config
logging.info("Starting...")
i = 0
while i < 10000:
arm_action = leader_arm.get_action()
observation = robot.get_observation()
for j in range(arm_action.size):
rr.log(f"arm_action_{j}", rr.Scalar(arm_action[j]))
for k, v in observation.items():
rr.log(k, rr.Image(v))
i += 1
robot.disconnect()
leader_arm.disconnect()
if __name__ == "__main__":
main()