The airframe runs a Betaflight-based flight controller, which means the radio link and the sensing payload are two completely separate systems on the drone — the FC only ever sees stick and switch data, never the sensor stream. That separation keeps the flight-critical link simple and fast, and lets the sensing payload fail safely without touching control authority.
Binding is the one-time pairing step that locks the receiver to a single transmitter so it won't respond to anyone else's radio on the same protocol — done once on the bench, holds until it's deliberately re-bound. The receiver speaks SBUS, so once it's bound there's no handshake left to negotiate — it just streams raw channel data straight to the FC over a single one-way serial line, every frame, no acknowledgment expected back.
That clip on the right is the link being checked at the signal level, not just "the goggles show a picture": a logic analyzer is clipped onto the receiver's data line, and its top trace sits flat — nothing moving, no data. The moment a switch on the transmitter gets toggled, the trace immediately fills with a dense, continuous train of pulses and keeps streaming. That's proof the bind holds and the link is actually carrying commands, not just powered on.
Before any of the sensing payload goes anywhere near the airframe, the base flight stack gets checked on its own, props off: can the flight controller actually spin each motor the way it's told to, and does the IMU report orientation correctly as the frame moves. Two separate sanity checks, done on the bench before anything gets trusted in the air.
Each motor driven individually off the flight controller's ESC outputs — confirming direction, spin-up response, and that motor order matches the configured layout before trusting the mixer with any throttle input in flight.
The frame rotated by hand through roll, pitch, and yaw while watching the live orientation feed, to confirm the IMU tracks the physical motion 1:1 before it's ever trusted to self-level or hold attitude in the air.
The 3D model on the configurator screen is reading the same IMU the flight controller flies off of — not a separate preview. As the frame gets picked up and tilted in hand, the model on screen banks and rotates right along with it in real time, axis for axis, confirming the IMU is wired in correctly (no swapped or inverted axes) before it's trusted for self-leveling or attitude hold.
Every sensor on the payload — camera, radar, and the WiFi sensing node — has to sit at a fixed, known position and orientation relative to the airframe for the fusion math downstream to hold up. A 3D-printed bracket does that job: a central mounting column for the primary sensor pair and a perpendicular side plate for the secondary module, all referenced to the same mounting pattern so the offsets between sensors stay constant and known.
Designed and sliced in Bambu Studio, printed on a Bambu printer.

Bottom to top: the battery feeds the drone frame, the printed mount bolts straight onto that frame, and the camera, the radar/WiFi-CSI sensor, and the Raspberry Pi all sit on that same mount — one reference point, every sensor offset known.

The first working version of the sensing stack ran on an LD240 radar sensor, plotting raw detections straight onto a flat, top-down map — each return is just a range and a bearing from the drone, with no elevation. A person standing and a person lying down look identical, and nothing in the data says how far off the floor a detection actually sits. It was enough to prove the pipeline end to end — radar return in, bearing/range out, point on a 2D map — but it throws away a dimension the sensor is capable of giving back.
The right-hand panel in the clip isn't a recording of actual LD240 output — it's a stand-in that illustrates what the sensor itself sees: just a point moving on a range axis off a fixed origin, nothing else. Starting just off the sensor, it moves away, reaches its farthest point around the six-second mark, then comes back — settling, by the end, about halfway between where it started and that farthest point. Once the real pipeline is recording, this is the panel actual detections replace.

From there the project moved on to real 3D readings off the same sensor, piped into a Meta Quest so detections can be walked around and inspected volumetrically instead of squashed onto a plane — the same radar returns that used to land as a flat dot on a map now sit at their actual height in space, viewable from any angle.
Each LD240 return already carries an elevation angle alongside range and bearing, so getting to a 3D position is just projecting that triple into Cartesian coordinates on the Pi — no second sensor or extra fusion step needed. The resulting point stream goes out over Wi-Fi as a lightweight UDP feed to the Quest, where a small Unity app built on the Meta XR SDK ingests it and renders every detection as a point anchored to the headset's room-scale origin, so the cloud of returns holds still in space while you walk around it and look from any angle.
The camera and the radar/WiFi sensing stack measure fundamentally different things, and the fusion approach leans on that: the camera gives bearing — the angle to a detected person, derived from where it falls in the frame relative to the camera's known field of view — while the radar/CSI sensing gives range — how far away it is, independent of lighting or whether the target is even visible to the lens. Neither signal alone gives a position. Together, bearing and range are exactly the two numbers needed to place a detection on a 2D map.
The same two numbers decompose differently depending on which way the sensor's pointed. Forward, bearing and range give a position on the floor; straight down, the identical trig — angle off vertical, plus range — gives height instead:
With bearing θ (or depression φ, pointed down) and range r from the sensing payload, the target's position — or the drone's own height — drops out of the same basic trigonometry:
That (x, y) point, rotated into the drone's current heading and offset by its own position in the room, is what gets plotted on the live 2D map — one point per detection, updated every cycle as the drone moves and the sensor sweep refreshes. Point the same sensor down instead and h is recomputed the same way, every cycle, straight from detections that are already coming in — filling the role a barometer normally would on a small drone, estimating altitude, except it's reading geometry off the radar instead of air pressure.