PERA Swarm · Indoor Drone Testbed

Operator's
Manual

Everything you need to install and operate the Drone Swarm control application — from camera calibration to flying autonomous missions in the arena.

Windows x64 Ubuntu x64 Runs 100% locally 4-camera tracking
01

Overview

The Drone Swarm Research Platform is an indoor testbed for swarm-robotics experiments. The control application runs entirely on your computer: a local backend tracks drones through four USB cameras, talks to the swarm over an ESP32 radio link, and serves a browser-based control interface. No cloud connection is needed to fly.

The indoor arena with four tracker cameras
Photo — arena & camera rig Add docs/images/manual/arena.jpg to replace this placeholder
The indoor arena with the four tracker cameras and the operator's station.

What you need

  • A Windows or Ubuntu computer with four USB camera inputs available.
  • The four tracker cameras mounted around the arena and plugged in.
  • The ESP32 radio transceiver connected via USB (serial).
  • One or more platform drones with charged batteries.
  • A printed checkerboard pattern glued to a flat board for calibration (default 9 × 6 inner corners, 23.9 mm squares — see Calibration).

Typical workflow

  1. Install and launch the application — the UI opens in your browser.
  2. In Camera Settings, confirm camera indices and the serial port.
  3. Run Calibration (only needed when cameras move or on first setup).
  4. Register your drones in the Drones page.
  5. Fly manually from MoCap or the Console, or upload a Python mission in Upload.
02

Installation

Download the package for your operating system from the project's release page:

PlatformPackageHow to run
WindowsDroneSwarm-Windows-x64.zip Extract the ZIP, then double-click DroneSwarm.exe.
UbuntuDroneSwarm-Ubuntu-x64.tar.gz Extract, then run the DroneSwarm binary inside.

The package is self-contained — you do not need Python, Node.js, or any libraries installed. The Windows ZIP also contains sender_esp32.ino and receiver_drone1.ino for programming the ESP32 boards.

Ubuntu serial permission. To access the ESP32 radio, your user must be in the dialout group:
sudo usermod -a -G dialout "$USER"
Log out and back in afterwards.

Where your data lives

Calibration files, fleet registry, settings, and uploaded missions are stored in %APPDATA%\DroneSwarm on Windows and ~/.config/DroneSwarm on Ubuntu. Deleting this folder resets the application.

Optional environment variables

VariableEffect
DRONE_BACKEND_PORTChange the local port (default 3001).
DRONE_SWARM_DATA_DIROverride the writable data directory.
DRONE_OPEN_BROWSER=falseDon't auto-open the browser on launch.
DRONE_CAMERA_BACKENDForce the camera backend: dshow, v4l2, or default.
03

First Launch

  1. The download includes two Arduino .ino sketches: one for the ground ESP32 transmitter and one for the drone ESP32 receiver.
  2. Before uploading the receiver sketch, check the MAC address of each ESP32 and add the required MAC address values to the receiver code.
  3. Use the Arduino IDE to upload the sender/transmitter sketch to the ground ESP32 and the receiver sketch to each drone ESP32.
  4. Plug in all four cameras and the ground ESP32 radio before starting the app.
  5. Run the application. The backend starts on 127.0.0.1:3001 and your default browser opens the interface automatically. If it doesn't, browse to http://127.0.0.1:3001 yourself.
  6. Open Camera Settings and check that each of the four camera slots shows the right view, and that the correct serial port is selected.
  7. If this is a new arena or the cameras have been moved, run the calibration wizard before flying.
The application on first launch
Screenshot — app on first launch Add docs/images/manual/ui-overview.png to replace this placeholder
The interface after launch, with the sidebar on the left and the MoCap page open.
Local only. The application binds to 127.0.0.1; it is not reachable from other machines on the network. Keep the terminal/console window it starts in open while operating.
04

Interface Tour

The sidebar switches between six pages. All pages stay live in the background — switching away doesn't stop streams, logs, or a running calibration.

MoCap
Live tracking: camera stream, 3D scene, flight controls, PID tuning, telemetry.
Drones
Register drones by name and MAC; monitor battery, position, and state.
Console
Type flight commands directly at a drone or the whole swarm.
Upload
Upload and run Python mission scripts against the swarm API.
Calibration
Four-step camera calibration wizard with live capture preview.
Camera Settings
Assign USB camera indices and choose the ESP32 serial port.
05

Camera Settings

Camera indices

Each tracker camera (cam1cam4) is bound to a USB device index. If the wrong physical camera shows up in a slot, change its index and apply. Applying releases all four captures and reopens them on the new indices — the stream freezes for a few seconds while this happens.

Serial port

Select the port where the ESP32 radio is connected (e.g. COM5 on Windows, /dev/ttyUSB0 on Ubuntu) and apply. The current port is shown even if the device is unplugged at the moment.

Camera Settings page
Screenshot — Camera Settings page Add docs/images/manual/camera-settings.png to replace this placeholder
Camera index assignment and serial-port selection.
06

Calibration

Calibration teaches the tracker where the cameras are and where the world origin is. Run it on first setup and whenever a camera is moved, refocused, or replaced.

Prepare the checkerboard first

Before starting the wizard, print the checkerboard pattern and paste it onto a flat, rigid surface — a clipboard, foam board, or piece of plywood works well. Any bending or waviness in the paper ruins the calibration accuracy, so glue it down completely flat with no bubbles or creases. Print at 100% scale (no "fit to page"), then measure one square with a ruler to confirm the size — you'll enter this measurement in the wizard.

Download the printable checkerboard PDF

Printed checkerboard mounted on a flat board
Photo — checkerboard on a flat board Add docs/images/manual/checkerboard.jpg to replace this placeholder
The printed checkerboard pasted flat on a rigid board, ready for capture.

The four steps

StepWhat it does
1 · IntrinsicsPer-camera lens parameters. Show the checkerboard to each camera and capture views.
2 · ExtrinsicsCamera positions relative to each other. Capture the board where camera pairs both see it.
3 · LandmarksSets the world origin and floor plane in the arena.
4 · VerifyTest tracking quality and accept or re-run the result.

Running the wizard

  1. Enter your checkerboard's inner-corner count and square size. Defaults match the standard board: 9 columns × 6 rows, 23.9 mm squares.
  2. Choose the starting step. You can start midway (e.g. only re-do Landmarks) — earlier steps are reused from the current calibration.
  3. During the two capture steps, press Space to capture the current frame while the Calibration page is visible.
  4. Watch the per-step log for capture counts and reprojection errors, then verify and accept.
Calibration wizard during intrinsics capture
Screenshot — calibration wizard (capture step) Add docs/images/manual/calibration-wizard.png to replace this placeholder
The wizard stepper with the live capture preview and per-step log.
Tip. Capture the checkerboard at varied angles and distances, covering the edges of each camera's view — this noticeably improves tracking accuracy.
07

Drone Fleet

Before a drone can be commanded it must be registered in the Drones page.

  1. Enter a friendly name and the drone's MAC address in the form AA:BB:CC:DD:EE:FF (dashes also accepted).
  2. Add the drone. It appears in the fleet list with live battery, position, state, and a "last seen" age.
  3. Toggle Active to include or exclude the drone from swarm commands and missions.

Battery badges are colour-coded: green above 60%, amber above 25%, red below. The fleet registry is saved on the backend, so it survives restarts.

Drone fleet page
Screenshot — Drones page with a registered fleet Add docs/images/manual/drones.png to replace this placeholder
Registered drones with live battery, position, and last-seen status.
08

MoCap & Flight

The MoCap page is the main flight screen for a single drone. Select the drone at the top, then use the panels:

  • Camera stream — live tracker view with detection overlay, plus tracker state, FPS, and heading age.
  • 3D scene — the drone's tracked position and setpoints in the arena.
  • FlightArm/Disarm, Takeoff to a target height (default 0.20 m), and Land. Takeoff is only enabled while armed.
  • PID — live controller gains. Change values only in small steps and be ready to land; bad gains cause oscillation.
  • Telemetry — position, heading (radians), battery, and controller state.
MoCap page during a hover
Screenshot — MoCap page during flight Add docs/images/manual/mocap.png to replace this placeholder
Camera stream, 3D scene, and flight controls during a hover test.
Before arming: confirm tracking is stable (position updating, low heading age), the arena is clear, and the drone is upright at a tracked location.
09

Console Commands

The Console sends typed commands to the selected target — one drone or the whole swarm. Every command is echoed in the history with its acknowledgement or error.

CommandDescription
arm <on|off>Arm or disarm the targeted drone(s).
takeoff <z>Climb to z metres and hold. z must be between 0 and 2.0, and the drone must be armed first.
landDescend and disarm at touchdown.
goto <x> <y> <z>Move to an absolute world position (metres).
move <dx> <dy> <dz>Shift the setpoint relative to the current one.
yaw <radians>Rotate to an absolute yaw angle.
hover <seconds>Hold the current setpoint for N seconds.
trim <T> <R> <P> <Y>Apply stick trim values (µs).
pid <index> <value>Update one PID gain (index 0–16); the full gain set is re-sent.
estopEmergency stop — immediate motor cut.
pingStatus echo: state, position, battery.
Console page with command history
Screenshot — Console with command history Add docs/images/manual/console.png to replace this placeholder
Command history with acknowledgements, and the command reference cards.
Example session.
arm on
takeoff 0.5
goto 0.8 0.4 0.5
hover 3
land
10

Mission Scripts

The Upload page runs Python mission scripts against a restricted swarm API. Drag in a .py file (only .py is accepted), review the preview, upload, and run. Output from the script streams into the run log; a running mission can be stopped at any time.

Scripts are validated before running: only calls to the functions below (plus print/log) are permitted.

FunctionDescription
arm()Arm the drone. Blocks until the controller reaches READY.
disarm()Disarm immediately.
takeoff(z)Climb to z metres. Blocks until HOVER is reached.
land()Descend and disarm at touchdown. Blocks until landed.
goto(x, y, z)Retarget to an absolute world position (non-blocking).
move(dx, dy, dz)Shift the setpoint relative to the current one (non-blocking).
set_yaw(yaw)Rotate to an absolute yaw (radians).
wait(seconds)Sleep — use after goto/move so the drone can get there.
get_position()Latest tracked world position in metres, or None.
get_battery(drone_id)Battery percentage by drone id, name, or MAC.
get_state()Controller state (IDLE, READY, TAKEOFF, HOVER, …).
list_active()Ids of all drones currently marked active.
on_telemetry(callback)Callback fired on every battery telemetry packet.
log(*args)Write a line to the run log.

Example mission

arm()
takeoff(0.5)
goto(0.8, 0.4, 0.5)
wait(3)
log("position:", get_position())
land()
Upload page with a mission running
Screenshot — Upload page with run log Add docs/images/manual/upload.png to replace this placeholder
A mission script uploaded and running, with live output in the run log.
11

Safety

  • Emergency stop: type estop in the Console for an immediate motor cut on the targeted drone(s). Prefer land when there is time for a controlled descent.
  • Keep hands, faces, and loose objects out of the arena while any drone is armed.
  • Never leave a drone armed unattended — disarm as soon as flight is done.
  • Takeoff height is capped at 2.0 m; stay well inside the calibrated tracking volume.
  • Land promptly when a battery badge turns amber; don't fly a red battery.
  • If tracking is lost mid-flight (frozen position, growing heading age), land or estop immediately.
Props spin fast. Always disarm before handling a drone, and remove props when bench-testing firmware or trim changes.
12

Troubleshooting

SymptomWhat to check
Camera error / frozen stream Go to Camera Settings and re-apply the camera indices — this releases and reloads all four cameras. If the error persists, close the application completely and restart it with the cameras plugged in.
UI doesn't open Browse to http://127.0.0.1:3001 manually. If the port is taken, set DRONE_BACKEND_PORT and restart.
Wrong / black camera views Reassign indices in Camera Settings. On Windows try DRONE_CAMERA_BACKEND=dshow; on Ubuntu v4l2. Ensure no other app holds the cameras.
No serial connection Pick the right port in Camera Settings. On Ubuntu, confirm your user is in the dialout group (relog after adding).
Drone not responding Check it's registered with the correct MAC, marked Active, and reporting battery ("last seen" recent). Send ping from the Console.
takeoff rejected The drone must be armed first, and z must be in (0, 2.0] metres.
Poor tracking / drifting hover Re-run calibration (start from Extrinsics if lenses are unchanged). Check lighting and that all four cameras see the arena centre.
Mission upload rejected Only .py files are accepted, and only the documented API calls are allowed in the script.
Reset everything Quit the app and delete the data folder (%APPDATA%\DroneSwarm or ~/.config/DroneSwarm). Calibration and fleet must then be redone.

Still stuck? Open an issue on the project repository — include your OS, the console output from the app, and what you were doing when it failed.