- Project Purpose
- System Architecture
- Repository Structure
- Requirements
- Hardware Description
- Firmware Setup
- GUI Setup
- How To Use
- Configuration File
- Experiment Data
- Educational Use Cases
- Optional: Build a Windows Executable
This repository combines:
- ESP32/M5Core2 firmware for DC motor control and data acquisition.
- A Python GUI to configure experiments, run tests, and save results.
- A serial communication pipeline for real-time monitoring and logging.
The project provides a reproducible and practical framework so students can:
- Configure control modes (
open-loop,position,velocity). - Run experiments with multiple input signals (
step,ramp,manual). - Export experiment data for post-processing.
- Connect control theory with embedded implementation and real measurements.
The system has three layers:
- ESP32/M5Core2 firmware.
- Serial communication between PC and the selected board (ESP32 or M5Core2).
- Python GUI for operation, visualization, and storage.
flowchart LR
A[Python GUI] -->|JSON config + START/END| B[ESP32 Firmware]
B -->|Serial data batches| A
A -->|CSV export| C[experiment_data]
.
|-- config/
| `-- config.json
|-- experiment_data/
| `-- *.csv
|-- firmware/
| |-- firmware_M5.ino
| `-- firmware_ESP32.ino
|-- images/
|-- dc_motor_gui.py
|-- send_json.py
|-- requirements.txt
`-- README.md
config/config.json: experiment and controller parameters generated and updated from the GUI.
firmware/firmware_M5.ino: M5Core2 version (includes display/touch logic throughDisplayTask).firmware_ESP32.ino: generic ESP32 version (no display task, no M5-specific dependencies).
dc_motor_gui.py- Main desktop app to connect, configure, run, stop, visualize, and save experiments.
experiment_data/- CSV output files generated from experiments.
send_json.py- Utility script to send JSON configuration over serial.
- 12 V / 5 A power supply (the required supply depends on the motor used)
- L298N H-bridge driver
- 12 V DC motor
- ESP32 or M5Core2
- Small prototyping board
- DC jack power connector
- Square ON/OFF switch
- USB cable for serial connection to the PC
- Arduino IDE
- Python 3.10+ (recommended)
- Python dependencies listed in
requirements.txt - CP210x USB driver (if required by your OS)
The kit is built around a low-cost DC motor control architecture suitable for educational laboratories.
Main hardware blocks:
- Power stage: external 12 V supply and L298N H-bridge for motor actuation.
- Control and acquisition: ESP32/M5Core2 running the firmware.
- Integration elements: prototyping board, DC jack input, and dedicated ON/OFF switch.
- Mechanical parts: base and wheel CAD files are publicly available.
- The CAD base is designed for the M5Core2-based assembly.
flowchart LR;
PS[12 V Power Supply] -->|12V| HB[L298N H-Bridge];
HB -->|Motor power| M[DC Motor];
MCU[ESP32 / M5Core2] -->|PWM_CCW_PIN GPIO25| HB;
MCU -->|PWM_CW_PIN GPIO26| HB;
MCU -->|3.3V| ENC[Motor Encoder];
ENC -->|A channel GPIO19| MCU;
ENC -->|B channel GPIO27| MCU;
GND[Common GND];
PS --- GND;
HB --- GND;
MCU --- GND;
ENC --- GND;
Pin mapping summary:
| Signal | Firmware symbol | MCU pin |
|---|---|---|
| H-bridge PWM (CCW) | PWM_CCW_PIN |
GPIO25 |
| H-bridge PWM (CW) | PWM_CW_PIN |
GPIO26 |
| Encoder channel A | ENCODER_A |
GPIO19 |
| Encoder channel B | ENCODER_B |
GPIO27 |
Connection notes:
- The H-bridge receives 12 V from the external power supply.
- The H-bridge motor outputs are connected to the motor power pins.
- The ESP32/M5Core2 drives the H-bridge with two PWM signals:
PWM_CCW_PINon GPIO25PWM_CW_PINon GPIO26
- The motor encoder is powered from 3.3 V provided by the ESP32/M5Core2.
- Encoder signals are connected as follows:
- Channel A to GPIO19 (
ENCODER_A) - Channel B to GPIO27 (
ENCODER_B)
- Channel A to GPIO19 (
- Ground must be shared by power supply, H-bridge, ESP32/M5Core2, and encoder.
Important operating note:
- This setup is designed to run connected to a PC through USB serial, with the GUI managing configuration, start/stop commands, and data logging.
- It is not intended to operate as a fully standalone kit without a host PC.
This section keeps the full step-by-step firmware setup flow.
- Use
firmware/firmware_M5.inowhen your device is M5Core2. - Use
firmware/firmware_ESP32.inowhen using a standard ESP32 board. - The ESP32 variant removes
DisplayTaskand all M5 display/touch dependencies.
Download and install from: https://www.arduino.cc/en/software/
The following steps (2 to 5) apply only to the M5Core2 workflow. If you are using a standard ESP32 board, go directly to step 6 and use firmware/firmware_ESP32.ino.
Add this board manager URL:
https://static-cdn.m5stack.com/resource/arduino/package_m5stack_index.jsonAfter installation, select the M5Core2 board:
Install M5Core2-related libraries and all dependencies.
Important:
- When prompted, install all dependent libraries too.
- Windows: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/drivers/CP210x_VCP_Windows.zip
- macOS: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/drivers/CP210x_VCP_MacOS.zip
- Linux: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/drivers/CP210x_VCP_Linux.zip
Additional reference: https://docs.m5stack.com/en/arduino/m5core2/program#2.usb%20driver%20installation
Port selection example:
Notes:
- On Windows, the port is usually
COMx(for example,COM5). - On Linux, it is usually
ttyUSBxorttyACMx.
Compile and upload the hello_world.ino example from the M5Core2 library first.
- Open the firmware that matches your board:
firmware/firmware_M5.inofor M5Core2firmware/firmware_ESP32.inofor standard ESP32
- Select board and serial port.
- Compile and upload.
- Open Serial Monitor and verify the
READYmessage appears.
Below is the M5Core2 pinout (the red pins are used in this project):
Warnings:
- Some M5Core2 pins are preconfigured, so verify wiring carefully.
- ESP32 serial ports:
Serial1is reserved for the display.Serial0is used for USB communication to the PC.Serial2is available for general use.
Install Python dependencies:
pip install -r requirements.txtRun the GUI:
python dc_motor_gui.pyRecommended experiment workflow:
- Connect the board and open the GUI.
- Select serial port and baud rate.
- Click
Connect. - Configure:
control_mode:open-loop,position,velocityinput_signal:step,ramp,manual- PID gains (
Kp,Ki,Kd) when applicable experiment_durationandsampling_rate
- Click
Send Config. - Click
Start Experiment. - Click
Stopat any time to end the run. - Click
Saveto export collected data to CSV.
Note:
Stophalts the experiment without clearing in-memory data, so saving afterward is supported.config/config.jsonis edited through the GUI controls andSend Config; manual file editing is not required.
This file is managed directly from the GUI. In normal usage, you should configure parameters in the application and click Send Config; manual editing is optional and generally unnecessary.
Common fields:
control_modeinput_signalrefKp,Ki,Kdexperiment_durationsampling_ratedead_zone_compensation
Example:
{
"control_mode": "position",
"input_signal": "step",
"ref": 0.0,
"Kp": 1.0,
"Ki": 0.0,
"Kd": 0.0,
"experiment_duration": 10.0,
"sampling_rate": 0.01,
"dead_zone_compensation": true
}Results are stored in experiment_data/ as CSV files, ready for analysis in Python, MATLAB/Octave, or Excel.
Expected CSV columns:
voltagepos_radvel_rad_per_svel_filtered_rad_per_sreftime_ms
This repository is intended for lab sessions and project-based learning in:
- Control engineering
- Industrial informatics
- Robotics
Suggested academic activities:
- Compare open-loop and closed-loop behavior.
- Tune PID controllers and evaluate transient response.
- Analyze the effect of sampling time and velocity filtering.
- Build end-to-end traceability from control command to stored dataset.
pip install pyinstaller
pyinstaller --onefile -w dc_motor_gui.pyThe executable will be generated in dist/.









