Plethandsken

Gruppemedlemmer: Stefan, Juri, Henning og Jakob

Vi ønsker at forbedre brugen af plethandsker i kampsport. Træner og elev skal kunne få en præcis beskrivelse af slagets antal, hårdhed og beskaffenhed. Målet er en plethandske der kan sende brugbare data til din computer eller telefon. Umiddelbart “var” der ikke lignende produkter på markedet så derfor anså vi det som en spændende udfordring!

checkt

  • Grøn ring: Arduino
  • Gul ring: Plethandske
  • Rød ring: FSR sensor
  • Brun ring: Boksehandske

Idegrundlag

Platformen er Arduino hvilket er en microcontroller. Vi har brugt Processing til at styring og aflæsning af sensor input. Til plethandsken har vi valgt at teste en FSR sensor og et accelerometer. VI har taget valget på baggrund af newtons anden lov som er følgende:

F = M · A
Kræft(N) = Masse(kg) · Acceleration(m/s)

Ideen er at når vi kender kraften og accelerationen af et slag kan vi sige noget om slagets beskaffenhed. Gennem fysisk test af en prototype vil vi afsløre om vore sensorer kan give et brugbart resultat. Der er flere faktorer som spiller ind bla:

  • Plethandsken er ikke statisk
  • Hvordan skal vore sensorer opfatte et korrekt slag?
  • Omsætte den fysiske data til håndgribelig brugerfeedback
  • Hvilken masse er det vi får regnet ud ?
  • Placering af sensorer

Test af sensor

For at tillade flere brugere ville den optimale løsning være at placere sensorer i selve plethandsken.

handske

Bruger scenariet er at træneren holder den grå “handske” og at forskellige elever kan få feedback på deres slag.
Vores tanker omkring brug af newtons lov kræver meget præcise målinger af alle sensorer. Vi har været begrænset af vores FSR sensor da den kun kan registrere 100 newton. Dvs. at alle test-slag gav et resultat nær max output.
Vi overvejede også at placere accelerometeret i boksehandsken også i processing angive brugerens vægt, men dette gav ikke mening for vores brugerscenarie.
Den brune handske er i bevægelse hele tiden så det er svært at få et korrekt sensor output der er brugbart. Derfor valgte vi at fokusere på FSR sensoren alene. Vores opgave var således at omsætte max værdierne til noget visuelt forståeligt for brugeren.

Opsætning af hardware

opsaet

På billedet her ses vores hardware opsætning. På arduinoen har vi monteret et bluetooth modul, der fungerer som en server vores pc ( klienten ) opretter forbindelse til.

På denne måde kan vi trådløst sende data til både pc og telefon. Bluetooth modulet opfører sig som en slags seriel port uden ledning.

FSR sensoren sender en værdi fra 0 -1024 og det er så “processings” opgave at oversætte det visuelt så en bruger kan forstå dataen.

Sammensætning af hardware

Kommunikationsmodel

flowchart

Teknisk tegning

fritzing af newtonhandsken

Kode (Arduino)

#include <SoftwareSerial.h>  

int bluetoothTx = 2;  // TX-O pin of bluetooth mate, Arduino D2
int bluetoothRx = 3;  // RX-I pin of bluetooth mate, Arduino D3

SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);

void setup()
{
  Serial.begin(9600);  // Begin the serial monitor at 9600bps

  bluetooth.begin(115200);  // The Bluetooth Mate defaults to 115200bps
  bluetooth.print("$");  // Print three times individually
  bluetooth.print("$");
  bluetooth.print("$");  // Enter command mode
  delay(1);  // Short delay, wait for the Mate to send back CMD
  bluetooth.println("U,9600,N");  // Temporarily Change the baudrate to 9600, no parity
  // 115200 can be too fast at times for NewSoftSerial to relay the data reliably
  bluetooth.begin(9600);  // Start bluetooth serial at 9600
}

void loop()
{
  int sensorValue = analogRead(A2); //stores the output from the sensor
  Serial.println(sensorValue); //prints it to the Serial Moniter for testing purposes
  delay(70); //this is the fastest we can send data without making trouble for processing on the other end
             //too much data will make processing get behind and the draw events will be delayed making it look iffy
  bluetooth.print(sensorValue); //prints the data via bluetooth
  bluetooth.print("\n"); //a marker for the other end to know that no more data is comming.
} 

Kode (Processing)

import processing.serial.*;

Serial myPort;  
float val;      
float max;
String strVal;
int counter;
int arrayLength = 5000;
int xStart = 20;
int yStart = 580;
color yellow = #FFCC00;
color red = #FF0000;
color blue = #00AAEE;
float[] number = new float[arrayLength];

void setup() 
{
  size(1200, 900);  //screen size
  frameRate(60);    //frame rate, how many times pr second the screen is redrawn
  String portName = Serial.list()[0]; // select the port you want to use, 0 is in our case the usb and 1 is the bluetooth, given that thoose are the only 2 devices connected
  myPort = new Serial(this, portName, 9600); //defines the port for later usage
  printArray(Serial.list()); //prints all COM ports for troubleshooting, use this to find out which port you should use.
  background(255);  //background is default white!
}

void draw()
{
  if ( myPort.available() > 0) {  // It will only draw if data is available
    strVal = myPort.readStringUntil('\n'); //stores the value in a string

    if (strVal != null) //alot of nulls will be send when there is no data or if there is some kind of noise, if this is the case we do not want to execute our code
    {  
  val = Float.parseFloat(strVal); //we store the value as a float, so we can apply math and draw figures with it

      if (val > 50) //values below 50 will not be read, as due to the mechanical setup the sensor is sometimes pressed slightly which gives small useless outputs. 
      {   

    while(val != 0.0) //we will run a while loop until we get a 0.0 value, this is because when hitting the sensor it will generate more than one value, 
                      //and we want to wait until we have all the values stored before we start drawing. otherwise the result will not be intuitive to the average user.
    {

     strVal = myPort.readStringUntil('\n'); //we need to check new values in the while loop too, as it does not leave this loop
     if (strVal != null) { //again check for nulls
     number[counter] = val; //we start storing our values in an array, we do this before overwring the old value with the new, so we get the initial value in the array aswell.
     val = parseFloat(strVal);
     println("this is a float value: "+val); //trouble shooting, gives output
     counter++; //incrementer for the array
     } 
    }
    println("-----: "+counter+" :-----"); //shows how many entries that was in the array

    max = max(number); //we take the largest value in the array, which is respresents hard the person hit 
    for(int i = 0; i < (arrayLength-1); i++) //dumb everything in the array so it can be used again
    {
      number[i] = 0; 
    }
    if (max > 800) { //different color for different sprectrum og values
    fill(red);
    } else if ((max < 800) && (max > 650)) {
    fill(yellow);
    } else {
    fill(blue);
    }
    rect(xStart, yStart-(max/2), 55, (max/2)); //uses values to draw a rectangle representing the value
    xStart = xStart+60; // move xStart so the new rectangle will be drawn next to the old one with a 5 pixel width seperating them
    }
    fill(255); 
    stroke(255); 
    rect(20,580,200,200); //this draw a box that deletes the old textvalue so a new one can be inserted
    textSize(40); 
    String strmax = ""+max; //the value to be written coverted back to a string
    stroke(#BEBEBE); //fancy color
    fill(#BEBEBE);
    line(20,600,1100,600); //a line for visual purposes
    text(strmax,20,640); //this gives the output as a text below the bars

    if( xStart > 1100) { //once a certain (18) amount of bars have been drawn, we want to reset the screen to make room for more, we do this by redrawing it white and resetting xStart 
       xStart = 20;
       background(255);
    }
  counter = 0; //reset the counter so once we get another value it will fill the array up from the start
 } 

}

} 

Alternativ udgave

Vi har sideløbende med den funktionelle prototype arbejdet på en forbedret visualisering i processing. Ideen var at der også skulle være lidt interaktivitet på skærmen, så man kunne interagere med sine resultater bagefter. Koden kom dog aldrig til at fungere helt i praksis med de fysiske slag. Her ses koden i test-fasen samt en videopræsentation af koden.

int numberOfColumns = 14; // antal søjler
int columnWidth = 40; // søjlebredde
int xStart = 75;
int yStart = 500;

PFont f; // klargør font

float maxVal = random(0, 400); // tilfældig TEMP tal

PShape[] rectangles = new PShape[numberOfColumns]; // array til søjler
int[] xPos = new int[numberOfColumns]; // array til xPos af hver kolonne
float[] yPos = new float[numberOfColumns]; // array til højden ell værdien af hver kolonne

String powerPoint = ""; // klargør streng til point angivelse

void setup() {
  f = createFont("Arial", 40, true); // lav font med max font str 40
  size(800, 600, P2D);
  background(255, 255, 255);
  fill(#BEBEBE);
  stroke(#BEBEBE);
  line(xStart, yStart+25, 800-xStart, yStart+25); // linje til adskillelse af søjler og text
  textFont(f, 18);
  text("Power", xStart, yStart+55); 
  noStroke(); // ingen ramme omkring søjler (kun fill)

  for (int i = 0; i < rectangles.length; i++) {
    rectangles[i] = createShape(RECT, xStart, yStart-maxVal, columnWidth, maxVal);
    shape(rectangles[i]); // tegn søjle

    xPos[i] = xStart; // gem værdien af søjlens x-position
    yPos[i] = maxVal; // gem værdien af søjlens y-værdi / point

    maxVal = random(0, 500); // nyt TEMP random tal
    xStart = xStart + columnWidth+5; // næste søjle har en afstand på 5px

    // print(i +".\t" + "x: " + xPos[i] + "\t" + "y: " + yPos[i] + "\n");
  }
}

void draw() {

  // ***************************************
  // hvid kasse til at skjule text-point når man hover over ny søjle
  fill(255, 255, 255); 
  rect(xPos[0]+65, yStart+35, 300, 50);
  fill(#BEBEBE);
  // ***************************************

  for (int i = 0; i < rectangles.length; i++) {    
    shape(rectangles[i]);

    // hvis man hover over en søjle, ændre farve og angiv point i text
    if ((mouseX > xPos[i]) && (mouseX < xPos[i]+columnWidth) && (mouseY < yStart ) && (mouseY > yStart-yPos[i]) ) {
      rectangles[i].setFill(color(#2FC944));       
      powerPoint = str(yPos[i]);
      textFont(f, 40);
      fill(0);
      text(powerPoint, xPos[0]+65, yStart+70);
    } 
    else { // når man "forlader" en søjle så gå tilbage til standard søjlefarve
      rectangles[i].setFill(color(#BEBEBE));
    }
  }
}

Video af fungerende prototype

Konklusion

Som det ses ud fra videoen af den fungerende prototype (ikke den alternative), så er det lidt tilfældigt hvor godt resultatet er. FSR-sensoren er desværre ikke præcis nok til at give et troværdigt resultat. Hvis vi skulle lave en ny prototype, så ville det kræve test af en række andre type sensorer. Idéen er der, men i praksis fungerer idéen ikke helt endnu..

Leave a Reply