Navn på wearable: “Ret Ryggen”

Gruppemedlemmer: Bjarke, Sacha, Kenza og Martin

IMAG1080 IMAG1083 IMAG1085

Video

Case

Efter en lille række af forskellige idéer til en wearable, kom vi frem til at løse et meget typisk sundhedsskadeligt problem. Vores case er en wearable der sættes på tøjet, placeret øverst på brystkassen, som har formålet at måle hvorledes du sidder med rettet ryg eller i en usund bøjet stilling. Det skulle gerne forbedre personens positur, ryg-, skulder- og nakkekondition, vejrtrækning, deres mentale sundhed samt mange andre sundhedsskadelige faktorer.

Dette er rettet mod alle som sidder i længere tid og efterhånden får en dårlig rygstilling. Det kan ske i mange situationer, såsom når man sidder og arbejder på kontoret, sidder og venter på en bus, sidder og spiller computer/konsol osv.

Det fysiske arbejde er derfor at opretholde en sund og rettet siddestilling, i stedet for at sidde i en dårlig og usund stilling som skader sind og krop.

Lignende Wearables

Vi har taget inspiration fra en lignende wearable kaldet Lumo Lift.

Lumo Lift er et lille, kompakt og mobilt apparat, som bæres på trøjen over brystet. Lumo Lift måler din daglige aktivitet og positur, og ved brug af iOS eller Android kan man tracke sin fysiske data.
Lumo Lift har en skridttæller, der måler hvor mange kalorier du brænder og hvor længe du sidder med rettet ryg. Hvis man sidder i en dårlig eller usund stilling, kan apparatet også sende vibrerende feedbacks til brugeren.

I forhold til en tidligere model kaldet Lumo Back, er denne model lille, kompakt og mobil. Lumo Lift har også flere funktioner. Lumo Back er et større bælte som holder øje med din ryg-stilling, ligesom Lumo Lift. Dog har Lumo Back en mere kraftig feedback, hvor Lumo Lift har et mere diskret feedback.

http://www.lumobodytech.com/

Video: https://www.youtube.com/watch?v=igQIMArIXNw

Andre lignende Wearables:
http://www.informationweek.com/mobile/10-wearable-devices-to-keep-patients-healthy/d/d-id/1104359

Design

Vores wearable virker således, at et 9-aksel gyroskop måler om personen sidder med den rette stilling. Accelerometeret er sat fast på brystet af brugeren. Sidder personen i en usund stilling, vil buzzeren udgive en høj tone efter et delay. Vi har valgt at tage en sundhedsmæssig problemstilling op, da om vi sidder med rettet ryg eller ej, påvirker os personligt i dagligdagen.

Ved hjælp af accelerometeret, måler vi hvorledes personen sidder rettet eller foroverbøjet. Med rettet ryg, overskrider accelerometeret ikke grænsen på Y-aksen, og derfor reagerer Buzzeren ikke. Læser accelerometeret at personen sidder bøjet over den grænse, som vi manuelt lægger ind afhængig af person, vil den sættes i et loop og efter et delay give signal til buzzeren om at afgive feedback. Man kan selvfølgelig bruge Flex Sensor, ved at sætte denne på ryggen og derfor måle hvor meget ryggen bøjer sig, dog har vi valgt accelerometeret fremfor for flex sensor, da vi gerne vil have et mindre besværligt wearable at have at gøre med. Noget der let kan sættes på tøjet til burgerens fordel.

Feedback typen vi har valgt, er en bippende lyd, da personen altid ville kunne lægge mærke til den, og derfor rette sig efter feedbacket. Et andet feedback vi bruger er visuelt som vises vha. Processing. Der bruges også en SilverMate Bluetooth enhed, som skal afsende data fra vores wearable til den tilsluttede computer. Dataindholdet er følgende:

  • Hvor mange gange buzzeren har lydt.
  • Procenterne ude af balance.
  • Procenterne i balance.

processing_in_use

Hardware

blahblah2

 

blahblah3

Igennem arbejdet med vores wearable havde vi to forskellige problemer med vores hardware. I første omgang var det med LSM9SD0, hvor vi ikke kunne få oprettet en I2C forbindelse med modulet, og når vi prøvede med en SPI forbindelse fik vi kun 0 eller -1 ud som data på de akser vi forsøgte at undersøge. Problemet forsvandt efter at vi loddede hanstik ordentligt på modulet.

Her ud over havde vi problemer med at få vores HID bluetooth til at virke, vi fik hele tiden en fejlmeddelelse der sagde, at den aktuelle COM port var optaget og der derfor ikke kunne oprettes forbindelse. Vi testede herefter med en anden gruppes kode og hardware og fandt frem til at det var vores modul der måtte være en fejl med. Vi skiftede derefter til en SilverMate og det løste problemet.

Arduino

blahblah4

Vores Arduino kode er opdelt i et setup(), hvor vi initialiserer både LSM9SD0 og bluetooth og et loop(), hvor vi kalder to metoder; en som læser og tjekker accelerometeret og kalder andre metoder, hvis de målte værdier er “ude a balance”, samt en metode der sender data fra arduinoen via bluetooth.

Da vi laver vores tidsberegning baseret på millis(), har vi helgraderet os og bruger hovedsageligt data typen unsigned long for at kunne holde på meget store tal (den ville kunne tælle i ca. 50 dage uafbrudt).

checkAccel(), den første af de to metoder i loopet, er en simpel if-statement. Først læser den værdien på y-aksen og efter tjekker den om værdien er over eller under den grænse vi har sat på forhånd. Hvis den er OK, så gør metoden ikke mere og loopet går videre til sendData(). Skulle den derimod måle, at værdien ikke er OK, så noterer den tidspunktet for hvornår man er kommet for langt frem og gemmer det til senere, hvorefter den kalder alarmDelay().

For at give brugeren en mulighed for selv at rette sin rygholdning eller for at imødekomme at personen fx bare samler noget op fra gulvet, har vi valgt at inkludere et ca. 10 sekunder langt delay. I praksis kunne det godt være det skulle være tættere på 30s.  Delayet, alarmDelay(), tjekker konstant i de 10s om man skulle rette sig op igen. Hvis man kommer tilbage i en ret position afblæses alarmen og tiden man har været bukket udregnes ud fra det tidspunkt checkAccel() noterede. Herefter lægges den tid til den samlede tid ude af balance.  Skulle brugeren derimod ikke selv rette sin position inden de 10s er omme, vil den starte buzzeren, og sende 15 små bib til brugeren. Rettes positionen under alarmen vil den stoppe, og igen udregnes for hvor lang tid brugeren har været ude af balance.

Herefter sendes dataen ud via bluetooth modulet og sendData(). For at lægge mindre pres på processing senere, laves første udregning i arduino. Derfor laver sendData() først en omregning på tiden ude af balance, og holder den op imod den samlede tid for at finde procenterne i og ude af balance. Værdierne konverteres fra unsigned long til strings (via et char array) der herefter sendes afsted via bluetooth.

// The SFE_LSM9DS0 requires both the SPI and Wire libraries.
// Unfortunately, you'll need to include both in the Arduino
// sketch, before including the SFE_LSM9DS0 library.
#include <SPI.h> // Included for SFE_LSM9DS0 library
#include <Wire.h>
#include <SFE_LSM9DS0.h>

// SDO_XM and SDO_G are both grounded, so our addresses are:
#define LSM9DS0_XM  0x1D // Would be 0x1E if SDO_XM is LOW
#define LSM9DS0_G   0x6B // Would be 0x6A if SDO_G is LOW

// Create an instance of the LSM9DS0 library called `dof` the
// parameters for this constructor are:
// [SPI or I2C Mode declaration],[gyro I2C address],[xm I2C add.]
LSM9DS0 dof(MODE_I2C, LSM9DS0_G, LSM9DS0_XM);

//Bluetooth library
#include <SoftwareSerial.h>

//Move Rx and Tx from D0+D1 to D2+D3
//This is so the program can run while plugged into the pc
int bluetoothTx = 2;
int bluetoothRx = 3;

SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);

int tiltAngle = 2000; //at what accel value will the alarm go off
/* We have chosen to manually write this number for each individual 
using the wearable. It would be possible to make a more automated
version by including a set-up start where the wearable asks the user 
to help it define these values. First standing with a straight back
while the wearable calculated desired value, then ask the user to 
lean forwards to the point where they would like to be reminded to
straighten their back. By storing these two points for each use(r)
it will be automated. */

int alarmCounter = 0;
unsigned long uptime = 0;
unsigned long totalOutOfBalance = 0;
unsigned long outOfBalance= 0;
unsigned long backInBalance = 0;
unsigned long greenPercent = 0;
unsigned long redPercent =0;

void setup()
{

   Serial.begin(115200); // Start serial at 115200 bps
  // Use the begin() function to initialize the LSM9DS0 library.
  // You can either call it with no parameters (the easy way):
  uint16_t status = dof.begin();

  //initialize bluetooth, then a small delay to give it a chance to respond
  bluetooth.begin(115200);
  delay(100);

  /* UNCOMMENT IF YOU WISH TO PRINT A COM CHECK IN ARDUINO MONITOR
  // WHO_AM_I response. Check communication was successful.
  Serial.print("LSM9DS0 WHO_AM_I's returned: 0x");
  Serial.println(status, HEX);
  Serial.println("Should be 0x49D4");
  Serial.println();
 */
}

void loop(){  
  checkAccel(); // Checks if tiltAngle is too high + COUNT IN+OUT OF BOUND
  sendData(); // Send current data to processing + COUNT OUT OF BOUND
}

void checkAccel(){
  dof.readAccel(); // reading accel data

  //checks if tiltAngle is within bounds, otherwise runs alarmDelay()
  if (dof.ay > tiltAngle) {
    outOfBalance = millis();
    alarmDelay();
  }
}

void alarmDelay(){   

  // Gives the user a ~10sec chance of correcting their posture 
  // before sounding the alarm. We do it this way to continously
  // check the posture, not just at the 0sec and 10sec mark.
  for (int x = 0; x < 4000; x ++){   
    dof.readAccel();  // reading accel data

    if (dof.ay < tiltAngle){      // bail out of loop if posture gets
       x = 0;                     // corrected within 10sec
       backInBalance = millis();
       totalOutOfBalance = totalOutOfBalance + (backInBalance-outOfBalance);
       break;
      }  
  }
   if (dof.ay > tiltAngle){ //posture not corrected, sounds the alarm!      
      alarmCounter ++;

      for (int x = 0; x < 15; x ++){       
      dof.readAccel(); // reading accel data
        if (dof.ay > tiltAngle){      // bail out if posture corrected
          tone(8, 2000, 50); 
          delay(400); 

        } 
      } 
       backInBalance = millis();
       totalOutOfBalance = totalOutOfBalance + (backInBalance-outOfBalance);
   } 
}

void sendData (){
  //Calculates % in balance and out of balance this session
  uptime = millis(); //total time running so far
  redPercent = round(totalOutOfBalance / (uptime/100)); //% out of balance
  greenPercent = 100 - redPercent;

  //converts unsigned long redPercent + greenPercent to readable strings
  char red[50]; 
  char green[50];

  sprintf(red, "%lu", redPercent);
  String redAngle(red);

  sprintf(green, "%lu", greenPercent);
  String greenAngle(green);

  Serial.println(greenAngle + ',' + redAngle + ',' + alarmCounter + ',');  

  //sends combined string of data via BT
  bluetooth.print(greenAngle + ',' + redAngle + ',' + alarmCounter + ',');
  bluetooth.print("\n");
  delay(100);
}

Processing

blahblah5

Processing delen er ligesom arduino delen opdelt i et setup(), hvor vi opsætter vores canvas’ størrelse og baggrund, og hvor vi opretter forbindelse med bluetooth modulet på arduinoen via en seriel COM port forbindelse, samt draw(), hvor vi indlæser data og tegner vores diagram.

I praksis starter koden med at tjekke, om der er kommet nyt data fra bluetooth modulet, hvis ikke tegner programmet vores cirkeldiagram og skriver vores tekst i forhold til de grundværdier vi allerede har givet variablerne. Skulle der være kommet data ind, tjekker koden om det er brugbar data. Er dataen null, gør programmet intet, men hvis der er kommet en forståelig string ind opdeler den det i et string array og konverterer to af værdierne til integers.

Herefter laver den en beregning på hvor mange grader hvert element i cirkeldiagrammet har ud fra de procenter arduino har sendt den, og indsætter så de grader i vores array angles[].

Når dette er gjort tegner programmet på ny vores diagram ved at kalde pieChart() og fodre den med en diameter på 300px og angles[]. pieChart() funktionen i sig selv kører efter et for loop der omregner graderne i angles[] til radianer og tegner dem ind som arcs med samme centrum, men med forskellige start og slut position. Farverne på de forskellige blokke finder den i vores pieColor[] array.

Til sidst skrives der oven på diagrammet hvor mange procent der er målt i og ude af balance, og den skriver også, hvor mange gange alarmen er kørt.

import processing.serial.*; //library
Serial myPort; //constructs an instance called myport
PImage bg; //background image
String sensorReading=""; //prepares string for incoming data
int[] angles = {360, 0, 0}; //prepares piechart array 
String alarmCounter = "";
int redPercent= 0;
int greenPercent= 100;
int redAngle =0;
int greenAngle=0;
int[] pieColor = { #7cc576, #f26d7d, #f4b317}; //colors in the piechart

void setup() {
  size(889,424); //sets up canvas size
  // The background image must be the same size as the parameters
  // into the size() method. In this program, the size of the image
  // is 640 x 360 pixels.
  bg = loadImage("background-image_small.png"); //loads bg image
  noStroke();  //removes strokes from all elements - piechart here

  printArray(Serial.list());    //prints array of available COM ports
  String portName = Serial.list()[2]; //insert chosen COM port in []
  myPort = new Serial(this, portName, 115200); //set baudrate
  myPort.bufferUntil('\n');

}

void draw() {
  background(bg);

  //read bluetooth data, split the string and convert it to numbers 
  if ( myPort.available() > 0) {  // If data is available,
  sensorReading = myPort.readStringUntil('\n');  // read it and store it in val
  println(sensorReading);

    if (sensorReading != null){

       String[] readData = split(sensorReading, ',');
       //printArray(readData);

       alarmCounter = readData[2];
       redPercent=Integer.parseInt(readData[1]);
       greenPercent=Integer.parseInt(readData[0]);

       redAngle = round(redPercent * 3.6);
       greenAngle = 360 - redAngle;
       println("red angle= " + redAngle);
       println("green angle= " + greenAngle);

       angles[0] = greenAngle;
       angles[1] = redAngle;  
       //printArray(angles);
    }
    else {
    println("Data not understood.");
    }
  }
  else {
  println("No new data.");
  }

   pieChart(300, angles);
    fill(222, 255, 255, 250);
    arc(205,230, 270, 270, -1.55, 4.74); // 360 degrees, radian

    textSize(20);
    fill(0, 0, 0);
    textAlign(CENTER);
    text(greenPercent+"% in balance", 205, 215);
    text(redPercent+"% out of balance", 205, 245);

    textSize(120);
    text(alarmCounter, 666, 235);     
}

void pieChart(float diameter, int[] data){ 
  //takes 300 as diameter and turns int[] angles into int[] data

  float lastAngle =0; //variable at 0
  for (int i = 0; i <data.length; i++){
    fill(pieColor[i]);
    arc(205, 230, diameter, diameter, lastAngle - HALF_PI, lastAngle+radians(angles[i]) -HALF_PI);
    // x, y, r, r, start, slut
    lastAngle += radians(angles[i]);
  }
}

Kodeudfordringer

Vi har stødt imod adskillige problemer undervejs i vores kodning, specielt i forbindelse med bluetooth og det at sende data, der kan læses, og med at forbinde den data, der så blev læst med noget grafisk i processing. Nedenfor er de væsentlige udfordringer, som ikke var forbundet med fejl 40 problemer.

  • Processing kunne ikke læse hele strengen fra bluetooth:
    I processing splitter vi strengen op i et string array ved hvert ‘,’ i strengen, men den sidste værdi kom altid ind som “0”. Ved at tilføje et ekstra “,” i slutningen af data-strengen kunne processing godt læse den 3. værdi, til gengæld får vi et ekstra “0” i vores string array, som så ikke bliver brugt til noget.
  • Arduino & processing kunne ikke regne:
    I forbindelse med de udregninger vi har lavet ville ingen af programmerne godkende ” = round(360 * (redPercent/100));” hvor redPercent var en unsigned long i arduino og en int i processing. Vi kom rundt om problemet ved i stedet at skrive ” = round(redPercent * 3.6);”
  • Processing var for langsom:
    Under vores tests kunne vi se at processing ikke kunne håndtere den mængde data som arduinoen kunne udsende, og at den derefter kom længere og længere bagud med at opdatere data. Derfor indlagde vi et delay i arduino delen på 100, hvilket var nok til at processing kunne følge med. Den computer vi kører processing på er heller ikke den hurtigste, vi har testet med en anden computer der kunne følge med allerede ved et delay på 30.
  • Processing klagede over nullPointerException:
    I første omgang havde vi ikke inkluderet kode for hvad processing skulle gøre, hvis den data streng der kom ind ikke kunne læses ordentligt. Vi er ikke klar over hvorfor der til tider så ud til at komme “korrupt” eller null data ind, men ved at inkludere “if (sensorReading != null){}” –> “else{}” omgik vi fejlen.

Konklusion

Rygskader, dårlig selvtillid og andre relaterede helbredsproblemer går hånd i hånd med dårlig siddestilling og positur. Vores wearable har som formål at forbedre disse helbredsproblemer, ved at minde brugeren om at rette ryggen hver gang de sidder i en dårlig eller usund stilling.

Vi kan konkludere at vores wearable løser problemet, da den efter få sekunder med dårlig siddestilling, afgiver hørbar feedback og minder brugeren om at rette ryggen. Når ryggen er rettet, stopper den med at afgive lyd, som resulterer i en bedre siddestilling.

Leave a Reply