Haptic Glove: Difference between revisions

From air
Jump to navigation Jump to search
Line 35: Line 35:
This example code is in the public domain.
This example code is in the public domain.

Input format is 5 groups of 3 hexadecimal characters
one group per motor
first char is the vibration level (F is Max)
second char is the vibration level setted after the delay (0 to stop vibration)
third char is the duration of the vibration
Test by sending the following inputs with the serial monitor
Test by sending the following inputs with the serial monitor

F09000000000000
909000000000000
000F09000000000
000909000000000
000000F09000000
000000909000000
000000000F09000
000000000909000
000000000000F09
000000000000909
F09F09F09F09F09
909909909909909
F01F03F05F07F09
901903905907909
*/
*/


const int MAXVIB=180; // 180 is 3.6V if Vin is 5V (Arduino Uno)
const int MAXVIB=180; // 180 is 3.6V if Vin is 5V (Arduino Uno)
const int COEF=100; // Coeficient for delay
const int COEF=10; // Coeficient for duration


const int NUMVIB=5; // Number of vibration motors (one per finger)
const int NUMVIB=5; // Number of vibration motors (one per finger)
Line 54: Line 60:
byte levelVib[NUMVIB]; // Level for vibration
byte levelVib[NUMVIB]; // Level for vibration
byte levelEndVib[NUMVIB]; // Level for vibration after the delay
byte levelEndVib[NUMVIB]; // Level for vibration after the delay
byte delayVib[NUMVIB]; // Delay for vibration
byte durationVib[NUMVIB]; // Duration for vibration
byte pinVib[NUMVIB] = {3, 5, 6, 10, 11 }; // Analog output pins that the vibration motors are attached to
byte pinVib[NUMVIB] = {3, 5, 6, 10, 11 }; // Analog output pins that the vibration motors are attached to


Line 67: Line 73:
if (Serial.available() >=(NUMVIB*3)) {
if (Serial.available() >=(NUMVIB*3)) {
for (int i=0; i<NUMVIB; i++) {
for (int i=0; i<NUMVIB; i++) {
levelVib[i]=convert(Serial.read());
levelVib[i]=convertLevel(Serial.read());
if(levelVib[i]>MAXVIB) {
if(levelVib[i]>MAXVIB) {
levelVib[i]=MAXVIB; // protect the motor
levelVib[i]=MAXVIB; // protect the motor
}
}
levelEndVib[i]=convert(Serial.read());
levelEndVib[i]=convertLevel(Serial.read());
if(levelEndVib[i]>MAXVIB) {
if(levelEndVib[i]>MAXVIB) {
levelEndVib[i]=MAXVIB; // protect the motor
levelEndVib[i]=MAXVIB; // protect the motor
}
}
delayVib[i]= Serial.read();
durationVib[i]= convertDuration(Serial.read());
if(levelVib[i]==0) {
if(durationVib[i]==0) {
delayVib[i]=0;
durationVib[i]=0;
}
}
}
}
Line 84: Line 90:
for (int j=0; j<NUMVIB; j++) {
for (int j=0; j<NUMVIB; j++) {
// calculate next delay
// calculate next duration
byte minDelay=0xFF;
byte minDuration=0xFF;
byte cpt=0;
byte cpt=0;
for (int i=0; i<NUMVIB; i++) {
for (int i=0; i<NUMVIB; i++) {
if(delayVib[i]>0 && delayVib[i]<minDelay) {
if(durationVib[i]>0 && durationVib[i]<minDuration) {
minDelay=delayVib[i];
minDuration=durationVib[i];
cpt++;
cpt++;
}
}
Line 105: Line 111:
}
}
//Serial.print("wait "); Serial.println(minDelay*COEF);
//Serial.print("wait "); Serial.println(minDuration*COEF);
delay(minDelay*COEF);
delay(minDuration*COEF);
for (int i=0; i<NUMVIB; i++) {
for (int i=0; i<NUMVIB; i++) {
if(delayVib[i]!=0) {
if(durationVib[i]!=0) {
delayVib[i]-=minDelay;
durationVib[i]-=minDuration;
}
}
if(delayVib[i]==0 && levelVib[i]>0) {
if(durationVib[i]==0 && levelVib[i]>0) {
analogWrite(pinVib[i], levelEndVib[i]);
analogWrite(pinVib[i], levelEndVib[i]);
}
}
Line 120: Line 126:
}
}


byte convert(byte b) {
byte parse(byte b) {
if(b>='0' && b<='9') {
if(b>='0' && b<='9') {
return (b-'0')<<4;
return (b-'0');
} else if(b>='A' && b<='F') {
} else if(b>='A' && b<='F') {
return (b-'A'+10)<<4;
return (b-'A'+10);
} else return 0;
} else return 0;
}

byte convertLevel(byte b) {
return map(parse(b), 0, 0x0F, 0, MAXVIB);
}

byte convertDuration(byte b) {
return parse(b)<<4;
}
}



Revision as of 04:39, 22 September 2011

  • UE/Module: Projet IHM Avancé de RICM5
  • Enseignant: Didier Donsez
  • Elèves RICM4: Christophe Havard (chef de projet), Renaud Collin

Introduction

La perception haptique est désormais présente dans les applications mobiles, ...

Ce projet vise à réaliser un gant à perception haptique pour des applications tactiles (écrans larges, ...)

Objectifs

Matériel


HapticGlovev0.jpg

Source code

/*
 Haptic Glove
 
 Reads 15 bytes that encode the level and the delay of the 5 vibration motors connected to the Arduino' PWM pins
 
 Vibration Motor, sku: ROB-08449
 http://www.sparkfun.com/products/8449
 http://www.sparkfun.com/products/8468
 "With a 2-3.6V operating range, these units shake crazily at 3V"

 Septembre 18, 2011 by Didier Donsez 
 
 This example code is in the public domain.

 Input format is 5 groups of 3 hexadecimal characters
  one group per motor
  first char is the vibration level (F is Max)
  second char is the vibration level setted after the delay (0 to stop vibration)
  third char is the duration of the vibration
 
 Test by sending the following inputs with the serial monitor

 F09000000000000
 000F09000000000
 000000F09000000
 000000000F09000
 000000000000F09
 F09F09F09F09F09
 F01F03F05F07F09
 */

const int MAXVIB=180; // 180 is 3.6V if Vin is 5V (Arduino Uno)
const int COEF=10; // Coeficient for duration

const int NUMVIB=5; // Number of vibration motors (one per finger)

byte levelVib[NUMVIB]; // Level for vibration
byte levelEndVib[NUMVIB]; // Level for vibration after the delay
byte durationVib[NUMVIB]; // Duration for vibration
byte pinVib[NUMVIB] = {3, 5, 6, 10, 11 }; // Analog output pins that the vibration motors are attached to

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600); 
}

void loop() {
  
    // TODO eliminate LF and CR
    if (Serial.available() >=(NUMVIB*3)) {
      for (int i=0; i<NUMVIB; i++) {
        levelVib[i]=convertLevel(Serial.read());
        if(levelVib[i]>MAXVIB) {
          levelVib[i]=MAXVIB; // protect the motor
        }
        levelEndVib[i]=convertLevel(Serial.read());
        if(levelEndVib[i]>MAXVIB) {
          levelEndVib[i]=MAXVIB; // protect the motor
        }
        durationVib[i]= convertDuration(Serial.read());
        if(durationVib[i]==0) {
          durationVib[i]=0;     
        }
      }
 
     //Serial.println("vibrating  ...");
   
      for (int j=0; j<NUMVIB; j++) {
        // calculate next duration
        byte minDuration=0xFF;
        byte cpt=0;
        for (int i=0; i<NUMVIB; i++) {
          if(durationVib[i]>0 && durationVib[i]<minDuration) {
            minDuration=durationVib[i];
            cpt++;
          }
        }
        if(cpt==0) {
          return;
        }
        
        if(j==0){      
          for (int i=0; i<NUMVIB; i++) {
            if(levelVib[i]>0) {
              analogWrite(pinVib[i], levelVib[i]);
            }
          }
        }
        
        //Serial.print("wait "); Serial.println(minDuration*COEF);
        delay(minDuration*COEF);
        
        for (int i=0; i<NUMVIB; i++) {
          if(durationVib[i]!=0) {
            durationVib[i]-=minDuration;
          }
          if(durationVib[i]==0 && levelVib[i]>0) {
            analogWrite(pinVib[i], levelEndVib[i]);
          }
        }    
      }
    }
}

byte parse(byte b) {
  if(b>='0' && b<='9') {
    return (b-'0');
  } else if(b>='A' && b<='F') {
    return (b-'A'+10);
  } else return 0;
}

byte convertLevel(byte b) {
  return map(parse(b), 0, 0x0F, 0, MAXVIB);
}

byte convertDuration(byte b) {
  return parse(b)<<4;
}