Accelerometer

All boards come with an accelerometer. The specific accelerometer model varies amongst the boards, howevever the API provides accelerometer agnostic functions in the accelerometer.h header file that can be safely used with all supported accelerometers.

Users can check which accelerometer is on their board at runtime to determine the appropriate accelerometer specific functions they need to use, if necessary.

#include "metawear/core/module.h"

#include "metawear/sensor/accelerometer_bosch.h"
#include "metawear/sensor/accelerometer_mma8452q.h"

void check_acc_type(MblMwMetaWearBoard* board) {
    auto acc_type= mbl_mw_metawearboard_lookup_module(board, MBL_MW_MODULE_ACCELEROMETER);
    switch(acc_type) {
    case MBL_MW_MODULE_TYPE_NA:
        // should never reach this case statement
        printf("No accelerometer on this board\n");
        break;
    case MBL_MW_MODULE_ACC_TYPE_MMA8452Q:
        printf("Acc Type = MMA8452Q\n");
        break;
    case MBL_MW_MODULE_ACC_TYPE_BMI160:
        printf("Acc Type = BMI160\n");
        break;
    case MBL_MW_MODULE_ACC_TYPE_BMA255:
        printf("Acc Type = BMA255\n");
        break;
    default:
        printf("Unknown type\n");
        break;
    }

Acceleration Sampling

Acceleration sampling measures the current acceleration forces at periodic intervals. To enable acceleration sampling, call mbl_mw_acc_enable_acceleration_sampling before starting the accelerometer.

Linear acceleration is represented with the MblMwCartesianFloat struct and the values are in units of Gs. The x, y, and z fields contain the acceleration in that direction.

#include "metawear/core/datasignal.h"
#include "metawear/core/types.h"

#include "metawear/sensor/accelerometer.h"

void enable_acc_sampling(MblMwMetaWearBoard* board) {
    auto data_handler = [](void* context, const MblMwData* data) -> void {
        // Cast value to MblMwCartesianFloat*
        auto acceleration = (MblMwCartesianFloat*) data->value;
        printf("(%.3fg, %.3fg, %.3fg)\n", acceleration->x, acceleration->y, acceleration->z);
    };

    auto acc_signal= mbl_mw_acc_get_acceleration_data_signal(board);
    mbl_mw_datasignal_subscribe(acc_signal, nullptr, data_handler);

    mbl_mw_acc_enable_acceleration_sampling(board);
    mbl_mw_acc_start(board);
}

Configuration

Users can configure the output data rate and the sampling range; these parameters control the sampling rate and the data range and resolution respectively. After configuring the settings, call mbl_mw_acc_write_acceleration_config to write the configuration to the sensor.

#include "metawear/sensor/accelerometer.h"

void configure_acc(MblMwMetaWearBoard* board) {
    // Set ODR to 25Hz or closest valid frequency
    mbl_mw_acc_set_odr(board, 25.f);

    // Set range to +/-4g or closest valid range
    mbl_mw_acc_set_range(board, 4.f);

    // Write the config to the sensor
    mbl_mw_acc_write_acceleration_config(board);
}

High Frequency Stream

Firmware v1.2.3+ contains a packed mode for the accelerometer which combines 3 acceleration data samples into 1 ble packet allowing the board to stream data at a throughput higher than 100Hz. This special data signal is retrieved from the mbl_mw_acc_get_packed_acceleration_data_signal function and is only for streaming; do not use it with data processing or logging.

auto high_freq_signal= mbl_mw_acc_get_high_freq_acceleration_data_signal(board);
mbl_mw_datasignal_subscribe(high_freq_signal, nullptr, [](void* context, const MblMwData* data) -> void {
    // Cast value to MblMwCartesianFloat*
    auto acceleration = (MblMwCartesianFloat*) data->value;
    printf("(%.3fg, %.3fg, %.3fg)\n", acceleration->x, acceleration->y, acceleration->z);
});

mbl_mw_acc_set_odr(board, 200.f);
mbl_mw_acc_enable_acceleration_sampling(board);
mbl_mw_acc_start(board);

Step Counter

The BMI160 accelerometer comes with a built in step counter. It has three operation modes that configure the sensitivity and robustness of the counter:

Mode Description
Normal Balanced between false positives and false negatives, recommended for most applications
Sensitive Few false negatives but eventually more false positives, recommended for light weighted people
Robust Few false positives but eventually more false negatives

When you have set the operation mode, call mbl_mw_acc_bmi160_write_step_counter_config to save the configuration to the board.

#include "metawear/sensor/accelerometer_bosch.h"

mbl_mw_acc_bmi160_set_step_counter_mode(board, MBL_MW_ACC_BMI160_STEP_COUNTER_MODE_SENSITIVE);
mbl_mw_acc_bmi160_write_step_counter_config(board);

Reading The Counter

One way to retrieve step counts is to periodcally read the step counter. To read the step counter, call mbl_mw_datasignal_read with the step counter data signal.

The counter is not enabled by default so you will need enable it by calling mbl_mw_acc_bmi160_enable_step_counter when configuring the board.

// enable the counter
mbl_mw_acc_bmi160_enable_step_counter(board);
mbl_mw_acc_bmi160_write_step_counter_config(board);
mbl_mw_acc_start(board);

// read step counter
auto step_counter= mbl_mw_acc_bmi160_get_step_counter_data_signal(board);
mbl_mw_datasignal_subscribe(step_counter, nullptr, [](void* context, const MblMwData* data) -> void {
    printf("steps= %d\n", *((uint32_t*) data->value));
});
mbl_mw_datasignal_read(adc_signal);

Using The Detector

Alternatively, you can receive notifications for each step detected by calling mbl_mw_acc_bmi160_enable_step_detector instead.

auto detector= mbl_mw_acc_bmi160_get_step_detector_data_signal(board);
mbl_mw_datasignal_subscribe(detector, nullptr, [](void* context, const MblMwData* data) -> void {
    printf("step detected\n");
});

mbl_mw_acc_bmi160_enable_step_detector(board);
mbl_mw_acc_bosch_start(board);

Orientation Detection

The orientation detector alerts you when the sensor’s orientation changes between portrait/landscape and front/back. Data is represented as an MblMwSensorOrientation enum.

This feature is currently only supported on devices using the BMI160 or BMA255 accelerometers.

#include "metawear/core/datasignal.h"
#include "metawear/core/types.h"
#include "metawear/sensor/accelerometer_bosch.h"

auto signal = mbl_mw_acc_bosch_get_orientation_detection_data_signal(board);
mbl_mw_datasignal_subscribe(signal, nullptr, [](void* context, const MblMwData* data) {
    cout << "orientation = " << *((MblMwSensorOrientation*)data->value) << endl;
});
mbl_mw_acc_bosch_enable_orientation_detection(board);
mbl_mw_acc_bosch_start(board);

Motion Detection

The motion detection algorithms on the Bosch chips use the difference in consecutive acceleration data samples to determine different types of motion. Currently, only “any motion” detection is supported with the C++ sdk.

Motion Description
Any Difference exceeds threshold for N consecutive samples
No Difference doesn’t exceed the threshold for a period of time
Slow Same as any motion but axis and direction information is not retained
#include "metawear/sensor/accelerometer_bosch.h"

// configure any motion detection
// difference > 0.75g for 4 consecutive samples
mbl_mw_acc_bosch_set_any_motion_count(board, 4)
mbl_mw_acc_bosch_set_any_motion_threshold(board, 0.75)
mbl_mw_acc_bosch_write_motion_config(board)

// Subscribe to any motion data
auto motion_signal = mbl_mw_acc_bosch_get_motion_data_signal(board);
mbl_mw_datasignal_subscribe(motion_signal, nullptr, [](void* context, const MblMwData* data) {
    auto casted = (MblMwBoschAnyMotion*) data->value;
    cout << "{sign: " << casted->sign ? "positive" : "negative" <<
        ", x-active: " << casted->x_axis_active <<
        ", y-active: " << casted->y_axis_active <<
        ", z-active: " << casted->z_axis_active <<
        "}" << endl;
});

// Enable motion detection and start accelerometer
mbl_mw_acc_bosch_enable_motion_detection(board)
mbl_mw_acc_bosch_start(board);

Tap Detection

The tap detection algorithm checks if the difference in acceleration exceeds a threshold. To detect double tap, a second tap must be registered within the quiet delay but before the double tap window ends. The shock duration is a period of time where the direction of the first tap is locked; the quiet delay starts after the shock duration ends. Use the various mbl_mw_acc_bosch_set_* functions to set these parameters, then mbl_mw_acc_bosch_write_tap_config to write the tap configuration to the board.

Data from the tap detection algorithm is represented as a MblMwBoschTap struct.

#include "metawear/core/types.h"
#include "metawear/sensor/accelerometer_bosch.h"

void bosch_single_tap(MblMwMetaWearBoard* board) {
    // set threshold to 2g
    mbl_mw_acc_bosch_set_threshold(board, 2.f);
    // set shock time to 50ms
    mbl_mw_acc_bosch_set_shock_time(board, MBL_MW_ACC_BOSCH_TAP_SHOCK_TIME_50ms);
    // write config to boarrd
    mbl_mw_acc_bosch_write_tap_config(board);

    auto signal = mbl_mw_acc_bosch_get_tap_data_signal(board);
    mbl_mw_datasignal_subscribe(signal, nullptr, [](void* context, const MblMwData* data) {
        auto casted = (MblMwBoschTap*) data->value;
        switch (casted->type) {
        case 1:
            cout << "Double tap" << endl;
            break;
        case 2:
            cout << "Single tap" << endl;
            break;
        default:
            cout << "Unable to determine tap" << endl;
            break;
        }
    });

    // enable single tap detection, but not double tap
    mbl_mw_acc_bosch_enable_tap_detection(board, 1, 0);
    mbl_mw_acc_bosch_start(board);
}