move gello control frequecy args to teleop
This commit is contained in:
parent
b2875851ae
commit
70b30fe307
@ -72,6 +72,7 @@ Predefined configs are provided under `config/`:
|
|||||||
- `teleop.joint_ids` / `teleop.joint_signs` — per-arm servo mapping and direction
|
- `teleop.joint_ids` / `teleop.joint_signs` — per-arm servo mapping and direction
|
||||||
- `teleop.start_joints` — GELLO calibration reference, should match the xArm SDK initial point (degrees)
|
- `teleop.start_joints` — GELLO calibration reference, should match the xArm SDK initial point (degrees)
|
||||||
- `teleop.gripper_id` — GELLO gripper servo ID (`8`; `-1` disables it)
|
- `teleop.gripper_id` — GELLO gripper servo ID (`8`; `-1` disables it)
|
||||||
|
- `teleop.realtime_control_fps` — independent GELLO-to-xArm command loop rate; it is separate from `dataset.fps`
|
||||||
- `dataset.root` / `dataset.repo_id` — where the dataset is stored
|
- `dataset.root` / `dataset.repo_id` — where the dataset is stored
|
||||||
- `dataset.single_task` — task description saved with each frame
|
- `dataset.single_task` — task description saved with each frame
|
||||||
- `dataset.fps` / `episode_time_s` / `reset_time_s` — recording timing
|
- `dataset.fps` / `episode_time_s` / `reset_time_s` — recording timing
|
||||||
|
|||||||
@ -72,6 +72,7 @@ ls /dev/serial/by-id/
|
|||||||
- `teleop.joint_ids` / `teleop.joint_signs` — 各型号机械臂的舵机映射与方向
|
- `teleop.joint_ids` / `teleop.joint_signs` — 各型号机械臂的舵机映射与方向
|
||||||
- `teleop.start_joints` — GELLO 校准参考值(角度),应与 xArm SDK 初始点一致
|
- `teleop.start_joints` — GELLO 校准参考值(角度),应与 xArm SDK 初始点一致
|
||||||
- `teleop.gripper_id` — GELLO 夹爪舵机 ID(`8`;`-1` 表示无夹爪)
|
- `teleop.gripper_id` — GELLO 夹爪舵机 ID(`8`;`-1` 表示无夹爪)
|
||||||
|
- `teleop.realtime_control_fps` — GELLO 到 xArm 的独立实时控制频率,与 `dataset.fps` 分开
|
||||||
- `dataset.root` / `dataset.repo_id` — 数据集保存位置
|
- `dataset.root` / `dataset.repo_id` — 数据集保存位置
|
||||||
- `dataset.single_task` — 随每一帧保存的任务描述
|
- `dataset.single_task` — 随每一帧保存的任务描述
|
||||||
- `dataset.fps` / `episode_time_s` / `reset_time_s` — 录制时序参数
|
- `dataset.fps` / `episode_time_s` / `reset_time_s` — 录制时序参数
|
||||||
|
|||||||
@ -10,6 +10,7 @@ robot:
|
|||||||
# make sure to edit with your correct configurations!
|
# make sure to edit with your correct configurations!
|
||||||
teleop:
|
teleop:
|
||||||
type: uf::gello_teleop
|
type: uf::gello_teleop
|
||||||
|
realtime_control_fps: 60
|
||||||
port: "/dev/serial/by-id/usb-FTDI_USB__-__Serial_Converter_FTAJZYC7-if00-port0"
|
port: "/dev/serial/by-id/usb-FTDI_USB__-__Serial_Converter_FTAJZYC7-if00-port0"
|
||||||
joint_ids: [1, 2, 4, 6, 7]
|
joint_ids: [1, 2, 4, 6, 7]
|
||||||
joint_signs: [1, 1, -1, 1, 1]
|
joint_signs: [1, 1, -1, 1, 1]
|
||||||
|
|||||||
@ -10,6 +10,7 @@ robot:
|
|||||||
# make sure to edit with your correct configurations!
|
# make sure to edit with your correct configurations!
|
||||||
teleop:
|
teleop:
|
||||||
type: uf::gello_teleop
|
type: uf::gello_teleop
|
||||||
|
realtime_control_fps: 60
|
||||||
port: "/dev/serial/by-id/usb-FTDI_USB__-__Serial_Converter_FTAJZYC7-if00-port0"
|
port: "/dev/serial/by-id/usb-FTDI_USB__-__Serial_Converter_FTAJZYC7-if00-port0"
|
||||||
joint_ids: [1, 2, 4, 5, 6, 7]
|
joint_ids: [1, 2, 4, 5, 6, 7]
|
||||||
joint_signs: [1, 1, -1, 1, 1, 1]
|
joint_signs: [1, 1, -1, 1, 1, 1]
|
||||||
|
|||||||
42
config/gello/xarm7_gello_cartesian_record_config.yaml
Normal file
42
config/gello/xarm7_gello_cartesian_record_config.yaml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
robot:
|
||||||
|
type: uf::robot
|
||||||
|
id: "uf_robot_cartesian"
|
||||||
|
robot_dof: 7
|
||||||
|
control_space: "cartesian"
|
||||||
|
robot_ip: "192.168.1.245"
|
||||||
|
gripper_type: 1
|
||||||
|
max_linear_velocity: 200
|
||||||
|
min_tcp_z_mm: -2.0
|
||||||
|
gripper_error_log_path: "logs/xarm7_gripper_errors.log"
|
||||||
|
cameras:
|
||||||
|
camera:
|
||||||
|
type: intelrealsense
|
||||||
|
serial_number_or_name: "242622070583"
|
||||||
|
width: 640
|
||||||
|
height: 480
|
||||||
|
fps: 30
|
||||||
|
camera2:
|
||||||
|
type: intelrealsense
|
||||||
|
serial_number_or_name: "148522072685"
|
||||||
|
width: 640
|
||||||
|
height: 480
|
||||||
|
fps: 30
|
||||||
|
|
||||||
|
teleop:
|
||||||
|
type: uf::gello_teleop
|
||||||
|
id: "gello_teleop"
|
||||||
|
port: "/dev/serial/by-id/usb-FTDI_USB__-__Serial_Converter_FTB9HYVD-if00-port0"
|
||||||
|
joint_ids: [1, 2, 3, 4, 5, 6, 7]
|
||||||
|
joint_signs: [1, 1, 1, 1, 1, 1, 1]
|
||||||
|
gripper_id: 8
|
||||||
|
gripper_open_deg: 198.28125
|
||||||
|
gripper_close_deg: 155.75
|
||||||
|
|
||||||
|
dataset:
|
||||||
|
root: "datasets/xarm7_gello_cartesian_datas"
|
||||||
|
repo_id: "ufactory/xarm7_gello_cartesian_datas"
|
||||||
|
single_task: "Pick up the purple grape and drop into the box on the left."
|
||||||
|
fps: 60
|
||||||
|
episode_time_s: 60
|
||||||
|
reset_time_s: 20
|
||||||
|
push_to_hub: False
|
||||||
@ -13,10 +13,9 @@ robot:
|
|||||||
gripper_speed: 1500
|
gripper_speed: 1500
|
||||||
# Use the high-frequency servo interface for lower-latency GELLO tracking.
|
# Use the high-frequency servo interface for lower-latency GELLO tracking.
|
||||||
joint_command_mode: 1
|
joint_command_mode: 1
|
||||||
realtime_control_fps: 60
|
|
||||||
max_joint_velocity: 120
|
max_joint_velocity: 120
|
||||||
# TCP z floor in the xArm base coordinate system (mm).
|
# TCP z floor in the xArm base coordinate system (mm).
|
||||||
min_tcp_z_mm: 70.0
|
min_tcp_z_mm: -2.0
|
||||||
# CPU-local FK/Jacobian projection keeps ServoJ free of synchronous SDK queries.
|
# CPU-local FK/Jacobian projection keeps ServoJ free of synchronous SDK queries.
|
||||||
tcp_z_guard_backend: "local_projection"
|
tcp_z_guard_backend: "local_projection"
|
||||||
tcp_z_soft_margin_mm: 5.0
|
tcp_z_soft_margin_mm: 5.0
|
||||||
@ -43,6 +42,8 @@ robot:
|
|||||||
teleop:
|
teleop:
|
||||||
type: uf::gello_teleop
|
type: uf::gello_teleop
|
||||||
id: "gello_teleop"
|
id: "gello_teleop"
|
||||||
|
# Independent GELLO -> xArm command loop; dataset.fps remains the recording rate.
|
||||||
|
realtime_control_fps: 60
|
||||||
port: "/dev/serial/by-id/usb-FTDI_USB__-__Serial_Converter_FTB9HYVD-if00-port0"
|
port: "/dev/serial/by-id/usb-FTDI_USB__-__Serial_Converter_FTB9HYVD-if00-port0"
|
||||||
joint_ids: [1, 2, 3, 4, 5, 6, 7]
|
joint_ids: [1, 2, 3, 4, 5, 6, 7]
|
||||||
joint_signs: [1, 1, 1, 1, 1, 1, 1]
|
joint_signs: [1, 1, 1, 1, 1, 1, 1]
|
||||||
|
|||||||
@ -20,7 +20,6 @@
|
|||||||
robot:
|
robot:
|
||||||
control_space: "joint"
|
control_space: "joint"
|
||||||
joint_command_mode: 1
|
joint_command_mode: 1
|
||||||
realtime_control_fps: 60
|
|
||||||
|
|
||||||
min_tcp_z_mm: 70.0
|
min_tcp_z_mm: 70.0
|
||||||
tcp_z_guard_backend: "local_projection"
|
tcp_z_guard_backend: "local_projection"
|
||||||
@ -31,6 +30,9 @@ robot:
|
|||||||
gripper_command_threshold: 0.01
|
gripper_command_threshold: 0.01
|
||||||
gripper_speed: 1500
|
gripper_speed: 1500
|
||||||
|
|
||||||
|
teleop:
|
||||||
|
realtime_control_fps: 60
|
||||||
|
|
||||||
dataset:
|
dataset:
|
||||||
fps: 30
|
fps: 30
|
||||||
```
|
```
|
||||||
|
|||||||
@ -26,7 +26,6 @@ class UFRobotConfig(RobotConfig):
|
|||||||
manual_gripper_speed: float = 0.5 # normalized gripper position per second in manual mode
|
manual_gripper_speed: float = 0.5 # normalized gripper position per second in manual mode
|
||||||
teach_sensitivity: int | None = None # xArm teaching sensitivity, valid range: 1-5
|
teach_sensitivity: int | None = None # xArm teaching sensitivity, valid range: 1-5
|
||||||
joint_command_mode: int = 6 # 1: servo-angle-j, 6: online trajectory planning
|
joint_command_mode: int = 6 # 1: servo-angle-j, 6: online trajectory planning
|
||||||
realtime_control_fps: int = 60 # independent of camera/dataset sampling fps
|
|
||||||
# start_joints and start_tcp_pose are intentionally disabled.
|
# start_joints and start_tcp_pose are intentionally disabled.
|
||||||
# Reset uses the xArm SDK initial_point instead of configuration poses.
|
# Reset uses the xArm SDK initial_point instead of configuration poses.
|
||||||
max_joint_velocity: int = 90 # °/s, only effective in joint control mode
|
max_joint_velocity: int = 90 # °/s, only effective in joint control mode
|
||||||
@ -62,8 +61,6 @@ class UFRobotConfig(RobotConfig):
|
|||||||
raise ValueError("gripper_command_interval_s must be finite and non-negative")
|
raise ValueError("gripper_command_interval_s must be finite and non-negative")
|
||||||
if self.control_space == "joint" and self.joint_command_mode not in (1, 6):
|
if self.control_space == "joint" and self.joint_command_mode not in (1, 6):
|
||||||
raise ValueError("joint_command_mode must be 1 or 6 for joint control")
|
raise ValueError("joint_command_mode must be 1 or 6 for joint control")
|
||||||
if self.realtime_control_fps <= 0:
|
|
||||||
raise ValueError("realtime_control_fps must be positive")
|
|
||||||
if self.min_tcp_z_mm is not None and not math.isfinite(self.min_tcp_z_mm):
|
if self.min_tcp_z_mm is not None and not math.isfinite(self.min_tcp_z_mm):
|
||||||
raise ValueError("min_tcp_z_mm must be finite when provided")
|
raise ValueError("min_tcp_z_mm must be finite when provided")
|
||||||
if (
|
if (
|
||||||
|
|||||||
@ -380,7 +380,7 @@ def record_loop(
|
|||||||
teleop=teleop,
|
teleop=teleop,
|
||||||
teleop_action_processor=teleop_action_processor,
|
teleop_action_processor=teleop_action_processor,
|
||||||
robot_action_processor=robot_action_processor,
|
robot_action_processor=robot_action_processor,
|
||||||
fps=getattr(robot.config, "realtime_control_fps", fps),
|
fps=int(teleop.config.realtime_control_fps),
|
||||||
initial_observation=last_robot_cmd,
|
initial_observation=last_robot_cmd,
|
||||||
)
|
)
|
||||||
realtime_controller.start()
|
realtime_controller.start()
|
||||||
|
|||||||
@ -288,6 +288,7 @@ def teleop_loop(cfg: TeleopConfig):
|
|||||||
experiment_start_t = None
|
experiment_start_t = None
|
||||||
previous_command_t = None
|
previous_command_t = None
|
||||||
realtime_controller = None
|
realtime_controller = None
|
||||||
|
realtime_control_fps = int(teleop.config.realtime_control_fps)
|
||||||
|
|
||||||
def start_realtime_controller():
|
def start_realtime_controller():
|
||||||
nonlocal realtime_controller
|
nonlocal realtime_controller
|
||||||
@ -303,7 +304,7 @@ def teleop_loop(cfg: TeleopConfig):
|
|||||||
teleop,
|
teleop,
|
||||||
teleop_action_processor,
|
teleop_action_processor,
|
||||||
robot_action_processor,
|
robot_action_processor,
|
||||||
cfg.fps,
|
realtime_control_fps,
|
||||||
obs,
|
obs,
|
||||||
)
|
)
|
||||||
realtime_controller.start()
|
realtime_controller.start()
|
||||||
@ -410,7 +411,9 @@ def teleop_loop(cfg: TeleopConfig):
|
|||||||
print("\n********** Teleop Control Loop Exit **********")
|
print("\n********** Teleop Control Loop Exit **********")
|
||||||
stop_realtime_controller()
|
stop_realtime_controller()
|
||||||
if latency_samples:
|
if latency_samples:
|
||||||
output_path = _write_guard_latency_timings(latency_samples, cfg.timing_log_dir, cfg.fps)
|
output_path = _write_guard_latency_timings(
|
||||||
|
latency_samples, cfg.timing_log_dir, realtime_control_fps
|
||||||
|
)
|
||||||
print(f"Guard latency timing log: {output_path}")
|
print(f"Guard latency timing log: {output_path}")
|
||||||
cleanup_connections()
|
cleanup_connections()
|
||||||
atexit.unregister(cleanup_connections)
|
atexit.unregister(cleanup_connections)
|
||||||
|
|||||||
@ -8,6 +8,8 @@ from lerobot.teleoperators import TeleoperatorConfig
|
|||||||
@TeleoperatorConfig.register_subclass("uf::gello_teleop")
|
@TeleoperatorConfig.register_subclass("uf::gello_teleop")
|
||||||
@dataclass
|
@dataclass
|
||||||
class GelloTeleopConfig(TeleoperatorConfig):
|
class GelloTeleopConfig(TeleoperatorConfig):
|
||||||
|
# Frequency of the independent GELLO -> xArm realtime control loop.
|
||||||
|
realtime_control_fps: int = 60
|
||||||
# Port to connect to the gello dummy arm
|
# Port to connect to the gello dummy arm
|
||||||
port: str = "/dev/serial/by-id/usb-FTDI_USB__-__Serial_Converter_FTAJZYC7-if00-port0"
|
port: str = "/dev/serial/by-id/usb-FTDI_USB__-__Serial_Converter_FTAJZYC7-if00-port0"
|
||||||
|
|
||||||
@ -27,6 +29,8 @@ class GelloTeleopConfig(TeleoperatorConfig):
|
|||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
self.id = 'gello_teleop' if self.id is None else self.id
|
self.id = 'gello_teleop' if self.id is None else self.id
|
||||||
|
if self.realtime_control_fps <= 0:
|
||||||
|
raise ValueError("realtime_control_fps must be positive")
|
||||||
if len(self.joint_ids) != len(self.joint_signs):
|
if len(self.joint_ids) != len(self.joint_signs):
|
||||||
raise ValueError("joint_ids and joint_signs must have the same length")
|
raise ValueError("joint_ids and joint_signs must have the same length")
|
||||||
if len(self.joint_ids) != len(self.start_joints):
|
if len(self.joint_ids) != len(self.start_joints):
|
||||||
|
|||||||
@ -2,6 +2,9 @@ import time
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from lerobot_robot_ufactory.teleoperators.gello_teleop.gello_teleop_config import (
|
||||||
|
GelloTeleopConfig,
|
||||||
|
)
|
||||||
from lerobot_robot_ufactory.utils.realtime_teleop import RealtimeTeleopController
|
from lerobot_robot_ufactory.utils.realtime_teleop import RealtimeTeleopController
|
||||||
|
|
||||||
|
|
||||||
@ -27,6 +30,15 @@ def identity_action_processor(value):
|
|||||||
return value[0]
|
return value[0]
|
||||||
|
|
||||||
|
|
||||||
|
def test_gello_realtime_control_fps_defaults_to_60():
|
||||||
|
assert GelloTeleopConfig().realtime_control_fps == 60
|
||||||
|
|
||||||
|
|
||||||
|
def test_gello_realtime_control_fps_must_be_positive():
|
||||||
|
with pytest.raises(ValueError, match="realtime_control_fps"):
|
||||||
|
GelloTeleopConfig(realtime_control_fps=0)
|
||||||
|
|
||||||
|
|
||||||
def test_realtime_controller_sends_without_waiting_for_observation_owner():
|
def test_realtime_controller_sends_without_waiting_for_observation_owner():
|
||||||
robot = FakeRobot()
|
robot = FakeRobot()
|
||||||
controller = RealtimeTeleopController(
|
controller = RealtimeTeleopController(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user