GrowBot ยท ESP32 build optional

An alternate brain board. The main build uses a Raspberry Pi Pico 2 W with a one-click browser flasher โ€” this path is for people who'd rather use an ESP32. Same body, same firmware, a few extra command-line steps.

With help by olie-o, who first tested on ESP32. ๐Ÿ™Œ

โ‰ˆ20 min ยท command line ยท any 2.4 GHz ESP32

01

What you need

  • An ESP32 dev board (classic ESP32, or S3/C3) with a data USB cable (not charge-only)
  • 2ร— servos + a 5โ€“6 V battery for the body โ€” same as the main build
  • Python 3 on your computer
  • The GrowBot Body Kit (firmware files + 3D prints)

The body, servos, wiring and gluing are identical to the main build โ€” only the brain board and the flashing steps change.

02

Get the firmware

Download the kit from the main build page (Step 05 โ†’ Download the kit) and unzip it. You'll work inside the growbot-body-kit/firmware/ folder.

Then grab a MicroPython firmware image for your ESP32 from micropython.org/download โ†— โ€” pick your exact board, download the .bin, and save it into that firmware/ folder.

03

Install the tools

In a terminal, in the growbot-body-kit/firmware/ folder:

pip install esptool mpremote

Optional but tidy: make a virtualenv first โ€” python3 -m venv .venv && source .venv/bin/activate (macOS/Linux) or .venv\Scripts\Activate.ps1 (Windows).

04

Flash MicroPython

Plug in the ESP32 and find its serial port:

mpremote connect list        # any OS โ€” shows the port
# macOS:   ls /dev/cu.*
# Linux:   ls /dev/ttyUSB* /dev/ttyACM*
# Windows: a COMx port

Erase, then flash the .bin you downloaded (replace the port and filename):

esptool --chip esp32 --port PORT erase-flash
esptool --chip esp32 --port PORT write-flash 0x1000 YOUR_FIRMWARE.bin
Flash offset: classic ESP32 uses 0x1000 (above). ESP32-S3 / C3 flash at 0x0 instead โ€” use --chip esp32s3 (or esp32c3) and write-flash 0x0 โ€ฆ. Some boards need you to hold the BOOT button while flashing starts.
05

Point the driver at your pins

The servo driver auto-detects a Pico carrier board; on a bare ESP32 you tell it to drive the pins directly. Open firmware/PicoRobotics.py, find the config block near the top, and set FORCE + your two pins ({left, right}):

FORCE      = "gpio"          # was None
GPIO_PINS  = {1: 18, 3: 19}  # left, right โ€” pick from the table below

Use two free PWM-capable output GPIOs, then wire each servo's signal (orange) to its pin. The safe defaults differ by chip โ€” the big trap is the S3/C3 native-USB pins:

chipgood pins (left, right)avoid for servos
ESP32 (classic){1: 18, 3: 19}34โ€“39 (input-only), 0/2/12/15 (strapping)
ESP32-S3{1: 4, 3: 5}19/20 = USB! ยท 0/3/45/46 (strapping)
ESP32-C3{1: 4, 3: 5}18/19 = USB! ยท 2/8/9 (strapping)

On the S3/C3, putting a servo on a USB pin fights the board's USB connection (random resets / disconnects) โ€” use the pins above instead. Servos draw power from the battery rail, never from an ESP32 pin (a GPIO can't source servo current โ€” it'll brown out or reset).

06

Add your Wi-Fi + upload

Copy the template, fill in your 2.4 GHz network (the ESP32 is 2.4 GHz only):

"2.4 GHz" is the Wi-Fi band, not your internet type โ€” 5G home, fiber, cable all work. Most routers broadcast a 2.4 GHz network; if you only see one, enable or "split" it in your router settings.

cp secrets.example.py secrets.py      # then edit secrets.py:
#   WIFI_SSID     = "YourNetwork"
#   WIFI_PASSWORD = "YourPassword"

Upload all four files (relay_chip.py becomes main.py):

mpremote cp secrets.py      :secrets.py
mpremote cp PicoRobotics.py :PicoRobotics.py
mpremote cp act_engine.py   :act_engine.py
mpremote cp relay_chip.py   :main.py
mpremote reset

On reset the ESP32 runs the leg-check, then joins your Wi-Fi and dials the GrowBot relay.

07

Read your pairing code

The code prints at boot, but ESP32 dev boards reset when the serial port opens, so it's easy to miss. You don't need to catch it โ€” the code is just gb- + the chip's hardware id, so print it any time:

mpremote exec "import binascii,machine; print('gb-'+binascii.hexlify(machine.unique_id()).decode()[-6:])"

That prints something like gb-7a3f0c. It's the same every boot, so write it down once. (If you'd rather watch the live boot log: mpremote repl, then tap the board's reset.)

08

Connect your phone

Your phone reaches the robot over Wi-Fi, through the relay โ€” not over the USB cable. On your phone, open the controller, type your pairing code, and connect:

โ–ถ Open the controller

Green dot = connected. Then drive it โ€” Manual, Policy & voice. Pairing code shown + phone connected = โœ… done. Send a clip!

โš™

Troubleshooting

symptomfix
"No module named PicoRobotics"a file didn't upload โ€” repeat the mpremote cp step and check each succeeds
no green dot / won't connectWi-Fi is 2.4 GHz? secrets.py correct? code typed exactly (lowercase)? Confirm it joined: mpremote exec "import network;print(network.WLAN(network.STA_IF).isconnected())"
servos don't movesignal wires on the GPIOs from your GPIO_PINS, shared ground, servos on the battery (not a GPIO), and the Step 05 edit saved
board resets / USB drops when a servo movesa servo is on a USB pin โ€” S3 = GPIO19/20, C3 = GPIO18/19. Move it to a safe pin (Step 05) and update GPIO_PINS
flashing failsright port? right --chip + offset for your board? data USB cable? close other serial apps; some boards need BOOT held