Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
469 changes: 469 additions & 0 deletions SAMPLING_RATE_FIX_SUMMARY.md

Large diffs are not rendered by default.

38 changes: 20 additions & 18 deletions arduino/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ Arduino firmware for Grip sensor data collection.
## Setup for Data Collection

1. Install Arduino IDE
2. Open `sensor_reader/sensor_reader.ino`
3. Set baud rate to **115200**
4. Upload to Arduino Uno/Nano
5. Connect sensors to analog pins
1. Open `sensor_reader/sensor_reader.ino`
1. Set baud rate to **115200**
1. Upload to Arduino Uno/Nano
1. Connect sensors to analog pins

## Pin Configuration

| Arduino Pin | Signal Type | Sensor | Description |
|-------------|-------------|--------|-------------|
| **A0** | Raw | Sensor 4 | Raw analog signal |
| **A1** | Processed | Sensor 4 | Filtered/envelope signal |
| **A2** | Raw | Sensor 3 | Raw analog signal |
| **A3** | Processed | Sensor 3 | Filtered/envelope signal |
| **A4** | Raw | Sensor 2 | Raw analog signal |
| **A5** | Processed | Sensor 2 | Filtered/envelope signal |
| **A6** | Raw | Sensor 1 | Raw analog signal |
| **A7** | Processed | Sensor 1 | Filtered/envelope signal |
| Arduino Pin | Signal Type | Sensor | Description |
| ----------- | ----------- | -------- | ------------------------ |
| **A0** | Raw | Sensor 4 | Raw analog signal |
| **A1** | Processed | Sensor 4 | Filtered/envelope signal |
| **A2** | Raw | Sensor 3 | Raw analog signal |
| **A3** | Processed | Sensor 3 | Filtered/envelope signal |
| **A4** | Raw | Sensor 2 | Raw analog signal |
| **A5** | Processed | Sensor 2 | Filtered/envelope signal |
| **A6** | Raw | Sensor 1 | Raw analog signal |
| **A7** | Processed | Sensor 1 | Filtered/envelope signal |

## Serial Output Format

Expand All @@ -30,6 +30,7 @@ Arduino firmware for Grip sensor data collection.
**Order:** `env0,raw0,env1,raw1,env2,raw2,env3,raw3`

Where:

- `env0, raw0` = Sensor 4 (processed, raw)
- `env1, raw1` = Sensor 3 (processed, raw)
- `env2, raw2` = Sensor 2 (processed, raw)
Expand All @@ -38,16 +39,17 @@ Where:
## Viewing Data in Arduino IDE

1. Upload `sensor_reader.ino` to Arduino
2. Open **Tools → Serial Monitor**
3. Set baud rate to **115200**
4. You'll see live sensor data streaming at ~100Hz
1. Open **Tools → Serial Monitor**
1. Set baud rate to **115200**
1. You'll see live sensor data streaming at ~30Hz

Example output:

```
# Grip Sensor System - 4 Sensors, 8 Channels
# Sensor Order: 4, 3, 2, 1
# Format: env0,raw0,env1,raw1,env2,raw2,env3,raw3
# Sampling at ~100Hz
# Sampling at ~30Hz
#
512,489,523,501,534,512,545,523
511,490,522,500,535,513,544,522
Expand Down
4 changes: 2 additions & 2 deletions arduino/sensor_pwm/sensor_8ch.ino
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
const int NUM_SENSORS = 4; // 4 sensor pairs
const int SENSOR_PINS[NUM_SENSORS] = {A0, A1, A2, A3};
const int BAUD_RATE = 115200; // Fast baud rate for high sampling
const int SAMPLE_DELAY = 10; // 10ms = ~100Hz sampling
const int SAMPLE_DELAY = 33; // 33ms = ~30Hz sampling (matches data collection and inference)

void setup() {
Serial.begin(BAUD_RATE);
Expand All @@ -23,7 +23,7 @@ void setup() {
// Print startup message (for debugging in Arduino IDE)
Serial.println("# Grip Sensor System - 8 Channel");
Serial.println("# Format: env0,raw0,env1,raw1,env2,raw2,env3,raw3");
Serial.println("# Sampling at ~100Hz");
Serial.println("# Sampling at ~30Hz");
delay(1000);
}

Expand Down
2 changes: 1 addition & 1 deletion arduino/sensor_reader/sensor_reader.ino
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ void loop() {
if (i < 3) Serial.print(";");
}
Serial.println();
delay(10);
delay(33); // ~30Hz sampling rate (matches data collection and inference)
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,5 @@ void loop() {
}
}

delay(10); // 100Hz sampling rate
delay(33); // ~30Hz sampling rate (matches data collection)
}
Binary file added data/martin6/best_lstm_model.pth
Binary file not shown.
5,012 changes: 5,012 additions & 0 deletions data/martin6/raw/integrated_data_20251116_152724.csv

Large diffs are not rendered by default.

10,064 changes: 10,064 additions & 0 deletions data/martin6/raw/integrated_data_20251116_162739.csv

Large diffs are not rendered by default.

Binary file added data/martin6/scaler_inputs_lstm.pkl
Binary file not shown.
3,104 changes: 3,104 additions & 0 deletions data/martin6/test/integrated_data_20251116_153827.csv

Large diffs are not rendered by default.

Binary file added data/tobias/best_lstm_model.pth
Binary file not shown.
9 changes: 9 additions & 0 deletions data/tobias/calibration/calibration_left_hand.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
timestamp,2025-11-16T18:45:25.221550
hand,Left
finger_id,finger_name,extended_value,flexed_value
0,Thumb Tip,0.582867814493423,0.24769850744210756
1,Thumb Base,1.6730267197846638,0.7882208101675205
2,Index,1.154674476270258,0.5944333955439255
3,Middle,1.3091144701541093,0.5725791942295128
4,Ring,1.2185373136177706,0.5891036379258903
5,Pinky,1.0398178624731274,0.44178572650315145
45,590 changes: 45,590 additions & 0 deletions data/tobias/raw/integrated_data_20251116_184419.csv

Large diffs are not rendered by default.

50,040 changes: 50,040 additions & 0 deletions data/tobias/raw/integrated_data_20251116_222753.csv

Large diffs are not rendered by default.

Binary file added data/tobias/scaler_inputs_lstm.pkl
Binary file not shown.
13,189 changes: 13,189 additions & 0 deletions data/tobias/test/integrated_data_20251116_193801.csv

Large diffs are not rendered by default.

45 changes: 29 additions & 16 deletions data_collection/collectors/integrated_collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def draw_hand_ui(detector, frame, hand_label):
def collect_integrated_data(
port: str = "MOCK",
num_iterations: int = 1000,
sleep_time: float = 0.05,
sleep_time: float = 0.033, # ~30Hz to match camera framerate
batch_size: int = 100,
username: str = "default",
) -> None:
Expand Down Expand Up @@ -146,12 +146,24 @@ def collect_integrated_data(
batch_buffer = []
should_exit = False

# Timing control for consistent sampling
target_sample_rate = 30.0 # Hz (matches typical webcam framerate)
sample_interval = 1.0 / target_sample_rate
last_sample_time = time.time()

print(
f"\n🎯 Target sampling rate: {target_sample_rate} Hz ({sample_interval * 1000:.1f}ms interval)"
)
print("=" * 60)

try:
with open(csv_file, "w", newline="") as f:
writer = csv.writer(f)
write_csv_header(writer)

while sample_count < num_iterations and not should_exit:
current_time = time.time()

success, frame = cap.read()

if not success:
Expand All @@ -162,45 +174,44 @@ def collect_integrated_data(
frame = detector.findHands(frame)
key = cv2.waitKey(1) & 0xFF

# Read ALL sensor data from queue and push to monitor
# ALWAYS drain queue to keep data fresh (prevent old data accumulation)
# But only use the LATEST reading
try:
queue_count = 0
while not subscription.queue.empty():
payload = subscription.queue.get_nowait()
latest_sensor_values = parse_port_event(payload)
queue_count += 1

# Debug: print first few values
if queue_count == 1 and sample_count < 5:
print(f"First sensor data: {latest_sensor_values}")

# Push each reading to web monitor immediately
# Push to web monitor for visualization
if web_monitor and len(latest_sensor_values) == 8:
web_monitor.push_data(latest_sensor_values)
elif web_monitor:
print(
f"Warning: Got {len(latest_sensor_values)} values (expected 8)"
)

# Debug: print queue activity regularly
if queue_count > 0 and sample_count % 10 == 0:
print(
f"Queue: {queue_count} items processed | Sample: {sample_count} | Values: {latest_sensor_values[:4]}..."
)

except Exception as e:
print(f"Error parsing sensor data: {e}")
import traceback

traceback.print_exc()

# Get hand data for current frame
hand_label, finger_values = get_hand_data(detector, frame)
draw_hand_ui(detector, frame, hand_label)
draw_sensor_data_panel(frame, latest_sensor_values[:8])
draw_collection_status_bar(
frame, is_collecting, sample_count, num_iterations
)
if is_collecting:

# RATE-LIMITED COLLECTION: Only save samples at target rate
time_since_last_sample = current_time - last_sample_time

if is_collecting and time_since_last_sample >= sample_interval:
# Record sample with timestamp
last_sample_time = current_time

row = (
[datetime.now().isoformat(), sample_count]
+ latest_sensor_values[:8]
Expand All @@ -209,12 +220,13 @@ def collect_integrated_data(
)
batch_buffer.append(row)
sample_count += 1

if len(batch_buffer) >= batch_size:
writer.writerows(batch_buffer)
f.flush()
batch_buffer.clear()
print(
f"\nBatch written: {sample_count}/{num_iterations} samples"
f"\nBatch written: {sample_count}/{num_iterations} samples | Rate: {1.0 / time_since_last_sample:.1f} Hz"
)
if sample_count >= num_iterations:
if batch_buffer:
Expand All @@ -225,6 +237,7 @@ def collect_integrated_data(
f"\nCollection complete! {sample_count} samples collected."
)
break

cv2.imshow("Integrated Data Collection", frame)

if key == ord(" "):
Expand Down Expand Up @@ -306,7 +319,7 @@ def collect_integrated_data(
collect_integrated_data(
port=port,
num_iterations=100000,
sleep_time=0.05,
sleep_time=0.033, # Not used anymore, keeping for API compatibility
batch_size=100,
username=username,
)
Loading
Loading