BMI160 Accelerometer

The BMI160 accelerometer class is an extension of the Accelerometer class that interacts specifically with the BMI160 chip, the accelerometer on the MetaWear R Pro/RG boards.

Acceleration Sampling

Axis sampling measures the acceleration data on the XYZ axes. Configuring the sampling is done with a SamplingConfigEditor, letting you set the measurement range and output data rate. If you wish you use data rates less than 12.5Hz, you must enable undersampling by calling enableUndersampling. When calling the function, you will need to pass in the number of samples that undersampling will use to average the data.

Available data sources are the acceleration from the XYZ axes and from the individual axis. Three axis data can be interpreted as a CartesianFloat (G’s) or a CartesianShort (milli G’s) whereas single axis data can be interpreted as a float (G) or short/integer/long (milli G).

When processing the 3 axis data, you are restricted to only data filters, minus the comparison and sample filters, and the rms and rss transformers. In order to access the full library of data processors, they must be chained after an rms or rss transformer. On firmware v1.1.2 and later, you can use the math processor on acceleration data. Each axis will be treated as separate inputs to the operation defined.

import com.mbientlab.metawear.module.Bmi160Accelerometer.AccRange;
import com.mbientlab.metawear.module.Bmi160Accelerometer.OutputDataRate;

Bmi160Accelerometer bmi160AccModule= mwBoard.getModule(Bmi160Accelerometer.class);

// Set measurement range to +/- 16G
// Set output data rate to 100Hz
bmi160AccModule.configureAxisSampling()
    .setFullScaleRange(AccRange.AR_16G)
    .setOutputDataRate(OutputDataRate.ODR_100_HZ)
    .commit();
// enable axis sampling
bmi160AccModule.enableAxisSampling();

// Switch the accelerometer to active mode
bmi160AccModule.start();

High Frequency Streams

Firmware v1.2.3+ supports high frequency streaming of accelerometer data, see the High Frequency Streams section for more details.

Step Detection

The BMI160 sensor comes built in with a step detector. You can periodically read the counter by calling readStepCounter to get the current step count or be alerted when a step is taken. The step counter is disabled by default so you must enable it with the StepDetectionConfigEditor.

import com.mbientlab.metawear.module.Bmi160Accelerometer;

Bmi160Accelerometer bmi160AccModule= mwBoard.getModule(Bmi160Accelerometer.class);

// Enable step detection
bmi160AccModule.enableStepDetection();

// Route data from the chip's step counter
bmi160AccModule.routeData().fromStepCounter(false).stream("step_counter").commit()
    .onComplete(new CompletionHandler<RouteManager>() {
        @Override
        public void success(RouteManager result) {
            result.subscribe("step_counter", new RouteManager.MessageHandler() {
                @Override
                public void process(Message msg) {
                    Log.i("MainActivity", "Steps= " + msg.getData(Integer.class));
                }
            });

            bmi160AccModule.readStepCounter(false);
        }
    });

// Receive notifications for each step detected
bmi160AccModule.routeData().fromStepDetector().stream("step_detector").commit()
    .onComplete(new CompletionHandler<RouteManager>() {
        @Override
        public void success(RouteManager result) {
            result.subscribe("step_detector", new RouteManager.MessageHandler() {
                @Override
                public void process(Message msg) {
                    Log.i("MainActivity", "You took a step");
                }
            });
        }
    });

There are three sensitivity modes for the step detector: normal, sensitive, and robust. These modes balance sensitivity (false negatives) and robustness (false positives). Normal mode is recommended for most applications as it is well balanced between false positives and false negatives.

bmi160AccModule.configureStepDetection()
    // Set sensitivity to normal
    .setMode(StepSensitivity.NORMAL)
    // Enable step counter
    .enableStepCounter()
    .commit();

Low/High Detection

Low-g and high-g detection monitors the board for free fall or high acceleration respectively. Data is interpretted as a LowHighResponse object.

import com.mbientlab.metawear.module.Bmi160Accelerometer;
import com.mbientlab.metawear.module.Bmi160Accelerometer.LowHighResponse;

// Enable high-g detection on xyz axes, disable low-g detection
accModule.enableLowHighDetection(false, true, true, true);
accModule.routeData().fromLowHigh().stream("low_high_stream").commit()
    .onComplete(new CompletionHandler<RouteManager>() {
        @Override
        public void success(RouteManager result) {
            result.subscribe("low_high_stream", new RouteManager.MessageHandler() {
                @Override
                public void process(Message msg) {
                    Log.i("test", "High motion! " + msg.getData(LowHighResponse.class));
                }
            });
            accModule.start();
        }
    });

Flat Detection

Flat detection checks when the sensor enters a horizontal position or leaves it. Data is interpretted as a boolean where true signifies the sensor is laying horizontally.

import com.mbientlab.metawear.module.Bmi160Accelerometer;

Bmi160Accelerometer bmi160AccModule= mwBoard.getModule(Bmi160Accelerometer.class);

// Enable flat detection
bmi160AccModule.enableFlatDetection();
bmi160AccModule.routeData().fromFlat().stream("flat_key").commit()
    .onComplete(new CompletionHandler<RouteManager>() {
        @Override
        public void success(RouteManager result) {
            result.subscribe("flat_key", new RouteManager.MessageHandler() {
                @Override
                public void process(Message msg) {
                    Log.i("MainActivity", "Flat? " + msg.getData(Boolean.class));
                }
            });
        }
    });

Orientation Detection

The orientation detector alerts you when the sensor’s orientation changes between portrait/landscape and front/back. Data is interpretted as a SensorOrientation enum.

import com.mbientlab.metawear.module.Bmi160Accelerometer;
import com.mbientlab.metawear.module.Bmi160Accelerometer.SensorOrientation;

Bmi160Accelerometer bmi160AccModule= mwBoard.getModule(Bmi160Accelerometer.class);

// Enable orientation detection
bmi160AccModule.enableOrientationDetection();

// Route data from the chip's step counter
bmi160AccModule.routeData().fromOrientation().stream("orientation").commit()
    .onComplete(new CompletionHandler<RouteManager>() {
        @Override
        public void success(RouteManager result) {
            result.subscribe("orientation", new RouteManager.MessageHandler() {
                @Override
                public void process(Message msg) {
                    Log.i("MainActivity", msg.getData(SensorOrientation.class));
                }
            });
        }
    });

Tap Detection

The BMI160 chip comes with a built in algorithm to detect single and double taps. The BMI160 chip detects a tap by checking if the acceleration difference exceeds a threshold. If that event occurs, the data is then frozen for a period of time called the shock period. Double tap is triggered if a second tap is registered after the quiet period but before the double tap window ends. Tap detection is configured with a TapConfigEditor and responses are encapsulated in the TapResponse interface. When you enable tap detection, you can choose to only detect single or double taps, or both.

import com.mbientlab.metawear.module.Bmi160Accelerometer;
import com.mbientlab.metawear.module.Bmi160Accelerometer.TapResponse;
import com.mbientlab.metawear.module.Bmi160Accelerometer.TapType;

Bmi160Accelerometer bmi160AccModule= mwBoard.getModule(Bmi160Accelerometer.class);

// Enable only single tap detection
bmi160AccModule.enableTapDetection(TapType.SINGLE);

// Route data from the chip's tap detector
bmi160AccModule.routeData().fromTap().stream("tap").commit()
    .onComplete(new CompletionHandler<RouteManager>() {
        @Override
        public void success(RouteManager result) {
            result.subscribe("tap", new RouteManager.MessageHandler() {
                @Override
                public void process(Message msg) {
                    TapResponse response= msg.getData(TapResponse.class);
                    switch(response.type()) {
                    case SINGLE:
                        Log.i("MainActivity", "Single tap");
                        break;
                    case DOUBLE:
                        Log.i("MainActivity", "Double tap"):
                        break;
                    }
                }
            });
        }
    });

Motion Detection

The BMI160 chip comes with 4 types of motion detection: any, significant, no, and slow. Only any motion detection retains the axis and direction that triggered the interrupt.

Any and slow motion uses the slopes of consecutive acceleration points to detect motion. The slope must exceed a threshold for a number of consecutive data points for an interrupt to be triggered. Configuring any and slow motion is done with the AnyMotionConfigEditor and SlowMotionConfigEditor respectively.

Significant motion triggers an interrupt from a change in location, such as walking or being in a moving vehicle. When motion is detected, the algorithm will then sleep for a period of time, called the skip time. After waking up, motion must still be detected within a window of time, called the proof time. Skip and proof time is configured with a SignificantMotionConfigEditor.

No motion is defined as the slope of data points not exceeding a threshold for a period of time. The duration and threshold is configured with a NoMotionConfigEditor.

import com.mbientlab.metawear.module.Bmi160Accelerometer;
import com.mbientlab.metawear.module.Bmi160Accelerometer.ProofTime;
import com.mbientlab.metawear.module.Bmi160Accelerometer.SkipTime;

Bmi160Accelerometer bmi160AccModule= mwBoard.getModule(Bmi160Accelerometer.class);

// Enable significant motion detection
bmi160AccModule.enableMotionDetection(MotionType.SIGNIFICANT_MOTION);
// Set skip time to 6 seconds and proof time to 2 seconds
bmi160AccModule.configureSignificantMotionDetection()
    .setSkipTime(SkipTime.ST_6_S)
    .setProofTime(ProofTime.PT_2_S)
    .commit();

// Route data from the chip's motion detector
bmi160AccModule.routeData().fromMotion().stream("motion").commit()
    .onComplete(new CompletionHandler<RouteManager>() {
        @Override
        public void success(RouteManager result) {
            result.subscribe("motion", new RouteManager.MessageHandler() {
                @Override
                public void process(Message msg) {
                    Log.i("MainActivity", "Significant motion detected");
                }
            });
        }
    });