Hack Notes CVA 090712: Difference between revisions

From Noisebridge
Jump to navigation Jump to search
No edit summary
No edit summary
 
Line 12: Line 12:
*First design failure: with the extra clip on, the motor jack does not fit. (The oversize tabs on the clip stick into the edge of the enclosure.) They are not necessary anyway, so the world is not ended.
*First design failure: with the extra clip on, the motor jack does not fit. (The oversize tabs on the clip stick into the edge of the enclosure.) They are not necessary anyway, so the world is not ended.
*Second design failure: the power plug is backwards! The CENTER must be GROUND for it to wor know. Don't know how this happened, and it is annoying.
*Second design failure: the power plug is backwards! The CENTER must be GROUND for it to wor know. Don't know how this happened, and it is annoying.
<pre>
/* Skory & Eric
July 12, 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 register
int enable_low = 3;
int serial_in  = 7;
int ser_clear_low = 5;
int RCK  = 4;
int SRCK = 6;
// define pins for transitors
int transistor_1 = 14; //14 = A0
int transistor_2 = 15; //15 = A1
#include <math.h>
//// define pins used to operate the digital compass (HM55B)
byte CLK_pin = 10;
byte EN_pin = 9;
byte DIO_pin = 8;
int X_Data = 0;
int Y_Data = 0;
int angle;
int status;
//timing vars
unsigned long counter = 0;
int prev_motor = 1;
int curr_motor = 1;
int cycles_per_second = 15; //board and compass specific - must measure
int count;
int activity = 100;
int max_activity = 200;
unsigned long serialTimer = millis();
int max_motor_strength = 220;  // 255 = full power
int min_motor_strength = 90; //point under which motors don't run or are unfeelable
int motor_strength = 210; // holds changing motor strength vals
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);
 
  //set transistors as digital outputs
  pinMode(transistor_1, OUTPUT);
  pinMode(transistor_2, OUTPUT);
  digitalWrite(transistor_1, HIGH); //keep T1 high to control just 8 motors
 
  // use some serial for debugging
  Serial.begin(57600);
  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 TPIC6 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();
  //set intial motor strength
  analogWrite(enable_low, 255-max_motor_strength);
}
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: ");
  Serial.print(X_Data); // print X strength
  Serial.print(" Y: ");
  Serial.print(Y_Data); // print Y strength
  Serial.print(" ANG: ");
  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.print(" ");
  //Turn on the appropriate motor while keeping track of time and varying motor strength
  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
    if (activity < max_activity){
    activity = activity + 1;      //increase activity level up to 200
    motor_strength = (((float)activity / (float)max_activity) * (max_motor_strength - min_motor_strength) + min_motor_strength); //set m_strength proportianately to activity
    }   // within range of min_ms-max_mas
  } else {   //if angle hasn't changed
    if (counter < (activity / 10) * cycles_per_second) { //only keep same motor on for
analogWrite(enable_low, 255-motor_strength); //less than cycles * activity level
      TurnOnMotor(curr_motor);
  while (motor_strength < ((float)activity / (float)max_activity) * (max_motor_strength - min_motor_strength) + min_motor_strength){  //if m_strength is low (motors off)
motor_strength++; //crescendo the m_strength
    Serial.print(" MS: ");
Serial.println(motor_strength);
analogWrite(enable_low, 255-motor_strength);
delay(50);
  }
    } else { //if counter runs to upper limit
  while (motor_strength > 50){ //if m_strength is high (motors on)
    motor_strength--; //decrescendo the m_strength
    analogWrite(enable_low, 255-motor_strength); //50 seems like point motor
    Serial.print(" MS: "); //stops running
Serial.println(motor_strength);
delay(50);
  }
      TurnOnMotor(0);            //then turn all motors off
    }
    counter++;                  //increment counter
    if (counter > (600 * cycles_per_second) / activity ){
      counter = 0;              //reset counter
      if (activity > 13){        //lower activity level
      activity = activity - 13;  //max val(s) 0-12
      }
    }
  }
 
  analogWrite(enable_low, 255-motor_strength);
  prev_motor = curr_motor;
  Serial.print("ACT: ");
  Serial.print(activity);
  Serial.print(" CNT: ");
  Serial.print(counter);
 
  Serial.print(" MS: ");
  Serial.println(motor_strength);
 
//  Serial.print("counter: ");
//  Serial.print(counter);
//  Serial.print(" activity: ");
//  Serial.println(activity);
 
/*
//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 5:
      shiftOut(serial_in, SRCK, LSBFIRST, B00000010);
      break;
    case 6:
      shiftOut(serial_in, SRCK, LSBFIRST, B00000001);
      break;
    case 7:
      shiftOut(serial_in, SRCK, LSBFIRST, B00000100);
      break;
    case 8:
      shiftOut(serial_in, SRCK, LSBFIRST, B00001000);
      break;
    case 1:
      shiftOut(serial_in, SRCK, LSBFIRST, B10000000);
      break;
    case 2:
      shiftOut(serial_in, SRCK, LSBFIRST, B01000000);
  break;
    case 3:
      shiftOut(serial_in, SRCK, LSBFIRST, B00100000);
      break;
    case 4:
      shiftOut(serial_in, SRCK, LSBFIRST, B00010000);
      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);
}
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;
}
</pre>


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

Latest revision as of 02:54, 14 July 2009

hack notes 090712[edit]

Our v1.0 boards are in! Here are some notes from initial testing:

  • Everything solders in fine, nothing too notable. Start with shorter things and move to taller. Care must be taken to solder compass sockets in the correct order.
  • Code uploaded fine, but there were no compass readings the first time
    • Solved:
    • No compass readings was due to having the compass headers on the backwards! (The de-soldering of which led to the pulling out of a pad and holy sheisse was that an hour long pain in the ass to fix!). So, 2x3 header must be ON TOP and the 1x3 ON BOTTOM of the board. The compass is then oriented with the "RoHS" facing towards the center of the board. In future, the pin labeled "1" on the bottom of the HM55B should be matched with a "1" on our silk screen.
  • Added code to set T1 to high all the time.
    • A0 as digital out is pin 14, A1 is pin 15
  • LED testing thing works as well as it should. (Needs to be re-built for new 16 motor design.)
  • First design failure: with the extra clip on, the motor jack does not fit. (The oversize tabs on the clip stick into the edge of the enclosure.) They are not necessary anyway, so the world is not ended.
  • Second design failure: the power plug is backwards! The CENTER must be GROUND for it to wor know. Don't know how this happened, and it is annoying.
/* Skory & Eric
July 12, 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 register
int enable_low = 3;
int serial_in  = 7;
int ser_clear_low = 5;
int RCK  = 4;
int SRCK = 6;

// define pins for transitors
int transistor_1 = 14;		//14 = A0
int transistor_2 = 15;		//15 = A1

#include <math.h>

//// define pins used to operate the digital compass (HM55B)
byte CLK_pin = 10;
byte EN_pin = 9;
byte DIO_pin = 8;
int X_Data = 0;
int Y_Data = 0;
int angle;
int status;

//timing vars
unsigned long counter = 0;
int prev_motor = 1;
int curr_motor = 1;
int cycles_per_second = 15; //board and compass specific - must measure
int count;
int activity = 100;
int max_activity = 200;

unsigned long serialTimer = millis();

int max_motor_strength = 220;  // 255 = full power
int min_motor_strength = 90; //point under which motors don't run or are unfeelable
int motor_strength = 210; // holds changing motor strength vals

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);
  
  //set transistors as digital outputs
  pinMode(transistor_1, OUTPUT);
  pinMode(transistor_2, OUTPUT);
  digitalWrite(transistor_1, HIGH);	//keep T1 high to control just 8 motors
  
  // use some serial for debugging
  Serial.begin(57600);
  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 TPIC6 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();

  //set intial motor strength
  analogWrite(enable_low, 255-max_motor_strength);

}


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: ");
  Serial.print(X_Data); // print X strength
  Serial.print(" Y: ");
  Serial.print(Y_Data); // print Y strength
  Serial.print(" ANG: ");
  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.print(" ");


  //Turn on the appropriate motor while keeping track of time and varying motor strength
  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
    if (activity < max_activity){
    activity = activity + 1;      //increase activity level up to 200
    motor_strength = (((float)activity / (float)max_activity) * (max_motor_strength - min_motor_strength) + min_motor_strength); //set m_strength proportianately to activity
    }									   // within range of min_ms-max_mas
  } else {						  //if angle hasn't changed
    if (counter < (activity / 10) * cycles_per_second) { //only keep same motor on for
	analogWrite(enable_low, 255-motor_strength);		 //less than cycles * activity level
      TurnOnMotor(curr_motor);
	  while (motor_strength < ((float)activity / (float)max_activity) * (max_motor_strength - min_motor_strength) + min_motor_strength){  	//if m_strength is low (motors off)
		 motor_strength++;						//crescendo the m_strength
	     Serial.print(" MS: ");
		 Serial.println(motor_strength);
		 analogWrite(enable_low, 255-motor_strength);
		 delay(50);
	  }
    } else {									//if counter runs to upper limit
	  while (motor_strength > 50){				//if m_strength is high (motors on)
	     motor_strength--;						//decrescendo the m_strength
	     analogWrite(enable_low, 255-motor_strength); //50 seems like point motor
	     Serial.print(" MS: ");					//stops running
		 Serial.println(motor_strength);
		 delay(50);
	  }
      TurnOnMotor(0);            				//then turn all motors off
    }
    counter++;                   //increment counter
    if (counter > (600 * cycles_per_second) / activity ){
      counter = 0;               //reset counter
      if (activity > 13){        //lower activity level
      activity = activity - 13;  //max val(s) 0-12
      }
    }
  }
  
  analogWrite(enable_low, 255-motor_strength);
  prev_motor = curr_motor;

  Serial.print("ACT: ");
  Serial.print(activity);

  Serial.print(" CNT: ");
  Serial.print(counter);
  
  Serial.print(" MS: ");
  Serial.println(motor_strength);
  

//  Serial.print("counter: ");
//  Serial.print(counter);
//  Serial.print(" activity: ");
//  Serial.println(activity);
  
/*
//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 5:
      shiftOut(serial_in, SRCK, LSBFIRST, B00000010);
      break;
    case 6:
      shiftOut(serial_in, SRCK, LSBFIRST, B00000001);
      break;
    case 7:
      shiftOut(serial_in, SRCK, LSBFIRST, B00000100);
      break;
    case 8:
      shiftOut(serial_in, SRCK, LSBFIRST, B00001000);
      break;
    case 1:
      shiftOut(serial_in, SRCK, LSBFIRST, B10000000);
      break;
    case 2:
      shiftOut(serial_in, SRCK, LSBFIRST, B01000000);
	  break;
    case 3:
      shiftOut(serial_in, SRCK, LSBFIRST, B00100000);
      break;
    case 4:
      shiftOut(serial_in, SRCK, LSBFIRST, B00010000);
      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);
}




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;
}