Code improvement & advice for my project

Greetings guys,

I'm seeking some advice , in order to improve my code & thus my project . TLDR: It will be a wearable device that detects movement utilizing an algorithm i have written & the Arduino Nano BLE 33 sense as a main board.

Additionally i will be using the ambient humidity & temperature sensor HTS221, found on the board, the IMU LSM9DS1 and 2 external modules named MLX90614 & MCP9808.
Concurrently , i will be advertising the output values of the pre-mentioned sensors using the BLE protocol and an Central App like Lightblue or nRF to read these values.

One of the functionalities is basically a remote temperature & humidity ambient sensor ,patient temperature monitoring device utilizing the BLE protocol.
I will add alerts& warnings, based on temperature and humidity readings , in the near future based on COVID specific conditions and WHO specific instructions.
This is the main reason i'm using the IMU to find out if a person has exercised & has high temperature or not.

/*=====================================================================*/
#include <Wire.h>                   /********************/
#include <Adafruit_SSD1306.h>       /****OLED Display****/
#include <Adafruit_GFX.h>           /********************/
#include <Arduino_LSM9DS1.h>        /******IMU lib*******/
#include <Arduino_HTS221.h>         /****Ambient lib*****/
#include <Adafruit_MLX90614.h>      /****Infrared lib****/
#include "Adafruit_MCP9808.h"       /****Contact lib*****/
#include <stdio.h>                  /********************/
#include "RTClib.h"                 /*****RTC libs*******/
#include <SPI.h>
#include <ArduinoBLE.h>     
/*=====================================================================*/

RTC_DS1307 rtc;

void setup_debugging();
void display_date_time();
void temp_sensors_disp();
void calibrate();
void movement_alg();
int getTemperature(float calibration);
unsigned int getHumidity();
void updateReadings();
unsigned int getTouchtemp();
unsigned int  getObjtemp();

/******************BLE VARIABLES & CONSTANTS*****************************/


const int UPDATE_FREQUENCY = 10000;
const float CALIBRATION_FACTOR = -4.0; //temperature Calibration Factor(Celcius)
int previousTemperature = 0;
unsigned int previousHumidity = 0;
unsigned int previoustouchtemp = 0;
unsigned int previousobjtemp = 0;
unsigned long previousMillis  = 0;
unsigned int touchTemp = 0;
unsigned int ObjTemp = 0;

BLEService environmentService("181A");

BLEIntCharacteristic tempCharacteristic("2A6E", BLERead | BLENotify);

BLEUnsignedIntCharacteristic humidCharacteristic("2A6F" , BLERead | BLENotify);

BLEUnsignedIntCharacteristic TouchtempCharacteristic("ffdbdc60-21f0-11ec-9621-0242ac130002", BLERead | BLENotify);

BLEUnsignedIntCharacteristic ObjtempCharacteristic("2f0ad996-21fb-11ec-9621-0242ac130002", BLERead | BLENotify);

/*=====================================================================*/

char daysOfTheWeek[7][12] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

String msg = "GREETINGS";
//bootloader delay
#define bootloader 200
#define TRUE 1
#define FALSE 0
const unsigned long eventInterval = 10000 ;

/***********************VARIABLES & CONSTANTS**************************/
//USED FOR THE MOVEMENT ALG
const int spikes_threshold = 20;
//upper threshold value

float upper_threshold = 1.55;
float xval[200] = {0};
float yval[200] = {0};
float zval[200] = {0};
float xavg, yavg, zavg;
int spikes;

int first_time = 1;
int counter = 0;
int exercising = 0 ;

/*=====================================================================*/

unsigned long currentmillis;
unsigned long currentmillis1;
unsigned long previousTime1 = 0;
unsigned long tempmillis;

//used for calibrate()
const unsigned long eventInterval2 = 10;
const unsigned long eventInterval3 = 100;
//variables for 3 iterations of calibrate
unsigned long startmillis;
unsigned long startmillis2;
unsigned long startmillis3;
unsigned long startmillis4;
unsigned long startmillis5;
float temperature1;
float humidity ;
/*=====================================================================*/
//initial message delay
const int initial_message_delay = 3000;

/*****************INITIALIZE TEMPERATURE SENSORS**********************/

Adafruit_MLX90614 mlx = Adafruit_MLX90614();
Adafruit_MCP9808 tempsensor = Adafruit_MCP9808();

/*=====================================================================*/

/*=====================================================================*/
float sumx = 0;
float sumy = 0;
float sumz = 0;
float totvect[200] = {0};
float totave[200] = {0};
float xaccl[200] = {0};
float yaccl[200] = {0};
float zaccl[200] = {0};
/*=====================================================================*/

/**********************OLED DISPLAY CONSTANTS***************************/
#define OLED_WIDTH 128
#define OLED_HEIGHT 64
#define OLED_MOSI   11
#define OLED_CLK   13
#define OLED_DC     9
#define OLED_CS     8
#define OLED_RESET  10
Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT, OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
/*=====================================================================*/

void setup()
{
  delay(bootloader);
  display.display();
  display.clearDisplay();
  /*=====================================================================*/
  Serial.begin(9600);
  /*=====================================================================*/
  setup_debugging();
  startmillis4 = millis();

  /*Initiallizing contact tempsensor accuracy*/
  tempsensor.setResolution(2);

  Serial.print("Accelerometer sample rate = ");
  Serial.print(IMU.accelerationSampleRate());
  Serial.println(" Hz");


  //clears display buffer
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  //(0,0) like an array 0-127
  display.setCursor(7, 12);
  display.println(msg);

  /*********************************************
    from displaytextsize to println before display.
    display the info is loaded into the memory of the screen
   **********************************************/

  //this function writes what is in memory to the screen.
  display.display();
  display.clearDisplay();
  delay(initial_message_delay);

  // Add "loop2" and "loop3" to scheduling.
  //loop is always stared by default
  calibrate();
  //get initial values
  temperature1 = HTS.readTemperature() + CALIBRATION_FACTOR ;
  humidity = HTS.readHumidity() ;

}

void loop()
{

  BLEDevice central = BLE.central(); // Wait for a BLE central to connect

  // If central is connected to peripheral
  if (central)
  {
    Serial.print("Connected to central MAC: ");
    Serial.println(central.address()); // Central's BT address:

    digitalWrite(LED_BUILTIN, HIGH); // Turn on the LED to indicate the connection

    while (central.connected()) {
      unsigned long currentMillis = millis();
      // After UPDATE_FREQUENCY ms have passed, check temperature & humidity
      if (currentMillis - previousMillis >= UPDATE_FREQUENCY)
      {
        previousMillis = currentMillis;
        updateReadings();
      }
    }

    digitalWrite(LED_BUILTIN, LOW); // When the central disconnects, turn off the LED
    Serial.print("Disconnected from central MAC: ");
    Serial.println(central.address());

  }

  display_date_time();

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(10, 20);
  display.println();
  display.setTextSize(1);
  display.setTextColor(WHITE);

  temp_sensors_disp();
  movement_alg();

}

/*=====================================================================*/
//adjust readings by using the average of 200 samples
void calibrate()
{
  currentmillis = millis();

  int i = 0;

  while (!IMU.accelerationAvailable())
  {

    Serial.print("All good");
  }
  //Finding the sum and average for each axis (x/y/z)
  //then filling the array with calibration data
  for ( i = 0; i < 100; i++)
  {
    IMU.readAcceleration(xval[i], yval[i], zval[i]);
    if (currentmillis - startmillis >= eventInterval2)
    {
      sumx = xval[i] + sumx;
      xavg = sumx / 200;
      startmillis = currentmillis;
    }
    if (currentmillis - startmillis2 >= eventInterval2)
    {
      sumy = yval[i] + sumy;
      yavg = sumy / 200;
      startmillis2 = currentmillis;
    }
    if (currentmillis - startmillis3 >= eventInterval2)
    {
      sumz = zval[i] + sumz;
      zavg = sumz / 200;
      startmillis3 = currentmillis;
    }
  }
}

void temp_sensors_disp()
{
  tempmillis = millis();

  tempsensor.wake();

  if (tempmillis - startmillis5 >= eventInterval)
  {
    temperature1 = HTS.readTemperature() + CALIBRATION_FACTOR;
    //ambient humidity
    humidity = HTS.readHumidity();

    startmillis5 = tempmillis;
  }
  float c = tempsensor.readTempC();

  float RawObjectTemperature = mlx.readObjectTempC();
  //lptemp = (0.98 * oldc) + (0.02 * RawObjectTemperature);
  //infrared temperature sensor

  char buffer2[50];
  char buffer3[50];

  //ambient temperature and humidity
  sprintf(buffer2, "AmT:%2.1f*C AmH:%2.1f %%\n", temperature1, humidity);

  //touch temperature and obj temperature
  sprintf(buffer3, "Tou:%2.1f*C Obj:%2.1f*C\n", c, RawObjectTemperature);

  display.setTextSize(1);
  display.setCursor(0, 30);

  display.print(buffer2);
  display.setCursor(0, 40);
  display.print(buffer3);
  //oldc = lptemp;

  tempsensor.shutdown_wake(1);

}

//date display function
void display_date_time()
{
  DateTime now = rtc.now();

  /*============Display Date=================*/
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print(daysOfTheWeek[now.dayOfTheWeek()]);
  char currentDate [16];
  uint8_t thisDay, thisMonth ;
  thisDay = now.day();
  thisMonth = now.month();
  //add leading zeros to the day and month
  sprintf (currentDate, "%02d/%02d/", thisDay, thisMonth);
  display.setTextSize(1);
  display.setCursor(62, 0);
  display.print(currentDate);
  display.setTextSize(1);
  display.setCursor(102, 0);
  display.print(now.year(), DEC);


  /*================Display Time================*/
  char buffer [16];
  uint8_t thisSec, thisMin, thisHour;
  thisSec = now.second();
  thisMin = now.minute();
  thisHour = now.hour();
  sprintf (buffer, "%02d:%02d:%02d", thisHour, thisMin, thisSec);
  display.setTextSize(2);
  display.setCursor(15, 9);
  display.print(buffer);
  display.display();

}
/*=====================================================================*/
void movement_alg()
{
  int acc = 0;


  for (int a = 0; a < 200; a++)
  {
    if (IMU.accelerationAvailable())
    {

      if (first_time) {
        previousTime1 = millis();
        first_time = 0;
      }

      unsigned long currentTime = millis(); //counter
      currentmillis1 = millis();

      if (currentmillis1 - startmillis4 >= eventInterval3 )
      {
        IMU.readAcceleration(xaccl[a], yaccl[a], zaccl[a]);

        counter++;
        //calculating vectors
        totvect[a] = sqrt(((xaccl[a] - xavg) * (xaccl[a] - xavg)) + ((yaccl[a] - yavg) * (yaccl[a] - yavg)) + ((zval[a] - zavg) * (zval[a] - zavg)));
        totave[a] = (totvect[a] + totvect[a - 1]) / 2 ;

        Serial.print('\n');
        Serial.print("TotalAverage[a]:");
        Serial.println(totave[a]);

        //calculate spikes
        if ( totave[a] > upper_threshold)
        {
          spikes++;
          Serial.println("Spike found");
        }
        startmillis4 = currentmillis1;
      }

      display.setTextSize(1);
      display.setCursor(30, 50);
      display.print("Exercising:");
      display.print(exercising);
      //check every 15 seconds

      if ((currentTime - previousTime1 ) >= eventInterval)
      {
        previousTime1 = millis();
        Serial.print("Spikes counter: ");
        Serial.println(spikes);
        Serial.print("Total counter: ");
        Serial.println(counter);

        if (exercising) exercising = 0;
        if (spikes >= spikes_threshold )
        {
          Serial.println("Exercise Found");
          exercising = 1 ;
          display.setCursor(23, 50);
          display.print("Exercising:");
          display.print(exercising);
        }
        //reset spikes
        spikes = 0;
        //reset counter
        counter = 0;

      }

    }
  }
}


/*=====================================================================*/
void setup_debugging()
{
  if (!display.begin(SSD1306_SWITCHCAPVCC))
  {
    Serial.println(F("SSD1306 allocation failed"));
    while (true);
  }

  if (!IMU.begin())
  {
    Serial.println("Failed to initialize accelerometer!");
    while (true);
  }

  if (!HTS.begin())
  {
    Serial.println("Failed to initialize humidity temperature sensor!");
    while (true);
  }

  if (!mlx.begin())
  {
    Serial.println("Error connecting to MLX sensor. Check wiring.");
    while (true);
  }

  if (!tempsensor.begin(0x18))
  {
    Serial.println("Couldn't find MCP9808! Check your connections and verify the address is correct.");
    while (true);
  }

  if (! rtc.begin())
  {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    abort();
  }

  if (! rtc.isrunning())
  {
    Serial.println("RTC is NOT running, let's set the time!");
    // When time needs to be set on a new device, or after a power loss, the
    // following line sets the RTC to the date & time this sketch was compiled
    // rtc.adjust(DateTime(2021, 6, 28, 20, 26, 0));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }

  if (!BLE.begin())
  { // Initialize NINA B306 BLE

    Serial.println("starting BLE failed!");
    while (1);

  }

  //BLE SETUP


  BLE.setLocalName("ArduinoNano33BLESense");    // Set name for connection
  BLE.setAdvertisedService(environmentService); // Advertise environment service

  environmentService.addCharacteristic(tempCharacteristic);     // Add temperature characteristic
  environmentService.addCharacteristic(humidCharacteristic);    // Add humidity characteristic
  environmentService.addCharacteristic(TouchtempCharacteristic); //Add touch temperature characteristic
  environmentService.addCharacteristic(ObjtempCharacteristic);  //Add infrared temperature characteristic


  BLE.addService(environmentService); // Add environment service

  tempCharacteristic.setValue(0);     // Set initial temperature value
  humidCharacteristic.setValue(0);    // Set initial humidity value
  TouchtempCharacteristic.setValue(0); // Set initial touchtemperature value
  ObjtempCharacteristic.setValue(0);  // Seti initial object temperature value

  BLE.advertise(); // Start advertising
  Serial.print("Peripheral device MAC: ");
  Serial.println(BLE.address());
  Serial.println("Waiting for connections…");

  /********************************************************************/
  tempsensor.setResolution(1);

}

/*=====================================================================*/
int getTemperature(float calibration)
{
  // Get calibrated temperature as signed 16-bit int for BLE characteristic

  return (int) (HTS.readTemperature()) + (int) (calibration);
}

/*=====================================================================*/
unsigned int getHumidity()
{
  // Get humidity as unsigned 16-bit int for BLE characteristic

  return (unsigned int) (HTS.readHumidity());
}

/*=====================================================================*/
unsigned int getTouchtemp()
{
  //Get touch temperature as signed 16-bit int for BLE characteristic
  return (unsigned int) (mlx.readObjectTempC());
}

/*=====================================================================*/
unsigned int getObjtemp()
{
  //Get object temperature as signed 16-bit int for BLE characteristic

  return (unsigned int) (tempsensor.readTempC());
}


/*=====================================================================*/
void updateReadings()
{
  int temperature = getTemperature(CALIBRATION_FACTOR);
  unsigned int humidity = getHumidity();
  unsigned int touchtemp = getTouchtemp();
  unsigned int Objtemp = getObjtemp();



  if (temperature != previousTemperature)
  { // If reading has changed

    Serial.print("Temperature: ");
    Serial.println(temperature);
    tempCharacteristic.writeValue(temperature); // Update characteristic
    previousTemperature = temperature;          // Save value

  }

  if (humidity != previousHumidity)
  {
    // If reading has changed
    Serial.print("Humidity: ");
    Serial.println(humidity);
    humidCharacteristic.writeValue(humidity);
    previousHumidity = humidity;

  }

  if (touchtemp !=  previoustouchtemp)
  {
    // If reading has changed
    Serial.print("Touchtemp: ");
    Serial.println(humidity);
    TouchtempCharacteristic.writeValue(touchtemp);
    previoustouchtemp = touchtemp;

  }

  if (Objtemp != previousobjtemp)
  {
    // If reading has changed
    Serial.print("Objtemp: ");
    Serial.println(Objtemp);
    ObjtempCharacteristic.writeValue(Objtemp);
    previousobjtemp = Objtemp;
  }

}
/*=====================================================================*/```

Can you clarify what this has to do with COVID, or ask a moderator to move it to a more appropriate section?

Your post was MOVED to its current location as it is more suitable.

i simulated your code

looks whenever a connection to a host is possible, it remains in a while loo() that only monitor/reports temperature & humidity. while in that loop it never reaches the code near the bottom of loop() that executes temp_sensor_disp() and movement_alg()

the code also has 5 (e.g. xval, totvevt, xacc) arrays that are large 200 float used to average. these could probably be eliminated using running averages (avg approaches sig after 3N)

  avg += (sig - avg) / N;

i'm glad to see the code uses sprintf() in some places, but it could be used more. some global buffers can be defined to avoid repeatedly defining them locally.

i also suggest creating a sub-function to display strings on the OLED as well as the serial monitor. that function could be passed 4 strings and use predefined y values for each line of text on the graphics display. those lines would also be sent to the monitor. this will reduce the amount of code, making is more readable as well as helping debug (via serial monitor).

only "printing" when a string changes, as you do, will reduce the clutter on the serial monitor

there's no need for forward declarations (e.g. void calibrate();" in the arduino environment nor is there a need for "#include <stdio.h>" (look at Arduino.h which is include in all .ino files)

i would think loop should monitor all sensors independent of a connection. some subset of those measurements (i.e. min, avg, max, ...) can be saved and reported when a connection is available. any anomalies could also be saved, perhaps along with a timestamp and reported

1 Like

That is not always the case but it does no harm

float xval[200] = {0}; does not initialize all values in xval to 0.

Yes it does.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.