MAX30102 zeigt falsche Werte

Hallo,

ich bin gerade am Bau eines Fitnesstrackers mithilfe von zwei Arduino Nanos, einem OLED-Display, einem GPS (u-blox NEO-6M) und einem Pulsoximeter (MAX30102).
Der Tracker funktioniert soweit, aber leider zeigt mir der Sensor mehr falsche als richtige Werte an. Aufgrund der Speicherkapazität habe ich den einen Arduino nur mit dem MAX30102 verbunden. Dieser gibt die Werte auf anfrage vom anderen Arduino weiter und da werden sie dann auf das OLED übertragen.
Kann mir jemand weiterhelfen, wie ich richtige Werte bekomme?

Hier der Code für den Arduino mit dem Pulsoximeter.

#include <Wire.h>
#include "MAX30105.h"
#include "spo2_algorithm.h"

MAX30105 particleSensor;

#define MAX_BRIGHTNESS 255
char buffer[10] = "00000000";

#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
//Arduino Uno doesn't have enough SRAM to store 100 samples of IR led data and red led data in 32-bit format
//To solve this problem, 16-bit MSB of the sampled data will be truncated. Samples become 16-bit data.
uint16_t irBuffer[100]; //infrared LED sensor data
uint16_t redBuffer[100];  //red LED sensor data
#else
uint32_t irBuffer[100]; //infrared LED sensor data
uint32_t redBuffer[100];  //red LED sensor data
#endif

int32_t bufferLength = 100; //data length
int32_t spo2; //SPO2 value
int8_t validSPO2; //indicator to show if the SPO2 calculation is valid
int32_t heartRate; //heart rate value
int8_t validHeartRate; //indicator to show if the heart rate calculation is valid

void setup()
{
  Serial.begin(115200); // initialize serial communication at 115200 bits per second:
  for(int x=0;x<100;x++){
    redBuffer[x]=0;
    irBuffer[x]=0;
  }


  // Initialize sensor
  particleSensor.begin(Wire, I2C_SPEED_FAST);
  //if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed


  byte ledBrightness = 60; //Options: 0=Off to 255=50mA
  byte sampleAverage = 4; //Options: 1, 2, 4, 8, 16, 32
  byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
  byte sampleRate = 100; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
  int pulseWidth = 411; //Options: 69, 118, 215, 411
  int adcRange = 4096; //Options: 2048, 4096, 8192, 16384

  particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
}

void loop()
{
 
  //calculate heart rate and SpO2 after first 100 samples (first 4 seconds of samples)
  maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
//*/
  

    //dumping the first 25 sets of samples in the memory and shift the last 75 sets of samples to the top
    for (byte i = 25; i < 100; i++)
    {
      redBuffer[i - 25] = redBuffer[i];
      irBuffer[i - 25] = irBuffer[i];
    }

    //take 25 sets of samples before calculating the heart rate.
    for (byte i = 75; i < 100; i++)
    {
      while (particleSensor.available() == false) //do we have new data?
        particleSensor.check(); //Check the sensor for new data


      redBuffer[i] = particleSensor.getRed();
      irBuffer[i] = particleSensor.getIR();
      particleSensor.nextSample(); //We're finished with this sample so move to next sample
      if(Serial.available()>1){
      //if(true){
        Serial.read();
        Serial.read();
        sprintf(buffer, "%4d", heartRate);
        Serial.print(buffer);
        sprintf(buffer, "%4d", spo2);  
        Serial.println(buffer);   
      }
     
    }

    //After gathering 25 new samples recalculate HR and SP02
    maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
  //}
}

Code von Arduino mit GPS und OLED:

#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);
//---------------------------------------------------------------------------
#include <SoftwareSerial.h>
#include <Wire.h>
#include <TinyGPS++.h> //1.0.3

#define rxPin 2
#define txPin 5 //unused


SoftwareSerial neogps(rxPin,txPin);


TinyGPSPlus gps;

//---------------------------------------------------------------------------
u8g_uint_t xx  = 0;
//---------------------------------------------------------------------------
//Program variables
int day, month, year;
String hour, minute;
int second;
int num_sat;
int speed;
int average_beat;
int SpO2;

char buffer [20] = "00000000";
//String buffer = "00000000";

unsigned long int timeNow = 0;
unsigned long int timePast = 0;
  
/*******************************************************************************************
 * gauge function
 * dispay gauge and other gps data on oled
*******************************************************************************************/
void gauge(uint8_t angle) {
  //fonts: u8g_font_chikita - u8g_font_04b_03br
  // u8g_font_orgv01 - u8g_font_freedoomr10r
  u8g.setFont(u8g_font_chikita);
  //---------------------------------------------------------------------------
  //GESCHWINDIGKEIT
  u8g.setFont(u8g_font_chikita);
  u8g.setPrintPos(20,6);
  u8g.print("km/h");
  u8g.setPrintPos(5,6);
  u8g.print(speed);
  //---------------------------------------------------------------------------
  //SATELLITENEMPFANG
  u8g.setFont(u8g_font_chikita);
  u8g.setPrintPos(95,6);
  u8g.print("Sat:");
  u8g.setPrintPos(115,6);
  u8g.print(num_sat, 5);
  //---------------------------------------------------------------------------
  //DISTANCE
 // u8g.setPrintPos(18,5);
  //u8g.print("km");
  //---------------------------------------------------------------------------
  //UHRZEIT
  u8g.setFont(u8g_font_chikita);
  u8g.setPrintPos(100, 59);
  u8g.print(hour);
  
  if(second%2 == 0) 
    {u8g.drawStr(105, 59, ":");}
  else
    {u8g.drawStr(105, 59, " ");}
    
  u8g.setPrintPos(110, 59);
  u8g.print(minute);
  
  //u8g.drawStr(90, 65, "00:00");
  //---------------------------------------------------------------------------
  //DATUM
  u8g.setFont(u8g_font_chikita);
  u8g.setPrintPos(10,59);
  u8g.print(day);
  u8g.setPrintPos(15,59);
  u8g.print(".");
  u8g.setPrintPos(20,59);
  u8g.print(month);
  u8g.setPrintPos(25,59);
  u8g.print(".");
  u8g.setPrintPos(30,59);
  u8g.print(year);
  //---------------------------------------------------------------------------
  //HERZFREQUENZ
  u8g.setFont(u8g_font_tpssb);
  u8g.setPrintPos(40,24);
  u8g.print(average_beat);
  u8g.setPrintPos(65,24);
  u8g.print("bpm");
  //---------------------------------------------------------------------------
  //BLOOD OXYGEN
  u8g.setFont(u8g_font_chikita);
  u8g.setPrintPos(51,45);
  u8g.print("2");
  u8g.setFont(u8g_font_tpssb);
  u8g.setPrintPos(30,43);
  u8g.print("SpO");
  u8g.setPrintPos(60,43);
  u8g.print(SpO2);
  u8g.setPrintPos(82,43);
  u8g.print("%");
  //---------------------------------------------------------------------------
}

/*******************************************************************************************
 * gauge function
 * dispay gauge and other gps data on oled
*******************************************************************************************/
int i = 200;
void setup(void) {
  Serial.begin(115200);
 

  neogps.begin(9600);
  
  u8g.setFont(u8g_font_chikita);
  u8g.setColorIndex(1);
}

/*******************************************************************************************
 * gauge function
 * dispay gauge and other gps data on oled
*******************************************************************************************/
void loop(void){
  //----------------------------------------------------------
  Read_GPS();
  Read_Pulsoximeter();

  //----------------------------------------------------------
  //Display Data on Oled
  {
    u8g.firstPage(); 
    do {             
      gauge(xx);
    }
    while( u8g.nextPage() );
  }
  //----------------------------------------------------------
}




void Read_GPS(){
  //------------------------------------------------------------------
  boolean newData = false;
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (neogps.available())
    {
      if (gps.encode(neogps.read()))
      {
        newData = true;
        break;
      }
    }
  }
  //------------------------------------------------------------------
  //If newData is true
  if(newData == true){
    newData = false;
    Get_GPS();
  }
  else { 
    //no data
  }
}

void Get_GPS(){
  num_sat = gps.satellites.value();

  if (gps.location.isValid() == 1) {
    speed = gps.speed.kmph();
    //Serial.print("Speed: ");Serial.println(gps_speed);

  }
  
  if (gps.time.isValid()){
    hour = String(gps.time.hour());
    hour = (hour.length() == 1) ? "0"+hour : hour;
    
    minute = String(gps.time.minute());
    minute= (minute.length() == 1) ? "0"+minute : minute;
    
    second = gps.time.second();
  }
}

//------------------------------------------------------------------

void Read_Pulsoximeter(){
timeNow = millis();
  if((timeNow - timePast) > 1000)
  {
    Serial.print("?");
  }
  if(Serial.available())
  {
    readline(Serial.read(), buffer, 20);
    //Serial.println(buffer);
    average_beat = CharArrToInt(buffer[1], buffer[2], buffer [3]);
    SpO2 = CharArrToInt(buffer[5], buffer[6], buffer [7]);
  }
}

int readline(int readch, char *buffer, int len)
{
  static int pos = 0;
  int rpos;

  if (readch > 0) {
    switch (readch) {
      case '\n': // Ignore new-lines
        break;
      case '\r': // Return on CR
        rpos = pos;
        pos = 0;  // Reset position index ready for next time
        return rpos;
      default:
        if (pos < len-1) {
          buffer[pos++] = readch;
          buffer[pos] = 0;
        }
    }
  }
  // No end of line has been found, so return -1.
  return -1;
}

int CharArrToInt(char one, char two, char three){
  int number= 0;
  if(one<0x30 || one >0x39)one=0x30;
  if(two<0x30 || two >0x39)two=0x30;
  if(three<0x30 || three >0x39)three=0x30;
  number = (one-0x30)*100+(two-0x30)*10+(three-0x30);
  return number;
}

Würden Sie die "schlechten" Werte aus dem Debug-Monitor (Text) oder Liniendiagramm (Bild) und Ihre erwarteten "guten" Werte anzeigen?

Ich habe gestern nochmal ein bisschen was am Code verändert und bekomme jetzt nurnoch Durchschnittswerte angezeigt. Davor bekam ich aber beispielsweise bei der Herzfrequenz den Wert -999 (kein Messergebnis) oder einen Wert ca. zwischen 1 und 300 bpm.
Die Ruheherzfrequenz eines Erwachsenen liegt bei 70 - 75 bpm.

Würde ich schon hoch ansehen. Wer sich irgendwie sportlich betätigt hat einen tieferen Ruhepuls.

Grüße Uwe

Verhält sich jeder Sensor wie ein einzelner Sensor? Wenn ja, prüfen Sie die gemeinsame Masse für beide Sensoren.

Ist der Lötjumper auf der Rückseite des Boards mit 3.3V geschlossen?

Die Sensoren messen beide über das gleiche Infrarot. Meinst du das?

Ja, der ist angeschlossen. Ich habe auch das gleiche Modell vom gleichen Hersteller und von einem anderen Hersteller. Aber ich bekomme bei keinem ein treffendes Messergebnis.

Der Sinn meiner Frage war; Wenn ein Sensor unregelmäßig, der andere jedoch stabil ist, überprüfen Sie vielleicht, ob die Erdung des unregelmäßigen Sensors dieselbe Erdung wie die des stabilen Sensors ist.

Ah okay. Leider geben beide unregelmäßige Werte ab. Teilweise gleichzeitig, teilweise nur einer.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.