Maja - Blutzucker Überwachungssystem für den Schreibtisch

Aus HRW FabLab MediaWiki
Wechseln zu: Navigation, Suche
Maja - Blutzucker Überwachungssystem für den Schreibtisch
Logo von Maja

Entwickler

Fabian Märkert, Dominic Mause, Marvin Püthe

3D Modelle

Thingiverse


Quellcode

GitHub

Verwendete Programmiersprache

Arduino C/C++

Eingesetzte Software

Arduino IDE, Autodesk Fusion 360 , Fritzing, Cura

Werkzeuge

Ultimaker 2+, Lötstation

Hardware

2 ESP32, NFC-Modul PN532, 4 RGB-LEDs, 18650 3,6V 9,0Wh Lithium Batterie und Konverter, 4 Taster, 1 Pieper, 12 Widerstände (100 Ohm)

Motivation[Bearbeiten]

Bis jetzt müssen Menschen mit Diabetes ihre Sensoren, welche den Blutzuckerwert messen, von Hand mit einem Lesegerät oder einer Smartphone-Applikation auslesen. Dadurch ist der Nutzer ständig gezwungen den Blutzuckerwert von Hand abzurufen und im Auge zu behalten. Kinder und Menschen mit Beeinträchtigungen sind möglicherweise nicht in der Lage die Werte zu interpretieren und daraus Rückschlüsse zu ziehen.
Durch Maja wird der Wert kontinuierlich überwacht und der Zustand durch LEDs signalisiert. Kindern und Menschen mit Beeinträchtigungen kann das Thema Diabetes dadurch leichter vermittelt werden und sie werden dadurch aktiv in die Behandlung eingebunden.

Projektbeschreibung[Bearbeiten]

Plakat von Maja

Unser Produkt liest, mithilfe von einer Vorrichtung am Arm, aus einem vorhandenen proprietären Sensor (Freestyle Libre Sensor) Blutzuckerwerte aus und sendet diese per Bluetooth an Maja. Maja ist eine Schildkröte, welche auf den Schreibtisch des Nutzers gestellt werden kann. Maja signalisiert dem Nutzer durch das Leuchten in verschiedenen Farben und das Abspielen von Tönen den aktuellen Zustand des Blutzuckerwertes.

Maja Orange.jpg

Maja Rot.jpeg

Renderbilder[Bearbeiten]

Maja Rendering Vorderansicht.pngMaja Rendering Seitenansicht.pngMaja Rendering Schale Draufsicht.pngMaja Rendering Schräsicht.png

Aufbau der Module[Bearbeiten]

Aufbau von Maja[Bearbeiten]

Gehäuse[Bearbeiten]

Maja Erster Prototyp.jpg

Das Gehäuse von Maja besteht aus drei Komponenten, welche mit PLA auf einem Ultimaker 2+ gedruckt wurden. Dem Körper, Technikring und dem Panzer.
Maja Rendering Schräge Vorderansicht.pngMaja Technikring.pngMaja Panzer.png
Der Körper beinhaltet den ESP32, welcher mit den LEDs und den Tastern am Technikring verbunden ist. Der Technikring wird an den Körper festgeklebt, wodurch die Komponenten miteinander verbunden sind.
Der Technikring hat Aussparungen, um den Panzer von Maja einzudrehen und dadurch zu fixieren. Dabei wurde 1 mm Platz zwischen den beiden Komponenten gelassen, damit der Panzer von Maja eingedrückt werden und dadurch nach oben und unten federn kann. Der Panzer wurde mit weißem ABS so dünn gedruckt, dass die LEDs durchscheinen können.

Elektronik[Bearbeiten]

Maja Elektronik Breadboard.jpg
Die Grundlage und somit auch die Intelligenz bildet ein ESP32. An diesen sind drei RGB-LEDs, zwei Taster und ein Pieper angeschlossen. Vor den RGB-LEDs sind jeweils drei 100 Ω Widerstände angeschlossen.
Die Taster sind parallel angeschlossen. Wird der Panzer nach unten gedrückt, wird der Schaltkreis geschlossen und der ESP32 kann dies über einen digitalen Eingang erkennen. Der Pieper wurde an einen digitalen Ausgang angeschlossen.

Aufbau des Armsensors[Bearbeiten]

Maja Armhalterung in Action.jpg

Gehäuse[Bearbeiten]

Maja Armhalterung mit Batterie.jpg
Das Gehäuse hat eine Breite von 8cm, um genügend Platz für den ESP32, das NFC-Lesegerät und eine Lithium-Ionen-Batterie zu bieten. An den seitlichen Kanten sind Aussparungen zur Befestigung eines Klett-Armbands vorhanden.

Elektronik[Bearbeiten]

Maja NFC Sensor.jpg
Das NFC-Lesegerät ist nach Herstellerangaben angeschlossen.
Die Stromversorgung des ESP32 wird durch eine Lithium-Ionen-Batterie bewerkstelligt. Diese kann z.B. aus dem Gehäuse einer Power-Bank ausgebaut werden. Dies bietet den Vorteil, dass bereits ein Spannungswandler mit USB-Anschluss angeschlossen ist und die Batterie mit dem Micro-USB-Anschluss wieder aufgeladen werden kann. Der ESP32 wird dann nur noch mit einem Micro-USB Kabel angeschlossen und durch die Batterie geladen.

Quellcode[Bearbeiten]

Datenstruktur für Glucose und Puffer[Bearbeiten]

Die Struktur zum Speichern der Daten besteht aus einem 2-Byte Zeitstempel und einem 2-Byte Integer, welcher den Glukosewert beinhaltet. Dies ist notwendig, da Werte größer als 255 erreicht werden.

struct glucoseData{
 uint16_t timestamp;
 uint16_t value;
};

Maja hat einen Puffer (Ring-Speicher) für 300 Glukosewerte. Das heißt sie speichert die Glukosewerte der letzten 5 Stunden im Arbeitsspeicher. Ist der Puffer voll, werden die Daten überschrieben. Eine Speicherung findet nicht statt.

int bufferSize=300;
glucoseData* buffer=new glucoseData[bufferSize];
int bufferPosition=0;
int bufferedElements=0;
static bool newData=false; //Static for the acces from another Thread 

Ein Bluetooth Characteristic kann insgesamt 600 Byte puffern. 4 Byte dafür werden für die Anzahl an übertragenen Glukosewerten verwendet. Daher bleiben noch 596 Byte zur Nutzung übrig. Die Anzahl der möglichen Werte wird durch die Größe der Datenstruktur ermittelt.

Bluetooth Low Energy Verbindung[Bearbeiten]

Die Bluetooth Low Energy Verbindung wird durch Maja initiiert. Maja scannt die gesamte Umgebung nach Bluetooth-Geräten und geht diese der Reihe nach durch. Wenn sie den Armsensor gefunden hat, baut sie eine Verbindung auf. Dieses Vorgehen geschieht in der Funktion isConnected.

if(connected){
 if(pClient->isConnected()){
  return true;
 } else {
  Serial.println("BLE Connection Lost!"); 
  pClient->disconnect();
  setColor(0, 0, 255);
  connected=false;
 }
}
if(!doConnect){
 if(pBLEScan==nullptr){
  pBLEScan = BLEDevice::getScan(); 
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);
 }
pBLEScan->start(30);

Bluetooth Versand und Empfang[Bearbeiten]

Das Austauschen der Daten geschieht über BLE Characteristics.

Der Armsensor fügt neue Daten zu seinem Puffer hinzu und kopiert diesen dann in die BLE Characteristic. Ruft nun Maja diese Daten ab, wird ein Callback ausgelöst und der Puffer wird geleert.

void addData(glucoseData data){
 //Writing into the buffer
 buffer[bufferPosition]=data;
 bufferPosition=(bufferPosition+1)%bufferSize;
 bufferedElements++;
 //Copying the buffered data into the BLE Characteristic
 uint32_t* bytes=new uint32_t[bufferedElements+1];
 bytes[0]=bufferedElements;
 int position=bufferPosition-1;  
 for(int i=0;i<bufferedElements;i++){
   uint32_t* ptr=(uint32_t*) &(buffer[position]);
   bytes[i+1]=*ptr;
   position--;
   if(position<0){
     position=bufferSize-1;
   }
 }
 uint8_t* msg=(uint8_t*) bytes;
 pCharacteristic->setValue(msg, bufferedElements*4+4);
 
 Serial.print("Data set. Size: ");
 Serial.println(pCharacteristic->getValue().size());
 pCharacteristic->notify();
}
class CustomCharacteristicsCallback: public BLECharacteristicCallbacks {
 void onRead(BLECharacteristic *pCharacteristic){
   bufferedElements=0;
   bufferPosition=0;
 }
 void onWrite(BLECharacteristic *pCharacteristic){}
};


Maja ruft die Daten von dem Sensor ab, decodiert diese und speichert diese in ihrem Ringspeicher.

void readDataIntoBuffer(){
 newData=false;
 std::string s=pRemoteCharacteristic->readValue();
 uint32_t* ptr=(uint32_t*) s.c_str();
 int numData=*ptr;
 for(int i=0;i<numData ;i++){
   glucoseData data;
   uint32_t* dataptr=(uint32_t*) &data;
   *dataptr=(uint32_t) ptr[i+1];
     
   buffer[bufferPosition]=data;
   bufferPosition=(bufferPosition+1)%bufferSize;
   if(bufferedElements<bufferSize){
     bufferedElements++;
   }
   Serial.println("Data read: ");
   Serial.print("Timestamp: ");
   Serial.println(data.timestamp);
   Serial.print("Value: ");
   Serial.println(data.value);
   Serial.println("");
 }

}

Glucose-Algorithmus[Bearbeiten]

Da die ausgelesenen Sensordaten nicht den realen Glukosewerten entsprechen, müssen diese vorher noch umgerechnet und die Temperaturabhängigkeit des Sensors beachtet werden. Der Algorithmus ist hier erklärt: https://github.com/UPetersen/LibreMonitor/wiki/Libre-OOP-Investigation

uint16_t calculateGlucose(uint8_t* data){
 Serial.println("Calculating Glucose:");
 
 int rawGlucose = data[0] + ((data[1] & 63) << 8);
 int rawTemperature = data[3] + ((data[4] & 63) << 8);
 
 double slope = (0.000015623 * rawTemperature + 0.0017457);
 double offset = (-0.0002327 * rawTemperature - 19.47);
 
 int glucose = (rawGlucose * slope + offset);
 
 Serial.print("Raw Glucose: ");
 Serial.println(rawGlucose);
 Serial.print("Raw Temperature:");
 Serial.println(rawTemperature);
 Serial.print("Glucose:");
 Serial.println(glucose);
 
 return glucose;
}

Auswertung und Steuerung der RGB-LEDs[Bearbeiten]

Setzt die Farbe je nach gemessenen Glukosewert

void setColorByGlucose(int glucose){
 
 float colorValue = fabs(105-glucose)/35.0f;
 if(colorValue>1){
  colorValue=1;
 }

 byte red = (byte) (255.0f * colorValue);  
 byte green = (byte) (255.0f * (1.0f-colorValue));
 setColor(red, green, 0);
}

In der Funktion setColor wird der ermittelte RGB Code an die verschiedenen LEDs weitergeleitet.

void setColor(byte r, byte g, byte b){
 ledcWrite(ledChannelR1, r);
 ledcWrite(ledChannelR2, r);
 ledcWrite(ledChannelR3, r);

 ledcWrite(ledChannelG1, g);
 ledcWrite(ledChannelG2, g);
 ledcWrite(ledChannelG3, g);

 ledcWrite(ledChannelB1, b);
 ledcWrite(ledChannelB2, b);
 ledcWrite(ledChannelB3, b);
}