EMG-Hand-Control / code /collect_hand_data.py
malansi's picture
Update hand_module/collect_hand_data.py โ€” 2026-07-07 18:04
37046a6 verified
Raw
History Blame Contribute Delete
7.58 kB
# collect_hand_data.py
# Guided EMG data collection for prosthetic hand control
# 10 gestures x 10 rounds x 5 seconds
import asyncio
import myo
from myo import ClassifierMode, EMGMode, IMUMode
import csv
import os
import time
from datetime import datetime
FS = 200
GESTURES = {
0: {
'name': 'rest',
'instruction': 'Rest your hand completely flat โ€” do not move anything',
},
1: {
'name': 'fist',
'instruction': 'Close ALL fingers into a tight fist',
},
2: {
'name': 'grasp',
'instruction': 'Curl fingers into a C-shape โ€” like holding a cup or bottle. NOT a full fist, leave space in the middle',
},
3: {
'name': 'index',
'instruction': 'Extend INDEX finger only โ€” keep all others closed in a fist',
},
4: {
'name': 'middle',
'instruction': 'Extend MIDDLE finger only โ€” keep all others closed in a fist',
},
5: {
'name': 'ring',
'instruction': 'Extend RING finger only โ€” keep all others closed. Take your time, this is hard',
},
6: {
'name': 'pinky',
'instruction': 'Extend PINKY finger only โ€” keep all others closed in a fist',
},
7: {
'name': 'thumb',
'instruction': 'Extend THUMB only โ€” keep all other fingers closed in a fist',
},
8: {
'name': 'wrist_rotate_out',
'instruction': 'Rotate wrist so palm faces DOWN toward the table โ€” arm stays still',
},
9: {
'name': 'wrist_rotate_in',
'instruction': 'Rotate wrist so palm faces UP toward you โ€” arm stays still',
},
}
ROUNDS = 10
HOLD_SECONDS = 5
REST_SECONDS = 4
COUNTDOWN = 4
class State:
emg_buffer = []
is_recording = False
sample_count = 0
STATE = State()
class Collector(myo.MyoClient):
async def on_emg_data(self, emg: myo.EMGData):
for sample in [emg.sample1, emg.sample2]:
if STATE.is_recording:
STATE.emg_buffer.append(list(sample))
STATE.sample_count += 1
async def on_imu_data(self, _): pass
async def on_classifier_event(self, _): pass
async def on_aggregated_data(self, _): pass
async def on_emg_data_aggregated(self, _): pass
async def on_fv_data(self, _): pass
async def on_motion_event(self, _): pass
def save_session(session_dir, all_data):
os.makedirs(session_dir, exist_ok=True)
filepath = f"{session_dir}/emg_data.csv"
with open(filepath, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow([
'emg_0', 'emg_1', 'emg_2', 'emg_3',
'emg_4', 'emg_5', 'emg_6', 'emg_7',
'label', 'gesture', 'timestamp'
])
for row in all_data:
writer.writerow(row)
print(f"\n Saved {len(all_data):,} samples โ†’ {filepath}\n")
return filepath
async def countdown_display(seconds, message):
for i in range(seconds, 0, -1):
print(f"\r โณ {message} โ€” {i}s ", end='', flush=True)
await asyncio.sleep(1)
print(f"\r โœ… GO! ")
async def run_collection():
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
session_dir = f"hand_module/sessions/session_{timestamp}"
print("\n" + "โ•" * 64)
print(" PROSTHETIC HAND โ€” EMG DATA COLLECTION")
print("โ•" * 64)
print(f"\n Gestures : {len(GESTURES)}")
print(f" Rounds : {ROUNDS} per gesture")
print(f" Hold : {HOLD_SECONDS}s each")
print(f" Rest : {REST_SECONDS}s between gestures")
print(f"\n Place your arm comfortably on the table.")
print(f" Only your hand/wrist moves โ€” keep your arm still.\n")
print(" Starting in 8 seconds โ€” get ready!")
await asyncio.sleep(8)
all_data = []
total_steps = len(GESTURES) * ROUNDS
step = 0
for gesture_id, gesture_info in GESTURES.items():
name = gesture_info['name']
instruction = gesture_info['instruction']
print(f"\n{'โ•'*64}")
print(f" GESTURE: {name.upper()}")
print(f" {instruction}")
print(f"{'โ•'*64}")
print(f" Study this gesture โ€” starting in {COUNTDOWN} seconds...")
await countdown_display(COUNTDOWN, f"Prepare for {name.upper()}")
for round_num in range(1, ROUNDS + 1):
step += 1
progress = f"[{step}/{total_steps}]"
print(f"\n {progress} Round {round_num}/{ROUNDS} โ€” {name.upper()}")
print(f" ๐Ÿ‘‰ {instruction}\n")
# countdown ู‚ุจู„ ุงู„ุชุณุฌูŠู„
await countdown_display(3, "Get ready")
# ุงุจุฏุฃ ุงู„ุชุณุฌูŠู„
print(f" ๐ŸŸข RECORDING โ€” hold steady for {HOLD_SECONDS} seconds!\n")
STATE.emg_buffer = []
STATE.sample_count = 0
STATE.is_recording = True
start = time.time()
while time.time() - start < HOLD_SECONDS:
elapsed = time.time() - start
progress_bar = int(elapsed / HOLD_SECONDS * 20)
bar = 'โ–ˆ' * progress_bar + 'โ–‘' * (20 - progress_bar)
print(f"\r [{bar}] {elapsed:.1f}s / {HOLD_SECONDS}s "
f"({STATE.sample_count} samples)",
end='', flush=True)
await asyncio.sleep(0.1)
STATE.is_recording = False
print()
# ุงุญูุธ ุงู„ู€ samples ู…ุน ุงู„ู€ label
ts = datetime.now().isoformat()
for sample in STATE.emg_buffer:
row = sample + [gesture_id, name, ts]
all_data.append(row)
samples = len(STATE.emg_buffer)
print(f" โœ… Captured {samples} samples "
f"({samples/FS:.1f}s)")
# ุฑุงุญุฉ ุจูŠู† ุงู„ู€ rounds (ุฅู„ุง ุขุฎุฑ round ููŠ ูƒู„ gesture)
if round_num < ROUNDS:
print(f"\n ๐Ÿ˜Œ Rest...")
await countdown_display(REST_SECONDS, "Relax your hand")
# ุฑุงุญุฉ ุฃุทูˆู„ ุจูŠู† ุงู„ู€ gestures
if gesture_id < len(GESTURES) - 1:
print(f"\n ๐Ÿ’ค Gesture complete! Rest for 6 seconds before next gesture.")
await countdown_display(6, "Relax completely")
# ุงุญูุธ ูƒู„ ุงู„ุฏุงุชุง
filepath = save_session(session_dir, all_data)
# ู…ู„ุฎุต
print("\n" + "โ•" * 64)
print(" SESSION COMPLETE")
print("โ•" * 64)
print(f"\n {'Gesture':<20} {'Samples':<12} {'Duration'}")
print(" " + "โ”€" * 45)
for gesture_id, info in GESTURES.items():
name = info['name']
samples = sum(1 for r in all_data if r[8] == gesture_id)
dur = samples / FS
print(f" {name:<20} {samples:<12,} {dur:.1f}s")
total = len(all_data)
print(f"\n Total: {total:,} samples ({total/FS:.0f}s)")
print(f" Saved: {filepath}")
print("โ•" * 64)
async def main():
print("๐Ÿ” Scanning for Myo Armband...")
client = await Collector.with_device()
print(f"โœ… Connected: {client.device.name}\n")
await client.setup(
classifier_mode=ClassifierMode.DISABLED,
emg_mode=EMGMode.SEND_EMG,
imu_mode=IMUMode.SEND_DATA,
)
await client.start()
try:
await run_collection()
except KeyboardInterrupt:
print("\n\n Interrupted โ€” saving collected data so far...")
finally:
await client.stop()
await client.disconnect()
print(" Done.")
if __name__ == "__main__":
asyncio.run(main())