FINAL PROJECT

In this section, I will describe the step-by-step process of the creation and design of my final project. Welcome to this journey that will surprise you.

FINAL PROJECT SUMMARY

Take a look of my Final project!

GesundFit

GesundFit is a smart bracelet that measures temperature, heart rate, and oxygen levels. It connects to an app that monitors your vital signs in real time and stores this information in a database.

GESUNDFIT APP

Image 1 Image 1 Image 1

Research

Methodology: Design Thinking

Design Thinking is an approach to problem-solving that focuses on understanding user needs and developing creative solutions through multidisciplinary collaboration. It is based on an iterative process that includes stages such as empathy, definition, ideation, prototyping, and testing.

Define Stage

Central Problem: Users desire a smart band that not only measures physical activity but also allows the information to be measurable by experts in the case of known diseases or simply for preventive purposes. Discomfort and lack of style are barriers to adoption, and most users seek a solution that is both accurate and motivating.

Empathy Stage

Descripción de la imagen

Ideas Stage

Now in this stage, with all my information, the problematic and the user I started with a brainstorming and sketching my ideas to understand more the way I wanted to work.

First ideas

Here are some of the aim final project ideas.

Image 1 Image 2

Idea Description

This smart band aims to measure body reactions in order to consistently store them in a database. The goal is to update the information released by the body on a daily basis. A health expert in a specific medical field can then evaluate this information and generate diagnoses related to existing or potential diseases.

Sensors

For this final project we use 3 different sensors

Sensor Name Description Approximate Cost
Temperature Sensor Measures the body temperature $70 mexican pesos.
SPO2 sensor Measures the body oxigenation $200 mexican pesos.
Cardiac beat sensor Measures heart beat from the body. $200 mexican pesos.

Bill of Materials

Here are the list of materials and components I have used for this project.

Material/Component Description Approximate Cost
XIAO ESP32S3 Microcontroller $700 mexican pesos.
Temperature Sensor Measures the body temperature $70 mexican pesos.
SPO2 sensor Measures the body oxigenation $200 mexican pesos.
Cardiac beat sensor Measures heart beat from the body. $200 mexican pesos.
TPU filament Flexible filament $200 mexican pesos.
Copper tape Tape for cutting the flexible PCB $300 mexican pesos.
Acetate paper for the base of the board $30 mexican pesos.
Faux leather for the bracelet strap. $350 mexican pesos.
5000 glue to be able to glue the straps $80 mexican pesos.

Internal design

Here is the entire process of the internal design of the smart band

PCB Design

List of components for the pcb desing

Material/Component Description
MAX30102 Sensor that includes SpO2 and cardiac sensor.
XIAO ESP32C3 BLE AND WIFI Microcontroller
MCP9700AT-E/LT IC SMD Sensor Temperature Body sesnor
Resistor 4199 Resistors from the Xiao towards the sensors.
Capacitors From voltage and ground for the entire PCB power supply

PinOut XIAO ESP32S3

Image 1

PinOut MAX30102 sensor

Image 2

PinOut MCP9700AT-E/LT IC SMD Sensor

Image 3

Process

I designed my circuit board in KiCad.

Step 1

First, I created the schematic design, and then I made the PCB connections while considering the component sizes to avoid making the board too large.

Image 3 Image 3

Step 2

Export the design as SVG as usual.

Image 3 Image 3

Step 3

Since I decided to use a vinyl cutter for the flexible PCB design, I needed to convert the SVG design to PNG because that's the format the cutter's program reads.

Therefore, I used an online format converter.

Image 3

Step 4

With the PCB cutting format ready, I went to the Silhouette Studio program, where I cut the PCB.

Image 3

Step 5

Within the program, you insert the image and arrange it on the cutting sheet.

Image 3

Step 6

Once the PNG is ready, you adjust the cutting machine settings to cut with a depth of 1, a pressure of 20, and a speed of 8.

Image 3 Image 3

Step 7

Once ready, I placed the acetate on top of the cutting sheet of the machine with two layers of copper tape stacked on each other to make the PCB guides more durable.

Image 3 Image 3

Step 8

Once everything was ready, I loaded the sheet into the machine and it began cutting.

Image 3 Image 3

Step 9

Afterwards, I used tweezers to remove the excess material, leaving the tracks of the board exposed and ready for soldering.

Image 3

Step 10

Carefully, I soldered the components to avoid breaking the tracks. After nearly 15 attempts, including errors and resoldering, I finally achieved the final soldered PCB.

Image 3 Image 3

Files

Programming Board

Now, with the board soldered, it is ready to be programmed.

Step 1

First, I wanted to ensure there was a connection between the XIAO and the sensors, so I wrote a code in Arduino to function as an I2C scanner.

Arduino I2C Scanner

					// Arduino I2C Scanner
					#include 
					
					void setup() {
					  Wire.begin();
					  Serial.begin(9600);
					  while (!Serial); // Wait for the serial connection
					  Serial.println("\nI2C Scanner");
					}
					
					void loop() {
					  byte error, address;
					  int nDevices;
					
					  Serial.println("Scanning...");
					
					  nDevices = 0;
					  for (address = 1; address < 127; address++) {
						Wire.beginTransmission(address);
						error = Wire.endTransmission();
					
						if (error == 0) {
						  Serial.print("I2C device found at address 0x");
						  if (address < 16)
							Serial.print("0");
						  Serial.print(address, HEX);
						  Serial.println("  !");
					
						  nDevices++;
						} else if (error == 4) {
						  Serial.print("Unknown error at address 0x");
						  if (address < 16)
							Serial.print("0");
						  Serial.println(address, HEX);
						}
					  }
					  if (nDevices == 0)
						Serial.println("No I2C devices found\n");
					  else
						Serial.println("done\n");
					
					  delay(5000); // wait 5 seconds for next scan
					}
					

Step 2

So, I uploaded this code to my board to verify the communication between the XIAO and the sensors.

And it work´s there is a clearly conextion between the XIAO and the sensors.

Step 3

Once the connection was established, I wrote code to read temperature, oxygenation, and heart rate by taking multiple samples with the infrared sensor. These samples were averaged to determine the values of each variable.

At the same time, I also sought to implement a WiFi connection, using my phone's WiFi, to establish connectivity right from the start with the app that I will explain later.

Final code

							#include 
								#include 
								#include 
								#include 
								#include "MAX30105.h"
								#include "spo2_algorithm.h"
								
								MAX30105 particleSensor;
								
								#define MAX_BRIGHTNESS 255
								
								#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
								// Arduino Uno doesn't have enough SRAM to store 100 samples of IR led data and red led data in 32-bit format
								// To solve this problem, 16-bit MSB of the sampled data will be truncated. Samples become 16-bit data.
								uint16_t irBuffer[100]; // infrared LED sensor data
								uint16_t redBuffer[100];  // red LED sensor data
								#else
								uint32_t irBuffer[100]; // infrared LED sensor data
								uint32_t redBuffer[100];  // red LED sensor data
								#endif
								
								int32_t bufferLength; // data length
								int32_t spo2; // SPO2 value
								int8_t validSPO2; // indicator to show if the SPO2 calculation is valid
								int32_t fc; // heart rate value
								int8_t validFC; // indicator to show if the heart rate calculation is valid
								float temp = 36.0; // fixed temperature value
								
								byte pulseLED = 1; // Must be on PWM pin
								byte readLED = 13; // Blinks with each data read
								
								const char* ssid = "iphone de Valeria (6)";
								const char* password = "hola1234";
								
								const char* serverName = "https://gesundfitapi.onrender.com/api/valeria/";
								
								void setup() {
								  Serial.begin(115200); // initialize serial communication at 115200 bits per second:
								
								  pinMode(pulseLED, OUTPUT);
								  pinMode(readLED, OUTPUT);
								
								  // Initialize sensor
								  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) { // Use default I2C port, 400kHz speed
									Serial.println(F("MAX30105 was not found. Please check wiring/power."));
									while (1);
								  }
								
								  Serial.println(F("Attach sensor to finger with rubber band. Press any key to start conversion"));
								  while (Serial.available() == 0); // wait until user presses a key
								  Serial.read();
								
								  byte ledBrightness = 60; // Options: 0=Off to 255=50mA
								  byte sampleAverage = 4; // Options: 1, 2, 4, 8, 16, 32
								  byte ledMode = 2; // Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
								  byte sampleRate = 100; // Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
								  int pulseWidth = 411; // Options: 69, 118, 215, 411
								  int adcRange = 4096; // Options: 2048, 4096, 8192, 16384
								
								  particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); // Configure sensor with these settings
								
								  WiFi.begin(ssid, password);
								  Serial.print("Conectando a WiFi...");
								  while (WiFi.status() != WL_CONNECTED) {
									delay(1000);
									Serial.print(".");
								  }
								  Serial.println("Conectado a la red WiFi");
								}
								
								void loop() {
								  bufferLength = 100; // buffer length of 100 stores 4 seconds of samples running at 25sps
								
								  // read the first 100 samples, and determine the signal range
								  for (byte i = 0; i < bufferLength; i++) {
									while (particleSensor.available() == false) // do we have new data?
									  particleSensor.check(); // Check the sensor for new data
								
									redBuffer[i] = particleSensor.getRed();
									irBuffer[i] = particleSensor.getIR();
									particleSensor.nextSample(); // We're finished with this sample so move to next sample
								
									Serial.print(F("red="));
									Serial.print(redBuffer[i], DEC);
									Serial.print(F(", ir="));
									Serial.println(irBuffer[i], DEC);
								  }
								
								  // calculate heart rate and SpO2 after first 100 samples (first 4 seconds of samples)
								  maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &fc, &validFC);
								
								  // Continuously taking samples from MAX30102. Heart rate and SpO2 are calculated every 1 second
								  while (1) {
									// dumping the first 25 sets of samples in the memory and shift the last 75 sets of samples to the top
									for (byte i = 25; i < 100; i++) {
									  redBuffer[i - 25] = redBuffer[i];
									  irBuffer[i - 25] = irBuffer[i];
									}
								
									// take 25 sets of samples before calculating the heart rate.
									for (byte i = 75; i < 100; i++) {
									  while (particleSensor.available() == false) // do we have new data?
										particleSensor.check(); // Check the sensor for new data
								
									  digitalWrite(readLED, !digitalRead(readLED)); // Blink onboard LED with every data read
								
									  redBuffer[i] = particleSensor.getRed();
									  irBuffer[i] = particleSensor.getIR();
									  particleSensor.nextSample(); // We're finished with this sample so move to next sample
								
									  // send samples and calculation result to terminal program through UART
									  Serial.print(F("red="));
									  Serial.print(redBuffer[i], DEC);
									  Serial.print(F(", ir="));
									  Serial.print(irBuffer[i], DEC);
								
									  Serial.print(F(", FC="));
									  Serial.print(fc, DEC);
								
									  Serial.print(F(", FCvalid="));
									  Serial.print(validFC, DEC);
								
									  Serial.print(F(", SPO2="));
									  Serial.print(spo2, DEC);
								
									  Serial.print(F(", SPO2Valid="));
									  Serial.println(validSPO2, DEC);
								
									  Serial.print(F(", TEMP="));
									  Serial.print(temp, 1); // print the temperature with one decimal place
								
									  Serial.print(F(", TEMPvalid="));
									  Serial.println(1); // assuming the temperature is always valid
									}
								
									// After gathering 25 new samples recalculate HR and SP02
									maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &fc, &validFC);
								
									// Send data to server
									sendHealthData(fc, spo2, temp);
								  }
								}
								
								void sendHealthData(int32_t fc, int32_t spo2, float temp) {
								  if (WiFi.status() == WL_CONNECTED) {
									HTTPClient http;
									// Specify the URL of the API
									http.begin(serverName);
									// Specify the content type
									http.addHeader("Content-Type", "application/json");
									// Create the JSON payload to send
									String jsonPayload = "{\"fc\": \"" + String(fc) + "\", \"spo2\": \"" + String(spo2) + "\", \"temp\": \"" + String(temp, 1) + "\"}";
									// Send the POST request
									int httpResponseCode = http.POST(jsonPayload);
									// Check the response from the server
									if (httpResponseCode > 0) {
									  String response = http.getString();
									  Serial.println(httpResponseCode);
									  Serial.println(response);
									} else {
									  Serial.print("Error en la solicitud: ");
									  Serial.println(httpResponseCode);
									}
									// End the connection
									http.end();
								  } else {
									Serial.println("Error en la conexión WiFi");
								  }
								}
								
							

Step 4

For this code, I needed to install the following libraries in Arduino

Library Name Purpose
SparkFun MAX3010x Library Used for interfacing with the MAX30100, MAX30101, and MAX30102 pulse oximeter and heart-rate sensor modules.
EspSoftwareSerial Enables serial communication on other digital pins of the ESP8266 and ESP32, similar to the Arduino SoftwareSerial library.
ArduinoHttpClient Facilitates HTTP communication for interacting with web servers and APIs.
Image 3 Image 3 Image 3

Step 5

After having everything ready, I tested the internet connection to ensure it was established, as it was crucial for connecting the data from the XIAO and sending it to our database.

Step 6

Once the connection was ready, it was time to verify that the code could correctly read the vital signs.

Variable name Meaning
TemValid=1 Means that value of the temperature is valid.
FCValid=1 Means that the Heart Beat rate is valid.
SPO2Valid=1 Means that the spo2 is valid.

Since everything is working correctly, it is time to link the information from the XIAO with the app.

Files

App Desing

For the app design, I decided to use Flutter Flow. Considering the need for a database, I used various programs to create a connection from the XIAO via WiFi to an API using the RENDER program, as it facilitates the connection between GitLab and Firebase.

Image 3
Program Description
XIAO Collects sensor data and sends it via WiFi.
WiFi Connection Enables XIAO to connect to the internet and communicate with the API.
API Endpoint (RENDER) Acts as an intermediary, receiving data from XIAO and forwarding it to Firebase.
GitLab Manages the API code, ensuring it is up-to-date and functional.
Firebase Stores the data received from the API and makes it accessible in real-time.
Flutter Flow App Connects to Firebase to fetch and display the sensor data to the user.

FireBase by Google

In Firebase, I created a database to receive data from the XIAO and link it with the app.

Step Action
Step 1 Access the Firebase Console and create a new project.
Step 2 Configure Firebase for your Flutter project:
Step 3 Select or create a project in Firebase Console.
Step 4 Connect with nummer in your Flutter Flow app, in settings
Step 5 Set up Firestore to store real-time data. Firestore is a flexible NoSQL database that you can use to store and synchronize data across your app clients.
Image 3 Image 3 Image 3 Image 3 Image 3 Image 3 Image 3 Image 3

Once the database is set up with real-time defined variables, similar to those in the Arduino code, they are ready to be linked with the app in Flutter Flow.

Flutter Flow app desing

For the app design, I used Flutter Flow because its platform is more user-friendly than others, and I preferred its design over the alternatives.

Step 1

First, I created an account on the platform.

Image 3

Step 2

I created a new project named "GesundFit," which became the name of my app.

Image 3

Step 3

Within the project, I used a template that I modified to suit my preferences and needs.

Image 3 Image 3

Step 4

I added various screens so that the user could learn about the product, register, and have a specific section where they could monitor their vital signs.

Image 3

Step 5

The screen where the vital signs are displayed is important because this is where the variables with the exact names we used in our Arduino code will be established.

Image 3

Final Result off the GesundFit APP

Image 1 Image 1 Image 1

With the variables in the database and the app design ready, we are prepared to proceed with the next step for the connection.

Connection between Flutter Flow and Firebase

Step 1

To connect our app with the Fiera database, it is very quick. First, we go to the configuration in Flutter Flow.

Image 3

Step 2

We go to Firebase and navigate to where it says "Connect to an existing database."

Image 3

Step 3

Here we add the number of the ID that we fine in our Firebase settings project.

Image 3 Image 3 Image 3

Git Lab repository

In GitLab, we created an account to establish the connection between the API and the repository.

Step 1

Create an account on GitLab.

Create an account on GitLab

Step 2

Once inside GitLab, create a project named "GesundFit".

Create a project named GesundFit

Step 3

Clone the repository by copying the SSH link.

Copy the SSH link Copy the SSH link

Step 4

Go to the terminal on your computer and use the command “git clone” along with the previously copied link to clone the repository to your computer.

Use git clone command

Once ready up to this point, it is time to move on to the next step.

Visual Studio Code

Now we will use Visual Studio to establish the foundation of the API, which we will later connect with Render and the application's database.

Step 1

Since we were previously in our terminal within the folder that was already cloned, using the command "code ." will automatically open Visual Studio Code with everything that was cloned.

Step 2

To verify that our communication with GitLab is working, we will create a basic file and upload it to the repository to check if we can access it online.

The name of this file will be "basic.py" because as we know ".py" means to play it.

Copy the SSH link

We need to make our normal git commit and push in order to save all of this in out gitLab acoount.

After this, we are going to open our terminal again and to write " Python ...." anthe name of this file to play it.

Copy the SSH link

As we can see there is a link so we need to open it.

Copy the SSH link

And it work´s.

Step 3

Within Visual Studio Code, we will create a new file that will be our project API.

We add the following code where it establishes the direct connection with Firebase

Final code

							from flask import Flask, jsonify, request
							import firebase_admin
							from firebase_admin import credentials, firestore
							from datetime import datetime
							from dotenv import load_dotenv
							import os
							
							load_dotenv()
							
							cred = credentials.Certificate(
								{
									"type": os.getenv("TYPE"),
									"project_id": os.getenv("PROJECT_ID"),
									"private_key_id": os.getenv("PRIVATE_KEY_ID"),
									"private_key": os.getenv("PRIVATE_KEY"),
									"client_email": os.getenv("CLIENT_EMAIL"),
									"client_id": os.getenv("CLIENT_ID"),
									"auth_uri": os.getenv("AUTH_URI"),
									"token_uri": os.getenv("TOKEN_URI"),
									"auth_provider_x509_cert_url": os.getenv("AUTH_PROVIDER_X509_CERT_URL"),
									"client_x509_cert_url": os.getenv("CLIENT_X509_CERT_URL"),
									"universe_domain": os.getenv("UNIVERSE_DOMAIN"),
									}
							)
							
							firebase_admin.initialize_app(cred)
							db = firestore.client()
							live_ref = db.collection('live').document('3mLXo2jXDBajROCaYMLN')
							
							app = Flask(__name__)
							
							
							base = '/api/valeria/'
							
							
							@app.route("/")
							def home():
								return "Hello I'm Vale!"
							
							
							@app.route(base, methods=['POST'])
							def set_data():
								data = request.json
							
								temp = float(data.get('temp'))
								spo2 = float(data.get('spo2'))
								fc = float(data.get('fc'))
							
								if temp is None or spo2 is None or fc is None:
									return jsonify({"error": "Missing data"}), 400
							
								send_to_firebase(temp, spo2, fc)
							
								return jsonify({"success": True}), 200
							
							
							def send_to_firebase(temp, spo2, fc):
								print(f"Temperatura: {temp}")
								print(f"Oxigenacion: {spo2}")
								print(f"Frecuencia cardiaca: {fc}")
							
								data = {
									"temp": temp,
									"spo2": spo2,
									"fc": fc
								}
								live_ref.set(data)  # Update data
							
							
							if __name__ == '__main__':
								app.run(debug=True)

						

Here we haved established the variables of our project, the same variables that we have used in everything.

  • temp": temp,
  • "spo2": spo2,
  • "fc": fc
  • Step 4

    After this we create a new git commit and we push it again.

    Copy the SSH link

    API by Render

    To observe the database in action, we need API integration with Render.

    Step 1

    First, create an account on Render directly using GitLab.

    Copy the SSH link

    Step 2

    I created a web service by selecting the option "Build and deploy from a Git repository."

    Copy the SSH link Copy the SSH link

    Step 3

    And there, the only available option should appear.

    Copy the SSH link

    Step 4

    Right there, we will find the "Add from env." option that we will need to create this connection between the databases and the app.

    Copy the SSH link

    Step 5

    Here we will observe the live activity of the database running with the app and with Xiao's information.

    Copy the SSH link

    FINAL RESULT

    Here its the final result with the SmartBand, the sensors,the app and the datebase.

    External desing

    3D Case Modelling

    We used Fusion 360 to design the smart band case.

    Step 1: Case Design

    Tool Used: Fusion 360

    We utilized Fusion 360 to design the smart band case.

    Copy the SSH link Copy the SSH link Copy the SSH link Copy the SSH link Copy the SSH link

    Step 2: Case Design Division

    We divided the case design into two parts to facilitate PCB insertion.

    This design choice allows the sensor to be exposed for direct skin contact, while safeguarding other components.

    Copy the SSH link Copy the SSH link Copy the SSH link

    Step 3: Exporting to STL for 3D Printing

    Exporting to STL for 3D Printing

    We exported the design to STL format from Fusion 360 to prepare it for 3D printing.

    Step 4: Slicing and Material Settings

    Slicing in Ultimaker Cura and Material Parameter Adjustment

    We used Ultimaker Cura to slice the model.

    We adjusted the material parameters for the TPU filament that was used.

    Copy the SSH link Copy the SSH link Copy the SSH link

    The same for both parts of the smartband case.

    Copy the SSH link Copy the SSH link

    And printing them without problems.

    Copy the SSH link Copy the SSH link Copy the SSH link

    More 3D Print Process

    Designing Smart Band Straps

    We will now proceed with designing the straps for the smart band.

    Step 1: Designing Straps in Fusion 360

    Tool Used: Fusion 360

    We designed the straps using Fusion 360, ensuring ergonomic comfort and durability.

    Copy the SSH link

    Step 2: Exporting to DXF for Laser Cutting

    We exported the strap designs to DXF format from Fusion 360 to facilitate laser cutting.

    Step 3: Using Faux Leather Material

    We utilized faux leather material for the straps to achieve the desired aesthetics and durability.

    Step 4: Adjusting SmartCarve Parameters

    We adjusted the SmartCarve parameters to cut the faux leather without causing burn marks.

    Copy the SSH link

    Final result

    I glued the leather strips with Resitol 5000 to prevent them from coming loose.

    Copy the SSH link Copy the SSH link Copy the SSH link

    More Laser cutting Process

    Final smartband "GesundFit"