I explain how to connect the eHealth sensor board from Cooking Hacks via Bluetooth to a Linux-based PC (or Raspberry Pi) to stream data and plot it on the computer with the bluePy library.
Contents
The eHealth Board
The eHealth sensor board is an Arduino-based board. It is a nice development platform to explore the biomedical sensors, but it has many drawbacks in terms of low reliability of the sensors. Depending on the application this sensor board can be adequate or not.
Generally, I think, the price does not worth with the product you get
Better you get separately (by other vendors maybe) the sensors you may need.
In my application, I wanted to stream real-time data from the human body and plot them in real-time wirelessly (via Bluetooth Low energy). The data should be as accurate and reliable as possible. The idea is to track human activities, so the sensors should be integrated somehow and send data continuously without the interaction of the person under test.
A Review over the eHealth Sensors
Here I explain the sensors I used, which not and why. The conclusions after testing all the eHealth sensors:
Patient position: this is in reality the NXP-accelerometer MMA8452Q. If we would like to use an accelerometer we would use better directly one like this from sparkfun with the same MMA8452Q component and 10$ instead of the 48$ of cooking hacks. Even you can buy the chip for less than 2$ in mouser or farnell.
Blood Pressure Sensor (Sphygmomanometer): This sensor does not allow to stream real time data. It is only one-time-measurements. This does not fit to add to my bio data collection project.
Pulse and Oxygen in Blood Sensor (SPO2): This sensor is not reliable. Actually it was funny when studying in deep the sensor I notice something wrong. Looking into the library, the transmitted data where read from the LCD, yes directly from the LCS.
The LCD input pins were bridged to the connector, later by a rather complex function in the software, the conversion of LCD-digits to a integer was made.
The business from “cooking-hacks” is: buy in ebay the oximeter sensor for 10€, hack it connecting 10 cables and a connector, for later sell it for only 66€. Fabulous.
The thing is that the solution is very smart and it works fine for small applications. The LCD has 3 digits, which are multiplexed. So there are 8 lines + one control line. The control or selector line is read with an interrupt, then you can read the digits and order them creating an integer value of the lecture.
The problem comes when your program is getting bigger, maybe you have many other “real time” measurements or you want to use more interrupts. Then stopping the program flow every time the selector line trigger to calculate a new digit, lows the overall performance a lot. For my case was almost impossible to synchronize the BLE and reading other sensors.
That is why this sensor was also discarded.
A smarter solution for this would be to include an extra microcontroller inside which perform the calculation of the LCDs and sent it back vie SPI or I2C. Of course it is more costly.
Galvanic Skin Response Sensor (GSR – Sweating): This sensor only measured the voltage differences between 2 pins. The values jump from time to time. The values have to be filtered or threated.
Electrocardiogram Sensor (ECG): The heart rate have to be calculated out of this measurements. There is another better and more comfortable solutions to integrate on the system, like the ant+ heart rate sensors.
Electromyography Sensor (EMG): We discarded this sensor because I have already 22 of this integrated on the Athos T-shirt and shorts. Also the ECG sensor cannot be used at the same time than the EMG.
Temperature: This sensor work quite fine and accurate. It can be also calibrated by measuring the real resistors value of your board and correct this error by software.
Glucometer: This sensor make isolate measurements and it does not stream values. The process of measurement cannot be automated: You need to put a drop of blood in the probe, then connect the cable to the Arduino for send the data to Arduino. This does not match with my project design.
Airflow: This sensor works very fine. It send a value between 0 and 1023 when you blow air from your nose. The problem I find to track the breathing is that when you breathe through your mouth you cannot measure nothing.
Finally I implemented the breathing sensor, the electrocardiogram, temperature sensor and the skin-resistance sensor were implemented in the Arduino Curie 101, because it has already built-in with BLE capabilities (and because I wanted to try the combination of Intel-arduino)
How does it work?
A program should run in the Arduino and another software in the computer side, a Linux-based machine.
Arduino side
To implement the Arduino Code I wrote a specific library combining the BLE Curie lib ad the eHealth library. This library you can find here and I called “SensorSuitBLE”. This can be found at the end of the post.
The Arduino software *.ino is:
>#include SensorSuit Sensor; void setup() { delay(5000); Sensor.initSystem(); Sensor.initBLE(); } void loop() { while(Sensor.amIconnected()==0){ //Waiting for a Master to connect } Serial.println("Connected to central"); //Serial.println(central.address());//print the central's MAC address: //Serial.print("I am connected = "); Serial.println(Sensor.amIconnected()); while (Sensor.amIconnected()) { delay(100); //long currentMillis = millis(); Sensor.updateSensors(); Sensor.decodeConfigBLE(); } Serial.println("Disconnected from central "); }//end loop //================================================ //!Interrupt Service Routine //================================================ //Interrupt for Serial incomming bytes void serialEvent() { Sensor.decodeSerialInput(); }
To debug the Arduino software, it is very useful to use the nRF connect app from NordicSemiconductors. There you can with you smart-phone scan and read the characteristics and notifications from the Arduino.
This is a first version of the project, which is logically very improvable and optimizable. The device name is “eHealth-board”, but this can be changed if you like something different.
Note: many of the connecting problems can be solved by the infallible and advanced method we learn in the university: RESET. Press the reset button hidden under the red board. Especially, if the connection get lost or disconnect in an improper way, you would need to reset. I should fix this bug in the coming versions, but for now it is ok.
Once the Arduino software is finished, tested and ready, you can forget about it. You just need to connect the Arduino to a power supply (USB or Battery) and it will send the lectures of the sensors.
The Voltage supply needs to be between 7 and 12V, therefore I built a battery-holder with the Arduino connector. This is quite bulky and not practical. Instead of this 2 small lithium batteries (3.8V+3.8V) in series can be used instead.
Computer side
I am using a XU4. This is a Linux-machine like rasperyPi or an Ubuntu computer. But it would be also exportable to windows (I think). I am using the bluePy library for Bluetooth. You may install this before you can run the script.
To change which sensor you want to activate, there is a configuration byte inside the activation command. Modifying it you can set which sensors are going to be measured.
The python script is the following:
################################################################### # Connecto to the eHealth board vie BLE with Intel Curie 101 # July 2017 # Know-Center Alberto Lopez #################################################################### import binascii #convert from bluepy import btle #Bluetooth low energy lib from struct import * #conversions import csv #handle csv files from datetime import datetime #fortimestamp import time #for time delays import subprocess #to call unix command EHEALTH = "84:68:3e:00:19:98" E9 = "e9:90:00:93:c2:a1" D5 = "d5:48:d0:91:27:40" UUID_SUIT = "19b10010-e8f2-537e-4f6c-d104768a1313" DEBUG =True def writeData(skin_, temperature_, heartRate_,airFlow_): ehealthFile.write(str(datetime.now().strftime("%Y/%m/%d %H:%M:%S.%f"))) ehealthFile.write(",") ehealthFile.write(str(skin_)) ehealthFile.write(",") ehealthFile.write(str(temperature_)) ehealthFile.write(",") ehealthFile.write(str(heartRate_)) ehealthFile.write(",") ehealthFile.write(str(airFlow_)) ehealthFile.write("\n") def newFile(): ehealthFile.write("Time,skin,temperature,heartRate,airFlow\n") return ######## MAIN ####### print("Connecting...") eHealth = btle.Peripheral(EHEALTH) #device is hci0 print("connected!") SuitSensor = btle.UUID(UUID_SUIT) SuitService = eHealth.getServiceByUUID(SuitSensor) SuitSensorConfig = SuitService.getCharacteristics()[0] # Enable the sensors cmd SuitSensorConfig.write(bytes("\x33",'utf-8'),True) time.sleep(1.0) # Allow sensor to stabilise val = SuitSensorConfig.read() print("Config raw value", binascii.b2a_hex(val)) SuitSensorVal1 = SuitService.getCharacteristics()[1] SuitSensorVal2 = SuitService.getCharacteristics()[2] SuitSensorVal3 = SuitService.getCharacteristics()[3] SuitSensorVal4 = SuitService.getCharacteristics()[4] subprocess.Popen(["kst2", "Health.kst"]) #open the real time plotter with open('Health.csv','w',1) as ehealthFile: newFile() while True: val1 = unpack('4B',SuitSensorVal1.read()) valor1 = format(val1[1],'0b').rjust(8,'0') + format(val1[0],'0b').rjust(8,'0') skin = int(valor1[0:16],2) val1 = unpack('4B',SuitSensorVal2.read()) valor1 = format(val1[1],'0b').rjust(8,'0') + format(val1[0],'0b').rjust(8,'0') temperature = int(valor1[0:16],2) val1 = unpack('4B',SuitSensorVal4.read()) valor1 = format(val1[1],'0b').rjust(8,'0') + format(val1[0],'0b').rjust(8,'0') heartRate = int(valor1[0:16],2) val1 = unpack('4B',SuitSensorVal3.read()) valor1 = format(val1[1],'0b').rjust(8,'0') + format(val1[0],'0b').rjust(8,'0') airFlow = int(valor1[0:16],2) if(DEBUG): print("Skin" + str(skin) + "\tTemperature " + str(temperature) + "\theartRate " +str(heartRate) + "\tairFlow " +str(airFlow)) #time.sleep(0.10) # Allow sensor to stabilise writeData(skin,temperature,heartRate,airFlow) eHealth.disconnect()
To run this script just open a terminal where the file is located and run the commad:
>> sudo python3 ConnectTo101.py
If you want something smarter like plotting it in real time in a graph, consider see my other tutorial:
“How to plot data in real-time using KST”
For further information and documentation about sensors and how to connect, then see the official web from cooking hacks.
Library for Arduino
Header file:
/* eHealth Sensor Suit BLE library * Know-Center Graz * June 2017 * Version 1.0 * Author: Alberto L. Gasso */ #ifndef SensorsuitBLE_h #define SensorsuitBLE_h #include "Arduino.h" #include #define SENSOR_NUM 7 #define BIT0 0x01 #define BIT1 0x02 #define BIT2 0x04 #define BIT3 0x08 #define BIT4 0x10 #define BIT5 0x20 #define BIT6 0x40 #define BIT7 0x80 const char*const UUID_SUIT = "19B10010-E8F2-537E-4F6C-D104768A1313"; //defined random UUID const char*const ENABLE = "FFFFFFFF-BEB0-BEB0-DEAD-AABBCCDDEEFF"; //defined random UUID const char*const SKIN = "00000001-BEB0-BeB0-DEAD-AABBCCDDEEFF"; //defined random UUID const char*const TEMPERATURE = "00000010-BEB0-BeB0-DEAD-AABBCCDDEEFF"; //defined random UUID const char*const CARDIO = "00010000-BEB0-BeB0-DEAD-AABBCCDDEEFF"; //defined random UUID const char*const AIR = "00100000-BEB0-BeB0-DEAD-AABBCCDDEEFF"; //defined random UUID static BLEPeripheral board; // create peripheral instance static BLEService eHealthService(UUID_SUIT); // create service // create switch characteristic and allow remote device to read and write static BLECharCharacteristic enableCharact(ENABLE, BLERead | BLEWrite); // create Sensor characteristic and allow remote device to get notifications static BLEIntCharacteristic skinCharact(SKIN, BLERead | BLENotify); // allows remote device to get notifications static BLEIntCharacteristic temperatureCharact(TEMPERATURE, BLERead | BLENotify); // allows remote device to get notifications //static BLECharCharacteristic rpmCharact(UUID_SUIT, BLERead | BLENotify); // allows remote device to get notifications //static BLECharCharacteristic spo2Charact(UUID_SUIT, BLERead | BLENotify); // allows remote device to get notifications static BLEIntCharacteristic airCharact(AIR, BLERead | BLENotify); // allows remote device to get notifications static BLEIntCharacteristic cardioCharact(CARDIO, BLERead | BLENotify); // allows remote device to get notifications // Library interface description class SensorSuit{ public: //! Configuration parameter of each sensor. /*! \param void * 0 == Skin conductance * 1 == Temperature * 2 == pulse * 3 == oxygen * 4 == Pcardio * 5 == airFlow * 6 == Accelerometer */ static int state[SENSOR_NUM]; /*! enables or disables the time stamp in microseconds since Arduino was reseted \param void * 0 == disabled * 1 == enabled (default) */ static int timeStamp; //*************************************************************** // Constructor of the class * //*************************************************************** //! Class constructor. SensorSuit(void); //*************************************************************** // Public Functions * //*************************************************************** //BLE functions// void initBLE(void); void updateSensors(void); void checkState(void); int amIconnected(void); uint8_t decodeConfigBLE(void); //BLECentral getCentral(void); //eHealth library modified functions// //! Initializes the BloodPressureSensor sensor and configure some values /*! \param float parameter with correction value \return void */ void readBloodPressureSensor(void); //! Swap data for blood pressure mesure char swap(char _data); //! Returns the corporal temperature. /*! \param void \return float : The corporal temperature value. */ float getTemperature( void ); //! Returns the value of skin conductance. /*! \param void \return int : The skin conductance value. */ int getSkinConductance(void); //! Returns an analogic value to represent the Electrocardiography. /*! \param void \return int : The analogic value (0-5V). */ int getECG(void); //! Returns an analogic value to represent the Electromyography. /*! \param void \return float : The analogic value (0-5V). */ int getEMG(void); //! Returns the value of the systolic pressure. /*! \param int \return int : The systolic pressure. */ int getSystolicPressure(int i); //! Returns the value of the diastolic pressure. /*! \param int \return int : The diastolic pressure. */ int getDiastolicPressure(int i); //! Returns an analogic value to represent the air flow. /*! \param void \return int : The value (0-1023) read from the analogic in. */ int getAirFlow(void); //! Read the values stored in the glucometer. /*! \param void \return void */ void readGlucometer(void); //!Returns the number of data stored in the glucometer. /*! \param void \return int : length of data */ uint8_t getGlucometerLength(void); //!Returns the number of data stored in the blood pressure sensor. /*! \param void \return int : length of data */ uint8_t getBloodPressureLength(void); //!Struct to store data of the glucometer. struct glucoseData { uint8_t year; uint8_t month; uint8_t day; uint8_t hour; uint8_t minutes; uint8_t glucose; uint8_t meridian; }; //!Vector to store the glucometer measures and dates. glucoseData glucoseDataVector[8]; //!Struct to store data of the blood pressure sensor. struct bloodPressureData { uint8_t year; uint8_t month; uint8_t day; uint8_t hour; uint8_t minutes; uint8_t systolic; uint8_t diastolic; uint8_t pulse; }; //!Vector to store the blood pressure measures and dates. bloodPressureData bloodPressureDataVector[8]; //Custom methods// //! Intialice the system. /*! \param void \return int : 0 when succesful */ uint8_t initSystem(void); //! read the sensors connected to the system. /*! \param void \return int : 0 when succesful */ uint8_t readSensors(void); //! Print the sensors connected to the system to debug /*! \param void \return int : 0 when succesful */ uint8_t printValuesOnTerminal(void); //! Print the sensors connected to the system to save data /*! \param void \return int : 0 when succesful */uint8_t printValuesForProcessing(void); //! Print the sensors connected to the system to debug /*! \param void \return int : 0 when succesful */ uint8_t decodeSerialInput(void); //! It enables the debug mode /*! * 1 == Debug mode on * 0 == Logging mode on */ uint8_t debudMode; /*! Return if the debug mode is on \param void \return int : 1 == Debug mode on * 0 == Logging mode on */ int isDebugModeOn(void); //! Print the headers for the enabled sensor for data logging /*! \param void \return int : 0 when succesful */ uint8_t printHeaders(void); //*************************************************************** // Private Functions * //*************************************************************** private: //! Print the sensors actual configuration status /*! \param void \return int : 0 when succesful */ uint8_t printSensorStatus(void); //! Print the sensor state enable or disabled /*! \param void \return int : 0 when succesful */ uint8_t printStatus(int state); //*************************************************************** // Private Variables * //*************************************************************** //! Time stamp unsigned long time; //! It stores the skin conductance value int conductance; //! It stores the temperature in Celsius grads value int temperature; //! It stores the pulse value int pulse; //! It stores the skin oxygen in blood value int oxygen; //! It stores the cardiogram signal int cardio; //! It stores the air flow signal int airFlow; struct accel { int x; int y; int z; }; //!It stores the number of data of the glucometer. uint8_t length; }; #endif
Source file:
/* eHealth Sensor Suit BLE library * June 2017 * Version 1.0 * Author: Alberto L. Gasso */ // include this library's description file #include "SensorSuitBLE.h" #include "Arduino.h" //*************************************************************** // Variables and definitions * //*************************************************************** int SensorSuit::state[SENSOR_NUM]; int SensorSuit::timeStamp; //*************************************************************** // Constructor of the class * //*************************************************************** //! Function that handles the creation and setup of instances SensorSuit::SensorSuit(void) { /*void constructor*/ } //*************************************************************** // Public Methods * //*************************************************************** //!****************************************************************************** //BLE functions// void SensorSuit::initBLE(void){ //BLEPeripheral board; // create peripheral instance /* BLEService eHealthService(UUID_SUIT); // create service // create switch characteristic and allow remote device to read and write BLECharCharacteristic enableCharact(UUID_SUIT, BLERead | BLEWrite); // create Sensor characteristic and allow remote device to get notifications BLEFloatCharacteristic skinCharact(UUID_SUIT, BLERead | BLENotify); // allows remote device to get notifications BLEFloatCharacteristic temperatureCharact(UUID_SUIT, BLERead | BLENotify); // allows remote device to get notifications BLECharCharacteristic rpmCharact(UUID_SUIT, BLERead | BLENotify); // allows remote device to get notifications BLECharCharacteristic spo2Charact(UUID_SUIT, BLERead | BLENotify); // allows remote device to get notifications BLEIntCharacteristic airCharact(UUID_SUIT, BLERead | BLENotify); // allows remote device to get notifications BLEIntCharacteristic cardioCharact(UUID_SUIT, BLERead | BLENotify); // allows remote device to get notifications */ // set the local name peripheral advertises board.setLocalName("eHealth-board"); // set the UUID for the service this peripheral advertises: board.setAdvertisedServiceUuid(eHealthService.uuid()); // add service and characteristics board.addAttribute(eHealthService); board.addAttribute(enableCharact); board.addAttribute(skinCharact); board.addAttribute(temperatureCharact); //board.addAttribute(rpmCharact); //board.addAttribute(spo2Charact); board.addAttribute(airCharact); board.addAttribute(cardioCharact); // advertise the service board.begin(); Serial.println("Bluetooth device active, waiting for connections..."); } int SensorSuit::amIconnected(void){ BLECentral central = board.central(); if (central) { //For Debugging //Serial.print("Connected to central: "); //print the central's MAC address: //Serial.println(central.address()); return 1; } else{ return 0; } } void SensorSuit::updateSensors(void){ /*Debugging */ //static float skin = 32; //static int temperature2 = 1000; //Serial.println("inside updateSensors"); // skin++; //temperature2--; /*Debuggin */ board.poll(); readSensors(); //Read sensors //Write to the server //TODO: update to the server only the enabled data to save energy skinCharact.setValue(conductance); //Serial.println(conductance,HEX); temperatureCharact.setValue(temperature); //rpmCharact.setValue(pulse); //spo2Charact.setValue(); cardioCharact.setValue(cardio); airCharact.setValue(airFlow); /* positionXCharact.setValue(accel.x); positionYCharact.setValue(accel.y); positionZCharact.setValue(accel.z); */ } void SensorSuit::checkState(void){ if (enableCharact.written()){ Serial.print("The configuration is ... ");Serial.println(enableCharact.value(),HEX); } if (enableCharact.value()){ Serial.println("Reading on"); } else { Serial.println("Readin off"); } } /* BLECentral SensorSuit::getCentral(void){ return board.central(); } */ uint8_t SensorSuit::decodeConfigBLE(void){ if(enableCharact.written()){ int i; int incomingByte = enableCharact.value(); // read the incoming byte for( i = 0; i<SENSOR_NUM;i++){ if(incomingByte&0x01){ state[i] = 1; //Sensor enable }else{ state[i] = 0; //sensor disable } incomingByte =incomingByte >> 1; } Serial.println("Sensor State"); printHeaders(); /* for( i = 0;i<SENSOR_NUM;i++){ Serial.println(state[i]); } */ return 0; } } //eHealth library modified functions// //!****************************************************************************** //! Name: readBloodPressureSensor() * //! Description: Initializes the BloodPressureSensor sensor. * //! Param : void * //! Returns: void * //! Example: eHealth.initBloodPressureSensor(); * //!****************************************************************************** void SensorSuit::readBloodPressureSensor(void) { unsigned char _data= 0x00; int ia=0; length=0; Serial.begin(19200); Serial.write(0xAA); delayMicroseconds(1); Serial.write(0x55); delayMicroseconds(1); Serial.write(0x88); delay(2500); Serial.print("\n"); if (Serial.available() > 0) { // The protocol sends the measures for (int i = 0; i<4; i++){ // Read four dummy data Serial.read(); } while(_data != 0xD1){ if (ia==0){ _data = Serial.read(); } bloodPressureDataVector[length].year = swap(_data); bloodPressureDataVector[length].month = swap(Serial.read()); bloodPressureDataVector[length].day = swap(Serial.read()); bloodPressureDataVector[length].hour = swap(Serial.read()); bloodPressureDataVector[length].minutes = swap(Serial.read()); bloodPressureDataVector[length].systolic = swap(Serial.read()); bloodPressureDataVector[length].diastolic = swap(Serial.read()); bloodPressureDataVector[length].pulse = swap(Serial.read()); length++; ia=1; for (int i = 0; i<4; i++){ // CheckSum 1 Serial.read(); } _data = Serial.read(); } for (int i = 0; i<3; i++){ // CheckSum 2 Serial.read(); } } } //! Swap data for blood pressure mesure char SensorSuit::swap(char _data) { char highBits = (_data & 0xF0) / 16; char lowBits = (_data & 0x0F) * 16; return ~(highBits + lowBits); } //!****************************************************************************** //! Name: getSystolicPressure() * //! Description: Returns the value of the systolic pressure. * //! Param : int * //! Returns: int with the systolic pressure. * //! Example: int systolic = getSystolicPressure(1); * //!****************************************************************************** int SensorSuit::getSystolicPressure(int i) { return bloodPressureDataVector[i].systolic; } //!****************************************************************************** //! Name: getDiastolicPressure() * //! Description: Returns the value of the diastolic pressure. * //! Param : int * //! Returns: int with the diastolic pressure. * //! Example: int diastolic = getDiastolicPressure(1); * //!****************************************************************************** int SensorSuit::getDiastolicPressure(int i) { return bloodPressureDataVector[i].diastolic; } //!****************************************************************************** //! Name: readGlucometer() * //! Description: It reads the data stored in the glucometer * //! Param : void * //! Returns: void * //! Example: readGlucometer(); * //!****************************************************************************** void SensorSuit::readGlucometer(void) { // Configuring digital pins like INPUTS pinMode(5, OUTPUT); digitalWrite(5, HIGH); delay(100); Serial.begin(1200); delay(100); Serial.print("U"); // Start communication command. delay(1000); // Wait while receiving data. Serial.print("\n"); if (Serial.available() > 0) { length = Serial.read();// The protocol sends the number of measures Serial.read(); // Read one dummy data for (int i = 0; i<length; i++) { // The protocol sends data in this order glucoseDataVector[i].year = Serial.read(); glucoseDataVector[i].month = Serial.read(); glucoseDataVector[i].day = Serial.read(); glucoseDataVector[i].hour = Serial.read(); glucoseDataVector[i].minutes = Serial.read(); Serial.read(); // Byte of separation must be 0x00. glucoseDataVector[i].glucose = Serial.read(); glucoseDataVector[i].meridian = Serial.read(); Serial.read(); // CheckSum 1 Serial.read(); // CheckSum 2 } } digitalWrite(5, LOW); } //!****************************************************************************** //! Name: getGlucometerLength() * //! Description: it returns the number of data stored in the glucometer * //! Param : void * //! Returns: uint8_t with length * //! Example: int length = getGlucometerLength(); * //!****************************************************************************** uint8_t SensorSuit::getGlucometerLength(void) { return length; } //!****************************************************************************** //! Name: getBloodPressureLength() * //! Description: it returns the number of data stored in * //! the blood pressure sensor * //! Param : void * //! Returns: uint8_t with length * //! Example: int length = getBloodPressureLength(); * //!****************************************************************************** uint8_t SensorSuit::getBloodPressureLength(void) { return length; } //!****************************************************************************** //! Name: getTemperature() * //! Description: Returns the corporal temperature. * //! Param : void * //! Returns: float with the corporal temperature value. * //! Example: float temperature = getTemperature(); * //!****************************************************************************** float SensorSuit::getTemperature(void) { //Local variables float Temperature= 0.0; //Corporal Temperature float Resistance; //Resistance of sensor. float ganancia=5.0; float Vcc=3.3; float RefTension=3.0; // Voltage Reference of Wheatstone bridge. float Ra=4700.0; //Wheatstone bridge resistance. float Rc=4700.0; //Wheatstone bridge resistance. float Rb=821.0; //Wheatstone bridge resistance. int sensorValue = analogRead(A3); float voltage2=((float)sensorValue*Vcc)/1023; // binary to voltage conversion // Wheatstone bridge output voltage. voltage2=voltage2/ganancia; // Resistance sensor calculate float aux=(voltage2/RefTension)+Rb/(Rb+Ra); Resistance=Rc*aux/(1-aux); if (Resistance >=1822.8) { // if temperature between 25ºC and 29.9ºC. R(tª)=6638.20457*(0.95768)^t Temperature=log(Resistance/6638.20457)/log(0.95768); } else { if (Resistance >=1477.1){ // if temperature between 30ºC and 34.9ºC. R(tª)=6403.49306*(0.95883)^t Temperature=log(Resistance/6403.49306)/log(0.95883); } else { if (Resistance >=1204.8){ // if temperature between 35ºC and 39.9ºC. R(tª)=6118.01620*(0.96008)^t Temperature=log(Resistance/6118.01620)/log(0.96008); } else{ if (Resistance >=988.1){ // if temperature between 40ºC and 44.9ºC. R(tª)=5859.06368*(0.96112)^t Temperature=log(Resistance/5859.06368)/log(0.96112); } else { if (Resistance >=811.7){ // if temperature between 45ºC and 50ºC. R(tª)=5575.94572*(0.96218)^t Temperature=log(Resistance/5575.94572)/log(0.96218); } } } } } return Temperature; } //!****************************************************************************** //! Name: getSkinConductance() * //! Description: Returns the value of skin conductance. * //! Param : void * //! Returns: int with the value of skin conductance * //! Example: int conductance = getSkinConductance(); * //!****************************************************************************** int SensorSuit::getSkinConductance(void) { // Given formula by the vendor: 2*(((sensorValue*5.0/1023) - 0.5) / 100000); int conductance = ((((analogRead(A2)+1)*5)-512)*20); //conductance1 = conductance1>>8; return conductance; //Return (value/1024) in uSiemens } //!****************************************************************************** //! Name: getAirFlow() * //! Description: Returns an analogic value to represent the air flow. * //! Param : void * //! Returns: int with the airFlow value (0-1023). * //! Example: int airFlow = getAirFlow(); * //!****************************************************************************** int SensorSuit::getAirFlow(void) { int airFlow = analogRead(A1); return airFlow; } //!****************************************************************************** //! Name: getECG() * //! Description: Returns an analogic value to represent the ECG. * //! Param : void * //! Returns: int with the ECG value in voltage * //! Example: int volt = eHealth.getECG(); * //!****************************************************************************** int SensorSuit::getECG(void) { int analog0 = analogRead(0); // binary to voltage conversion (float)analog0 * 5 / 1023.0 return analog0; } //Custom Functions // //!****************************************************************************** //! Name: initSystem() * //! Description: Initializes the sensor and configure some values. * //! Param : void * //! Returns: void * //! Example: eHealth.initPositionSensor(); * //!****************************************************************************** uint8_t SensorSuit::initSystem(void){ debudMode = 1; //Debug mode on timeStamp = 1; //Time stamp on //start communication with computer Serial.begin(115200); //eHealth.AccelStatus(); //eHealth.initPulsioximeter(); if(debudMode){ Serial.println("============================================="); Serial.println("|| System initialized .... "); Serial.println("|| - Project Sensor Suit - "); Serial.println("|| - Know Center - June 2017 - "); Serial.println("============================================="); Serial.println("Send the command cXXXXXXX where X is:"); Serial.println("1 to enable \n0 to disable sensor"); } return 0; } /*! Return if the debug mode is on \param void \return int : 1 == Debug mode on * 0 == Logging mode on */ int SensorSuit::isDebugModeOn(void){ return debudMode; } uint8_t SensorSuit::readSensors(void){ if(timeStamp){ time = micros(); } if(state[0] ==1){ conductance = getSkinConductance(); } if(state[1] ==1){ temperature = getTemperature()*100; } if(state[2] ==1){ //pulse = getBPM(); } if(state[3] ==1){ //oxygen = getOxygenSaturation(); } if(state[4] ==1){ cardio =getECG(); } if(state[5] ==1){ airFlow = getAirFlow(); } if(state[6] ==1){ //position = eHealth.getBodyPosition(); } return 0; } uint8_t SensorSuit::printValuesOnTerminal(void){ // if(timeStamp){ // Serial.print("Time Stamp : ");Serial.println(time); // } if(state[0] ==1){ Serial.print("Conductance : ");Serial.println(conductance); } if(state[1] ==1){ Serial.print("Temperature ( C): "); Serial.println(temperature, 2); } if(state[2] ==1){ Serial.print("PRbpm : "); Serial.println(pulse); } if(state[3] ==1){ Serial.print("%SPo2 : "); Serial.println(oxygen); } if(state[4] ==1){ Serial.print("cardio/muscle : "); Serial.println(cardio); } if(state[5] ==1){ Serial.print("Air flow : "); Serial.println(airFlow); } if(state[6] ==1){ /* Serial.print("Accelerometer X: "); Serial.println(positions.x); Serial.print("Accelerometer Y: "); Serial.println(positions.y); Serial.print("Accelerometer Z: "); Serial.println(positions.z); */ } if(state[0] || state[1] ||state[2] || state[3] || state[4] || state[5] || state[6] ==1){ Serial.println("========================================"); } return 0; } uint8_t SensorSuit::printValuesForProcessing(void){ if(timeStamp==1){ Serial.print(time); Serial.print(";"); } if(state[0] ==1){ Serial.print(conductance); Serial.print(";"); } if(state[1] ==1){ Serial.print(temperature, 2); Serial.print(";"); } if(state[2] ==1){ Serial.print(pulse); Serial.print(";"); } if(state[3] ==1){ Serial.print(oxygen); Serial.print(";"); } if(state[4] ==1){ Serial.print(cardio); Serial.print(";"); } if(state[5] ==1){ Serial.print(airFlow); Serial.print(";"); } if(state[6] ==1){ /* Serial.print(positions.x); Serial.print(";"); Serial.print(positions.y); Serial.print(";"); Serial.print(positions.z); Serial.print(";"); */ } if(state[0] || state[1] ||state[2] || state[3] || state[4] || state[5] || state[6] ==1){ Serial.println(""); } return 0; } uint8_t SensorSuit::decodeSerialInput(void){ // read the incoming byte int incomingByte = Serial.read(); //Serial.print(incomingByte,DEC); switch (incomingByte){ case 'c': //configuration for(int i = 0; i< SENSOR_NUM;i++){ incomingByte = Serial.read(); switch(incomingByte){ case '0': //sensor disable state[i] = 0; break; case '1': //Sensor enable state[i] = 1; break; }} Serial.println("newConfig"); if(debudMode){ printSensorStatus(); } break; case 's': //status request printSensorStatus(); break; case 'd': if(debudMode){ debudMode = 0; Serial.println("StartRecording"); printHeaders(); } else { debudMode = 1; } break; } return 0; } //! Print the headers for the enabled sensor for data logging /*! \param void \return int : 0 when succesful */ uint8_t SensorSuit::printHeaders(void){ if(timeStamp==1){ Serial.print("TimeStamp"); Serial.print(";"); } if(state[0] ==1){ Serial.print("Conductance"); Serial.print(";"); } if(state[1] ==1){ Serial.print("Temperature"); Serial.print(";"); } if(state[2] ==1){ Serial.print("Pulse"); Serial.print(";"); } if(state[3] ==1){ Serial.print("Oxygen"); Serial.print(";"); } if(state[4] ==1){ Serial.print("Cardio"); Serial.print(";"); } if(state[5] ==1){ Serial.print("AirFlow"); Serial.print(";"); } if(state[6] ==1){ Serial.print("Position.x"); Serial.print(";"); Serial.print("Position.y"); Serial.print(";"); Serial.print("Position.z"); Serial.print(";"); } if(state[0] || state[1] ||state[2] || state[3] || state[4] || state[5] || state[6] ==1){ Serial.println(""); } return 0; } //*************************************************************** // Private Methods * //*************************************************************** uint8_t SensorSuit::printSensorStatus(void){ Serial.print("1- Conductance is: "); printStatus(state[0]); Serial.print("2- Temperature is: "); printStatus(state[1]); Serial.print("3- Pulse is:\t "); printStatus(state[2]); Serial.print("4- Oxygen is: \t"); printStatus(state[3]); Serial.print("5- Cardio is: \t"); printStatus(state[4]); Serial.print("6- Air Flow is: \t"); printStatus(state[5]); Serial.print("7- Accelerometer is: "); printStatus(state[6]); Serial.println("===============*"); return 0; } uint8_t SensorSuit::printStatus(int state){ switch(state){ case 0: Serial.println("disabled"); break; case 1: Serial.println("enabled"); break; default: Serial.println("unkown"); break; } return 0; }
Bonjour Alberto I recently bought the Patient position belt ( the old one 5.96 €) from cooking-hack as i want to use it in a project and connect it first to a standard Arduino and next to a lolin d32 to try to get data via Bluetooth. As normaly the sensor is a MMA8452Q i trying to find the pinout of the connector, I thought to you as you may be already open it during your test Best regards Christophe
Hello Christophe, in the datasheet you can find the pinout and a then following the routes you can now the pinout of the connector. If not something should be labeled in the PCB, right?
best Regards