Skip to content

Android SBeacon Framework Calibration

AigarsM edited this page Jan 28, 2026 · 6 revisions

Accelerometer Calibration

Calibration ensures accurate driving behavior detection by establishing a baseline reference for the beacon's accelerometer. This is a required step before using driving behavior features.


Why Calibration Matters

The SBeacon's accelerometer measures G-forces in three axes (X, Y, Z) following the ISO8855 vehicle axis system. Without calibration:

  • Gravity may be incorrectly attributed to movement
  • Event detection thresholds will be inaccurate
  • False positives/negatives will occur

How Calibration Works

Calibration fundamentally changes how incident thresholds are calculated:

Uncalibrated Mode:

  • Threshold compared against: √(x² + y² + z²)
  • Includes the Z-axis gravity component (~1g when stationary)
  • Results in inaccurate detection as gravity interferes with motion detection

Calibrated Mode:

  • Threshold compared against: √(x² + y²)
  • Excludes the Z-axis gravity component
  • Only horizontal plane motion (actual vehicle movement) is measured
  • Significantly more accurate event detection

Calibration establishes:

  • The orientation of the beacon in the vehicle
  • The baseline gravity vector (typically Z-axis = 1g when stationary)
  • Proper axis mapping for driving events
  • A rotation matrix for correct force vector interpretation

Prerequisites

Before calibrating:

  1. Beacon must be paired - See Beacon Pairing
  2. Beacon must be connected - Ensure active BLE connection
  3. Vehicle must be stationary - Park on a level surface (critical for accurate calibration)
  4. Beacon must be properly mounted - Install in final position following mounting guidelines below

Critical: Mounting Orientation

The SBeacon MUST be mounted vertically for proper calibration:

Standard Mounting (Button Facing Up):

  • Mount beacon vertically with button facing up
  • Adhesive pad should face toward the vehicle front
  • This is the default orientation requiring no post-processing

Logo Beacon Mounting (Button Facing Down):

  • For beacons with logo markings, mount with button facing down (logo upright)
  • Adhesive pad should face toward the vehicle front
  • Important: This orientation requires X/Y axis inversion in post-processing
  • Consult with support if using logo beacons

Why Vertical Mounting Matters:

  • Ensures Z-axis aligns with gravity (perpendicular to ground)
  • Allows calibration to establish proper baseline (Z ≈ 1g when stationary)
  • Enables accurate horizontal plane motion detection (X/Y axes)

Calibration Process

Step 1: Check Current Calibration Status

val bleManager = BLEManager.retrieveInstance(context)

// Request calibration state
bleManager.requestAccelerometerConfig(beaconMac)

// Handle response via EventsReceiver
private val eventsReceiver = object : IBFHelper.EventsReceiver() {
    override fun onUpdateBeaconCalibrationStateReceived(mac: String, isCalibrated: Boolean) {
        if (isCalibrated) {
            Log.d("Calibration", "Beacon is already calibrated")
        } else {
            Log.d("Calibration", "Beacon needs calibration")
        }
    }
}

// Register in onResume
override fun onResume() {
    super.onResume()
    IBFHelper.registerEventsReceiver(requireContext(), eventsReceiver)
}

You can also check the beacon's local state:

lifecycleScope.launch {
    val beacon = bleManager.getBeacon(beaconMac)
    val isCalibrated = beacon?.isCalibrated ?: false
    Log.d("Calibration", "Local state: calibrated = $isCalibrated")
}

Step 2: Start Calibration

// Ensure vehicle is stationary and beacon is in final position
bleManager.requestAccelerometerCalibration(beaconMac)

The calibration process:

  1. Enables the rotation bit (internal prerequisite)
  2. Initiates auto-calibration (command 10 11)
  3. Beacon measures baseline accelerometer values
  4. Calculates rotation angles
  5. Stores calibration data and rotation angles in flash memory

Step 3: Handle Completion

private val eventsReceiver = object : IBFHelper.EventsReceiver() {
    override fun onAutoCalibrationReceived(mac: String) {
        Log.d("Calibration", "Calibration successful for $mac")
        // Beacon is now ready for driving behavior detection
        // Calibration data is stored in beacon's flash memory
    }
}

Step 4: Verify Calibration (Optional)

After calibration completes, you can verify proper calibration by checking accelerometer readings when the vehicle is stationary:

Expected Values (Vehicle Stationary, Level Surface):

  • X-axis: ≈ 0g (lateral - left/right motion)
  • Y-axis: ≈ 0g (longitudinal - forward/backward motion)
  • Z-axis: ≈ 1g (vertical - gravity)

If values significantly deviate from this (e.g., Z-axis reads 0.5g or X/Y axes show constant non-zero values), the beacon may not be mounted vertically or calibration failed. In this case:

  1. Verify beacon is mounted vertically (not tilted)
  2. Check vehicle is on level surface
  3. Recalibrate

Resetting Calibration

If the beacon position changes or calibration seems incorrect:

// This is an internal method - typically not exposed via BLEManager
// Contact support if recalibration is needed after initial setup

After reset, the beacon's isCalibrated flag will be set to false, and you must perform calibration again.


Calibration States

State Description
Not Calibrated isCalibrated = false - Calibration required
Calibrated isCalibrated = true - Ready for use

The calibration state is:

  • Stored in the beacon's flash memory (persists across power cycles)
  • Cached locally in the app's database
  • Updated automatically when calibration completes or resets

Technical Details

ISO8855 Vehicle Axis System

The SBeacon accelerometer axes can be configured to align with the ISO8855:2011 Vehicle Axis System standard. This standard defines X (lateral), Y (longitudinal), and Z (vertical) axes relative to the vehicle body frame.

When properly calibrated and mounted vertically:

  • Z-axis aligns with gravity (~1g when stationary)
  • X and Y axes measure horizontal plane motion
  • Horizontal plane forces √(x² + y²) are isolated from gravitational effects

Note: The SBeacon default axes align with Android's Automotive Sensor implementation. A configuration bit can enable ISO8855:2011 alignment if required.

Rotation Matrix and Orientation

During calibration, the beacon:

  1. Enables the rotation bit (Bit 4 in accelerometer configuration)
  2. Triggers auto-calibration (command 10 11)
  3. Calculates rotation angles (alpha, beta, gamma) for X, Y, Z axes
  4. Persists the rotation angles and calibration flag to flash memory

When rotation is enabled, all accelerometer values are rotated by the configured angles before being used for event detection.

Button-Down Mounting (Logo Beacons):

  • For beacons with logos, button faces down (logo upright)
  • X and Y axis values will be inverted after calibration
  • Correction must be applied in post-processing: x_corrected = -x, y_corrected = -y, z_corrected = z
  • This corresponds to a rotation matrix with -1 multipliers on X and Y axes

Best Practices

Before Calibration

  1. Mount the beacon vertically - Button facing up (or down for logo beacons), adhesive toward vehicle front
  2. Ensure firm mounting - Beacon must not wobble or move; use proper adhesive surface
  3. Park on level ground - Vehicle must be on a completely level surface, not on a slope
  4. Stop the engine - Minimize vibration during calibration
  5. Verify BLE connection - Beacon must be connected before starting calibration

Beacon Placement

Critical Requirement: The beacon must be mounted to the windshield in a vertical orientation (button up/down) for proper calibration.

Mounting requirements:

  1. Vertical orientation - Beacon must be perpendicular to ground (not tilted or horizontal)
  2. Windshield mounting - Use adhesive to attach to windshield
  3. Button orientation - Button facing up (standard) or down (logo beacons)
  4. Adhesive pad direction - Should face toward vehicle front
  5. Stable surface - Ensure beacon is firmly attached and will not wobble or move

Important: Any location requiring horizontal mounting is not suitable. The beacon requires a vertical mounting surface on the windshield for proper accelerometer calibration.

After Calibration

  1. Verify with a test drive - Confirm events are detected correctly
  2. Check threshold sensitivity - Adjust if too many/few events
  3. Recalibrate if moved - Any position change requires recalibration

Troubleshooting

Calibration Not Starting

Problem: requestAccelerometerCalibration doesn't respond

Solutions:

  1. Verify beacon is connected (isBeaconConnected(beacon))
  2. Check Bluetooth permissions are granted
  3. Ensure beacon firmware is up to date
  4. Try disconnecting and reconnecting

Calibration Fails Silently

Problem: No completion event received

Solutions:

  1. Ensure vehicle is completely stationary
  2. Check for excessive vibration (engine running, nearby traffic)
  3. Wait longer (calibration can take several seconds)
  4. Verify event subscription is active before starting calibration

Inaccurate Detection After Calibration

Problem: False positives or missed events

Solutions:

  1. Verify vertical mounting - Beacon must be mounted vertically (button up/down), not horizontally
  2. Check accelerometer readings when stationary (X≈0, Y≈0, Z≈1)
  3. Recalibrate with vehicle on level surface
  4. Check if beacon has moved since calibration
  5. Verify beacon is firmly mounted (no wobble)
  6. Adjust detection thresholds (see Driving Behavior)

Incorrect Accelerometer Readings

Problem: Z-axis doesn't read ~1g when stationary, or X/Y axes show constant non-zero values

Solutions:

  1. Check mounting orientation - Beacon likely not mounted vertically
  2. Verify vehicle is on level surface during calibration
  3. Remount beacon in vertical orientation (button up/down)
  4. Recalibrate after correcting mounting position

isCalibrated Shows False After Calibration

Problem: State not updating

Solutions:

  1. Request calibration state explicitly: requestAccelerometerConfig(beaconMac)
  2. Check local database sync
  3. Verify completion event was received

Complete Example

class CalibrationFragment : Fragment() {

    private val bleManager by lazy { BLEManager.retrieveInstance(requireContext()) }
    private var beaconMac: String? = null

    sealed class CalibrationState {
        object Unknown : CalibrationState()
        object NotCalibrated : CalibrationState()
        object InProgress : CalibrationState()
        object Calibrated : CalibrationState()
    }

    private var calibrationState: CalibrationState = CalibrationState.Unknown
        set(value) {
            field = value
            updateUI(value)
        }

    private val eventsReceiver = object : IBFHelper.EventsReceiver() {
        override fun onUpdateBeaconCalibrationStateReceived(
            mac: String,
            isCalibrated: Boolean
        ) {
            if (mac == beaconMac) {
                calibrationState = if (isCalibrated) {
                    CalibrationState.Calibrated
                } else {
                    CalibrationState.NotCalibrated
                }
            }
        }

        override fun onAutoCalibrationReceived(mac: String) {
            if (mac == beaconMac) {
                calibrationState = CalibrationState.Calibrated
            }
        }
    }

    override fun onResume() {
        super.onResume()
        IBFHelper.registerEventsReceiver(requireContext(), eventsReceiver)
        checkCalibrationStatus()
    }

    override fun onPause() {
        super.onPause()
        IBFHelper.unregisterEventsReceiver(requireContext(), eventsReceiver)
    }

    fun checkCalibrationStatus() {
        calibrationState = CalibrationState.Unknown
        beaconMac?.let { bleManager.requestAccelerometerConfig(it) }
    }

    fun startCalibration() {
        calibrationState = CalibrationState.InProgress
        beaconMac?.let { bleManager.requestAccelerometerCalibration(it) }
    }

    private fun updateUI(state: CalibrationState) {
        // Update your UI based on state
    }
}

UI Integration

@Composable
fun CalibrationScreen(
    calibrationManager: CalibrationManager,
    beaconMac: String
) {
    val state by calibrationManager.calibrationState.collectAsState()

    Column(modifier = Modifier.padding(16.dp)) {
        Text("Calibration Status", style = MaterialTheme.typography.h6)

        when (state) {
            is CalibrationState.Unknown -> {
                Text("Checking calibration status...")
                LaunchedEffect(beaconMac) {
                    calibrationManager.checkCalibrationStatus(beaconMac)
                }
            }
            is CalibrationState.NotCalibrated -> {
                Text("Beacon needs calibration")
                Text("1. Park on level ground")
                Text("2. Turn off engine")
                Text("3. Ensure beacon is mounted")
                Button(onClick = { calibrationManager.startCalibration(beaconMac) }) {
                    Text("Start Calibration")
                }
            }
            is CalibrationState.InProgress -> {
                CircularProgressIndicator()
                Text("Calibrating... Keep vehicle stationary")
            }
            is CalibrationState.Calibrated -> {
                Icon(Icons.Default.Check, "Calibrated", tint = Color.Green)
                Text("Beacon is calibrated and ready")
            }
            is CalibrationState.Error -> {
                Text("Error: ${(state as CalibrationState.Error).message}", color = Color.Red)
            }
        }
    }
}

Related Pages

Clone this wiki locally