basic bugfix with delays and disabling source switching during data collection
This commit is contained in:
37
emg_gui.py
37
emg_gui.py
@@ -29,7 +29,7 @@ from datetime import datetime
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
||||
from matplotlib.figure import Figure
|
||||
import matplotlib.animation as animation
|
||||
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
|
||||
|
||||
# Import from the existing pipeline
|
||||
from learning_data_collection import (
|
||||
@@ -545,7 +545,12 @@ class CollectionPage(BasePage):
|
||||
self.stream = RealSerialStream(port=port)
|
||||
self._update_connection_status("orange", "Connecting...")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Connection Error", f"Failed to create serial stream:\n{e}")
|
||||
error_msg = f"Failed to create serial stream:\n{e}"
|
||||
if "PermissionError" in str(type(e).__name__) or "Permission denied" in str(e):
|
||||
error_msg += "\n\nThe port may still be in use. Wait a few seconds and try again."
|
||||
elif "FileNotFoundError" in str(type(e).__name__):
|
||||
error_msg += f"\n\nPort '{port}' not found. Try refreshing the port list."
|
||||
messagebox.showerror("Connection Error", error_msg)
|
||||
return
|
||||
else:
|
||||
# Simulated stream (gesture-aware for realistic testing)
|
||||
@@ -577,6 +582,10 @@ class CollectionPage(BasePage):
|
||||
self.save_button.configure(state="disabled")
|
||||
self.status_label.configure(text="Starting...")
|
||||
|
||||
# Disable source selection during collection
|
||||
self.sim_radio.configure(state="disabled")
|
||||
self.real_radio.configure(state="disabled")
|
||||
|
||||
# Start collection thread
|
||||
self.collection_thread = threading.Thread(target=self.collection_loop, daemon=True)
|
||||
self.collection_thread.start()
|
||||
@@ -592,6 +601,9 @@ class CollectionPage(BasePage):
|
||||
try:
|
||||
if self.stream:
|
||||
self.stream.stop()
|
||||
# Give OS time to release the port (important for macOS)
|
||||
if self.using_real_hardware:
|
||||
time.sleep(0.5)
|
||||
except Exception:
|
||||
pass # Ignore cleanup errors
|
||||
|
||||
@@ -610,6 +622,10 @@ class CollectionPage(BasePage):
|
||||
self.prompt_label.configure(text="DONE", text_color="green")
|
||||
self.countdown_label.configure(text="")
|
||||
|
||||
# Re-enable source selection
|
||||
self.sim_radio.configure(state="normal")
|
||||
self.real_radio.configure(state="normal")
|
||||
|
||||
# Update connection status
|
||||
if self.using_real_hardware:
|
||||
self._update_connection_status("gray", "Disconnected")
|
||||
@@ -1387,6 +1403,10 @@ class PredictionPage(BasePage):
|
||||
self.is_predicting = True
|
||||
self.start_button.configure(text="Stop", fg_color="red")
|
||||
|
||||
# Disable source selection during prediction
|
||||
self.sim_radio.configure(state="disabled")
|
||||
self.real_radio.configure(state="disabled")
|
||||
|
||||
# Start prediction thread
|
||||
thread = threading.Thread(target=self._prediction_thread, daemon=True)
|
||||
thread.start()
|
||||
@@ -1402,6 +1422,9 @@ class PredictionPage(BasePage):
|
||||
try:
|
||||
if self.stream:
|
||||
self.stream.stop()
|
||||
# Give OS time to release the port (important for macOS)
|
||||
if self.using_real_hardware:
|
||||
time.sleep(0.5)
|
||||
except Exception:
|
||||
pass # Ignore cleanup errors
|
||||
|
||||
@@ -1412,6 +1435,10 @@ class PredictionPage(BasePage):
|
||||
self.sim_label.configure(text="")
|
||||
self.raw_label.configure(text="", text_color="gray")
|
||||
|
||||
# Re-enable source selection
|
||||
self.sim_radio.configure(state="normal")
|
||||
self.real_radio.configure(state="normal")
|
||||
|
||||
# Update connection status
|
||||
if self.using_real_hardware:
|
||||
self._update_connection_status("gray", "Disconnected")
|
||||
@@ -1453,7 +1480,10 @@ class PredictionPage(BasePage):
|
||||
try:
|
||||
self.stream = RealSerialStream(port=port)
|
||||
except Exception as e:
|
||||
self.data_queue.put(('error', f"Failed to create serial stream: {e}"))
|
||||
error_msg = f"Failed to create serial stream: {e}"
|
||||
if "Permission denied" in str(e) or "Resource busy" in str(e):
|
||||
error_msg += "\n\nThe port may still be in use. Wait a moment and try again."
|
||||
self.data_queue.put(('error', error_msg))
|
||||
return
|
||||
else:
|
||||
self.stream = GestureAwareEMGStream(num_channels=NUM_CHANNELS, sample_rate=SAMPLING_RATE_HZ)
|
||||
@@ -1668,7 +1698,6 @@ class VisualizationPage(BasePage):
|
||||
extractor = EMGFeatureExtractor()
|
||||
X_features = extractor.extract_features_batch(X)
|
||||
|
||||
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
|
||||
lda = LinearDiscriminantAnalysis()
|
||||
lda.fit(X_features, y)
|
||||
X_lda = lda.transform(X_features)
|
||||
|
||||
@@ -103,7 +103,11 @@ class RealSerialStream:
|
||||
print(f"[SERIAL] Connected to {self.port} at {self.baud_rate} baud")
|
||||
|
||||
except serial.SerialException as e:
|
||||
raise RuntimeError(f"Failed to open {self.port}: {e}")
|
||||
error_msg = f"Failed to open {self.port}: {e}"
|
||||
# Add helpful context for common errors
|
||||
if "Permission denied" in str(e) or "Resource busy" in str(e):
|
||||
error_msg += "\n\nThe port may still be in use from a previous connection. Wait a moment and try again."
|
||||
raise RuntimeError(error_msg)
|
||||
|
||||
def stop(self) -> None:
|
||||
"""
|
||||
@@ -113,9 +117,15 @@ class RealSerialStream:
|
||||
"""
|
||||
self.running = False
|
||||
|
||||
if self.serial and self.serial.is_open:
|
||||
self.serial.close()
|
||||
print(f"[SERIAL] Disconnected from {self.port}")
|
||||
if self.serial:
|
||||
try:
|
||||
if self.serial.is_open:
|
||||
self.serial.close()
|
||||
print(f"[SERIAL] Disconnected from {self.port}")
|
||||
except Exception as e:
|
||||
print(f"[SERIAL] Warning during disconnect: {e}")
|
||||
finally:
|
||||
self.serial = None
|
||||
|
||||
def readline(self) -> Optional[str]:
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user