Project tutorial
Hygie - Better follow and understand your menopause

Hygie - Better follow and understand your menopause © GPL3+

A device to better follow your body's reactions. Hygie helps you to understand the evolution of symptoms that can affect you on daily basis

  • 250 views
  • 0 comments
  • 0 respects

Components and supplies

Necessary tools and machines

Apps and online services

About this project

Introduction

Menopause is an inevitable phenomenon in a woman's life. It results in a strong hormonal upheaval that can have more or less consequences depending on the individual.

These symptoms can be very varied, a list of the 35 main ones can be found here.

1. Hygie - Better follow and understand the symptoms of your menopause.

The Hygie project has been designed to help women listen to and follow their bodies during this complicated period. To do this, it offers a simple and evolving interface that allows the different symptoms to be traced over time. The small device can easily fit into a coat pocket or handbag to accompany you discreetly everywhere.

Hygieia (Hygie in French) was one of the daughters of the God of medecine Asclepius in the Greek mythology. she was the goddess/personification of health.

The 4 buttons on the top allow you to trace the symptoms over time. Each of them must be associated with one (single click) or two (double click) symptoms according to the need and therefore recurrence for its user.

Here is a configuration example :

  • Button 1 (single click) : Hot Flashes
  • Button 1 (double click) : Fatigue
  • Button 2 (single click) : Hair Loss
  • Button 2 (double click) : Incontinence
  • Button 3 (single click) : Change in odor
  • Button 4 (single click) : Mood Swings

Pressing these buttons at the onset of symptoms will allow you to trace the event over time and better understand their recurrence. Using Hygie for a period of time will thus generate graphs on the mobile application.

These data are also associated in tabular form with simple interpretations such as "The phenomenon of fatigue is particularly present after a meal" or "Gum problems" are often associated with "Breast Soreness".

But Hygie isn't just a simple counter, it also offers more advanced features to stay in tune with your body. At the onset of certain symptoms, the user can place her thumb on the spot in the middle of the circle and measure her heartbeat in real time.

This information can be associated with the symptom in question.

The user can take her temperature remotely

The user can also place the device on her belly to measure her breathing speed.

Now that we can track and trace the evolution of these symptoms, it is time to work to reduce them.

You can add activities recommended by the application that will likely have a positive effect on your symptoms.

Over time, you can easily check their effectiveness by looking at the graphs!

To remedy certain symptoms such as sleep and concentration problems, it is sometimes advisable to meditate or try to focus your mind on something soothing.

In this case, the module will emit a blue halo that will pulse at the speed of a calm breath. Try to take deep breaths, concentrating as much as possible on the light.

2 Build the device

2.1 Block diagram, description and cost of components

The next section describes each of the components shown in the diagram. Most of these components are not unique and can be replaced by equivalent providing the same functionalities. For example, if you want to add a 3-axis magnetometer you can replace the MPU6050 with an MPU9250. The code has been separated into functions that should allow you to easily replace components.

On all the Arduino circuits on the market, this one is probably one of the smallest and cheapestmicrocontroler board. There is only the absolute minimum to run the onboard Atmega328p (not even a USB connector !).

To program it, we have to use another Arduino UNO board (example), or a FTDI adapter. It has a Atmega328p (same as Arduino UNO) and can be bought with 3.3V (8Mhz) or 5V (16MHz) configuration. Here we choose 3.3V to maximize energie savings.

Those little board can detect movements on several axes. We now know them well from playing on our smartphone. This one has 6 axes (no magneto), but this should be way enough for our application.

Here is a little demo application I made based on FreeIMU software. It's linked to a processing interface (also available on GIT repo).

HC-06 module is a easy to use interface to prototype Bluetooth module. It communicate with the main module using a serial communication and AT command.

This cyber-tronic looking sensor hides a secret behind it's glimmering eye. Unlike most temperature sensors, this sensor measures infrared light bouncing off of remote objects so it can sense temperature without having to touch them physically.

The MAX30100 is an integrated particle-sensing module. It includes internal LEDs, photodetectors, optical elements, and low-noise electronics with ambient light rejection. The new version MAX30102 work fine as well with the same code. I also tried the MAX30105, but it seems a bit less stable.

Our system is probably not always going to be connected on Bluetooth. When it's turned off, it can't exactly know what time is it. A RTC or Real Time Clock is here to ensure that the system always know the date and time when a button is press.

This device has two functions : It manages the flow of current to allow the system to be powered by the battery and recharged via USB. But it also boosts the 3.7V Lipo voltage to 5V.

To use the remote temperature reading function, it is advisable to project a red light on the object where you want to take the reading. Instead of adding just a simple red LED, I used an RGB LED because there are still several unused PINs on the microcontroller. The green LED will allow me to indicate information to the user such as the validation of a button press. The blue LED is used for the Relax LED Breathing.

Here I choose 12mm push buttons as they will be easier to find if you use the device in a bag for exemple. Don't forget to use a pull-up resistor !

This button is simply there to cut power to the system. However, it does not prevent the battery from recharging.

This board is used to load the program into the ATmega328p. By leaving it plugged in it also allows to create a serial link with the computer for DEBUG.

2.2 Hardware

In this section you will find the circuit schematic :

The most important thing to remember here is that almost whole the system works in 3.3V. This forced me to carefully select the components (at first I wanted to use WS2812 RGB LEDs, but they are rather unstable in 3.3V so I had to remove them... too bad for the color rendering!).

At first, I thought the 3.6V Bluetooth would work on the 3.7V battery, but it seemed unstable... So I had to add a BOOST at the end to power only this part with 5V and step down everything else with the embedded regulator on the Arduino Pro Mini. I will probably change the Bluetooth board on the next version to remove the BOOST and have the all system working at 3.3V. This will also be a good occasion to move to BLE.

Another interesting part will be to develop small boards with MOSFETs to cut the power supply of unused modules. Indeed, this system uses some functionality only very occasionally. It is therefore a pity that a module like the MPU6050 consumes power all the time.

2.3 Embedded Software

  • First download and install the Arduino program from HERE. Don't forget to install the USB driver.
  • Download the repository open with Arduino the file in Software/Hygie_main
  • Plug the programer to the Arduino Pro Mini (RX on TX and vice versa!). Plug the USB
  • IMPORTANT : Choose the Arduino FIO board (FIO board also has a Atmega328p and run at 8Mhz).
  • Select the PORT. If you are not sure wich one is it, unplug the USB and verify the port. If you plug the USB and verify again you should have a new port.
  • Select the library manager and install the following libraries :

Now you can run your Verify your program using Ctrl+R. If everything is alright, the message Done compiling should appear. After this, use Ctrl+U to load the program on the Arduino Pro Mini Board.

Then, you can open the Serial Monitor to verify the different function of the system

Now you have the entire program ready in the microcontroler. As we have many different peripherals on the system, it could be interesting to test every module and connection separately. That's the reason why you can find an Arduino program dedicated to each communicating peripheral on the main Arduino board.

All those programs use the Serial fonction. It's an easy way to get precise information to see if everything is OK.

To test the MPU6050, I actually added a Processing program from FreeIMU. This program allow you to check your board position on computer. To use this program, you have to download Processing and open the.pde file with it. Don't forget to change the PORT number in the Processing program !

2.4 3D design

All the design are made with Sketchup 2017. So you can, as an individual, open and modify the 3D for free.

Sketchup cannot natively export STL files for 3D printing. You have to go in the Extension Manager and add a STL module.

Using this module, you will generate a STL file readable by 3D printing software like Cura for Ultimaker. Choose the software dedicated to your printer.

Now we are ready to print the Hygie device

2.5. Graph on your phone

Bluetooth application development is a world I didn't know very well. Starting from scratch from Android Studio scared me a bit. So I tried App Inventor MIT for a more graphical approach. It's a free and easy to use software to create Android applications.

The creation of basic functionality like a simple serial conversation with the Arduino is quickly set up. You can find many examples on the internet like here.

On the other hand, setting up a more complex window management and especially a communication protocol can be quite a lot of work.

For Hygie I created an application based on 2 windows allowing to connect/change mode on one and to retrieve the data available on the other. In this part, the application sends a request message to the module. If this one has data, it sends them sequentially until a message to prevent that the buffer is empty. Each symptom is then classified with its icon and a small drop-down menu displaying each request.

To use the application, you need to create an account on MIT App Inventor. Then, you just have to import the.aia project available on the Git repo.

Then you can click on Build (Provide QR code)

Then, download the MIT Inventor app on your smartphone and click on scan QR code. This will download the app, just install it and paire the Bluetooth HC-05 on your Parameter.

Now you are ready !

3. Key steps of the conception

3.1. Paper model + Button + Dimmer LED (WS2812)

I like to start a design with a 3D paper model. It's not much but it give you the opportunity to see if everything can fit in it and to carry the object in your hand. Here I also wanted to verify the brightness of WS2812 inside the paper (at the end, I didn't use those LED).

3.2 Test all the functionalities available on a development board

At this time, several components where still missing : MLX90614, batteries, BOOST and MAX30100 (replaced here by a MAX30105)

3.3 First 3D print, not sure everything is going to fit...

3.4 Second versionprinted,paint and assembly

Everything fit ! But the assembly wasn't easy... So the last version will have 16mm (0.63") height inside, instead of 14mm (0.55").

3.5 waiting for the lasts components to arrive

At this stage, I have not yet received all the components to finish testing all the features. The most worrisome is probably the MLX90614 temperature sensors which are out of stock (or at exorbitant prices everywhere). The batterie/boost manager is also missing. So I used a simple TP4056 manager for now (no 5V... no Bluetooth...).

I guess a lot of medical devices are using the temperature sensor and the current crisis is causing them to be out of stock... As most of the software bricks already exist, this shouldn't prevent me from finishing the development.

3.6 Pseudo Real time Arduino Code

Most of Arduino code examples don't work in real time. The Atmega328p is actually a pretty slow microcontroler compare to other from NXP or ST so it's not common to parallel much tasks on it.

So I tried a "home made" (and very simple!) real time system. The buttons are the main controller to switch from the different modes (long press button).

The main loop is counting a 2 bytes variable

int cpt=0; // counting the loop from 0 to 0xFFFF

When it reach 0xFFFF it goes back to 0 and start over.

My main tasks are defined with a process frequency (the number of time it will be call during the time "cpt" goes from 0 to 0xFFFF).

#define MPU6050_FREQUENCY 128
#define MPU6050_FREQUENCY_READ_PER_CYCLE cpt%((MAX_COUNTER/MPU6050_FREQUENCY)+1)

In the main loop, the functions are also called depending on their mode (defined with the buttons). Here the call will only happen if we are in device_MODE 4, which mean a long press on button 4.

if (MPU6050_FREQUENCY_READ_PER_CYCLE == 0 && device_MODE==4){

3.7 Working on I2C bus

We have 5 components communicating with I2C. The Arduino Micro as Master and 4 slaves (MLX90614, MPU6050, MAX30100 and DS1307). As those components never run together, I thought it should work fine...

BUT MPU6050 and DS1307 are both using the identification address 0x68 ! So you both will answer I2C request.

After running a lot of test with both device not working together... I checked the MPU6050 datasheet. The PIN AD0 is present on the chip to change your address to 0x69 if you pull it up. This was designed in case you want to use 2 MPU6050 on the same bus. So just a pull up, and everything seems to work fine.

3.8 Memory and storage

As we want the device to work even if there isn't any Bluetooth connection, we need to store all the recorded values.

Atmega328p has 1024 bytes of EEPROM memory available. I choose 8 bytes "cluster" with all those informations coded on 1 bytes each :

Symptom Number / Value (0 if button) / Hours / Minutes / Seconde / Day / Month / Year

We can store 128 clusters in the EEPROM. After what we need to load data on the application.

3.9 Manage Battery

It took me some time to choose the main control board for my system. Indeed, I wanted to stay in the Arduino standard in order to accelerate the development of my libraries. However, most Arduino boards work at 5V because that's the voltage needed for the Atmega328p microcontroller to work at full power, i.e. 16MHz.

I also wanted to use a Lithium battery for the power supply. The disadvantage is that these batteries have a nominal voltage of 3.7V. To raise the voltage to 5V, it is in this case necessary to use a BOOST module, which is unfortunately very energy consuming...

To develop this project, I made the choice to lower the speed of the Atmega328p at 8Mhz. At this speed I can use my Atmega328 at 3.3V which is perfect for Battery and compatibility. Thus, I don't need to use a Boost module or 5V/3.3V voltage converters. On the other hand, I can only use my Atmega328p at 8Mhz and make sure that all the selected components work in the 3.3V range.

The use of an ATmega328p at 8Mhz is really limited in power level. Here, I made the bet that since I don't use all the components together, 8MHz could be sufficient... For the moment everything is fine ! :)

At first, I wanted to don't use any BOOST. The specification of HC-05 Bluetooth was minimum 3.6V. so I thought I could power the Bluetooth directly from the Lipo at 4.2V. With this solution a simple TP4056 was enough to manage my battery. But the Bluetooth was unstable with this solution... so I had to change my power board and have a 5V BOOST output... regulated again to 3.3V :-(

To have good energie performance is a complicated work. It is most of the time impossible to do it with components on the shelf like the one I used... Here, I can only avoid major energy leak by setting unused components to sleep and changing certain components on the board.

As an example of energy optimisation, in most circuit people use of 10kohm pull resistor for buttons. But here is the energy lost :

I=U/R >> I=3.3V / 10000ohm >> I=0.33mA per hour !

0.33mA per hours are constantly leaking from those resistors which is a huge loss for embedded system. One resistor like this will drain our 1000mA resistor in 125 days...

If you use a simple 100kohm you need 0.033mA so 1250 days !

4. Conclusion & Improvement

This project has been really interesting to build. It taught me a lot of things in different technical parts. The whole thing is functional, but still needs improvement in many parts :

  • Data management and display on the Bluetooth application to be improved
  • Sorting in software libraries to free memory space.
  • Better power management to have an autonomy of at least one month.
  • Designing a PCB for industrialise. The wiring is a bit too long right now ^^
  • ...

I hope it will help a lot of people in the development of medical connected objects. I will find time to continue to improve it quickly :)

If you have any questions, don't hesitate to contact me !

5. Ressources

  • 3D design : Sketchup
  • 3D design render : Twilight Render V2
  • 3D print ready : Cura
  • Illustrations : dreamstime.com (Proof of Licence available)
  • Assembly : Power Point / Paint / www4.lunapic.com
  • Hardware design : Fritzing
  • Software : Arduino & Processing

Code

Main_Arduino_CodeArduino
  
#include <Wire.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <SoftwareSerial.h>
#include <Adafruit_MLX90614.h>
#include "MAX30105.h"
#include "heartRate.h"
#include "RTCDS1307.h"
#include <EEPROM.h>

#define MPU_ADDR 0x68
#define MEM_START_ADDR 0x6E
#define MEM_R_W 0x6F

#define Min_Time_Short_Push_Button 2
#define Min_Time_Long_Push_Button 15

#define MAX_COUNTER 0xFFFF

#define Buttons_FREQUENCY 64
#define Buttons_FREQUENCY_READ_PER_CYCLE cpt%((MAX_COUNTER/Buttons_FREQUENCY)+1)
#define MAX30105_FREQUENCY 64
#define MAX30105_FREQUENCY_READ_PER_CYCLE cpt%((MAX_COUNTER/MAX30105_FREQUENCY)+1)
#define MLX90614_FREQUENCY 1
#define MLX90614_FREQUENCY_READ_PER_CYCLE cpt%((MAX_COUNTER/MLX90614_FREQUENCY)+1)
#define MPU6050_FREQUENCY 128
#define MPU6050_FREQUENCY_READ_PER_CYCLE cpt%((MAX_COUNTER/MPU6050_FREQUENCY)+1)
#define DS1307_FREQUENCY 1
#define DS1307_FREQUENCY_READ_PER_CYCLE cpt%((MAX_COUNTER/DS1307_FREQUENCY)+1)
#define HC06_FREQUENCY 128
#define HC06_FREQUENCY_READ_PER_CYCLE cpt%((MAX_COUNTER/HC06_FREQUENCY)+1)
#define Serial_FREQUENCY 128
#define Serial_FREQUENCY_READ_PER_CYCLE cpt%((MAX_COUNTER/Serial_FREQUENCY)+1)
#define DimLED_FREQUENCY 64
#define DimLED_FREQUENCY_READ_PER_CYCLE cpt%((MAX_COUNTER/DimLED_FREQUENCY)+1)
#define DebugLED_FREQUENCY 1
#define DebugLED_FREQUENCY_READ_PER_CYCLE cpt%((MAX_COUNTER/DebugLED_FREQUENCY)+1)

long lastRead = 0;
byte processed_packet[8];
byte received_packet[50];
byte temp = 0;
byte fifoCountL = 0;
byte fifoCountL2 = 0;
byte packetCount = 0x00;
boolean longPacket = false;
boolean firstPacket = true;
float q[4];

//This 3D array contains the default DMP memory bank binary that gets loaded during initialization.
//In the Invensense UC3-A3 firmware this is uploaded in 128 byte tranmissions, but the Arduino Wire
//library only supports 32 byte transmissions, including the register address to which you're writing,
//so I broke it up into 16 byte transmission payloads which are sent in the dmp_init() function below.
//
//This was reconstructed from observed I2C traffic generated by the UC3-A3 demo code, and not extracted
//directly from that code. That is true of all transmissions in this sketch, and any documentation has
//been added after the fact by referencing the Invensense code.

// this tab takes 6% of memory program storage 
unsigned const char dmpMem[8][16][16] PROGMEM = {
  {
    {0xFB, 0x00, 0x00, 0x3E, 0x00, 0x0B, 0x00, 0x36, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00},
    {0x00, 0x65, 0x00, 0x54, 0xFF, 0xEF, 0x00, 0x00, 0xFA, 0x80, 0x00, 0x0B, 0x12, 0x82, 0x00, 0x01},
    {0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x28, 0x00, 0x00, 0xFF, 0xFF, 0x45, 0x81, 0xFF, 0xFF, 0xFA, 0x72, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x03, 0xE8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x7F, 0xFF, 0xFF, 0xFE, 0x80, 0x01},
    {0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x3E, 0x03, 0x30, 0x40, 0x00, 0x00, 0x00, 0x02, 0xCA, 0xE3, 0x09, 0x3E, 0x80, 0x00, 0x00},
    {0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00},
    {0x41, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x2A, 0x00, 0x00, 0x16, 0x55, 0x00, 0x00, 0x21, 0x82},
    {0xFD, 0x87, 0x26, 0x50, 0xFD, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x05, 0x80, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00},
    {0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6F, 0x00, 0x02, 0x65, 0x32, 0x00, 0x00, 0x5E, 0xC0},
    {0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0xFB, 0x8C, 0x6F, 0x5D, 0xFD, 0x5D, 0x08, 0xD9, 0x00, 0x7C, 0x73, 0x3B, 0x00, 0x6C, 0x12, 0xCC},
    {0x32, 0x00, 0x13, 0x9D, 0x32, 0x00, 0xD0, 0xD6, 0x32, 0x00, 0x08, 0x00, 0x40, 0x00, 0x01, 0xF4},
    {0xFF, 0xE6, 0x80, 0x79, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xD6, 0x00, 0x00, 0x27, 0x10}
  },
  {
    {0xFB, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0xFA, 0x36, 0xFF, 0xBC, 0x30, 0x8E, 0x00, 0x05, 0xFB, 0xF0, 0xFF, 0xD9, 0x5B, 0xC8},
    {0xFF, 0xD0, 0x9A, 0xBE, 0x00, 0x00, 0x10, 0xA9, 0xFF, 0xF4, 0x1E, 0xB2, 0x00, 0xCE, 0xBB, 0xF7},
    {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x0C},
    {0xFF, 0xC2, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0xCF, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x14},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x03, 0x3F, 0x68, 0xB6, 0x79, 0x35, 0x28, 0xBC, 0xC6, 0x7E, 0xD1, 0x6C},
    {0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x6A, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x30},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x25, 0x4D, 0x00, 0x2F, 0x70, 0x6D, 0x00, 0x00, 0x05, 0xAE, 0x00, 0x0C, 0x02, 0xD0}
  },
  {
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x54, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x01, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0xFF, 0xEF, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00},
    {0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
  },
  {
    {0xD8, 0xDC, 0xBA, 0xA2, 0xF1, 0xDE, 0xB2, 0xB8, 0xB4, 0xA8, 0x81, 0x91, 0xF7, 0x4A, 0x90, 0x7F},
    {0x91, 0x6A, 0xF3, 0xF9, 0xDB, 0xA8, 0xF9, 0xB0, 0xBA, 0xA0, 0x80, 0xF2, 0xCE, 0x81, 0xF3, 0xC2},
    {0xF1, 0xC1, 0xF2, 0xC3, 0xF3, 0xCC, 0xA2, 0xB2, 0x80, 0xF1, 0xC6, 0xD8, 0x80, 0xBA, 0xA7, 0xDF},
    {0xDF, 0xDF, 0xF2, 0xA7, 0xC3, 0xCB, 0xC5, 0xB6, 0xF0, 0x87, 0xA2, 0x94, 0x24, 0x48, 0x70, 0x3C},
    {0x95, 0x40, 0x68, 0x34, 0x58, 0x9B, 0x78, 0xA2, 0xF1, 0x83, 0x92, 0x2D, 0x55, 0x7D, 0xD8, 0xB1},
    {0xB4, 0xB8, 0xA1, 0xD0, 0x91, 0x80, 0xF2, 0x70, 0xF3, 0x70, 0xF2, 0x7C, 0x80, 0xA8, 0xF1, 0x01},
    {0xB0, 0x98, 0x87, 0xD9, 0x43, 0xD8, 0x86, 0xC9, 0x88, 0xBA, 0xA1, 0xF2, 0x0E, 0xB8, 0x97, 0x80},
    {0xF1, 0xA9, 0xDF, 0xDF, 0xDF, 0xAA, 0xDF, 0xDF, 0xDF, 0xF2, 0xAA, 0xC5, 0xCD, 0xC7, 0xA9, 0x0C},
    {0xC9, 0x2C, 0x97, 0x97, 0x97, 0x97, 0xF1, 0xA9, 0x89, 0x26, 0x46, 0x66, 0xB0, 0xB4, 0xBA, 0x80},
    {0xAC, 0xDE, 0xF2, 0xCA, 0xF1, 0xB2, 0x8C, 0x02, 0xA9, 0xB6, 0x98, 0x00, 0x89, 0x0E, 0x16, 0x1E},
    {0xB8, 0xA9, 0xB4, 0x99, 0x2C, 0x54, 0x7C, 0xB0, 0x8A, 0xA8, 0x96, 0x36, 0x56, 0x76, 0xF1, 0xB9},
    {0xAF, 0xB4, 0xB0, 0x83, 0xC0, 0xB8, 0xA8, 0x97, 0x11, 0xB1, 0x8F, 0x98, 0xB9, 0xAF, 0xF0, 0x24},
    {0x08, 0x44, 0x10, 0x64, 0x18, 0xF1, 0xA3, 0x29, 0x55, 0x7D, 0xAF, 0x83, 0xB5, 0x93, 0xAF, 0xF0},
    {0x00, 0x28, 0x50, 0xF1, 0xA3, 0x86, 0x9F, 0x61, 0xA6, 0xDA, 0xDE, 0xDF, 0xD9, 0xFA, 0xA3, 0x86},
    {0x96, 0xDB, 0x31, 0xA6, 0xD9, 0xF8, 0xDF, 0xBA, 0xA6, 0x8F, 0xC2, 0xC5, 0xC7, 0xB2, 0x8C, 0xC1},
    {0xB8, 0xA2, 0xDF, 0xDF, 0xDF, 0xA3, 0xDF, 0xDF, 0xDF, 0xD8, 0xD8, 0xF1, 0xB8, 0xA8, 0xB2, 0x86}
  },
  {
    {0xB4, 0x98, 0x0D, 0x35, 0x5D, 0xB8, 0xAA, 0x98, 0xB0, 0x87, 0x2D, 0x35, 0x3D, 0xB2, 0xB6, 0xBA},
    {0xAF, 0x8C, 0x96, 0x19, 0x8F, 0x9F, 0xA7, 0x0E, 0x16, 0x1E, 0xB4, 0x9A, 0xB8, 0xAA, 0x87, 0x2C},
    {0x54, 0x7C, 0xB9, 0xA3, 0xDE, 0xDF, 0xDF, 0xA3, 0xB1, 0x80, 0xF2, 0xC4, 0xCD, 0xC9, 0xF1, 0xB8},
    {0xA9, 0xB4, 0x99, 0x83, 0x0D, 0x35, 0x5D, 0x89, 0xB9, 0xA3, 0x2D, 0x55, 0x7D, 0xB5, 0x93, 0xA3},
    {0x0E, 0x16, 0x1E, 0xA9, 0x2C, 0x54, 0x7C, 0xB8, 0xB4, 0xB0, 0xF1, 0x97, 0x83, 0xA8, 0x11, 0x84},
    {0xA5, 0x09, 0x98, 0xA3, 0x83, 0xF0, 0xDA, 0x24, 0x08, 0x44, 0x10, 0x64, 0x18, 0xD8, 0xF1, 0xA5},
    {0x29, 0x55, 0x7D, 0xA5, 0x85, 0x95, 0x02, 0x1A, 0x2E, 0x3A, 0x56, 0x5A, 0x40, 0x48, 0xF9, 0xF3},
    {0xA3, 0xD9, 0xF8, 0xF0, 0x98, 0x83, 0x24, 0x08, 0x44, 0x10, 0x64, 0x18, 0x97, 0x82, 0xA8, 0xF1},
    {0x11, 0xF0, 0x98, 0xA2, 0x24, 0x08, 0x44, 0x10, 0x64, 0x18, 0xDA, 0xF3, 0xDE, 0xD8, 0x83, 0xA5},
    {0x94, 0x01, 0xD9, 0xA3, 0x02, 0xF1, 0xA2, 0xC3, 0xC5, 0xC7, 0xD8, 0xF1, 0x84, 0x92, 0xA2, 0x4D},
    {0xDA, 0x2A, 0xD8, 0x48, 0x69, 0xD9, 0x2A, 0xD8, 0x68, 0x55, 0xDA, 0x32, 0xD8, 0x50, 0x71, 0xD9},
    {0x32, 0xD8, 0x70, 0x5D, 0xDA, 0x3A, 0xD8, 0x58, 0x79, 0xD9, 0x3A, 0xD8, 0x78, 0x93, 0xA3, 0x4D},
    {0xDA, 0x2A, 0xD8, 0x48, 0x69, 0xD9, 0x2A, 0xD8, 0x68, 0x55, 0xDA, 0x32, 0xD8, 0x50, 0x71, 0xD9},
    {0x32, 0xD8, 0x70, 0x5D, 0xDA, 0x3A, 0xD8, 0x58, 0x79, 0xD9, 0x3A, 0xD8, 0x78, 0xA8, 0x8A, 0x9A},
    {0xF0, 0x28, 0x50, 0x78, 0x9E, 0xF3, 0x88, 0x18, 0xF1, 0x9F, 0x1D, 0x98, 0xA8, 0xD9, 0x08, 0xD8},
    {0xC8, 0x9F, 0x12, 0x9E, 0xF3, 0x15, 0xA8, 0xDA, 0x12, 0x10, 0xD8, 0xF1, 0xAF, 0xC8, 0x97, 0x87}
  },
  {
    {0x34, 0xB5, 0xB9, 0x94, 0xA4, 0x21, 0xF3, 0xD9, 0x22, 0xD8, 0xF2, 0x2D, 0xF3, 0xD9, 0x2A, 0xD8},
    {0xF2, 0x35, 0xF3, 0xD9, 0x32, 0xD8, 0x81, 0xA4, 0x60, 0x60, 0x61, 0xD9, 0x61, 0xD8, 0x6C, 0x68},
    {0x69, 0xD9, 0x69, 0xD8, 0x74, 0x70, 0x71, 0xD9, 0x71, 0xD8, 0xB1, 0xA3, 0x84, 0x19, 0x3D, 0x5D},
    {0xA3, 0x83, 0x1A, 0x3E, 0x5E, 0x93, 0x10, 0x30, 0x81, 0x10, 0x11, 0xB8, 0xB0, 0xAF, 0x8F, 0x94},
    {0xF2, 0xDA, 0x3E, 0xD8, 0xB4, 0x9A, 0xA8, 0x87, 0x29, 0xDA, 0xF8, 0xD8, 0x87, 0x9A, 0x35, 0xDA},
    {0xF8, 0xD8, 0x87, 0x9A, 0x3D, 0xDA, 0xF8, 0xD8, 0xB1, 0xB9, 0xA4, 0x98, 0x85, 0x02, 0x2E, 0x56},
    {0xA5, 0x81, 0x00, 0x0C, 0x14, 0xA3, 0x97, 0xB0, 0x8A, 0xF1, 0x2D, 0xD9, 0x28, 0xD8, 0x4D, 0xD9},
    {0x48, 0xD8, 0x6D, 0xD9, 0x68, 0xD8, 0xB1, 0x84, 0x0D, 0xDA, 0x0E, 0xD8, 0xA3, 0x29, 0x83, 0xDA},
    {0x2C, 0x0E, 0xD8, 0xA3, 0x84, 0x49, 0x83, 0xDA, 0x2C, 0x4C, 0x0E, 0xD8, 0xB8, 0xB0, 0xA8, 0x8A},
    {0x9A, 0xF5, 0x20, 0xAA, 0xDA, 0xDF, 0xD8, 0xA8, 0x40, 0xAA, 0xD0, 0xDA, 0xDE, 0xD8, 0xA8, 0x60},
    {0xAA, 0xDA, 0xD0, 0xDF, 0xD8, 0xF1, 0x97, 0x86, 0xA8, 0x31, 0x9B, 0x06, 0x99, 0x07, 0xAB, 0x97},
    {0x28, 0x88, 0x9B, 0xF0, 0x0C, 0x20, 0x14, 0x40, 0xB8, 0xB0, 0xB4, 0xA8, 0x8C, 0x9C, 0xF0, 0x04},
    {0x28, 0x51, 0x79, 0x1D, 0x30, 0x14, 0x38, 0xB2, 0x82, 0xAB, 0xD0, 0x98, 0x2C, 0x50, 0x50, 0x78},
    {0x78, 0x9B, 0xF1, 0x1A, 0xB0, 0xF0, 0x8A, 0x9C, 0xA8, 0x29, 0x51, 0x79, 0x8B, 0x29, 0x51, 0x79},
    {0x8A, 0x24, 0x70, 0x59, 0x8B, 0x20, 0x58, 0x71, 0x8A, 0x44, 0x69, 0x38, 0x8B, 0x39, 0x40, 0x68},
    {0x8A, 0x64, 0x48, 0x31, 0x8B, 0x30, 0x49, 0x60, 0xA5, 0x88, 0x20, 0x09, 0x71, 0x58, 0x44, 0x68}
  },
  {
    {0x11, 0x39, 0x64, 0x49, 0x30, 0x19, 0xF1, 0xAC, 0x00, 0x2C, 0x54, 0x7C, 0xF0, 0x8C, 0xA8, 0x04},
    {0x28, 0x50, 0x78, 0xF1, 0x88, 0x97, 0x26, 0xA8, 0x59, 0x98, 0xAC, 0x8C, 0x02, 0x26, 0x46, 0x66},
    {0xF0, 0x89, 0x9C, 0xA8, 0x29, 0x51, 0x79, 0x24, 0x70, 0x59, 0x44, 0x69, 0x38, 0x64, 0x48, 0x31},
    {0xA9, 0x88, 0x09, 0x20, 0x59, 0x70, 0xAB, 0x11, 0x38, 0x40, 0x69, 0xA8, 0x19, 0x31, 0x48, 0x60},
    {0x8C, 0xA8, 0x3C, 0x41, 0x5C, 0x20, 0x7C, 0x00, 0xF1, 0x87, 0x98, 0x19, 0x86, 0xA8, 0x6E, 0x76},
    {0x7E, 0xA9, 0x99, 0x88, 0x2D, 0x55, 0x7D, 0x9E, 0xB9, 0xA3, 0x8A, 0x22, 0x8A, 0x6E, 0x8A, 0x56},
    {0x8A, 0x5E, 0x9F, 0xB1, 0x83, 0x06, 0x26, 0x46, 0x66, 0x0E, 0x2E, 0x4E, 0x6E, 0x9D, 0xB8, 0xAD},
    {0x00, 0x2C, 0x54, 0x7C, 0xF2, 0xB1, 0x8C, 0xB4, 0x99, 0xB9, 0xA3, 0x2D, 0x55, 0x7D, 0x81, 0x91},
    {0xAC, 0x38, 0xAD, 0x3A, 0xB5, 0x83, 0x91, 0xAC, 0x2D, 0xD9, 0x28, 0xD8, 0x4D, 0xD9, 0x48, 0xD8},
    {0x6D, 0xD9, 0x68, 0xD8, 0x8C, 0x9D, 0xAE, 0x29, 0xD9, 0x04, 0xAE, 0xD8, 0x51, 0xD9, 0x04, 0xAE},
    {0xD8, 0x79, 0xD9, 0x04, 0xD8, 0x81, 0xF3, 0x9D, 0xAD, 0x00, 0x8D, 0xAE, 0x19, 0x81, 0xAD, 0xD9},
    {0x01, 0xD8, 0xF2, 0xAE, 0xDA, 0x26, 0xD8, 0x8E, 0x91, 0x29, 0x83, 0xA7, 0xD9, 0xAD, 0xAD, 0xAD},
    {0xAD, 0xF3, 0x2A, 0xD8, 0xD8, 0xF1, 0xB0, 0xAC, 0x89, 0x91, 0x3E, 0x5E, 0x76, 0xF3, 0xAC, 0x2E},
    {0x2E, 0xF1, 0xB1, 0x8C, 0x5A, 0x9C, 0xAC, 0x2C, 0x28, 0x28, 0x28, 0x9C, 0xAC, 0x30, 0x18, 0xA8},
    {0x98, 0x81, 0x28, 0x34, 0x3C, 0x97, 0x24, 0xA7, 0x28, 0x34, 0x3C, 0x9C, 0x24, 0xF2, 0xB0, 0x89},
    {0xAC, 0x91, 0x2C, 0x4C, 0x6C, 0x8A, 0x9B, 0x2D, 0xD9, 0xD8, 0xD8, 0x51, 0xD9, 0xD8, 0xD8, 0x79}
  },
  {
    {0xD9, 0xD8, 0xD8, 0xF1, 0x9E, 0x88, 0xA3, 0x31, 0xDA, 0xD8, 0xD8, 0x91, 0x2D, 0xD9, 0x28, 0xD8},
    {0x4D, 0xD9, 0x48, 0xD8, 0x6D, 0xD9, 0x68, 0xD8, 0xB1, 0x83, 0x93, 0x35, 0x3D, 0x80, 0x25, 0xDA},
    {0xD8, 0xD8, 0x85, 0x69, 0xDA, 0xD8, 0xD8, 0xB4, 0x93, 0x81, 0xA3, 0x28, 0x34, 0x3C, 0xF3, 0xAB},
    {0x8B, 0xF8, 0xA3, 0x91, 0xB6, 0x09, 0xB4, 0xD9, 0xAB, 0xDE, 0xFA, 0xB0, 0x87, 0x9C, 0xB9, 0xA3},
    {0xDD, 0xF1, 0xA3, 0xA3, 0xA3, 0xA3, 0x95, 0xF1, 0xA3, 0xA3, 0xA3, 0x9D, 0xF1, 0xA3, 0xA3, 0xA3},
    {0xA3, 0xF2, 0xA3, 0xB4, 0x90, 0x80, 0xF2, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3},
    {0xA3, 0xB2, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xB0, 0x87, 0xB5, 0x99, 0xF1, 0xA3, 0xA3, 0xA3},
    {0x98, 0xF1, 0xA3, 0xA3, 0xA3, 0xA3, 0x97, 0xA3, 0xA3, 0xA3, 0xA3, 0xF3, 0x9B, 0xA3, 0xA3, 0xDC},
    {0xB9, 0xA7, 0xF1, 0x26, 0x26, 0x26, 0xD8, 0xD8, 0xFF}
  }
};

//DMP update transmissions (Bank, Start Address, Update Length, Update Data...)
// 13% of global variables
static byte dmp_updates[29][9] =
{
  {0x03, 0x7B, 0x03, 0x4C, 0xCD, 0x6C} //FCFG_1 inv_set_gyro_calibration
  ,{0x03, 0xAB, 0x03, 0x36, 0x56, 0x76} //FCFG_3 inv_set_gyro_calibration
  ,{0x00, 0x68, 0x04, 0x02, 0xCB, 0x47, 0xA2} //D_0_104 inv_set_gyro_calibration
  ,{0x02, 0x18, 0x04, 0x00, 0x05, 0x8B, 0xC1} //D_0_24 inv_set_gyro_calibration
  ,{0x01, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00} //D_1_152 inv_set_accel_calibration
  ,{0x03, 0x7F, 0x06, 0x0C, 0xC9, 0x2C, 0x97, 0x97, 0x97} //FCFG_2 inv_set_accel_calibration
  ,{0x03, 0x89, 0x03, 0x26, 0x46, 0x66} //FCFG_7 inv_set_accel_calibration
  ,{0x00, 0x6C, 0x02, 0x20, 0x00} //D_0_108 inv_set_accel_calibration
  ,{0x02, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00} //CPASS_MTX_00 inv_set_compass_calibration
  ,{0x02, 0x44, 0x04, 0x00, 0x00, 0x00, 0x00} //CPASS_MTX_01
  ,{0x02, 0x48, 0x04, 0x00, 0x00, 0x00, 0x00} //CPASS_MTX_02
  ,{0x02, 0x4C, 0x04, 0x00, 0x00, 0x00, 0x00} //CPASS_MTX_10
  ,{0x02, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00} //CPASS_MTX_11
  ,{0x02, 0x54, 0x04, 0x00, 0x00, 0x00, 0x00} //CPASS_MTX_12
  ,{0x02, 0x58, 0x04, 0x00, 0x00, 0x00, 0x00} //CPASS_MTX_20
  ,{0x02, 0x5C, 0x04, 0x00, 0x00, 0x00, 0x00} //CPASS_MTX_21
  ,{0x02, 0xBC, 0x04, 0x00, 0x00, 0x00, 0x00} //CPASS_MTX_22
  ,{0x01, 0xEC, 0x04, 0x00, 0x00, 0x40, 0x00} //D_1_236 inv_apply_endian_accel
  ,{0x03, 0x7F, 0x06, 0x0C, 0xC9, 0x2C, 0x97, 0x97, 0x97} //FCFG_2 inv_set_mpu_sensors
  ,{0x04, 0x02, 0x03, 0x0D, 0x35, 0x5D} //CFG_MOTION_BIAS inv_turn_on_bias_from_no_motion
  ,{0x04, 0x09, 0x04, 0x87, 0x2D, 0x35, 0x3D} //FCFG_5 inv_set_bias_update
  ,{0x00, 0xA3, 0x01, 0x00} //D_0_163 inv_set_dead_zone
  ,//SET INT_ENABLE at i=22
   {0x07, 0x86, 0x01, 0xFE} //CFG_6 inv_set_fifo_interupt
  ,{0x07, 0x41, 0x05, 0xF1, 0x20, 0x28, 0x30, 0x38} //CFG_8 inv_send_quaternion
  ,{0x07, 0x7E, 0x01, 0x30} //CFG_16 inv_set_footer
  ,{0x07, 0x46, 0x01, 0x9A} //CFG_GYRO_SOURCE inv_send_gyro
  ,{0x07, 0x47, 0x04, 0xF1, 0x28, 0x30, 0x38} //CFG_9 inv_send_gyro -> inv_construct3_fifo
  ,{0x07, 0x6C, 0x04, 0xF1, 0x28, 0x30, 0x38} //CFG_12 inv_send_accel -> inv_construct3_fifo
  ,{0x02, 0x16, 0x02, 0x00, 0x0A} //D_0_22 inv_set_fifo_rate
};

SoftwareSerial hc06(2,3); // RXPIN TXPIN
Adafruit_MLX90614 mlx = Adafruit_MLX90614();

MAX30105 particleSensor;
const byte RATE_SIZE = 4; //Increase this for more averaging. 4 is good.
byte rates[RATE_SIZE]; //Array of heart rates
byte rateSpot = 0;
long lastBeat = 0; //Time at which the last beat occurred
float beatsPerMinute;
int beatAvg;

RTCDS1307 rtc(0x68);
uint8_t year, month, weekday, day, hour, minute, second;
bool period = 0;
//String m[12] = {"January", "February", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"};
//String w[7] = {"Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado"};

/*
 * PIN Description : 
 *  D0 Serial USB RX
 *  D1 Serial USB TX 
 *  D2 Serial Bluetooth RX
 *  D3 Serial Bluetooth TX
 *  D4 Button 1
 *  D5 Button 2
 *  D6 Button 3
 *  D7 Button 4
 *  D8 --------------->UNUSED
 *  D9 DIMMER BLUE LED
 *  D10 LED RGB RED
 *  D11 LED RGB Green
 *  D12 LED RGB BLUE
 *  D13 LED DEBUG
 *  A0 --------------->UNUSED
 *  A1 --------------->UNUSED
 *  A2 --------------->UNUSED
 *  A3 --------------->UNUSED
 *  A4 SDA I2C >> 6-DOF / RTC / Temperature / Pulse
 *  A5 SCL I2C >> 6-DOF / RTC / Temperature / Pulse
 */

int Button_1_Pin = 4;
int Button_2_Pin = 5;
int Button_3_Pin = 6;
int Button_4_Pin = 7;
int ledDim_Pin = 9;       // LED dimmer connected to digital pin 9

int ledRGB_Red_Pin = 10;
int ledRGB_Green_Pin = 11;
int ledRGB_Blue_Pin = 12;
int ledDebug_Pin = 13;    // LED Debug connected to digital 13 

byte Button_1_press = 0;
byte Button_2_press = 0;
byte Button_3_press = 0;
byte Button_4_press = 0;
int Button_1_press_cpt = 0;
int Button_2_press_cpt = 0;
int Button_3_press_cpt = 0;
int Button_4_press_cpt = 0;

int device_MODE = 0;

bool flag_init_MPU6050=0;

unsigned int cpt=0; // General system counter

// LED Dimmer management
unsigned int fadeValue=0;
bool fadeDirection=0;

int EEPROM_current_addr = 0;

void setup() {

  Serial.begin(9600);
  Wire.begin();
  delay(1);  
  
  pin_init(); // Initialize input/output PIN
  mlx.begin();
  
  //MAX30105_init();
  
  hc06_init();
  DS1307_init();
  Serial.println("START LOOP");
}

void loop() {

  if (Buttons_FREQUENCY_READ_PER_CYCLE == 0){Button_read();}  

  // Heart rate sensor module
  //if (MAX30105_FREQUENCY_READ_PER_CYCLE == 0){MAX30105_read();}
  // Temperature module
  if (MLX90614_FREQUENCY_READ_PER_CYCLE == 0 && device_MODE==3){MLX90614_read();}
  // 6-DOF sensor module
  if (MPU6050_FREQUENCY_READ_PER_CYCLE == 0 && device_MODE==4){
    if(!flag_init_MPU6050){
      MPU6050_init();
      delay(10);
      flag_init_MPU6050=1;
    }
    MPU6050_read();}
  // Real time clock module
  if (DS1307_FREQUENCY_READ_PER_CYCLE == 0 && device_MODE==1){DS1307_read();}
  // Bluetooth Module
  if (HC06_FREQUENCY_READ_PER_CYCLE == 0 && device_MODE==1){if (hc06.available()){Serial.write(hc06.read());}}

  if (Serial_FREQUENCY_READ_PER_CYCLE == 0 && device_MODE==1){if (Serial.available()){Serial.write(Serial.read());}}

  if (DimLED_FREQUENCY_READ_PER_CYCLE == 0 && device_MODE==2){DimLED_write();}
    
  if (DebugLED_FREQUENCY_READ_PER_CYCLE == 0 && device_MODE==0){DebugLED_write();}

  if (DebugLED_FREQUENCY_READ_PER_CYCLE == 0){
    if(device_MODE != 4 && flag_init_MPU6050 == 1){
      flag_init_MPU6050=0;
    }
    if(device_MODE != 4 && flag_init_MPU6050 == 1){
      DebugINFO_write();
    }
  }
  
  if(cpt == MAX_COUNTER){cpt=0;}
  else{cpt++;}
  
  //delay(1);
}

// --------------------General functions--------------------
void pin_init() {
  pinMode(ledDim_Pin, OUTPUT);
  pinMode(ledDebug_Pin, OUTPUT);
  pinMode(ledRGB_Red_Pin, OUTPUT);
  pinMode(ledRGB_Green_Pin, OUTPUT);
  pinMode(ledRGB_Blue_Pin, OUTPUT);
  pinMode(Button_1_Pin, INPUT);
  pinMode(Button_2_Pin, INPUT);
  pinMode(Button_3_Pin, INPUT);
  pinMode(Button_4_Pin, INPUT);
}

void DebugINFO_write() {
  Serial.print("SYSTEM INFO : ");
  Serial.print("MODE=");Serial.print(device_MODE);Serial.print(" --- ");
  Serial.print("CPT_1=");Serial.print(Button_1_press);Serial.print(" --- ");
  Serial.print("CPT_2=");Serial.print(Button_2_press);Serial.print(" --- ");
  Serial.print("CPT_3=");Serial.print(Button_3_press);Serial.print(" --- ");
  Serial.print("CPT_4=");Serial.print(Button_4_press);Serial.print(" --- ");
  Serial.println();  
  EEPROM.write(EEPROM_current_addr, Button_1_press);
  //EEPROM.length()
}

void DebugLED_write() {
  digitalWrite(ledDebug_Pin, !digitalRead(ledDebug_Pin));
}

// --------------------Buttons and mode management--------------------
void Button_read(){
  // --------------Button 1--------------
  int Button_Statut = 0;

  if (Button_1_press_cpt >= Min_Time_Short_Push_Button && Button_1_press_cpt < Min_Time_Long_Push_Button && (digitalRead(Button_1_Pin))==1){Button_Statut=1;}
  else if (Button_1_press_cpt >= Min_Time_Long_Push_Button && (digitalRead(Button_1_Pin))==1){Button_Statut=2;}
  
  if(Button_Statut == 1){
    Serial.println("Short Press Button 1");
    Button_1_press++;
    device_MODE=0;
    Button_1_press_cpt=0;
  }
  else if(Button_Statut == 2){
    Serial.println("Long Press Button 1");
    device_MODE=1;
    Button_1_press_cpt=0;

  }
  //if((digitalRead(Button_1_Pin))==0){Button_1_press_cpt++;Serial.println(Button_1_press_cpt);}
  //else{Button_1_press_cpt=0;}
  if((digitalRead(Button_1_Pin))==0){Button_1_press_cpt++;}
  else{Button_1_press_cpt=0;}

  // --------------Button 2--------------
  Button_Statut=0;
  if (Button_2_press_cpt >= Min_Time_Short_Push_Button && Button_2_press_cpt < Min_Time_Long_Push_Button && (digitalRead(Button_2_Pin))==1){Button_Statut=1;}
  else if (Button_2_press_cpt >= Min_Time_Long_Push_Button && (digitalRead(Button_2_Pin))==1){Button_Statut=2;}
  
  if(Button_Statut == 1){
    Serial.println("Short Press Button 2");
    Button_2_press++;
    device_MODE=0;
    Button_2_press_cpt=0;
  }
  else if(Button_Statut == 2){
    Serial.println("Long Press Button 2");
    device_MODE=2;
    Button_2_press_cpt=0;
  }
  if((digitalRead(Button_2_Pin))==0){Button_2_press_cpt++;}
  else{Button_2_press_cpt=0;}

  // --------------Button 3--------------
  Button_Statut=0;
  if (Button_3_press_cpt >= Min_Time_Short_Push_Button && Button_3_press_cpt < Min_Time_Long_Push_Button && (digitalRead(Button_3_Pin))==1){Button_Statut=1;}
  else if (Button_3_press_cpt >= Min_Time_Long_Push_Button && (digitalRead(Button_3_Pin))==1){Button_Statut=2;}
  
  if(Button_Statut == 1){
    Serial.println("Short Press Button 3");
    Button_3_press++;
    device_MODE=0;
    Button_3_press_cpt=0;
  }
  else if(Button_Statut == 2){
    Serial.println("Long Press Button 3");
    device_MODE=3;
    Button_3_press_cpt=0;
  }
  if((digitalRead(Button_3_Pin))==0){Button_3_press_cpt++;}
  else{Button_3_press_cpt=0;}

  // --------------Button 4--------------
  Button_Statut=0;
  if (Button_4_press_cpt >= Min_Time_Short_Push_Button && Button_4_press_cpt < Min_Time_Long_Push_Button && (digitalRead(Button_4_Pin))==1){Button_Statut=1;}
  else if (Button_4_press_cpt >= Min_Time_Long_Push_Button && (digitalRead(Button_4_Pin))==1){Button_Statut=2;}
  
  if(Button_Statut == 1){
    Serial.println("Short Press Button 4");
    Button_4_press++;
    device_MODE=0;
    Button_4_press_cpt=0;
  }
  else if(Button_Statut == 2){
    Serial.println("Long Press Button 4");
    device_MODE=4;
    Button_4_press_cpt=0;
  }
  if((digitalRead(Button_4_Pin))==0){Button_4_press_cpt++;}
  else{Button_4_press_cpt=0;}
}

// --------------------Dimmer LED--------------------
void DimLED_write() {
    //Serial.print(fadeDirection);
    //Serial.print("  ");
    //Serial.println(fadeValue);
    analogWrite(ledDim_Pin, fadeValue);
    if(fadeDirection==0){
      fadeValue=fadeValue+8;
    }
    else if(fadeDirection==1){
      fadeValue=fadeValue-8;
    }
    if (fadeValue > 255 && fadeValue <= 0x7FFF){
      fadeDirection=1;
      fadeValue=255;
    }
    else if (fadeValue > 0x7FFF){
      fadeDirection=0;
      fadeValue=0;
    }
}

// --------------------DS1307 RTC Clock functions--------------------
void DS1307_init(){
  rtc.begin();
  rtc.setDate(19, 2, 28);
  rtc.setTime(23, 59, 50);  
}

void DS1307_read(){
  /*rtc.getDate(year, month, day, weekday);
  rtc.getTime(hour, minute, second, period);
  if (!(second % 3)) rtc.setMode(1 - rtc.getMode());
  rtc.getTime(hour, minute, second, period);

  Serial.print(w[weekday - 1]);
  Serial.print("  ");
  Serial.print(day, DEC);
  Serial.print("/");
  Serial.print(m[month - 1]);
  Serial.print("/");
  Serial.print(year + 2000, DEC);
  Serial.print("  ");
  Serial.print(hour, DEC);
  Serial.print(":");
  Serial.print(minute, DEC);
  Serial.print(":");
  Serial.print(second, DEC);
  Serial.print(rtc.getMode() ? (period ? " PM" : " AM") : "");
  Serial.println();*/
  //delay(1000); 
}

// --------------------MLX90614 Temperature Sensor--------------------
void MLX90614_read(){
  //Serial.print("Ambient = "); 
/*  Serial.print(mlx.readAmbientTempC()); 
  Serial.print("*C\tObject = "); 
  Serial.print(mlx.readObjectTempC()); Serial.println("*C");
  Serial.print("Ambient = "); 
  Serial.print(mlx.readAmbientTempF()); 
  Serial.print("*F\tObject = "); 
  Serial.print(mlx.readObjectTempF()); Serial.println("*F");
  Serial.println();*/
  //delay(500);
}

// --------------------MAX30105 Pulse Sensor--------------------
void MAX30105_init() {
  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
  {
    Serial.println("MAX30105 was not found. Please check wiring/power. ");
    while (1);
  }
  Serial.println("Place your index finger on the sensor with steady pressure.");

  particleSensor.setup(); //Configure sensor with default settings
  particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
  particleSensor.setPulseAmplitudeGreen(0); //Turn off Green LED  
}

void MAX30105_read(){
  digitalWrite(ledRGB_Red_Pin, HIGH);
  long irValue = particleSensor.getIR();

  if (checkForBeat(irValue) == true)
  {
    //We sensed a beat!
    long delta = millis() - lastBeat;
    lastBeat = millis();

    beatsPerMinute = 60 / (delta / 1000.0);

    if (beatsPerMinute < 255 && beatsPerMinute > 20)
    {
      rates[rateSpot++] = (byte)beatsPerMinute; //Store this reading in the array
      rateSpot %= RATE_SIZE; //Wrap variable

      //Take average of readings
      beatAvg = 0;
      for (byte x = 0 ; x < RATE_SIZE ; x++)
        beatAvg += rates[x];
      beatAvg /= RATE_SIZE;
    }
    digitalWrite(ledRGB_Red_Pin, LOW);
  }

  Serial.print("IR=");
  Serial.print(irValue);
  Serial.print(", BPM=");
  Serial.print(beatsPerMinute);
  Serial.print(", Avg BPM=");
  Serial.print(beatAvg);

  if (irValue < 50000)
    Serial.print(" No finger?");

  Serial.println();    
}

// --------------------HC-06 Bluetooth functions--------------------
void hc06_init() {
  hc06.begin(9600);
  //hc06.write('A');
  //hc06.write('T');
  //hc06.write('\n');
}

// --------------------MPU6050 6DOF functions--------------------
void MPU6050_init() {
  check_MPU();
  regWrite(0x6B, 0xC0);
  regWrite(0x6C, 0x00);
  delay(10);

  // regWrite(0x6B, 0x70);
  regWrite(0x6B, 0x00);
  regWrite(0x6D, 0x70);
  regWrite(0x6E, 0x06);
  temp = regRead(0x6F);
  //Serial.print("Bank 1, Reg 6 = ");
  //Serial.println(temp, HEX);

  // temp = regRead(0x6B);
  // Serial.println(temp, HEX);

  regWrite(0x6D, 0x00);

  temp = regRead(0x00);
  //Serial.println(temp, HEX);
  temp = regRead(0x01);
  //Serial.println(temp, HEX);
  temp = regRead(0x02);
  //Serial.println(temp, HEX);
  temp = regRead(0x6A);
  //Serial.println(temp, HEX);

  regWrite(0x37, 0x32);

  temp = regRead(0x6B);
  //Serial.println(temp, HEX);
  delay(5);
  // regWrite(0x25, 0x68); //Set Slave 0 to self
  //
  // regWrite(0x6A, 0x02);

  mem_init();
  delay(20);  
}

void MPU6050_read() {
  if (millis() >= lastRead + 10) {
    lastRead = millis();
    if (fifoReady()) {
      getPacket();
      temp = regRead(0x3A);
      if (firstPacket) {
        delay(1);
        bank_sel(0x00);
        regWrite(0x6E, 0x60);
        Wire.beginTransmission(MPU_ADDR);
        Wire.write(0x6F);
        Wire.write(0x04); Wire.write(0x00); Wire.write(0x00); Wire.write(0x00);
        // Wire.write(0x00); Wire.write(0x80); Wire.write(0x00); Wire.write(0x00);
        Wire.endTransmission();
        bank_sel(1);
        regWrite(0x6E, 0x62);
        Wire.beginTransmission(MPU_ADDR);
        Wire.write(0x6F);
        Wire.endTransmission();
        Wire.beginTransmission(MPU_ADDR);
        Wire.requestFrom(MPU_ADDR, 2);
        temp = Wire.read();
        temp = Wire.read();
        firstPacket = false;

        fifoReady();
      }
      // resetFifo();

      if (fifoCountL == 42) {
        processQuat();
        sendQuat();
      }
    }
  }  
}

void dmp_init() {

  for (int i = 0; i < 7; i++) {
    bank_sel(i);
    for (byte j = 0; j < 16; j++) {

      byte start_addy = j * 0x10;
      Wire.beginTransmission(MPU_ADDR);
      Wire.write(MEM_START_ADDR);
      Wire.write(start_addy);
      Wire.endTransmission();

      Wire.beginTransmission(MPU_ADDR);
      Wire.write(MEM_R_W);
      for (int k = 0; k < 16; k++) {
        unsigned char byteToSend = pgm_read_byte(&(dmpMem[i][j][k]));
        Wire.write((byte) byteToSend);
      }
      Wire.endTransmission();
    }
  }

  bank_sel(7);

  for (byte j = 0; j < 8; j++) {

    byte start_addy = j * 0x10;

    Wire.beginTransmission(MPU_ADDR);
    Wire.write(MEM_START_ADDR);
    Wire.write(start_addy);
    Wire.endTransmission();

    Wire.beginTransmission(MPU_ADDR);
    Wire.write(MEM_R_W);
    for (int k = 0; k < 16; k++) {
      unsigned char byteToSend = pgm_read_byte(&(dmpMem[7][j][k]));
      Wire.write((byte) byteToSend);
    }
    Wire.endTransmission();
  }

  Wire.beginTransmission(MPU_ADDR);
  Wire.write(MEM_START_ADDR);
  Wire.write(0x80);
  Wire.endTransmission();

  Wire.beginTransmission(MPU_ADDR);
  Wire.write(MEM_R_W);
  for (int k = 0; k < 9; k++) {
    unsigned char byteToSend = pgm_read_byte(&(dmpMem[7][8][k]));
    Wire.write((byte) byteToSend);
  }
  Wire.endTransmission();

  Wire.beginTransmission(MPU_ADDR);
  Wire.write(MEM_R_W);
  Wire.endTransmission();
  Wire.beginTransmission(MPU_ADDR);
  Wire.requestFrom(MPU_ADDR, 9);
  // Wire.endTransmission();
  byte incoming[9];
  for (int i = 0; i < 9; i++) {
    incoming[i] = Wire.read();
  }
}

void mem_init() {

  dmp_init();

  for (byte i = 0; i < 22; i++) {
    bank_sel(dmp_updates[i][0]);
    Wire.beginTransmission(MPU_ADDR);
    Wire.write(MEM_START_ADDR);
    Wire.write(dmp_updates[i][1]);
    Wire.endTransmission();

    Wire.beginTransmission(MPU_ADDR);
    Wire.write(MEM_R_W);
    for (byte j = 0; j < dmp_updates[i][2]; j++) {
      Wire.write(dmp_updates[i][j + 3]);
    }
    Wire.endTransmission();
  }

  regWrite(0x38, 0x32);

  for (byte i = 22; i < 29; i++) {
    bank_sel(dmp_updates[i][0]);
    Wire.beginTransmission(MPU_ADDR);
    Wire.write(MEM_START_ADDR);
    Wire.write(dmp_updates[i][1]);
    Wire.endTransmission();

    Wire.beginTransmission(MPU_ADDR);
    Wire.write(MEM_R_W);
    for (byte j = 0; j < dmp_updates[i][2]; j++) {
      Wire.write(dmp_updates[i][j + 3]);
    }
    Wire.endTransmission();
  }

  temp = regRead(0x6B);
  //Serial.println(temp, HEX);
  temp = regRead(0x6C);
  //Serial.println(temp, HEX);

  regWrite(0x38, 0x02);
  regWrite(0x6B, 0x03);
  regWrite(0x19, 0x04);
  regWrite(0x1B, 0x18);
  regWrite(0x1A, 0x0B);
  regWrite(0x70, 0x03);
  regWrite(0x71, 0x00);
  regWrite(0x00, 0x00);
  regWrite(0x01, 0x00);
  regWrite(0x02, 0x00);

  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x13);
  for (byte i = 0; i < 6; i++) {
    Wire.write(0x00);
  }
  Wire.endTransmission();

  // regWrite(0x24, 0x00);

  bank_sel(0x01);
  regWrite(0x6E, 0xB2);
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x6F);
  Wire.write(0xFF); Wire.write(0xFF);
  Wire.endTransmission();

  bank_sel(0x01);
  regWrite(0x6E, 0x90);

  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x6F);
  Wire.write(0x09); Wire.write(0x23); Wire.write(0xA1); Wire.write(0x35);
  Wire.endTransmission();

  temp = regRead(0x6A);

  regWrite(0x6A, 0x04);

  //Insert FIFO count read?
  fifoReady();

  regWrite(0x6A, 0x00);
  regWrite(0x6B, 0x03);

  delay(2);

  temp = regRead(0x6C);
  // Serial.println(temp, HEX);
  regWrite(0x6C, 0x00);
  temp = regRead(0x1C);
  // Serial.println(temp, HEX);
  regWrite(0x1C, 0x00);
  delay(2);
  temp = regRead(0x6B);
  // Serial.println(temp, HEX);
  regWrite(0x1F, 0x02);
  regWrite(0x21, 0x9C);
  regWrite(0x20, 0x50);
  regWrite(0x22, 0x00);
  regWrite(0x6A, 0x04);
  regWrite(0x6A, 0x00);
  regWrite(0x6A, 0xC8);

  bank_sel(0x01);
  regWrite(0x6E, 0x6A);
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x6F);
  Wire.write(0x06); Wire.write(0x00);
  Wire.endTransmission();

  bank_sel(0x01);
  regWrite(0x6E, 0x60);
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x6F);
  for (byte i = 0; i < 8; i++) {
    Wire.write(0x00);
  }
  Wire.endTransmission();
  bank_sel(0x00);
  regWrite(0x6E, 0x60);
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x6F);
  Wire.write(0x40); Wire.write(0x00); Wire.write(0x00); Wire.write(0x00);
  Wire.endTransmission();

  //resetFifo();
}

void regWrite(byte addy, byte regUpdate) {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(addy);
  Wire.write(regUpdate);
  Wire.endTransmission();
}

byte regRead(byte addy) {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(addy);
  Wire.endTransmission();
  Wire.beginTransmission(MPU_ADDR);
  Wire.requestFrom(MPU_ADDR, 1);
  // Wire.endTransmission();
  while (!Wire.available()) {
  }
  byte incoming = Wire.read();
  return incoming;
}

void getPacket() {
  if (fifoCountL > 32) {
    fifoCountL2 = fifoCountL - 32;
    longPacket = true;
  }
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x74);
  Wire.endTransmission();
  // Wire.requestFrom(MPU_ADDR, 42);
  // for(byte i = 0; i < fifoCountL; i++){
  if (longPacket) {
    Wire.beginTransmission(MPU_ADDR);
    Wire.requestFrom(MPU_ADDR, 32);
    for (byte i = 0; i < 32; i++) {
      received_packet[i] = Wire.read();
    }
    Wire.beginTransmission(MPU_ADDR);
    Wire.write(0x74);
    Wire.endTransmission();
    Wire.beginTransmission(MPU_ADDR);
    Wire.requestFrom(MPU_ADDR, (unsigned int)fifoCountL2);
    for (byte i = 32; i < fifoCountL; i++) {
      received_packet[i] = Wire.read();
    }
    longPacket = false;
  }
  else {
    Wire.beginTransmission(MPU_ADDR);
    Wire.requestFrom(MPU_ADDR, (unsigned int)fifoCountL);
    for (byte i = 0; i < fifoCountL; i++) {
      received_packet[i] = Wire.read();
    }
  }
}

byte read_interrupt() {
  byte int_status = regRead(0x3A);
  return int_status;
}

boolean fifoReady() {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x72);
  Wire.endTransmission();
  Wire.beginTransmission(MPU_ADDR);
  Wire.requestFrom(MPU_ADDR, 2);
  // Wire.endTransmission();
  byte fifoCountH = Wire.read();
  fifoCountL = Wire.read();
   //Serial.println(fifoCountL, DEC);
  if (fifoCountL == 42 || fifoCountL == 44) {
    return 1;
  }
  else if(fifoCountL != 0){
    resetFifo();
 }
  else return 0;
}

void resetFifo() {
  byte ctrl = regRead(0x6A);
  ctrl |= 0b00000100;
  regWrite(0x6A, ctrl);
}

void check_MPU() {

  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x75);
  Wire.endTransmission();
  Wire.beginTransmission(MPU_ADDR);
  Wire.requestFrom(MPU_ADDR, 1);
  byte aByte = Wire.read();

  if (aByte == 0x68) {
    Serial.println("Found MPU6050");
  }
  else {
    Serial.println("Didn't find MPU6050");
  }
}

void processQuat() {
  processed_packet[0] = received_packet[0];
  processed_packet[1] = received_packet[1];
  processed_packet[2] = received_packet[4];
  processed_packet[3] = received_packet[5];
  processed_packet[4] = received_packet[8];
  processed_packet[5] = received_packet[9];
  processed_packet[6] = received_packet[12];
  processed_packet[7] = received_packet[13];

}

void sendQuat() {
  q[0] = (long) ((((unsigned long) processed_packet[0]) << 8) + ((unsigned long) processed_packet[1]));
...

This file has been truncated, please download it to see its full contents.
Arduino Main Code and examples
The Arduino Main file has the code with everything. Other code are juste here to test every peripherals

Custom parts and enclosures

Sketchup Full enclosure
Full enclosure with TOP, BOTTOM and Components.
Open it with Sketchup software (2017 recommended, but other should be fine).
health_device_v9_dmyFGVB8WQ.skp

Schematics

Fritzing Schematic
Unnamed 15xw6zb0su
Fritzing document
project_hygie_v3_wRtypyUKSN.fzz

Comments

Similar projects you might like

Joy Robot (Robô Da Alegria)

Project tutorial by Igor Fonseca Albuquerque

  • 6,034 views
  • 6 comments
  • 36 respects

Thirst Alert Plant Alarm

Project tutorial by Patchr

  • 6,881 views
  • 3 comments
  • 42 respects

eMotion - Towards a Better Future

Project tutorial by Team FactoryEight

  • 4,803 views
  • 2 comments
  • 14 respects

Pushup Counter

Project tutorial by Team MixPose

  • 4,682 views
  • 0 comments
  • 24 respects

HealthSphere

Project tutorial by EdOliver and Victor Altamirano

  • 2,677 views
  • 1 comment
  • 15 respects
Add projectSign up / Login