by Chong Hong Lok & Vitti Ng
Navigating inside a building is challenging, as ceilings and other obstructions in the building are having major impact on ability of GPS to ascertain a ground device’s position successfully.
Even in situations where GPS signals are able to penetrate a building and provide a strong connection with a ground device, there is another significant factor to consider when using GPS indoors, which is the overall accuracy that GPS is able to achieve. GPS in ideal situations is routinely able to pinpoint a ground device’s position to an accuracy of between 5 and 10 meters.
In indoor environments, this level of potential discrepancy between a user’s reported position and their actual position presents enormous issues. This is due to the much smaller dimensions of the average indoor space versus the average outdoor environment. A user being told to turn left immediately when they’re actually 10 meters further down a corridor than their device thinks they could be led into a room that is multiple rooms away from the one they intended to enter.
Stable and accurate indoor navigation and positioning can be achieved by using technologies similar to GPS. Bluetooth® Low Energy, Wi-Fi, and UWB are the most effective ones.
Bluetooth® Low Energy (BLE)
One of the most convenient tools for tracking objects indoors is the Bluetooth Low Energy technology. To set up indoor positioning Bluetooth® Low Energy beacons should be installed inside the facility. The beacons then will emit Bluetooth® LE signals at a predefined frequency.
Wi-Fi
Wi-Fi technology is sometimes used as an alternative to GPS for indoor positioning. The reason for its popularity is its widespread occurrence. Access points can be found in any building, which allows leveraging of existing infrastructure.
The active range of access points is up to 150 m and positioning is carried out using smartphones.
Ultra-wideband (UWB)
The UWB technology has a great potential for indoor positioning. It is the most accurate among the existing systems. Achievable accuracy is up to 20 cm. Calculations are performed with the help of ultra-wideband signals that are sent at a frequency of up to several GHz. The reception of these signals doesn’t require direct visibility and can be performed by a limited number of components.
Autonomy and insignificant size the Bluetooth® LE technology is supported by most modern smartphones. It is the most economical one among similar systems on the market and provides high accuracy localization inside buildings.
Highlight of advantages:
We chose the indoor map making solution from Mappedin, and Teltonika Eye Beacon to build an indoor positioning system.
Highlight for Mappedin:
Highlight for Eye Beacon:
On software and development side, we are using Flutter, known for its cross-platform capabilities and ease of use. With mappedin Web SDK, we are provide users with an interactive and engaging map experience and reducing the cost of maintaining it, as compared to native iOS and Android SDK.
Here’s a simplified diagram illustrating the process flow for the IPS solution:
import {
getVenue,
showVenue,
TGetVenueOptions,
STATE,
E_SDK_EVENT,
CAMERA_EASING_MODE
} from "@mappedin/mappedin-js";
import { MapView } from "@mappedin/mappedin-js";
import { Mappedin } from "@mappedin/mappedin-js";
import { Marker } from "@mappedin/mappedin-js";
import { TConnectionTemplateFn } from "@mappedin/mappedin-js";
import "@mappedin/mappedin-js/lib/mappedin.css";
import "./styles.css";
// See Trial API key Terms and Conditions
// https://developer.mappedin.com/guides/api-keys
const options: TGetVenueOptions = {
venue: "{venue}",
clientId: "{clientId}",
clientSecret: "{clientSecret}"
};
var mapView: MapView;
var venue: Mappedin;
async function init() {
venue = await getVenue(options);
mapView = await showVenue(document.getElementById("app")!, venue);
//Display Floating Labels on all locations.
mapView.FloatingLabels.labelAllLocations();
mapView.setState(STATE.FOLLOW);
}
init();
window.flutter_inappwebview.callHandler
function.async function getLocationList() {
const sortedCategories = Mappedin.categories;
let sortedLocationList = [];
sortedCategories.forEach((category) => {
let sortTags = category.locations;
let mappedValue = sortTags.map(location => {
return {id: location.id, name: location.name}
});
sortedLocationList.push(...mappedValue);
});
let tempValue = sortedLocationList;
window.flutter_inappwebview.callHandler('locationListRetrievedHandler', ...tempValue);
}
inFigure 5: Web (Angular) implemented with Mapped In Web
flutterReactiveBle
.scanForDevices(withServices: [], scanMode: ScanMode.lowLatency).listen((DiscoveredDevice device) {
// TODO: To add on action when discovered (sort beacons, etc.)
});
Widget build(BuildContext context) {
...
InAppWebView(
initialUrlRequest:
URLRequest(url: WebUri.uri(Uri.parse('Your hosted web url'))),
initialOptions: groupOptions,
onWebViewCreated: webViewCreated,
),
}
...
void webViewCreated(InAppWebViewController controller) {
controller.addJavaScriptHandler(
handlerName: 'locationListRetrievedHandler',
callback: (args) {
args.forEach((element) => print(element.toString());
});
}
Create the functions to allow user use navigation feature provided in Mappedin SDK, where user can select start and stop location in previous step.
Receive start and end location from mobile app, submit to Mappedin SDK to create interactive navigation path with prefer routes.
const markerAnimateDuration: number = 500;
window.addEventListener("startNavigation", startNavigation);
async function startNavigation(e) {
var startPoint = e.detail.start;
var endPoint = e.detail.end;
var myLatitude = e.detail.latitude;
var myLongitude = e.detail.longitude;
var accessible = e.detail.accessible;
const start = venue.locations.find((l) => l.name === startPoint)!;
const destination = venue.locations.find((l) => l.name === endPoint)!;
//Get directions between the start and end locations.
const directions = start.directionsTo(destination, { accessible: accessible });
mapView.Journey.draw(directions);
mapView.Camera.focusOn({ polygons: start.polygons });
}
Stop the ongoing journey and clear the path.
async function stopNavigation() {
mapView.Journey.clear();
}
inappwebview.callAsyncJavaScript()
.The functions will be called based on user action in the mobile app.
void startNavigation(String startPoint, String endPoint) {
controller?.callAsyncJavaScript(functionBody: """
const event = new CustomEvent('startNavigation', {
detail: {
start: "${startPoint.name}",
end: "${endPoint.name}"
}
});
window.dispatchEvent(event);
""");
}
void stopNavigation() {
controller?.callAsyncJavaScript(functionBody: """
const event = new CustomEvent('stopNavigation', {});
window.dispatchEvent(event);
""");
}
changePosition()
method to listen to latest position updates from mobile app.The function change the position of user marker in Mappedin interactive map based on latitude, longitude, floorID.
function changePosition(e) {
var latitude = e.detail.latitude;
var longitude = e.detail.longitude;
const coordinate = mapView.currentMap.createCoordinate(latitude, longitude);
mapView.Markers.animate(marker, coordinate.nearestNode,
{
duration: markerAnimateDuration,
easing: CAMERA_EASING_MODE.LINEAR
});
}
void _updateDetectedBeaconList(BeaconModel beaconModel) async {
_appendBeacon(_detectedBeaconListMap, beaconModel);
_cleanInvalidBeaconList(_detectedBeaconListMap);
}
Future<BeaconModel?> epitaphCalculationProcessing(Tracker tracker, List<BeaconModel> nearbyBeacons) async {
///radius of earth in meters
const R = earthRadius * 1000;
final beaconsForIpsFormula = nearbyBeacons.map((value) {
var latitude = radians(value.latlng?.latitude ?? 0);
var longitude = radians(value.latlng?.longitude ?? 0);
var x = R * cos(latitude) * cos(longitude);
var y = R * cos(latitude) * sin(longitude);
var z = R * sin(latitude);
final beacon = MockBeacon(value.name ?? '', value.name ?? '', Point(x, y, z));
final rssiValue = value.rssiValue?.toInt() ?? rssiDefault;
beacon.rssiUpdate((rssiValue) >= 0 ? rssiDefault : rssiValue);
return beacon;
}).toList();
final calculatedPosition = tracker.calculatePosition(beaconsForIpsFormula);
return calculatedPosition
}
Future<bool> shouldUpdatePosition(List<BeaconModel> nearbyBeacons) {
if ((lastDetectedBeaconsGroup?.length ?? 0) == nearbyBeacons.length) {
bool sameGroupOfBeacons = true;
///sort the list according to name for easier comparison
lastDetectedBeaconsGroup?.sort((a, b) => (a.name ?? '').compareTo(b.name ?? ''));
nearbyBeacons.sort((a, b) => (a.name ?? '').compareTo(b.name ?? ''));
///check if it is the same group of beacons detected
lastDetectedBeaconsGroup?.forEachIndexed((index, element) {
if (nearbyBeacons[index].name != element.name) {
sameGroupOfBeacons = false;
}
});
int rssiPowerChangedCount = 0;
if (sameGroupOfBeacons) {
nearbyBeacons.forEach((nearby) {
int lastDetectedRssi = lastDetectedBeaconsGroup
?.firstWhere((lastDetected) => nearby.name == lastDetected.name)
.rssiValue
?.toInt() ?? 0;
var rssiDiff = (lastDetectedRssi.abs() - (nearby.rssiValue ?? 0).abs()).abs();
if (lastDetectedRssi < 0 && rssiDiff > rssiPowerSpikedBuffer) {
rssiPowerChangedCount++;
}
});
}
lastDetectedBeaconsGroup = nearbyBeacons;
return Future.value(!sameGroupOfBeacons || rssiPowerChangedCount > rssiPowerChangingCountBaseline);
}
lastDetectedBeaconsGroup = nearbyBeacons;
return Future.value(true);
}
Combining Flutter’s versatility with InAppWebView allows us to effortlessly embed Mappedin Web into the app. The provided code snippet serves as a starting point for integrating Mappedin Web, which can be further extend to meet the app’s requirements.
The code snippet above shows how to include the pre-built Mappedin Web into Flutter app. But what if you desire a more custom solution? The Mappedin Web SDK could also be used in a more customisable way. A more functions web app using the Mappedin Web SDK that satisfies the use case of the problems.
Developing this IPS solution involved overcoming several challenges:
Although Mappedin does support some level of customisation, more effort and knowledge are required to achieve the desired presentation if the solutions are designed to provide many more bespoke functions apart from what is provided.
With the use of TOA (time-of-arrival) as estimation method, receiving signal strength from BLE beacons (rssi) play vital roles. A very minor different of signal strength can impact hard to the estimated position.
Due to the nature of signal travel, RSSI value are greatly impact and interfered by the obstructions around, such as ceiling, wall, doors, glasses and basically anything within the buildings. Multiple trial and measurement are being tested to get the best stable RSSI value, amongst them are cache-ing, detection queue, trilateration to multilateration.
Obstructions in venue is interfering the travelling of signal to mobile devices in various level. Highly impacted obstructions are like:
Crowded Area:
Building Structure:
Figure 6: Waves reflecting and passing by Elexana
The above contents has documented the core information of Indoor Positioning System (IPS) with the leverage of Bluetooth® Low Energy (BLE), Mappedin SDK and combining with versatile Flutter mobile development.
With the combinations, we are able to create an full-flex of IPS solutions based on different use-cases and problems that the market needs. With all the advance and thorough algorithm and techn stacks implemented, we have achieved high level of satisfaction on accuracy and consistency solutions. This solutions are able to provide a highly reliable and adaptability to various problems and use-cases.