espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.47k stars 7.38k forks source link

Adafruit_MLX90614 and MAX30102 Not working #4561

Closed fervidautomation closed 3 years ago

fervidautomation commented 3 years ago

Make your question, not a Statement, inclusive. Include all pertinent information:

What you are trying to do
I tried to use ESP32 wroom dev board and use Adafruit_MLX90614 and MAX30102 sensor on I2C communication. As you might know both works on I2C communication. but It did not work. Any piece of advice will be highly appreciated.

Describe your system (Hardware, computer, O/S, core version, environment)
ESP32 Wroom dev MLX90614 and MAX30102 Describe what is failing
MAX30102 provide the data but mlx does not. If I am using a separate-2 2 programs then It is working fine.Which is kind of indication that the wiring is correct.

/*

simple SpO2 plotter for MH-ET LIVE MAX30102 breakout board and ESP32 devkit-C

Using Sparkfun MAX3010X library https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library

ESP32_MAX30102_simple-SpO2_plotter.ino by coniferconifer Copyright 2020 LICENSED under Apache License 2.0

Version 1.0

Shows SpO2 and the user's heart beat on Arduino's serial plotter. No display hardware is required. This program should not be used for medical purposes. I wrote this to learn how SpO2 can be measured and pay tributes for the inventors.

Pulse oximetry was developed in 1972, by Takuo Aoyagi and Michio Kishi, bioengineers, at Nihon Kohden in Japan. https://ethw.org/Takuo_Aoyagi

Since MH-ET LIVE MAX30102 breakout board seems outputting IR and RED swapped. red = particleSensor.getFIFOIR(); ir = particleSensor.getFIFORed(); is used in my code. If you have Sparkfun's MAX30105 breakout board , try to use #define MAX30105

Tips:

SpO2 is calculated as R=((square root means or Red/Red average )/((square root means of IR)/IR average)) SpO2 = -23.3 * (R - 0.4) + 100; // taken from a graph in https://ww1.microchip.com/downloads/jp/AppNotes/00001525B_JP.pdf // https://ww1.microchip.com/downloads/en/Appnotes/00001525B.pdf

Instructions:

0) Install Sparkfun's MAX3010X library 1) Load code onto ESP32 with MH-ET LIVE MAX30102 board 2) Put MAX30102 board in plastic bag and insulates from your finger. and attach sensor to your finger tip 3) Run this program by pressing reset botton on ESP32 4) Wait for 3 seconds and Open Arduino IDE Tools->'Serial Plotter' Make sure the drop down is set to 115200 baud 5) Search the best position and presure for the sensor by watching the blips on Arduino's serial plotter I recommend to place LED under the backside of nail and wrap you finger and the sensor by rubber band softly. 6) Checkout the SpO2 and blips by seeing serial Plotter 100%,95%,90%,85% SpO2 lines are always drawn on the plotter

Hardware Connections (Breakoutboard to ESP32 Arduino):

-VIN = 3.3V -GND = GND -SDA = 21 (or SDA) -SCL = 22 (or SCL) -INT = Not connected

this script also works on Arduino nao

Hardware Connections (Breakoutboard to Arduino nano): experimental

-VIN = 3.3V -GND = GND -SDA = A4 (or SDA) -SCL = A5 (or SCL) -INT = Not connected

Trouble Shooting:

Make sure to solder jumper on 3V3 side. if you forget this, I2C does not work and can not find MAX30102. says "MAX30102 was not found. Please check wiring/power."

*/

#include <Wire.h>
#include "MAX30105.h" //sparkfun MAX3010X library
#include <Adafruit_MLX90614.h>

bool status; 
Adafruit_MLX90614 mlx = Adafruit_MLX90614(0x5A);
MAX30105 particleSensor;
TwoWire I2CBME = TwoWire(0);
//#define MAX30105 //if you have Sparkfun's MAX30105 breakout board , try #define MAX30105 

#define USEFIFO
#define I2C_SDA 33  //21
#define I2C_SCL 32  //22

void setup()
{
 // Serial.begin(9600);

  Serial.begin(115200);
  I2CBME.begin(I2C_SDA, I2C_SCL, I2C_SPEED_FAST);
 // Serial.println("mlx start Initializing...");

//status = mlx.begin();  
  Serial.print(status) ;
 // mlx.begin();
  mlx.begin();
 // Serial.println("mls end Initializing...");

 // Serial.println("max start Initializing...") ;

  // Initialize sensor
  //if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
  if (!particleSensor.begin(I2CBME, I2C_SPEED_FAST ,0x57)) //Use default I2C port, 400kHz speed
  {
  //  Serial.println("MAX30102 was not found. Please check wiring/power/solder jumper at MH-ET LIVE MAX30102 board. ");
  //  while (1);
  }

  //Setup to sense a nice looking saw tooth on the plotter
  byte ledBrightness = 0x7F; //Options: 0=Off to 255=50mA
  byte sampleAverage = 4; //Options: 1, 2, 4, 8, 16, 32
  byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
  //Options: 1 = IR only, 2 = Red + IR on MH-ET LIVE MAX30102 board
  int sampleRate = 200; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
  int pulseWidth = 411; //Options: 69, 118, 215, 411
  int adcRange = 16384; //Options: 2048, 4096, 8192, 16384
  // Set up the wanted parameters
  particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
}
double avered = 0; double aveir = 0;
double sumirrms = 0;
double sumredrms = 0;
int i = 0;
int Num = 100;//calculate SpO2 by this sampling interval

double ESpO2 = 95.0;//initial value of estimated SpO2
double FSpO2 = 0.7; //filter factor for estimated SpO2
double frate = 0.95; //low pass filter for IR/red LED value to eliminate AC component
#define TIMETOBOOT 3000 // wait for this time(msec) to output SpO2
#define SCALE 88.0 //adjust to display heart beat and SpO2 in the same scale
#define SAMPLING 5 //if you want to see heart beat more precisely , set SAMPLING to 1
#define FINGER_ON 30000 // if red signal is lower than this , it indicates your finger is not on the sensor
#define MINIMUM_SPO2 80.0

void loop()
{
  Serial.print("status is mlx " + status) ;
  Serial.println("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");

  uint32_t ir, red , green;
  double fred, fir;
  double SpO2 = 0; //raw SpO2 before low pass filtered

#ifdef USEFIFO
  particleSensor.check(); //Check the sensor, read up to 3 samples

  while (particleSensor.available()) {//do we have new data
#ifdef MAX30105
   red = particleSensor.getFIFORed(); //Sparkfun's MAX30105
    ir = particleSensor.getFIFOIR();  //Sparkfun's MAX30105
#else
    red = particleSensor.getFIFOIR(); //why getFOFOIR output Red data by MAX30102 on MH-ET LIVE breakout board
    ir = particleSensor.getFIFORed(); //why getFIFORed output IR data by MAX30102 on MH-ET LIVE breakout board
#endif
    i++;

    mlx.begin();
    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(1000);

    fred = (double)red;
    fir = (double)ir;
    avered = avered * frate + (double)red * (1.0 - frate);//average red level by low pass filter
    aveir = aveir * frate + (double)ir * (1.0 - frate); //average IR level by low pass filter
    sumredrms += (fred - avered) * (fred - avered); //square sum of alternate component of red level
    sumirrms += (fir - aveir) * (fir - aveir);//square sum of alternate component of IR level
    if ((i % SAMPLING) == 0) {//slow down graph plotting speed for arduino Serial plotter by thin out
      if ( millis() > TIMETOBOOT) {
        float ir_forGraph = (2.0 * fir - aveir) / aveir * SCALE;
        float red_forGraph = (2.0 * fred - avered) / avered * SCALE;
        //trancation for Serial plotter's autoscaling
        if ( ir_forGraph > 100.0) ir_forGraph = 100.0;
        if ( ir_forGraph < 80.0) ir_forGraph = 80.0;
        if ( red_forGraph > 100.0 ) red_forGraph = 100.0;
        if ( red_forGraph < 80.0 ) red_forGraph = 80.0;
        //        Serial.print(red); Serial.print(","); Serial.print(ir);Serial.print(".");
        if (ir < FINGER_ON) ESpO2 = MINIMUM_SPO2; //indicator for finger detached
        Serial.print(ir_forGraph); // to display pulse wave at the same time with SpO2 data
        Serial.print(","); Serial.print(red_forGraph); // to display pulse wave at the same time with SpO2 data
        Serial.print(",");
        Serial.print(ESpO2); //low pass filtered SpO2
        Serial.print(","); Serial.print(85.0); //reference SpO2 line
        Serial.print(","); Serial.print(90.0); //warning SpO2 line
        Serial.print(","); Serial.print(95.0); //safe SpO2 line
        Serial.print(","); Serial.println(100.0); //max SpO2 line
        delay(3000);

      }
    }
    if ((i % Num) == 0) {
      double R = (sqrt(sumredrms) / avered) / (sqrt(sumirrms) / aveir);
      // Serial.println(R);
      SpO2 = -23.3 * (R - 0.4) + 100; //http://ww1.microchip.com/downloads/jp/AppNotes/00001525B_JP.pdf
      ESpO2 = FSpO2 * ESpO2 + (1.0 - FSpO2) * SpO2;//low pass filter
      //  Serial.print(SpO2);Serial.print(",");Serial.println(ESpO2);
      sumredrms = 0.0; sumirrms = 0.0; i = 0;
      break;
    }
    particleSensor.nextSample(); //We're finished with this sample so move to next sample
    //Serial.println(SpO2);
  }
#else

  while (1) {//do we have new data
#ifdef MAX30105
   red = particleSensor.getRed();  //Sparkfun's MAX30105
    ir = particleSensor.getIR();  //Sparkfun's MAX30105
#else
    red = particleSensor.getIR(); //why getFOFOIR outputs Red data by MAX30102 on MH-ET LIVE breakout board
    ir = particleSensor.getRed(); //why getFIFORed outputs IR data by MAX30102 on MH-ET LIVE breakout board
#endif
    i++;
    fred = (double)red;
    fir = (double)ir;
    avered = avered * frate + (double)red * (1.0 - frate);//average red level by low pass filter
    aveir = aveir * frate + (double)ir * (1.0 - frate); //average IR level by low pass filter
    sumredrms += (fred - avered) * (fred - avered); //square sum of alternate component of red level
    sumirrms += (fir - aveir) * (fir - aveir);//square sum of alternate component of IR level
    if ((i % SAMPLING) == 0) {//slow down graph plotting speed for arduino IDE toos menu by thin out
      //#if 0
      if ( millis() > TIMETOBOOT) {
        float ir_forGraph = (2.0 * fir - aveir) / aveir * SCALE;
        float red_forGraph = (2.0 * fred - avered) / avered * SCALE;
        //trancation for Serial plotter's autoscaling
        if ( ir_forGraph > 100.0) ir_forGraph = 100.0;
        if ( ir_forGraph < 80.0) ir_forGraph = 80.0;
        if ( red_forGraph > 100.0 ) red_forGraph = 100.0;
        if ( red_forGraph < 80.0 ) red_forGraph = 80.0;
        //        Serial.print(red); Serial.print(","); Serial.print(ir);Serial.print(".");
        if (ir < FINGER_ON) ESpO2 = MINIMUM_SPO2; //indicator for finger detached
        Serial.print((2.0 * fir - aveir) / aveir * SCALE); // to display pulse wave at the same time with SpO2 data
        Serial.print(","); Serial.print((2.0 * fred - avered) / avered * SCALE); // to display pulse wave at the same time with SpO2 data
        Serial.print(","); Serial.print(ESpO2); //low pass filtered SpO2
        Serial.print(","); Serial.print(85.0); //
        Serial.print(","); Serial.print(90.0); //warning SpO2 line
        Serial.print(","); Serial.print(95.0); //safe SpO2 line
        Serial.print(","); Serial.println(100.0); //max SpO2 line
        //#endif

        Serial.println();
        delay(1000);

      }
    }
    if ((i % Num) == 0) {
      double R = (sqrt(sumredrms) / avered) / (sqrt(sumirrms) / aveir);
      // Serial.println(R);
      SpO2 = -23.3 * (R - 0.4) + 100; //http://ww1.microchip.com/downloads/jp/AppNotes/00001525B_JP.pdf
      ESpO2 = FSpO2 * ESpO2 + (1.0 - FSpO2) * SpO2;
      //  Serial.print(SpO2);Serial.print(",");Serial.println(ESpO2);
      sumredrms = 0.0; sumirrms = 0.0; i = 0;
      break;
    }
    particleSensor.nextSample(); //We're finished with this sample so move to next sample
    //Serial.println(SpO2);
  }
#endif
}
me-no-dev commented 3 years ago

long post but no logs or good explanation of what "it didn't work" means.

Enable debug, collect logs and screenshots and post a good explanation of the problem.

stale[bot] commented 3 years ago

[STALE_SET] This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. Thank you for your contributions.

stale[bot] commented 3 years ago

[STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions.

stale[bot] commented 3 years ago

[STALE_CLR] This issue has been removed from the stale queue. Please ensure activity to keep it openin the future.

SuGlider commented 3 years ago

Arduino Core 2.0.0 and PR #5664 may solve this issue. Please test it and let me know. Thanks.

me-no-dev commented 3 years ago

closed by https://github.com/espressif/arduino-esp32/pull/5683