Rather than replacing inexpensive BLDC controllers, this project transforms how they behave.
Cheap Chinese BLDC motor controllers are excellent value, but they're designed for e-bikes—not heavy utility vehicles. At very low speeds they often exhibit throttle deadband, jerky starts and inconsistent torque, making precise manoeuvring almost impossible. This project sits between the throttle and two commodity motor controllers, transforming their behaviour without modifying them.
And it's pretty cost effective too. Total component cost around £16
This is TrakTrike. An electriclly powered, dual track driven trike I created fpr EMF camp 2022. But it has a problem. The VSEC75100 clone electronic speed controllers I chose keep dying. I've destroyed 2 pairs since I started this project and at ~£80 each it's a bit expensive.
A broken VESC75100 clone
The last failure was on the first day of WHY2025. The guys from Hacky Racers were at the event and they suggested a replacement as 'anything on Aliexpress over £30'.
I took their advice and got these:
A cheap BLDC motor controller
But I discovered a couple of problems. First, the low-speed control was terrible. Small throttle movements produced no response, followed by an abrupt surge once the motors finally overcame static friction. Precise manoeuvring became difficult and sometimes unsafe.
Second, I split the throttle to connect to both controllers. Since each controller has slightly different throttle characteristics, identical throttle voltages don't produce identical motor speeds. The result is the vehicle constantly pulling to one side.
These controllers are not really designed for dual motor systems.......
So I decided to try and fix it....
I wanted to place a throttle profiler inbetween the twist throttle and the motor controllers. I will dictate in software what the motor controller throttle inputs see!
The architecture is:
My feature list is
Smooth, predictable low-speed control
Eliminates jerky starts and throttle deadband
Precise crawling speed for accurate manoeuvring
Configurable acceleration and deceleration profiles
Adjustable throttle response curves
Automatic forward/reverse transition handling
DAC output pacing to improve controller reliability during direction changes
Individual calibration for each BLDC controller
Supports dual rear motor controllers
Independent configuration of left and right drive systems
Persistent configuration stored in non-volatile memory
Runtime configuration of important parameters without recompiling firmware
Designed specifically for heavy, low-speed electric vehicles
Compatible with inexpensive Chinese BLDC motor controllers
Improves drivability without modifying the motor controllers themselves
Built around readily available, low-cost hardware
Open-source firmware and hardware
The control circuit has the following components
Arduino Nano. There is a bit of floating point math, but nothing the nano can't handle
A MCP4728 12 bit DAC module. This is readily available from Aliexpress and comes in a DIP package
A MCP6002 op-amp. This works as a rail to rail voltage follower to isolate the DAC from odd input impedances of the controller.
A I2C LCD display.
Ports for brake and reverse switches
A simple mode change button.
The schematic is:
And the PCB design:
I normally CNC route my PCBs, but PCBWay kindly offered to sponsor its manufacture. The PCBs arrived within about a week of ordering and I was really pleased with the quality of the boards. The fact that the order contains 5 copies means that I can use IC sockets for the protoype and solder the ICs in for the produciton boards and have a few spares. Thanks to PCB way for sponsoring these!
If you want to get a copy oif these the files are at PCBWay.
Really happy with the PCBs.
A populated production board
The software is written in C/C++ in VSCode with the PlatformIO extension. I've been developing embedded code for 35+ years and decided to try this 'vibe coding' thing the kids are talking about...and I found it very satisfying. I used ChatGPT and after describing the base function, I had a working app and while ChatGPT produced a working application surprisingly quickly, experience still mattered. I ended up pushing back on several design decisions:
Config data stored in EEPROM and copied var by var into global variables. Just use a config struct for everything and do a memcpy.