A basic indoor & outdoor positioning example #
Situm provides indoor&outdoor positioning, with the ability to detect automatically the building where the user is and also the floor.
Before you dive in, start by reading how Situm estimates the location and orientation of the phone. Then, eexecute the Basic Java Android or Basic Swift iOS examples and copy & paste the following code in your “MainActivity” or “ViewController”.
public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); //First, declare a LocationListener. This will receive the computed geolocations, status changes and errors private LocationListener locationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { Log.i(TAG, "onLocationChanged() called with: location = [" + location + "]"); } @Override public void onStatusChanged(@NonNull LocationStatus status) { Log.i(TAG, "onStatusChanged() called with: status = [" + status + "]"); } @Override public void onError(@NonNull Error error) { Log.e(TAG, "onError() called with: error = [" + error + "]"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //Initialize Situm SDK SitumSdk.init(this); //Ask for runtime permissions (ACCESS_FINE_LOCATION) // Warning! This is a naive way to ask for permissions for the example's simplicity // Check https://developer.android.com/training/permissions/requesting to know how // to ask for permissions ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},0); //Build the LocationRequest with default parameters LocationRequest locationRequest = new LocationRequest.Builder().build(); //Start positioning! -> Geolocations will be passed to the locationListener callbacks SitumSdk.locationManager().requestLocationUpdates(locationRequest, locationListener); } }
class ViewController: UIViewController, SITLocationDelegate { var sitLocManager: SITLocationManager = SITLocationManager.sharedInstance() ... //This method is called when the user clicks the "Initialization Button" @IBAction func initializeButton(_ sender: UIButton) { //This function has been defined in the "Grant app permissions" Section requestLocationAuth() //Set the delegate so the update functions receive the messages sitLocManager.delegate = self } //This method is called when the user clicks the "StartButton" @IBAction func startRequestButton(_ sender: UIButton) { //Create the request to activate positioning let request: SITLocationRequest = SITLocationRequest() //Start positioning by requesting location updates sharedLocManager.requestLocationUpdates(request) } ... // Delegate functions to receive notifications func locationManager(_ locationManager: SITLocationInterface, didUpdate location: SITLocation) { print("*POSITION UPDATED*\nPosition was updated to:\n Latitude: \(location.position.coordinate().latitude)\n Longitude: (location.position.coordinate().longitude).") } func locationManager(_ locationManager: SITLocationInterface, didFailWithError error: Error?) { print("*POSITIO UPDATED*\nThere was an error with the request: \(error?.localizedDescription ?? "")") } func locationManager(_ locationManager: SITLocationInterface, didUpdate state: SITLocationState) { print("*POSITION UPDATED*\nState was updated to \(state.rawValue)") }
As you can see, a few entities work together in order to compute the smartphone geolocation.
Entity | Explanation | Documentation |
---|---|---|
LocationManager | Handles all positioning tasks. Implements methods “requestLocationUpdates” and “removeUpdates”, which start & stop positioning. | Android iOS |
LocationRequest | Allows to configure the positioning parameters: Building vs Global, whether or not to use WiFi or BLE, etc. | Android iOS |
LocationListener | Interface allows you to receive and respond to all the generated geolocations, as well as to other useful information (status and errors). | Android iOS |
Running the code: initialization #
If you build & execute the previous code, your application will produce a log similar to the following one (for the Android example, iOS will be similar).
2021-02-06 00:49:14.441 2592-2592/com.example.androidtestapp I/MainActivity: onStatusChanged() called with: status = [CALCULATING] 2021-02-06 00:49:15.535 2592-2592/com.example.androidtestapp I/MainActivity: onStatusChanged() called with: status = [STARTING]
At first, the onStatusChanged method is called to inform that the Situm SDK is in status “CALCULATING”. Then, it is called again to inform that is in status “STARTING”.
#
After a few moments, the positioning will start producing a few first outdoor geolocations. If you open the RealTime Panel, you should see your geolocation on the world! Then, behind the scenes, Situm will try to detect if you are within a building that has been configured with Situm technology. If you are in one and open the RealTime Panel, after a few seconds you will see your indoor geolocation within the building.
If you inspect the log lines, you will see very interesting information.
2021-02-06 00:49:16.567 2592-2592/com.example.androidtestapp I/MainActivity: onLocationChanged() called with: location = [Location{provider='SITUM_PROVIDER', deviceId=356655406358, timestamp=1612568956544, position=Point{buildingIdentifier='-1', floorIdentifier='-1', cartesianCoordinate=CartesianCoordinate{x=0,00, y=0,00}, coordinate=Coordinate{latitude=43,356441, longitude=-8,413430}, isOutdoor=true}, quality=HIGH, accuracy=20.287, cartesianBearing=Angle{radians=0.00, degrees=0.00}, bearing=Angle{radians=0.51, degrees=29.44}, bearingQuality=HIGH, customFields={}}]
2021-02-06 01:14:47.319 2592-2592/com.example.androidtestapp I/MainActivity: onLocationChanged() called with: location = [Location{provider='SITUM_PROVIDER', deviceId=356655406358, timestamp=1612570486718, position=Point{buildingIdentifier='6541', floorIdentifier='13483', cartesianCoordinate=CartesianCoordinate{x=17,50, y=10,20}, coordinate=Coordinate{latitude=43,356433, longitude=-8,413040}, isOutdoor=false}, quality=HIGH, accuracy=0.70591295, cartesianBearing=Angle{radians=1.66, degrees=95.19}, bearing=Angle{radians=6.19, degrees=354.81}, bearingQuality=HIGH, customFields={}}]
Location data: detailed overview #
The location data received in the previous example has the following fields:
Field | Description |
---|---|
provider | Always set to SITUM_PROVIDER. Internal parameter. |
deviceId | The identifier of the device that is running the application. |
timestamp | Current Unix Timestamp, in milliseconds since Jan 01 1970 (UTC). |
position.buildingIdentifier | Identifier of the venue where the user is. If “-1”, the user is outdoors (outdoor location). |
position.floorIdentifier | Identifier of the floor where the user is. If “-1”, the user is outdoors (outdoor location). |
position.cartesianCoordinate | Cartesian (XY) location within a building’s floorplan. If we’re dealing with an outdoor location, it will be {x=0.00, y=0.00} (default value) |
position.coordinate | Latitude and longitude in WSG 84 format. If location is an indoor location, this is just a conversion from the cartesianCoordinate to lat/lng. |
position.isOutdoor | This indicates that if are dealing with an outdoor location. |
quality | Indicates whether Situm has a good (HIGH) or bad (LOW) estimation of the position. Usually, it will be LOW when it starts, and it will converge to HIGH as the user walks. It only applies to indoor locations, outdoor locations will always be set to HIGH. |
accuracy | Estimated accuracy of the location, in meters. It can be thought as the approximate error radius around the estimated location that probably encloses the location of the user. It will be high at first and decrease as the user walks. |
cartesianBearing | Cartesian orientation with respect to the bulding’s axis. Only applies to indoor locations. For historical compatibility, in Situm SDK the angles between North and East go between 360º and 450º. |
bearing | Orientation with respect to the Earth North: 0 degrees is North, 90 degrees is East, etc. For historical compatibility, in Situm SDK the angles between North and East go between 360º and 450º. |
bearingQuality | Indicates whether Situm has a good (HIGH) or bad (LOW) estimation of the orientation. Usually, it will be LOW when it starts, and it will converge to HIGH as the user walks. It only applies to indoor locations, outdoor locations will always be set to HIGH. |
customFields | JSON dictionary that may contain key-value tuples. Usually empty. |
Geolocation modes #
Situm is able to provide Indoor Positions within any building where Situm technology has been configured. Situm provides three methods (mutually exclusive) for computing this indoor geolocation: Situm Indoor, Calibrated Indoor GPS, Uncalibrated Indoor GPS.
Indoor geolocation mode | Description | How to use it |
---|---|---|
Situm Indoor | Determines the user’s position in the calibrated areas of a building by matching WiFi/BLE signals received with the calibrations. More info. | Set to false LocationRequest.Builder().useGps (Android) or SITLocationRequest.useGPS (iOS) |
Calibrated Indoor GPS | Mixes the WiFi/BLE + the GPS signals within all the calibrated areas. Recommended in buildings with indoor/outdoor areas with good GPS coverage. More info. | Set to true LocationRequest.Builder().useGps (Android) or SITLocationRequest.useGPS (iOS) |
Uncalibrated Indoor GPS | Works just as the Calibrated GPS Indoor mode, but can also use the GPS signal within outdoor uncalibrated areas of your building. This can help you avoid the effort of calibrating big outdoor areas while still having the benefits of using the GPS signal in them. | Set to true LocationRequest.Builder().useGps (Android) or SITLocationRequest.useGPS (iOS). Create geofences with a specific configuration in all the outdoor areas where you want Situm to use the GPS information. |
In any of these methods, there may be times when Situm will not be able to provide a valid Indoor Location, usually because the signals do not match with what is expected in a given building. In this case, Situm will inform that the user is not in any known building.
You may try each of these modes using our Situm Mapping Tool application: this will help you get a better understanding on how they work and what you can expect from them.
Building vs Global Mode #
Situm SDK allows you to choose between two positioning modes: Building and Global Mode.
Mode | Building detector | Description | How to use it |
---|---|---|---|
Building | None | Locates the user within a specific building. If user is in the building, generates Indoor Positions. Otherwise, informs that the user is not in the building. | Set the LocationRequest.Builder().buildingIdentifier (Android) or SITLocationRequest.buildingID (iOS). |
Global | Detects automatically the building where the user is and provides his Indoor Position. | ||
GPS based | Default detector but unrecommended. User will be geolocated in the nearest building from those within a certain maximum distance. More info. | Set the OutdoorLocationOptions.Builder() .buildingDetector to GPS_PROXIMITY (Android) or SITOutdoorLocationOptions.buildingDetector to kSITGpsProximity (iOS). | |
WiFi/BLE based | Recommended. The user user will be geolocated inside the building whose calibration signals match better with those perceived by the user smartphone. More info. For fast building transitions, enable the “Always on mode” (Android only). More info. | In Android, set the OutdoorLocationOptions.Builder() .buildingDetector to WIFI, BLE or WIFI_AND_BLE, depending on the sensor you want to use to match the signals. In iOS, set the SITOutdoorLocationOptions.buildingDetector to kSITBLE. Always on Mode (Android only). Set the OutdoorLocationOptions.Builder().scansBasedDetectorAlwaysOn method to true. | |
GPS + WiFi/BLE based | Only available when using the Uncalibrated GPS Indoor positioning mode. User will be geolocated inside the building where: 1) calibration signals match better with those perceived by the user smartphone, and/or 2) GPS signal falls within one of the GPS-configured geofences of the building. | In Android, set the OutdoorLocationOptions.Builder() .buildingDetector to WIFI, BLE or WIFI_AND_BLE, depending on the sensor you want to use to match the signals. Also, set to true LocationRequest.Builder().useGps and the OutdoorLocationOptions.Builder.useGeofencesInBuildingSelector. In iOS, set the SITOutdoorLocationOptions.buildingDetector to kSITBLE and set to true SITLocationRequest.useGPS and the SITOutdoorLocationOptions.useGeofencesInBuildingSelector. This mode also requires to configure special geofences in the building. This mode supports the Always on Mode, like the WiFi/BLE mode (Android only). Set the OutdoorLocationOptions.Builder().scansBasedDetectorAlwaysOn method to true. |
Note that the OutdoorLocationOptions / SITOutdoorLocationOptions are passed to the LocationRequest.Builder.outdoorLocationOptions (Android) or SITLocationRequest.outdoorLocationOptions (iOS).
Indoor Positioning Sensor Management #
As explained in this article, in order to compute the most accurate geolocation, Situm can use many of the sensor information that modern smartphones provide. Situm SDK allows you to activate/deactivate most of these sensors when computing indoor geolocations. This can come in handy to activate special features by enable a certain sensor, saving battery by disabling another, etc.
Sensor | Sub-Mode | Description | How to use it |
---|---|---|---|
WiFi (Android only) | Scan WiFi for indoor positioning and building detection. | Enabled by default. Controlled by the LocationRequest.Builder().useWifi (Android). Not available in iOS | |
Ignore WiFi throttling (Android only) | In Android 10, you may ignore the WiFi Throttling limitation and scan WiFi at full speed. Also, in Android 11 with SitumSDK v2.69.1 and inferior. Android 5,6,7,8 are not affected by WiFi Throttling. Android 9 doesn’t allow to disable WiFi Throttling. Android 11 + Situm SDK v>2.69.1 scans at full speed if WiFi Throttling is disabled. So, this parameter has no effect on them. | Set to true LocationRequets.Builder().ignoreWiFiThrottling to scan at full speed. False by default (assumes WiFi Throttling is enabled in the device). Make sure you have turned off WiFi Throttling in your device before. | |
BLE | Scan BLE for indoor positioning and building detection. | Enabled by default. Controlled by the LocationRequest.Builder().useBLE (Android). Not available in iOS (always scans BLE). | |
Beacon filters | By default, Situm only detects beacons with Situm’s UUID (73697475-6D73-6974-756D-736974756D15) and Kontakt’s UUID f7826da6-4fa2-4e98-8024-bc5b71e0893e). Nevertheless, you may use any other iBeacon with a different UUID. | Recommended way is through Situm Dashboard: see Section “How do I configure my beacons?” of this article. Alternatively, you may hardcode other beacon UUIDs in your app, using the method LocationRequest.Builder().addBeaconFilter or LocationRequest.Builder().addBeaconFilters (Android). In iOS, you may use SITLocationRequest.beaconFilters. | |
Auto-enable BLE (Android only) | User may disable Bluetooth on the smartphone, preventing Situm SDK to scan BLE signals. SitumSDK re-enables Bluetooth automatically if LocationRequest.Builder().useBLE is true. | To disable this automatic, set LocationRequest.Builder().autoEnableBleDuringPositioning to false. WARNING: This option is not compatible with Android >= 13 or Huawei devices. If you start positioning on those devices using this option, location status to will change to AUTO_ENABLE_BLE_FORBIDDEN. In this case, ask the user to enable the bluetooth sensor by: 1. In Android >= 13 devices: throwing the BluetoothAdapter.ACTION_REQUEST_ENABLE intent. 2. In Huawei devices: just call BluetoothAdapter.enable() (Huawei already implements this dialog). | |
GPS | Use GPS for indoor positioning (useful in buildings with outdoor areas with good GPS coverage). Using GPS implies that Calibrated or Uncalibrated GPS Indoor modes will be used. Do not mistake using GPS with Global Mode: GPS can be used both in Building and Global modes. | Disabled by default. Enable it by setting LocationRequest.Builder().useGPS to true. | |
Gyroscope | Gyroscope measures the angular velocity (rate at which the smartphone turns). Combined with compass, Situm provides an accurate orientation. | Enabled by default. You may disable it (not recommended) by setting LocationRequest.Builder().useGyro to false. | |
Compass | Compass measures the absolute smartphone orientation with respect to the Earth’s North. | Enabled by default. You may disable it (not recommended) by setting LocationRequest.Builder().useCompass to false. | |
Barometer | It is the instrument that measures the pressure of the air in the atmosphere against everything it touches, as gravity pulls it towards the Earth. | Enabled by default. You may disable it (not recommended) by setting LocationRequest.Builder().useBarometer to false. From OS 17.4 you should request NSMotionUsageDescription permission to use the barometer (you can find more information here). |
Detail on how Auto-enable BLE works
Configuration of positioning in navigation #
This positioning feature allows for the adjustment of the user’s current position and orientation to align with a selected navigation route. This feature is governed by three key parameters: Route adjustment, distance threshold and angle difference threshold.
Configuration | Description | How to use it |
---|---|---|
Route adjustment | Enabled by default, it determines whether the positioning should adapt to the chosen path. When activated, it aligns the user’s position and orientation with the selected navigation route (based on the following parameters). | Set the parameter “useRouteAdjustment “(Android) to “true” or “false” to enable or disable this functionality. |
Distance threshold | Defines a “Distance Threshold” in meters to determine when a user’s position is adjusted to the navigation route. If the user is within this threshold, their position is aligned with the route; if they are farther away, their actual position remains unchanged. | Set the value of “distanceThreshold”(Android) to specify the distance in meters at which this functionality operates in relation to the distance between the user and the route. |
Angle difference threshold | Measured in radians, controls the user’s alignment with a navigation route based on their orientation. If the user’s orientation is within the specified angle difference from the route’s direction, they align with the route; if the difference is larger, their orientation stays unaltered. | Set the angle value in radians “angleDifferenceThreshold” (Android) to specify the angle in radians relative to the route at which the functionality adjusts the position and orientation |
You can also adjust this navigation parameter in the Situm SDK for both Android and iOS through our Remote Configuration feature.
Location Updates Configuration #
By default, Situm SDK computes one geolocation estimate per second, uploads it to the Situm cloud, and gets stored.
This is fine for more apps, but sometimes you may want to tweak this behaviour (or even disable positioning at all). For example, in a wayfinding app the user may turn around in an instant. Waiting one second to show the turn (default behaviour) does not account for a good navigation UX: faster orientation updates will be handy.
Indoor Positioning #
Configuration | Description | How to use it |
---|---|---|
Realtime updates interval | Sets the interval for uploading real-time locations. More info. | Set LocationRequest.Builder().interval (Android) or SITLocationRequest.interval (iOS) to the interval value in milliseconds. |
Location updates interval | Interval between consecutive Indoor Location updates (by default, 1 second) provided via the LocationListener.onLocationChanged callback. More info. | Set LocationRequest.Builder().interval (Android) or SITLocationRequest.interval (iOS) to the interval value in milliseconds. |
Location updates displacement | Configures the minimum movement that the user has to perform to produce a new location via the LocationListener.onLocationChanged callback. More info. | Set LocationRequest.Builder().smallestDisplacement (Android) or SITLocationRequest.interval (iOS) to the smallest displacement (in meters) required. |
Dead reckoning (faster orientation changes) | Computes fast orientation changes between every two locations and provides several location updates per second (only orientation changes, approx 1 per 150ms) via the LocationListener.onLocationChanged callback. Useful to provide a better user experience when the user turns quickly. | Deactivated by default. Recommended to enable it for a better UX in wayfinding apps. To enable it, set the LocationRequest.Builder().useDeadReckoning (Android) or SITLocationRequest.useDeadReckoning (iOS) to true. |
None of the above configurations change: 1) the frequency with which Situm computes it’s geolocations, 2) the frequency and number of geolocations that Situm uploads to Situm Cloud.
Regarding the update intervals, we only recommend adjusting the Realtime updates interval.
Outdoor Positioning (Global Mode only) #
Configuration | Description | How to use it |
---|---|---|
Disable outdoor positioning | You may want to do this to make sure that users are not tracked outside of the building(s). If you disable it, the GPS based building detector will not work. Therefore, you should set a different building detector (e.g. WiFi/BLE based). | Set to false OutdoorLocationOptions.Builder().enableOutdoorPositions (Android) or SITOutdoorLocationOptions.enableOutdoorPositions (iOS). |
Compute interval | Frequency with which outdoor locations are computed. Helps reducing battery consumption. | Set the OutdoorLocationOptions.Builder().computeInterval (Android) or SITOutdoorLocationOptions.computeInterval (iOS). |
Update Interval | Frequency with which outdoor locations are delivered to the application. Does not change the frequency with which Situm computes geolocations (it just discards some of them). Useful to reduce the amount of data stored in Situm Cloud to perform geospatial with less data. | Set the OutdoorLocationOptions.Builder().updateInterval (Android) or SITOutdoorLocationOptions.updateInterval (iOS). |
Minimum outdoor accuracy | Filters out outdoor positioning that do not meet a certain accuracy. | Set OutdoorLocationOptions.Builder().minimumOutdoorLocationAccuracy (Android) or SITOutdoorLocationOptions.minimumOutdoorLocationAccuracy (iOS). |