Skip to content
Draft
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
11 changes: 11 additions & 0 deletions XIAO_ESP32S3_MIDI_Stepper/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.pio/
build/
dist/
__pycache__/
*.pyc
*.bin
*.elf
*.hex
*.map
.vscode/
.DS_Store
65 changes: 65 additions & 0 deletions XIAO_ESP32S3_MIDI_Stepper/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# XIAO ESP32-S3 MIDI Stepper Player

Standalone project for a Seeed XIAO ESP32-S3-based MIDI stepper controller.
This repository is separate from the Gauge workspace and is designed to use a host MIDI bridge and serial-controlled stepper drivers.

## Features
- XIAO ESP32-S3 PlatformIO project using `AccelStepper`
- Three independent stepper outputs with a shared enable pin
- Host-side MIDI parsing with serial commands
- Compatible with the BarlowTJ48 MIDI stepper example flow

## Getting started
1. Open this folder in VS Code.
2. Build with PlatformIO.
3. Flash the XIAO ESP32-S3 with the firmware in `src/main.cpp`.
4. Install Python dependencies: `pip install -r requirements.txt`.
5. Run `python midi_interface.py COMx` (replace `COMx` with your XIAO serial port).
6. Select a MIDI input port and send notes to channels 0, 1, and 2.

## Wiring
- Connect each stepper driver STEP/DIR pins to the GPIO pins defined in `src/main.cpp`.
- Connect the shared stepper driver enable pin to `ENABLE_PIN`.
- Power the stepper drivers from an external supply (e.g. 12V), not from the XIAO USB.

## Notes
- MIDI is parsed on the host PC and sent to the XIAO over USB serial.
- The firmware accepts commands of the form `s,<motor>,<speed>`, `e,<motor>`, and `d`.
- This project is configured for 3 motors, matching the XIAO's available GPIO and your hardware setup.

## Packaging as a single Windows EXE (PyInstaller)

1. Install Python requirements in the environment you'll run PyInstaller from:

```powershell
python -m pip install -r requirements.txt
```

2. Build a one-file EXE using PyInstaller (console output):

```powershell
pyinstaller --onefile --console launcher.py
```

3. To embed an icon, place an ICO at `assets/app.ico` and either:

```powershell
pyinstaller --onefile --icon=assets/app.ico launcher.py
```

or use the provided spec file:

```powershell
pyinstaller launcher.spec
```

4. The built executable will be at `dist\launcher.exe`. Run it with the COM port:

```powershell
dist\launcher.exe COM3
```

Notes:
- Use `--noconsole` to hide the console window (not recommended for debugging).
- If PyInstaller misses imports (e.g., `rtmidi`), add `--hidden-import=rtmidi` or edit `launcher.spec`.
- Test the EXE on the target Windows machine where the XIAO is connected.
Submodule example_repo added at 021ba0
13 changes: 13 additions & 0 deletions XIAO_ESP32S3_MIDI_Stepper/assets/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Place a Windows ICO file here named `app.ico` if you want an embedded icon in the EXE.

Recommended size: include multiple sizes in the ICO (16x16, 32x32, 48x48, 256x256) for best results.

Example usage with PyInstaller (from project root):

pyinstaller --onefile --icon=assets/app.ico launcher.py

Or use the provided spec file:

pyinstaller launcher.spec

Note: The spec references `assets/app.ico` as the icon path.
84 changes: 84 additions & 0 deletions XIAO_ESP32S3_MIDI_Stepper/docs/wiring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Wiring (text-only)

This project uses a Seeed XIAO ESP32-S3 as the controller, three stepper motor drivers, and an external motor power supply.

XIAO -> Stepper driver signal wiring (default pins used in `src/main.cpp`):

- GPIO2 -> STEP0
- GPIO5 -> DIR0
- GPIO3 -> STEP1
- GPIO6 -> DIR1
- GPIO4 -> STEP2
- GPIO7 -> DIR2
- GPIO8 -> ENABLE (shared enable for drivers)

Important notes and safety:

- Connect all stepper driver GND pins to the XIAO GND. The drivers and XIAO must share a common ground.
- Power the stepper drivers from an external motor supply (for example 12V). Do NOT power the motors from the XIAO USB.
- Keep motor power wiring separate from logic wiring as much as possible; use short, thick wires for motor supply and twisted pairs where appropriate.
- Before connecting motors to drivers, verify coil pair polarity using a multimeter or the paperclip polarity test; reversed coils will reduce torque or cause poor operation.
- Set current limit on your driver (A4988/DRV8825 or similar) appropriately for your motors before running at full speed.

MIDI and host-side bridge (recommended flow):

- The XIAO runs a serial command firmware (see `src/main.cpp`). MIDI is parsed on the host PC by `midi_interface.py`.
- Connect the XIAO to the PC over USB. Run the Python bridge:

```bash
pip install -r requirements.txt
python midi_interface.py COMx
```

- Select the desired MIDI input port when prompted and play notes on MIDI channels 0, 1 and 2 (they map to motors 0..2).

Troubleshooting quick tips:

- If motors do not move, verify the shared `ENABLE` pin state and that each driver's `STEP`/`DIR` pins are connected to the pins listed above.
- If movement sounds wrong, re-check motor coil polarity and driver current limit.
- Use the serial monitor at `115200` to view status messages from the firmware.

If you want the wiring document converted to a printable PDF or a separate schematic SVG later, say so and I will add that.
# Wiring Diagrams

This project uses a Seeed XIAO ESP32-S3 as the controller, three stepper motor drivers, and an external power supply for the motors.

## XIAO to Stepper Driver Wiring

- `GPIO2` -> `STEP0`
- `GPIO5` -> `DIR0`
- `GPIO3` -> `STEP1`
- `GPIO6` -> `DIR1`
- `GPIO4` -> `STEP2`
- `GPIO7` -> `DIR2`
- `GPIO8` -> `ENABLE`

### Notes
- All stepper driver grounds must be connected to the XIAO ground.
- Motor power must come from the stepper driver power supply, not the XIAO USB.
- Use separate wiring for motor power and logic power when possible.

## Example Diagram

![XIAO Stepper Wiring](images/xiao_stepper_wiring.svg)

## Reference Images

The following real-device reference photos are pulled from the example MIDI stepper project and show the type of stepper enable wiring and motor driver setup used in similar builds.

![Stepper driver enable jumper](images/a_stepper_enable.png)
*Example: stepper driver enable jumper configuration.*

![Stepper motor polarity test](images/polarity_test.jpg)
*Example: verifying stepper coil polarity before connecting to the driver.*

![Driver and motor layout](images/motor_5_configuration.png)
*Example: stepper driver board and motor wiring layout.*

## MIDI / Serial Bridge Wiring

For this project, MIDI is interpreted on the host PC and sent to the XIAO via USB serial.

- XIAO USB -> PC USB
- Host runs `midi_interface.py`
- MIDI input port selected from your DAW or MIDI device
47 changes: 47 additions & 0 deletions XIAO_ESP32S3_MIDI_Stepper/launcher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import argparse
import subprocess
import sys

def install_requirements():
subprocess.check_call([sys.executable, '-m', 'pip', 'install', '-r', 'requirements.txt'])


def main():
parser = argparse.ArgumentParser(description='Launch MIDI -> Stepper bridge')
parser.add_argument('comport', nargs='?', help='XIAO COM port (e.g. COM3)')
parser.add_argument('--pitch', action='store_true', help='Enable pitch bending')
parser.add_argument('--install', action='store_true', help='Install Python requirements before running')
args = parser.parse_args()

if args.install:
print('Installing requirements...')
try:
install_requirements()
except subprocess.CalledProcessError:
print('Failed to install requirements. Exiting.')
sys.exit(1)

if not args.comport:
args.comport = input('Enter XIAO COM port (e.g. COM3): ').strip()
if not args.comport:
print('No COM port provided, exiting.')
sys.exit(1)

# Import here so packaging picks up the module
try:
import midi_interface
except Exception as e:
print('Failed to import midi_interface:', e)
print('Make sure this script is run from the project folder or that the package is built correctly.')
sys.exit(1)

argv = [args.comport]
if args.pitch:
argv.append('pitch_bending')

# Call the main function from midi_interface
ret = midi_interface.main(argv)
sys.exit(ret)

if __name__ == '__main__':
main()
35 changes: 35 additions & 0 deletions XIAO_ESP32S3_MIDI_Stepper/launcher.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis(['launcher.py'],
pathex=['.'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
cipher=block_cipher)

pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='launcher',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True,
icon='assets/app.ico')

coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
name='launcher')
Loading