Skip to content

BLE Scanning & Positioning ​

The mobile app uses Bluetooth Low Energy (BLE) to detect nearby beacons and estimate the user's indoor position.

BLE Scanner ​

File: ariadne/lib/services/ble_scanner.dart

The scanner wraps flutter_blue_plus to detect WTK beacons and collect RSSI (signal strength) readings.

Beacon Filtering ​

  • Only processes beacons with the WTK_ name prefix
  • Filters to a set of "active" beacons registered via setActiveBeacons(unames)
  • Ignores packets with serviceUuids (e.g. battery service advertisements)

RSSI Buffer ​

Maintains a circular buffer of the last 50 RSSI readings per beacon. This provides:

  • getAverageRssi(uname) — Average RSSI for smooth positioning
  • getDetectedBeaconsSorted() — All detected beacons ordered by signal strength (strongest first)

Scanning ​

  • startScan() — Starts continuous BLE scanning with a 4-second timeout
  • stopScan() — Stops scanning
  • onUpdate — Optional callback invoked when scan results change

Positioning Engine ​

File: ariadne/lib/core/positioning.dart

Converts BLE RSSI readings into a 2D position estimate on the floor map.

Setup ​

loadBeacons(floors) processes the navigation bundle:

  • Registers all non-static beacons by their uname
  • Sets the scanner's active beacon filter
  • Builds an internal map of beacon positions (x, y coordinates on the floor map)

Position Calculation ​

calculatePosition({isNavigating}) returns a PositionEstimate based on the number of detected beacons:

Beacons DetectedMethodConfidenceAlgorithm
1singleBeacon0.3Snap to beacon position
2midpoint0.5Weighted midpoint (navigating) or strongest beacon (idle)
3+trilateration0.8Cramer's rule trilateration

RSSI to Distance ​

The path-loss model converts RSSI to estimated distance:

distance = 10^((txPower - rssi) / (10 * n)) * 50

Where:

  • txPower = -59 dBm (calibrated transmit power)
  • n = 2.0 (path-loss exponent)
  • * 50 scales to pixel coordinates on the map

Trilateration ​

When 3 or more beacons are detected, the engine uses Cramer's rule to solve the trilateration equations:

  1. Takes the 3 strongest beacons
  2. Converts RSSI to distances
  3. Solves the system of circle intersection equations
  4. Returns the estimated (x, y) position

Static Beacons ​

Beacons with isStatic == 1 are excluded from positioning calculations. Static beacons are used as fixed reference points (POIs) rather than for positioning.

Position Update Cycle ​

During navigation, the position updates every 2 seconds:

  1. BleScanner provides latest RSSI readings
  2. PositioningEngine.calculatePosition() estimates position
  3. If navigating, position is projected onto the nearest graph edge via NavigationGraph.projectOntoNearestEdge()
  4. NavigationGame.updatePlayerPosition() moves the player arrow
  5. Camera optionally centers on the new position