Drive a Microbots ProtoBot from a Flipper Zero over Bluetooth LE. No extra hardware, no dongle.
Replaces the robot's firmware and adds a Flipper app, together covering nearly everything the official MicroLink phone app does: joystick driving, shape routines, path replay, the full sensor set, and the robot's settings.
The Flipper Zero cannot act as a BLE central. Its furi_hal_bt API has no
functions for scanning, connecting to a peripheral, or GATT client operations,
and the STM32WB55 runs ST's peripheral-only stm32wb5x_BLE_Stack_light_fw.bin.
Momentum, Unleashed and RogueMaster inherit the same stack, so custom firmware
doesn't change it.
Since the ProtoBot's firmware is open, the fix is to swap the roles:
stock: phone ──central──> ProtoBot (peripheral)
ProtoLink: Flipper (peripheral) <──central── ProtoBot
The Flipper advertises a custom GATT service with pairing disabled; the robot scans for it, connects, subscribes to a 20 Hz control stream, and writes telemetry and log messages back. Protocol details in docs/link-protocol.md.
A .fap is locked to the SDK API version it was built against, so pick the one
matching your firmware and copy it to apps/Bluetooth/ on the SD card:
| File | Firmware | API |
|---|---|---|
dist/protobot_remote-momentum-api87.1.fap |
Momentum | 87.1 |
dist/protobot_remote-official-api88.2.fap |
official dev |
88.2 |
Both are built from identical sources — no #ifdefs, no fork-specific code.
The app appears under Apps → Bluetooth.
arduino-cli config add board_manager.additional_urls \
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
arduino-cli core update-index
arduino-cli core install esp32:esp32
arduino-cli lib install ProtoBot
arduino-cli compile --fqbn esp32:esp32:esp32c6:CDCOnBoot=cdc firmware/protobot_link
arduino-cli upload --fqbn esp32:esp32:esp32c6:CDCOnBoot=cdc -p COM4 firmware/protobot_link
CDCOnBoot=cdcmatters. It defaults to Disabled on the ESP32-C6, which routesSerialto UART0 instead of USB — you get no output at all.
In the Arduino IDE: install the esp32 core and the ProtoBot library,
select ESP32C6 Dev Module, set USB CDC On Boot = Enabled, and upload
firmware/protobot_link/protobot_link.ino.
- Launch ProtoBot Remote on the Flipper. It advertises as
ProtoLink. - Run the robot on battery, not USB — see Gotchas.
- Eyes dim blue = searching, dim green = linked.
- Drive → OK to arm, then the D-pad.
| Screen | Contents |
|---|---|
| Drive | stick + live telemetry. D-pad drives (ramps to full over 250 ms), OK arms/disarms, hold OK = emergency stop |
| Shapes & Replay | circle / square / triangle / infinity, size 10–100, loop, run/stop, replay recorded path, face north |
| Sensors | battery, heading, proximity front+base, light front+base, ground speed, roll/pitch/yaw, tap |
| Settings | avoid, front avoid, eye display, eye colour, speed, proximity lock |
| Robot Log | messages pushed by the robot |
Back returns to the menu; Back from the menu exits and restores the stock BLE profile. The robot stops if no control packet arrives for 500 ms, and the app sends a disarm packet on exit.
The robot only drives on battery power. ProtoBot::Run() gates its entire
drive path behind _bot_status == STATE_BAT_RUN. On USB the status is
STATE_USB and the motors will not respond to anything. This is stock library
behaviour, not something this firmware introduces.
Upstream library bug. ProtoBot::RotateHandler contains
if ((!_manual_mode) || ((_manual_mode) && (shape_num = 2))) — an assignment,
not a comparison. Every rotation during a shape rewrites shape_num to 2, so a
square turns into a triangle at its first corner. The MicroLink app never hits
it (_manual_mode is 0 there, so || short-circuits), but the public
Drive*() API sets _manual_mode = 1. This firmware works around it by
re-asserting shape_num after each Run(). Fix submitted upstream as
microbotsio/ProtoBot#2; the
patch is in patches/.
Security. The BLE profile is deliberately open — GapPairingNone,
bonding_mode = false, ATTR_PERMISSION_NONE on every characteristic. That's
what lets a robot with no keypad connect unattended. The link is therefore
unauthenticated and unencrypted: anyone in range can drive the robot. Fine for a
toy; don't reuse this profile for anything that matters.
git clone --recursive https://github.com/Next-Flip/Momentum-Firmware.git
cp -r flipper/protobot_remote Momentum-Firmware/applications_user/
cd Momentum-Firmware
./fbt fap_protobot_remote # build
./fbt launch APPSRC=applications_user/protobot_remote # build, deploy, runfbt bootstraps its own toolchain — ARM GCC, SCons and a bundled Python — so
git is the only prerequisite. First run downloads ~1 GB. Substitute
flipperzero-firmware for an official build.
On Windows use .\fbt.cmd, and run git config --system core.longpaths true
once as admin — the firmware tree is deep enough to hit MAX_PATH.
Download firmware/protobot.ino.bin from the
ProtoBot repo — it's an ESP-IDF
application image, so it goes at the app offset:
esptool --chip esp32c6 --port COM4 --baud 921600 write-flash 0x10000 protobot.ino.binThe bootloader and partition table written by arduino-cli upload are
compatible, so only the app slot needs replacing. EEPROM settings survive.
If the board won't enter download mode, disconnect the battery — stock firmware hibernates while charging and stops servicing the USB reset.
flipper/protobot_remote/ Flipper app (FAP)
protobot_remote.c menus, views, 20 Hz control loop
protobot_link_profile.c custom BLE profile - open, no pairing
protobot_link_service.c GATT service: control, telemetry, config, log
protobot_protocol.h wire format, shared with the sketch by hand
firmware/protobot_link/ ESP32-C6 Arduino sketch - BLE central, motor mixing
docs/ protocol specs
patches/ upstream fix for the ProtoBot library
dist/ prebuilt .fap for both firmware forks
docs/protobot-ble-protocol.md documents the robot's stock GATT interface,
reverse-engineered from the vendor library. This project doesn't use it, but
it's the reference if you'd rather keep stock firmware and drive the robot from
something that can act as a central.
- Microbots for the ProtoBot and its open Arduino library
- flipperzero-firmware and Momentum
- fbs — the closest existing example of a FAP driving BLE
MIT — see LICENSE.