SkyHub is a drone-fleet operations platform spread across fifteen repositories — twelve live services and firmware plus three stubs. This page is the shared vocabulary: the entities, transports, and networks every other page assumes you already know. Each entry links to the deep page that owns the detail — read this once, then follow the links when you need more.
New to the platform shape? Start with the Platform Introduction and Platform Architecture Overview. For an end-to-end walk of a request, see Cross-System Data Flows.

The mental model

The Dashboard (browser) talks to the Gateway (cloud) over HTTP + Socket.IO. The Gateway is the control-plane hub: it authenticates users, brokers telemetry, and dispatches commands over rosbridge to a vehicle — either a physical drone reached through a WireGuard VPN, or a SITL Docker container the Gateway spawns. Video and manual gamepad control travel their own out-of-band paths. The key insight the whole platform is built on: SITL and physical drones speak the exact same rosbridge/topic contract, so the Gateway treats them almost identically. The only real differences are how it addresses them (a VPN IP vs a Docker host) and that it manages the SITL container’s lifecycle itself.

Vehicles & simulation

drone
The generic unit the platform controls. Every drone has a typephysical or sitl — defined in src/utils/drone_types.py (DroneTypes enum), and a vehicle_type (copter or rover). From the Gateway’s API and service layer, both types look the same. See Drone Fleet Management.
physical drone
A real aircraft running SkyCore Drone OS on an NVIDIA Jetson. It is reachable from the Gateway only after it joins the drone WireGuard plane (10.71.0.0/16); the Gateway connects rosbridge to its 10.71.x address (or routes through the jumphost). See Physical drone activation.
SITL (Software-In-The-Loop)
A hardware-free simulated drone: a Docker container running ArduPilot SITL + MAVROS + rosbridge + a GStreamer→WHIP video node, standing in for a real aircraft. The Gateway’s SITLDroneService spawns containers named SKYHUB_SITL_<n> (only when ENABLE_SITL=true), maps rosbridge to host port 9090+n, and connects to DOCKER_HOST_IP. See SITL Drone Lifecycle and the SITL Simulator.
SkyCore Drone OS
The on-drone software layer: a ROS2 (Humble) + Docker microservice stack on the Jetson — a core service (MAVROS, rosbridge, video, precision landing), a gamepad/ws_proxy service, an Isaac Visual SLAM service, and mavp2p as the single MAVLink router. See SkyCore Drone OS Overview.

Control & telemetry transport

The binary messaging protocol spoken by the ArduPilot flight controller (FCU) — COMMAND_LONG, SET_MODE, SET_POSITION_TARGET_LOCAL_NED, VISION_POSITION_ESTIMATE, etc. Everything a drone ultimately does is a MAVLink message to the FCU. See MAVLink Routing.
MAVROS
The ROS2 node bridging MAVLink to ROS2 topics and services (/mavros/state, /mavros/cmd/arming, /mavros/global_position/global, …). Gateway commands are expressed as MAVROS service calls / topic publishes. Topic and service names live in src/utils/mavros_topics.py.
mavp2p
The single lightweight MAVLink router on the drone. It bridges the FCU serial link (/dev/ttyACM0 @ 115200) to UDP fan-out: 14550→MAVROS, 14777→gamepad, 14560→RTK. It is the one hub every on-drone service talks MAVLink through. See MAVLink Routing.
rosbridge
A WebSocket server (port 9090) on the drone/SITL that re-exposes ROS2 topics and services as JSON (advertise/subscribe/call_service). This is the Gateway’s command-and-telemetry channel to the vehicle. The Gateway keeps a pooled, auto-reconnecting Connection per drone. See Rosbridge Connection & Reconnect.
Socket.IO telemetry
The Gateway→UI real-time channel. The Dashboard opens a Socket.IO connection with ?token=<jwt>, emits subscribe_telemetry{drone_id, stream_type}, and receives telemetry_data events. Rooms are drone-scoped: drone_{drone_id}_{stream_type}. See Socket.IO Telemetry Streaming and the client side.

Telemetry stream types

Requested via subscribe_telemetry{stream_type}; each maps to MAVROS topics fanned out over rosbridge.
stream_typeSource topicsNotes
gps/mavros/global_position/globalPosition only
logs/rosoutROS log messages
relalt/mavros/global_position/rel_altRelative altitude
system/diagnosticsSystem diagnostics
dashboardGPS + GPS_RAW + rel_alt + /rosout + VFR_HUD + IMU + home + /diagnosticsCombined stream with server-computed yaw
In practice only dashboard delivers data to the current UI — the single-stream rooms (gps/logs/relalt/system) are effectively dead code. The dashboard stream injects a server-computed yaw into the GPS payload (VFR_HUD heading first, else IMU quaternion → compass). Do not “clean up” the room-naming string drone_{id}_dashboard casually — it is a hard contract with the Dashboard.

Network & VPN

Three separate WireGuard planes run on the single VPN host (see the User VPN service and Network & VPN Topology).
PlaneCIDRUDP portInterfaceWho lives here
Core10.69.0.0/1651822wg0Drone hosts / on-prem infra (DOCKER_HOST_IP=<office-docker-host>, SigNoz)
User10.70.0.0/1651823users0Dashboard users
Drone10.71.0.0/1651824drones0Physical drones (Gateway resolves 10.71.x)
jumphost
The single WireGuard EC2 instance (<prod-ingress-ip>) that doubles as the platform’s jumphost and bridge to on-prem SITL. The Gateway can route rosbridge to a drone through it using x-drone-ip / x-drone-port headers (JUMPHOST_IP/JUMPHOST_PORT, default port 9090). It is the architectural keystone — and the primary single point of failure. See VPN IP Authentication & Jumphost Routing.
Cloud Map service discovery
Production runs on ECS Fargate in AWS eu-central-1. Each service registers a stable internal DNS name in the private hosted zone skyhub-prod.internal (e.g. gateway.skyhub-prod.internal, janus.skyhub-prod.internal, redis.skyhub-prod.internal, database.skyhub-prod.internal). Nearly everything — including PostgreSQL and Redis — is a self-hosted container discovered this way; there is no RDS and no ALB. See ECS Fargate Services.

Video

Janus VideoRoom
Janus is the WebRTC SFU (Selective Forwarding Unit). The Gateway’s VideoService creates one VideoRoom per drone (room id == drone.id, H264) and hands the drone the room_id/password/token over the rosbridge topic /video_room_details. The Dashboard subscribes to that room over WebRTC to watch the feed. See Janus WebRTC SFU and Janus Video Rooms.
WHIP
WebRTC-HTTP Ingestion Protocol — the video ingest front door (Node.js server, REST /whip, port 7080). The drone’s GStreamer pipeline whipsinks its H264 stream to /whip/endpoint/<id>; WHIP registers that as a publisher in the matching Janus VideoRoom over Janus’ WebSocket API (:8188). See WHIP Ingest Server and on-drone Video Streaming.
Video is fully out-of-band from telemetry: drone → WHIP → Janus → Dashboard, never through the Gateway’s rosbridge path. ArUco precision-landing overlays are not burned into the video — they travel via Redis {ip}:aruco_tracking and are drawn as a frontend canvas overlay.

Manual control (gamepad)

WS Proxy (ws_proxy)
The cloud FastAPI relay (port 7070) that carries manual gamepad input on a separate, low-latency path from the Gateway’s rosbridge. It resolves the drone IP from PostgreSQL and publishes to Redis. See WebSocket Gamepad Proxy and Vehicle Commands & Gamepad.
redispad
The preferred WS Proxy mode: wss://{ws_proxy}/redispad/{droneId}?access_token=<jwt>. It decouples the client from the drone via Redis pub/sub ({drone_ip}:gamepad_input inbound, {drone_ip}:output / {drone_ip}:aruco_tracking outbound). The alternative /gamepad/{id} mode bridges directly to the drone’s onboard control socket. See Redis Message Bus.
GUIDED velocity control
On the drone, gamepad axes become SET_POSITION_TARGET_LOCAL_NED body-frame velocity setpoints — only when guided control is user-enabled and the vehicle is in GUIDED mode, with a 0.5 s dead-man timeout (zero velocity = hold). This deliberately replaces dangerous RC_CHANNELS_OVERRIDE. See the Safe Control model.

On-drone autonomy

Isaac Visual SLAM
NVIDIA Isaac ROS Visual SLAM running on RealSense stereo + IMU, bridged into ArduPilot’s EKF as VISION_POSITION_ESTIMATE for GPS-denied navigation. See Isaac Visual SLAM & Pose Bridge.
ArUco landing / docking
Two distinct marker systems: e-ArUco precision landing for drones (DICT_7X7_250, multi-level descent) and RealSense-D435 ArUco rover docking (marker id 70). See YOLO Detection, ArUco Landing & Docking.
RTK NTRIP
Real-Time Kinematic GPS corrections: an NTRIP client receives RTCM and injects it into the FCU for centimeter-level positioning. See RTK NTRIP GPS Corrections.
SkyCore modules
The core service loads feature modules (video_stream, aruco_landing, battery) via a ROS2-node ModuleLoader gated by <NAME>_ENABLED env vars. See Core & Gamepad Module Systems.

Domain objects (Gateway data model)

execution
A record of one flight/mission run. Created on ARM (drone callback POST /executions/start), completed on land/disarm, and enriched with uploaded assets (video, photos, .bin flight logs) that feed automated log analysis and reports. See Executions, Log Analysis & Reports.
asset
A file produced by a flight — HLS video, images, or logs — stored in S3 (skyhub-prod-assets) and linked to an execution/vehicle. Uploaded by the drone via presigned URLs. See S3 Assets, HLS Video & Execution Archives.
mission
An ordered set of MAVLink waypoints. MissionPoint rows are stored in MAVLink format and pushed to the drone via the /mavros/mission/push service; push_mission auto-prepends a synthetic TAKEOFF (command 22) if the first point isn’t already one. See Mission & Geofence MAVLink Format and Missions & Geofences API.
geofence
A boundary the vehicle must respect — polygon or circle, inclusion or exclusion. Distinct from a mission: geofences are pushed via the dedicated /mavros/geofence/push service and can be synced/cleared independently. Enabled geofences can be batch-synced to the FCU.
The MAVLink command codes you will see in mission/geofence data:
CommandMeaning
16Waypoint (NAV_WAYPOINT)
21Land
22Takeoff
20Return-to-launch (RTL)
178Change speed
The older CLAUDE.md description of missions auto-generating a reversed return path + RTL + speed points is stale. The backend uploads the stored waypoints as-is, plus the synthetic TAKEOFF prepend — nothing more.

The three auth models

Three distinct authentication schemes coexist across the stack. Knowing which one an endpoint uses tells you how to call it and how to secure it. See HTTP API Overview & Auth Models and Authentication & Security Model.
ModelWhoHowWhere
JWT BearerDashboard usersHS256 access token (10 min) + refresh (12 hr), Authorization: Bearer; Socket.IO reads it from ?token=Almost all /api/v1/* UI routes
VPN source-IP trustDrone / gamepad callbackscheck_vpn_ip decorator trusts a source IP starting with 10.71. (or an X-Drone-IP of SKYHUB_SITL_*) — no JWTsrc/middleware/drone_vpn.py; activation pull, executions, asset uploads
Token / signatureBootstrap, video, Stripe10-digit drone-activation header token, per-room video Bearer token, Stripe-Signature webhook verificationDrone activation, POST /video_room, POST /billing/webhook
The JWT lifecycle (login/refresh/logout, the in-memory BLOCKLIST, the level claim) is covered in Authentication & JWT Lifecycle.

Overloaded names — disambiguate carefully

(1) The cloud service skyhub_ws_proxy — a standalone FastAPI relay (port 7070) that carries gamepad input from the Dashboard, described above. (2) The on-drone ws_proxy docker-compose service — this is the SkyCore gamepad service (FastAPI WebSocket on 5001), the thing that actually turns operator input into MAVLink. They are named similarly and sit at opposite ends of the same control path. See Ecosystem WS Proxy vs Drone-OS Services.
SkyCore’s core service uses a ROS2-node ModuleLoader (env <NAME>_ENABLED flags). The gamepad and isaac-slam services each use their own plain loaders / DI containers. They share a name and an idea but are not the same code — do not merge them blindly. See Core & Gamepad Module Systems.
A drone’s type is physical or sitl (transport/lifecycle). Its vehicle_type is the airframe/rover class (copter/rover). Both are set at creation (POST /api/v1/drone). Don’t conflate them.
WHIP’s REST ingest is on 7080; Janus’ WebSocket API (what WHIP and the Dashboard drive) is on 8188. They are separate services on separate ports in the same video pipeline.

Where to go next

Local Dev Quickstart

Run the Gateway and a SITL drone on your machine.

Repository Map

Which repo owns what, and who maintains it.

Cross-System Flows

Follow a command and a telemetry frame end-to-end.