Skip to content

Feature/mech dog - #5

Merged
VinceIngram07 merged 41 commits into
htil:feature/mech-dogfrom
VinceIngram07:feature/MechDog
May 1, 2026
Merged

VinceIngram07 merged 41 commits into
htil:feature/mech-dogfrom
VinceIngram07:feature/MechDog

Conversation

@VinceIngram07

Copy link
Copy Markdown
Member

Moving mech-dog updates to main repo

VinceIngram07 and others added 30 commits January 28, 2025 13:01
forward = Right
down = Left
Added new blocks (Move and Color)
Only Forward command is working with vex
WORK IN PROGRESS
Previous block functionality
still working on new block functions
Found problem: the number for the muscle energy window and the raw data doesn't match up
- need to connect the vex through AP before starting the application
- fixed colors
- no longer degrees for turn block (for kids)
- Shortcut is ready to be used (Neuroscope-EMG)
-Updated gitignore (pycache)
* src/main/index.js:
  - Fixed production build path from loadURL to loadFile with correct relative path
  - Added Python process spawning with virtual environment detection
  - Implemented WebSocket connection validation with 10s timeout
  - Added proper process cleanup on app quit and window close
  - Updated hardcoded references from Muse to Ganglion devices
  - Fixed port configuration from 3000 to 3002

* src/renderer/js/muse-client.js:
  - Fixed duplicate filters property that was overriding device name filters
  - Added Ganglion service (0xfe84) to optionalServices for proper discovery

* package.json:
  - Updated electron-builder config to include build/renderer directory
  - Added extraResources for Python executable bundling
  - Enhanced build scripts with python:build for PyInstaller integration
  - Updated serve script to use port 3002
  - Added build:local script for complete build process

* VEXServer.spec (new):
  - PyInstaller specification for Python server executable
  - Proper dependency handling for websockets and asyncio
  - Console executable configuration for debugging

* resources/python/VEXServer_dev.py (new):
  - Created simulation mode WebSocket server for development
  - Mock VEX robot with full command protocol (led_on, move, turn_left, turn_right)
  - Enables testing without physical VEX robot hardware
  - Runs on ws://127.0.0.1:8777 with JSON command interface

* requirements.txt:
  - Added PyInstaller>=5.0 for standalone executable creation

**Key Improvements:**
- Enables successful Windows executable creation with integrated Python server
- Two-process architecture provides reliable communication in both dev and production
- Fixed Bluetooth device scanning to properly detect Ganglion devices instead of Muse
- Automatic virtual environment detection in development mode
- Production builds now bundle Python server as standalone executable
- Enhanced development workflow with simulation server for hardware-free testing
…rking WebSocket management

**New Features:**
* Console UI: Replace frequency bands display with clean console output
* VEX Reconnect: Add functional reconnect button to restart VEX connection without app restart
* Enhanced Testing: Complete VEX simulation server with comprehensive test suite
* Robust WebSocket Management: Proper connection handling with reconnection support

**Console System (NEW):**
* src/renderer/js/console.js: Clean terminal-like console without timestamps/emojis
* src/renderer/index.html: Replace bands display with console container
* src/renderer/js/main.js: Integrate Console class replacing BandPowerVis
* src/renderer/js/wrapper-functions.js: Connect blockly_print to console output

**VEX Reconnect System (FULLY FUNCTIONAL):**
* src/main/index.js: Complete WebSocket connection management with proper scoping
  - Added stopPythonServer() and reconnectVEX() process management
  - Moved WebSocket variables and functions to global scope for proper access
  - Implemented createWebSocketConnection() with timeout and error handling
  - Fixed function scoping issues that prevented reconnection
* src/main/preload.js: Expose vexReconnect IPC method to renderer
* src/renderer/index.html: Add VEX reconnect button in sidebar (orange refresh icon)
* src/renderer/js/events.js: Implement reconnect button handler with visual feedback

**Enhanced VEX Testing:**
* resources/python/VEXServer_dev.py: Complete simulation server with full command support
* test_vex_server.py: Comprehensive WebSocket test suite for validation

**Key Technical Improvements:**
- Fixed variable scoping: ws and createWebSocketConnection now accessible globally
- Proper WebSocket lifecycle management: Close old connections before creating new ones
- Enhanced error handling with timeout protection and graceful fallbacks
- Clean console replaces cluttered frequency bands display
- Robust reconnection process with proper server restart sequence
- Enhanced print blocks accept any data type and output to console

**WebSocket Reconnection Flow:**
1.  Close existing WebSocket connection
2.  Stop Python VEX server gracefully (SIGTERM with SIGKILL fallback)
3.  Wait 2 seconds for cleanup
4.  Restart Python VEX server
5.  Wait 3 seconds for server initialization
6.  Re-establish WebSocket connection with timeout protection
7.  Resume VEX command functionality
**Block-to-Text Converter:**
* src/renderer/js/simple-text-view.js: Text coding environment using Blockly's built-in code generation
* src/renderer/index.html: Add toggle buttons for block/text modes and export functionality
* src/renderer/js/main.js: Integrate text view with existing Blockly system
… app rename

Python (resources/python):

Add resilient AIM connection loop; server stays alive and retries when robot is offline

Add reconnect_robot action to reset robot connection without restarting server

Add disconnect_robot cleanup to close websocket threads and sockets before re-init

Add status action reporting robot_connected for UI

Improve connection logs (attempting / connected / retry)

Electron main (src/main):

Detect and spawn bundled VEXServer.exe in production

Replace waitOn websocket probe with lightweight TCP port polling

Guard reconnectVEX against overlap and clear force-kill timer to avoid killing new process

Periodically poll server status and relay to renderer via vex-status

Fix false-positive connected state by distinguishing wsConnected vs robotConnected

Add lazy-init UDP sockets for Tello (no bind to 9000/8890 until needed)

Renderer:

Add connectivity status dot showing wsConnected (grey/yellow) and robotConnected (green)

Add onVexStatus and requestVexStatus to preload for UI updates

Packaging/build:

Ensure PyInstaller bundle includes vex module/resources and fix spec path resolution

Use process.resourcesPath/python/VEXServer.exe in production and improve spawn/path logging

Naming/branding:

Rename app to "NeuroBlock EMG for VEX" (productName/appId, window title, HTML title)

Docs:

Update README with "Adding a New Blockly Block (Example: VEX Kicker)" section and build notes

Notes:

Reconnect button sends reconnect_robot when local websocket is up; only restarts Python process if websocket is down

Status dot: grey = websocket down, yellow = websocket up/robot down, green = robot connected

Avoid binding to port 9000 unless Tello is actively used
…X integration

### Application Branding & Identity
- Rename app from 'NeuroBlock EMG for VEX' → 'NeuroBlock EEG for VEX'
- Update package.json productName, window title, and HTML title
- Update appId to reflect EEG focus: com.htil.neuroblock-emg-vex

### EEG Signal Processing (Muse Headset)
- Restore Signal class for real-time EEG data buffering (512-sample buffer)
- Restore BandPowerVis for frequency band visualization (delta, theta, alpha, beta, gamma)
- Restore FeatureExtractor for band power computation from raw EEG samples
- Restore BLE (Bluetooth Low Energy) integration for Muse headset connection
- Wire Muse eegReadings callback → Signal.add_data() for live data streaming

### UI Layout - Two-Panel Design
- Left panel (45% width):
  * Top card (40vh): 4 EEG channel graphs (channels 0-3 from Muse)
  * Bottom card (40vh): Band power frequency spectrum visualization
- Right panel (55% width):
  * Blockly visual programming editor for robot control
  * VEX AIM robot command center and status display
  * Console output and device connection status
…band power metrics and fixing controls_if handler
Copilot AI review requested due to automatic review settings May 1, 2026 16:27
@VinceIngram07
VinceIngram07 merged commit 207d945 into htil:feature/mech-dog May 1, 2026
2 of 3 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates “mech-dog” (MechDog/VEX) support into the main Electron app by adding a Python robot backend, IPC bridges, new Blockly blocks/categories, and a blocks↔text-code view/export flow.

Changes:

  • Add a Python WebSocket backend (MechDog + VEX AIM) and wire it into the Electron main process with reconnect/status polling.
  • Expand Blockly with MechDog/VEX control + telemetry blocks and add validation improvements.
  • Add text-mode/editor/conversion utilities and export tooling, plus assorted test/demo assets and build scripts.

Reviewed changes

Copilot reviewed 39 out of 52 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
test_vex_server.py Adds a simple Python WebSocket smoke-test script for the dev server.
test-reconnect.js Adds a Node.js script to test WebSocket reconnection behavior.
test-converter.html Adds a browser test page for the block-to-text converter.
src/renderer/js/wrapper-functions.js Adds safer band-power getters, MechDog telemetry getters, and VEX/MechDog command wrappers.
src/renderer/js/text-editor.js Adds a Monaco-based text editor component with Python completions.
src/renderer/js/simple-text-view.js Adds a simple blocks→text display/export controller.
src/renderer/js/muse-client.js Adjusts Bluetooth request options (services) for Muse/Ganglion connections.
src/renderer/js/main.js Adds global telemetry/band-power initialization and VEX status handling for UI readouts.
src/renderer/js/interpreter-api.js Exposes new wrapper functions (MechDog/VEX + kicker + muscle energy) to js-interpreter.
src/renderer/js/feature-extractor.js Hardens relative band power calculation (avoids divide-by-zero/undefined).
src/renderer/js/events.js Adds export + MechDog reconnect UI event handlers and sends a stop command on stop.
src/renderer/js/customblock.js Adds MechDog telemetry blocks, muscle energy block, and multiple VEX/MechDog control blocks.
src/renderer/js/console.js Adds an in-app console UI and API (window.neuroConsole usage).
src/renderer/js/coding-mode-manager.js Adds a “blocks vs text” mode manager (Monaco + Blockly sync/export).
src/renderer/js/categories.js Adds a MechDog category and includes muscle energy in Data category.
src/renderer/js/blockly-main.js Adds block validation UX, adds MechDog category to toolbox, improves run flow and error reporting.
src/renderer/js/block-to-text-converter.js Adds a Blockly workspace → Python-like text converter module.
src/renderer/index.html Updates UI for text mode/editor, adds export/reconnect controls, adds MechDog sonar readout.
src/main/tello.js Lazily instantiates the Tello controller to avoid initializing unless needed.
src/main/preload.js Exposes new IPC APIs for VEX/MechDog commands, status, reconnect, and generic sendCommand.
src/main/index.js Adds Python backend process management, WebSocket client, IPC routing, polling, and packaging path changes.
src/main/index copy.js Minor formatting tweak in dev reloader try/catch.
setup-venv.sh Adds a helper script to create/activate a Python venv and install requirements.
resources/python/vex/vex_types.py Adds VEX AIM API type definitions and constants.
resources/python/vex/vex_messages.py Adds VEX AIM WebSocket message definitions.
resources/python/vex/vex_globals.py Adds VEXcode-style globals to mirror VEX API ergonomics.
resources/python/vex/settings.py Adds settings loader for VEX AIM configuration.
resources/python/vex/settings.json Adds default VEX connection settings (host).
resources/python/vex/__pycache__/vex_globals.cpython-313.pyc Adds a compiled Python bytecode artifact (should not be tracked).
resources/python/vex/__pycache__/settings.cpython-313.pyc Adds a compiled Python bytecode artifact (should not be tracked).
resources/python/vex/__pycache__/__init__.cpython-313.pyc Adds a compiled Python bytecode artifact (should not be tracked).
resources/python/vex/__init__.py Adds VEX package init re-exporting AIM/types.
resources/python/VexTest.py Adds a Python WebSocket test script for VEX server commands.
resources/python/VEXServer_dev.py Adds a mock VEX server for development without hardware.
resources/python/VEXServer.py Adds a VEX AIM WebSocket server with reconnect/status/kicker support.
resources/python/MechDogServer.py Adds a BLE-backed MechDog WebSocket server with telemetry and action commands.
requirements.txt Adds Python dependencies for servers (websockets, bleak, pyinstaller, etc.).
programs/maze_program_emg.xml Adds a sample Blockly program using muscle energy + VEX movement.
package.json Updates dev server port, adds python build scripts, updates Electron builder config/resources, adds deps.
block-text-demo.html Adds a standalone demo page for block-to-text conversion.
VEXServer.spec Adds PyInstaller spec (currently building MechDogServer.exe).
README.md Replaces placeholder README with detailed usage/build/docs (incl. VEX kicker pattern).
Neuroscope.bat Adds a Windows batch helper to activate venv and run the app.
Neuroscope-EMG.lnk Adds a Windows shortcut artifact (should not be tracked).
.gitignore Adds ignores for Python bytecode and venv-related paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +132 to +137
if (window.electronAPI && typeof window.electronAPI.vexKicker === 'function') {
window.electronAPI.vexKicker(k);
} else {
// Fallback to generic command if alias missing (defensive)
window.electronAPI.sendCommand({ action: "kicker", type: k });
}

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vex_kicker() checks window.electronAPI only in the if branch, but the else branch still calls window.electronAPI.sendCommand(...) and will throw if electronAPI is undefined. Guard sendCommand as well (or no-op / log) so this stays truly defensive.

Copilot uses AI. Check for mistakes.
Comment on lines +249 to +253
toast.innerHTML = `
<i class="close icon" onclick="this.parentElement.remove()"></i>
<div class="header">${type.charAt(0).toUpperCase() + type.slice(1)}</div>
<p>${message}</p>
`;

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

showMessage() builds the toast using innerHTML and interpolates message directly into the HTML. Since message can include error.message (and could contain user-controlled content), this creates an XSS injection path. Prefer building DOM nodes and setting textContent for the message body/header instead of using innerHTML.

Copilot uses AI. Check for mistakes.
'''A percentage unit that represents a value from 0% to 100%'''
LEFT = TurnType.LEFT
'''A turn unit that is defined as left turning.'''
RIGHT = TurnType.LEFT

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RIGHT is incorrectly assigned to TurnType.LEFT, so any code using the global RIGHT constant will behave like a left turn. This should reference TurnType.RIGHT.

Suggested change
RIGHT = TurnType.LEFT
RIGHT = TurnType.RIGHT

Copilot uses AI. Check for mistakes.
Comment on lines +5 to 6
let dr // 1. Define the block's JSONks_color = 70;

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 5 is a corrupted variable declaration (let dr // ... ks_color = 70;) which makes this file invalid JavaScript and will break the renderer build at import time. Restore the original drone_blocks_color declaration (or otherwise fix the declaration) so the module parses.

Copilot uses AI. Check for mistakes.
Comment thread src/renderer/js/events.js
Comment on lines +115 to +118
const button = document.getElementById("vex-reconnect");
const originalHTML = button.innerHTML;
button.innerHTML = '<i class="spinner loading icon"></i>';
button.disabled = true;

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reconnect_vex() assumes document.getElementById("vex-reconnect") always exists; if it’s missing, button.innerHTML will throw and break the handler. Add a null check (or use the existing eById helper) before reading/modifying the button.

Copilot uses AI. Check for mistakes.
Comment on lines +114 to +117
// Resize Blockly
if (this.blocklyWorkspace) {
Blockly.svgResize(this.blocklyWorkspace);
}

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file calls Blockly.svgResize(...) but does not import Blockly, so switching modes will throw a ReferenceError: Blockly is not defined. Import Blockly (e.g. from blockly/core) or route resizing through an injected dependency.

Copilot uses AI. Check for mistakes.
Comment on lines +241 to +244
handlePrint(block) {
const value = this.getFieldOrInputValue(block, 'VALUE', '"Hello World"');
this.addLine(`print(${value})`);
}

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The converter’s handlers don’t match the actual custom block input names/types. For example, the print block’s input is named val (see customblock.js), but handlePrint() looks for VALUE, so conversions will always fall back to the default string. Align the converter’s field/input names with the real Blockly block definitions so the generated text reflects the workspace accurately.

Copilot uses AI. Check for mistakes.
Comment on lines +37 to 41
vex_kicker: this.wrapperFunctions.vex_kicker,

// ← NEW: expose muscle energy from window.filteredSample
getMuscleEnergy: () => window.filteredSample
};

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getMuscleEnergy returns window.filteredSample, but that global is not defined anywhere else in the codebase right now, so this will always be undefined. Either define/update window.filteredSample where the EMG feature is computed, or make this function return a numeric default (and/or compute muscle energy directly) so the muscle_energy block reliably outputs a Number.

Copilot uses AI. Check for mistakes.
Comment thread src/renderer/index.html
Comment on lines +78 to +89
<div style="position: absolute; right: 5px; top: 260px; z-index: 100">
<button id="exportCode" class="huge circular ui teal icon button" style="display: inherit; margin-left: auto"
title="Export code as Python file">
<i class="download icon"></i>
</button>
</div>

<!-- File Upload-->
<input type="file" id="file_handler" style="display: none" />
<div style="position: absolute; right: 5px; top: 260px; z-index: 100">
<button id="bluetooth" class="huge circular ui blue icon button" style="display: inherit; margin-left: auto">
<i class="bluetooth icon"></i>
</button>
</div>

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new Export and Bluetooth buttons are both positioned at top: 260px, so they will overlap and one will be unclickable depending on z-index/DOM order. Adjust the layout so each button has a unique position (or use a vertical button group) to avoid UI collision.

Copilot uses AI. Check for mistakes.
Comment thread setup-venv.sh
Comment on lines +22 to +25
# Activate the venv
echo "Activating virtual environment..."
source venv/Scripts/activate

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script is named setup-venv.sh but activates the venv using the Windows path (venv/Scripts/activate). On macOS/Linux the activation script is typically venv/bin/activate, so the current script will fail. Update it to detect platform/shell and use the correct activate path (and consider aligning the venv dir name with .venv used elsewhere).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants