MAVLink Edge Adapter — Deployment Guide

The MAVLink Edge Adapter connects PX4 and ArduPilot vehicles to the Zequent platform. It's built on the Python Edge SDK and MAVSDK-Python, exposing the standard EdgeAdapterService gRPC interface and translating incoming platform commands into MAVSDK calls against the vehicle identified by the request's serial number.


Prerequisites

  • Access to the Zequent container registry (ghcr.io/zequent)
  • A reachable MAVLink endpoint for your vehicle (serial, UDP, or TCP — anything MAVSDK supports)
  • Running Zequent platform services: Connector Service, Live Data Service

Implemented Commands

CommandMaps to
TakeOffset_takeoff_altitude → arm → takeoff
GoToaction.goto_location(lat, lon, alt, yaw=0)
ReturnToHomeaction.return_to_launch (with optional RTL altitude)
RebootAssetaction.reboot
EnterManualControlmanual_control.start_position_control
ExitManualControlaction.hold
ManualControlInputstreams stick input → manual_control.set_manual_control_input
SendCustomCommand("mission.waypoint.execute")uploads the inline waypoint list as a MAVSDK mission (mission.upload_mission), arms, then mission.start_mission
SendCustomCommand("mission.pause") / ("mission.resume")mission.pause_mission / mission.start_mission
StopTaskmission.pause_mission — the platform calls it to cancel a running command
RegisterAssetregisters with the Connector Service and eagerly opens the MAVSDK connection
DeRegisterAssetreleases the MAVSDK connection

Every other command defaults to "not supported" and is reported as such through GetCapabilities — including PrepareTask/StartTask, which the 2.0 platform never calls. Waypoint routes arrive as the mission.waypoint.execute command, the same way as on the simulator and edge-dji, and the adapter reports their progress with command execution events. See Waypoint Missions for the full picture across adapters.


Environment Variables

All of these except MAVLINK_CONNECTION/MAVLINK_PRECONNECT_SN come from the shared Python Edge SDK's EdgeAdapterConfig.from_env() — this adapter passes no overrides, so these are that class's own real defaults, confirmed in edge_sdk/config.py:

VariableDefaultPurpose
GRPC_HOST0.0.0.0gRPC server bind host
GRPC_PORT50051gRPC server bind port — this is what the platform reaches the adapter on
ZQNT_CLAIM_CODEunsetA one-time pairing code from the console's Pair device dialog. Used only when the platform does not already know a serial number this adapter is bringing up: the code decides which organization the resulting asset belongs to, and that cannot be changed afterwards. Leave it unset once the assets exist — an already-paired device does not need it, and the code is single-use. Without it, an unknown serial simply has no asset, and the adapter creates nothing.
ZQNT_EDGE_TOKENunsetThe adapter's edge credential, sent on every call to the platform. Issued in the Admin Console under Manage → Access & Integrations → Credentials (kind Edge adapter); without it the platform refuses the calls
ZQNT_PLATFORM_PUBLIC_KEYunsetThe platform's public key (alias SERVICE_AUTH_PUBLIC_KEY). The adapter refuses every command the platform did not sign with it; without it, every command is refused
ZQNT_EDGE_AUTH_DISABLEDfalsetrue accepts commands from anyone who can reach the port — local stacks only
CONNECTOR_HOSTlocalhostConnector Service host
CONNECTOR_PORT50053Connector Service port — not the real Connector Service platform port (8010, see the image table); set it explicitly, don't rely on this default
TELEMETRY_HOSTlocalhostLive Data Service host — telemetry forwarding is always on, there's no way to disable it via this variable
TELEMETRY_PORT50052Live Data Service port — likewise not the real platform port (8003); set it explicitly
ADAPTER_SNmavlink-adapterSerial number used on outgoing telemetry frames
EDGE_ENDPOINTunsetEndpoint this adapter advertises via optional Redis service-discovery registration
ASSET_TYPEunsetFull proto-style name, not the bare enum member — ASSET_TYPE_AIRCRAFT, not AIRCRAFT. A bare value fails proto_enum_lookup and silently skips registration (logged as a warning only)
ASSET_VENDORunsetSame requirement — ASSET_VENDOR_MAVLINK, not MAVLINK
REDIS_URLredis://localhost:6379Two independent uses: the SDK's own service-discovery registration (only when EDGE_ENDPOINT/ASSET_TYPE/ASSET_VENDOR are all set), and this adapter's own asset online/offline caching (used whenever the variable is set, regardless of EDGE_ENDPOINT)
LOG_LEVELINFODEBUG / INFO / WARNING / ERROR
LOG_FORMATjsonjson or text

MISSION_AUTONOMY_HOST/PORT are read by the shared SDK config but have no effect here — this adapter doesn't talk to the Mission Autonomy Service directly (see Edge SDK — Mission Autonomy).

The vehicle's MAVLink connection string (e.g. udp://:14540, serial:///dev/ttyUSB0:57600) is resolved per-asset at registration time, not from a single global environment variable — see the adapter's own README for the exact resolution order if you need to override it.


Docker Compose

services:
  edge-mavlink:
    image: ghcr.io/zequent/zqnt-adapter-mavlink:2.0.0
    env_file:
      - .env
    ports:
      - "9001:50051"
    restart: unless-stopped

.env:

GRPC_PORT=50051
CONNECTOR_HOST=connector-service
CONNECTOR_PORT=8010
TELEMETRY_HOST=live-data-service
TELEMETRY_PORT=8003
ADAPTER_SN=mavlink-01
ASSET_TYPE=ASSET_TYPE_AIRCRAFT
ASSET_VENDOR=ASSET_VENDOR_MAVLINK

Kubernetes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: edge-mavlink
spec:
  replicas: 1
  selector:
    matchLabels:
      app: edge-mavlink
  template:
    metadata:
      labels:
        app: edge-mavlink
    spec:
      containers:
        - name: edge-mavlink
          image: ghcr.io/zequent/zqnt-adapter-mavlink:2.0.0
          ports:
            - containerPort: 50051
          env:
            - name: CONNECTOR_HOST
              value: "connector-service"
            - name: CONNECTOR_PORT
              value: "8010"
            - name: TELEMETRY_HOST
              value: "live-data-service"
            - name: TELEMETRY_PORT
              value: "8003"
            - name: ADAPTER_SN
              value: "mavlink-01"
            - name: ASSET_TYPE
              value: "ASSET_TYPE_AIRCRAFT"
            - name: ASSET_VENDOR
              value: "ASSET_VENDOR_MAVLINK"
---
apiVersion: v1
kind: Service
metadata:
  name: edge-mavlink
spec:
  selector:
    app: edge-mavlink
  ports:
    - port: 50051
      targetPort: 50051

Testing against a simulator

The adapter's own test setup uses headless PX4 SITL over UDP — useful for verifying your deployment before connecting real hardware:

docker run --rm -it --name px4-sim --net=host \
  jonasvautherin/px4-gazebo-headless:1.14.0 <HOST_IP>

Replace <HOST_IP> with the IP address of the host running the adapter — PX4 streams MAVLink telemetry back to that address. The adapter falls back to udp://:14540 when no connection string is registered for the asset, which matches this simulator's default.


Port

The adapter listens on 50051 for incoming gRPC commands from the platform.

Was this page helpful?