A learning module for PID angular position control of a DC motor, built on the ESP32. Tune Kp, Ki, and Kd with a rotary encoder or from a web dashboard over Wi-Fi, and watch the system response as a real-time chart.
Developed for the Electronic Engineering Department, Vocational Faculty, as a teaching aid for control systems labs.
- Overview
- Features
- System Architecture
- Hardware
- Required Libraries
- Getting Started
- Usage
- PID Configuration
- WebSocket Protocol
- Repository Structure
- Notes & Known Limitations
- References
- License
PID Trainer is an angular position control trainer. An AS5600 magnetic sensor reads the angle of the DC motor shaft, the ESP32 computes the PID control signal every 10 ms, and the motor driver moves the shaft toward the target angle.
Users can change the PID parameters and immediately see the effect on the motor response: rise time, settling time, overshoot, and steady-state error.
| Category | Feature |
|---|---|
| ๐๏ธ Control | Angular position PID with a 0.5ยฐ deadband and ยฑ30ยฐ angle limits |
| ๐ Physical interface | Kp/Ki/Kd tuning with a rotary encoder, values shown on a 1.44" TFT |
| ๐ Web dashboard | Real-time chart, PID inputs, Record, Pause, and Screenshot buttons |
| ๐ Response analysis | Rise time, settling time, overshoot, and steady-state error |
| ๐ก Connectivity | ESP32 as an Access Point with a captive portal |
| ๐งฒ Sensor | AS5600 magnet position check at boot |
| ๐ Reset | Reset PID parameters by holding the encoder button or from the web |
flowchart LR
subgraph HW["โ๏ธ Hardware"]
ENC["๐งฒ AS5600<br/>angle sensor"]
MOT["๐ง DC Motor"]
DRV["Motor driver"]
ROT["๐ Rotary encoder"]
TFT["๐ฅ๏ธ ST7735 TFT"]
end
ESP["๐ง ESP32<br/>PID @ 10 ms"]
subgraph WEB["๐ Web Dashboard"]
UI["Chart ยท PID inputs ยท Response metrics"]
end
ENC -- "I2C" --> ESP
ROT -- "Kp / Ki / Kd" --> ESP
ESP -- "PWM" --> DRV --> MOT
ESP --> TFT
ESP <-- "Wi-Fi AP + WebSocket :81" --> UI
MOT -. "shaft rotates" .-> ENC
flowchart LR
T["Target<br/>angle"] --> E(("ฮฃ"))
E -- "error" --> PID["Kpยทe + Kiยทโซe + Kdยทde/dt"]
PID -- "PWM ยฑ7" --> M["Driver + DC Motor"]
M --> S["AS5600"]
S -- "measured angle" --> E
| Component | Notes |
|---|---|
| Microcontroller | ESP32 DevKit (WROOM-32) |
| Angle sensor | AS5600 12-bit magnetic encoder |
| Motor driver | L298N (per the component list) |
| Step-down converter | LM2596 |
| Display | 1.44" 128ร128 ST7735 TFT |
| Input | Rotary encoder with push button |
| Power | 12V 2A DC adapter + panel-mount DC jack |
The full component list with purchase links is in Project/Hardware/KOMPONEN FIKS.md.
| Device | Signal | GPIO |
|---|---|---|
AS5600 (I2C, address 0x36) |
SDA | 16 |
| SCL | 17 | |
| ST7735 TFT | CS | 5 |
| RST | 4 | |
| DC | 15 | |
| Rotary encoder | CLK | 32 |
| DT | 25 | |
| SW | 13 | |
| Motor driver | RPWM | 26 |
| LPWM | 27 | |
| REN | 22 | |
| LEN | 21 |
โ ๏ธ The remaining TFT signals (SCK/MOSI) use the ESP32's default SPI pins.
Install via the Arduino Library Manager (or PlatformIO):
| Library | Purpose |
|---|---|
Adafruit GFX |
Basic graphics for the TFT |
Adafruit ST7735 and ST7789 |
ST7735 display driver |
ESPAsyncWebServer (+ AsyncTCP) |
Asynchronous web server |
WebSocketsServer (arduinoWebSockets) |
Real-time communication |
ArduinoJson |
JSON messages |
Wire, WiFi, DNSServer, SPIFFS |
Included with the ESP32 Arduino core |
- Assemble the hardware following the pin mapping above.
- Open the firmware in the Arduino IDE:
Project/Firmware/main/main.ino. - Select the board ESP32 Dev Module and install all required libraries.
- Upload the web files to SPIFFS. The
data/folder (containingindex.html,chart.min.js,tailwind.js) must be uploaded with the ESP32 Sketch Data Upload plugin. - Upload the sketch to the ESP32.
- On boot, the display shows
Checking Magnet...until the magnet is detected at the right distance. Adjust the magnet-to-AS5600 gap until the status clears.
-
Connect your device to the Wi-Fi network:
SSID PID TrainerPassword motordc1 -
Open
http://192.168.4.1(it should open automatically through the captive portal), then go to the Web Interface. -
The dashboard starts in View mode (read-only). Flip the toggle to Edit mode to change parameters.
-
Enter Kp, Ki, and Kd values, then press Set Parameter.
-
Use Record to capture data, Pause to freeze the chart, and Screenshot to save an image of the chart.
| Action | Result |
|---|---|
| Rotate | Increase/decrease the active parameter (highlighted in yellow on the TFT) |
| Short press | Switch parameter: Kp โ Ki โ Kd โ Kp |
| Hold 1.5 s | Reset Kp, Ki, Kd to 0 (with a progress bar on screen) |
| Parameter | Step per click | Range |
|---|---|---|
| Kp | 0.1 | 0 โ 1.0 |
| Ki | 0.0001 | โฅ 0 |
| Kd | 0.001 | โฅ 0 |
Initial values and key parameters in main.ino:
| Parameter | Value | Description |
|---|---|---|
Kp |
0.4 | Initial proportional gain |
Ki |
0.0003 | Initial integral gain |
Kd |
0.001 | Initial derivative gain |
pidInterval |
10 ms | PID computation period |
| Deadband | 0.5ยฐ | Errors below this value are treated as zero |
| PWM output | โ7 โฆ +7 | PID output is clamped (constrain) before reaching the driver |
CW_LIMIT / CCW_LIMIT |
+30ยฐ / โ30ยฐ | The motor stops when the angle limit is exceeded |
offsetFromZpos |
145 | Offset of the mechanical zero relative to the AS5600 reading |
The angle is read from AS5600 register 0x0E, converted with raw ร 0.087890625 (360 / 4096), reduced by offsetFromZpos, then normalized to the โ180ยฐ โฆ +180ยฐ range.
The WebSocket server runs on port 81 (ws://192.168.4.1:81/).
ESP32 โ Web (sent every PID cycle):
{
"motor": 12.3,
"kp": 0.4,
"ki": 0.0003,
"kd": 0.001,
"error": -2.1,
"pid_out": 3.0,
"time_s": 42.5
}The
kp,ki,kdfields are not sent while Edit mode is active, so the input fields are not overwritten.
Web โ ESP32:
| Command | Example message |
|---|---|
| Change mode | {"type":"mode","value":"edit"} or "view" |
| Update a parameter | {"type":"pid_single","parameter":"kp","value":0.5} |
| Reset parameters | {"type":"calibrate"} |
PID-Trainer/
โโโ LICENSE
โโโ README.md
โโโ Project/
โโโ Firmware/
โ โโโ main/ # โญ Main firmware
โ โ โโโ main.ino
โ โ โโโ KalmanFilter.h/.cpp
โ โ โโโ WebSocketServer.h
โ โ โโโ data/ # Web files for SPIFFS (index.html, chart.min.js, tailwind.js)
โ โโโ dev-process/ # Experimental & test sketches from development
โ โโโ as5600-overall/ # AS5600 reading tests
โ โโโ auto-cal-as5600/ # automatic zero calibration
โ โโโ motor-*/ # motor tests
โ โโโ pid-*/ # PID & dashboard iterations
โ โโโ GUI/ # GUI prototypes (Python & HTML)
โโโ Hardware/ # Component list
โโโ Notes/ # Project notes
โโโ Refferences/ # Concept, hardware, and image references
- ๐งช The
dev-process/folder holds experimental sketches and is not part of the final firmware. - ๐ฏ The dashboard's Set Target button sends a
target_setmessage, butmain.inocurrently has no handler for it, sotargetAnglestays fixed at 0ยฐ. - ๐งฎ
KalmanFilteris included and initialized, but is not yet used for angle readings in the main loop. - ๐ The Wi-Fi password is hard-coded. Change it if the device is used in a public environment.
- โฑ๏ธ
driveMotor()contains adelay(10), which blocks the main loop on every control cycle.
Concept references for PID, motor hardware options, and UI comparison images are in Project/Refferences.
Released under the MIT License. ยฉ 2025 Teknik Elektronika UNY.