Exclude log record in data collection
This commit is contained in:
parent
172bec5fe6
commit
99546165ec
@ -84,6 +84,7 @@ Predefined configs are provided under `config/`:
|
|||||||
- `robot.teach_sensitivity` — teaching sensitivity, valid range 1–5
|
- `robot.teach_sensitivity` — teaching sensitivity, valid range 1–5
|
||||||
- `robot.manual_gripper_speed` — gripper velocity in normalized position per second (default `0.5`)
|
- `robot.manual_gripper_speed` — gripper velocity in normalized position per second (default `0.5`)
|
||||||
- `robot.observe_joint_vel` — record joint velocities in observations (`false` by default)
|
- `robot.observe_joint_vel` — record joint velocities in observations (`false` by default)
|
||||||
|
- `robot.enable_logs` — enable optional per-cycle timing/diagnostic logs (`false` by default)
|
||||||
- `robot.cameras.camera` — Intel RealSense camera (`serial_number_or_name`, resolution, fps)
|
- `robot.cameras.camera` — Intel RealSense camera (`serial_number_or_name`, resolution, fps)
|
||||||
- `dataset.root` / `dataset.repo_id` / `single_task` / `fps` / `episode_time_s` / `reset_time_s` / `num_episodes` — dataset settings
|
- `dataset.root` / `dataset.repo_id` / `single_task` / `fps` / `episode_time_s` / `reset_time_s` / `num_episodes` — dataset settings
|
||||||
|
|
||||||
@ -134,6 +135,7 @@ records the loop period, GELLO read, safety guard, ServoJ, and complete
|
|||||||
```bash
|
```bash
|
||||||
uv run uf-robot-teleop \
|
uv run uf-robot-teleop \
|
||||||
--config_path config/gello/xarm7_gello_record_config.yaml \
|
--config_path config/gello/xarm7_gello_record_config.yaml \
|
||||||
|
--robot.enable_logs=true \
|
||||||
--fps 60 \
|
--fps 60 \
|
||||||
--guard_latency_experiment=true \
|
--guard_latency_experiment=true \
|
||||||
--experiment_duration_s 60
|
--experiment_duration_s 60
|
||||||
|
|||||||
@ -84,6 +84,7 @@ ls /dev/serial/by-id/
|
|||||||
- `robot.teach_sensitivity` — 示教灵敏度,有效范围 1–5
|
- `robot.teach_sensitivity` — 示教灵敏度,有效范围 1–5
|
||||||
- `robot.manual_gripper_speed` — 夹爪速度(每秒归一化位置变化,默认 `0.5`)
|
- `robot.manual_gripper_speed` — 夹爪速度(每秒归一化位置变化,默认 `0.5`)
|
||||||
- `robot.observe_joint_vel` — 是否在观测中记录关节速度(默认 `false`)
|
- `robot.observe_joint_vel` — 是否在观测中记录关节速度(默认 `false`)
|
||||||
|
- `robot.enable_logs` — 是否启用每帧耗时和诊断日志(默认 `false`)
|
||||||
- `robot.cameras.camera` — Intel RealSense 相机配置(`serial_number_or_name`、分辨率、fps)
|
- `robot.cameras.camera` — Intel RealSense 相机配置(`serial_number_or_name`、分辨率、fps)
|
||||||
- `dataset.root` / `dataset.repo_id` / `single_task` / `fps` / `episode_time_s` / `reset_time_s` / `num_episodes` — 数据集配置
|
- `dataset.root` / `dataset.repo_id` / `single_task` / `fps` / `episode_time_s` / `reset_time_s` / `num_episodes` — 数据集配置
|
||||||
|
|
||||||
@ -124,6 +125,7 @@ GELLO 读取、安全检测、ServoJ 和完整 `send_action` 耗时:
|
|||||||
```bash
|
```bash
|
||||||
uv run uf-robot-teleop \
|
uv run uf-robot-teleop \
|
||||||
--config_path config/gello/xarm7_gello_record_config.yaml \
|
--config_path config/gello/xarm7_gello_record_config.yaml \
|
||||||
|
--robot.enable_logs=true \
|
||||||
--fps 60 \
|
--fps 60 \
|
||||||
--guard_latency_experiment=true \
|
--guard_latency_experiment=true \
|
||||||
--experiment_duration_s 60
|
--experiment_duration_s 60
|
||||||
|
|||||||
@ -5,6 +5,7 @@ robot:
|
|||||||
control_space: "joint"
|
control_space: "joint"
|
||||||
robot_ip: "192.168.1.245"
|
robot_ip: "192.168.1.245"
|
||||||
gripper_type: 1
|
gripper_type: 1
|
||||||
|
enable_logs: false
|
||||||
|
|
||||||
# make sure to edit with your correct configurations!
|
# make sure to edit with your correct configurations!
|
||||||
teleop:
|
teleop:
|
||||||
|
|||||||
@ -5,6 +5,7 @@ robot:
|
|||||||
control_space: "joint"
|
control_space: "joint"
|
||||||
robot_ip: "192.168.1.245"
|
robot_ip: "192.168.1.245"
|
||||||
gripper_type: 1
|
gripper_type: 1
|
||||||
|
enable_logs: false
|
||||||
|
|
||||||
# make sure to edit with your correct configurations!
|
# make sure to edit with your correct configurations!
|
||||||
teleop:
|
teleop:
|
||||||
|
|||||||
@ -5,6 +5,7 @@ robot:
|
|||||||
control_space: "cartesian"
|
control_space: "cartesian"
|
||||||
robot_ip: "192.168.1.245"
|
robot_ip: "192.168.1.245"
|
||||||
gripper_type: 1
|
gripper_type: 1
|
||||||
|
enable_logs: false
|
||||||
max_linear_velocity: 200
|
max_linear_velocity: 200
|
||||||
min_tcp_z_mm: 50
|
min_tcp_z_mm: 50
|
||||||
gripper_error_log_path: "logs/xarm7_gripper_errors.log"
|
gripper_error_log_path: "logs/xarm7_gripper_errors.log"
|
||||||
|
|||||||
@ -5,6 +5,7 @@ robot:
|
|||||||
control_space: "joint"
|
control_space: "joint"
|
||||||
robot_ip: "192.168.1.245"
|
robot_ip: "192.168.1.245"
|
||||||
gripper_type: 1
|
gripper_type: 1
|
||||||
|
enable_logs: false
|
||||||
# Up to 60 Hz goal updates; the first command after idle is immediate.
|
# Up to 60 Hz goal updates; the first command after idle is immediate.
|
||||||
# Keeping the gripper below its 5000 maximum speed avoids C19 in testing.
|
# Keeping the gripper below its 5000 maximum speed avoids C19 in testing.
|
||||||
gripper_command_interval_s: 0.0166667
|
gripper_command_interval_s: 0.0166667
|
||||||
|
|||||||
@ -7,6 +7,7 @@ robot:
|
|||||||
robot_ip: "192.168.1.245"
|
robot_ip: "192.168.1.245"
|
||||||
# Gripper type: 1 is the xArm gripper.
|
# Gripper type: 1 is the xArm gripper.
|
||||||
gripper_type: 1
|
gripper_type: 1
|
||||||
|
enable_logs: false
|
||||||
manual_mode: true
|
manual_mode: true
|
||||||
# Normalized gripper position change per second while holding C/O.
|
# Normalized gripper position change per second while holding C/O.
|
||||||
manual_gripper_speed: 0.5
|
manual_gripper_speed: 0.5
|
||||||
|
|||||||
@ -5,6 +5,7 @@ robot:
|
|||||||
control_space: "cartesian"
|
control_space: "cartesian"
|
||||||
robot_ip: "192.168.1.85"
|
robot_ip: "192.168.1.85"
|
||||||
gripper_type: 10
|
gripper_type: 10
|
||||||
|
enable_logs: false
|
||||||
max_linear_velocity: 200
|
max_linear_velocity: 200
|
||||||
cameras:
|
cameras:
|
||||||
fisheye:
|
fisheye:
|
||||||
|
|||||||
@ -5,6 +5,7 @@ robot:
|
|||||||
control_space: "cartesian"
|
control_space: "cartesian"
|
||||||
robot_ip: "192.168.1.127"
|
robot_ip: "192.168.1.127"
|
||||||
gripper_type: 0
|
gripper_type: 0
|
||||||
|
enable_logs: false
|
||||||
|
|
||||||
cameras:
|
cameras:
|
||||||
overhead:
|
overhead:
|
||||||
|
|||||||
@ -12,6 +12,7 @@ robot:
|
|||||||
control_space: "cartesian"
|
control_space: "cartesian"
|
||||||
robot_ip: "192.168.1.29"
|
robot_ip: "192.168.1.29"
|
||||||
gripper_type: 2
|
gripper_type: 2
|
||||||
|
enable_logs: false
|
||||||
max_linear_velocity: 200
|
max_linear_velocity: 200
|
||||||
cameras:
|
cameras:
|
||||||
fisheye:
|
fisheye:
|
||||||
@ -28,6 +29,7 @@ robot:
|
|||||||
control_space: "cartesian"
|
control_space: "cartesian"
|
||||||
robot_ip: "192.168.1.83"
|
robot_ip: "192.168.1.83"
|
||||||
gripper_type: 2
|
gripper_type: 2
|
||||||
|
enable_logs: false
|
||||||
max_linear_velocity: 200
|
max_linear_velocity: 200
|
||||||
cameras:
|
cameras:
|
||||||
fisheye:
|
fisheye:
|
||||||
|
|||||||
@ -5,6 +5,7 @@ robot:
|
|||||||
control_space: "cartesian"
|
control_space: "cartesian"
|
||||||
robot_ip: "192.168.1.83"
|
robot_ip: "192.168.1.83"
|
||||||
gripper_type: 2
|
gripper_type: 2
|
||||||
|
enable_logs: false
|
||||||
max_linear_velocity: 250
|
max_linear_velocity: 250
|
||||||
cameras:
|
cameras:
|
||||||
fisheye:
|
fisheye:
|
||||||
|
|||||||
@ -55,6 +55,7 @@ GELLO get_action
|
|||||||
```bash
|
```bash
|
||||||
uv run uf-robot-teleop \
|
uv run uf-robot-teleop \
|
||||||
--config_path config/gello/xarm7_gello_record_config.yaml \
|
--config_path config/gello/xarm7_gello_record_config.yaml \
|
||||||
|
--robot.enable_logs=true \
|
||||||
--fps 60 \
|
--fps 60 \
|
||||||
--experiment_1_baseline=true \
|
--experiment_1_baseline=true \
|
||||||
--experiment_duration_s 60
|
--experiment_duration_s 60
|
||||||
|
|||||||
@ -107,6 +107,7 @@ class UFRobot(Robot, Thread):
|
|||||||
self._is_connected = False
|
self._is_connected = False
|
||||||
self._is_calibrated =True
|
self._is_calibrated =True
|
||||||
|
|
||||||
|
self.enable_logs = bool(getattr(config, "enable_logs", False))
|
||||||
self.logs = {}
|
self.logs = {}
|
||||||
|
|
||||||
self._cmd_cnt = 0
|
self._cmd_cnt = 0
|
||||||
@ -539,6 +540,7 @@ class UFRobot(Robot, Thread):
|
|||||||
local = self._local_kinematics.tcp_position(joints)
|
local = self._local_kinematics.tcp_position(joints)
|
||||||
error_mm = float(np.linalg.norm(local - reported))
|
error_mm = float(np.linalg.norm(local - reported))
|
||||||
limit = float(self.config.local_kinematics_max_error_mm)
|
limit = float(self.config.local_kinematics_max_error_mm)
|
||||||
|
if getattr(self, "enable_logs", True):
|
||||||
self.logs["local_kinematics_error_mm"] = error_mm
|
self.logs["local_kinematics_error_mm"] = error_mm
|
||||||
if math.isfinite(error_mm) and error_mm <= limit:
|
if math.isfinite(error_mm) and error_mm <= limit:
|
||||||
self._local_model_fault_count = 0
|
self._local_model_fault_count = 0
|
||||||
@ -820,9 +822,10 @@ class UFRobot(Robot, Thread):
|
|||||||
def get_observation(self) -> dict[str, np.ndarray]:
|
def get_observation(self) -> dict[str, np.ndarray]:
|
||||||
obs_dict = {}
|
obs_dict = {}
|
||||||
self._log_controller_error_if_changed("get_observation")
|
self._log_controller_error_if_changed("get_observation")
|
||||||
|
logs_enabled = bool(getattr(self, "enable_logs", True))
|
||||||
|
|
||||||
# Read Stretch state
|
# Read robot state
|
||||||
before_read_t = time.perf_counter()
|
before_read_t = time.perf_counter() if logs_enabled else None
|
||||||
if self._control_space == "joint":
|
if self._control_space == "joint":
|
||||||
code, states = self.real_arm.get_joint_states(is_radian=True, num=3)
|
code, states = self.real_arm.get_joint_states(is_radian=True, num=3)
|
||||||
pos_list = states[0].copy()
|
pos_list = states[0].copy()
|
||||||
@ -867,12 +870,13 @@ class UFRobot(Robot, Thread):
|
|||||||
self.real_arm.robotiq_get_status(number_of_registers=3)
|
self.real_arm.robotiq_get_status(number_of_registers=3)
|
||||||
grippos = self.real_arm.robotiq_status['gPO'] # 0..255
|
grippos = self.real_arm.robotiq_status['gPO'] # 0..255
|
||||||
grippos_norm = self._gripper_param.get_gripper_norm(grippos) # 0=open, 1=closed
|
grippos_norm = self._gripper_param.get_gripper_norm(grippos) # 0=open, 1=closed
|
||||||
|
if logs_enabled:
|
||||||
self.logs["read_pos_dt_s"] = time.perf_counter() - before_read_t
|
self.logs["read_pos_dt_s"] = time.perf_counter() - before_read_t
|
||||||
obs_dict[f"{self.prefix}gripper.pos"] = grippos_norm
|
obs_dict[f"{self.prefix}gripper.pos"] = grippos_norm
|
||||||
|
|
||||||
# Capture images from cameras
|
# Capture images from cameras
|
||||||
for cam_key, cam in self.cameras.items():
|
for cam_key, cam in self.cameras.items():
|
||||||
before_camread_t = time.perf_counter()
|
before_camread_t = time.perf_counter() if logs_enabled else None
|
||||||
frame = cam.async_read()
|
frame = cam.async_read()
|
||||||
shape = frame.shape
|
shape = frame.shape
|
||||||
if (self.camera_height > 0 and self.camera_height != shape[0]) or (self.camera_width > 0 and self.camera_width != shape[1]):
|
if (self.camera_height > 0 and self.camera_height != shape[0]) or (self.camera_width > 0 and self.camera_width != shape[1]):
|
||||||
@ -881,7 +885,10 @@ class UFRobot(Robot, Thread):
|
|||||||
import cv2
|
import cv2
|
||||||
frame = cv2.resize(frame, (camera_height, camera_width), interpolation=cv2.INTER_AREA)
|
frame = cv2.resize(frame, (camera_height, camera_width), interpolation=cv2.INTER_AREA)
|
||||||
obs_dict[f"{self.prefix}{cam_key}"] = frame
|
obs_dict[f"{self.prefix}{cam_key}"] = frame
|
||||||
self.logs[f"async_read_camera_{cam_key}_dt_s"] = time.perf_counter() - before_camread_t
|
if logs_enabled:
|
||||||
|
self.logs[f"async_read_camera_{cam_key}_dt_s"] = (
|
||||||
|
time.perf_counter() - before_camread_t
|
||||||
|
)
|
||||||
|
|
||||||
return obs_dict
|
return obs_dict
|
||||||
|
|
||||||
@ -896,6 +903,7 @@ class UFRobot(Robot, Thread):
|
|||||||
return self.get_observation()
|
return self.get_observation()
|
||||||
if not self._rt_report_normal:
|
if not self._rt_report_normal:
|
||||||
raise ConnectionError("RT Report for target robot NOT READY!")
|
raise ConnectionError("RT Report for target robot NOT READY!")
|
||||||
|
logs_enabled = bool(getattr(self, "enable_logs", True))
|
||||||
with self._update_lock:
|
with self._update_lock:
|
||||||
positions = self.rt_actual_joint_pos.copy()
|
positions = self.rt_actual_joint_pos.copy()
|
||||||
velocities = self.rt_actual_joint_speed.copy()
|
velocities = self.rt_actual_joint_speed.copy()
|
||||||
@ -919,9 +927,9 @@ class UFRobot(Robot, Thread):
|
|||||||
obs_dict[f"{self.prefix}gripper.pos"] = float(gripper)
|
obs_dict[f"{self.prefix}gripper.pos"] = float(gripper)
|
||||||
|
|
||||||
for camera_key, camera in self.cameras.items():
|
for camera_key, camera in self.cameras.items():
|
||||||
before_camera_t = time.perf_counter()
|
before_camera_t = time.perf_counter() if logs_enabled else None
|
||||||
frame = camera.async_read()
|
frame = camera.async_read()
|
||||||
after_camera_t = time.perf_counter()
|
after_camera_t = time.perf_counter() if logs_enabled else None
|
||||||
shape = frame.shape
|
shape = frame.shape
|
||||||
if (
|
if (
|
||||||
self.camera_height > 0
|
self.camera_height > 0
|
||||||
@ -935,6 +943,7 @@ class UFRobot(Robot, Thread):
|
|||||||
height = self.camera_height if self.camera_height != 0 else shape[0]
|
height = self.camera_height if self.camera_height != 0 else shape[0]
|
||||||
frame = cv2.resize(frame, (width, height), interpolation=cv2.INTER_AREA)
|
frame = cv2.resize(frame, (width, height), interpolation=cv2.INTER_AREA)
|
||||||
obs_dict[f"{self.prefix}{camera_key}"] = frame
|
obs_dict[f"{self.prefix}{camera_key}"] = frame
|
||||||
|
if logs_enabled:
|
||||||
self.logs[f"async_read_camera_{camera_key}_dt_s"] = (
|
self.logs[f"async_read_camera_{camera_key}_dt_s"] = (
|
||||||
after_camera_t - before_camera_t
|
after_camera_t - before_camera_t
|
||||||
)
|
)
|
||||||
@ -944,11 +953,13 @@ class UFRobot(Robot, Thread):
|
|||||||
before_camera_t,
|
before_camera_t,
|
||||||
after_camera_t,
|
after_camera_t,
|
||||||
)
|
)
|
||||||
|
if logs_enabled:
|
||||||
self._last_realtime_observation_end_monotonic_s = time.perf_counter()
|
self._last_realtime_observation_end_monotonic_s = time.perf_counter()
|
||||||
return obs_dict
|
return obs_dict
|
||||||
|
|
||||||
def _send_gripper_action(self, gripper_norm: float) -> None:
|
def _send_gripper_action(self, gripper_norm: float) -> None:
|
||||||
gripper_norm = min(max(float(gripper_norm), 0.0), 1.0)
|
gripper_norm = min(max(float(gripper_norm), 0.0), 1.0)
|
||||||
|
logs_enabled = bool(getattr(self, "enable_logs", True))
|
||||||
if (
|
if (
|
||||||
self._last_gripper_command is not None
|
self._last_gripper_command is not None
|
||||||
and abs(gripper_norm - self._last_gripper_command)
|
and abs(gripper_norm - self._last_gripper_command)
|
||||||
@ -964,7 +975,7 @@ class UFRobot(Robot, Thread):
|
|||||||
if now - self._last_gripper_command_attempt_s < self.config.gripper_command_interval_s:
|
if now - self._last_gripper_command_attempt_s < self.config.gripper_command_interval_s:
|
||||||
return
|
return
|
||||||
self._last_gripper_command_attempt_s = now
|
self._last_gripper_command_attempt_s = now
|
||||||
command_start_s = now
|
command_start_s = now if logs_enabled else None
|
||||||
|
|
||||||
if self._gripper_type == GripperType.xArmGripper:
|
if self._gripper_type == GripperType.xArmGripper:
|
||||||
grippos = self._gripper_param.get_grippos(gripper_norm)
|
grippos = self._gripper_param.get_grippos(gripper_norm)
|
||||||
@ -1005,14 +1016,22 @@ class UFRobot(Robot, Thread):
|
|||||||
result = self.real_arm.getset_tgpio_modbus_data(modbus_datas)
|
result = self.real_arm.getset_tgpio_modbus_data(modbus_datas)
|
||||||
|
|
||||||
code = result[0] if isinstance(result, (tuple, list)) else result
|
code = result[0] if isinstance(result, (tuple, list)) else result
|
||||||
command_dt_ms = (time.perf_counter() - command_start_s) * 1000
|
command_dt_ms = (
|
||||||
|
(time.perf_counter() - command_start_s) * 1000
|
||||||
|
if logs_enabled
|
||||||
|
else None
|
||||||
|
)
|
||||||
if code not in (None, 0):
|
if code not in (None, 0):
|
||||||
|
detail = f"target={gripper_norm:.6f}, pulse={grippos}"
|
||||||
|
if command_dt_ms is not None:
|
||||||
|
detail += f", dt_ms={command_dt_ms:.3f}"
|
||||||
self._log_gripper_error(
|
self._log_gripper_error(
|
||||||
"send_gripper_action",
|
"send_gripper_action",
|
||||||
code,
|
code,
|
||||||
f"target={gripper_norm:.6f}, pulse={grippos}, dt_ms={command_dt_ms:.3f}",
|
detail,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
if logs_enabled:
|
||||||
self._log_gripper_command(gripper_norm, grippos, command_dt_ms)
|
self._log_gripper_command(gripper_norm, grippos, command_dt_ms)
|
||||||
self._last_gripper_command = gripper_norm
|
self._last_gripper_command = gripper_norm
|
||||||
|
|
||||||
@ -1139,10 +1158,8 @@ class UFRobot(Robot, Thread):
|
|||||||
if self.config.no_action:
|
if self.config.no_action:
|
||||||
return action
|
return action
|
||||||
|
|
||||||
before_write_t = time.perf_counter()
|
logs_enabled = bool(getattr(self, "enable_logs", True))
|
||||||
self.logs["safety_guard_dt_s"] = 0.0
|
before_write_t = time.perf_counter() if logs_enabled else None
|
||||||
self.logs["servo_j_dt_s"] = 0.0
|
|
||||||
self.logs["safety_guard_path"] = "not_run"
|
|
||||||
safe_action = dict(action)
|
safe_action = dict(action)
|
||||||
if self._control_space == "joint":
|
if self._control_space == "joint":
|
||||||
# first sync with gello or other control device SLOWLY!
|
# first sync with gello or other control device SLOWLY!
|
||||||
@ -1152,8 +1169,9 @@ class UFRobot(Robot, Thread):
|
|||||||
cmd_list = [0]*(self._dof)
|
cmd_list = [0]*(self._dof)
|
||||||
for i in range(self._dof):
|
for i in range(self._dof):
|
||||||
cmd_list[i] = action[f"{self.prefix}J{i+1}.pos"]
|
cmd_list[i] = action[f"{self.prefix}J{i+1}.pos"]
|
||||||
guard_start_t = time.perf_counter()
|
guard_start_t = time.perf_counter() if logs_enabled else None
|
||||||
safe_cmd = self._guard_joint_target(cmd_list)
|
safe_cmd = self._guard_joint_target(cmd_list)
|
||||||
|
if logs_enabled:
|
||||||
self.logs["safety_guard_dt_s"] = time.perf_counter() - guard_start_t
|
self.logs["safety_guard_dt_s"] = time.perf_counter() - guard_start_t
|
||||||
self.logs["safety_guard_path"] = self._last_guard_path
|
self.logs["safety_guard_path"] = self._last_guard_path
|
||||||
if safe_cmd is None:
|
if safe_cmd is None:
|
||||||
@ -1174,10 +1192,11 @@ class UFRobot(Robot, Thread):
|
|||||||
code = self.real_arm.set_state(0)
|
code = self.real_arm.set_state(0)
|
||||||
self._check_motion_code("set_state(0)", code)
|
self._check_motion_code("set_state(0)", code)
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
servo_j_start_t = time.perf_counter()
|
servo_j_start_t = time.perf_counter() if logs_enabled else None
|
||||||
code = self.real_arm.set_servo_angle_j(
|
code = self.real_arm.set_servo_angle_j(
|
||||||
safe_cmd[:self._dof].tolist(), speed=jnt_spd, is_radian=True
|
safe_cmd[:self._dof].tolist(), speed=jnt_spd, is_radian=True
|
||||||
)
|
)
|
||||||
|
if logs_enabled:
|
||||||
self.logs["servo_j_dt_s"] = time.perf_counter() - servo_j_start_t
|
self.logs["servo_j_dt_s"] = time.perf_counter() - servo_j_start_t
|
||||||
self._check_motion_code("set_servo_angle_j", code)
|
self._check_motion_code("set_servo_angle_j", code)
|
||||||
elif safe_cmd is not None:
|
elif safe_cmd is not None:
|
||||||
@ -1222,6 +1241,7 @@ class UFRobot(Robot, Thread):
|
|||||||
if self._gripper_type > GripperType.NoGripper:
|
if self._gripper_type > GripperType.NoGripper:
|
||||||
self._send_gripper_action(safe_action[f"{self.prefix}gripper.pos"])
|
self._send_gripper_action(safe_action[f"{self.prefix}gripper.pos"])
|
||||||
|
|
||||||
|
if logs_enabled:
|
||||||
self.logs["write_pos_dt_s"] = time.perf_counter() - before_write_t
|
self.logs["write_pos_dt_s"] = time.perf_counter() - before_write_t
|
||||||
return safe_action
|
return safe_action
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,7 @@ class UFRobotConfig(RobotConfig):
|
|||||||
gripper_command_threshold: float = 0.01 # normalized change required before sending a new command
|
gripper_command_threshold: float = 0.01 # normalized change required before sending a new command
|
||||||
gripper_command_interval_s: float = 0.1 # minimum interval between tool RS485 goals
|
gripper_command_interval_s: float = 0.1 # minimum interval between tool RS485 goals
|
||||||
gripper_error_log_path: str | None = "logs/xarm_gripper_errors.log"
|
gripper_error_log_path: str | None = "logs/xarm_gripper_errors.log"
|
||||||
|
enable_logs: bool = False # optional per-cycle timing and diagnostic logs
|
||||||
observe_joint_vel: bool = False # only effective in joint control mode
|
observe_joint_vel: bool = False # only effective in joint control mode
|
||||||
manual_mode: bool = False # xArm joint teaching mode; records state and optional gripper actions
|
manual_mode: bool = False # xArm joint teaching mode; records state and optional gripper actions
|
||||||
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
|
||||||
|
|||||||
@ -102,6 +102,18 @@ def _manual_gripper_action_key(action_features):
|
|||||||
return next((key for key in action_features if key.endswith("gripper.pos")), None)
|
return next((key for key in action_features if key.endswith("gripper.pos")), None)
|
||||||
|
|
||||||
|
|
||||||
|
def _diagnostic_logs_enabled(robot) -> bool:
|
||||||
|
"""Return whether optional per-cycle diagnostics are enabled for a robot."""
|
||||||
|
config = getattr(robot, "config", None)
|
||||||
|
if config is not None and hasattr(config, "enable_logs"):
|
||||||
|
return bool(config.enable_logs)
|
||||||
|
|
||||||
|
child_robots = getattr(robot, "robots", None)
|
||||||
|
if child_robots:
|
||||||
|
return any(_diagnostic_logs_enabled(child) for child in child_robots.values())
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _manual_action_from_observation(observation, action_features, gripper_target=None):
|
def _manual_action_from_observation(observation, action_features, gripper_target=None):
|
||||||
"""Keep only robot action fields when mirroring manual-mode state."""
|
"""Keep only robot action fields when mirroring manual-mode state."""
|
||||||
action = {key: value for key, value in observation.items() if key in action_features}
|
action = {key: value for key, value in observation.items() if key in action_features}
|
||||||
@ -353,6 +365,7 @@ def record_loop(
|
|||||||
manual_gripper_action_key = _manual_gripper_action_key(robot.action_features)
|
manual_gripper_action_key = _manual_gripper_action_key(robot.action_features)
|
||||||
|
|
||||||
realtime_controller = None
|
realtime_controller = None
|
||||||
|
diagnostic_logs_enabled = _diagnostic_logs_enabled(robot)
|
||||||
sync_log_file = None
|
sync_log_file = None
|
||||||
sync_log_writer = None
|
sync_log_writer = None
|
||||||
sync_frame_index = 0
|
sync_frame_index = 0
|
||||||
@ -371,10 +384,12 @@ def record_loop(
|
|||||||
initial_observation=last_robot_cmd,
|
initial_observation=last_robot_cmd,
|
||||||
)
|
)
|
||||||
realtime_controller.start()
|
realtime_controller.start()
|
||||||
|
if diagnostic_logs_enabled:
|
||||||
sync_log_dir = Path("logs")
|
sync_log_dir = Path("logs")
|
||||||
sync_log_dir.mkdir(parents=True, exist_ok=True)
|
sync_log_dir.mkdir(parents=True, exist_ok=True)
|
||||||
sync_log_path = sync_log_dir / (
|
sync_log_path = sync_log_dir / (
|
||||||
f"gello_record_sync_{time.strftime('%Y%m%d_%H%M%S')}_{time.time_ns() % 1_000_000:06d}.csv"
|
f"gello_record_sync_{time.strftime('%Y%m%d_%H%M%S')}_"
|
||||||
|
f"{time.time_ns() % 1_000_000:06d}.csv"
|
||||||
)
|
)
|
||||||
sync_log_file = sync_log_path.open("w", newline="", buffering=1)
|
sync_log_file = sync_log_path.open("w", newline="", buffering=1)
|
||||||
sync_log_writer = csv.DictWriter(
|
sync_log_writer = csv.DictWriter(
|
||||||
@ -405,13 +420,16 @@ def record_loop(
|
|||||||
# Get robot observation
|
# Get robot observation
|
||||||
if realtime_controller is not None:
|
if realtime_controller is not None:
|
||||||
obs = robot.get_realtime_observation()
|
obs = robot.get_realtime_observation()
|
||||||
observation_monotonic_s = getattr(
|
observation_monotonic_s = getattr(robot, "_last_realtime_observation_monotonic_s", None)
|
||||||
robot, "_last_realtime_observation_monotonic_s", time.perf_counter()
|
if observation_monotonic_s is None:
|
||||||
)
|
observation_monotonic_s = time.perf_counter()
|
||||||
realtime_controller.update_observation(obs)
|
realtime_controller.update_observation(obs)
|
||||||
|
if diagnostic_logs_enabled:
|
||||||
matched_action, matched_action_sent_s = realtime_controller.action_sample_at(
|
matched_action, matched_action_sent_s = realtime_controller.action_sample_at(
|
||||||
observation_monotonic_s
|
observation_monotonic_s
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
matched_action = realtime_controller.action_at(observation_monotonic_s)
|
||||||
else:
|
else:
|
||||||
obs = robot.get_observation()
|
obs = robot.get_observation()
|
||||||
|
|
||||||
|
|||||||
@ -162,6 +162,10 @@ def teleop_loop(cfg: TeleopConfig):
|
|||||||
|
|
||||||
if cfg.guard_latency_experiment:
|
if cfg.guard_latency_experiment:
|
||||||
_validate_guard_latency_config(cfg)
|
_validate_guard_latency_config(cfg)
|
||||||
|
if hasattr(cfg.robot, "enable_logs") and not cfg.robot.enable_logs:
|
||||||
|
raise ValueError(
|
||||||
|
"Guard latency experiment requires robot.enable_logs=true"
|
||||||
|
)
|
||||||
logging.warning(
|
logging.warning(
|
||||||
"Guard latency experiment enabled: measuring GELLO, safety guard, ServoJ, "
|
"Guard latency experiment enabled: measuring GELLO, safety guard, ServoJ, "
|
||||||
"and total send latency for %.1f active seconds",
|
"and total send latency for %.1f active seconds",
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
import logging
|
import logging
|
||||||
import time
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError
|
from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError
|
||||||
from ..base_teleop import UFBaseTeleop
|
from ..base_teleop import UFBaseTeleop
|
||||||
@ -170,11 +169,8 @@ class GelloTeleop(UFBaseTeleop):
|
|||||||
def get_action(self) -> dict[str, np.ndarray]:
|
def get_action(self) -> dict[str, np.ndarray]:
|
||||||
if not self._teleop_enabled:
|
if not self._teleop_enabled:
|
||||||
raise RuntimeError("Gello teleop is disabled")
|
raise RuntimeError("Gello teleop is disabled")
|
||||||
start = time.perf_counter()
|
|
||||||
fake_obs = dict({"joint_state": np.array([0.0]*(self.dof+1))}) # for agent.act() argument, actually no use
|
fake_obs = dict({"joint_state": np.array([0.0]*(self.dof+1))}) # for agent.act() argument, actually no use
|
||||||
action_array = self.gello_agent.act(fake_obs) # current gello joint pos as np.ndarray
|
action_array = self.gello_agent.act(fake_obs) # current gello joint pos as np.ndarray
|
||||||
dt_ms = (time.perf_counter() - start) * 1e3
|
|
||||||
logger.debug(f"{self} read action: {dt_ms:.1f}ms")
|
|
||||||
|
|
||||||
action = {}
|
action = {}
|
||||||
for i in range(self.dof):
|
for i in range(self.dof):
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user