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;
}
}
/*=====================================================================*/```