Skip to the content
PCBKitNew board
2 layers97.5 × 96.7 mmLegoesp32, the printed circuit board in 3D

Megahub is an ESP32-based alternative hub designed for LEGO© enthusiasts and robotics builders.

Size
97.5 × 96.7 mm
Copper layers
2
Thickness
1.6 mm
Parts
26
Nets
100
Pads
252
Tracks, vias
777, 58
Routed
Yes
KiCad
KiCad 9.0 (file 20241229)
Created
26 Dec 2025
Updated
30 Oct 2026

Overview

Legoesp32 is an open-source printed circuit board by mirkosertic, from the mirkosertic/Megahub repository on GitHub. It is a 2-layer board of 97.5 × 96.7 mm with 26 parts on 100 nets, routed with 777 tracks and 58 vias.

Its parts include 4 resistors, 4 connectors and 1 IC. It belongs with the robots and motor control boards and the ESP32 boards of this library.

README

README.md

Megahub

PlatformIO CI

Introduction

Megahub is an ESP32-based experimentation platform for robotics enthusiasts and makers. It combines native support for LEGO WeDo/Powered Up devices with a web-based IDE featuring Lua scripting and Blockly visual programming. The project is fully open source and ships with hardware schematics, PCB production files, and firmware as a PlatformIO project.

Build and use it at your own risk.


Key Features

  • KiCad schematics: All schematics and PCB production files are available in KiCad and Gerber format
  • WiFi: Built-in wireless connectivity for remote control and programming
  • Bluetooth: Acts as a BLE (Bluetooth Low Energy) server and Bluetooth Classic client simultaneously
  • Web IDE: Configure and program Megahub through the Megahub IDE
  • Visual programming: Blockly drag-and-drop programming for beginners and rapid prototyping
  • Lua scripting: Full Lua 5.4 scripting for advanced users
  • SD card storage: Store multiple projects on an SD card; the IDE remembers which project was last selected for autostart
  • 4 LEGO device ports: Connect up to 4 LEGO WeDo 2.0/Powered Up motors, sensors, and other devices simultaneously
  • IMU: Integrated MPU6050 6-axis accelerometer and gyroscope for motion sensing
  • FastLED/NeoPixel: Built-in support for WS2812B addressable RGB LED strips
  • GPIO expansion: Additional GPIO pins for custom sensors, buttons, and peripherals
  • Gamepad support: Pair a Bluetooth Classic HID gamepad (e.g., 8BitDo M30) for manual control

Screenshots

Project management Project Management

IMU interaction IMU Interaction

LEGO and Gamepad interaction LEGO and Gamepad interaction


Hardware Photos

Assembled prototype


Getting Started

Prerequisites

  • PlatformIO installed as a CLI tool or as a VSCode extension
  • An ESP32 development board
  • USB cable for flashing
  • Chrome, Edge, or Opera desktop browser (required for the Web Bluetooth API)

Building the Firmware

  1. Clone the repository:

    bash
    git clone https://github.com/mirkosertic/Megahub.git
    cd Megahub
  2. Build the project:

    bash
    pio run

    Or click Build in the PlatformIO toolbar inside VSCode.

Flashing the Board

  1. Connect the ESP32 board via USB.

  2. Flash the firmware:

    bash
    pio run --target upload

    Or click Upload in the PlatformIO toolbar inside VSCode.

First Boot and Connection

The device starts in Bluetooth mode by default.

  1. Open the Megahub IDE in Chrome, Edge, or Opera on a desktop computer.
  2. Click Connect in the IDE.
  3. Select your Megahub device from the browser's Bluetooth pairing dialog.
  4. Once connected, the IDE shows the project list and the logger output.

Serial Monitor

View diagnostic output from the board:

bash
pio device monitor

Default baud rate: 115200.

Testing the IDE Without Hardware

You can run the Megahub IDE locally in your browser without a physical board. This is useful for exploring the interface, building Blockly programs, and inspecting generated Lua code — no firmware flashing required.

bash
cd frontend
npm install
npm run dev

Vite starts a local development server (typically at http://localhost:5173). Open that URL in any browser.

What works in dev mode:

  • Full IDE UI — project management, Blockly workspace, toolbox
  • Blockly drag-and-drop programming and real-time Lua code generation
  • Lua Preview panel — inspect the generated code for any program

What does not work:

  • Connecting to a device (no BLE in dev mode)
  • Executing or stopping programs — the Execute button requires a live connection to the firmware

Hardware Reference

LEGO Device Ports

Megahub provides 4 LEGO device ports, numbered 1 to 4. Each port uses the LEGO Powered Up UART protocol. Two SC16IS752 I2C-to-UART bridge chips translate between the ESP32 and the LEGO connectors: bridge chip 1 (UART1) drives ports 1 and 2, bridge chip 2 (UART2) drives ports 3 and 4. Each chip also exposes four additional GPIO pins (GP4–GP7) that can be used for custom sensors or buttons — see UART1_GP4–UART2_GP7 in LUAAPI.md. All four ports are available from Blockly.

Motor speed range: -127 (full reverse) to +127 (full forward). Zero stops the motor.

GPIO Pins

FastLED / NeoPixel output — use any of these GPIO pins for WS2812B LED strips: 13, 16, 17, 25, 26, 27, 32, 33.

SD card (SPI bus):

SignalGPIO
CLK18
MOSI23
MISO19
CS4

IMU (I2C): The MPU6050 is connected to the I2C bus. Its address and pins are fixed in hardware.

Supported LEGO Devices

Megahub supports LEGO WeDo 2.0 and Powered Up devices that communicate over the LEGO Powered Up UART (LUMP) protocol. This includes motors, color and distance sensors, tilt sensors, and other compatible devices. See the LUMP Protocol Documentation for the full technical specification.


Using the IDE

Connecting

The Megahub IDE runs entirely in your browser and communicates over BLE when the device is in Bluetooth mode.

Supported browsers: Chrome, Edge, Opera (desktop only). Firefox and Safari do not support the Web Bluetooth API and cannot connect to the device.

Steps:

  1. Open the IDE in a supported browser.
  2. Click Connect.
  3. Select the Megahub device from the pairing dialog.
  4. The IDE connects and shows the project list on the left and a logger panel on the right.

Creating a Project

  1. Click New project in the project list.
  2. Enter a name for the project.
  3. The IDE opens the Blockly workspace for that project.

Programming with Blockly

The Blockly workspace lets you build programs visually without writing code.

  1. Find a block in the toolbox on the left side of the workspace. Blocks are grouped by category: Control flow, LEGO, Gamepad, FastLED, IMU, I/O, Math, and more.
  2. Drag a block onto the canvas and connect it to other blocks.
  3. As you build, the IDE generates the corresponding Lua code automatically — expand the Lua Preview panel in the sidebar to inspect it.
  4. When the program is ready, click Execute to send and run it on the device.
  5. Output and log messages from the running program appear in the Logger panel.

For a visual reference of every available block, see BLOCKS.md.

Toolbox Category Guide

The toolbox is divided into these categories:

CategoryWhat it contains
Control flowInitialization block, Start thread, Wait, Stop thread
LogicIf/else, comparisons (=, ≠, <, >), AND/OR, NOT, boolean values
LoopRepeat N times, count-for loop, break/continue
MathArithmetic, rounding, trigonometry, random numbers, constrain
TextString operations; Print to Logger
ListsCreate, read, write, sort, and split lists
I/OSet motor speed, GPIO read/write, pin mode, port selector
LEGO©Select sensor mode on a port, read sensor dataset
GamepadButton pressed, analog axis values, connection check
FastLEDInitialize LED strip, set individual LED colour, show, clear
IMURead yaw, pitch, roll, or acceleration from the on-board sensor
UIDisplay a labelled value in the IDE Logger panel, map visualization (plot position, clear)
AlgorithmsPID controller (init/compute/reset), dead reckoning (init/update/get/reset/set pose), moving average filter, map/scale, hysteresis, debounce, rate limiter, 1D Kalman filter
DebugFree heap memory, milliseconds since boot

Common gotcha: The Set motor speed block is in the I/O category — not LEGO©. The LEGO© category only contains sensor blocks (selecting a measurement mode and reading the sensor dataset). If you want to drive a motor, open I/O.

Running and Stopping Programs

  • Click Execute to upload and start the program.
  • Click Stop to halt a running program at any time.
  • The Logger panel shows output in real time.

Autostart

You can mark a project as the autostart project. When the IDE connects to the device, it reads the autostart setting and opens that project automatically.

In the IDE project list, find the project you want and toggle the autostart switch. This writes the following file to the SD card:

json
{ "project": "your-project-id" }

The file is stored at /autostart.json on the SD card. To clear the autostart selection, toggle the switch off in the IDE or delete the file from the SD card.


WiFi Mode

By default Megahub runs in Bluetooth mode. You can switch to WiFi mode to access the web interface over your local network.

Switching from Bluetooth to WiFi Mode

  1. Insert an SD card into the device.
  2. Create a file named config.json in the root of the SD card with the following content:
    json
    {
      "bluetoothEnabled": false,
      "wifiEnabled": true,
      "ssid": "YourNetwork",
      "pwd": "YourPassword"
    }
  3. Reboot the device. It connects to your WiFi network and starts the web server.

You can also run both Bluetooth and WiFi simultaneously by setting both bluetoothEnabled and wifiEnabled to true.

config.json Reference

FieldTypeDefaultDescription
bluetoothEnabledbooleantrueEnable BLE and Bluetooth Classic
wifiEnabledbooleanfalseConnect to WiFi and start web server
ssidstring—WiFi network name
pwdstring—WiFi password

Accessing the Web UI

Once the device is connected to WiFi:

  • Open http://<device-ip>/ in any browser, or
  • Open http://<device-uid>.local/ (requires mDNS support — works on macOS, Linux, and Windows 10+)

The web UI provides the same project management, Blockly programming, and execution features as the Bluetooth-connected IDE. For the full REST API reference used by the web server, see HUBAPI.md.


Gamepad Support

Pairing a Gamepad

Scanning and pairing are done from the IDE while the device is connected in Bluetooth mode.

  1. Open the Bluetooth Devices panel in the IDE sidebar.
  2. Click the Scan button (circular icon at the top of the panel). The panel shows "Scanning…" while the firmware searches for nearby Bluetooth Classic devices.
  3. Put your gamepad into pairing mode so it becomes discoverable.
  4. The gamepad appears in the list with its name, MAC address, device type, and signal strength.
  5. Click Pair Device on the gamepad entry. The firmware initiates pairing; the entry updates to show a Paired badge.
  6. Once paired, the gamepad state is available to your Blockly programs immediately.

To remove a pairing, click Remove Pairing on the paired device entry in the panel.

Supported Gamepads

Any Bluetooth Classic HID-compatible gamepad should work. The 8BitDo M30 has been tested and confirmed to work.

Gamepad input available in Blockly:

InputRange / Values
Buttons (1–16)pressed / not pressed
D-paddirectional state
Left stick X/Y-32768 to +32767
Right stick X/Y-32768 to +32767

Blockly Blocks for Gamepad

The Gamepad category in the Blockly toolbox provides 5 blocks for reading button states, D-pad direction, and analog stick values. See BLOCKS.md for the full visual reference.


Hardware Features

LEGO Powered Up

Megahub speaks the LEGO Powered Up UART protocol (LUMP) natively. Each of the 4 ports independently detects a connected device, negotiates its capabilities, and streams sensor data. Motors accept a speed value from -127 to +127. Sensors report values according to the mode you select in your Blockly program.

The LEGO category in the Blockly toolbox provides blocks for:

  • Selecting a sensor mode on a port
  • Reading the current sensor data from a port and dataset

Motor speed is set using the Set motor speed block in the I/O category.

See LUMP.md for the complete protocol specification.

FastLED / NeoPixel Addressable LEDs

Connect a WS2812B LED strip to any of the supported GPIO pins (13, 16, 17, 25, 26, 27, 32, or 33). The FastLED category in the Blockly toolbox provides 4 blocks for:

  • Initializing the LED strip (type, GPIO pin, number of LEDs)
  • Setting individual LED colors (RGB)
  • Showing/updating the LED strip
  • Clearing all LEDs

IMU — Orientation and Acceleration

The on-board MPU6050 provides 6-axis motion data, updated every 100 ms. Read it in Blockly using the IMU block:

OutputUnitDescription
YAW°Rotation around vertical axis
PITCH°Forward/back tilt
ROLL°Left/right tilt
ACCELERATION_Xm/s²Acceleration along X axis
ACCELERATION_Ym/s²Acceleration along Y axis
ACCELERATION_Zm/s²Acceleration along Z axis

Algorithm Blocks

The Algorithms category provides blocks for closed-loop control and position tracking.

PID controller: A proportional-integral-derivative controller for motor speed regulation, line following, or any closed-loop control. Uses an explicit lifecycle:

  1. Init PID — creates a new controller instance, returns a handle
  2. PID compute — computes control output using the handle, setpoint, process variable, and gains
  3. PID reset — clears the state of an existing controller (e.g., when switching setpoints)

Store the handle from Init PID in a variable and pass it to PID compute in your control loop.

Dead reckoning (DR): Estimates the robot's (x, y, heading) pose by integrating wheel encoder ticks and IMU yaw. The following blocks are available:

BlockDescription
Init DRCreates a new dead reckoning instance and returns a handle. Call once before your main loop.
DR updateUpdates pose from left/right encoder ticks and IMU yaw. Takes 7 inputs: handle, left ticks, right ticks, yaw (deg), m/tick, wheelbase (m), IMU weight. Does not return a value.
DR pose X/Y/HEADING ofReads one component of the pose from a handle — X and Y in meters, HEADING in degrees.
Reset DR pose ofResets pose to origin (0, 0, 0°). Re-bootstraps encoder baselines so the next update produces zero delta.
Set DR pose ofInjects a known (x, y, heading) position for landmark-based drift correction.

Moving average filter: Smooths noisy sensor readings using a sliding window of the last N samples. Uses the same explicit handle pattern as PID and DR — call Initialize moving average once before your loop, store the handle in a variable, then pass it to Moving average on each update.

BlockDescription
Initialize moving averageCreates a new moving average filter instance and returns a handle. Store in a variable. Call once before your loop.
Moving averageAdds a new sample and returns the arithmetic mean of the last N values. Inputs: handle, sensor value, window size (2–50; default 10). On first call the buffer is pre-filled so there is no startup ramp.

Map / Scale: Linearly maps a value from one numeric range to another. Stateless — no initialization required.

BlockDescription
MapMaps value from [inMin, inMax] to [outMin, outMax]. Equivalent to Arduino map() with float support. Output is not clamped — values outside the input range extrapolate linearly.

LEGO motor POS mode prerequisite: DR reads absolute encoder positions. Before using DR blocks, call lego select mode with mode 2 (POS) on the motor ports in hub.init(), then wait briefly for the sensor to settle.

For a full explanation including the math, calibration procedure, coordinate conventions, and example programs, see DEADRECKONING.md.

Signal conditioning filters: Four filters for cleaning up noisy or jerky signals before they reach your control logic. All use the same explicit handle pattern as PID and DR.

Block pairDescription
Initialize hysteresis + HysteresisSchmitt trigger — output latches to 0 or 1, only switching when the input crosses a high or low threshold. Eliminates chatter at sensor boundaries.
Initialize debounce + DebounceWaits for a digital signal to be stable for a minimum number of milliseconds before updating output. Eliminates mechanical button bounce and contact noise.
Initialize rate limiter + Rate limitLimits how fast the output value can change per call, producing smooth acceleration ramps. Prevents wheel slip and encoder errors from sudden motor commands.
Initialize Kalman filter + Kalman filter1D Kalman filter — weighted sensor smoothing based on process noise Q and measurement noise R. More principled than moving average for sensors with known noise characteristics.

For intuition, math, tuning guidance, and pipeline examples, see FILTERS.md.

Map Visualization

The IDE sidebar includes a live map panel that renders the robot's trail as it moves. Use the UI category blocks to drive it:

BlockDescription
Map: plot positionSends an (x, y, heading) pose to the map panel. Wire in DR get blocks for x, y, and heading. The firmware rate-limits sends to 5 Hz — call at any rate in your loop.
Map: clearClears the trail from the map panel. Call this at the start of each run alongside Reset DR pose.

SD Card Storage

Projects created in the IDE are saved to the SD card. The SD card connects over SPI (CLK=18, MOSI=23, MISO=19, CS=4). Use a standard microSD card formatted as FAT32. Configuration files (config.json, autostart.json) also live in the root of the SD card.

SD card is required. If the SD card is absent or fails to mount at boot, the device halts immediately and cannot start.


How Programs Run

Understanding this sequence explains many "why isn't it working?" situations.

Boot sequence

  1. The SD card is mounted. If mounting fails the device halts — nothing else starts.
  2. config.json is read from the SD card root. WiFi and/or Bluetooth are started based on its content.
  3. All four LEGO ports initialise and begin device detection in the background.
  4. The device enters idle state. No program runs automatically at this point.

Autostart does not run a program at boot. The autostart setting only tells the IDE which project to navigate to when you connect. The device always starts with no program running — you must click Execute in the IDE to start a program.

When you click Execute

  1. Any currently running program and all its threads are stopped immediately.
  2. All four LEGO ports are reinitialized (motors stop, sensors reset).
  3. A fresh Lua environment is created and the program runs from the top:
    • hub.init() — runs synchronously and completes before anything else.
    • hub.startthread() — each call spawns a background task that loops independently.
    • The main program body finishes. Background threads continue running.
  4. Each thread loops continuously with a 1 ms scheduler yield between iterations.

When a thread crashes

If a Lua runtime error occurs inside a thread:

  • The thread exits and the error appears in the Logger panel.
  • All four LEGO ports are reinitialized (all motors stop).
  • Other threads continue running.

When you click Stop

  1. All threads receive a stop signal and exit.
  2. All four LEGO ports are reinitialized (all motors stop, all sensors reset).

Key point: every time a program stops — by request, by crashing, or because a new Execute is sent — all motors stop and all ports reset. You never need to manually zero motors before stopping.


Troubleshooting

BLE Not Connecting

  • Make sure you are using Chrome, Edge, or Opera on a desktop computer. Mobile browsers and Firefox/Safari do not support the Web Bluetooth API.
  • Ensure Bluetooth is enabled on your computer.
  • Reload the IDE page and click Connect again — the browser may need a fresh connection attempt.
  • Check that no other browser tab or application is already connected to the device (only one BLE connection is active at a time).

Device Not Found in Bluetooth Scan

  • Confirm the device is powered on.
  • Move the device closer to your computer — BLE range is typically 5–10 metres in open air.
  • Reboot the device and try the scan again.
  • If the device was previously paired with a different computer, you may need to remove it from that computer's Bluetooth settings first.

LEGO Device Not Responding

  • Check that the LEGO device cable is fully seated in the port.
  • Confirm the port number in your Blockly program matches the physical port (1–4).
  • Some LEGO devices require a short delay between commands. Add a wait block between motor commands if the device ignores rapid successive commands.
  • Reboot the device. The port detection sequence runs on every startup.

Reading the Serial Log

Connect the device via USB and run:

bash
pio device monitor

The log (115200 baud) shows boot messages, port detection results, BLE connection events, and any errors from running Lua programs. Copy the relevant lines when reporting a bug.


Documentation

DocumentDescription
BLOCKS.mdComplete visual reference for all Blockly blocks, auto-generated with screenshots
LUAAPI.mdLua scripting API — all modules, functions, and constants available in Megahub programs
BLEPROTOCOL.mdBLE protocol reference — GATT profile, framing, request/response and event formats
HUBAPI.mdREST API and Server-Sent Events reference for WiFi mode
LUMP.mdLEGO Powered Up UART protocol technical specification
MEGAHUBIDE.mdFrontend IDE architecture — module structure, state, events, components, testing
DEADRECKONING.mdDead reckoning guide — intuition, kinematics, math, coordinate conventions, Blockly usage, and calibration
FILTERS.mdSignal conditioning filters guide — hysteresis, debounce, rate limiter, and 1D Kalman filter: intuition, math, tuning, and pipeline patterns

Parts

26
QtyValueFootprintReferences
41kCustomFootprints:ResistorR1, R2, R3, R4
4~CustomFootprints:LegoWedoConnectorPort1, Port2, Port3, Port4
2~CustomFootprints:DRV8833DRV8833_1, DRV8833_2
2~CustomFootprints:SC16IS752SC16IS752_UART1, SC16IS752_UART2
1ESP32IOCustomFootprints:Header_10x2ESP32IO1
1Port1DebugCustomFootprints:Header_3x2J2
1Port2DebugCustomFootprints:Header_3x2J3
1Port3DebugCustomFootprints:Header_3x2J6
1Port4DebugCustomFootprints:Header_3x2J7
1UART1_I2C_ADRCustomFootprints:Header_4x2UART1_I2C_ADR1
1UART2_I2C_ADRCustomFootprints:Header_4x2UART2_I2C_ADR1
1UARTIOCustomFootprints:Header_6x2UARTIO1
1USBPWRCustomFootprints:JumperUSBPWR1
1~CustomFootprints:MPU6050MPU6050
1~CustomFootprints:BuckConverterBuckConverter1
1~CustomFootprints:SDCardReaderSDCardReader1
1~Connector_JST:JST_PH_B2B-PH-K_1x02_P2.00mm_VerticalU1
1~CustomFootprints:ESP32DevKitESP32

Questions

How big is the Legoesp32 PCB?

It measures 97.5 × 96.7 mm and has 2 copper layers, 1.6 mm thick.

What parts does the Legoesp32 use?

26 parts. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Legoesp32 KiCad files?

From the mirkosertic/Megahub repository on GitHub, at the commit this page was made from: the board is kicad/esp32_devkit/legoesp32.kicad_pcb and its schematic kicad/esp32_devkit/legoesp32.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Legoesp32 design in my own project?

Its repository states no licence, so its author keeps all rights: ask mirkosertic before reusing the design.

Similar boards

  • 2 layers57.3 × 19 mm11ua, the printed circuit board in 3D

    11ua

    rene-dev/stmbl

    AC Servo Driver for STM32F4

    26 parts990GPL-3.0
  • 2 layers98 × 59.5 mmMCP23017 PCB, the printed circuit board in 3D

    MCP23017 PCB

    hackclub/OnBoard

    💡 Join 1,000 teenagers and make your first PCB with a $100 grant!

    26 parts915
  • 2 layers142.9 × 98.5 mmCantor MX, the printed circuit board in 3D

    Cantor MX

    diepala/cantor

    Cantor keyboard, a 42 key diodeless split keyboard.

    26 parts756GPL-3.0
  • 2 layers103.8 × 50 mmGalagino pcb set, the printed circuit board in 3D

    Galagino pcb set

    harbaum/galagino

    A Galaga, Pac-Man and Donkey Kong arcade emulator for the ESP32

    26 parts558
  • 2 layers20.3 × 34.8 mmL0 ESP32, the printed circuit board in 3D

    L0 ESP32

    Luos-io/luos_engine

    Open-source and real-time orchestrator for cyber-physical-systems, to easily design, test and deploy embedded applications and digital twins.

    26 parts546MIT
  • 2 layers40.6 × 50.8 mmWALTsm, the printed circuit board in 3D

    WALTsm

    google/walt

    A device for measuring latency of physical sensors and outputs on phones and computers

    26 parts474Apache-2.0
  • 2 layers158.5 × 75 mmDoj v2, the printed circuit board in 3D

    Doj v2

    kelu124/echomods

    Open source ultrasound processing modules and building blocks

    26 parts463