My Cart

Realtime Mountain Climber Monitoring using eHealth Sensor Platform for Arduino and Raspberry Pi (Biometric Sensing)

Difficulty Level: Expert -


This is a project made for all mountain lovers. As you know, mountain sports are more than a walk. You need some experience and preparation to enjoy them safely. In this sense, it is strongly recommended to be located and monitored all the time.

The aim of this project carried out by Cooking Hacks team is to develop a device capable to measure different biometric parameters, using some sensors compatible with our e-Health sensor board and send these data in real time to a receiver by means of a LoRa and 3G/GPRS wireless connection.

The hardware base is the Arduino MEGA 2560 microcontroller board and the e-Health Sensor Shield V2.0. The rest of hardware components are: SX1272 LoRa and Multiprotocol, 3G + GPS module, Battery Li-Ion, Solar Charger Shield v2, Flexible Solar Panel, Flexible Solar Panel, Air Flow sensor, Galvanic Skin Response Sensor (GSR), Accelerometer, Pulse and Oxygen in Blood Sensor (SPO2), Body Temperature Sensor and a TFT LCD 2.2” screen.


Realtime Vital Signs Monitoring

The device is sending constantly the vital signs readings to a receiver. In normal conditions, the Autonomous Biometric Sensor Device uses LoRa wireless communication when the range is less than 20 kilometers. Beyond this distance, LoRa module is out of range and starts emitting using 3G/GPRS wireless communication. This mode can be used to research about vital signs evolution during the exercise.


Emergency Mode

The Autonomous Biometric Sensor Device sensors has defined a minimum and a maximum ranges for the vital signs. In case of the sensors collect data below or over this ranges, it could mean that the mountain climber is in trouble, so emergency mode is activated. For that, the device enables the GPS signal which is sent to the base station in order to locate the injured person.


Article Index

1. Features

The system shloud be designed to be easily transported. The sensors that were chosen, can be placed easily by anyone and they can measure their values simultaneously.

With these premises, we chose to monitor the following biometric parameters:

  • Skin temperature.
  • Breathing frequency.
  • Pulse oximetry.
  • Skin conductance.
  • Patient position.

Given the possible applications we decided that the final design must meet the following specifications:

  • Portable (battery powered).
  • Light.
  • Display,
  • Communication to a remote center using two different wireless protocols.
  • Easy to replicate hardware by other users.
  • Software high-level functions.
  • Low cost.

Block diagram

The next block diagram illustrates the communication between the different modules of the project.

2. Hardware

Backpack

To transport the project, we bought a backpack that we customize. We made some holes that allow us to put the antennas and the sensors outside. Also, we made a window to see the display.


To modify the backpack, we used a pair of scissors and a sewing kit (thread, needle and thimble). We cut the fabric of the backpack, and we round off the edges with a seam.

We made a hole for the screen:


For the sensors:


And for the antennas:


A complete modification that allow us to use this commercial backpack with our DIY project.

Arduino Mega 2560

The Arduino MEGA based on the ATmega2560 is the extended version of the Arduino UNO. It offers more capacity to perform all functions, it allow us to develope more complex codes.

Arduino MEGA
Microcontroller ATmega2560
Operating Voltage 5V
Input Voltage (recommended) 7-12V
Input Voltage (limits) 6-20V
Digital I/O Pins 54 (of which 15 provide PWM output)
Analog Input Pins 16
DC Current per I/O Pin 40 mA
DC Current for 3.3V Pin 50 mA
Flash Memory 128 KB of which 4 KB used by bootloader
SRAM 8 KB
EEPROM 4 KB
Clock Speed 16 MHz

TFT LCD 22"

To display the sensors information, we have chosen a color TFT LCD screen of 2.2" and a resolution of 240x320 px.

The operating voltage levels of the screen are 3.3V and the leves of the inputs and outputs in the Arduino MEGA are 5V and the operating voltage levels of the screen are 3.3V. This difference of voltage has been adapted using the CD4050BC chip.

Buy now


SX1272 LoRa

As main communication module has been used the SX1272 LoRa. Due to its wide range of scope, it will be ideal to send the data collected by the sensors to a central point where we can collect the information.

LoRa is a new, private and spread-spectrum modulation technique which allows sending data at extremely low data-rates to extremely long ranges. The low data-rate (down to few bytes per second) and LoRa modulation lead to very low receiver sensitivity (down to -134 dBm), which combined to an output power of +14 dBm means extremely large link budgets: up to 148 dB., what means more than 22km (13.6 miles) in LOS links and up to 2km (1.2miles) in NLOS links in urban environment (going through buildings).

LoRa
Module SX1272
Dual Frequency Band 863-870 MHz (Europe)
902-928 MHz (US)
Transmission Power 25 mW
Sensitivity -134 dBm
Channels 8 (868MHz)
13 (900MHz)
Range LOS = 21km (13.4miles)
NLOS = +2km (1.2miles)
Buy now


Multiprotocol Radio Shield

The Multiprotocol Radio Shield is an interconnection shield for Arduino, and was designed to connect two communication modules at the same time. This that means a lot of possibilities and applications can be made using the cooking-hacks modules. The Multiprotocol Radio Shield includes the SPI bus connections that allows the use of the RS-485, CAN Bus, LoRa modules and LoRaWAN, but also is compatible with the rest of the cooking-hacks modules as RFID, XBee or Bluetooth.

Buy now


3G/GPRS shield

The module used as a second source of wireless communication in case of failure the main module is the 3G + GPS shield.

The 3G shield enables the connectivity to high speed WCDMA cellular networks in order to make possible the creation of the next level of worldwide interactivity projects inside the new "Internet of Things" era.

Its connectivity 3G / GPRS allows the user to perform various tasks such as uploading or downloading content from a web server with HTTP browsing or also work with the FTP protocol to upload files to a server.

In this case, the module used by this board is the SIM5218 from SIMCom, it has GPS which will help us to make the geolocation of the user if it is required.

Buy now


Solar Charger Shield

To ensure the autonomy of the system we used the Solar Charger Shield v2.

This module allows you to connect a rechargeable battery which can also be gradually recharged with a solar panel. I allows us to create a completely autonomous system.

The module accepts batteries between 2.7 and 4.7 V raising the voltage to 5 volts. It is able to supply a maximum current of up to 700mA. It also has short-circuit protection and a USB connector to charge the battery.

Buy now


Rechargeable Battery

The battery selected to power the system is a lithium-ion battery.

Its light weight and reduced size make it perfect for the system, It is composed of two 220 mAh cell which will be sufficient to fee the project during hours.

Polymer Lithium Ion Battery
Charge voltage 4.2V
Nominal Voltage 3.7V
Nominal capacity 4400mAh @ 0.2C discharge
Minimum rated capacity 2100mAh @ 0.2C discharge
Max. Charge current 2.2A
Max. Discharge current 4.4A
Cell weight Approx.83g
Dimension 53mm x 51mm x 17.mm
Connector type JST2.0mm
Wire length 60±5mm
Buy now


Flexible Solar Panel

The project is intended to be used outside, that's why we have selected a flexible solar pannel.

Flexible Solar Panel
Size 180mm x 280mm
Voltage 5.5 V
Current 100 mAh
Voltage (oc) 6.4 V

This is a custom flexible solar panel, which has a high efficiency at 16%. This unit has a clear epoxy coating with hard-board backing. Robust sealing for out door applications.

Buy now


e-Health Sensor Shield V2.0

The e-Health Sensor Shield V2.0 allows Arduino and Raspberry Pi users to perform biometric and medical applications where body monitoring is needed by using 10 different sensors: pulse, oxygen in blood (SPO2), airflow (breathing), body temperature, electrocardiogram (ECG), glucometer, galvanic skin response (GSR - sweating), blood pressure (sphygmomanometer), patient position (accelerometer) and muscle/eletromyography sensor (EMG).

This information can be used to monitor in real time the state of a patient or to get sensitive data in order to be subsequently analysed for medical diagnosis. Biometric information gathered can be wirelessly sent using any of the connectivity options available.

IMPORTANT: The e-Health Sensor Platform has been designed by Cooking Hacks (the open hardware division of Libelium) in order to help researchers, developers and artists to measure biometric sensor data for experimentation, fun and test purposes. Cooking Hacks provides a cheap and open alternative compared with the proprietary and price prohibitive medical market solutions. However, as the platform does not have medical certifications it can not be used to monitor critical patients who need accurate medical monitoring or those whose conditions must be accurately measured for a ulterior professional diagnosis.
Buy now


Sensors

Airflow Sensor

The nasal / mouth airflow sensor is a device used to measure the breathing rate in a patient in need of respiratory help or person. This device consists of a flexible thread which fits behind the ears, and a set of two prongs which are placed in the nostrils. Breathing is measured by these prongs.

The specifically designed cannula/holder allows the thermocouple sensor to be placed in the optimal position to accurately sense the oral/nasal thermal airflow changes as well as the nasal temperature air. Comfortable adjustable and easy to install.

Buy now


Galvanic Skin Response Sensor (GSR - Sweating)

Skin conductance, also known as galvanic skin response (GSR) is a method of measuring the electrical conductance of the skin, which varies with its moisture level. This is of interest because the sweat glands are controlled by the sympathetic nervous system, so moments of strong emotion, change the electrical resistance of the skin. Skin conductance is used as an indication of psychological or physiological arousal, The Galvanic Skin Response Sensor (GSR - Sweating) measures the electrical conductance between 2 points, and is essentially a type of ohmmeter.

In skin conductance response method, conductivity of skin is measured at fingers of the palm. The principle or theory behind functioning of galvanic response sensor is to measure electrical skin resistance based on sweat produced by the body. When high level of sweating takes place, the electrical skin resistance drops down. A dryer skin records much higher resistance. The skin conductance response sensor measures the psycho galvanic reflex of the body. Emotions such as excitement, stress, shock, etc. can result in the fluctuation of skin conductivity. Skin conductance measurement is one component of polygraph devices and is used in scientific research of emotional or physiological arousal.

Buy now


Patient Position Sensor

The Patient Position Sensor (Accelerometer) monitors five different patient positions (standing/sitting, supine, prone, left and right.)

In many cases, it is necessary to monitor the body positions and movements made because of their relationships to particular diseases (i.e., sleep apnea and restless legs syndrome). Analyzing movements during sleep also helps in determining sleep quality and irregular sleeping patterns. The body position sensor could help also to detect fainting or falling of elderly people or persons with disabilities.

eHealth Body Position Sensor uses a triple axis accelerometer to obtain the patient's position.

Buy now


Pulse and Oxygen in Blood Sensor (SPO2)

Pulse oximetry a noninvasive method of indicating the arterial oxygen saturation of functional hemoglobin.

Oxygen saturation is defined as the measurement of the amount of oxygen dissolved in blood, based on the detection of Hemoglobin and Deoxyhemoglobin. Two different light wavelengths are used to measure the actual difference in the absorption spectra of HbO2 and Hb. The bloodstream is affected by the concentration of HbO2 and Hb, and their absorption coefficients are measured using two wavelengths 660 nm (red light spectra) and 940 nm (infrared light spectra). Deoxygenated and oxygenated hemoglobin absorb different wavelengths.

Deoxygenated hemoglobin (Hb) has a higher absorption at 660 nm and oxygenated hemoglobin (HbO2) has a higher absorption at 940 nm . Then a photo-detector perceives the non-absorbed light from the LEDs to calculate the arterial oxygen saturation.

A pulse oximeter sensor is useful in any setting where a patient's oxygenation is unstable, including intensive care, operating, recovery, emergency and hospital ward settings, pilots in unpressurized aircraft, for assessment of any patient's oxygenation, and determining the effectiveness of or need for supplemental oxygen.

Acceptable normal ranges for patients are from 95 to 99 percent, those with a hypoxic drive problem would expect values to be between 88 to 94 percent, values of 100 percent can indicate carbon monoxide poisoning.

Buy now


Body Temperature Sensor

Body temperature depends upon the place in the body at which the measurement is made, and the time of day and level of activity of the person. Different parts of the body have different temperatures.

The commonly accepted average core body temperature (taken internally) is 37.0°C (98.6°F). In healthy adults, body temperature fluctuates about 0.5°C (0.9°F) throughout the day, with lower temperatures in the morning and higher temperatures in the late afternoon and evening, as the body's needs and activities change.

It is of great medical importance to measure body temperature. The reason is that a number of diseases are accompanied by characteristic changes in body temperature. Likewise, the course of certain diseases can be monitored by measuring body temperature, and the efficiency of a treatment initiated can be evaluated by the physician.

Hypothermia <35.0 °C (95.0 °F)
Normal 36.5–37.5 °C (97.7–99.5 °F)
Fever or Hyperthermia >37.5–38.3 °C (99.5–100.9 °F
Hyperpyrexia >40.0–41.5 °C (104–106.7 °F)
Buy now


E-Health Portable Board

To join all the elements that have the final project, we have created a special shield that allow us to connect all the different modules. Also, if one of them is damaged, you can replace it easily.


To develope this board, we made different tests that allowed us to join all the modules together.

The following table summarizes the connections made between the modules.

Connections
Module
Module Pinout
Arduino Pinout
Power supply
e-Health Airflow → A1
GSR → A2
Body temp. → A3
SPO2 → D6-D13
Acelerómetro → A4,A5, D3
Airflow → A1
GSR → A2
Body temp. → A3
SPO2 → D6-D13
Acelerómetro → A4,A5, D3
5V, 3V3, GND
Multiprotocol Radio Shield MOSI, MISO, SCK, RX, TX, T1, T2, T3 D50-D52, RX1, TX1, D36, D38, D40 5V, GND
3G + GPS RX, TX, D2 RX0, TX0, D22 5V, GND
TFT LCD CS_TFT, RESET, DC, MOSI, SCK, LED, MISO, CS_SD D47-D52 5V, GND
Solar Charger Shield 5V, GND 5V, GND Battery

It's very important to know how we are going place the shields over the board. Also you have to pay attention where are the connectors that we are going to use of each shield (for example the solar panel connector) because you have to be able to reach them when we put the full system into a box. In addition pay atention in the distance between holes for the pin headers of each board.

Here we show you the example of the board where we try to minimize the final size. In the next lines you can read the step by step of this board.

First thing that you have to do to develope a board, is to do a schematic. A circuit diagram (electrical diagram, elementary diagram, electronic schematic) is a graphical representation of an electrical circuit. A schematic diagram shows the components and interconnections of the circuit using standardized symbolic representations. The presentation of the interconnections between circuit components in the schematic diagram does not necessarily correspond to the physical arrangements in the finished device.

In this case, most of the components are connector that allow us to put all the hardware together in the same board.


Download the e-Health Portable Board schematic.


Once we have developed the schematic, we have to develope the board or PCB. A printed circuit board (PCB) mechanically supports and electrically connects electronic components using conductive tracks, pads and other features etched from copper sheets laminated onto a non-conductive substrate. Components – capacitors, resistors or active devices – are generally soldered on the PCB.

Our design is a double sided (two copper layers) PCB.


Download the e-Health Portable Board Eagle files.


Then, when we have the printed circuit board designed we send it to a PCB manufacturer, a company a company that takes our designs to reality.

When we receive the boards, we have to solder the board components. In this case, basically, the components are THD pin strips, male and female, with a pitch of 0.1 invhes (2.54mm). These pins are standard in all Arduino modulos. Thy will allow us to connect a disconnect each module and fix them securely but with the possibility to extract them.

In the next photo you can see the top of the board. In this part we have placed the next components:

  • e-Health Sensor Shield V2.0
  • Solar Charger Shield
  • Multiprotocol Radio Shield
  • SX1272 LoRa module
  • TFT LCD 22"
  • CD4050BC chip


In the other side of the board, the bottom, we have got the rest of the components of the project. You can see them in the next photo.

  • Rechargeable Battery
  • 3G/GPRS shield
  • Arduino Mega 2560


Box

To carry out the encapsulation of the system, we have made it through 3D printing.

To make the 3D model we have used Tinkercad. It is online and it allows an easy and intuitive design of 3D models and then export them to a file in different standard formats for 3D printing.

Once the box was designed, we printed it.

Top of the box:



Bottom of the box:



Complete box:



Download the files to print the box.

3. Software

LCD Functions

The display control is performed using the Adafruit_GFX, Adafruit_ILI9341 and Arduinos SPI libraries.

Function Description
tft.begin() Initializes the display
tft.fillScreen(uint16_t color) Full color screen
tft.setRotation(uint8_t x) Sets the orientation
tft.setCursor(int16_t x, int16_t y) Sets the coordinates where you start to draw / write
tft.setTextColor(uint16_t c) Select text color
tft.setTextSize(uint8_t s) Select text size
tft.println() Write on the screen with the parameters defined

Also, two functions have been created to control easily the display:

  • printLogo()

    → Print the logo when the system is powered.

  • setScreen()

    → Set the screen to plot data of the sensors.

Functions of the sensors

To program the sensors, the e-Health sensor board libraries have been used. These libreries are designed specifically for the Arduino UNO so it has been necessary to make small modifications in the code to work correctly in the Arduino MEGA.

For each sensor we have created a function where we mix the functions of e-Health and the LCD diplay.

Function Description
getShowSPO2() Read and show in the display the pulse and level of oxygen in blood
getShowConductance() Read and show in the display conductance of the skin
getShowTemp() Read and show in the display the temperature
getShowPosition() Read and show in the display the position
getShowAirflow() Read and show in the display the number of breaths per minute

The operation of these functions is explained in the following flow chart:

In the case of the airflow sensor, it has been necessary to create a new function in the e-Health library to give us a numerical value of breaths and to be represented on screen. This function is called AirflowBPM() and counts the number of breaths in 10 seconds to caclculate the total of breaths in a minute.

Frame Functions

The information hass to be sent wirelessly that's why we have created a frame type that is compatible with the two wireless modules. Fort his, we have done a function called compoundFrame() in which we take all the values of the sensors and transform then in a character string. In addition, we list the frames to see if any of them is lost.

The format of the frame is like:

LoRa Functions

LoRa code is divided into two parts, module configuration and sending data. For this, we have created two functions startLora() and sendLora().

The most important functios to configure and control the LoRa module are:

Function Description
sx1272.ON() Switches the SX1272 LoRa module ON
sx1272.setMode(uint8_t mode) Sets the BW, CR and SF of the LoRa modulation
sx1272.setChannel(uint32_t ch) Sets the indicated frequency channel in the module
sx1272.setPower(char p) Sets the signal power indicated in the module
sx1272.setNodeAddress(uint8_t addr) Sets the node address in the module
sx1272.setRetries(uint8_t ret) Sets the maximum number of retries.
sx1272.OFF() Switches the SX1272 LoRa module OFF

The innovative LoRa mode is the most interesting included in this module. It is an advanced and private modulation that increases the range comparing to classic modulations. The LoRa long range mode provides ultra-long range spread spectrum communication and high interference immunity whilst minimizing current consumption. It combines digital spread spectrum, digital signal processing, and forward error correction coding to achieve unprecedented performance. LoRa also provides significant advantages in both blocking and selectivity over conventional modulation techniques.

LoRa has three configurable parameters: the bandwidth (BW), the coding rate (CR) and the spreading factor (SF). The combination of these values defines the transmission mode. It is possible to set a predefined mode or to set these three parameters manually.

There are ten predefined modes in the API, including the largest distance mode, the fastest mode, and eight other intermediate modes that Libelium has found interesting. All of them can be modified or deleted, and also it is possible to attach new modes in the appropriate function. The predefined modes and its properties are shown in the next table.

ModeBWCRSFSensitivity (dB)Comments
1 125 4/5 12 -134 max range, slow data rate
2 250 4/5 12 -131  
3 125 4/5 10 -129  
4 500 4/5 12 -128  
5 250 4/5 10 -126  
6 500 4/5 11 -125.5  
7 250 4/5 9 -123  
8 500 4/5 9 -120  
9 500 4/5 8 -117  
10 500 4/5 7 -114 min range, fast data rate, minimum battery impact

There are two frequency bands available to work with this module, 868 MHz and 900 MHz ISM bands. Depending on the country the user is located, one or the other will be chosen. Inside each frequency band there are several channels, so the user can choose among them.

Finally, we have to select the power level (dBm) at which the module transmits conducted power. Its possible values are:

ParameterSX1272 power level
'L' 0 dBm
'H' 7 dBm
'M' 14 dBm

Once the module is configured, we have to select the way we send the information:

Function Description
sx1272.sendPacketTimeout(uint8_t dest, char *payload) Sends a packet to the specified destination before a timeout expires
sx1272.sendPacketMAXTimeout(uint8_t dest, char *payload) Same as previous function with maximum timeout
sx1272.sendPacketTimeoutACK(uint8_t dest, char *payload) Sends a packet to a destination before a timeout and wait for an ACK response
sx1272.sendPacketMAXTimeoutACK(uint8_t dest, char *payload) Same as previous function with maximum timeout
sx1272.sendPacketTimeoutACKRetries(uint8_t dest, char *payload) Sends a packet to a destination before a timeout, wait for an ACK response and retry to send the packet if ACK is lost.
sx1272.sendPacketMAXTimeoutACKRetries(uint8_t dest, char *payload) Same as previous function with maximum timeout

Also, we have to select the way we receive the information:

Function Description
sx1272.receivePacketTimeout(uint8_t dest, char *payload) Receives information before a timeout expires
sx1272.receivePacketMAXTimeout(uint8_t dest, char *payload) Same as previous function with maximum timeout
sx1272.receivePacketTimeoutACK(uint8_t dest, char *payload) Receives information before a timeout expires and responds with ACK
sx1272.receivePacketMAXTimeoutACK(uint8_t dest, char *payload) Same as previous function with maximum timeout
sx1272.receivePacketTimeoutACKRetries(uint8_t dest, char *payload) Sends a packet to a destination before a timeout, wait for an ACK response and retry to send the packet if ACK is lost
sx1272.receivePacketMAXTimeoutACKRetries(uint8_t dest, char *payload) Same as previous function with maximum timeout

3G + GPS Functions

This module will be used in case the main communication module fails. Its 3G connectivity will be used to upload data from the sensors to a server using the FTP protocol.

In addition, the module is used to set the position where the carrier of the system is using the GPS.

The communication with this shield is done by Hayes commands. It is a specific command language. The command set consists of a series of short text strings which can be combined to produce commands for operations such as dialing, hanging up, and changing the parameters of the connection. The vast majority of dial-up modems use the Hayes command set in numerous variations.

All the instructions of the 3G shield are in the send3G() function. Te main commands used are in the next table:

AT Command Description
AT+CPIN Enter the pin code of the SIM card
AT+CREG Establishes a connection with the module to connect to the network
AT+CGSOCKCONT Sets the protocol and the access point name
AT+CFTPSERV Sets the domain name of the FTP server
AT+CFTPPORT Sets the port of the FTP server
AT+CFTPMODE Sets the FTP mode
AT+CFTPUN Sets the name for server access
AT+CFTPPW Sets the password to access the server
AT+CFTPPUT Upload a file to the server

The operation of these functions is explained in the following flow chart:

In the same way, we have created the getGPSposition() function that allow us to get the coordinates of our position.

AT Command Description
AT+CGPS Activates the GPS module
AT+CGPSINFO Collects the coordinates of the current position

Main sketch

Main Code for Arduino MEGA:

/*
 *  PORTABLE eHealth SYSTEM complete example.
 *
 *  Description: Example with all modules working  
 * 
 *  Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L.
 *  http://www.libelium.com
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/> .
 *
 *  Version 1.0
 *  Author: ANDRES FALO
 */

//Libraries eHealth
#include <eHealth.h> 
#include <PinChangeInt.h>

//Libraries TFT
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

//Libraria LoRa
#include "SX1272.h"

//Definition of used pins for TFT
#define TFT_DC 49
#define TFT_CS 53
#define TFT_MOSI 51
#define TFT_CLK 52
#define TFT_RST 48
#define TFT_MISO 50

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);

//eHealth
int BPM;
int SPO2;
float conductance;
//float resistance;
//float conductanceVol;
float temperature;
uint8_t position;
char* position2;
int countsPerMinute;

char POS1[]="Supine position";    
char POS2[]="Left position";
char POS3[]="Rigth position";
char POS4[]="Prone position";
char POS5[]="Stand position";
char POS6[]="non-defined";

//LoRa 
char conductanceSEND[10];
char temperatureSEND[10];

int e;

//3G + GPS
int8_t answer;
int onModulePin = 22, aux;
int data_size = 0;
int end_file = 0;

char gps_data[150];
int counter;

char aux_str[150];

char response[150];
int x = 0;
long previous;

int cont3G;
unsigned long start;

int errorGPS;
int datagpsOK;

int y = 1;

//BATTERY
const int analogInPin = A0;  // Analog input pin that the VBAT pin is attached to
int BatteryValue = 0;        // value read from the VBAT pin
float outputValue = 0;

//other variables
char dataFrame[150];

int stabilize;//how many times you read de sensors before reading

int cont = 0;

int error;

int alarm;

int numFrame = 0;

// the setup routine runs once when you press reset:
void setup() {

  tft.begin();

  printLogo();

  eHealth.initPulsioximeter();

  eHealth.initPositionSensor();

  //Attach the inttruptions for using the pulsioximeter.   
  pinMode(A15, INPUT); 
  digitalWrite(A15, HIGH);
  PCintPort::attachInterrupt(A15, &readPulsioximeter, RISING);

  pinMode(onModulePin, OUTPUT);

  Serial.begin(115200);

}

// the loop routine runs over and over again forever:
void loop() {

  setScreen();

  //loop to stabilize measures
  for (stabilize=3; stabilize>1; stabilize--)
  {

    showBatLevel();

    getShowSPO2();

    getShowConductance();

    getShowTemp();

    getShowPosition(); 

    getShowAirflow();

  }

  tft.fillScreen(ILI9341_BLACK);

  //setAlarm();

  compoundFrame();

  startLora();

  sendLora();

  if (error == 1)
  {
    send3G();
  }

  if ((alarm == 1) || (numFrame == 10*y))
  {
    errorGPS=0;

    getGPSposition();

    if (errorGPS==0 && datagpsOK==1)
    {
      strncpy(dataFrame,gps_data,150);
      
      y++;

      startLora();

      sendLora();

      if (error == 1)
      {
        send3G();
      }

    }
    else
    {
      delay(1000);
    }

  }

}

//************************************************************

void printLogo(){

  tft.fillScreen(ILI9341_BLACK);
  tft.setRotation(2);
  tft.setCursor(50, 20);
  tft.setTextColor(ILI9341_WHITE);  
  tft.setTextSize(3);
  tft.println("Portable");
  tft.setCursor(50, 50);
  tft.println("e-Health");
  tft.setCursor(65, 80);
  tft.println("System");
  tft.setCursor(30, 120);
  tft.setTextColor(ILI9341_YELLOW);  
  tft.setTextSize(2);
  tft.println("for Mountaineer");
  tft.setCursor(60, 140);
  tft.println("Assitance");

  //(x,y,width,length,colour)
  tft.fillRect(100, 175, 30, 100, ILI9341_WHITE);
  tft.setRotation(1);
  tft.fillRect(80, 65, 30, 100, ILI9341_WHITE);

  tft.setRotation(2);
  tft.setCursor(30, 300);
  tft.setTextColor(ILI9341_RED);  
  tft.setTextSize(2);
  tft.println("by Cooking Hacks");

  delay(2000);

  tft.setRotation(2);
  tft.setCursor(50, 20);
  tft.setTextColor(ILI9341_BLACK);  
  tft.setTextSize(3);
  tft.println("Portable");
  tft.setCursor(50, 50);
  tft.println("e-Health");
  tft.setCursor(65, 80);
  tft.println("System");
  tft.setCursor(30, 120);
  tft.setTextColor(ILI9341_BLACK);  
  tft.setTextSize(2);
  tft.println("for Mountaineer");
  tft.setCursor(60, 140);
  tft.println("Assitance");

  //(x,y,width,length,colour)
  tft.fillRect(100, 175, 30, 100, ILI9341_BLACK);
  tft.setRotation(1);
  tft.fillRect(80, 65, 30, 100, ILI9341_BLACK);

  tft.setRotation(2);
  tft.setCursor(30, 300);
  tft.setTextColor(ILI9341_BLACK);  
  tft.setTextSize(2);
  tft.println("by Cooking Hacks");
}

//************************************************************

void setScreen(){

  tft.setCursor(10, 10);
  tft.setTextColor(ILI9341_YELLOW);  
  tft.setTextSize(2);
  tft.println("Conductance:");
  tft.setCursor(10, 40);
  tft.setTextColor(ILI9341_YELLOW);  
  tft.setTextSize(2);
  tft.println("PRbpm:");
  tft.setCursor(10, 70);
  tft.setTextColor(ILI9341_YELLOW);  
  tft.setTextSize(2);
  tft.println("%SPO2:");
  tft.setCursor(10, 100);
  tft.setTextColor(ILI9341_YELLOW);  
  tft.setTextSize(2);
  tft.println("Temperature:");
  tft.setCursor(10, 130);
  tft.setTextColor(ILI9341_YELLOW);  
  tft.setTextSize(2);
  tft.println("Position:");
  tft.setCursor(10, 190);
  tft.setTextColor(ILI9341_YELLOW);  
  tft.setTextSize(2);
  tft.println("Airflow BPM:");
  tft.setCursor(10, 250);
  tft.setTextColor(ILI9341_YELLOW);  
  tft.setTextSize(2);
  tft.println("Battery Voltage:"); 
}

//************************************************************

void readPulsioximeter(){  

  cont ++;

  if (cont == 50) { //Get only of one 50 measures to reduce the latency
    eHealth.readPulsioximeter();  
    cont = 0;
  }
}

//************************************************************

void showBatLevel(){

  tft.setCursor(10, 280);
  tft.setTextColor(ILI9341_BLACK);  
  tft.setTextSize(2);
  tft.println(outputValue);

  BatteryValue = analogRead(analogInPin);            
  outputValue = ((float(BatteryValue)*5)/1023*2)-0.15;


  tft.setCursor(10, 280);
  tft.setTextColor(ILI9341_WHITE);  
  tft.setTextSize(2);
  tft.println(outputValue);  
}

//************************************************************

void getShowSPO2(){

  tft.setTextColor(ILI9341_BLACK);
  tft.setCursor(100,40);
  tft.println(BPM);

  tft.setTextColor(ILI9341_BLACK);
  tft.setCursor(100,70);
  tft.println(SPO2); 

  BPM=eHealth.getBPM();

  SPO2=eHealth.getOxygenSaturation();

  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(100,40);
  tft.println(BPM);

  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(100,70);
  tft.println(SPO2);
}

//************************************************************

void getShowConductance(){

  tft.setTextColor(ILI9341_BLACK);
  tft.setCursor(160, 10);
  tft.println(conductance);

  conductance = eHealth.getSkinConductance();

  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(160, 10);
  tft.println(conductance);
}

//************************************************************

void getShowTemp(){

  tft.setTextColor(ILI9341_BLACK);
  tft.setCursor(160,100);
  tft.println(temperature);

  temperature = eHealth.getTemperature();

  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(160,100);
  tft.println(temperature);
}

//************************************************************

void getShowPosition(){

  tft.setTextColor(ILI9341_BLACK);
  tft.setCursor(10,160);
  tft.println(position2);  

  position = eHealth.getBodyPosition(); 

  if (position == 1) {
    position2=POS1;    
  } 
  else if (position == 2) {
    position2=POS2;
  } 
  else if (position == 3) {
    position2=POS3;
  } 
  else if (position == 4) {
    position2=POS4;
  } 
  else if (position == 5) {
    position2=POS5;
  } 
  else  {
    position2=POS6;
  }

  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(10,160);
  tft.println(position2);
}

//************************************************************

void getShowAirflow(){

  tft.setCursor(160, 190);
  tft.setTextColor(ILI9341_BLACK); 
  tft.println(countsPerMinute); 

  countsPerMinute=eHealth.airFlowBPM();

  tft.setCursor(160, 190);
  tft.setTextColor(ILI9341_WHITE);
  tft.println(countsPerMinute);

}

//************************************************************
void setAlarm(){

  //  if ( SPO2<90 || BPM<30){
  //
  //    alarm=1;
  //  }
  //  else{
  //    alarm=0;
  //  }

  alarm=1;

}

//************************************************************

void compoundFrame(){

  dtostrf(conductance,2,2,conductanceSEND);
  dtostrf(temperature,2,2,temperatureSEND);

  snprintf(dataFrame,150,
  "#N:%d#COND:%s#BPM:%d#SPO2:%d#TEMP:%s#AirBPM:%d#POS:%s#ALARM:%d",numFrame,conductanceSEND,BPM,SPO2,temperatureSEND,countsPerMinute,position2,alarm);

  numFrame++;
  datagpsOK=0;

}

//************************************************************

void startLora(){

  tft.setTextColor(ILI9341_RED);
  tft.setCursor(10,10);
  tft.println("Sending data via");
  tft.setCursor(10,40);
  tft.println("LoRa");

  sx1272.ON();
  e = sx1272.setMode(1);

  // Select frequency channel
  e = sx1272.setChannel(CH_16_868);

  // Select output power (Max, High or Low)
  e = sx1272.setPower('H');

  // Set the node address and print the result
  e = sx1272.setNodeAddress(4);

}

//************************************************************

void sendLora(){

  e = sx1272.sendPacketTimeoutACK(3, dataFrame);

  sx1272.OFF();

  error=0;

  if (e == 0)
  {
    tft.setCursor(10,70);
    tft.println("Packet sent");
  }
  else
  {
    tft.setCursor(10,70);
    tft.println("Error sending");
    tft.setCursor(10,100);
    tft.println("Packet");
    error=1;
  }

  delay(2000);
  tft.fillScreen(ILI9341_BLACK);

}

//************************************************************

void send3G(){

  tft.setTextColor(ILI9341_RED);
  tft.setCursor(10,10);
  tft.println("Sending data via 3G");

  power_on();

  if (cont3G == 0)

  {
    tft.setCursor(10,40);
    tft.println("Problem turning on the module");    
    delay(2000);
    tft.fillScreen(ILI9341_BLACK);
  }

  else{

    delay(3000);

    start = millis();

    while( ((sendATcommand("AT+CREG?", "+CREG: 0,1", 500) || sendATcommand("AT+CREG?", "+CREG: 0,5", 500)) == 0) && (millis() - start < 20000) );

    tft.setCursor(10,40);
    tft.println("Waiting to connect to the network...");    

    // sets APN, user name and password
    sendATcommand("AT+CGSOCKCONT=1,\"IP\",\"movistar.es\"", "OK", 2000);
    sendATcommand("AT+CSOCKAUTH=1,1,\"movistar\",\"movistar\"", "OK", 2000);

    sendATcommand("AT+CFTPSERV=\"pruebas.libelium.com\"", "OK", 2000);
    sendATcommand("AT+CFTPPORT=21", "OK", 2000);
    sendATcommand("AT+CFTPMODE=1", "OK", 2000);
    sendATcommand("AT+CFTPUN=\"t3g@libelium.com\"", "OK", 2000);
    sendATcommand("AT+CFTPPW=\"ftp1234\"", "OK", 2000);


    // uploads data to the FTP server
    if (datagpsOK==0)
    {
      sprintf(aux_str, "AT+CFTPPUT=\"/falo2/sensor%03u.txt\"", numFrame);
    }
    else
    {
      sprintf(aux_str, "AT+CFTPPUT=\"/falo2/position%03u.txt\"", numFrame);  
    }

    answer = sendATcommand(aux_str, "+CFTPPUT: BEGIN", 20000);

    if (answer == 1)
    {        
      Serial.print(dataFrame);

      // Sends <Ctrl+Z>
      aux_str[0] = 0x1A;
      aux_str[1] = 0x00;
      answer = sendATcommand(aux_str, "OK", 20000);

      if (answer == 1)
      {
        tft.setCursor(10,100);
        tft.println("Upload done");
      }
      else
      {
        tft.setCursor(10,100);
        tft.println("Upload fail");
      }

    }
    else
    {
      tft.setCursor(10,100);
      tft.println("Error with server");    
    } 

  }

  delay(2000);
  tft.fillScreen(ILI9341_BLACK);  

}

//************************************************************

void power_on(){

  uint8_t answer=0;

  // checks if the module is started
  answer = sendATcommand("AT", "OK", 2000);
  if (answer == 0)
  {
    // power on pulse
    digitalWrite(onModulePin,HIGH);
    delay(3000);
    digitalWrite(onModulePin,LOW);

    cont3G=15;

    // waits for an answer from the module
    while(answer == 0 && cont3G>0){ 

      cont3G--;

      // Send AT every two seconds and wait for the answer
      answer = sendATcommand("AT", "OK", 2000);    
    }
  }

}

//************************************************************

int8_t sendATcommand(char* ATcommand, char* expected_answer1,
unsigned int timeout)
{

  uint8_t x=0,  answer=0;
  char response[100];
  unsigned long previous;

  memset(response, '\0', 100);    // Initialize the string

  delay(100);

  while( Serial.available() > 0) Serial.read();    // Clean the input buffer

  Serial.println(ATcommand);    // Send the AT command 

    x = 0;
  previous = millis();

  // this loop waits for the answer
  do{

    if(Serial.available() != 0){    
      response[x] = Serial.read();
      x++;
      // check if the desired answer is in the response of the module
      if (strstr(response, expected_answer1) != NULL)    
      {
        answer = 1;
      }
    }
    // Waits for the asnwer with time out
  }
  while((answer == 0) && ((millis() - previous) < timeout));    

  return answer;
}

//************************************************************

void getGPSposition(){

  tft.setTextColor(ILI9341_RED);
  tft.setCursor(10,10);
  tft.println("Alarm detected!");

  tft.setCursor(10,40);
  tft.println("Geting position");

  power_on();

  if (cont3G == 0)

  {
    tft.setCursor(10,70);
    tft.println("Problem turning on the module");
    delay(2000);
    tft.fillScreen(ILI9341_BLACK);
    errorGPS=1;
  }

  else

  {

    tft.setCursor(10,70);
    tft.println("Turn on the board");

    delay(2000);

    // starts GPS session in stand alone mode
    answer = sendATcommand("AT+CGPS=1,1","OK",1000);    
    if (answer == 0)
    {
      //Serial.println("Error starting the GPS");
      //Serial.println("The code stucks here!!");
      while(1);
    }

    start = millis();

    datagpsOK=0;

    while ((millis() - start < 60000) && (datagpsOK==0))

    {

      answer = sendATcommand("AT+CGPSINFO","+CGPSINFO:",1000);    // request info from GPS

      if (answer == 1)
      {

        counter = 0;
        do{
          while(Serial.available() == 0);
          gps_data[counter] = Serial.read();
          counter++;
        }
        while(gps_data[counter - 1] != '\r');
        gps_data[counter] = '\0';

        if(gps_data[0] == ',')
        {

          tft.setCursor(10,130);
          tft.println("GPS data:");
          tft.setCursor(10,160);
          tft.println("NO DATA");
          tft.setTextColor(ILI9341_BLACK);
          delay(200);
          tft.setCursor(10,160);
          tft.println("NO DATA");
          tft.setTextColor(ILI9341_RED);

        }
        else
        {    
          datagpsOK=1;     
          tft.setCursor(10,130);
          tft.println("GPS data:");
          tft.setCursor(10,160);
          tft.println(gps_data);
          delay(2000);         
        }       

      }
      else
      {
        tft.setCursor(10,160);
        tft.println("ERROR"); 
      }
    }

    delay(3000);
    tft.fillScreen(ILI9341_BLACK);
  }
}

			

4. User manual: learn how to build your backpack

First step it's to attach all the modules into the e-health portable board, also place the pigtails for 3G and GPS on the intended holes.


The LCD should be attached dirrectly to the top art of the box. After that it's posible to place the board into the bottom part of the box and attach it with some screws.


Then, we can put the e-Health Portable Board inside with all the shields on it.


Once we have everything into the box it's time to plug all the sensors to our system. Almost all the sensor can be connected easily with the box closed maybe you will need to open the top part of the box to attach GSR and Airflowsensor. When everything connected close the box with the screws.


With all the sensors connected it's time to insert the system into our backpack.

Our backpack has been modified specially for our system but you can made a new one with a different style and with all improvements you can think.

Attach the antennas and the solar panel.


With some help put your backpack and connect all sensors into your body. It will be useful use some velcro bands to fix the wires through your arm.


Finally turn on the system and you can start to test outside!

5. Tests

Once the project is finished, we performed various tests.

Power consumption

The system consumption vary considerably depending on the software loaded in the Arduino and de wireless communication used. We have tested the system with two codes:

  • Measure sensors and send information via LoRa:
    • Battery life: 17.5 hours
    • Power consumption: 250mAh
  • Measure sensors and GPS and send information via 3G:
    • Battery life: 6.5 hours
    • Power consumption: 677mAh

The solar panel will allow us to increase the autonomy with a typical load current of 100 mAh and 150 mAh in case of maximum solar incidence. In any case, we can increase the autonomy connecting a ectra battery to the USB port of the Solar Charger Shield.

Coverage

Line of Sight (LOS) tests

The Line of Sight (LOS) tests were taken between two different points next to the surrounding area of Zaragoza (Spain). The emitter was set in the point A : viewpoint of 'La Plana de Cadrete'. The receiver was set in the point B: viewpoint of the village of Alfocea. These points are 21.6 km (13.4 miles) apart.

Results:

LoRa ModeRangePowerChannelSuccess (%)Mean SNR (dB)Mean RSSI (dBm)Mean RSSI packet (dBm)Sensitivity (dB)Margin (dB)
Mode 1 21.6 km (13.4 miles) High CH_12_868 100 -9.79 -113.72 -126.79 -134 7.21
Max 100 -4.33 -113.76 -121.76 -134 12.24
High CH_16_868 100 -10.06 -114.28 -127.06 -134 6.94
Max 100 -3.20 -113.97 -120.21 -134 13.79
Mode 3 21.6 km (13.4 miles) High CH_12_868 95 -10.29 -114.16 -127.29 -129 1.71
Max 95 -3.73 -114.08 -120.73 -129 8.27
Mode 6 21.6 km (13.4 miles) High CH_12_868 99 -14.77 -107.22 -125.77 -125.5 -0.27
Max 100 -8.42 -106.60 -119.43 -125.5 6.07
Mode 9 21.6 km (13.4 miles) High CH_12_868 0 - - - -117 -
Max 49 -9.95 -107.68 -120.95 -117 -3.95

Non Line of Sight (NLOS) tests

The Non Line of Sight (NLOS) tests were taken between several points. The receiver is a Meshlium device, installed on the roof of the Libelium's headquarters. The emitter was set in several points in order to know the performance of this module in NLOS conditions within a city area.

Test features:

  • Lora Mode 1: maximum range.
  • Maximum output power: 14dBm.
  • Frequency channel: CH_12_868 in the 868mHz band.
  • Packets were set to a Waspmote Frame reaching around a 80-byte payload.
  • Fifty attempts were performed for every point.

Results:

PointRange (m)Number of Buildings (signal going through)Success (%)Mean SNR (dB)Mean RSSI (dBm)Mean RSSI packet (dBm)Margin (dB)
Point 1 830 4 96 -7.89 -112.95 -124.89 9.11
Point 2 960 14 92 -14.26 -111.26 -131.26 2.74
Point 3 1070 6 98 -3.22 -114.14 -120.24 13.76
Point 4 1530 14 98 -13.16 -112.24 -130.16 3.84
Point 5 863 6 100 -3.42 -113.48 -120.42 13.58

3G Tests

In the case of uploading data to the server using the 3G network, it has been always succesful like using GPRS network, we had the same success but with lower rate of data transfer.

Finally, the GPS tests have given good result with good accuracy but with the disadvantage of a high time obtaining the position between 15 and 20 seconds.

Full system tests

To check the correct operation of the system, we have tested it outside during several hours. In this case, we have used a code in which the data is collected and sent via LoRa or 3G.

In the next photos you can see how the system is used:


With the data measured by the sensors we have draw some graphs to verify their correct operation. In this case, the next graphs show the evolution of the pulse and respiration per minute, it was measured in the same period of time and increasing the physical activity during one hour.

If you are interested in Internet of Things (IoT) or M2M projects check our open source sensor platform Waspmote which counts with more than 100 sensors available to use 'off the shelf', a complete API with hundreds of ready to use codes and a low consumption mode of just 0.7µA to ensure years of battery life.

Know more at:

Get the Starter Kits at: