Hack Notes CVA 090411

From Noisebridge
Revision as of 01:20, 12 April 2009 by Elgreengeeto (talk | contribs) (New page: (Skory's) Hacknotes 090411 =Hella Progress= *Remade the pager motor array on a ribbon cable without plastic crimps and added two more pager motors. **It's plenty comfortable now, but I d...)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

(Skory's) Hacknotes 090411

Hella Progress

  • Remade the pager motor array on a ribbon cable without plastic crimps and added two more pager motors.
    • It's plenty comfortable now, but I don't like the spacing of the motors. Nothing is ever perfect! I might add a ninth motor (although I've already trimmed the ribbon cable and doing that would definitly be non-trivial!) or possibly resort to resoldering a couple current ones in different positions.
  • Built (well, really my dad did most of the work because he's the one with a bandsaw) a plastic casing for the electronics. It definitely adds bulk, but it still fits in the external elastic pocket and there's no way I could wear this thing without protecting all that hard work.
  • Borrowed a socket for the battery connector from the Sparkfun charger (it has three sockets I only need one to charge a battery...)
  • Added timing to the code so motors don't just stay on forever if you aren't moving around. Currently it just counts iterations through the main loop, which I timed at about 22 cycles per second. I have it set to stay on any one motor for no more than about 10 seconds, and to buzz once a minute if you haven't moved. As long as you keep moving more than once every ten seconds it won't shut off. I might mess around later with having the buzz duration diminish with time if you continue to not move. Here's the code (sorry Eric it was too messy to leave your compass functions in there):
/* Skory & Eric
 * Compass Vibro-Anklet
 * We Rule, April 11, 2009
 */


/* Some code from:
 * 2009-03-24, pager motor test, lamont lucas

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


// define the pins used to run the shift registers 
int enable_low = 10;  //enable outputs, low = on
int serial_in  = 12; 
int ser_clear_low = 9;  //pulse low to zero out the shift buffer
int RCK  = 7;  //RCK, push the serial buffer to the outputs
int SRCK = 8;  //

#include <math.h>

//// define pins used to operate the digital compass (HM55B)
byte CLK_pin = 11;
byte EN_pin = 5;
byte DIO_pin = 4;

int X_Data = 0;
int Y_Data = 0;
int angle;
unsigned long counter = 0;
int prev_motor = 1;
int curr_motor = 1;
int status;
unsigned long serialTimer = millis();

int MotorStrength = 230;  // 255 = full power 

void setup() {
  pinMode(enable_low, OUTPUT);  // set shift register pins as outputs
  pinMode(serial_in, OUTPUT);
  pinMode(ser_clear_low, OUTPUT);
  pinMode(RCK, OUTPUT);
  pinMode(SRCK, OUTPUT);
  
  // use some serial for debugging
  Serial.begin(115200);
  Serial.println("Setting up board");
  
  // make sure we start out all off
  digitalWrite(enable_low, HIGH);
  // this should wipe out the serial buffer on the shift register
  digitalWrite(ser_clear_low, LOW);
  delay(100);   //delay in ms
  
  // the TPIC6b595 clocks work on a rising edge, so make sure they're low to start.
  digitalWrite(RCK, LOW);
  digitalWrite(SRCK, LOW);
  
  digitalWrite(ser_clear_low, HIGH);   //we are now clear to write into the serial buffer

  Serial.println("Board is setup");

  // setup for HM55B compass chip
  pinMode(EN_pin, OUTPUT);
  pinMode(CLK_pin, OUTPUT);
  pinMode(DIO_pin, INPUT);

  HM55B_Reset();

}


void loop() {
  // make the compass get a reading
  
  HM55B_StartMeasurementCommand(); // necessary!!
  delay(40); // the data is ready 40ms later
  status = HM55B_ReadCommand();
  Serial.print(status); // read data and print Status
  Serial.print(" ");
  X_Data = ShiftIn(11); // Field strength in X
  Y_Data = ShiftIn(11); // and Y direction
  X_Data = X_Data * -1;  // In current rig, chip
  Y_Data = Y_Data * -1;  // is upside-down; compensate
  Serial.print(X_Data); // print X strength
  Serial.print(" ");
  Serial.print(Y_Data); // print Y strength
  Serial.print(" ");
  digitalWrite(EN_pin, HIGH); // ok deselect chip
  angle = 180 * (atan2(-1 * Y_Data , X_Data) / M_PI); // angle is atan( -y/x) !!!
  if (angle < 0) angle = (360 + angle); //offset neg angles
  Serial.print(angle); // print angle
  Serial.println(" ");

  //Turn on the appropriate motor while keeping track of time
  curr_motor = CalcMotor(8, angle);
  if (curr_motor != prev_motor) { //if we changed angle enough
    TurnOnMotor(curr_motor);      //turn on the new motor
    counter = 0;                  //reset counter
  } else {
    if (counter < 250) {         //otherwise only keep
      TurnOnMotor(curr_motor);   //same motor on for
    } else {                     //less than 250 cycles
      TurnOnMotor(0);            //(it's ~22 cycles / second)
    }
    counter++;                   //increment counter
    if (counter > 1320){
      counter = 0;               //reset counter after ~1 min.
    }
  }
  prev_motor = curr_motor;

  Serial.println(counter);

/*  //Debug wacky motor wiring disorder  
  count++;
  TurnOnMotor(count);
  Serial.print(count); // print angle
  Serial.println("  ");
  delay(2000);
  if (count >= 8)
  {
    count = 0;
    delay(2000);
  }*/
  
  
}



//// FUNCTIONS

void TurnOnMotor(int which){
  // accept which from 1 to 8
  // send message to shift register as appropiate
  digitalWrite(enable_low, HIGH);
  delayMicroseconds(100);  //slow and steady
  Serial.print("Motor  ");
  Serial.println(which); // print angle
  switch(which){
    case 1:
      shiftOut(serial_in, SRCK, LSBFIRST, B00000100);
      break;
    case 2:
      shiftOut(serial_in, SRCK, LSBFIRST, B00000001);
      break;
    case 3:
      shiftOut(serial_in, SRCK, LSBFIRST, B00001000);
      break;
    case 4:
      shiftOut(serial_in, SRCK, LSBFIRST, B00000010);
      break;
    case 5:
      shiftOut(serial_in, SRCK, LSBFIRST, B00010000);
      break;
    case 6:
      shiftOut(serial_in, SRCK, LSBFIRST, B00100000);
      break;
    case 7:  // not used in current armature
      shiftOut(serial_in, SRCK, LSBFIRST, B01000000);
      break;
    case 8:  // not used in current armature
      shiftOut(serial_in, SRCK, LSBFIRST, B10000000);
      break;
    case 9:
      shiftOut(serial_in, SRCK, LSBFIRST, B11111111);
      break;
    case 10:
      shiftOut(serial_in, SRCK, LSBFIRST, B11110000);
      break;
    case 11:
      shiftOut(serial_in, SRCK, LSBFIRST, B00001111);
      break;
    default:
      // turn them all off
      shiftOut(serial_in, SRCK, LSBFIRST, B00000000);
  } 
  //in all cases, pulse RCK to pop that into the outputs
  delayMicroseconds(100);
  digitalWrite(RCK, HIGH);
  delayMicroseconds(100);
  digitalWrite(RCK, LOW);
  analogWrite(enable_low, 255-MotorStrength);
}




int CalcAngle(int howMany, int which)
{  // function which calculates the "switch to next motor" angle
  // given how many motors there are in a circle and which position you want
  // assume which is 1-indexed (i.e. first position is 1, not zero)
  // assume circle is 0-360, we can always offset later...
  
  return (360/howMany*(which-0.5));
}

int CalcMotor(int howMany, int angle)
{  // function to calculate which motor to turn on, given
  // how many motors there are and what the current angle is
  // assumes motor 1 = angle 0
  // assumes angle is from 0-360
  int i;
  for (i = 1; i<howMany;i++)
  {
    if ( (angle >= CalcAngle(howMany, i)) & (angle <= CalcAngle(howMany, i+1)) )
       return i+1; 
  } 
  // if we're still here, it's the last case, the loop over case, which
  // is actually motor 1 by assumption
  return 1;
}




//HM55B Functions

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

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; 
      }
      else {
        ShiftIn_result = (ShiftIn_result << 1) + 0;
      }
      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 & 1 << 11) == 1 << 11) {
    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;
}

  • I still really need to order all that stuff that we need to order already but haven't yet...