Measuring Your Heart Rate on Android Using MetaWear

MetaWear Heart Rate Screenshot While the MbientLab MetaWear has a number of sensors built into the board, it also has the ability to interface with a host of analog sensors. With many wearable devices focusing on fitness, you might find yourself needing to integrate a heart rate sensor into your board.

Getting Started

To get started you will need to have a heart rate sensor in addition to a MetaWear board. This post on the MbientLab projects page will give you information on where to find and how to wire up the sensor to your board. Once you are done with this you will need to set up your project to include the MetaWear API, app permissions etc.. Our post on logging thermistor data here goes over the steps to set up your project and connect to the board.

Reading The Data

Now that you are able to connect to the board you will need to read analog data from a GPIO pin. To do that we first need to get the GPIO module.

try {
      gpio = metaWearBoard.getModule(Gpio.class);
    } catch (UnsupportedModuleException e) {
      Log.e("HeartRateSensorFragment", e.toString());
      return false;
    }

For this application we are going to stream the data the GPIO pin to a stream that we will call HEART_RATE and pass in CompletionHandler called gpioHandler that will set up the rest of the chain once the route has been configured.

private final byte GPIO_PIN = 0;
private final String HEART_RATE = "heart_rate";
   
gpio.routeData().fromAnalogIn(GPIO_PIN, Gpio.AnalogReadMode.ADC).stream(HEART_RATE)
                .commit().onComplete(gpioHandler);

Our CompletionHandler is going to do a couple of things in a over-ridden success method. First it is gonig to subscribe to our stream with a data handler that will process reads from the pin (more on that handler later in this post).

result.subscribe(HEART_RATE, dataHandler);

Then it needs to set up a timer to periodically get a reading from the pin.

private final int SCAN_INTERVAL = 50;

try {
     AsyncOperation<Timer.Controller> taskResult = metaWearBoard.getModule(Timer.class).scheduleTask(
        new Timer.Task() {
            @Override
            public void commands() {
                 gpio.readAnalogIn(GPIO_PIN, Gpio.AnalogReadMode.ADC);
            }
        }, SCAN_INTERVAL, false);
     taskResult.onComplete(
        new AsyncOperation.CompletionHandler<Timer.Controller>() {
            @Override
            public void success(Timer.Controller result) {
                  result.start();
            }
          }
        );
    } catch (UnsupportedModuleException e) {
        Log.e("HeartRateSensorFragment", e.toString());
    }

The entire handler ends up looking like this.

    private final AsyncOperation.CompletionHandler<RouteManager> gpioHandler = new AsyncOperation.CompletionHandler<RouteManager>() {
        @Override
        public void success(RouteManager result) {
            result.subscribe(HEART_RATE, dataHandler);
            try {
                AsyncOperation<Timer.Controller> taskResult = metaWearBoard.getModule(Timer.class).scheduleTask(
                        new Timer.Task() {
                            @Override
                            public void commands() {
                                gpio.readAnalogIn(GPIO_PIN, Gpio.AnalogReadMode.ADC);
                            }
                        }, SCAN_INTERVAL, false);
                taskResult.onComplete(
                        new AsyncOperation.CompletionHandler<Timer.Controller>() {
                            @Override
                            public void success(Timer.Controller result) {
                                result.start();
                            }
                        }
                );
            } catch (UnsupportedModuleException e) {
                Log.e("HeartRateSensorFragment", e.toString());
            }
        }

    };

Then our MessageHandler (what we refer to as our dataHandler) will look like this.

    private final RouteManager.MessageHandler dataHandler = new RouteManager.MessageHandler() {
        @Override
        public void process(Message message) {
            short rawValue = message.getData(Short.class);
            Log.i("HeartRateSensorFragment", String.valueOf(rawValue));

            .
            .
            . heart rate calculations
            .
            .

            getActivity().runOnUiThread(
                    new Runnable() {
                        @Override
                        public void run() {
                            bpmView.setText(String.valueOf(bpm));
                        }
                    }
            );
            Log.i("HRSFragment BPM", String.valueOf(bpm));

        }
    };

You can find the code here . Feel free to fork it and make it your own. The application can also be found on the play store here.

About Me: I am a Atlanta based, mobile/Android/IOS/AngularJS/Ruby developer, polyglot programmer, founder of Polyglot Programming Inc., wearable technology enthusiast and am interested in the internet of things. You will often find me purr programming and I regularly speak at conferences around the world. I am available for hire! More Posts

Follow Me:
TwitterLinkedInGoogle Plus

I am a Atlanta based, mobile/Android/IOS/AngularJS/Ruby developer, polyglot programmer, founder of Polyglot Programming Inc., wearable technology enthusiast and am interested in the internet of things. You will often find me purr programming and I regularly speak at conferences around the world. I am available for hire!

Posted in Android, MetaWear, Mobile, Wearables Tagged with: , ,