Project 01 · 2025

Custom Quadcopter

A quadcopter designed from nothing — frame, wiring, and flight software. Five CAD iterations to get from “it flies” to “it holds a stable hover and tracks a target on its own.”

5frame iterations
100%custom CAD frame
Pi + camonboard compute
ELRSradio link

The brief

Design and CAD-model a fully custom quadcopter frame, reinforce it to survive crashes, integrate a flight-controller / ESC stack, brushless motors, and an ELRS radio system, and hand-solder every power and signal connection.

Then diagnose the flight-stability problems that showed up — frame flex, weight balance, oscillation — and fix them through redesign until the airframe hovers cleanly with a Raspberry Pi, camera, and GPS aboard.

Stack

DesignFusion 360, 3D-printed frame
Flight controllerFC / ESC — confirm model
Motorsbrushless — size / kv?
RadioExpressLRS (ELRS)
CompanionRaspberry Pi + USB camera + GPS
AutopilotArduPilot (MAVLink / GUIDED)
VisionPython, OpenCV

The iterations

v1 → v5

01

Iteration 1

Baseline airframe

V1 — interactive model / photos
drop files in assets/drones/v1/

First printable frame: top plate, bottom plate, and four arms. Proof that the geometry, motor mounts, and stack layout work together.

  • Three-part printed frame — top, bottom, arms
  • draft — tell me what v1 got right / wrong
Frame size? mm motor-to-motor
All-up weight? g
Outcomeflew? flex issues?
02

Iteration 2

Refined geometry

V2 — interactive model / photos
drop files in assets/drones/v2/

Second pass on the same three parts — tighter tolerances and a cleaner layout for the flight-controller stack and wiring.

  • Reworked top / bottom / arm parts
  • draft — what changed and why
Change vs v1?
Outcome?
03

Iteration 3

Stiffening the frame

V3 — interactive model / photos
drop files in assets/drones/v3/

Added dedicated arm supports and a top cap. This is the iteration where the frame stopped flexing under motor load — gussets and bracing to kill the oscillation.

  • New part: arm support (gusset / brace)
  • New part: cap
  • draft — did this fix the oscillation? by how much?
AddedArm support, cap
Problem targetedFrame rigidity / oscillation
Outcome?
04

Iteration 4

Modular joints + payload

V4 — interactive model / photos
drop files in assets/drones/v4/

Introduced push-pin joints for tool-free assembly and an arm claw for clamping. A pin-less variant was prototyped and dropped.

  • New: male / female push-pin joints
  • New: arm claw
  • New: alternate cap
  • Abandoned: pin-less arm concept
  • draft — why push-pins? what was the claw for?
AddedPush-pin joints, arm claw, alt cap
Outcome?
05

Iteration 5 · current

Sensors + autonomy-ready

V5 — interactive model / photos
drop files in assets/drones/v5/

The flying configuration: a dedicated GPS mount, refined arms and claw, and the 150 mm printed sphere the drone tracks in the air.

  • New: GPS module mount
  • Refined: arm, arm support, claw
  • New: printed tracking target (150 mm sphere)
  • draft — final weight, flight time, what you'd do next
AddedGPS mount, tracking sphere
All-up weight? g
Hoverstable / notes
SW

Flight software

Autonomous visual tracking

On top of ArduPilot, a Python stack running on the Raspberry Pi detects a blue printed sphere with OpenCV, estimates its distance from apparent size, and streams velocity + yaw-rate commands to the flight controller over MAVLink to yaw toward the ball and hold a set distance.

DetectorHSV threshold + roundness / saturation gates, 960 px, ~150 mm ball
DistancePinhole model, calibrated focal length in pixels
Yaw controlProportional on image offset, deadband, rate-limited
Forward controlProportional on distance error, smoothed, clamped
Linkpymavlink, SET_POSITION_TARGET in body frame at 10 Hz
Safety--dry-run / --no-fc modes, lost-target timeout, manual-override switch
# follow.py — the control step
if usable:
    yaw_rate = yaw_ctl.update(result["offset_x"])
    vx, _   = fwd_ctl.update(result["distance_m"])
    state = "TRACK"
else:
    # keep sending zeros — going silent for 3 s
    # drops the FC out of velocity control
    yaw_rate, vx = 0.0, 0.0
    state = "SEARCH"

fc.send_command(vx, yaw_rate)

Full source: github.com/jjkim08 link the exact repo


In the air

Flight log

flight video goes here — drop a muted loop at assets/drones/flight.mp4
(send me the clips and I’ll cut them into a cinematic band with click-to-expand)
← all projects