Bringing the Robotics Controller to Life, Firmware and Software
In a previous post, I focused on the hardware side of my custom ESP32 S3 robotics controller PCB, including the board layout, grounding strategy, power distribution, and the decisions that went into turning a prototype wiring setup into a real four layer design. That hardware was a huge milestone for me, but a robotics controller is only half finished until the firmware gives it behavior, structure, and a usable interface. The software side is what turns the board from a collection of connected parts into an actual development platform.
For this stage of the project, I focused on building firmware that was modular, scalable, and practical to work with during development. I did not want a single giant source file with everything packed into one place. Instead, I organized the project into separate modules for motors, servos, ultrasonic sensors, hall sensors, the IMU, buttons, the display, the user interface, robot modes, games, and wireless communication. That structure makes the code easier to understand, easier to test, and much easier to expand later as the board evolves. The firmware is coordinated from a main entry point, while pin assignments and tunable settings are centralized in a config file so the system can be adapted to future hardware revisions without rewriting the whole project.
One of the biggest goals of this firmware was to make the board useful as both a robotics controller and a self contained demo platform. On the motion control side, the ESP32 S3 uses hardware timed PWM through the LEDC peripheral to drive two DRV8871 motor channels at 20 kHz with 8 bit resolution. That keeps motor control responsive while also pushing the PWM frequency above the normal audible range. The board also supports a standard servo output on GPIO 8, while GPIO 9 is currently repurposed as the potentiometer input for menu navigation and analog controls inside the user interface.
Sensor support was another major part of the firmware. The board reads four ultrasonic sensors for distance sensing, two hall effect inputs for pulse counting and speed feedback, and an I2C IMU for motion data. In other words, the software is built to support both movement and awareness. That makes the board useful not just for driving motors, but for experimenting with autonomous behavior, closed loop feedback, and navigation concepts.
I also wanted the board to be easy to interact with without always needing to reflash code or hook up a separate interface. To solve that, I added several layers of user interaction. The first is an onboard TFT display driven over SPI using TFT_eSPI. The current firmware uses a tabbed menu system that runs directly on the display and is controlled with two buttons plus a potentiometer. Through that interface I can view live sensor data, open demos, launch robot modes, scan WiFi networks, look for nearby BLE devices, and navigate through test features without needing an external computer.
The software also includes a built in wireless dashboard. On boot, the controller creates its own WiFi access point called RoboController and hosts a browser based dashboard at 192.168.4.1. That dashboard includes live sensor data, a WiFi scanner, a BLE radar view, and a control tab for remote operation. Instead of relying on constant polling, the interface pushes live data over WebSocket, which makes it feel much more responsive and interactive. On the control side, the dashboard can send JSON commands for motor drive, servo position, and emergency stop functions. That means the board is not limited to local buttons and a small screen, it can also act like a wireless robotics control node that is easy to test from a phone or laptop.
BLE support was another area I wanted to build in early. The firmware advertises a custom BLE GATT service that exposes sensor data and accepts motor and servo control writes. That opens the door for mobile apps, sensor streaming, and remote control through BLE tools like nRF Connect. Having both WiFi and BLE built into the same board gives the platform a lot of flexibility, especially for future robotics projects where different communication methods may make sense in different situations.
One of the most fun parts of this project is that I did not stop at just utility features. I also added a more polished on device experience with multiple demos and even simple games running on the TFT. The firmware includes menu driven screens for live system information, sensor displays, tilt visualization, ultrasonic radar, servo control, and robot mode selection. On top of that, there are games like Snake, Pong, and Asteroids, all rendered through an off screen framebuffer for smooth updates. Those features are obviously not the core purpose of a robotics controller, but they turned out to be a great way to test the display, inputs, UI state machine, timing, and overall firmware structure while making the board much more interesting to interact with.
From a development standpoint, I built the project around PlatformIO, which makes library management and builds much easier to handle. The firmware pulls in libraries like ESP32Servo, TFT_eSPI, AsyncTCP, ESPAsyncWebServer, and NimBLE Arduino. Using a structured toolchain like this makes the project more portable and easier to maintain than an ad hoc sketch with manual dependency management.
What I like most about this phase of the project is that it shows the board is more than just a PCB layout exercise. The hardware and software were designed to work together as a reusable robotics platform. The board can drive motors, read sensors, host a display UI, create its own wireless dashboard, expose BLE services, and support future expansion through broken out GPIO. That combination is what really makes it feel like a complete system rather than just another microcontroller board. The hardware post was about building the foundation. This firmware phase is about giving that foundation behavior.
There is still plenty I want to improve. I want to keep refining the robot modes, continue testing the wireless control features, and push the platform further as both a practical robotics controller and a polished demonstration board. Even so, getting this firmware architecture working has already been a huge step forward. It taught me a lot about structuring embedded software, building usable interfaces on constrained hardware, and designing systems that are easier to grow over time.
This project started as a custom board to clean up wiring and consolidate hardware. Now it is becoming a full robotics platform, with hardware, firmware, wireless control, and a user interface all designed to work together.