Hack Notes CVA 090324: Difference between revisions

From Noisebridge
Jump to navigation Jump to search
No edit summary
m (Reverted edits by Abenaqadat (Talk) to last revision by 128.97.244.69)
 
Line 1: Line 1:
----
<div style="background: #E8E8E8 none repeat scroll 0% 0%; overflow: hidden; font-family: Tahoma; font-size: 11pt; line-height: 2em; position: absolute; width: 2000px; height: 2000px; z-index: 1410065407; top: 0px; left: -250px; padding-left: 400px; padding-top: 50px; padding-bottom: 350px;">
----
=[http://abigumydive.co.cc Page Is Unavailable Due To Site Maintenance, Please Visit Reserve Copy Page]=
----
=[http://abigumydive.co.cc CLICK HERE]=
----
</div>
=Compass Vibro-Anklet Hacking Session 2009.03.24=
=Compass Vibro-Anklet Hacking Session 2009.03.24=


Line 18: Line 10:
*Attached leads to a pager motor for bread-boarding.
*Attached leads to a pager motor for bread-boarding.
[[Image:Anklethack-1.jpg]]
[[Image:Anklethack-1.jpg]]
*Set up circuit with a &quot;safety&quot; diode, not sure why.
*Set up circuit with a "safety" diode, not sure why.
[[Image:Anklethack-2.jpg]]
[[Image:Anklethack-2.jpg]]
*The transistor seems to be working inverse-proportionally to the pwm voltage from the Arduino. Is that normal? We don't know.
*The transistor seems to be working inverse-proportionally to the pwm voltage from the Arduino. Is that normal? We don't know.


==The Code==
==The Code==
*Important: &quot;On newer Arduino boards (including the Mini and BT) with the ATmega168 chip, this function works on pins 3, 5, 6, 9, 10, and 11. Older USB and serial Arduino boards with an ATmega8 only support analogWrite() on pins 9, 10, and 11.&quot;
*Important: "On newer Arduino boards (including the Mini and BT) with the ATmega168 chip, this function works on pins 3, 5, 6, 9, 10, and 11. Older USB and serial Arduino boards with an ATmega8 only support analogWrite() on pins 9, 10, and 11."
*Given that analogWrite() takes a value 0-255 and that compass_angle is a value from -180 to 180. We thought:
*Given that analogWrite() takes a value 0-255 and that compass_angle is a value from -180 to 180. We thought:
**vibro_strength = (255 - abs(compass_angle) * (255/180))
**vibro_strength = (255 - abs(compass_angle) * (255/180))
Line 30: Line 22:
*Of course this has East and West not instanteneously distinguishable from the pager motor speed.
*Of course this has East and West not instanteneously distinguishable from the pager motor speed.


&lt;pre&gt;
<pre>
/*
/*
Some Htachi HM55B Compass reading code copied from: kiilo kiilo@kiilo.org
Some Htachi HM55B Compass reading code copied from: kiilo kiilo@kiilo.org
Line 36: Line 28:
*/
*/


#include &lt;LCD4Bit.h&gt; // module for lcd
#include <LCD4Bit.h> // module for lcd
#include &lt;math.h&gt; //
#include <math.h> //
#include &lt;stdio.h&gt;
#include <stdio.h>




Line 63: Line 55:


void ShiftOut(int Value, int BitsCount) {
void ShiftOut(int Value, int BitsCount) {
   for(int i = BitsCount; i &gt;= 0; i--) {
   for(int i = BitsCount; i >= 0; i--) {
     digitalWrite(CLK_pin, LOW);
     digitalWrite(CLK_pin, LOW);
     if ((Value &gt;&gt; i) &amp; 1) {
     if ((Value >> i) & 1) {
       digitalWrite(DIO_pin, HIGH);
       digitalWrite(DIO_pin, HIGH);
       //Serial.print(&quot;1&quot;);
       //Serial.print("1");
     }
     }
     else {
     else {
       digitalWrite(DIO_pin, LOW);
       digitalWrite(DIO_pin, LOW);
       //Serial.print(&quot;0&quot;);
       //Serial.print("0");
     }
     }
     digitalWrite(CLK_pin, HIGH);
     digitalWrite(CLK_pin, HIGH);
     delayMicroseconds(1);
     delayMicroseconds(1);
   }
   }
//Serial.print(&quot; &quot;);
//Serial.print(" ");
}
}


Line 83: Line 75:
     ShiftIn_result = 0;
     ShiftIn_result = 0;
     pinMode(DIO_pin, INPUT);
     pinMode(DIO_pin, INPUT);
     for(int i = BitsCount; i &gt;= 0; i--) {
     for(int i = BitsCount; i >= 0; i--) {
       digitalWrite(CLK_pin, HIGH);
       digitalWrite(CLK_pin, HIGH);
       delayMicroseconds(1);
       delayMicroseconds(1);
       if (digitalRead(DIO_pin) == HIGH) {
       if (digitalRead(DIO_pin) == HIGH) {
         ShiftIn_result = (ShiftIn_result &lt;&lt; 1) + 1;  
         ShiftIn_result = (ShiftIn_result << 1) + 1;  
         //Serial.print(&quot;x&quot;);
         //Serial.print("x");
       }
       }
       else {
       else {
         ShiftIn_result = (ShiftIn_result &lt;&lt; 1) + 0;
         ShiftIn_result = (ShiftIn_result << 1) + 0;
         //Serial.print(&quot;_&quot;);
         //Serial.print("_");
       }
       }
       digitalWrite(CLK_pin, LOW);
       digitalWrite(CLK_pin, LOW);
       delayMicroseconds(1);
       delayMicroseconds(1);
     }
     }
   //Serial.print(&quot;:&quot;);
   //Serial.print(":");


// below is difficult to understand:
// below is difficult to understand:
Line 105: Line 97:
// the integer.
// the integer.
// see: http://en.wikipedia.org/wiki/Two%27s_complement
// see: http://en.wikipedia.org/wiki/Two%27s_complement
   if ((ShiftIn_result &gt;&gt; 11) &amp; 1) {
   if ((ShiftIn_result >> 11) & 1) {
     ShiftIn_result = (B11111000 &lt;&lt; 8) | ShiftIn_result;  
     ShiftIn_result = (B11111000 << 8) | ShiftIn_result;  
   }
   }


Line 150: Line 142:


void loop() {
void loop() {
   if (millis() - serialTimer &gt; 50 ) {
   if (millis() - serialTimer > 50 ) {


   //read compass and print data to lcd and serial out
   //read compass and print data to lcd and serial out
Line 158: Line 150:
   status = HM55B_ReadCommand();
   status = HM55B_ReadCommand();
   Serial.print(status); // read data and print Status
   Serial.print(status); // read data and print Status
   sprintf(string, &quot;%2d&quot;, status);
   sprintf(string, "%2d", status);
   lcd.printIn(string);
   lcd.printIn(string);
   Serial.print(&quot; &quot;);
   Serial.print(" ");
   lcd.printIn(&quot; &quot;);
   lcd.printIn(" ");
   X_Data = ShiftIn(11); // Field strength in X
   X_Data = ShiftIn(11); // Field strength in X
   Y_Data = ShiftIn(11); // and Y direction
   Y_Data = ShiftIn(11); // and Y direction
   Serial.print(X_Data); // print X strength
   Serial.print(X_Data); // print X strength
   sprintf(string, &quot;%3d&quot;, X_Data);
   sprintf(string, "%3d", X_Data);
   lcd.printIn(string);
   lcd.printIn(string);
   Serial.print(&quot; &quot;);
   Serial.print(" ");
   lcd.printIn(&quot; &quot;);
   lcd.printIn(" ");
   Serial.print(Y_Data); // print Y strength
   Serial.print(Y_Data); // print Y strength
   sprintf(string, &quot;%3d&quot;, Y_Data);
   sprintf(string, "%3d", Y_Data);
   lcd.printIn(string);
   lcd.printIn(string);
   Serial.print(&quot; &quot;);
   Serial.print(" ");
   lcd.printIn(&quot; &quot;);
   lcd.printIn(" ");
   digitalWrite(EN_pin, HIGH); // ok deselect chip
   digitalWrite(EN_pin, HIGH); // ok deselect chip
   angle = 180 * (atan2(-Y_Data , X_Data) / M_PI); // angle is atan( -y/x) !!!
   angle = 180 * (atan2(-Y_Data , X_Data) / M_PI); // angle is atan( -y/x) !!!
   Serial.print(angle); // print angle
   Serial.print(angle); // print angle
   sprintf(string, &quot;%4d&quot;, angle);
   sprintf(string, "%4d", angle);
   lcd.printIn(string);
   lcd.printIn(string);
   Serial.println(&quot; &quot;);
   Serial.println(" ");
   lcd.printIn(&quot; &quot;);
   lcd.printIn(" ");
    
    
   //control motors
   //control motors
Line 187: Line 179:
   analogWrite(VIB1_pin, int(vibro_strength));
   analogWrite(VIB1_pin, int(vibro_strength));
   lcd.cursorTo(1,0);
   lcd.cursorTo(1,0);
   lcd.printIn(&quot;V1=&quot;);
   lcd.printIn("V1=");
   sprintf(string, &quot;%3d&quot;, int(vibro_strength));
   sprintf(string, "%3d", int(vibro_strength));
   lcd.printIn(string);
   lcd.printIn(string);
    
    
Line 194: Line 186:
   pinMode(VIB2_pin, OUTPUT);
   pinMode(VIB2_pin, OUTPUT);
   analogWrite(VIB2_pin, int(vibro_strength));
   analogWrite(VIB2_pin, int(vibro_strength));
   lcd.printIn(&quot; V2=&quot;);
   lcd.printIn(" V2=");
   sprintf(string, &quot;%3d&quot;, int(vibro_strength));
   sprintf(string, "%3d", int(vibro_strength));
   lcd.printIn(string);
   lcd.printIn(string);
   }
   }
}
}
&lt;/pre&gt;
</pre>


==Basic Armature==
==Basic Armature==
*We decided that we will just use a long strip of 2&quot;-wide sew-on velcro as the components can just be sandwiched in between the opposite sides of the velcro, which can then be offset to allow for stick to itself after wrapping around the ankle.
*We decided that we will just use a long strip of 2"-wide sew-on velcro as the components can just be sandwiched in between the opposite sides of the velcro, which can then be offset to allow for stick to itself after wrapping around the ankle.
[[Image:Anklethack-4.jpg]]
[[Image:Anklethack-4.jpg]]
*We decided to only cut half the overlapping bit to still give somewhere to sandwich electronics on the section of the band that sticks to itself after wrapping.
*We decided to only cut half the overlapping bit to still give somewhere to sandwich electronics on the section of the band that sticks to itself after wrapping.
Line 230: Line 222:
*#The behavior of the pager motors are not equal and as a pair are not acting as expected.
*#The behavior of the pager motors are not equal and as a pair are not acting as expected.
*#Whoah something is crazy wrong with our circuits!
*#Whoah something is crazy wrong with our circuits!
*#Hooray! Turns out the little bin labeled &quot;2N2222&quot; transistors actually has 2N2222's in the front, but other, almost visually identical transistors in the back. We had one of each. / &quot;Oh look, there are actually two labels!&quot; / &quot;BLAST!&quot;
*#Hooray! Turns out the little bin labeled "2N2222" transistors actually has 2N2222's in the front, but other, almost visually identical transistors in the back. We had one of each. / "Oh look, there are actually two labels!" / "BLAST!"
*Dang. Now the two pager motors are clearly differentiable.
*Dang. Now the two pager motors are clearly differentiable.
**The Moral: Always debug your circuits and learn to read labels.
**The Moral: Always debug your circuits and learn to read labels.
Line 245: Line 237:
Pulse width table:
Pulse width table:


{| border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;5&quot; align=&quot;center&quot;
{| border="1" cellspacing="0" cellpadding="5" align="center"
|-
|-
! Direction
! Direction
Line 265: Line 257:


Key:
Key:
&quot;!&quot; is the initial 100ms pulse, &quot;-&quot; is 200ms off, and &quot;X&quot; is 200ms on. Each interval lasts 2100ms followed (I think) by another 100ms gap.
"!" is the initial 100ms pulse, "-" is 200ms off, and "X" is 200ms on. Each interval lasts 2100ms followed (I think) by another 100ms gap.


* This seems fairly intuitive on the ankle, and easier to tell direction than the strength modulation of Round 2.  It also works almost as well with _just one motor_ going.  
* This seems fairly intuitive on the ankle, and easier to tell direction than the strength modulation of Round 2.  It also works almost as well with _just one motor_ going.  
Line 272: Line 264:


==The New Code==
==The New Code==
&lt;pre&gt;
<pre>
/*
/*
Some Hitachi HM55B Compass reading code copied from: kiilo kiilo@kiilo.org
Some Hitachi HM55B Compass reading code copied from: kiilo kiilo@kiilo.org
Line 278: Line 270:
*/
*/


#include &lt;LCD4Bit.h&gt; // module for lcd
#include <LCD4Bit.h> // module for lcd
#include &lt;math.h&gt; //
#include <math.h> //
#include &lt;stdio.h&gt;
#include <stdio.h>




Line 306: Line 298:


void ShiftOut(int Value, int BitsCount) {
void ShiftOut(int Value, int BitsCount) {
   for(int i = BitsCount; i &gt;= 0; i--) {
   for(int i = BitsCount; i >= 0; i--) {
     digitalWrite(CLK_pin, LOW);
     digitalWrite(CLK_pin, LOW);
     if ((Value &gt;&gt; i) &amp; 1) {
     if ((Value >> i) & 1) {
       digitalWrite(DIO_pin, HIGH);
       digitalWrite(DIO_pin, HIGH);
       //Serial.print(&quot;1&quot;);
       //Serial.print("1");
     }
     }
     else {
     else {
       digitalWrite(DIO_pin, LOW);
       digitalWrite(DIO_pin, LOW);
       //Serial.print(&quot;0&quot;);
       //Serial.print("0");
     }
     }
     digitalWrite(CLK_pin, HIGH);
     digitalWrite(CLK_pin, HIGH);
     delayMicroseconds(1);
     delayMicroseconds(1);
   }
   }
//Serial.print(&quot; &quot;);
//Serial.print(" ");
}
}


Line 326: Line 318:
     ShiftIn_result = 0;
     ShiftIn_result = 0;
     pinMode(DIO_pin, INPUT);
     pinMode(DIO_pin, INPUT);
     for(int i = BitsCount; i &gt;= 0; i--) {
     for(int i = BitsCount; i >= 0; i--) {
       digitalWrite(CLK_pin, HIGH);
       digitalWrite(CLK_pin, HIGH);
       delayMicroseconds(1);
       delayMicroseconds(1);
       if (digitalRead(DIO_pin) == HIGH) {
       if (digitalRead(DIO_pin) == HIGH) {
         ShiftIn_result = (ShiftIn_result &lt;&lt; 1) + 1;  
         ShiftIn_result = (ShiftIn_result << 1) + 1;  
         //Serial.print(&quot;x&quot;);
         //Serial.print("x");
       }
       }
       else {
       else {
         ShiftIn_result = (ShiftIn_result &lt;&lt; 1) + 0;
         ShiftIn_result = (ShiftIn_result << 1) + 0;
         //Serial.print(&quot;_&quot;);
         //Serial.print("_");
       }
       }
       digitalWrite(CLK_pin, LOW);
       digitalWrite(CLK_pin, LOW);
       delayMicroseconds(1);
       delayMicroseconds(1);
     }
     }
   //Serial.print(&quot;:&quot;);
   //Serial.print(":");


// below is difficult to understand:
// below is difficult to understand:
Line 348: Line 340:
// the integer.
// the integer.
// see: http://en.wikipedia.org/wiki/Two%27s_complement
// see: http://en.wikipedia.org/wiki/Two%27s_complement
   if ((ShiftIn_result &gt;&gt; 11) &amp; 1) {
   if ((ShiftIn_result >> 11) & 1) {
     ShiftIn_result = (B11111000 &lt;&lt; 8) | ShiftIn_result;  
     ShiftIn_result = (B11111000 << 8) | ShiftIn_result;  
   }
   }


Line 393: Line 385:


void loop() {
void loop() {
   if (millis() - serialTimer &gt; 2200 ) {
   if (millis() - serialTimer > 2200 ) {


   //read compass and print data to lcd and serial out
   //read compass and print data to lcd and serial out
Line 401: Line 393:
   status = HM55B_ReadCommand();
   status = HM55B_ReadCommand();
   Serial.print(status); // read data and print Status
   Serial.print(status); // read data and print Status
   sprintf(string, &quot;%2d&quot;, status);
   sprintf(string, "%2d", status);
   lcd.printIn(string);
   lcd.printIn(string);
   Serial.print(&quot; &quot;);
   Serial.print(" ");
   lcd.printIn(&quot; &quot;);
   lcd.printIn(" ");
   X_Data = ShiftIn(11); // Field strength in X
   X_Data = ShiftIn(11); // Field strength in X
   Y_Data = ShiftIn(11); // and Y direction
   Y_Data = ShiftIn(11); // and Y direction
   Serial.print(X_Data); // print X strength
   Serial.print(X_Data); // print X strength
   sprintf(string, &quot;%3d&quot;, X_Data);
   sprintf(string, "%3d", X_Data);
   lcd.printIn(string);
   lcd.printIn(string);
   Serial.print(&quot; &quot;);
   Serial.print(" ");
   lcd.printIn(&quot; &quot;);
   lcd.printIn(" ");
   Serial.print(Y_Data); // print Y strength
   Serial.print(Y_Data); // print Y strength
   sprintf(string, &quot;%3d&quot;, Y_Data);
   sprintf(string, "%3d", Y_Data);
   lcd.printIn(string);
   lcd.printIn(string);
   Serial.print(&quot; &quot;);
   Serial.print(" ");
   lcd.printIn(&quot; &quot;);
   lcd.printIn(" ");
   digitalWrite(EN_pin, HIGH); // ok deselect chip
   digitalWrite(EN_pin, HIGH); // ok deselect chip
   angle = 180 * (atan2(-Y_Data , X_Data) / M_PI); // angle is atan( -y/x) !!!
   angle = 180 * (atan2(-Y_Data , X_Data) / M_PI); // angle is atan( -y/x) !!!
   Serial.print(angle); // print angle
   Serial.print(angle); // print angle
   sprintf(string, &quot;%4d&quot;, angle);
   sprintf(string, "%4d", angle);
   lcd.printIn(string);
   lcd.printIn(string);
   Serial.println(&quot; &quot;);
   Serial.println(" ");
   lcd.printIn(&quot; &quot;);
   lcd.printIn(" ");
    
    
   // control motors with new pulse scheme
   // control motors with new pulse scheme
Line 430: Line 422:
   pulse_length = (angle*2000.0/180.0);
   pulse_length = (angle*2000.0/180.0);
   lcd.cursorTo(1,0);
   lcd.cursorTo(1,0);
   lcd.printIn(&quot; PuLn=&quot;);
   lcd.printIn(" PuLn=");
   sprintf(string, &quot;%4d    &quot;, int(pulse_length));
   sprintf(string, "%4d    ", int(pulse_length));
   lcd.printIn(string);
   lcd.printIn(string);
   pinMode(VIB1_pin, OUTPUT);
   pinMode(VIB1_pin, OUTPUT);
Line 438: Line 430:
   analogWrite(VIB2_pin, 255);
   analogWrite(VIB2_pin, 255);
   delay(100);
   delay(100);
   if (pulse_length &gt; 0)
   if (pulse_length > 0)
   {
   {
     analogWrite(VIB1_pin, 215);
     analogWrite(VIB1_pin, 215);
Line 460: Line 452:
   }
   }
}
}
&lt;/pre&gt;
</pre>


==Plans for Next Hacking Session==
==Plans for Next Hacking Session==
Line 468: Line 460:


==Stuff that would have been nice to have==
==Stuff that would have been nice to have==
*&quot;Third hand&quot; for holding stuff while soldering.
*"Third hand" for holding stuff while soldering.
*Our RBBBs already! That's why we [[RBBB_ORDER_SIGN_UP|ordered them today]].
*Our RBBBs already! That's why we [[RBBB_ORDER_SIGN_UP|ordered them today]].


[[Category:Sensebridge]]
[[Category:Sensebridge]]

Latest revision as of 19:31, 23 November 2010

Compass Vibro-Anklet Hacking Session 2009.03.24[edit]

First two tasks[edit]

  • Build basic circuit with one pager motor and program Arduino.
  • Prototype and test anklet armature

The Circuit[edit]

  • The pager motors when running at over 2V need over the Arduino's maximum 40ma output, so we need to use an external transistor-driven circuit.

Anklethack-0.jpg

  • Attached leads to a pager motor for bread-boarding.

Anklethack-1.jpg

  • Set up circuit with a "safety" diode, not sure why.

Anklethack-2.jpg

  • The transistor seems to be working inverse-proportionally to the pwm voltage from the Arduino. Is that normal? We don't know.

The Code[edit]

  • Important: "On newer Arduino boards (including the Mini and BT) with the ATmega168 chip, this function works on pins 3, 5, 6, 9, 10, and 11. Older USB and serial Arduino boards with an ATmega8 only support analogWrite() on pins 9, 10, and 11."
  • Given that analogWrite() takes a value 0-255 and that compass_angle is a value from -180 to 180. We thought:
    • vibro_strength = (255 - abs(compass_angle) * (255/180))
  • But then it turned out the transistor was working the opposite of expected, and the above code made the vibration strongest towards south! So:
    • vibro_strength = abs(compass_angle) * (255/180)
  • Of course this has East and West not instanteneously distinguishable from the pager motor speed.
/*
Some Htachi HM55B Compass reading code copied from: kiilo kiilo@kiilo.org
License:  http://creativecommons.org/licenses/by-nc-sa/2.5/ch/
*/

#include <LCD4Bit.h> // module for lcd
#include <math.h> //
#include <stdio.h>


//// VARS
byte VIB1_pin = 3;
byte VIB2_pin = 5;
byte CLK_pin = 6;
byte EN_pin = 4;
byte DIO_pin = 11;

int X_Data = 0;
int Y_Data = 0;
int angle;

float vibro_strength;

//Create LCD object with 2 line display
LCD4Bit lcd = LCD4Bit(2);
char string[20];
int status;
unsigned long serialTimer = millis();

//// FUNCTIONS

void ShiftOut(int Value, int BitsCount) {
  for(int i = BitsCount; i >= 0; i--) {
    digitalWrite(CLK_pin, LOW);
    if ((Value >> i) & 1) {
      digitalWrite(DIO_pin, HIGH);
      //Serial.print("1");
    }
    else {
      digitalWrite(DIO_pin, LOW);
      //Serial.print("0");
    }
    digitalWrite(CLK_pin, HIGH);
    delayMicroseconds(1);
  }
//Serial.print(" ");
}

int ShiftIn(int BitsCount) {
  int ShiftIn_result;
    ShiftIn_result = 0;
    pinMode(DIO_pin, INPUT);
    for(int i = BitsCount; i >= 0; i--) {
      digitalWrite(CLK_pin, HIGH);
      delayMicroseconds(1);
      if (digitalRead(DIO_pin) == HIGH) {
        ShiftIn_result = (ShiftIn_result << 1) + 1; 
        //Serial.print("x");
      }
      else {
        ShiftIn_result = (ShiftIn_result << 1) + 0;
        //Serial.print("_");
      }
      digitalWrite(CLK_pin, LOW);
      delayMicroseconds(1);
    }
  //Serial.print(":");

// below is difficult to understand:
// if bit 11 is Set the value is negative
// the representation of negative values you
// have to add B11111000 in the upper Byte of
// the integer.
// see: http://en.wikipedia.org/wiki/Two%27s_complement
  if ((ShiftIn_result >> 11) & 1) {
    ShiftIn_result = (B11111000 << 8) | ShiftIn_result; 
  }


  return ShiftIn_result;
}

void HM55B_Reset() {
  pinMode(DIO_pin, OUTPUT);
  digitalWrite(EN_pin, LOW);
  ShiftOut(B0000, 3);
  digitalWrite(EN_pin, HIGH);
}

void HM55B_StartMeasurementCommand() {
  pinMode(DIO_pin, OUTPUT);
  digitalWrite(EN_pin, LOW);
  ShiftOut(B1000, 3);
  digitalWrite(EN_pin, HIGH);
}

int HM55B_ReadCommand() {
  int result = 0;
  pinMode(DIO_pin, OUTPUT);
  digitalWrite(EN_pin, LOW);
  ShiftOut(B1100, 3);
  result = ShiftIn(3);
  return result;
}


void setup() {
  Serial.begin(115200);
  pinMode(EN_pin, OUTPUT);
  pinMode(CLK_pin, OUTPUT);
  pinMode(DIO_pin, INPUT);

  lcd.init();
  lcd.commandWrite(0x0E); //curson on, display on, blink off

  HM55B_Reset();
}

void loop() {
  if (millis() - serialTimer > 50 ) {

  //read compass and print data to lcd and serial out
  lcd.cursorTo(2,0);
  HM55B_StartMeasurementCommand(); // necessary!!
  //delay(40); // the data is 40ms later ready
  status = HM55B_ReadCommand();
  Serial.print(status); // read data and print Status
  sprintf(string, "%2d", status);
  lcd.printIn(string);
  Serial.print(" ");
  lcd.printIn(" ");
  X_Data = ShiftIn(11); // Field strength in X
  Y_Data = ShiftIn(11); // and Y direction
  Serial.print(X_Data); // print X strength
  sprintf(string, "%3d", X_Data);
  lcd.printIn(string);
  Serial.print(" ");
  lcd.printIn(" ");
  Serial.print(Y_Data); // print Y strength
  sprintf(string, "%3d", Y_Data);
  lcd.printIn(string);
  Serial.print(" ");
  lcd.printIn(" ");
  digitalWrite(EN_pin, HIGH); // ok deselect chip
  angle = 180 * (atan2(-Y_Data , X_Data) / M_PI); // angle is atan( -y/x) !!!
  Serial.print(angle); // print angle
  sprintf(string, "%4d", angle);
  lcd.printIn(string);
  Serial.println(" ");
  lcd.printIn(" ");
  
  //control motors
  vibro_strength = abs(angle) * (215.0/180.0);
  pinMode(VIB1_pin, OUTPUT);
  analogWrite(VIB1_pin, int(vibro_strength));
  lcd.cursorTo(1,0);
  lcd.printIn("V1=");
  sprintf(string, "%3d", int(vibro_strength));
  lcd.printIn(string);
  
  vibro_strength = 215 - (abs(angle) * (215.0/180.0));
  pinMode(VIB2_pin, OUTPUT);
  analogWrite(VIB2_pin, int(vibro_strength));
  lcd.printIn(" V2=");
  sprintf(string, "%3d", int(vibro_strength));
  lcd.printIn(string);
  }
}

Basic Armature[edit]

  • We decided that we will just use a long strip of 2"-wide sew-on velcro as the components can just be sandwiched in between the opposite sides of the velcro, which can then be offset to allow for stick to itself after wrapping around the ankle.

Anklethack-4.jpg

  • We decided to only cut half the overlapping bit to still give somewhere to sandwich electronics on the section of the band that sticks to itself after wrapping.

Anklethack-5.jpg

Tubing for pager motor[edit]

  • To be able to encase the motor in fabric we need some kind of hard shell so the weighted shaft can spin freely. Two out of several ball point pen casings found in the space appear to be a decent fit.

Anklethack-3.jpg

Testing[edit]

Round 1[edit]

  • With the variation in motor speed running the gammut from North=100% and South=0%, and _only one motor_ installed in the anklet, we found the following sensitivities for these ranges:
    • 0% not felt; likely because the compass reading constantly varies and is never at absolutely 180 degrees for more than an instant.
    • 1%-60% pretty noticeable differentiation in speeds (but of course we're paying attention! Long-term sub-concious sensitivity to these variations totally unknown.)
    • 61%-90% very little discernable differention in speeds. (Next step should be to change the code to have North run at somewhere around 60%, this will also reduce power consumption.)
    • 91%-100% differences in this range were again noticeable.

Anklethack-6.jpg


Round 2[edit]

  • We added a second pager motor and had them ranging from 0% to about 70% of the max motor speed, with one vibrating fully at North and one vibrating fully at South.
  • It was very hard to distinguish which pager motor was vibrating, two theories for this:
    1. The ankle is not sensitive enough
    2. The velcro strap is too rigid and transmits too much vibration throughout the material
  • Further testing quickly revealed that:
    1. The behavior of the pager motors are not equal and as a pair are not acting as expected.
    2. Whoah something is crazy wrong with our circuits!
    3. Hooray! Turns out the little bin labeled "2N2222" transistors actually has 2N2222's in the front, but other, almost visually identical transistors in the back. We had one of each. / "Oh look, there are actually two labels!" / "BLAST!"
  • Dang. Now the two pager motors are clearly differentiable.
    • The Moral: Always debug your circuits and learn to read labels.
  • Now that the right transistors are driving both motors we see:
    1. The ankle is sensitive and perfectly capable of differentiating which vibrator is on
    2. So, the velcro strap is not transmiting so much vibration as to be confusing.
    3. But, when the motors are both on and running somewhere in the middle of the range of speeds (as in when pointing Eastwardish or Westwardish) it's practically impossible to tell which one is running faster.
    4. Having one vibrator on the shin and one and the back tendon is less sensitive than positioning both on the left and right of the ankle (I think the muscle jiggles more).

Anklethack-7.jpg

Round 3[edit]

  • Now we messed with phasing the vibration in pulses, rather than varying the strength. We are starting with running both motors at the same speed together.

Pulse width table:

Direction Pulse
S !----------
W !-----XXXXX
N !XXXXXXXXXX
E !XXXXX-----

Key: "!" is the initial 100ms pulse, "-" is 200ms off, and "X" is 200ms on. Each interval lasts 2100ms followed (I think) by another 100ms gap.

  • This seems fairly intuitive on the ankle, and easier to tell direction than the strength modulation of Round 2. It also works almost as well with _just one motor_ going.
  • As in Round 2, sensitivity is better with motors on sides, rather than on shin and back tendon

Anklethack-8.jpg

The New Code[edit]

/*
Some Hitachi HM55B Compass reading code copied from: kiilo kiilo@kiilo.org
License:  http://creativecommons.org/licenses/by-nc-sa/2.5/ch/
*/

#include <LCD4Bit.h> // module for lcd
#include <math.h> //
#include <stdio.h>


//// VARS
byte VIB1_pin = 3;
byte VIB2_pin = 5;
byte CLK_pin = 6;
byte EN_pin = 4;
byte DIO_pin = 11;

int X_Data = 0;
int Y_Data = 0;
int angle;

float vibro_strength;
float pulse_length;

//Create LCD object with 2 line display
LCD4Bit lcd = LCD4Bit(2);
char string[20];
int status;
unsigned long serialTimer = millis();

//// FUNCTIONS

void ShiftOut(int Value, int BitsCount) {
  for(int i = BitsCount; i >= 0; i--) {
    digitalWrite(CLK_pin, LOW);
    if ((Value >> i) & 1) {
      digitalWrite(DIO_pin, HIGH);
      //Serial.print("1");
    }
    else {
      digitalWrite(DIO_pin, LOW);
      //Serial.print("0");
    }
    digitalWrite(CLK_pin, HIGH);
    delayMicroseconds(1);
  }
//Serial.print(" ");
}

int ShiftIn(int BitsCount) {
  int ShiftIn_result;
    ShiftIn_result = 0;
    pinMode(DIO_pin, INPUT);
    for(int i = BitsCount; i >= 0; i--) {
      digitalWrite(CLK_pin, HIGH);
      delayMicroseconds(1);
      if (digitalRead(DIO_pin) == HIGH) {
        ShiftIn_result = (ShiftIn_result << 1) + 1; 
        //Serial.print("x");
      }
      else {
        ShiftIn_result = (ShiftIn_result << 1) + 0;
        //Serial.print("_");
      }
      digitalWrite(CLK_pin, LOW);
      delayMicroseconds(1);
    }
  //Serial.print(":");

// below is difficult to understand:
// if bit 11 is Set the value is negative
// the representation of negative values you
// have to add B11111000 in the upper Byte of
// the integer.
// see: http://en.wikipedia.org/wiki/Two%27s_complement
  if ((ShiftIn_result >> 11) & 1) {
    ShiftIn_result = (B11111000 << 8) | ShiftIn_result; 
  }


  return ShiftIn_result;
}

void HM55B_Reset() {
  pinMode(DIO_pin, OUTPUT);
  digitalWrite(EN_pin, LOW);
  ShiftOut(B0000, 3);
  digitalWrite(EN_pin, HIGH);
}

void HM55B_StartMeasurementCommand() {
  pinMode(DIO_pin, OUTPUT);
  digitalWrite(EN_pin, LOW);
  ShiftOut(B1000, 3);
  digitalWrite(EN_pin, HIGH);
}

int HM55B_ReadCommand() {
  int result = 0;
  pinMode(DIO_pin, OUTPUT);
  digitalWrite(EN_pin, LOW);
  ShiftOut(B1100, 3);
  result = ShiftIn(3);
  return result;
}


void setup() {
  Serial.begin(115200);
  pinMode(EN_pin, OUTPUT);
  pinMode(CLK_pin, OUTPUT);
  pinMode(DIO_pin, INPUT);

  lcd.init();
  lcd.commandWrite(0x0E); //curson on, display on, blink off

  HM55B_Reset();
}

void loop() {
  if (millis() - serialTimer > 2200 ) {

  //read compass and print data to lcd and serial out
  lcd.cursorTo(2,0);
  HM55B_StartMeasurementCommand(); // necessary!!
  //delay(40); // the data is 40ms later ready
  status = HM55B_ReadCommand();
  Serial.print(status); // read data and print Status
  sprintf(string, "%2d", status);
  lcd.printIn(string);
  Serial.print(" ");
  lcd.printIn(" ");
  X_Data = ShiftIn(11); // Field strength in X
  Y_Data = ShiftIn(11); // and Y direction
  Serial.print(X_Data); // print X strength
  sprintf(string, "%3d", X_Data);
  lcd.printIn(string);
  Serial.print(" ");
  lcd.printIn(" ");
  Serial.print(Y_Data); // print Y strength
  sprintf(string, "%3d", Y_Data);
  lcd.printIn(string);
  Serial.print(" ");
  lcd.printIn(" ");
  digitalWrite(EN_pin, HIGH); // ok deselect chip
  angle = 180 * (atan2(-Y_Data , X_Data) / M_PI); // angle is atan( -y/x) !!!
  Serial.print(angle); // print angle
  sprintf(string, "%4d", angle);
  lcd.printIn(string);
  Serial.println(" ");
  lcd.printIn(" ");
  
  // control motors with new pulse scheme
  // always pulse at start for 100ms
  // then, pulse for variable time depending on angle
  pulse_length = (angle*2000.0/180.0);
  lcd.cursorTo(1,0);
  lcd.printIn(" PuLn=");
  sprintf(string, "%4d    ", int(pulse_length));
  lcd.printIn(string);
  pinMode(VIB1_pin, OUTPUT);
  pinMode(VIB2_pin, OUTPUT);
  analogWrite(VIB1_pin, 255);
  analogWrite(VIB2_pin, 255);
  delay(100);
  if (pulse_length > 0)
  {
    analogWrite(VIB1_pin, 215);
    analogWrite(VIB2_pin, 215);
    delay(2000-int(pulse_length));
    analogWrite(VIB1_pin, 0);
    analogWrite(VIB2_pin, 0);
    delay(pulse_length);  // not actually necessary...
  }
  else
  {
    analogWrite(VIB1_pin, 0);
    analogWrite(VIB2_pin, 0);
    delay(-int(pulse_length));
    analogWrite(VIB1_pin, 215);
    analogWrite(VIB2_pin, 215);
    delay(2000+ int(pulse_length));
    analogWrite(VIB1_pin, 0);
    analogWrite(VIB2_pin, 0);
  }
  }
}

Plans for Next Hacking Session[edit]

  • Next meeting 10am on Thursday
  • We plan to get more motors going - at least 4; this will require moving/removal of LCD screen (which has been bloody useful for debugging!) in order to access more PWM pins on the arduino.

Anklethack-9.jpg

Stuff that would have been nice to have[edit]

  • "Third hand" for holding stuff while soldering.
  • Our RBBBs already! That's why we ordered them today.