Sobhit PandaPratyush Mallick
Published © MIT

Smart Helmet powered by Blues Wireless Notecard

Smart headgear that covers up your safety on road with tinyML-based crash detection and SOS alert over LTE-M

IntermediateFull instructions providedOver 4 days804
Smart Helmet powered by Blues Wireless Notecard

Things used in this project

Hardware components

Blues Wireless Feather Starter Kit for Swan
Blues Wireless Feather Starter Kit for Swan
×1
Analog Devices EVAL-ADXL355Z
×1
Li-Ion Battery 1000mAh
Li-Ion Battery 1000mAh
×1

Software apps and online services

Arduino IDE
Arduino IDE
Blues Notehub.io
Blues Notehub.io
Edge Impulse Studio
Edge Impulse Studio
SMS Messaging API
Twilio SMS Messaging API

Hand tools and fabrication machines

Hot glue gun (generic)
Hot glue gun (generic)
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires

Story

Read more

Schematics

Circuit Diagram

Code

Setting Up communication between Notecard and Swan MCU

C/C++
This basic project shows how to send JSON queries to Notecard from Swan MCU using Notecard communication APIs.
#include "Wire.h"
#include <Notecard.h> /*Install the Blues Wireless Arduino Library*/

#define productUID "com.gmail.sobhitpanda25:helmet"
Notecard notecard;

void setup()
{
  notecard.begin();
  Serial.begin(115200);
  notecard.setDebugOutputStream(Serial);
  J *req = notecard.newRequest("hub.set");
  JAddStringToObject(req, "product", productUID);
  JAddStringToObject(req, "mode", "continuous");
  notecard.sendRequest(req);
}

void loop()
{
  J *req = notecard.newRequest("note.add");
  if (req != NULL)
  {
    JAddStringToObject(req, "file", "sensors.qo");
    JAddBoolToObject(req, "sync", true);
    J *body = JAddObjectToObject(req, "body");

    if(body)
    {
      JAddNumberToObject(body, "x", 9.14);
      JAddNumberToObject(body, "y", 9.14);
      JAddNumberToObject(body, "z", 9.14);
    }
    
    notecard.sendRequest(req);
    Serial.println("not null");
  }
  delay(10000);
}

ADXL355Z Interfacing SPI

C/C++
This getting started project shows, how to interface Analog Devices EVAL-ADXL355Z accelerometer sensor to the Blues Wireless Swan MCU using Arduino Library.
#include <Arduino.h>
#include <SPI.h>

namespace Adxl355 {

  const char SPI_W = 0;
  const char SPI_R = 1;

  enum Reg {
    DEVID_AD = 0x00,
    DEVID_MST = 0x01,
    DEVID = 0x02,  
    REVID = 0x03,
    STATUS = 0x04,
    FIFO_ENTRIES = 0x05,
    TEMP2 = 0x06,
    TEMP1 = 0x07,
    XDATA3 = 0x08,
    XDATA2 = 0x09,
    XDATA1 = 0x0A,
    YDATA3 = 0x0B,
    YDATA2 = 0x0C,
    YDATA1 = 0x0D,
    ZDATA3 = 0x0E,
    ZDATA2 = 0x0F,
    ZDATA1 = 0x10,
    FIFO_DATA = 0x11,
    OFFSET_X_H = 0x1E,
    OFFSET_X_L = 0x1F,
    OFFSET_Y_H = 0x20,
    OFFSET_Y_L = 0x21,
    OFFSET_Z_H = 0x22,
    OFFSET_Z_L = 0x23,
    ACT_EN = 0x24,
    ACT_THRESH_H = 0x25,
    ACT_THRESH_L = 0x26,
    ACT_COUNT =  0x27,
    FILTER = 0x28,
    FIFO_SAMPLES = 0x29,
    INT_MAP = 0x2A,
    SYNC = 0x2B,
    RANGE = 0x2C,
    POWER_CTL = 0x2D,
    SELF_TEST = 0x2E,
    RESET = 0x2F
  };

  namespace Range {
    struct type {
      uint8_t code;
      double coef;
    };
    const type _2G = { 0b01, 256000.0 };
    const type _4G = { 0b10, 128000.0 };
    const type _8G = { 0b11, 64000.0  };
  }


  namespace ODR {
    struct type {
      uint8_t code;
    };
    const type ODR_4000_Hz   = { 0 };  // odr = 4000 Hz and lpf = 1000 Hz
    const type ODR_2000_Hz   = { 1 };  // odr = 2000 Hz and lpf = 500 Hz
    const type ODR_1000_Hz   = { 2 };  // odr = 1000 Hz and lpf = 250 Hz
    const type ODR_500_Hz    = { 3 };  // odr = 500 Hz and lpf = 125 Hz
    const type ODR_250_Hz    = { 4 };  // odr = 250 Hz and lpf = 62.5 Hz
    const type ODR_125_Hz    = { 5 };  // odr = 125 Hz and lpf = 31.25 Hz
    const type ODR_62_5_Hz   = { 6 };  // odr = 62.5 Hz and lpf = 15.625 Hz
    const type ODR_31_25_Hz  = { 7 };  // odr = 31.25 Hz and lpf = 7.813 Hz
    const type ODR_15_625_Hz = { 8 };  // odr = 15.625 Hz and lpf = 3.906
    const type ODR_7_813_Hz  = { 9 };  // odr = 7.813 Hz and lpf = 1.953 Hz
    const type ODR_3_906_Hz  = { 10 }; // odr = 3.906 Hz and lpf = 0.977 Hz
  }

  namespace HPF {
    struct type {
      uint8_t code;
    };
    const type NO_HPF      = { 0 }; // no high pass filter
    const type _247_ODR    = { 1 }; // corner freq = 247  10^3  ODR
    const type _62_084_ODR = { 2 }; // corner freq = 62.048  10^3  ODR
    const type _15_545_ODR = { 3 }; // corner freq = 15.454  10^3  ODR
    const type _3_862_ODR  = { 4 }; // corner freq = 3.862  10^3  ODR
    const type _0_954_ODR  = { 5 }; // corner freq = 0.954  10^3  ODR
    const type _0_238_ODR  = { 6 }; // corner freq = 0.238  10^3  ODR
  }


  class Adxl355 {
  public:
    Adxl355(SPIClass *spi, uint32_t cs, uint32_t spiFreq = 10000000)
    :spi(spi), cs(cs), spiFreq(spiFreq) {}

    void begin();
    void resetSpi(); // reset spi settings to this objects config
    void wakeup();
    void sleep();
    void setRange(Range::type range);
    void setODR(ODR::type odr);
    void setHPF(HPF::type hpf);

    uint8_t readByte(uint32_t addr);
    void readBytes(uint32_t addr, uint8_t *bytes, size_t len);
    void writeByte(uint32_t addr, uint8_t byte);
    void writeBytes(uint32_t addr, uint8_t *bytes, size_t len);
    void updateT();
    void updateXyz();
    void updateTxyz();

    float x;
    float y;
    float z;
    float temp;

  private:
    SPIClass *spi;
    uint32_t cs;
    uint32_t spiFreq;
    
    Range::type range = Range::_2G;
    ODR::type odr = ODR::ODR_4000_Hz;
    HPF::type hpf = HPF::NO_HPF;
  };

  void Adxl355::begin() {
    pinMode(cs, OUTPUT);
    digitalWrite(cs, HIGH);

    spi->beginTransaction(SPISettings(spiFreq, MSBFIRST, SPI_MODE0));
  }

  void Adxl355::resetSpi() {
    spi->beginTransaction(SPISettings(spiFreq, MSBFIRST, SPI_MODE0));
  }

  void Adxl355::wakeup() {
    writeByte(Reg::POWER_CTL, 0);
  }

  void Adxl355::sleep() {
    writeByte(Reg::POWER_CTL, 1);
  }

  void Adxl355::setRange(Range::type range) {
    this->range = range;
    writeByte(Reg::RANGE, range.code);
  }

  void Adxl355::setODR(ODR::type odr) {
    this->odr = odr;
    uint8_t byte = (this->hpf.code & 0x07) << 4 | (this->odr.code & 0x0F);
    writeByte(Reg::FILTER, byte);
  }

  void Adxl355::setHPF(HPF::type hpf) {
    this->hpf = hpf;
    uint8_t byte = (this->hpf.code & 0x07) << 4 | (this->odr.code & 0x0F);
    writeByte(Reg::FILTER, byte);
  }

  uint8_t Adxl355::readByte(uint32_t addr) {
    uint8_t bytes[] = {(addr << 1) | SPI_R, 0};
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 2);
    digitalWrite(cs, HIGH);
    return bytes[1];
  }

  void Adxl355::readBytes(uint32_t addr, uint8_t *bytes, size_t len) {
    bytes[0] = (addr << 1) | SPI_R;
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 12);
    digitalWrite(cs, HIGH);
  }

  void Adxl355::writeByte(uint32_t addr, uint8_t byte) {
    uint8_t bytes[] = {(addr << 1) | SPI_W, byte};
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 2);
    digitalWrite(cs, HIGH);
  }

  void Adxl355::writeBytes(uint32_t addr, uint8_t *bytes, size_t len) {
    return;
  }

  void Adxl355::updateTxyz() {

    uint8_t bytes[12];
    readBytes(Reg::TEMP2, bytes, 12);

    int16_t temp = int16_t(bytes[1]) << 8 | bytes[2];
    
    int32_t x = ((int32_t(bytes[3]) << 24) | (int32_t(bytes[4])  << 16) | int32_t(bytes[5]  & 0xF0) << 8) >> 12;
    int32_t y = ((int32_t(bytes[6]) << 24) | (int32_t(bytes[7])  << 16) | int32_t(bytes[8]  & 0xF0) << 8) >> 12;
    int32_t z = ((int32_t(bytes[9]) << 24) | (int32_t(bytes[10]) << 16) | int32_t(bytes[11] & 0xF0) << 8) >> 12;

    this->temp = ((temp - 1852) / (-9.05)) + 25; // below is simplified version of this line
    // this->temp = temp / -9.05 + 229.640883978;
    
    this->x = float(x) / range.coef;
    this->y = float(y) / range.coef;
    this->z = float(z) / range.coef;
  }

  void Adxl355::updateXyz() {

    uint8_t bytes[10];
    readBytes(Reg::XDATA3, bytes, 10);

    int32_t x = ((int32_t(bytes[1]) << 24) | (int32_t(bytes[2]) << 16) | int32_t(bytes[3] & 0xF0) << 8) >> 12;
    int32_t y = ((int32_t(bytes[4]) << 24) | (int32_t(bytes[5]) << 16) | int32_t(bytes[6] & 0xF0) << 8) >> 12;
    int32_t z = ((int32_t(bytes[7]) << 24) | (int32_t(bytes[8]) << 16) | int32_t(bytes[9] & 0xF0) << 8) >> 12;

    this->x = float(x) / range.coef;
    this->y = float(y) / range.coef;
    this->z = float(z) / range.coef;
  }

  void Adxl355::updateT() {

    uint8_t bytes[2];
    readBytes(Reg::TEMP2, bytes, 2);

    int16_t temp = int16_t(bytes[1]) << 8 | bytes[2];

    this->temp = ((temp - 1852) / (-9.05)) + 25; // below is simplified version of this line
    // this->temp = temp / -9.05 + 229.640883978;
  }

} // namespace Adxl355

using namespace Adxl355;

#define CS PC5  //Chip Select Pin
Adxl355::Adxl355 adxl (&SPI, CS);

void setup() {
    Serial.begin(115200);

    adxl.begin();
    adxl.setRange(Range::_8G);
    adxl.setHPF(HPF::NO_HPF);
    adxl.setODR(ODR::ODR_2000_Hz);
    adxl.wakeup();
}

void loop() {
    adxl.updateTxyz();

    int id = adxl.readByte(Reg::DEVID);
    Serial.print(id, HEX); Serial.print(" ");
    Serial.print(adxl.x); Serial.print(" ");
    Serial.print(adxl.y); Serial.print(" ");
    Serial.print(adxl.z); Serial.println("");
}

Continuous Riding Data Collection

C/C++
This project is used to collect the riding data continuously. I used it while riding my scooter on the roads of Bangalore.
#include <Arduino.h>
#include <SPI.h>
#include <Notecard.h>
#include "Wire.h"

#define productUID "com.gmail.sobhitpanda25:helmet"
Notecard notecard;

unsigned long prevtime, currtime;

namespace Adxl355 {

  const char SPI_W = 0;
  const char SPI_R = 1;

  enum Reg {
    DEVID_AD = 0x00,
    DEVID_MST = 0x01,
    DEVID = 0x02,  
    REVID = 0x03,
    STATUS = 0x04,
    FIFO_ENTRIES = 0x05,
    TEMP2 = 0x06,
    TEMP1 = 0x07,
    XDATA3 = 0x08,
    XDATA2 = 0x09,
    XDATA1 = 0x0A,
    YDATA3 = 0x0B,
    YDATA2 = 0x0C,
    YDATA1 = 0x0D,
    ZDATA3 = 0x0E,
    ZDATA2 = 0x0F,
    ZDATA1 = 0x10,
    FIFO_DATA = 0x11,
    OFFSET_X_H = 0x1E,
    OFFSET_X_L = 0x1F,
    OFFSET_Y_H = 0x20,
    OFFSET_Y_L = 0x21,
    OFFSET_Z_H = 0x22,
    OFFSET_Z_L = 0x23,
    ACT_EN = 0x24,
    ACT_THRESH_H = 0x25,
    ACT_THRESH_L = 0x26,
    ACT_COUNT =  0x27,
    FILTER = 0x28,
    FIFO_SAMPLES = 0x29,
    INT_MAP = 0x2A,
    SYNC = 0x2B,
    RANGE = 0x2C,
    POWER_CTL = 0x2D,
    SELF_TEST = 0x2E,
    RESET = 0x2F
  };

  namespace Range {
    struct type {
      uint8_t code;
      double coef;
    };
    const type _2G = { 0b01, 256000.0 };
    const type _4G = { 0b10, 128000.0 };
    const type _8G = { 0b11, 64000.0  };
  }


  namespace ODR {
    struct type {
      uint8_t code;
    };
    const type ODR_4000_Hz   = { 0 };  // odr = 4000 Hz and lpf = 1000 Hz
    const type ODR_2000_Hz   = { 1 };  // odr = 2000 Hz and lpf = 500 Hz
    const type ODR_1000_Hz   = { 2 };  // odr = 1000 Hz and lpf = 250 Hz
    const type ODR_500_Hz    = { 3 };  // odr = 500 Hz and lpf = 125 Hz
    const type ODR_250_Hz    = { 4 };  // odr = 250 Hz and lpf = 62.5 Hz
    const type ODR_125_Hz    = { 5 };  // odr = 125 Hz and lpf = 31.25 Hz
    const type ODR_62_5_Hz   = { 6 };  // odr = 62.5 Hz and lpf = 15.625 Hz
    const type ODR_31_25_Hz  = { 7 };  // odr = 31.25 Hz and lpf = 7.813 Hz
    const type ODR_15_625_Hz = { 8 };  // odr = 15.625 Hz and lpf = 3.906
    const type ODR_7_813_Hz  = { 9 };  // odr = 7.813 Hz and lpf = 1.953 Hz
    const type ODR_3_906_Hz  = { 10 }; // odr = 3.906 Hz and lpf = 0.977 Hz
  }

  namespace HPF {
    struct type {
      uint8_t code;
    };
    const type NO_HPF      = { 0 }; // no high pass filter
    const type _247_ODR    = { 1 }; // corner freq = 247  10^3  ODR
    const type _62_084_ODR = { 2 }; // corner freq = 62.048  10^3  ODR
    const type _15_545_ODR = { 3 }; // corner freq = 15.454  10^3  ODR
    const type _3_862_ODR  = { 4 }; // corner freq = 3.862  10^3  ODR
    const type _0_954_ODR  = { 5 }; // corner freq = 0.954  10^3  ODR
    const type _0_238_ODR  = { 6 }; // corner freq = 0.238  10^3  ODR
  }


  class Adxl355 {
  public:
    Adxl355(SPIClass *spi, uint32_t cs, uint32_t spiFreq = 10000000)
    :spi(spi), cs(cs), spiFreq(spiFreq) {}

    void begin();
    void resetSpi(); // reset spi settings to this objects config
    void wakeup();
    void sleep();
    void setRange(Range::type range);
    void setODR(ODR::type odr);
    void setHPF(HPF::type hpf);

    uint8_t readByte(uint32_t addr);
    void readBytes(uint32_t addr, uint8_t *bytes, size_t len);
    void writeByte(uint32_t addr, uint8_t byte);
    void writeBytes(uint32_t addr, uint8_t *bytes, size_t len);
    void updateT();
    void updateXyz();
    void updateTxyz();

    float x;
    float y;
    float z;
    float temp;

  private:
    SPIClass *spi;
    uint32_t cs;
    uint32_t spiFreq;
    
    Range::type range = Range::_2G;
    ODR::type odr = ODR::ODR_4000_Hz;
    HPF::type hpf = HPF::NO_HPF;
  };

  void Adxl355::begin() {
    pinMode(cs, OUTPUT);
    digitalWrite(cs, HIGH);

    spi->beginTransaction(SPISettings(spiFreq, MSBFIRST, SPI_MODE0));
  }

  void Adxl355::resetSpi() {
    spi->beginTransaction(SPISettings(spiFreq, MSBFIRST, SPI_MODE0));
  }

  void Adxl355::wakeup() {
    writeByte(Reg::POWER_CTL, 0);
  }

  void Adxl355::sleep() {
    writeByte(Reg::POWER_CTL, 1);
  }

  void Adxl355::setRange(Range::type range) {
    this->range = range;
    writeByte(Reg::RANGE, range.code);
  }

  void Adxl355::setODR(ODR::type odr) {
    this->odr = odr;
    uint8_t byte = (this->hpf.code & 0x07) << 4 | (this->odr.code & 0x0F);
    writeByte(Reg::FILTER, byte);
  }

  void Adxl355::setHPF(HPF::type hpf) {
    this->hpf = hpf;
    uint8_t byte = (this->hpf.code & 0x07) << 4 | (this->odr.code & 0x0F);
    writeByte(Reg::FILTER, byte);
  }

  uint8_t Adxl355::readByte(uint32_t addr) {
    uint8_t bytes[] = {(addr << 1) | SPI_R, 0};
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 2);
    digitalWrite(cs, HIGH);
    return bytes[1];
  }

  void Adxl355::readBytes(uint32_t addr, uint8_t *bytes, size_t len) {
    bytes[0] = (addr << 1) | SPI_R;
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 12);
    digitalWrite(cs, HIGH);
  }

  void Adxl355::writeByte(uint32_t addr, uint8_t byte) {
    uint8_t bytes[] = {(addr << 1) | SPI_W, byte};
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 2);
    digitalWrite(cs, HIGH);
  }

  void Adxl355::writeBytes(uint32_t addr, uint8_t *bytes, size_t len) {
    return;
  }

  void Adxl355::updateTxyz() {

    uint8_t bytes[12];
    readBytes(Reg::TEMP2, bytes, 12);

    int16_t temp = int16_t(bytes[1]) << 8 | bytes[2];
    
    int32_t x = ((int32_t(bytes[3]) << 24) | (int32_t(bytes[4])  << 16) | int32_t(bytes[5]  & 0xF0) << 8) >> 12;
    int32_t y = ((int32_t(bytes[6]) << 24) | (int32_t(bytes[7])  << 16) | int32_t(bytes[8]  & 0xF0) << 8) >> 12;
    int32_t z = ((int32_t(bytes[9]) << 24) | (int32_t(bytes[10]) << 16) | int32_t(bytes[11] & 0xF0) << 8) >> 12;

    this->temp = ((temp - 1852) / (-9.05)) + 25; // below is simplified version of this line
    // this->temp = temp / -9.05 + 229.640883978;
    
    this->x = float(x) / range.coef;
    this->y = float(y) / range.coef;
    this->z = float(z) / range.coef;
  }

  void Adxl355::updateXyz() {

    uint8_t bytes[10];
    readBytes(Reg::XDATA3, bytes, 10);

    int32_t x = ((int32_t(bytes[1]) << 24) | (int32_t(bytes[2]) << 16) | int32_t(bytes[3] & 0xF0) << 8) >> 12;
    int32_t y = ((int32_t(bytes[4]) << 24) | (int32_t(bytes[5]) << 16) | int32_t(bytes[6] & 0xF0) << 8) >> 12;
    int32_t z = ((int32_t(bytes[7]) << 24) | (int32_t(bytes[8]) << 16) | int32_t(bytes[9] & 0xF0) << 8) >> 12;

    this->x = float(x) / range.coef;
    this->y = float(y) / range.coef;
    this->z = float(z) / range.coef;
  }

  void Adxl355::updateT() {

    uint8_t bytes[2];
    readBytes(Reg::TEMP2, bytes, 2);

    int16_t temp = int16_t(bytes[1]) << 8 | bytes[2];

    this->temp = ((temp - 1852) / (-9.05)) + 25; // below is simplified version of this line
    // this->temp = temp / -9.05 + 229.640883978;
  }

} // namespace Adxl355

using namespace Adxl355;

#define CS PC5
Adxl355::Adxl355 adxl (&SPI, CS);

void setup() {
  pinMode(USER_BTN, INPUT);

  notecard.begin();
  Serial.begin(115200);
  notecard.setDebugOutputStream(Serial);
  Serial.println("Notecard running");

  adxl.begin();
  adxl.setRange(Range::_2G);
  adxl.setHPF(HPF::NO_HPF);
  adxl.setODR(ODR::ODR_2000_Hz);
  adxl.wakeup();

  J *req = notecard.newRequest("hub.set");
  JAddStringToObject(req, "product", productUID);
  JAddStringToObject(req, "mode", "continuous");
  notecard.sendRequest(req);
  
  delay(10000);
}

void loop() {
  int id, xdata,ydata,zdata;

  if(digitalRead(USER_BTN) == 0){
    delay(120000);
    while(1){
      J *req = notecard.newRequest("note.add");
      if (req != NULL)
      {
        JAddStringToObject(req, "file", "sensors.qo");
        JAddBoolToObject(req, "sync", true);
        J *body = JAddObjectToObject(req, "body");
    
        if(body)
        {
          J *values = JAddArrayToObject(body, "values");
          currtime = micros();
          for(int i=0;i<500;i++){
            adxl.updateTxyz();
            prevtime = currtime;
            id = adxl.readByte(Reg::DEVID);
            xdata = adxl.x * 100;
            ydata = adxl.y * 100;
            zdata = adxl.z * 100;
    
            double num[] = {xdata,ydata,zdata}; 
            JAddItemToArray(values, JCreateNumberArray(num, 3));
            currtime = micros();
            while((currtime-prevtime) <= 10000){
              currtime = micros();
            }
          }
        }
        notecard.sendRequest(req);
        Serial.println("not null");
      }
    }
  }
  
}

Inferencing at the Edge

C/C++
This is to test the Edge Impulse library generated and inferencing at the Edge.
/* Includes ---------------------------------------------------------------- */
#include <Blues_test_inferencing.h>

/* Private variables ------------------------------------------------------- */
static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal

#include <Arduino.h>
#include <SPI.h>
#include <Notecard.h>
#include "Wire.h"

#define productUID "com.gmail.sobhitpanda25:helmet"
Notecard notecard;

unsigned long prevtime, currtime;

namespace Adxl355 {

  const char SPI_W = 0;
  const char SPI_R = 1;

  enum Reg {
    DEVID_AD = 0x00,
    DEVID_MST = 0x01,
    DEVID = 0x02,  
    REVID = 0x03,
    STATUS = 0x04,
    FIFO_ENTRIES = 0x05,
    TEMP2 = 0x06,
    TEMP1 = 0x07,
    XDATA3 = 0x08,
    XDATA2 = 0x09,
    XDATA1 = 0x0A,
    YDATA3 = 0x0B,
    YDATA2 = 0x0C,
    YDATA1 = 0x0D,
    ZDATA3 = 0x0E,
    ZDATA2 = 0x0F,
    ZDATA1 = 0x10,
    FIFO_DATA = 0x11,
    OFFSET_X_H = 0x1E,
    OFFSET_X_L = 0x1F,
    OFFSET_Y_H = 0x20,
    OFFSET_Y_L = 0x21,
    OFFSET_Z_H = 0x22,
    OFFSET_Z_L = 0x23,
    ACT_EN = 0x24,
    ACT_THRESH_H = 0x25,
    ACT_THRESH_L = 0x26,
    ACT_COUNT =  0x27,
    FILTER = 0x28,
    FIFO_SAMPLES = 0x29,
    INT_MAP = 0x2A,
    SYNC = 0x2B,
    RANGE = 0x2C,
    POWER_CTL = 0x2D,
    SELF_TEST = 0x2E,
    RESET = 0x2F
  };

  namespace Range {
    struct type {
      uint8_t code;
      double coef;
    };
    const type _2G = { 0b01, 256000.0 };
    const type _4G = { 0b10, 128000.0 };
    const type _8G = { 0b11, 64000.0  };
  }


  namespace ODR {
    struct type {
      uint8_t code;
    };
    const type ODR_4000_Hz   = { 0 };  // odr = 4000 Hz and lpf = 1000 Hz
    const type ODR_2000_Hz   = { 1 };  // odr = 2000 Hz and lpf = 500 Hz
    const type ODR_1000_Hz   = { 2 };  // odr = 1000 Hz and lpf = 250 Hz
    const type ODR_500_Hz    = { 3 };  // odr = 500 Hz and lpf = 125 Hz
    const type ODR_250_Hz    = { 4 };  // odr = 250 Hz and lpf = 62.5 Hz
    const type ODR_125_Hz    = { 5 };  // odr = 125 Hz and lpf = 31.25 Hz
    const type ODR_62_5_Hz   = { 6 };  // odr = 62.5 Hz and lpf = 15.625 Hz
    const type ODR_31_25_Hz  = { 7 };  // odr = 31.25 Hz and lpf = 7.813 Hz
    const type ODR_15_625_Hz = { 8 };  // odr = 15.625 Hz and lpf = 3.906
    const type ODR_7_813_Hz  = { 9 };  // odr = 7.813 Hz and lpf = 1.953 Hz
    const type ODR_3_906_Hz  = { 10 }; // odr = 3.906 Hz and lpf = 0.977 Hz
  }

  namespace HPF {
    struct type {
      uint8_t code;
    };
    const type NO_HPF      = { 0 }; // no high pass filter
    const type _247_ODR    = { 1 }; // corner freq = 247  10^3  ODR
    const type _62_084_ODR = { 2 }; // corner freq = 62.048  10^3  ODR
    const type _15_545_ODR = { 3 }; // corner freq = 15.454  10^3  ODR
    const type _3_862_ODR  = { 4 }; // corner freq = 3.862  10^3  ODR
    const type _0_954_ODR  = { 5 }; // corner freq = 0.954  10^3  ODR
    const type _0_238_ODR  = { 6 }; // corner freq = 0.238  10^3  ODR
  }


  class Adxl355 {
  public:
    Adxl355(SPIClass *spi, uint32_t cs, uint32_t spiFreq = 10000000)
    :spi(spi), cs(cs), spiFreq(spiFreq) {}

    void begin();
    void resetSpi(); // reset spi settings to this objects config
    void wakeup();
    void sleep();
    void setRange(Range::type range);
    void setODR(ODR::type odr);
    void setHPF(HPF::type hpf);

    uint8_t readByte(uint32_t addr);
    void readBytes(uint32_t addr, uint8_t *bytes, size_t len);
    void writeByte(uint32_t addr, uint8_t byte);
    void writeBytes(uint32_t addr, uint8_t *bytes, size_t len);
    void updateT();
    void updateXyz();
    void updateTxyz();

    float x;
    float y;
    float z;
    float temp;

  private:
    SPIClass *spi;
    uint32_t cs;
    uint32_t spiFreq;
    
    Range::type range = Range::_2G;
    ODR::type odr = ODR::ODR_4000_Hz;
    HPF::type hpf = HPF::NO_HPF;
  };

  void Adxl355::begin() {
    pinMode(cs, OUTPUT);
    digitalWrite(cs, HIGH);

    spi->beginTransaction(SPISettings(spiFreq, MSBFIRST, SPI_MODE0));
  }

  void Adxl355::resetSpi() {
    spi->beginTransaction(SPISettings(spiFreq, MSBFIRST, SPI_MODE0));
  }

  void Adxl355::wakeup() {
    writeByte(Reg::POWER_CTL, 0);
  }

  void Adxl355::sleep() {
    writeByte(Reg::POWER_CTL, 1);
  }

  void Adxl355::setRange(Range::type range) {
    this->range = range;
    writeByte(Reg::RANGE, range.code);
  }

  void Adxl355::setODR(ODR::type odr) {
    this->odr = odr;
    uint8_t byte = (this->hpf.code & 0x07) << 4 | (this->odr.code & 0x0F);
    writeByte(Reg::FILTER, byte);
  }

  void Adxl355::setHPF(HPF::type hpf) {
    this->hpf = hpf;
    uint8_t byte = (this->hpf.code & 0x07) << 4 | (this->odr.code & 0x0F);
    writeByte(Reg::FILTER, byte);
  }

  uint8_t Adxl355::readByte(uint32_t addr) {
    uint8_t bytes[] = {(addr << 1) | SPI_R, 0};
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 2);
    digitalWrite(cs, HIGH);
    return bytes[1];
  }

  void Adxl355::readBytes(uint32_t addr, uint8_t *bytes, size_t len) {
    bytes[0] = (addr << 1) | SPI_R;
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 12);
    digitalWrite(cs, HIGH);
  }

  void Adxl355::writeByte(uint32_t addr, uint8_t byte) {
    uint8_t bytes[] = {(addr << 1) | SPI_W, byte};
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 2);
    digitalWrite(cs, HIGH);
  }

  void Adxl355::writeBytes(uint32_t addr, uint8_t *bytes, size_t len) {
    return;
  }

  void Adxl355::updateTxyz() {

    uint8_t bytes[12];
    readBytes(Reg::TEMP2, bytes, 12);

    int16_t temp = int16_t(bytes[1]) << 8 | bytes[2];
    
    int32_t x = ((int32_t(bytes[3]) << 24) | (int32_t(bytes[4])  << 16) | int32_t(bytes[5]  & 0xF0) << 8) >> 12;
    int32_t y = ((int32_t(bytes[6]) << 24) | (int32_t(bytes[7])  << 16) | int32_t(bytes[8]  & 0xF0) << 8) >> 12;
    int32_t z = ((int32_t(bytes[9]) << 24) | (int32_t(bytes[10]) << 16) | int32_t(bytes[11] & 0xF0) << 8) >> 12;

    this->temp = ((temp - 1852) / (-9.05)) + 25; // below is simplified version of this line
    // this->temp = temp / -9.05 + 229.640883978;
    
    this->x = float(x) / range.coef;
    this->y = float(y) / range.coef;
    this->z = float(z) / range.coef;
  }

  void Adxl355::updateXyz() {

    uint8_t bytes[10];
    readBytes(Reg::XDATA3, bytes, 10);

    int32_t x = ((int32_t(bytes[1]) << 24) | (int32_t(bytes[2]) << 16) | int32_t(bytes[3] & 0xF0) << 8) >> 12;
    int32_t y = ((int32_t(bytes[4]) << 24) | (int32_t(bytes[5]) << 16) | int32_t(bytes[6] & 0xF0) << 8) >> 12;
    int32_t z = ((int32_t(bytes[7]) << 24) | (int32_t(bytes[8]) << 16) | int32_t(bytes[9] & 0xF0) << 8) >> 12;

    this->x = float(x) / range.coef;
    this->y = float(y) / range.coef;
    this->z = float(z) / range.coef;
  }

  void Adxl355::updateT() {

    uint8_t bytes[2];
    readBytes(Reg::TEMP2, bytes, 2);

    int16_t temp = int16_t(bytes[1]) << 8 | bytes[2];

    this->temp = ((temp - 1852) / (-9.05)) + 25; // below is simplified version of this line
    // this->temp = temp / -9.05 + 229.640883978;
  }

} // namespace Adxl355

using namespace Adxl355;

#define CS PC5
Adxl355::Adxl355 adxl (&SPI, CS);

/**
* @brief      Arduino setup function
*/
void setup()
{
  pinMode(USER_BTN , INPUT);

  notecard.begin();
  Serial.begin(115200);
  notecard.setDebugOutputStream(Serial);
  Serial.println("Notecard running");

  adxl.begin();
  adxl.setRange(Range::_2G);
  adxl.setHPF(HPF::NO_HPF);
  adxl.setODR(ODR::ODR_2000_Hz);
  adxl.wakeup();
  Serial.println("IMU running");

  J *req = notecard.newRequest("hub.set");
  JAddStringToObject(req, "product", productUID);
  JAddStringToObject(req, "mode", "continuous");
  notecard.sendRequest(req);

  if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != 3) {
      ei_printf("ERR: EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME should be equal to 3 (the 3 sensor axes)\n");
      return;
  }
}

/**
 * @brief Return the sign of the number
 * 
 * @param number 
 * @return int 1 if positive (or 0) -1 if negative
 */
float ei_get_sign(float number) {
    return (number >= 0.0) ? 1.0 : -1.0;
}

/**
* @brief      Get data and run inferencing
*
* @param[in]  debug  Get debug info if true
*/
void loop()
{
    ei_printf("\nStarting inferencing in 2 seconds...\n");

    delay(2000);

    ei_printf("Sampling...\n");

    // Allocate a buffer here for the values we'll read from the IMU
    float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 };

    for (size_t ix = 0; ix < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; ix += 3) {
        // Determine the next tick (and then sleep later)
        uint64_t next_tick = micros() + (EI_CLASSIFIER_INTERVAL_MS * 1000);

        adxl.updateTxyz();
        buffer[ix] = adxl.x * 100;
        buffer[ix + 1] = adxl.y * 100;
        buffer[ix + 2] = adxl.z * 100;

        delayMicroseconds(next_tick - micros());
    }

    // Turn the raw buffer in a signal which we can the classify
    signal_t signal;
    int err = numpy::signal_from_buffer(buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal);
    if (err != 0) {
        ei_printf("Failed to create signal from buffer (%d)", err);
        Serial.println("");
        return;
    }

    // Run the classifier
    ei_impulse_result_t result = { 0 };

    err = run_classifier(&signal, &result, debug_nn);
    if (err != EI_IMPULSE_OK) {
        ei_printf("ERR: Failed to run classifier (%d)", err);
        Serial.println("");
        return;
    }

    // print the predictions
    ei_printf("Predictions ");
    ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
        result.timing.dsp, result.timing.classification, result.timing.anomaly);
    ei_printf(": \n");
    Serial.println("");
    for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
    //    ei_printf_float("    %s: %.5f\n", result.classification[ix].label, result.classification[ix].value);
    ei_printf("%s:",result.classification[ix].label);
    ei_printf_float(result.classification[ix].value);
        Serial.println("");
    }
#if EI_CLASSIFIER_HAS_ANOMALY == 1
    ei_printf_float("    anomaly score: %.3f\n", result.anomaly);
    Serial.println("");
#endif
}

#if !defined(EI_CLASSIFIER_SENSOR) || EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_ACCELEROMETER
#error "Invalid model for current sensor"
#endif

SOS Alert Twilio + GPS Location

C/C++
To detect crashes and send an SOS Alert with GPS Location.
/* Includes ---------------------------------------------------------------- */
#include <Blues_test_inferencing.h>
#include <Arduino.h>
#include <SPI.h>
#include <Notecard.h>
#include "Wire.h"
#include "string.h"

/* Private variables ------------------------------------------------------- */
static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal

#define CS PC5
size_t gps_time_s;

using namespace std;

#define productUID "com.gmail.sobhitpanda25:helmet"
Notecard notecard;

unsigned long prevtime, currtime;

namespace Adxl355 {

  const char SPI_W = 0;
  const char SPI_R = 1;

  enum Reg {
    DEVID_AD = 0x00,
    DEVID_MST = 0x01,
    DEVID = 0x02,  
    REVID = 0x03,
    STATUS = 0x04,
    FIFO_ENTRIES = 0x05,
    TEMP2 = 0x06,
    TEMP1 = 0x07,
    XDATA3 = 0x08,
    XDATA2 = 0x09,
    XDATA1 = 0x0A,
    YDATA3 = 0x0B,
    YDATA2 = 0x0C,
    YDATA1 = 0x0D,
    ZDATA3 = 0x0E,
    ZDATA2 = 0x0F,
    ZDATA1 = 0x10,
    FIFO_DATA = 0x11,
    OFFSET_X_H = 0x1E,
    OFFSET_X_L = 0x1F,
    OFFSET_Y_H = 0x20,
    OFFSET_Y_L = 0x21,
    OFFSET_Z_H = 0x22,
    OFFSET_Z_L = 0x23,
    ACT_EN = 0x24,
    ACT_THRESH_H = 0x25,
    ACT_THRESH_L = 0x26,
    ACT_COUNT =  0x27,
    FILTER = 0x28,
    FIFO_SAMPLES = 0x29,
    INT_MAP = 0x2A,
    SYNC = 0x2B,
    RANGE = 0x2C,
    POWER_CTL = 0x2D,
    SELF_TEST = 0x2E,
    RESET = 0x2F
  };

  namespace Range {
    struct type {
      uint8_t code;
      double coef;
    };
    const type _2G = { 0b01, 256000.0 };
    const type _4G = { 0b10, 128000.0 };
    const type _8G = { 0b11, 64000.0  };
  }


  namespace ODR {
    struct type {
      uint8_t code;
    };
    const type ODR_4000_Hz   = { 0 };  // odr = 4000 Hz and lpf = 1000 Hz
    const type ODR_2000_Hz   = { 1 };  // odr = 2000 Hz and lpf = 500 Hz
    const type ODR_1000_Hz   = { 2 };  // odr = 1000 Hz and lpf = 250 Hz
    const type ODR_500_Hz    = { 3 };  // odr = 500 Hz and lpf = 125 Hz
    const type ODR_250_Hz    = { 4 };  // odr = 250 Hz and lpf = 62.5 Hz
    const type ODR_125_Hz    = { 5 };  // odr = 125 Hz and lpf = 31.25 Hz
    const type ODR_62_5_Hz   = { 6 };  // odr = 62.5 Hz and lpf = 15.625 Hz
    const type ODR_31_25_Hz  = { 7 };  // odr = 31.25 Hz and lpf = 7.813 Hz
    const type ODR_15_625_Hz = { 8 };  // odr = 15.625 Hz and lpf = 3.906
    const type ODR_7_813_Hz  = { 9 };  // odr = 7.813 Hz and lpf = 1.953 Hz
    const type ODR_3_906_Hz  = { 10 }; // odr = 3.906 Hz and lpf = 0.977 Hz
  }

  namespace HPF {
    struct type {
      uint8_t code;
    };
    const type NO_HPF      = { 0 }; // no high pass filter
    const type _247_ODR    = { 1 }; // corner freq = 247  10^3  ODR
    const type _62_084_ODR = { 2 }; // corner freq = 62.048  10^3  ODR
    const type _15_545_ODR = { 3 }; // corner freq = 15.454  10^3  ODR
    const type _3_862_ODR  = { 4 }; // corner freq = 3.862  10^3  ODR
    const type _0_954_ODR  = { 5 }; // corner freq = 0.954  10^3  ODR
    const type _0_238_ODR  = { 6 }; // corner freq = 0.238  10^3  ODR
  }


  class Adxl355 {
  public:
    Adxl355(SPIClass *spi, uint32_t cs, uint32_t spiFreq = 10000000)
    :spi(spi), cs(cs), spiFreq(spiFreq) {}

    void begin();
    void resetSpi(); // reset spi settings to this objects config
    void wakeup();
    void sleep();
    void setRange(Range::type range);
    void setODR(ODR::type odr);
    void setHPF(HPF::type hpf);

    uint8_t readByte(uint32_t addr);
    void readBytes(uint32_t addr, uint8_t *bytes, size_t len);
    void writeByte(uint32_t addr, uint8_t byte);
    void writeBytes(uint32_t addr, uint8_t *bytes, size_t len);
    void updateT();
    void updateXyz();
    void updateTxyz();

    float x;
    float y;
    float z;
    float temp;

  private:
    SPIClass *spi;
    uint32_t cs;
    uint32_t spiFreq;
    
    Range::type range = Range::_2G;
    ODR::type odr = ODR::ODR_4000_Hz;
    HPF::type hpf = HPF::NO_HPF;
  };

  void Adxl355::begin() {
    pinMode(cs, OUTPUT);
    digitalWrite(cs, HIGH);

    spi->beginTransaction(SPISettings(spiFreq, MSBFIRST, SPI_MODE0));
  }

  void Adxl355::resetSpi() {
    spi->beginTransaction(SPISettings(spiFreq, MSBFIRST, SPI_MODE0));
  }

  void Adxl355::wakeup() {
    writeByte(Reg::POWER_CTL, 0);
  }

  void Adxl355::sleep() {
    writeByte(Reg::POWER_CTL, 1);
  }

  void Adxl355::setRange(Range::type range) {
    this->range = range;
    writeByte(Reg::RANGE, range.code);
  }

  void Adxl355::setODR(ODR::type odr) {
    this->odr = odr;
    uint8_t byte = (this->hpf.code & 0x07) << 4 | (this->odr.code & 0x0F);
    writeByte(Reg::FILTER, byte);
  }

  void Adxl355::setHPF(HPF::type hpf) {
    this->hpf = hpf;
    uint8_t byte = (this->hpf.code & 0x07) << 4 | (this->odr.code & 0x0F);
    writeByte(Reg::FILTER, byte);
  }

  uint8_t Adxl355::readByte(uint32_t addr) {
    uint8_t bytes[] = {(addr << 1) | SPI_R, 0};
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 2);
    digitalWrite(cs, HIGH);
    return bytes[1];
  }

  void Adxl355::readBytes(uint32_t addr, uint8_t *bytes, size_t len) {
    bytes[0] = (addr << 1) | SPI_R;
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 12);
    digitalWrite(cs, HIGH);
  }

  void Adxl355::writeByte(uint32_t addr, uint8_t byte) {
    uint8_t bytes[] = {(addr << 1) | SPI_W, byte};
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 2);
    digitalWrite(cs, HIGH);
  }

  void Adxl355::writeBytes(uint32_t addr, uint8_t *bytes, size_t len) {
    return;
  }

  void Adxl355::updateTxyz() {

    uint8_t bytes[12];
    readBytes(Reg::TEMP2, bytes, 12);

    int16_t temp = int16_t(bytes[1]) << 8 | bytes[2];
    
    int32_t x = ((int32_t(bytes[3]) << 24) | (int32_t(bytes[4])  << 16) | int32_t(bytes[5]  & 0xF0) << 8) >> 12;
    int32_t y = ((int32_t(bytes[6]) << 24) | (int32_t(bytes[7])  << 16) | int32_t(bytes[8]  & 0xF0) << 8) >> 12;
    int32_t z = ((int32_t(bytes[9]) << 24) | (int32_t(bytes[10]) << 16) | int32_t(bytes[11] & 0xF0) << 8) >> 12;

    this->temp = ((temp - 1852) / (-9.05)) + 25; // below is simplified version of this line
    // this->temp = temp / -9.05 + 229.640883978;
    
    this->x = float(x) / range.coef;
    this->y = float(y) / range.coef;
    this->z = float(z) / range.coef;
  }

  void Adxl355::updateXyz() {

    uint8_t bytes[10];
    readBytes(Reg::XDATA3, bytes, 10);

    int32_t x = ((int32_t(bytes[1]) << 24) | (int32_t(bytes[2]) << 16) | int32_t(bytes[3] & 0xF0) << 8) >> 12;
    int32_t y = ((int32_t(bytes[4]) << 24) | (int32_t(bytes[5]) << 16) | int32_t(bytes[6] & 0xF0) << 8) >> 12;
    int32_t z = ((int32_t(bytes[7]) << 24) | (int32_t(bytes[8]) << 16) | int32_t(bytes[9] & 0xF0) << 8) >> 12;

    this->x = float(x) / range.coef;
    this->y = float(y) / range.coef;
    this->z = float(z) / range.coef;
  }

  void Adxl355::updateT() {

    uint8_t bytes[2];
    readBytes(Reg::TEMP2, bytes, 2);

    int16_t temp = int16_t(bytes[1]) << 8 | bytes[2];

    this->temp = ((temp - 1852) / (-9.05)) + 25; // below is simplified version of this line
    // this->temp = temp / -9.05 + 229.640883978;
  }

} // namespace Adxl355

using namespace Adxl355;
Adxl355::Adxl355 adxl (&SPI, CS);


/**
* @brief      Arduino setup function
*/
void setup()
{
  pinMode(USER_BTN , INPUT);

  notecard.begin();
  Serial.begin(115200);
  notecard.setDebugOutputStream(Serial);
  Serial.println("Notecard running");

  adxl.begin();
  adxl.setRange(Range::_2G);
  adxl.setHPF(HPF::NO_HPF);
  adxl.setODR(ODR::ODR_2000_Hz);
  adxl.wakeup();
  Serial.println("IMU running");

  J *req = notecard.newRequest("hub.set");
  JAddStringToObject(req, "product", productUID);
  JAddStringToObject(req, "mode", "periodic");
  notecard.sendRequest(req);

  req = notecard.newRequest("card.location.mode");
  JAddStringToObject(req, "mode", "periodic");
  JAddNumberToObject(req, "seconds", 3600);
  notecard.sendRequest(req);

  req = notecard.newRequest("card.location.track");
  JAddBoolToObject(req, "sync", true);
  JAddBoolToObject(req, "heartbeat", true);
  JAddNumberToObject(req, "hours", 12);
  notecard.sendRequest(req);

  J *rsp = notecard.requestAndResponse(notecard.newRequest("card.location"));
  gps_time_s = JGetInt(rsp, "time");
  NoteDeleteResponse(rsp);

  if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != 3) {
      ei_printf("ERR: EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME should be equal to 3 (the 3 sensor axes)\n");
      return;
  }
}

/**
 * @brief Return the sign of the number
 * 
 * @param number 
 * @return int 1 if positive (or 0) -1 if negative
 */
float ei_get_sign(float number) {
    return (number >= 0.0) ? 1.0 : -1.0;
}

/**
* @brief      Get data and run inferencing
*
* @param[in]  debug  Get debug info if true
*/
void loop()
{
  if(digitalRead(USER_BTN) == 0){
    ei_printf("\nStarting inferencing in 120 seconds...\n");

    delay(15000);

    ei_printf("Sampling...\n");

    // Allocate a buffer here for the values we'll read from the IMU
    float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 };

    for (size_t ix = 0; ix < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; ix += 3) {
        // Determine the next tick (and then sleep later)
        uint64_t next_tick = micros() + (EI_CLASSIFIER_INTERVAL_MS * 1000);

        adxl.updateTxyz();
        buffer[ix] = adxl.x * 100;
        buffer[ix + 1] = adxl.y * 100;
        buffer[ix + 2] = adxl.z * 100;

        delayMicroseconds(next_tick - micros());
    }

    // Turn the raw buffer in a signal which we can the classify
    signal_t signal;
    int err = numpy::signal_from_buffer(buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal);
    if (err != 0) {
        ei_printf("Failed to create signal from buffer (%d)", err);
        Serial.println("");
        return;
    }

    // Run the classifier
    ei_impulse_result_t result = { 0 };

    err = run_classifier(&signal, &result, debug_nn);
    if (err != EI_IMPULSE_OK) {
        ei_printf("ERR: Failed to run classifier (%d)", err);
        Serial.println("");
        return;
    }

    // print the predictions
    ei_printf("Predictions ");
    ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
        result.timing.dsp, result.timing.classification, result.timing.anomaly);
    ei_printf(": \n");
    Serial.println("");
    for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
    //    ei_printf_float("    %s: %.5f\n", result.classification[ix].label, result.classification[ix].value);
    ei_printf("%s:",result.classification[ix].label);
    ei_printf_float(result.classification[ix].value);
    Serial.println("");
    }



    double lat,lon;
    char arr[200];


    //Send the data to twilio if it is a crash
    if(result.classification[1].value > 0.8){
        J *req = notecard.newRequest("card.location.mode");
        JAddStringToObject(req, "mode", "continuous");
        notecard.sendRequest(req);

        // Block while waiting for a GPS/GNSS location
        for (;;)
        {
          // Get the latest location
          J *rsp = notecard.requestAndResponse(notecard.newRequest("card.location"));

          // See if the location has changed from the previous reading
          if (JGetInt(rsp, "time") != gps_time_s)
          {
            // If you get in here, you have a new reading.
            lat = JGetNumber(rsp, "lat");
            lon = JGetNumber(rsp, "lon");
            Serial.println(lat);
            Serial.println(lon);

            String t = "Its a crash! Send help to: http://maps.google.com/?q=" + String(lat, 6) + "," + String(lon, 6);
            strcpy(arr,t.c_str());
            Serial.println(t);
            Serial.println(arr);
            // This is where youd place your application-specific code to use the
            // new coordinates.
            NoteDeleteResponse(rsp);
            break;
          }
          NoteDeleteResponse(rsp);

          // Wait 2 seconds before trying again
          delay(2000);
        }
    }

    J *req = notecard.newRequest("note.add");
    if (req != NULL)
    {
      JAddStringToObject(req, "file", "twilio.qo");
      JAddBoolToObject(req, "sync", true);
      J *body = JAddObjectToObject(req, "body");

      if(body)
      {
        JAddStringToObject(body, "twilioBody", arr);
      }
      notecard.sendRequest(req);
    }






#if EI_CLASSIFIER_HAS_ANOMALY == 1
    ei_printf_float("    anomaly score: %.3f\n", result.anomaly);
    Serial.println("");
#endif

  }
}

#if !defined(EI_CLASSIFIER_SENSOR) || EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_ACCELEROMETER
#error "Invalid model for current sensor"
#endif

Data Collection Over the Air

C/C++
This project is to collect 5-second accelerometer data upload to the Notehub Cloud and route it to the Edge Impulse Training dataset upon a button press.
#include <Arduino.h>
#include <SPI.h>
#include <Notecard.h>
#include "Wire.h"

#define productUID "com.gmail.sobhitpanda25:helmet"
Notecard notecard;

unsigned long prevtime, currtime;

namespace Adxl355 {

  const char SPI_W = 0;
  const char SPI_R = 1;

  enum Reg {
    DEVID_AD = 0x00,
    DEVID_MST = 0x01,
    DEVID = 0x02,  
    REVID = 0x03,
    STATUS = 0x04,
    FIFO_ENTRIES = 0x05,
    TEMP2 = 0x06,
    TEMP1 = 0x07,
    XDATA3 = 0x08,
    XDATA2 = 0x09,
    XDATA1 = 0x0A,
    YDATA3 = 0x0B,
    YDATA2 = 0x0C,
    YDATA1 = 0x0D,
    ZDATA3 = 0x0E,
    ZDATA2 = 0x0F,
    ZDATA1 = 0x10,
    FIFO_DATA = 0x11,
    OFFSET_X_H = 0x1E,
    OFFSET_X_L = 0x1F,
    OFFSET_Y_H = 0x20,
    OFFSET_Y_L = 0x21,
    OFFSET_Z_H = 0x22,
    OFFSET_Z_L = 0x23,
    ACT_EN = 0x24,
    ACT_THRESH_H = 0x25,
    ACT_THRESH_L = 0x26,
    ACT_COUNT =  0x27,
    FILTER = 0x28,
    FIFO_SAMPLES = 0x29,
    INT_MAP = 0x2A,
    SYNC = 0x2B,
    RANGE = 0x2C,
    POWER_CTL = 0x2D,
    SELF_TEST = 0x2E,
    RESET = 0x2F
  };

  namespace Range {
    struct type {
      uint8_t code;
      double coef;
    };
    const type _2G = { 0b01, 256000.0 };
    const type _4G = { 0b10, 128000.0 };
    const type _8G = { 0b11, 64000.0  };
  }


  namespace ODR {
    struct type {
      uint8_t code;
    };
    const type ODR_4000_Hz   = { 0 };  // odr = 4000 Hz and lpf = 1000 Hz
    const type ODR_2000_Hz   = { 1 };  // odr = 2000 Hz and lpf = 500 Hz
    const type ODR_1000_Hz   = { 2 };  // odr = 1000 Hz and lpf = 250 Hz
    const type ODR_500_Hz    = { 3 };  // odr = 500 Hz and lpf = 125 Hz
    const type ODR_250_Hz    = { 4 };  // odr = 250 Hz and lpf = 62.5 Hz
    const type ODR_125_Hz    = { 5 };  // odr = 125 Hz and lpf = 31.25 Hz
    const type ODR_62_5_Hz   = { 6 };  // odr = 62.5 Hz and lpf = 15.625 Hz
    const type ODR_31_25_Hz  = { 7 };  // odr = 31.25 Hz and lpf = 7.813 Hz
    const type ODR_15_625_Hz = { 8 };  // odr = 15.625 Hz and lpf = 3.906
    const type ODR_7_813_Hz  = { 9 };  // odr = 7.813 Hz and lpf = 1.953 Hz
    const type ODR_3_906_Hz  = { 10 }; // odr = 3.906 Hz and lpf = 0.977 Hz
  }

  namespace HPF {
    struct type {
      uint8_t code;
    };
    const type NO_HPF      = { 0 }; // no high pass filter
    const type _247_ODR    = { 1 }; // corner freq = 247  10^3  ODR
    const type _62_084_ODR = { 2 }; // corner freq = 62.048  10^3  ODR
    const type _15_545_ODR = { 3 }; // corner freq = 15.454  10^3  ODR
    const type _3_862_ODR  = { 4 }; // corner freq = 3.862  10^3  ODR
    const type _0_954_ODR  = { 5 }; // corner freq = 0.954  10^3  ODR
    const type _0_238_ODR  = { 6 }; // corner freq = 0.238  10^3  ODR
  }


  class Adxl355 {
  public:
    Adxl355(SPIClass *spi, uint32_t cs, uint32_t spiFreq = 10000000)
    :spi(spi), cs(cs), spiFreq(spiFreq) {}

    void begin();
    void resetSpi(); // reset spi settings to this objects config
    void wakeup();
    void sleep();
    void setRange(Range::type range);
    void setODR(ODR::type odr);
    void setHPF(HPF::type hpf);

    uint8_t readByte(uint32_t addr);
    void readBytes(uint32_t addr, uint8_t *bytes, size_t len);
    void writeByte(uint32_t addr, uint8_t byte);
    void writeBytes(uint32_t addr, uint8_t *bytes, size_t len);
    void updateT();
    void updateXyz();
    void updateTxyz();

    float x;
    float y;
    float z;
    float temp;

  private:
    SPIClass *spi;
    uint32_t cs;
    uint32_t spiFreq;
    
    Range::type range = Range::_2G;
    ODR::type odr = ODR::ODR_4000_Hz;
    HPF::type hpf = HPF::NO_HPF;
  };

  void Adxl355::begin() {
    pinMode(cs, OUTPUT);
    digitalWrite(cs, HIGH);

    spi->beginTransaction(SPISettings(spiFreq, MSBFIRST, SPI_MODE0));
  }

  void Adxl355::resetSpi() {
    spi->beginTransaction(SPISettings(spiFreq, MSBFIRST, SPI_MODE0));
  }

  void Adxl355::wakeup() {
    writeByte(Reg::POWER_CTL, 0);
  }

  void Adxl355::sleep() {
    writeByte(Reg::POWER_CTL, 1);
  }

  void Adxl355::setRange(Range::type range) {
    this->range = range;
    writeByte(Reg::RANGE, range.code);
  }

  void Adxl355::setODR(ODR::type odr) {
    this->odr = odr;
    uint8_t byte = (this->hpf.code & 0x07) << 4 | (this->odr.code & 0x0F);
    writeByte(Reg::FILTER, byte);
  }

  void Adxl355::setHPF(HPF::type hpf) {
    this->hpf = hpf;
    uint8_t byte = (this->hpf.code & 0x07) << 4 | (this->odr.code & 0x0F);
    writeByte(Reg::FILTER, byte);
  }

  uint8_t Adxl355::readByte(uint32_t addr) {
    uint8_t bytes[] = {(addr << 1) | SPI_R, 0};
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 2);
    digitalWrite(cs, HIGH);
    return bytes[1];
  }

  void Adxl355::readBytes(uint32_t addr, uint8_t *bytes, size_t len) {
    bytes[0] = (addr << 1) | SPI_R;
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 12);
    digitalWrite(cs, HIGH);
  }

  void Adxl355::writeByte(uint32_t addr, uint8_t byte) {
    uint8_t bytes[] = {(addr << 1) | SPI_W, byte};
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 2);
    digitalWrite(cs, HIGH);
  }

  void Adxl355::writeBytes(uint32_t addr, uint8_t *bytes, size_t len) {
    return;
  }

  void Adxl355::updateTxyz() {

    uint8_t bytes[12];
    readBytes(Reg::TEMP2, bytes, 12);

    int16_t temp = int16_t(bytes[1]) << 8 | bytes[2];
    
    int32_t x = ((int32_t(bytes[3]) << 24) | (int32_t(bytes[4])  << 16) | int32_t(bytes[5]  & 0xF0) << 8) >> 12;
    int32_t y = ((int32_t(bytes[6]) << 24) | (int32_t(bytes[7])  << 16) | int32_t(bytes[8]  & 0xF0) << 8) >> 12;
    int32_t z = ((int32_t(bytes[9]) << 24) | (int32_t(bytes[10]) << 16) | int32_t(bytes[11] & 0xF0) << 8) >> 12;

    this->temp = ((temp - 1852) / (-9.05)) + 25; // below is simplified version of this line
    // this->temp = temp / -9.05 + 229.640883978;
    
    this->x = float(x) / range.coef;
    this->y = float(y) / range.coef;
    this->z = float(z) / range.coef;
  }

  void Adxl355::updateXyz() {

    uint8_t bytes[10];
    readBytes(Reg::XDATA3, bytes, 10);

    int32_t x = ((int32_t(bytes[1]) << 24) | (int32_t(bytes[2]) << 16) | int32_t(bytes[3] & 0xF0) << 8) >> 12;
    int32_t y = ((int32_t(bytes[4]) << 24) | (int32_t(bytes[5]) << 16) | int32_t(bytes[6] & 0xF0) << 8) >> 12;
    int32_t z = ((int32_t(bytes[7]) << 24) | (int32_t(bytes[8]) << 16) | int32_t(bytes[9] & 0xF0) << 8) >> 12;

    this->x = float(x) / range.coef;
    this->y = float(y) / range.coef;
    this->z = float(z) / range.coef;
  }

  void Adxl355::updateT() {

    uint8_t bytes[2];
    readBytes(Reg::TEMP2, bytes, 2);

    int16_t temp = int16_t(bytes[1]) << 8 | bytes[2];

    this->temp = ((temp - 1852) / (-9.05)) + 25; // below is simplified version of this line
    // this->temp = temp / -9.05 + 229.640883978;
  }

} // namespace Adxl355

using namespace Adxl355;

#define CS PC5
Adxl355::Adxl355 adxl (&SPI, CS);

void setup() {
  pinMode(USER_BTN , INPUT);

  notecard.begin();
  Serial.begin(115200);
  notecard.setDebugOutputStream(Serial);
  Serial.println("Notecard running");

  adxl.begin();
  adxl.setRange(Range::_2G);
  adxl.setHPF(HPF::NO_HPF);
  adxl.setODR(ODR::ODR_2000_Hz);
  adxl.wakeup();

  J *req = notecard.newRequest("card.location.mode");
  JAddStringToObject(req, "mode", "periodic");
  JAddNumberToObject(req, "seconds", 3600);
  notecard.sendRequest(req);

  req = notecard.newRequest("hub.set");
  JAddStringToObject(req, "product", productUID);
  JAddStringToObject(req, "mode", "continuous");
  notecard.sendRequest(req);

}

void loop() {
  int id, xdata,ydata,zdata;
  if(digitalRead(USER_BTN) == LOW){
    delay(10000);
    J *req = notecard.newRequest("note.add");
    if (req != NULL)
    {
      JAddStringToObject(req, "file", "sensors.qo");
      JAddBoolToObject(req, "sync", true);
      J *body = JAddObjectToObject(req, "body");

      if(body)
      {
        J *values = JAddArrayToObject(body, "values");
        currtime = micros();
        for(int i=0;i<500;i++){
          adxl.updateTxyz();
          prevtime = currtime;
          id = adxl.readByte(Reg::DEVID);
          xdata = adxl.x * 100;
          ydata = adxl.y * 100;
          zdata = adxl.z * 100;

          double num[] = {xdata,ydata,zdata}; 
          JAddItemToArray(values, JCreateNumberArray(num, 3));
          currtime = micros();
          while((currtime-prevtime) <= 10000){
            currtime = micros();
          }
        }
      }
      notecard.sendRequest(req);
      Serial.println("not null");
    }
  }
}

SOS_Twilio

C/C++
Crash Detection and SMS Alert!
/* Includes ---------------------------------------------------------------- */
#include <Blues_test_inferencing.h>

/* Private variables ------------------------------------------------------- */
static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal

#include <Arduino.h>
#include <SPI.h>
#include <Notecard.h>
#include "Wire.h"
#include "string.h"

using namespace std;

#define productUID "com.gmail.sobhitpanda25:helmet"
Notecard notecard;

unsigned long prevtime, currtime;

namespace Adxl355 {

  const char SPI_W = 0;
  const char SPI_R = 1;

  enum Reg {
    DEVID_AD = 0x00,
    DEVID_MST = 0x01,
    DEVID = 0x02,  
    REVID = 0x03,
    STATUS = 0x04,
    FIFO_ENTRIES = 0x05,
    TEMP2 = 0x06,
    TEMP1 = 0x07,
    XDATA3 = 0x08,
    XDATA2 = 0x09,
    XDATA1 = 0x0A,
    YDATA3 = 0x0B,
    YDATA2 = 0x0C,
    YDATA1 = 0x0D,
    ZDATA3 = 0x0E,
    ZDATA2 = 0x0F,
    ZDATA1 = 0x10,
    FIFO_DATA = 0x11,
    OFFSET_X_H = 0x1E,
    OFFSET_X_L = 0x1F,
    OFFSET_Y_H = 0x20,
    OFFSET_Y_L = 0x21,
    OFFSET_Z_H = 0x22,
    OFFSET_Z_L = 0x23,
    ACT_EN = 0x24,
    ACT_THRESH_H = 0x25,
    ACT_THRESH_L = 0x26,
    ACT_COUNT =  0x27,
    FILTER = 0x28,
    FIFO_SAMPLES = 0x29,
    INT_MAP = 0x2A,
    SYNC = 0x2B,
    RANGE = 0x2C,
    POWER_CTL = 0x2D,
    SELF_TEST = 0x2E,
    RESET = 0x2F
  };

  namespace Range {
    struct type {
      uint8_t code;
      double coef;
    };
    const type _2G = { 0b01, 256000.0 };
    const type _4G = { 0b10, 128000.0 };
    const type _8G = { 0b11, 64000.0  };
  }


  namespace ODR {
    struct type {
      uint8_t code;
    };
    const type ODR_4000_Hz   = { 0 };  // odr = 4000 Hz and lpf = 1000 Hz
    const type ODR_2000_Hz   = { 1 };  // odr = 2000 Hz and lpf = 500 Hz
    const type ODR_1000_Hz   = { 2 };  // odr = 1000 Hz and lpf = 250 Hz
    const type ODR_500_Hz    = { 3 };  // odr = 500 Hz and lpf = 125 Hz
    const type ODR_250_Hz    = { 4 };  // odr = 250 Hz and lpf = 62.5 Hz
    const type ODR_125_Hz    = { 5 };  // odr = 125 Hz and lpf = 31.25 Hz
    const type ODR_62_5_Hz   = { 6 };  // odr = 62.5 Hz and lpf = 15.625 Hz
    const type ODR_31_25_Hz  = { 7 };  // odr = 31.25 Hz and lpf = 7.813 Hz
    const type ODR_15_625_Hz = { 8 };  // odr = 15.625 Hz and lpf = 3.906
    const type ODR_7_813_Hz  = { 9 };  // odr = 7.813 Hz and lpf = 1.953 Hz
    const type ODR_3_906_Hz  = { 10 }; // odr = 3.906 Hz and lpf = 0.977 Hz
  }

  namespace HPF {
    struct type {
      uint8_t code;
    };
    const type NO_HPF      = { 0 }; // no high pass filter
    const type _247_ODR    = { 1 }; // corner freq = 247  10^3  ODR
    const type _62_084_ODR = { 2 }; // corner freq = 62.048  10^3  ODR
    const type _15_545_ODR = { 3 }; // corner freq = 15.454  10^3  ODR
    const type _3_862_ODR  = { 4 }; // corner freq = 3.862  10^3  ODR
    const type _0_954_ODR  = { 5 }; // corner freq = 0.954  10^3  ODR
    const type _0_238_ODR  = { 6 }; // corner freq = 0.238  10^3  ODR
  }


  class Adxl355 {
  public:
    Adxl355(SPIClass *spi, uint32_t cs, uint32_t spiFreq = 10000000)
    :spi(spi), cs(cs), spiFreq(spiFreq) {}

    void begin();
    void resetSpi(); // reset spi settings to this objects config
    void wakeup();
    void sleep();
    void setRange(Range::type range);
    void setODR(ODR::type odr);
    void setHPF(HPF::type hpf);

    uint8_t readByte(uint32_t addr);
    void readBytes(uint32_t addr, uint8_t *bytes, size_t len);
    void writeByte(uint32_t addr, uint8_t byte);
    void writeBytes(uint32_t addr, uint8_t *bytes, size_t len);
    void updateT();
    void updateXyz();
    void updateTxyz();

    float x;
    float y;
    float z;
    float temp;

  private:
    SPIClass *spi;
    uint32_t cs;
    uint32_t spiFreq;
    
    Range::type range = Range::_2G;
    ODR::type odr = ODR::ODR_4000_Hz;
    HPF::type hpf = HPF::NO_HPF;
  };

  void Adxl355::begin() {
    pinMode(cs, OUTPUT);
    digitalWrite(cs, HIGH);

    spi->beginTransaction(SPISettings(spiFreq, MSBFIRST, SPI_MODE0));
  }

  void Adxl355::resetSpi() {
    spi->beginTransaction(SPISettings(spiFreq, MSBFIRST, SPI_MODE0));
  }

  void Adxl355::wakeup() {
    writeByte(Reg::POWER_CTL, 0);
  }

  void Adxl355::sleep() {
    writeByte(Reg::POWER_CTL, 1);
  }

  void Adxl355::setRange(Range::type range) {
    this->range = range;
    writeByte(Reg::RANGE, range.code);
  }

  void Adxl355::setODR(ODR::type odr) {
    this->odr = odr;
    uint8_t byte = (this->hpf.code & 0x07) << 4 | (this->odr.code & 0x0F);
    writeByte(Reg::FILTER, byte);
  }

  void Adxl355::setHPF(HPF::type hpf) {
    this->hpf = hpf;
    uint8_t byte = (this->hpf.code & 0x07) << 4 | (this->odr.code & 0x0F);
    writeByte(Reg::FILTER, byte);
  }

  uint8_t Adxl355::readByte(uint32_t addr) {
    uint8_t bytes[] = {(addr << 1) | SPI_R, 0};
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 2);
    digitalWrite(cs, HIGH);
    return bytes[1];
  }

  void Adxl355::readBytes(uint32_t addr, uint8_t *bytes, size_t len) {
    bytes[0] = (addr << 1) | SPI_R;
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 12);
    digitalWrite(cs, HIGH);
  }

  void Adxl355::writeByte(uint32_t addr, uint8_t byte) {
    uint8_t bytes[] = {(addr << 1) | SPI_W, byte};
    digitalWrite(cs, LOW);
    spi->transfer(bytes, 2);
    digitalWrite(cs, HIGH);
  }

  void Adxl355::writeBytes(uint32_t addr, uint8_t *bytes, size_t len) {
    return;
  }

  void Adxl355::updateTxyz() {

    uint8_t bytes[12];
    readBytes(Reg::TEMP2, bytes, 12);

    int16_t temp = int16_t(bytes[1]) << 8 | bytes[2];
    
    int32_t x = ((int32_t(bytes[3]) << 24) | (int32_t(bytes[4])  << 16) | int32_t(bytes[5]  & 0xF0) << 8) >> 12;
    int32_t y = ((int32_t(bytes[6]) << 24) | (int32_t(bytes[7])  << 16) | int32_t(bytes[8]  & 0xF0) << 8) >> 12;
    int32_t z = ((int32_t(bytes[9]) << 24) | (int32_t(bytes[10]) << 16) | int32_t(bytes[11] & 0xF0) << 8) >> 12;

    this->temp = ((temp - 1852) / (-9.05)) + 25; // below is simplified version of this line
    // this->temp = temp / -9.05 + 229.640883978;
    
    this->x = float(x) / range.coef;
    this->y = float(y) / range.coef;
    this->z = float(z) / range.coef;
  }

  void Adxl355::updateXyz() {

    uint8_t bytes[10];
    readBytes(Reg::XDATA3, bytes, 10);

    int32_t x = ((int32_t(bytes[1]) << 24) | (int32_t(bytes[2]) << 16) | int32_t(bytes[3] & 0xF0) << 8) >> 12;
    int32_t y = ((int32_t(bytes[4]) << 24) | (int32_t(bytes[5]) << 16) | int32_t(bytes[6] & 0xF0) << 8) >> 12;
    int32_t z = ((int32_t(bytes[7]) << 24) | (int32_t(bytes[8]) << 16) | int32_t(bytes[9] & 0xF0) << 8) >> 12;

    this->x = float(x) / range.coef;
    this->y = float(y) / range.coef;
    this->z = float(z) / range.coef;
  }

  void Adxl355::updateT() {

    uint8_t bytes[2];
    readBytes(Reg::TEMP2, bytes, 2);

    int16_t temp = int16_t(bytes[1]) << 8 | bytes[2];

    this->temp = ((temp - 1852) / (-9.05)) + 25; // below is simplified version of this line
    // this->temp = temp / -9.05 + 229.640883978;
  }

} // namespace Adxl355

using namespace Adxl355;

#define CS PC5
Adxl355::Adxl355 adxl (&SPI, CS);

/**
* @brief      Arduino setup function
*/
void setup()
{
  pinMode(USER_BTN , INPUT);

  notecard.begin();
  Serial.begin(115200);
  notecard.setDebugOutputStream(Serial);
  Serial.println("Notecard running");

  adxl.begin();
  adxl.setRange(Range::_2G);
  adxl.setHPF(HPF::NO_HPF);
  adxl.setODR(ODR::ODR_2000_Hz);
  adxl.wakeup();
  Serial.println("IMU running");

  J *req = notecard.newRequest("hub.set");
  JAddStringToObject(req, "product", productUID);
  JAddStringToObject(req, "mode", "continuous");
  notecard.sendRequest(req);

  req = notecard.newRequest("card.location.track");
  JAddBoolToObject(req, "sync", true);
  JAddBoolToObject(req, "heartbeat", true);
  JAddNumberToObject(req, "hours", 12);
  notecard.sendRequest(req);

  if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != 3) {
      ei_printf("ERR: EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME should be equal to 3 (the 3 sensor axes)\n");
      return;
  }
}

/**
 * @brief Return the sign of the number
 * 
 * @param number 
 * @return int 1 if positive (or 0) -1 if negative
 */
float ei_get_sign(float number) {
    return (number >= 0.0) ? 1.0 : -1.0;
}

/**
* @brief      Get data and run inferencing
*
* @param[in]  debug  Get debug info if true
*/
void loop()
{
  if(digitalRead(USER_BTN) == 0){
    ei_printf("\nStarting inferencing in 120 seconds...\n");

    delay(15000);

    ei_printf("Sampling...\n");

    // Allocate a buffer here for the values we'll read from the IMU
    float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 };

    for (size_t ix = 0; ix < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; ix += 3) {
        // Determine the next tick (and then sleep later)
        uint64_t next_tick = micros() + (EI_CLASSIFIER_INTERVAL_MS * 1000);

        adxl.updateTxyz();
        buffer[ix] = adxl.x * 100;
        buffer[ix + 1] = adxl.y * 100;
        buffer[ix + 2] = adxl.z * 100;

        delayMicroseconds(next_tick - micros());
    }

    // Turn the raw buffer in a signal which we can the classify
    signal_t signal;
    int err = numpy::signal_from_buffer(buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal);
    if (err != 0) {
        ei_printf("Failed to create signal from buffer (%d)", err);
        Serial.println("");
        return;
    }

    // Run the classifier
    ei_impulse_result_t result = { 0 };

    err = run_classifier(&signal, &result, debug_nn);
    if (err != EI_IMPULSE_OK) {
        ei_printf("ERR: Failed to run classifier (%d)", err);
        Serial.println("");
        return;
    }

    // print the predictions
    ei_printf("Predictions ");
    ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
        result.timing.dsp, result.timing.classification, result.timing.anomaly);
    ei_printf(": \n");
    Serial.println("");
    for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
    //    ei_printf_float("    %s: %.5f\n", result.classification[ix].label, result.classification[ix].value);
    ei_printf("%s:",result.classification[ix].label);
    ei_printf_float(result.classification[ix].value);
    Serial.println("");
    }

    //Send the data to twilio if it is a crash
    if(result.classification[1].value > 0.8){
      J *req = notecard.newRequest("note.add");
      if (req != NULL)
      {
        JAddStringToObject(req, "file", "twilio.qo");
        JAddBoolToObject(req, "sync", true);
        J *body = JAddObjectToObject(req, "body");

        if(body)
        {
          JAddStringToObject(body, "twilioBody", "Its a crash!");
        }
      }
      notecard.sendRequest(req);
    }

#if EI_CLASSIFIER_HAS_ANOMALY == 1
    ei_printf_float("    anomaly score: %.3f\n", result.anomaly);
    Serial.println("");
#endif

  }
}

#if !defined(EI_CLASSIFIER_SENSOR) || EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_ACCELEROMETER
#error "Invalid model for current sensor"
#endif

Credits

Sobhit Panda

Sobhit Panda

3 projects • 5 followers
Tinkering with electronics, one wire at a time, for the love of all things embedded.
Pratyush Mallick

Pratyush Mallick

4 projects • 32 followers
I love tinkering, taking things apart, and making them work. Happy Hacking

Comments