2024-07-15 23:43:10 +08:00
"""
2024-08-16 00:11:33 +08:00
Utilities to control a robot .
Useful to record a dataset , replay a recorded episode , run the policy on your robot
and record an evaluation dataset , and to recalibrate your robot if needed .
2024-07-15 23:43:10 +08:00
Examples of usage :
2024-08-16 00:11:33 +08:00
- Recalibrate your robot :
` ` ` bash
python lerobot / scripts / control_robot . py calibrate
` ` `
2024-07-15 23:43:10 +08:00
- Unlimited teleoperation at highest frequency ( ~ 200 Hz is expected ) , to exit with CTRL + C :
` ` ` bash
python lerobot / scripts / control_robot . py teleoperate
2024-08-16 00:11:33 +08:00
# Remove the cameras from the robot definition. They are not used in 'teleoperate' anyway.
python lerobot / scripts / control_robot . py teleoperate - - robot - overrides ' ~cameras '
2024-07-15 23:43:10 +08:00
` ` `
- Unlimited teleoperation at a limited frequency of 30 Hz , to simulate data recording frequency :
` ` ` bash
python lerobot / scripts / control_robot . py teleoperate \
- - fps 30
` ` `
- Record one episode in order to test replay :
` ` ` bash
2024-08-16 00:11:33 +08:00
python lerobot / scripts / control_robot . py record \
2024-07-15 23:43:10 +08:00
- - fps 30 \
- - repo - id $ USER / koch_test \
- - num - episodes 1 \
- - run - compute - stats 0
` ` `
- Visualize dataset :
` ` ` bash
python lerobot / scripts / visualize_dataset . py \
- - repo - id $ USER / koch_test \
- - episode - index 0
` ` `
- Replay this test episode :
` ` ` bash
2024-08-16 00:11:33 +08:00
python lerobot / scripts / control_robot . py replay \
2024-07-15 23:43:10 +08:00
- - fps 30 \
- - repo - id $ USER / koch_test \
- - episode 0
` ` `
- Record a full dataset in order to train a policy , with 2 seconds of warmup ,
30 seconds of recording for each episode , and 10 seconds to reset the environment in between episodes :
` ` ` bash
2024-08-16 00:11:33 +08:00
python lerobot / scripts / control_robot . py record \
2024-07-15 23:43:10 +08:00
- - fps 30 \
- - repo - id $ USER / koch_pick_place_lego \
- - num - episodes 50 \
- - warmup - time - s 2 \
- - episode - time - s 30 \
- - reset - time - s 10
` ` `
* * NOTE * * : You can use your keyboard to control data recording flow .
- Tap right arrow key ' -> ' to early exit while recording an episode and go to resseting the environment .
- Tap right arrow key ' -> ' to early exit while resetting the environment and got to recording the next episode .
- Tap left arrow key ' <- ' to early exit and re - record the current episode .
- Tap escape key ' esc ' to stop the data recording .
This might require a sudo permission to allow your terminal to monitor keyboard events .
2024-12-03 19:20:05 +08:00
* * NOTE * * : You can resume / continue data recording by running the same data recording command and adding ` - - resume 1 ` .
If the dataset you want to extend is not on the hub , you also need to add ` - - local - files - only 1 ` .
2024-07-15 23:43:10 +08:00
- Train on this dataset with the ACT policy :
` ` ` bash
2024-11-30 02:04:00 +08:00
python lerobot / scripts / train . py \
2024-07-15 23:43:10 +08:00
policy = act_koch_real \
env = koch_real \
dataset_repo_id = $ USER / koch_pick_place_lego \
hydra . run . dir = outputs / train / act_koch_real
` ` `
- Run the pretrained policy on the robot :
` ` ` bash
2024-08-16 00:11:33 +08:00
python lerobot / scripts / control_robot . py record \
- - fps 30 \
- - repo - id $ USER / eval_act_koch_real \
- - num - episodes 10 \
- - warmup - time - s 2 \
- - episode - time - s 30 \
- - reset - time - s 10
2024-07-15 23:43:10 +08:00
- p outputs / train / act_koch_real / checkpoints / 080000 / pretrained_model
` ` `
"""
import argparse
import logging
import time
from pathlib import Path
2024-10-17 02:51:35 +08:00
from typing import List
2024-07-15 23:43:10 +08:00
# from safetensors.torch import load_file, save_file
2024-10-17 02:51:35 +08:00
from lerobot . common . datasets . lerobot_dataset import LeRobotDataset
from lerobot . common . robot_devices . control_utils import (
control_loop ,
has_method ,
init_keyboard_listener ,
init_policy ,
log_control_info ,
record_episode ,
reset_environment ,
sanity_check_dataset_name ,
2024-11-30 02:04:00 +08:00
sanity_check_dataset_robot_compatibility ,
2024-10-17 02:51:35 +08:00
stop_recording ,
warmup_record ,
)
2024-07-15 23:43:10 +08:00
from lerobot . common . robot_devices . robots . factory import make_robot
2024-10-17 02:51:35 +08:00
from lerobot . common . robot_devices . robots . utils import Robot
2024-10-05 00:56:42 +08:00
from lerobot . common . robot_devices . utils import busy_wait , safe_disconnect
2024-10-17 02:51:35 +08:00
from lerobot . common . utils . utils import init_hydra_config , init_logging , log_say , none_or_int
2024-10-10 23:12:45 +08:00
2024-10-05 00:56:42 +08:00
########################################################################################
# Control modes
########################################################################################
@safe_disconnect
2024-10-03 23:05:23 +08:00
def calibrate ( robot : Robot , arms : list [ str ] | None ) :
2024-10-05 00:56:42 +08:00
# TODO(aliberts): move this code in robots' classes
if robot . robot_type . startswith ( " stretch " ) :
if not robot . is_connected :
robot . connect ( )
if not robot . is_homed ( ) :
robot . home ( )
return
2024-10-25 17:23:55 +08:00
if arms is None :
arms = robot . available_arms
2024-10-17 02:51:35 +08:00
unknown_arms = [ arm_id for arm_id in arms if arm_id not in robot . available_arms ]
available_arms_str = " " . join ( robot . available_arms )
2024-09-05 01:28:05 +08:00
unknown_arms_str = " " . join ( unknown_arms )
if arms is None or len ( arms ) == 0 :
raise ValueError (
" No arm provided. Use `--arms` as argument with one or more available arms. \n "
f " For instance, to recalibrate all arms add: `--arms { available_arms_str } ` "
)
if len ( unknown_arms ) > 0 :
raise ValueError (
f " Unknown arms provided ( ' { unknown_arms_str } ' ). Available arms are ` { available_arms_str } `. "
)
for arm_id in arms :
arm_calib_path = robot . calibration_dir / f " { arm_id } .json "
if arm_calib_path . exists ( ) :
print ( f " Removing ' { arm_calib_path } ' " )
arm_calib_path . unlink ( )
else :
print ( f " Calibration file not found ' { arm_calib_path } ' " )
2024-08-16 00:11:33 +08:00
if robot . is_connected :
robot . disconnect ( )
# Calling `connect` automatically runs calibration
# when the calibration file is missing
robot . connect ( )
2024-09-05 01:28:05 +08:00
robot . disconnect ( )
print ( " Calibration is done! You can now teleoperate and record datasets! " )
2024-08-16 00:11:33 +08:00
2024-10-05 00:56:42 +08:00
@safe_disconnect
2024-10-17 02:51:35 +08:00
def teleoperate (
robot : Robot , fps : int | None = None , teleop_time_s : float | None = None , display_cameras : bool = False
) :
control_loop (
robot ,
control_time_s = teleop_time_s ,
fps = fps ,
teleoperate = True ,
display_cameras = display_cameras ,
)
2024-07-15 23:43:10 +08:00
2024-10-05 00:56:42 +08:00
@safe_disconnect
2024-08-16 00:11:33 +08:00
def record (
2024-07-15 23:43:10 +08:00
robot : Robot ,
2024-11-30 02:04:00 +08:00
root : Path ,
2024-10-17 02:51:35 +08:00
repo_id : str ,
2024-11-30 02:04:00 +08:00
single_task : str ,
2024-10-17 02:51:35 +08:00
pretrained_policy_name_or_path : str | None = None ,
policy_overrides : List [ str ] | None = None ,
2024-12-09 17:21:50 +08:00
assign_rewards : bool = False ,
2024-07-15 23:43:10 +08:00
fps : int | None = None ,
2024-11-30 02:04:00 +08:00
warmup_time_s : int | float = 2 ,
episode_time_s : int | float = 10 ,
reset_time_s : int | float = 5 ,
num_episodes : int = 50 ,
video : bool = True ,
run_compute_stats : bool = True ,
push_to_hub : bool = True ,
tags : list [ str ] | None = None ,
num_image_writer_processes : int = 0 ,
num_image_writer_threads_per_camera : int = 4 ,
display_cameras : bool = True ,
play_sounds : bool = True ,
resume : bool = False ,
# TODO(rcadene, aliberts): remove local_files_only when refactor with dataset as argument
local_files_only : bool = False ,
) - > LeRobotDataset :
2024-07-15 23:43:10 +08:00
# TODO(rcadene): Add option to record logs
2024-10-17 02:51:35 +08:00
listener = None
events = None
policy = None
device = None
use_amp = None
2024-12-09 17:21:50 +08:00
extra_features = (
{ " next.reward " : { " dtype " : " int64 " , " shape " : ( 1 , ) , " names " : None } } if assign_rewards else None
)
2024-10-17 02:51:35 +08:00
2024-11-30 02:04:00 +08:00
if single_task :
task = single_task
else :
raise NotImplementedError ( " Only single-task recording is supported for now " )
2024-10-17 02:51:35 +08:00
# Load pretrained policy
if pretrained_policy_name_or_path is not None :
policy , policy_fps , device , use_amp = init_policy ( pretrained_policy_name_or_path , policy_overrides )
if fps is None :
fps = policy_fps
logging . warning ( f " No fps provided, so using the fps from policy config ( { policy_fps } ). " )
elif fps != policy_fps :
logging . warning (
f " There is a mismatch between the provided fps ( { fps } ) and the one from policy config ( { policy_fps } ). "
)
2024-11-30 02:04:00 +08:00
if resume :
dataset = LeRobotDataset (
repo_id ,
root = root ,
local_files_only = local_files_only ,
)
dataset . start_image_writer (
num_processes = num_image_writer_processes ,
num_threads = num_image_writer_threads_per_camera * len ( robot . cameras ) ,
)
sanity_check_dataset_robot_compatibility ( dataset , robot , fps , video )
else :
# Create empty dataset or load existing saved episodes
sanity_check_dataset_name ( repo_id , policy )
dataset = LeRobotDataset . create (
repo_id ,
fps ,
root = root ,
robot = robot ,
use_videos = video ,
image_writer_processes = num_image_writer_processes ,
image_writer_threads = num_image_writer_threads_per_camera * len ( robot . cameras ) ,
2024-12-09 17:21:50 +08:00
features = extra_features ,
2024-11-30 02:04:00 +08:00
)
2024-07-15 23:43:10 +08:00
if not robot . is_connected :
robot . connect ( )
2024-12-09 17:21:50 +08:00
listener , events = init_keyboard_listener ( assign_rewards = assign_rewards )
2024-08-16 00:11:33 +08:00
2024-10-17 02:51:35 +08:00
# Execute a few seconds without recording to:
# 1. teleoperate the robot to move it in starting position if no policy provided,
# 2. give times to the robot devices to connect and start synchronizing,
# 3. place the cameras windows on screen
enable_teleoperation = policy is None
log_say ( " Warmup record " , play_sounds )
warmup_record ( robot , events , enable_teleoperation , warmup_time_s , display_cameras , fps )
2024-08-16 00:11:33 +08:00
2024-10-05 00:56:42 +08:00
if has_method ( robot , " teleop_safety_stop " ) :
robot . teleop_safety_stop ( )
2024-11-30 02:04:00 +08:00
recorded_episodes = 0
2024-10-17 02:51:35 +08:00
while True :
2024-11-30 02:04:00 +08:00
if recorded_episodes > = num_episodes :
2024-10-17 02:51:35 +08:00
break
2024-11-30 02:04:00 +08:00
# TODO(aliberts): add task prompt for multitask here. Might need to temporarily disable event if
# input() messes with them.
# if multi_task:
# task = input("Enter your task description: ")
log_say ( f " Recording episode { dataset . num_episodes } " , play_sounds )
2024-10-17 02:51:35 +08:00
record_episode (
dataset = dataset ,
robot = robot ,
events = events ,
episode_time_s = episode_time_s ,
display_cameras = display_cameras ,
policy = policy ,
device = device ,
use_amp = use_amp ,
fps = fps ,
2024-10-10 23:12:45 +08:00
)
2024-10-17 02:51:35 +08:00
# Execute a few seconds without recording to give time to manually reset the environment
# Current code logic doesn't allow to teleoperate during this time.
# TODO(rcadene): add an option to enable teleoperation during reset
# Skip reset for the last episode to be recorded
if not events [ " stop_recording " ] and (
2025-01-15 17:50:38 +08:00
( recorded_episodes < num_episodes - 1 ) or events [ " rerecord_episode " ]
2024-10-17 02:51:35 +08:00
) :
log_say ( " Reset the environment " , play_sounds )
reset_environment ( robot , events , reset_time_s )
if events [ " rerecord_episode " ] :
log_say ( " Re-record episode " , play_sounds )
events [ " rerecord_episode " ] = False
events [ " exit_early " ] = False
2024-11-30 02:04:00 +08:00
dataset . clear_episode_buffer ( )
2024-10-17 02:51:35 +08:00
continue
2024-11-30 02:04:00 +08:00
dataset . save_episode ( task )
recorded_episodes + = 1
2024-10-17 02:51:35 +08:00
if events [ " stop_recording " ] :
break
2024-07-15 23:43:10 +08:00
2024-10-17 02:51:35 +08:00
log_say ( " Stop recording " , play_sounds , blocking = True )
stop_recording ( robot , listener , display_cameras )
2024-10-10 23:12:45 +08:00
2024-11-30 02:04:00 +08:00
if run_compute_stats :
logging . info ( " Computing dataset statistics " )
dataset . consolidate ( run_compute_stats )
if push_to_hub :
dataset . push_to_hub ( tags = tags )
2024-10-17 02:51:35 +08:00
log_say ( " Exiting " , play_sounds )
2024-11-30 02:04:00 +08:00
return dataset
2024-07-15 23:43:10 +08:00
2024-10-17 02:51:35 +08:00
@safe_disconnect
2024-10-10 23:12:45 +08:00
def replay (
2024-11-30 02:04:00 +08:00
robot : Robot ,
root : Path ,
repo_id : str ,
episode : int ,
fps : int | None = None ,
play_sounds : bool = True ,
2024-12-03 17:53:21 +08:00
local_files_only : bool = False ,
2024-10-10 23:12:45 +08:00
) :
2024-10-17 02:51:35 +08:00
# TODO(rcadene, aliberts): refactor with control_loop, once `dataset` is an instance of LeRobotDataset
2024-07-15 23:43:10 +08:00
# TODO(rcadene): Add option to record logs
2024-11-30 02:04:00 +08:00
dataset = LeRobotDataset ( repo_id , root = root , episodes = [ episode ] , local_files_only = local_files_only )
actions = dataset . hf_dataset . select_columns ( " action " )
2024-07-15 23:43:10 +08:00
if not robot . is_connected :
robot . connect ( )
2024-10-17 02:51:35 +08:00
log_say ( " Replaying episode " , play_sounds , blocking = True )
2024-11-30 02:04:00 +08:00
for idx in range ( dataset . num_frames ) :
2024-08-16 00:11:33 +08:00
start_episode_t = time . perf_counter ( )
2024-07-15 23:43:10 +08:00
2024-11-30 02:04:00 +08:00
action = actions [ idx ] [ " action " ]
2024-07-15 23:43:10 +08:00
robot . send_action ( action )
2024-08-16 00:11:33 +08:00
dt_s = time . perf_counter ( ) - start_episode_t
2024-07-15 23:43:10 +08:00
busy_wait ( 1 / fps - dt_s )
2024-08-16 00:11:33 +08:00
dt_s = time . perf_counter ( ) - start_episode_t
2024-07-15 23:43:10 +08:00
log_control_info ( robot , dt_s , fps = fps )
if __name__ == " __main__ " :
parser = argparse . ArgumentParser ( )
subparsers = parser . add_subparsers ( dest = " mode " , required = True )
# Set common options for all the subparsers
base_parser = argparse . ArgumentParser ( add_help = False )
base_parser . add_argument (
2024-08-16 00:11:33 +08:00
" --robot-path " ,
type = str ,
default = " lerobot/configs/robot/koch.yaml " ,
help = " Path to robot yaml file used to instantiate the robot using `make_robot` factory function. " ,
)
base_parser . add_argument (
" --robot-overrides " ,
2024-07-15 23:43:10 +08:00
type = str ,
2024-08-16 00:11:33 +08:00
nargs = " * " ,
help = " Any key=value arguments to override config values (use dots for.nested=overrides) " ,
2024-07-15 23:43:10 +08:00
)
2024-08-16 00:11:33 +08:00
parser_calib = subparsers . add_parser ( " calibrate " , parents = [ base_parser ] )
2024-09-05 01:28:05 +08:00
parser_calib . add_argument (
" --arms " ,
2024-09-06 20:44:31 +08:00
type = str ,
2024-09-05 01:28:05 +08:00
nargs = " * " ,
help = " List of arms to calibrate (e.g. `--arms left_follower right_follower left_leader`) " ,
)
2024-08-16 00:11:33 +08:00
2024-07-15 23:43:10 +08:00
parser_teleop = subparsers . add_parser ( " teleoperate " , parents = [ base_parser ] )
parser_teleop . add_argument (
" --fps " , type = none_or_int , default = None , help = " Frames per second (set to None to disable) "
)
2024-10-17 02:51:35 +08:00
parser_teleop . add_argument (
" --display-cameras " ,
type = int ,
default = 1 ,
help = " Display all cameras on screen (set to 1 to display or 0). " ,
)
2024-07-15 23:43:10 +08:00
2024-08-16 00:11:33 +08:00
parser_record = subparsers . add_parser ( " record " , parents = [ base_parser ] )
2024-11-30 02:04:00 +08:00
task_args = parser_record . add_mutually_exclusive_group ( required = True )
2024-07-15 23:43:10 +08:00
parser_record . add_argument (
" --fps " , type = none_or_int , default = None , help = " Frames per second (set to None to disable) "
)
2024-11-30 02:04:00 +08:00
task_args . add_argument (
" --single-task " ,
type = str ,
help = " A short but accurate description of the task performed during the recording. " ,
)
# TODO(aliberts): add multi-task support
# task_args.add_argument(
# "--multi-task",
# type=int,
# help="You will need to enter the task performed at the start of each episode.",
# )
2024-07-15 23:43:10 +08:00
parser_record . add_argument (
" --root " ,
type = Path ,
2024-11-30 02:04:00 +08:00
default = None ,
2024-12-03 17:53:21 +08:00
help = " Root directory where the dataset will be stored (e.g. ' dataset/path ' ). " ,
2024-07-15 23:43:10 +08:00
)
parser_record . add_argument (
" --repo-id " ,
type = str ,
default = " lerobot/test " ,
help = " Dataset identifier. By convention it should match ' {hf_username} / {dataset_name} ' (e.g. `lerobot/test`). " ,
)
2024-12-03 17:53:21 +08:00
parser_record . add_argument (
" --local-files-only " ,
type = int ,
default = 0 ,
help = " Use local files only. By default, this script will try to fetch the dataset from the hub if it exists. " ,
)
2024-07-15 23:43:10 +08:00
parser_record . add_argument (
" --warmup-time-s " ,
type = int ,
2024-08-16 00:11:33 +08:00
default = 10 ,
2024-07-15 23:43:10 +08:00
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 ,
2024-08-16 00:11:33 +08:00
default = 60 ,
2024-07-15 23:43:10 +08:00
help = " Number of seconds for data recording for each episode. " ,
)
parser_record . add_argument (
" --reset-time-s " ,
type = int ,
2024-08-16 00:11:33 +08:00
default = 60 ,
2024-07-15 23:43:10 +08:00
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. " )
parser_record . add_argument (
" --run-compute-stats " ,
type = int ,
default = 1 ,
help = " By default, run the computation of the data statistics at the end of data collection. Compute intensive and not required to just replay an episode. " ,
)
parser_record . add_argument (
" --push-to-hub " ,
type = int ,
default = 1 ,
help = " Upload dataset to Hugging Face hub. " ,
)
2024-12-09 17:21:50 +08:00
# parser_record.add_argument(
# "--tags",
# type=str,
# nargs="*",
# help="Add tags to your dataset on the hub.",
# )
2024-07-15 23:43:10 +08:00
parser_record . add_argument (
2024-10-10 23:12:45 +08:00
" --num-image-writer-processes " ,
type = int ,
default = 0 ,
help = (
" Number of subprocesses handling the saving of frames as PNGs. Set to 0 to use threads only; "
" set to ≥1 to use subprocesses, each using threads to write images. The best number of processes "
" and threads depends on your system. We recommend 4 threads per camera with 0 processes. "
" If fps is unstable, adjust the thread count. If still unstable, try using 1 or more subprocesses. "
) ,
)
parser_record . add_argument (
" --num-image-writer-threads-per-camera " ,
2024-07-15 23:43:10 +08:00
type = int ,
2024-09-12 20:20:24 +08:00
default = 4 ,
help = (
" Number of threads writing the frames as png images on disk, per camera. "
2024-10-10 23:12:45 +08:00
" Too many threads might cause unstable teleoperation fps due to main thread being blocked. "
2024-09-12 20:20:24 +08:00
" Not enough threads might cause low camera fps. "
) ,
2024-07-15 23:43:10 +08:00
)
parser_record . add_argument (
2024-11-30 02:04:00 +08:00
" --resume " ,
2024-07-15 23:43:10 +08:00
type = int ,
default = 0 ,
2024-11-30 02:04:00 +08:00
help = " Resume recording on an existing dataset. " ,
2024-07-15 23:43:10 +08:00
)
2024-08-16 00:11:33 +08:00
parser_record . add_argument (
" -p " ,
" --pretrained-policy-name-or-path " ,
type = str ,
help = (
" Either the repo ID of a model hosted on the Hub or a path to a directory containing weights "
" saved using `Policy.save_pretrained`. "
) ,
)
parser_record . add_argument (
" --policy-overrides " ,
type = str ,
nargs = " * " ,
help = " Any key=value arguments to override config values (use dots for.nested=overrides) " ,
)
2024-12-09 17:21:50 +08:00
parser_record . add_argument (
" --assign-rewards " ,
type = int ,
default = 0 ,
help = " Enables the assignation of rewards to frames (by default no assignation). When enabled, assign a 0 reward to frames until the space bar is pressed which assign a 1 reward. Press the space bar a second time to assign a 0 reward. The reward assigned is reset to 0 when the episode ends. " ,
)
2024-07-15 23:43:10 +08:00
2024-08-16 00:11:33 +08:00
parser_replay = subparsers . add_parser ( " replay " , parents = [ base_parser ] )
2024-07-15 23:43:10 +08:00
parser_replay . add_argument (
" --fps " , type = none_or_int , default = None , help = " Frames per second (set to None to disable) "
)
parser_replay . add_argument (
" --root " ,
type = Path ,
2024-11-30 02:04:00 +08:00
default = None ,
2024-12-03 17:53:21 +08:00
help = " Root directory where the dataset will be stored (e.g. ' dataset/path ' ). " ,
2024-07-15 23:43:10 +08:00
)
parser_replay . add_argument (
" --repo-id " ,
type = str ,
default = " lerobot/test " ,
help = " Dataset identifier. By convention it should match ' {hf_username} / {dataset_name} ' (e.g. `lerobot/test`). " ,
)
2024-12-03 17:53:21 +08:00
parser_replay . add_argument (
" --local-files-only " ,
type = int ,
default = 0 ,
help = " Use local files only. By default, this script will try to fetch the dataset from the hub if it exists. " ,
)
2024-07-15 23:43:10 +08:00
parser_replay . add_argument ( " --episode " , type = int , default = 0 , help = " Index of the episode to replay. " )
args = parser . parse_args ( )
init_logging ( )
control_mode = args . mode
2024-08-16 00:11:33 +08:00
robot_path = args . robot_path
robot_overrides = args . robot_overrides
2024-07-15 23:43:10 +08:00
kwargs = vars ( args )
del kwargs [ " mode " ]
2024-08-16 00:11:33 +08:00
del kwargs [ " robot_path " ]
del kwargs [ " robot_overrides " ]
robot_cfg = init_hydra_config ( robot_path , robot_overrides )
robot = make_robot ( robot_cfg )
2024-07-15 23:43:10 +08:00
2024-08-16 00:11:33 +08:00
if control_mode == " calibrate " :
calibrate ( robot , * * kwargs )
elif control_mode == " teleoperate " :
2024-07-15 23:43:10 +08:00
teleoperate ( robot , * * kwargs )
2024-08-16 00:11:33 +08:00
elif control_mode == " record " :
2024-10-17 02:51:35 +08:00
record ( robot , * * kwargs )
2024-08-16 00:11:33 +08:00
elif control_mode == " replay " :
replay ( robot , * * kwargs )
if robot . is_connected :
# Disconnect manually to avoid a "Core dump" during process
# termination due to camera threads not properly exiting.
robot . disconnect ( )