Add CSV plotting and episode recording functionality

- Implemented `plot_data_csv.py` to read CSV files and generate plots for velocity and linear acceleration signals.
- Created `record1.py` for recording ESP32 IMU data, DIN/DOUT states, and RealSense camera images into episodes.
- Enhanced `ProviderWorldIMUVelocityEstimator` to include stationary detection logic, resetting velocity when stationary.
- Updated `EpisodeWriter` to save episode data with timestamped filenames for better organization.
This commit is contained in:
Brunsmeier
2026-07-10 10:23:15 +08:00
parent b4739362a5
commit 781540d3a8
16 changed files with 18282 additions and 3 deletions

View File

@ -277,6 +277,9 @@ class ProviderWorldIMUVelocityEstimator:
self.v_world = np.zeros(3, dtype=float)
self.last_acc_world_ms2 = np.zeros(3, dtype=float)
self.stationary_count = 0
self.stationary_count_required = 10
self.gyro_deadband = 3.0 # deg/s
def reset(self):
self.start_t_ms = None
@ -288,6 +291,7 @@ class ProviderWorldIMUVelocityEstimator:
self.v_world[:] = 0.0
self.last_acc_world_ms2[:] = 0.0
self.stationary_count = 0
def gravity_body_g(self, roll_deg, pitch_deg):
roll = math.radians(roll_deg)
@ -372,9 +376,20 @@ class ProviderWorldIMUVelocityEstimator:
# ---------------- deadband before rotation ----------------
# Norm is unchanged by pure rotation, so before/after rotation both okay.
if np.linalg.norm(linear_acc_body_ms2) < self.acc_deadband:
gyro_body_dps = np.array(packet["gyro_dps"], dtype=float)
acc_is_small = np.linalg.norm(linear_acc_body_ms2) < self.acc_deadband
gyro_is_small = np.linalg.norm(gyro_body_dps) < self.gyro_deadband
if acc_is_small and gyro_is_small:
self.stationary_count += 1
linear_acc_body_ms2[:] = 0.0
if self.stationary_count >= self.stationary_count_required:
self.v_world[:] = 0.0
else:
self.stationary_count = 0
# ---------------- body frame -> world frame ----------------
R_bw = self.rot_body_to_world(
roll_deg=roll_deg,
@ -475,7 +490,9 @@ class EpisodeWriter:
if self.recording:
return
episode_name = "episode_" + datetime.now().strftime("%Y%m%d_%H%M%S")
episode_time = datetime.now().strftime("%Y%m%d_%H%M%S")
episode_name = f"episode_{episode_time}"
self.episode_dir = self.root_dir / episode_name
self.rgb_dir = self.episode_dir / "rgb"
@ -489,7 +506,7 @@ class EpisodeWriter:
if self.save_depth:
self.depth_dir.mkdir(parents=True, exist_ok=True)
csv_path = self.episode_dir / "data.csv"
csv_path = self.episode_dir / f"episode_{episode_time}_data.csv"
self.csv_file = open(csv_path, "w", newline="", encoding="utf-8")
fieldnames = [