From cff0347fb2f5449ae4c720df5864b770273d4820 Mon Sep 17 00:00:00 2001 From: Remi Cadene Date: Mon, 29 Jul 2024 17:17:02 +0200 Subject: [PATCH] improve --- examples/7_get_started_with_real_robot.md | 32 +++++++++++-------- .../common/robot_devices/motors/dynamixel.py | 2 +- lerobot/common/utils/utils.py | 1 + lerobot/scripts/control_robot.py | 6 ++-- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/examples/7_get_started_with_real_robot.md b/examples/7_get_started_with_real_robot.md index 8225e666..320a314b 100644 --- a/examples/7_get_started_with_real_robot.md +++ b/examples/7_get_started_with_real_robot.md @@ -56,7 +56,7 @@ python lerobot/common/robot_devices/motors/dynamixel.py >>> Reconnect the usb cable. ``` -Then you can instantiate each arm by listing their motors with their name, motor index, and model. The initial motor index from factory for every motors is `1`. However, unique indices are required for these motors to function in a chain on a common bus. To this end, we set different indices and follow the ascendant convention starting from index `1`. These indices will be written inside the persisting memory of each motor during the first connection. Here is an example of what the instantiation looks like: +Then you can instantiate each arm by listing their motors with their name, motor index, and model. The initial motor index from factory for every motors is `1`. However, unique indices are required for these motors to function in a chain on a common bus. To this end, we set different indices and follow the ascendant convention starting from index `1` (e.g. "1, 2, 3, 4, 5, 6" ). These indices will be written inside the persisting memory of each motor during the first connection. Here is an example of what the instantiation looks like: ```python from lerobot.common.robot_devices.motors.dynamixel import DynamixelMotorsBus @@ -89,7 +89,7 @@ follower_arm = DynamixelMotorsBus( **Configure and Connect** -During the first connection of the motors, `DynamixelMotorsBus` automatically detects a mismatch between the present motor indices (all `1` by default) and the specified motor indices. This triggers the configuration procedure which requires to unplug the power cord and motors, and to sequentially plug each motor again, starting from the closest to the bus. Because it is quite involved, we provide a youtube video for help. The output of the procedure looks like that: +During the first connection of the motors, `DynamixelMotorsBus` automatically detects a mismatch between the present motor indices (all `1` by default) and the specified motor indices (e.g. "1, 2, 3, 4, 5, 6"). This triggers the configuration procedure which requires to unplug the power cord and motors, and to sequentially plug each motor again, starting from the closest to the bus. Because it is quite involved, we provide a youtube video for help. The output of the procedure looks like that: ```python leader_arm.connect() @@ -243,14 +243,14 @@ See: `lerobot/configs/robot/koch.yaml` ```bash python lerobot/scripts/control_robot.py teleoperate \ - --robot lerobot/configs/robot/koch.yaml + --robot-path lerobot/configs/robot/koch.yaml >>> ``` ```bash python lerobot/scripts/control_robot.py teleoperate \ - --robot lerobot/configs/robot/koch.yaml \ + --robot-path lerobot/configs/robot/koch.yaml \ --robot-overrides \ leader_arms.main.port=/dev/tty.usbmodem575E0031751 \ follower_arms.main.port=/dev/tty.usbmodem575E0032081 @@ -260,7 +260,7 @@ python lerobot/scripts/control_robot.py teleoperate \ ```bash python lerobot/scripts/control_robot.py teleoperate \ - --robot lerobot/configs/robot/koch.yaml \ + --robot-path lerobot/configs/robot/koch.yaml \ --robot-overrides \ leader_arms.main.port=/dev/tty.usbmodem575E0031751 \ follower_arms.main.port=/dev/tty.usbmodem575E0032081 @@ -291,24 +291,29 @@ for _ in range(fps * record_time_s): TODO: We added ways to write the frames to disk in multiple thread We added warmap, reset time between episodes At the end we encode the frames into videos +control +if fail, re-record episode +checkpointing We consolidate the data into a LeRobotDataset and upload on the hub. Here is an example for 1 episode ```bash python lerobot/scripts/control_robot.py record \ --fps 30 \ - --root tmp/data \ + --root /tmp/data \ --repo-id $USER/koch_test \ --num-episodes 10 \ --run-compute-stats 1 ``` +TODO: USER HF, make sure you can push + ### Replay episode on your robot with the `replay` function ```bash python lerobot/scripts/control_robot.py replay \ --fps 30 \ - --root tmp/data \ + --root /tmp/data \ --repo-id $USER/koch_test \ --episode 0 ``` @@ -349,9 +354,10 @@ huggingface-cli upload cadene/2024_07_27_act_koch_pick_place_1_lego_raph_nightly ### Visualize predictions on training set ```bash -python lerobot/scripts/visualize_dataset.py \ - --repo-id $USER/koch_test - -p TODO +python lerobot/scripts/visualize_dataset_html.py \ + --repo-id lerobot/koch_pick_place_1_lego \ + --episodes 0 1 2 \ + -p ../lerobot/outputs/train/2024_07_29_act_koch_pick_place_1_lego_mps/checkpoints/006000/pretrained_model ``` ## 5. Evaluate your policy @@ -361,11 +367,11 @@ python lerobot/scripts/visualize_dataset.py \ ```bash python lerobot/scripts/control_robot.py record \ --fps 30 \ - --root tmp/data \ - --repo-id $USER/koch_test \ + --root /tmp/data \ + --repo-id $USER/eval_koch_test \ --num-episodes 10 \ --run-compute-stats 1 - -p TODO + -p ../lerobot/outputs/train/2024_07_29_act_koch_pick_place_1_lego_mps/checkpoints/006000/pretrained_model ``` ### Visualize evaluation afterwards diff --git a/lerobot/common/robot_devices/motors/dynamixel.py b/lerobot/common/robot_devices/motors/dynamixel.py index fb00f18b..bae74c78 100644 --- a/lerobot/common/robot_devices/motors/dynamixel.py +++ b/lerobot/common/robot_devices/motors/dynamixel.py @@ -224,7 +224,7 @@ def assert_same_address(model_ctrl_table, motor_models, data_name): def find_available_ports(): ports = [] - for path in Path("/dev").glob("*"): + for path in Path("/dev").glob("tty*"): ports.append(str(path)) return ports diff --git a/lerobot/common/utils/utils.py b/lerobot/common/utils/utils.py index 79db627a..ef5e8375 100644 --- a/lerobot/common/utils/utils.py +++ b/lerobot/common/utils/utils.py @@ -158,6 +158,7 @@ def init_hydra_config(config_path: str, overrides: list[str] | None = None) -> D version_base="1.2", ) cfg = hydra.compose(Path(config_path).stem, overrides) + return cfg diff --git a/lerobot/scripts/control_robot.py b/lerobot/scripts/control_robot.py index dae6f79e..d88126b5 100644 --- a/lerobot/scripts/control_robot.py +++ b/lerobot/scripts/control_robot.py @@ -668,19 +668,19 @@ if __name__ == "__main__": parser_record.add_argument( "--warmup-time-s", type=int, - default=2, + default=10, help="Number of seconds before starting data collection. It allows the robot devices to warmup and synchronize.", ) parser_record.add_argument( "--episode-time-s", type=int, - default=10, + default=60, help="Number of seconds for data recording for each episode.", ) parser_record.add_argument( "--reset-time-s", type=int, - default=5, + default=60, help="Number of seconds for resetting the environment after each episode.", ) parser_record.add_argument("--num-episodes", type=int, default=50, help="Number of episodes to record.")