- C++ 90.9%
- C 9.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| include | ||
| legacy code | ||
| lib | ||
| src | ||
| test | ||
| .gitignore | ||
| platformio.ini | ||
| README.md | ||
ESP32 Dual-VESC Rover Controller
Firmware for an experimental two-wheel rover using an ESP32, an ELRS/CRSF radio link and two VESC motor controllers connected through CAN/TWAI.
The controller implements differential steering, four drive modes, configurable speed limiting, acceleration/deceleration ramping, safety handling, traction control, a serial diagnostic console, OTA updates and a browser-based fallback controller.
Project status: Experimental / under active development. This software controls real motors and can cause physical movement. Test with the drive wheels lifted from the ground before operating the rover normally.
Overview
The rover uses an ESP32 as its central controller.
Control data is normally received from an ELRS receiver using the CRSF protocol. The ESP32 converts throttle and steering inputs into separate target eRPM values for the left and right motors and transmits them to two VESCs over CAN.
The firmware currently provides:
- four configurable drive modes
- user-adjustable speed limiting
- differential/skid steering
- speed-dependent steering sensitivity
- proportional acceleration and braking ramps
- CRSF link-loss failsafe
- arm/disarm handling
- Mode 1 traction/slip control
- buzzer and status LED support
- auxiliary relay output
- serial debug/test console
- Wi-Fi access point
- ArduinoOTA firmware updates
- browser-based fallback control
- WebSocket status and serial-log output
Hardware
Current design:
- ESP32-based controller
- ELRS receiver using CRSF
- two VESC motor controllers
- two brushless direct-drive hub motors
- CAN/TWAI connection between ESP32 and VESCs
- buzzer
- status LED
- auxiliary relay
Pin configuration
| Function | GPIO |
|---|---|
| CAN TX | 2 |
| CAN RX | 3 |
| ELRS RX | 0 |
| ELRS TX | 1 |
| Buzzer | 45 |
| Status LED | 47 |
| Relay | 48 |
These are the currently intended rover pin assignments.
VESC configuration
The firmware communicates with the VESCs using extended CAN frames.
Current VESC IDs:
| Motor | VESC ID |
|---|---|
| Left | 1 |
| Right | 2 |
CAN bitrate:
500 kbit/s
Motor commands are transmitted every:
20 ms
The firmware uses VESC RPM commands.
The values referred to as RPM in this project are electrical RPM (eRPM).
They must not be interpreted as mechanical wheel RPM.
Conversion between eRPM, mechanical RPM and vehicle speed depends on motor pole-pair count and wheel dimensions.
CRSF channel mapping
| Channel | Function |
|---|---|
| 1 | Steering |
| 2 | Throttle |
| 3 | Speed limit |
| 4 | unused |
| 5 | Buzzer enable |
| 6 | Drive mode |
| 7 | Arm |
| 8 | Relay |
| 9 | Mode 4 / Kick |
| 10 | unused |
The firmware currently assumes approximately:
Minimum: 988
Center: 1500
Maximum: 2012
Drive modes
Three positions of the mode switch select Modes 1–3.
Mode 4 is activated by holding the Kick button while Mode 3 is selected.
| Mode | Maximum eRPM | Steering sensitivity | Ramp limit |
|---|---|---|---|
| 1 | 1,000 | 2.0 | 50 eRPM/tick |
| 2 | 4,000 | 1.0 | 200 eRPM/tick |
| 3 | 6,000 | 0.2 | 300 eRPM/tick |
| 4 | 10,000 | 0.1 | 500 eRPM/tick |
Mode 1 is intended as the conservative low-speed maneuvering mode and is also the only mode in which traction control is enabled.
The speed-limit control on CRSF channel 3 scales the maximum allowed motor eRPM between zero and the maximum of the selected mode.
Direction handling
The current firmware does not automatically reverse the driving direction in Modes 3 or 4.
Motor direction must therefore be configured and tested on the physical rover.
Support for explicitly inverting the right motor is present in the source but currently disabled.
Steering
The rover uses differential steering.
The basic mixer works as follows:
Left motor = throttle + steering
Right motor = throttle - steering
The result is normalized when necessary to prevent either motor command from exceeding the allowed range.
Steering sensitivity depends on the selected drive mode.
Steering authority is additionally reduced as motor speed increases. This allows strong steering response during low-speed maneuvering while reducing aggressive differential steering at higher speeds.
Acceleration and braking ramp
Motor commands do not immediately jump to the requested target eRPM.
The controller gradually moves the current command toward the requested target.
The proportional component currently uses:
12% of the remaining difference per 20 ms update
Each drive mode additionally defines a hard maximum change per update.
This produces relatively large changes when the current speed is far away from the requested target and progressively smaller changes when approaching it.
Traction control
Experimental traction/slip control is active only in Mode 1.
Because the VESCs operate in RPM-control mode, the controller monitors motor current independently for each wheel.
A moving current baseline represents the recent normal load of each motor.
If the measured current drops substantially below its previous baseline while a meaningful target eRPM is requested, the controller interprets this as possible loss of traction.
The target eRPM of the affected motor is then reduced.
Current parameters:
Minimum target eRPM: 100
Minimum current baseline: 200 mA
Current-drop threshold: 50 %
RPM reduction factor: 0.4
Baseline EMA factor: 0.05
This system is experimental and must be tuned using the physical rover.
Safety and failsafe
Normal CRSF motor control requires:
- an active CRSF link
- the Arm channel to be enabled
- CRSF communication to remain inside the configured timeout
Current CRSF timeout:
500 ms
If these conditions are not satisfied, both VESC targets are set to zero.
The auxiliary relay is also disabled during the normal failsafe condition.
The status LED is switched off when the radio link is completely unavailable and blinks when a link exists but normal driving conditions are not satisfied.
Physical safety
Firmware safety systems are not substitutes for physical safety measures.
Initial motor testing should be performed with:
- the driven wheels lifted from the ground
- an accessible main power disconnect
- conservative VESC current limits
- conservative motor-speed limits
- sufficient free space around the rover
Web fallback controller
The ESP32 hosts a browser interface containing:
- rover status
- virtual joystick
- fallback-control enable switch
- live firmware log
- current left/right eRPM
- CRSF link status
- arm state
- relay state
- buzzer state
Web fallback control is only accepted when the normal RC link is unavailable.
When the CRSF link returns, web control is automatically disabled and radio control receives priority.
Fallback control is restricted to Mode 1.
A command watchdog requires fresh web-control messages within:
300 ms
Wi-Fi and OTA
The ESP32 creates its own Wi-Fi access point.
Before compiling the firmware, configure:
#define WIFI_SSID "SET OWN SSID"
#define WIFI_PASSWORD "SET OWN PASSWORD"
#define OTA_PASSWORD "SET OWN PASSWORD"
Replace these values with your own credentials in your local source tree if required.
Do not commit personal or production credentials to a public repository.
The web interface is served on:
http://<ROVER-IP>/
The ESP32 prints its access-point IP address to the serial console after Wi-Fi startup.
ArduinoOTA is also enabled on the access point.
Building with PlatformIO
The firmware is intended to be built using PlatformIO.
From the project directory:
pio run
Clean the build directory with:
pio run -t clean
Flashing over USB
Connect the ESP32 using USB.
PlatformIO can normally detect the appropriate serial port automatically:
pio run -t upload
Available serial devices can be displayed with:
pio device list
A port can also be specified explicitly.
Linux example:
pio run -t upload --upload-port /dev/ttyACM0
or:
pio run -t upload --upload-port /dev/ttyUSB0
Windows example:
pio run -t upload --upload-port COM3
After flashing, the serial monitor can be started with:
pio device monitor
The rover firmware currently uses:
115200 baud
Flashing over Wi-Fi / OTA
The rover firmware supports ArduinoOTA.
The computer performing the update must first be connected to the Wi-Fi access point created by the rover.
The rover prints its current IP address to the serial console when the access point starts.
PlatformIO requires an OTA upload environment using the espota upload protocol.
A PlatformIO environment can for example contain:
[env:rover-ota]
platform = espressif32
board = YOUR_BOARD
framework = arduino
upload_protocol = espota
upload_port = ROVER_IP
upload_flags =
--auth=YOUR_OTA_PASSWORD
ROVER_IP must be replaced with the IP address printed by the rover.
YOUR_OTA_PASSWORD must match the value configured as:
OTA_PASSWORD
The firmware can then be compiled and uploaded over WLAN using:
pio run -e rover-ota -t upload
The IP address can also be supplied directly:
pio run -e rover-ota -t upload --upload-port ROVER_IP
For example:
pio run -e rover-ota -t upload --upload-port 192.168.x.x
The first firmware installation should be performed using USB. OTA can only be used once firmware containing the OTA functionality is already running on the ESP32.
Serial debug console
Debug functionality is controlled by:
#define DEBUG_LEVEL
Current levels:
| Level | Behavior |
|---|---|
| 0 | Debugging disabled |
| 1 | Periodic information output |
| 2 | Information + verbose diagnostics + interactive console |
The current firmware uses:
#define DEBUG_LEVEL 1
The interactive console is therefore present in the firmware but only processed when DEBUG_LEVEL is changed to 2.
Available commands:
HELP
STATUS
MANUAL ON
MANUAL OFF
RPM L <value>
RPM R <value>
RPM BOTH <value>
BUZZER <frequency>
BUZZER OFF
LED ON
LED OFF
RELAY ON
RELAY OFF
OTA ON
OTA OFF
Manual motor test mode
MANUAL ON disables normal CRSF motor control and allows direct eRPM target commands through the serial console.
Example:
MANUAL ON
RPM BOTH 500
RPM BOTH 0
MANUAL OFF
Commands are restricted by the firmware's absolute eRPM limit.
The manual-control watchdog automatically leaves manual mode when no command has been received for:
30 seconds
Motor testing should only be performed with the rover physically secured.
Software dependencies
The firmware currently uses:
- Arduino framework
- AlfredoCRSF
- ESP32 TWAI driver
- WiFi
- ArduinoOTA
- ESPAsyncWebServer
- ArduinoJson
The exact board, platform and library dependencies are defined through the PlatformIO project configuration.
Important configuration values
Most rover-specific configuration is located near the beginning of main.cpp.
Important values include:
CAN_TX_PIN
CAN_RX_PIN
ELRS_RX_PIN
ELRS_TX_PIN
VESC_ID_LEFT
VESC_ID_RIGHT
BUZZER_PIN
LED_PIN
RELAY_PIN
MODE1_MAX_RPM
MODE2_MAX_RPM
MODE3_MAX_RPM
MODE4_MAX_RPM
STEERING_SENSE_MODE1
STEERING_SENSE_MODE2
STEERING_SENSE_MODE3
STEERING_SENSE_MODE4
CRSF_TIMEOUT_MS
WIFI_SSID
WIFI_PASSWORD
OTA_PASSWORD
Development status
The project is experimental and under active development.
Important areas still requiring real-world validation and tuning include:
- physical motor direction
- VESC CAN configuration
- motor pole-pair count
- eRPM-to-wheel-speed conversion
- maximum safe eRPM
- steering sensitivity
- acceleration and braking behavior
- traction-control thresholds
- CRSF failsafe behavior under real link loss
- web fallback behavior
- OTA/update recovery behavior
The comments inside main.cpp are also still undergoing cleanup and may contain outdated development notes. The actual code should be considered authoritative where comments and implementation disagree.
License
No license has been selected yet.
Until a license file is added, normal copyright restrictions apply even if the source repository is publicly accessible.