ESP32-S3 firmware for a robotic platform with MQTT communication, motor control, battery monitoring, and display management.
- π Battery Management: Real-time voltage and current monitoring with INA219 sensor
- π Motor Control: Differential drive control for 4-wheel platforms using TB6612FNG drivers
- π± Display: ST7789 TFT display for status visualization
- π‘ Wireless: WiFi connectivity with MQTT communication protocol
- β‘ Embassy: Async/await based firmware using Embassy framework
- π§ Configurable: Easy configuration via environment variables
- ESP32-S3 development board (with at least 8MB Flash, 2MB PSRAM recommended)
- ST7789 display (135x240 pixels)
- TB6612FNG motor drivers (2x for 4-wheel drive)
- INA219 current/voltage sensor for battery monitoring
- Battery pack (2-cell Li-ion/Li-Po, 7.4V nominal)
- Rust (latest stable version)
- probe-rs for flashing and debugging
- ESP Rust toolchain for Xtensa architecture support
| Component | ESP32-S3 GPIO | Notes |
|---|---|---|
| I2C SDA | GPIO39 | For INA219 sensor |
| I2C SCL | GPIO38 | For INA219 sensor |
| ST7789 Display | SPI pins | CS, DC, RST pins (check your board) |
| Motor Drivers | PWM pins | TB6612FNG control pins |
# Install the ESP Rust toolchain
cargo install espup
espup install
# Source the environment (add to your shell profile)
. $HOME/export-esp.shyay -S probe-rsOr
# Install probe-rs for flashing
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-tools-installer.sh | shThe .cargo/config.toml file in the project root contains the configuration for the build environment.
Update it with your specific settings:
[target.xtensa-esp32s3-none-elf]
runner = "probe-rs run --chip=esp32s3 --preverify --always-print-stacktrace --no-location --catch-hardfault"
[env]
DEFMT_LOG = "info" # Log level: trace, debug, info, warn, error
SSID = "your_wifi_ssid" # Your WiFi network name
PASSWORD = "your_wifi_password" # Your WiFi password
MQTT_BROKER = "192.168.1.100" # MQTT broker IP address
MQTT_PORT = "1883" # MQTT broker port
ROBOT_ID = "0" # Unique robot identifier (0-255)
[build]
rustflags = ["-C", "link-arg=-nostartfiles"]
target = "xtensa-esp32s3-none-elf"
[unstable]
build-std = ["alloc", "core"]# Set environment variables in your shell profile (.bashrc, .zshrc, etc.)
export WIFI_SSID="your_wifi_ssid"
export WIFI_PASSWORD="your_wifi_password"
export MQTT_BROKER="192.168.1.100"Then build the project.
# Build and flash in one command (development)
cargo run
# Build and flash optimized version
cargo run --releasecargo buildcargo build --release# Run clippy for linting
cargo clippy --all-features --workspace -- -D warnings
# Format code
cargo fmt --all
# Check formatting without applying
cargo fmt --all -- --check# Flash development build
cargo run
# Flash release build (optimized)
cargo run --releaseIf you need more control over the flashing process:
# Flash with specific chip target
probe-rs run --chip=esp32s3 target/xtensa-esp32s3-none-elf/release/project-emerge-firmware
# Flash with different speed (if having connection issues)
probe-rs run --chip=esp32s3 --speed 115200 target/xtensa-esp32s3-none-elf/debug/project-emerge-firmware# Monitor serial output with RTT (Real-Time Transfer)
probe-rs run --chip=esp32s3 --catch-hardfault
# Alternative monitoring
probe-rs attach --chip=esp32s3# Run unit tests on host
cargo test# Flash and run embedded tests on actual hardware
cargo test --target xtensa-esp32s3-none-elf
# Run specific test
cargo test --target xtensa-esp32s3-none-elf -- --exact test_nameThe firmware uses MQTT for wireless communication. Replace {ROBOT_ID} with your robot's unique identifier.
| Topic | Description | Payload Example |
|---|---|---|
robot/{ROBOT_ID}/move |
Motor movement commands | {"left": 0.5, "right": -0.3} |
robot/{ROBOT_ID}/stop |
Emergency stop | {} |
robot/{ROBOT_ID}/config |
Configuration updates | {"max_speed": 0.8} |
{
"left": 0.5, // Left wheel speed: -1.0 (full reverse) to 1.0 (full forward)
"right": -0.3 // Right wheel speed: -1.0 (full reverse) to 1.0 (full forward)
}| Topic | Description | Update Frequency |
|---|---|---|
robot/{ROBOT_ID}/battery |
Battery status | Every 5 seconds |
robot/{ROBOT_ID}/status |
General robot status | On state change |
robot/{ROBOT_ID}/heartbeat |
Connection health | Every 30 seconds |
{
"battery_voltage": 7.8, // Voltage in V (5.0-8.4V range)
"battery_percentage": 85, // Percentage (0-100%)
"absorbed_current": 150, // Current draw in mA
"low_battery_warning": false // Warning flag
}Each robot must have a unique ID set in the ROBOT_ID environment variable. This is used for:
Each robot must have a unique ID (0-255) set in the ROBOT_ID environment variable. This ID is used for:
- π·οΈ MQTT topic namespacing - Ensures messages are routed correctly
- π± Display identification - Shows robot ID on the display
- π Network differentiation - Distinguishes robots on the same network
The firmware supports differential drive control:
| Parameter | Range | Description |
|---|---|---|
left |
-1.0 to 1.0 | Left wheel speed (negative = reverse) |
right |
-1.0 to 1.0 | Right wheel speed (negative = reverse) |
Movement Examples:
- Forward:
{"left": 0.5, "right": 0.5} - Backward:
{"left": -0.5, "right": -0.5} - Turn left:
{"left": -0.3, "right": 0.3} - Turn right:
{"left": 0.3, "right": -0.3}
- Battery type: 2-cell Li-ion/Li-Po (7.4V nominal)
- Voltage range: 5.0V (0%) to 8.4V (100%)
- Sensor: INA219 for current and voltage measurement
- Features:
- Real-time voltage monitoring
- Current consumption tracking
- Automatic low battery warnings
- Battery percentage calculation
# Clean build artifacts and start fresh
cargo clean
# Update all dependencies
cargo update
# Check your Rust toolchain
rustup show
# Reinstall ESP toolchain if needed
espup install --force# List connected devices
probe-rs list
# Check if ESP32-S3 is detected
lsusb | grep -i esp
# Try flashing with different speed
probe-rs run --chip=esp32s3 --speed 115200 target/xtensa-esp32s3-none-elf/debug/project-emerge-firmware
# Reset the device manually before flashing
probe-rs erase --chip=esp32s3# Check serial output with crash detection
probe-rs run --chip=esp32s3 --catch-hardfault
# Monitor logs via RTT (Real-Time Transfer)
probe-rs attach --chip=esp32s3
# Check WiFi connection status
# (Look for "WiFi connected" in the logs)Common Runtime Checks:
- β Verify WiFi credentials in config
- β Confirm MQTT broker is reachable
- β Check I2C connections for sensors
- β Ensure adequate power supply
| Error Message | Likely Cause | Solution |
|---|---|---|
Failed to initialize INA219 |
I2C connection issue | Check SDA=GPIO39, SCL=GPIO38 connections |
MQTT disconnected |
Network/broker issue | Verify broker IP and network connectivity |
WiFi connection failed |
Wrong credentials | Double-check SSID and password |
Low memory warning |
Heap exhaustion | Reduce heap usage or increase allocation |
Watchdog timeout |
Task blocking | Check for long-running operations |
src/
βββ bin/main.rs # Main application entry point
βββ lib.rs # Library root
βββ robot/ # Robot control modules
β βββ battery_manager.rs
β βββ display_manager.rs
β βββ event_loop.rs
β βββ events.rs
β βββ motors_manager.rs
β βββ mod.rs
βββ utils/ # Utility modules
βββ channels.rs
βββ mqtt_manager.rs
βββ protocol.rs
βββ topics.rs
βββ mod.rs
- Define events in
robot/events.rs - Handle events in
robot/event_loop.rs - Add MQTT topics in
utils/topics.rs - Update protocol in
utils/protocol.rs
[Add your license information here]
[Add contribution guidelines here]