Appearance
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: mobile/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 positioninggetDetectedBeaconsSorted()— All detected beacons ordered by signal strength (strongest first)
Scanning
startScan()— Starts continuous BLE scanning with a 4-second timeoutstopScan()— Stops scanningonUpdate— Optional callback invoked when scan results change
Positioning Engine
File: mobile/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 Detected | Method | Confidence | Algorithm |
|---|---|---|---|
| 1 | singleBeacon | 0.3 | Snap to beacon position |
| 2 | midpoint | 0.5 | Weighted midpoint (navigating) or strongest beacon (idle) |
| 3+ | trilateration | 0.8 | Cramer's rule trilateration |
RSSI to Distance
The path-loss model converts RSSI to estimated distance:
distance = 10^((txPower - rssi) / (10 * n)) * 50Where:
txPower= -59 dBm (calibrated transmit power)n= 2.0 (path-loss exponent)* 50scales 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:
- Takes the 3 strongest beacons
- Converts RSSI to distances
- Solves the system of circle intersection equations
- 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:
BleScannerprovides latest RSSI readingsPositioningEngine.calculatePosition()estimates position- If navigating, position is projected onto the nearest graph edge via
NavigationGraph.projectOntoNearestEdge() NavigationGame.updatePlayerPosition()moves the player arrow- Camera optionally centers on the new position