Skip to the content
PCBKitNew board
4 layers90 × 51 mmDroneBMS, the printed circuit board in 3D

TakeUp is a voice controlled quadrocopter designed to recieve commends through seemless audio transmission.

Size
90 × 51 mm
Copper layers
4
Thickness
1.6 mm
Parts
42
Nets
11
Pads
196
Tracks, vias
139, 156
Pours
5
Routed
Yes
KiCad
KiCad 9.0 (file 20241229)
Created
12 Jun 2026
Updated
23 Jul 2026

Overview

DroneBMS is an open-source printed circuit board by zmuhammad07, from the zmuhammad07/TakeUp repository on GitHub, published under the MIT licence. It is a 4-layer board of 90 × 51 mm with 42 parts on 11 nets, routed with 139 tracks and 156 vias.

It is built around the AMS1117-3.3 and SMAJ15A. Its parts include 13 capacitors, 6 resistors, 3 diodes, 2 ICs and 2 connectors.

Main components

2

README

README.md

TakeUp

TakeUp is a custom quadrotor flight stack built from scratch: a hand-wired STM32F4 flight controller, a self-etched power distribution board, a bit-banged NRF24L01+ radio link, and a from-scratch DShot150 ESC driver. The end goal is voice-controlled flight — commands transmitted over audio instead of a stick input — with the current build flying on a manual PS5-controller-over-RF link while the audio pipeline is developed.

Status: in progress. Attitude estimation, the RF link, and standard PWM motor control are working. DShot150 and voice control are active work-in-progress (see Known Limitations).


Table of Contents


System Overview

image

Today, the RC packet source is a PS5 controller relayed through an ESP32 (Software/Src/esp32.c) rather than voice — this is the interim control path used to validate the flight controller, IMU fusion, and radio link while the voice front-end is built out.


Repository Layout

text
TakeUp/
├── Hardware/
│   └── BMS/
│       ├── DroneBMS.kicad_sch     # power distribution board schematic (KiCad 9)
│       ├── DroneBMS.kicad_pcb     # 4-layer PCB layout
│       └── PCB_Render_1.png       # 3D render
│   └── Flight Controller/
│       └── IMG_4678.jpeg          # hand-soldered flight controller build
├── Software/
│   ├── INC/                       # headers
│   │   ├── Dshot150.h
│   │   ├── Motors.h
│   │   ├── Nrf2401.h
│   │   ├── mpu6050.h
│   │   └── main.h
│   └── Src/
│       ├── Dshot150.c              # custom DShot150 frame builder + DMA-PWM transmit
│       ├── Motors.c                # standard 1000-2000us PWM ESC control
│       ├── Nrf2401.c                # bare-register NRF24L01+ driver (no external RF24 lib)
│       ├── mpu6050.c                # IMU driver + complementary filter
│       ├── esp32.c                  # ESP32 transmitter sketch (PS5 controller → NRF24)
│       └── main.c                   # flight controller entry point / RX loop
└── image.png                        # power board schematic export

Flight Controller (STM32F4)

The flight controller runs on an STM32F4 Nucleo-64 board (pin map matches the standard Nucleo layout: PC13 user button, PA5 = LD2). Firmware is generated with STM32CubeMX/HAL and hand-extended.

Flight controller build — MPU6050 and NRF24L01+ hand-soldered onto perfboard

Hand-wired prototype: MPU6050 breakout and NRF24L01+ (with SMA antenna) soldered onto perfboard with screw-terminal breakouts for power and signal.

Clock tree: 8 MHz HSE → PLL (M=4, N=72, P=/2) → 72 MHz SYSCLK, APB1 = 36 MHz (72 MHz timer clock), APB2 = 72 MHz.

Peripherals in use:

PeripheralRolePins
I2C1MPU6050 IMU, 100 kHz standard modePB6 = SCL, PB7 = SDA
SPI2NRF24L01+ radio, mode 0, fPCLK/2PB14 = MISO, PB15 = MOSI, PC7 = SCK
—NRF24 chip-select / chip-enable (bit-banged GPIO, not SPI NSS)PC0 = CSN, PB0 = CE
TIM2 (4ch)ESC PWM / DShot outputPA0 = CH1 (active), PA1 = CH2, PB10 = CH3, PB2 = CH4 (configured, unused)
USART2Debug/telemetry console, 115200 8N1PA2 = TX, PA3 = RX

Boot sequence (main.c): GPIO → USART2 → I2C1 → SPI2 → TIM2 → arm ESC (Motor_Init) → bring up radio (Nrf_init) → enter RX loop, printing BOOT/I2C OK/SPI OK/TIM OK over UART at each stage so a bring-up failure is localized immediately from the serial log.


IMU / Attitude Estimation (MPU6050)

mpu6050.c talks to the MPU6050 directly over I2C1 (no external library) at address 0x68.

Init sequence:

RegisterValuePurpose
0x75 (WHO_AM_I)read, expect 0x68sanity check on boot
0x6B (PWR_MGMT_1)0x00wake from sleep, select internal clock
0x1A (CONFIG)0x01DLPF on, ~184 Hz bandwidth
0x25 (SMPLRT_DIV)0x00sample rate = 1 kHz / (1 + 0) = 1 kHz
0x1B (GYRO_CONFIG)0b00011000±2000 °/s full scale
0x1C (ACCEL_CONFIG)0x00±16 g full scale

Raw accel/gyro burst-reads come from 0x3B (6 bytes, accel X/Y/Z) and 0x43 (6 bytes, gyro X/Y/Z), scaled by the datasheet sensitivity for the selected range (/16384.0f g/LSB for accel, /16.4f (°/s)/LSB for gyro).

Gyro calibration (calibrate_gyro) averages 1000 samples at boot to compute a static bias — currently computed but not yet subtracted from live readings (see Known Limitations).

Attitude fusion (log_data) runs a single-stage complementary filter:

  1. Exponential low-pass (ALPHA = 0.02) on both accel and gyro channels.
  2. Body-rate → Euler-rate transform: phiHat_rps = gx + tan(theta)*(sin(phi)*gy + cos(phi)*gz), thetaHat_rps = cos(phi)*gy - sin(phi)*gz.
  3. Gyro integration at dt = 0.001 s (1 kHz loop assumption) added to the running angle.
  4. Fusion with accel-derived tilt (atan/asin off the gravity vector) at a 0.98 / 0.05 gyro/accel blend, printed over USART2 as Pitch:__, Roll:__.

Wireless Link (NRF24L01+)

Both ends of the radio link are custom drivers — the STM32 side (Nrf2401.c) talks directly to the NRF24L01+ command/register set over SPI2 with no radio library, and the transmit side (esp32.c) uses the Arduino RF24 library on an ESP32 paired to a PS5 controller over Bluetooth.

Link configuration (must match on both ends):

SettingValue
Data rate1 Mbps
RF channel85 (2.485 GHz)
TX power0 dBm
Address width5 bytes (SETUP_AW = 0x03)
RX/TX addressE7 E7 E7 E7 E7
Payload size16 bytes, static (no dynamic payloads)
Auto-ACKdisabled on both ends
CRC16-bit (ESP32 side); STM32 driver disables hardware auto-ack/CRC handling and relies on the fixed packet contract instead

Packet format — a flat 16-byte struct sent as raw bytes:

c
typedef struct {
    float throttle;
    float roll;
    float pitch;
    float yaw;
} rc_packet;   // 4 x 4-byte float = 16 bytes, matches NRF24 payload size exactly

TX side (esp32.c): reads PS5 gamepad stick axes via ps5Controller, maps left stick → throttle/roll and right stick → pitch/yaw, and pushes a packet over RF24::write() roughly every 20 ms.

RX side (Nrf2401.c + main.c): Nrf_init() powers up the radio, configures the RF settings above, and starts listening (CE high). Recieve_nrf() polls the STATUS register for the RX_DR flag, pulls the 16-byte payload with the R_RX_PAYLOAD command, and clears the flag. main.c copies the payload into an rc_packet, runs the throttle channel through a first-order low-pass (alpha = 0.1), and feeds the result to Motor_SetSpeed().

Note: enable_auto_ack() exists in the driver but is not currently called from Nrf_init() — auto-ack stays disabled to match the transmitter's setAutoAck(false).


Motor Control

Motors.c drives ESCs with standard hobby PWM on TIM2 channel 1: with the timer clocked at 1 MHz (72 MHz / (prescaler 71 + 1)) and a 20000-tick period, CCR1 directly represents the pulse width in microseconds at a 50 Hz refresh rate — the same 1000–2000 µs framing every analog PWM ESC expects.

FunctionBehavior
Motor_Init()Arms the ESC: full throttle (2000) for 2 s, then minimum (1000) for 2 s, matching the standard ESC calibration/arm beep sequence
Motor_SetSpeed(percent)Maps 0–100 % linearly to 1000–2000 µs
Motor_SetRaw(ccr)Direct CCR write for bench testing
Motor_Stop()Forces minimum throttle (1000)
Motor_Control_UART()Serial bench-test command parser (S<pct> set speed, R<ccr> set raw, X stop) over USART2

Only TIM2_CH1 is currently wired to a motor output in main.c — channels 2–4 are configured (see pin table above) but not yet driven, so multi-motor mixing isn't implemented yet.


Custom DShot150 Driver

Dshot150.c implements the DShot150 digital ESC protocol frame-by-frame, from scratch, on top of TIM2 + DMA.

Frame construction is spec-correct. A DShot frame is 16 bits: 11-bit throttle value, 1 telemetry-request bit, and a 4-bit CRC:

c
data  = (throttle << 1) | telemetry;                  // 12 bits: 11-bit throttle + telemetry
crc   = (data ^ (data >> 4) ^ (data >> 8)) & 0xF;      // XOR-nibble checksum, per the DShot spec
frame = (data << 4) | crc;                             // final 16-bit frame

Bit encoding. Each of the 16 frame bits is expanded into a duty-cycle value for one PWM period — 170 (≈85% duty) for a 1 bit, 85 (≈42.5% duty) for a 0 bit — into a 17-entry buffer (16 bits + a trailing 0 to force the line low/reset). The buffer is streamed to TIM2_CH1's CCR1 register via HAL_TIM_PWM_Start_DMA, so each bit's duty cycle loads automatically without CPU intervention.

c
void readBits(uint16_t data) {
    for (int i = 0; i < 16; i++) {
        uint16_t bitVal = (data >> (15 - i)) & 0x1;
        dshotbuffer[i] = bitVal ? 170 : 85;
    }
    dshotbuffer[16] = 0;
}

Current state: this correctly reproduces DShot's bit encoding and checksum, but the timer feeding it is still configured for the 20 ms / 1 MHz standard-PWM setup described above rather than a proper DShot150 bit clock (real DShot150 needs a ~6.67 µs bit period, i.e. the whole 16-bit frame takes ~107 µs — not 16 × 20 ms). Getting this fully protocol-compliant means giving TIM2 a dedicated ARR/prescaler for DShot bit timing (or moving DShot to its own timer) and reworking the DMA burst length accordingly. This is the main piece marked "in progress" in this repo — see below.


Power Distribution Board

Hardware/BMS/DroneBMS.kicad_sch — titled "TakeUp Power Distribution Board" in the schematic sheet — is a custom 4-layer (1.6 mm) PCB that takes a 3S LiPo in over an XT60 connector and produces the regulated rails and battery telemetry the flight controller needs. It's referred to informally as the "BMS" but its scope today is power conditioning + voltage sensing rather than active cell balancing.

BMS schematic

Power path:

text
XT60 (3S, ~11.1V) → Fuse (F1) + TVS diode (D3, SMAJ15A) → VBATTMAIN
                                                              │
                              ┌───────────────────────────────┼───────────────────────────────┐
                              ▼                                ▼                               ▼
                    LMR51430 buck (U1)                4x ESC power pads                Battery-voltage
                    11.1V → 5V, 4.7uH inductor,        (raw VBATTMAIN + GND,            sense divider
                    73k/10k feedback divider           470uF bulk cap each)             (10k/3.3k → STM32 ADC)
                              │
                              ▼
                    AMS1117-3.3 LDO (U2)
                    5V → 3.3V logic rail
SectionComponentsNotes
Battery inputXT60BATT1, F1 (fuse), D3 (SMAJ15A TVS)Overcurrent + transient surge protection on the main battery line before it fans out
5V railU1 LMR51430 synchronous buck, L1 4.7 µH, R1/R2 = 73k/10k feedback, bulk + decoupling caps, D1 "5V On" LEDSteps 11.1V pack voltage down to 5V
3.3V railU2 AMS1117-3.3 LDO, D2 "3.3V On" LEDSteps 5V down to 3.3V for the MCU/logic
Battery senseR3/R4 = 10k/3.3k divider → J1/J2Scales VBATTMAIN down into ADC range for the STM32 to read pack voltage in software
ESC powerESC1–ESC4 pads, 470 µF bulk cap each, plus a raw +12V padDistributes unregulated battery voltage directly to each ESC

Board: 4 copper layers (F.Cu/In1.Cu/In2.Cu/B.Cu), 1.6 mm stack-up, 4 mounting holes, KiCad 9 source files included for both schematic and layout, plus a 3D render at Hardware/BMS/PCB_Render_1.png.


Building the Firmware

The Software/ tree is a standard STM32CubeIDE / STM32CubeMX HAL project targeting an STM32F4 Nucleo-64 board.

  1. Import Software/ into STM32CubeIDE (or point a Makefile-based ARM GCC toolchain at Software/INC and Software/Src).
  2. Flash over the Nucleo's onboard ST-LINK.
  3. Open a serial terminal at 115200 8N1 on the ST-LINK VCP to watch boot status (BOOT, I2C OK, SPI OK, TIM OK) and the live RC/attitude log.
  4. Flash Software/Src/esp32.c to an ESP32 (Arduino core, RF24 + ps5Controller libraries) to act as the transmitter, or drive TIM2_CH1 directly via Motor_Control_UART() for a bench test with no radio at all.

Known Limitations / TODO

  • Voice control isn't implemented yet. The current transmit path is a PS5 controller relayed through an ESP32, standing in for the audio pipeline this project is ultimately meant to use.
  • Power board has no active cell balancing/protection IC — today it's fusing, a TVS clamp, regulation, and voltage-divider telemetry, not a full smart BMS.

License

MIT — see LICENSE.

Parts

42
QtyValueFootprintReferences
5470uFCapacitor_THT:CP_Radial_D8.0mm_P3.50mmC7, C8, C9, C10, C13
5ESCPWRCustom_Footprints:ESC_SOLDER_PADESC1, ESC2, ESC3, ESC4, ESC5
4MountingHole_3.2mm_M3MountingHole:MountingHole_3.2mm_M3H1, H2, H3, H4
20.1uFCapacitor_SMD:C_1206_3216MetricC1, C3
210kResistor_SMD:R_0805_2012MetricR2, R3
21kResistor_SMD:R_0805_2012MetricR5, R6
21uFCapacitor_SMD:C_1206_3216MetricC11, C12
2BattLevel (ADC)Connector_PinHeader_1.00mm:PinHeader_1x01_P1.00mm_VerticalJ1, J2
2GndCustom_Footprints:ESC_SOLDER_PAD3.3VPAD1, 5VPAD1
2GndConnector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Vertical3.3V1, 5V1
110uFCapacitor_SMD:CP_Elec_4x4.5C5
122uFCapacitor_SMD:C_1206_3216MetricC4
122uFCapacitor_SMD:CP_Elec_4x5.3C6
13.3V OnLED_SMD:LED_0805_2012MetricD2
13.3kResistor_SMD:R_0805_2012MetricR4
14.7uFCapacitor_SMD:C_1206_3216MetricC2
14.7uHCustom_Footprints:IND_VSAB0630-4R7ML1
15V OnLED_SMD:LED_0805_2012MetricD1
173kResistor_SMD:R_0805_2012MetricR1
1AMS1117-3.3Package_TO_SOT_SMD:SOT-223-3_TabPin2U2
1FuseFuse:Fuse_1206_3216MetricF1
1LMR51430Package_TO_SOT_SMD:SOT-23-6U1
1SMAJ15ADiode_SMD:D_SMAD3
1VBattConnector_AMASS:AMASS_XT60-M_1x02_P7.20mm_VerticalXT60BATT1

Questions

How big is the DroneBMS PCB?

It measures 90 × 51 mm and has 4 copper layers, 1.6 mm thick.

What parts does the DroneBMS use?

42 parts, built around the AMS1117-3.3 and SMAJ15A. 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 DroneBMS KiCad files?

From the zmuhammad07/TakeUp repository on GitHub, at the commit this page was made from: the board is Hardware/BMS/DroneBMS.kicad_pcb and its schematic Hardware/BMS/DroneBMS.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the DroneBMS design in my own project?

Its repository publishes it under the MIT licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).

Similar boards

  • 8 layers85 × 55 mmDadu 8L 2side 85x55, the printed circuit board in 3D

    Dadu 8L 2side 85x55

    comedy1982-spec/pcb-viewer

    Dadu 기반 ELD 솔레노이드 ECU. 12 V 입력, TC364 · CAN-FD · PMIC, PCB 위 센서는 NTC 하나. A4911(3상 드라이버)의 A·B 레그로 H-브리지(하프브리지 IAUC60N04S6N050H ×2, 레그 션트 2 mΩ ×2), C 레그는 비워 두고 SPI로 그 고장(VC · CHO · CLO · OC3)을 마스크.

    130 parts
  • 4 layers150 × 90 mmMultibay, the printed circuit board in 3D

    Multibay

    EdgeOfAssembly/multi-hdd-usb3-adapter

    USB3 multi-HDD adapter (PATA+SATA) — JLCPCB Gerbers/BOM

    131 parts
  • 4 layers135 × 101.3 mmNft hydroponic controller, the printed circuit board in 3D

    Nft hydroponic controller

    hasan-abuzaid/nft-hydroponic-controller

    Open-hardware ESP32-S3 controller for NFT hydroponics: pH/EC/level sensing, 6 relay channels, ESPHome + Home Assistant

    107 partsCERN-OHL-S-2.0
  • 4 layers65 × 65 mmBaja daq, the printed circuit board in 3D

    Baja daq

    myamhili/Baja_daq

    Uwaterloo Baja SAE Central Data Acquisition Pcb

    57 parts
  • 2 layers100 × 70 mmGswitch brain, the printed circuit board in 3D

    Gswitch brain

    MarkWestbroek/MusicBrain

    A central brain running on teensy or a lighter MCU to process any control signals (MIDI, CV, our own) into the same but adding logic, ADSRs, DCOs, CV matrices etc. to it

    69 partsMIT
  • 4 layers74.5 × 70.3 mmNest mini v2-drop in pcb, the printed circuit board in 3D

    Nest mini v2-drop in pcb

    iMike78/nest-mini-drop-in-pcb

    Drop-in PCB replacement for the Google Nest Mini v2 with ESP32-S3, ESP32-P4 and optional ESP32-C6. Inspired by Onju Voice and Home Assistant Voice PE.

    229 parts628CERN-OHL-S-2.0
  • 4 layers58.8 × 29 mmSparkAltBatteryBoardV1, the printed circuit board in 3D

    SparkAltBatteryBoardV1

    fahreddinaykut/SparkAltBatteryBoard

    A custom research-oriented battery interface and telemetry board for the DJI Spark platform, built around a standard 3S LiPo battery pack instead of the discontinued, hard-to-find OEM Smart Battery.

    46 parts20
  • 2 layers100 × 60 mmPpse-2021, the printed circuit board in 3D

    Ppse-2021

    thomasnonis/ppse-2021

    This is the repository for SALMO, the Solar Azimuth and eLevation Motorized lOcator. It is a PCB used for driving a tracking solar panel system, using GPS location and a MPPT algorithm to maximise the incident power.

    133 parts5