mirror of
https://github.com/huggingface/lerobot.git
synced 2026-07-20 00:11:59 +00:00
Add Foxglove display mode to lerobot-record
Wire the --display_mode flag (rerun|foxglove) into lerobot-record, matching lerobot-teleoperate: route init/log through the backend-agnostic dispatchers and stop the visualization backend on exit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
CarolinePascal
parent
3062bf0548
commit
5ed0981bc5
@@ -38,6 +38,9 @@ lerobot-record \\
|
|||||||
--display_data=true
|
--display_data=true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To stream the data to Foxglove instead of Rerun, add ``--display_mode=foxglove`` (then connect the
|
||||||
|
Foxglove app to ``ws://127.0.0.1:8765``; override the port with ``--display_port=<port>``).
|
||||||
|
|
||||||
Example recording with bimanual so100:
|
Example recording with bimanual so100:
|
||||||
```shell
|
```shell
|
||||||
lerobot-record \\
|
lerobot-record \\
|
||||||
@@ -157,7 +160,11 @@ from lerobot.utils.utils import (
|
|||||||
init_logging,
|
init_logging,
|
||||||
log_say,
|
log_say,
|
||||||
)
|
)
|
||||||
from lerobot.utils.visualization_utils import init_rerun, log_rerun_data
|
from lerobot.utils.visualization_utils import (
|
||||||
|
init_visualization,
|
||||||
|
log_visualization_data,
|
||||||
|
shutdown_visualization,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -168,11 +175,14 @@ class RecordConfig:
|
|||||||
teleop: TeleoperatorConfig | None = None
|
teleop: TeleoperatorConfig | None = None
|
||||||
# Display all cameras on screen
|
# Display all cameras on screen
|
||||||
display_data: bool = False
|
display_data: bool = False
|
||||||
# Display data on a remote Rerun server
|
# Visualization backend used when display_data is True: "rerun" or "foxglove".
|
||||||
|
# "foxglove" starts a WebSocket server (default ws://127.0.0.1:8765) to stream data to the Foxglove app.
|
||||||
|
display_mode: str = "rerun"
|
||||||
|
# For "rerun": IP of a remote Rerun server to connect to. Unused by "foxglove".
|
||||||
display_ip: str | None = None
|
display_ip: str | None = None
|
||||||
# Port of the remote Rerun server
|
# For "rerun": port of the remote Rerun server. For "foxglove": port to bind the WebSocket server to.
|
||||||
display_port: int | None = None
|
display_port: int | None = None
|
||||||
# Whether to display compressed images in Rerun
|
# Whether to display compressed (JPEG) images instead of raw frames
|
||||||
display_compressed_images: bool = False
|
display_compressed_images: bool = False
|
||||||
# Use vocal synthesis to read events.
|
# Use vocal synthesis to read events.
|
||||||
play_sounds: bool = True
|
play_sounds: bool = True
|
||||||
@@ -233,6 +243,7 @@ def record_loop(
|
|||||||
control_time_s: int | None = None,
|
control_time_s: int | None = None,
|
||||||
single_task: str | None = None,
|
single_task: str | None = None,
|
||||||
display_data: bool = False,
|
display_data: bool = False,
|
||||||
|
display_mode: str = "rerun",
|
||||||
display_compressed_images: bool = False,
|
display_compressed_images: bool = False,
|
||||||
):
|
):
|
||||||
if dataset is not None and dataset.fps != fps:
|
if dataset is not None and dataset.fps != fps:
|
||||||
@@ -327,8 +338,11 @@ def record_loop(
|
|||||||
dataset.add_frame(frame)
|
dataset.add_frame(frame)
|
||||||
|
|
||||||
if display_data:
|
if display_data:
|
||||||
log_rerun_data(
|
log_visualization_data(
|
||||||
observation=obs_processed, action=action_values, compress_images=display_compressed_images
|
display_mode,
|
||||||
|
observation=obs_processed,
|
||||||
|
action=action_values,
|
||||||
|
compress_images=display_compressed_images,
|
||||||
)
|
)
|
||||||
|
|
||||||
dt_s = time.perf_counter() - start_loop_t
|
dt_s = time.perf_counter() - start_loop_t
|
||||||
@@ -354,7 +368,9 @@ def record(
|
|||||||
init_logging()
|
init_logging()
|
||||||
logging.info(pformat(asdict(cfg)))
|
logging.info(pformat(asdict(cfg)))
|
||||||
if cfg.display_data:
|
if cfg.display_data:
|
||||||
init_rerun(session_name="recording", ip=cfg.display_ip, port=cfg.display_port)
|
init_visualization(
|
||||||
|
cfg.display_mode, session_name="recording", ip=cfg.display_ip, port=cfg.display_port
|
||||||
|
)
|
||||||
display_compressed_images = (
|
display_compressed_images = (
|
||||||
True
|
True
|
||||||
if (cfg.display_data and cfg.display_ip is not None and cfg.display_port is not None)
|
if (cfg.display_data and cfg.display_ip is not None and cfg.display_port is not None)
|
||||||
@@ -464,6 +480,7 @@ def record(
|
|||||||
control_time_s=cfg.dataset.episode_time_s,
|
control_time_s=cfg.dataset.episode_time_s,
|
||||||
single_task=cfg.dataset.single_task,
|
single_task=cfg.dataset.single_task,
|
||||||
display_data=cfg.display_data,
|
display_data=cfg.display_data,
|
||||||
|
display_mode=cfg.display_mode,
|
||||||
display_compressed_images=display_compressed_images,
|
display_compressed_images=display_compressed_images,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -485,6 +502,7 @@ def record(
|
|||||||
control_time_s=cfg.dataset.reset_time_s,
|
control_time_s=cfg.dataset.reset_time_s,
|
||||||
single_task=cfg.dataset.single_task,
|
single_task=cfg.dataset.single_task,
|
||||||
display_data=cfg.display_data,
|
display_data=cfg.display_data,
|
||||||
|
display_mode=cfg.display_mode,
|
||||||
)
|
)
|
||||||
|
|
||||||
if events["rerecord_episode"]:
|
if events["rerecord_episode"]:
|
||||||
@@ -510,6 +528,9 @@ def record(
|
|||||||
if listener is not None:
|
if listener is not None:
|
||||||
listener.stop()
|
listener.stop()
|
||||||
|
|
||||||
|
if cfg.display_data:
|
||||||
|
shutdown_visualization(cfg.display_mode)
|
||||||
|
|
||||||
if cfg.dataset.push_to_hub:
|
if cfg.dataset.push_to_hub:
|
||||||
if dataset and dataset.num_episodes > 0:
|
if dataset and dataset.num_episodes > 0:
|
||||||
dataset.push_to_hub(tags=cfg.dataset.tags, private=cfg.dataset.private)
|
dataset.push_to_hub(tags=cfg.dataset.tags, private=cfg.dataset.private)
|
||||||
|
|||||||
Reference in New Issue
Block a user