This code accomplishes the same thing the first generation of code had done, except more efficiently. Efficiently in that less wires go to the Arduino. Here, I added a servo controller along with an Input/Output expander made of Multiplexers (4051's). There is smaller versions of these codes as well as wiring documents on the previous page that better explains each. The end accomplishment though is that 18 servos and 18 sensors can be run off of 2 pins (five address pins, one transmit pin, and two outputs) of the Arduino, excluding power and ground.

/*reader pin 
*/
#include <SoftwareSerial.h>

SoftwareSerial Servos(10, 11); // RX is digital pin 10 (connect to TX of other device) * TX is digital pin 11 (connect to RX of other device)--we only need to connect pin 11

int n;//first random number
int m;//second random number
int threshold=30;//of ambient light
int targets=6;
int score=0;//initialized to 0
int time=1000;//time to hit target once it pops up
int TIME=60000;//total time for game==1 minute--and yes 60000 fits into an int
int TIME_Played=0;//initialize time played

int anodePin=4;//all led's use this pin for their long leg

int Apin=14;//A0
int Bpin=15;//A1
int Cpin=16;//A2
int Dpin=17;//A3
int Epin=18;//A4
int cathodePin0=19;//A5

int A;
int B;
int C;
int D;
int E;

int delays[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};  //starts all delays at 0
int tworandom(int i,int j);//random funcition generator for second number
int reads(int led);//read led
int readsavg(int n, int led);//takes average of n readings for led
int reset(int servonum);//initialize current servo, reset delay of current servo, assign a new serov to n or m
int scores(int servonum);//score when you shoot (shooting aliens==++)
int scored(int servonum);//score when you don't shoot (don't shoot humans==++)

void talk(int command, int servo, int data1, int data2);
void rotate(int servo,int angle);
void initialize(void);//sets initial servo positons

int convert(int i);
void setup()
{
  
  //deactivates pullup resistors
  _SFR_IO8(0x35) |= 4;
  _SFR_IO8(0x35) |= (1<<4); 
  
  randomSeed(analogRead(0));//select start point of random number chain before setting pin A0 to output--reading analog should allow for random start in chain--wiring led to there may get rid of random start--will just cause every game to be the same--will change for final design, but for this week it would not be a problem
  n=random(targets);  //choose first random number
  m=tworandom(n,m);  //choose second random number based off of the first
  
  
  pinMode(anodePin, OUTPUT);  //set pins associated with led light sensors to outputs
  pinMode(Apin, OUTPUT);
  pinMode(Bpin, OUTPUT);
  pinMode(Cpin, OUTPUT);
  pinMode(Dpin, OUTPUT);
  pinMode(Epin, OUTPUT);
  pinMode(cathodePin0, OUTPUT);
  
  
  digitalWrite(anodePin, HIGH);
  digitalWrite(cathodePin0,LOW);
  
  digitalWrite(Apin,LOW);
  digitalWrite(Bpin,LOW);
  digitalWrite(Cpin,LOW);
  digitalWrite(Dpin,LOW);
  digitalWrite(Epin,LOW);
  
  
  initialize();
  
  Serial.begin(9600);//set up serial communication to monitor
  Servos.begin(9600);
}

void loop(){
  rotate(m,0);//pop up the first two servos
  rotate(n,0);
  Serial.print("n and m are");
  Serial.print(n);
  Serial.println(m);
  int number=3;//number of times led is read
  //all delays initialized at 0 or reset to 0 in "reset"
  delays[m]=delays[m]+(2*number*50);//each read delays 50 so n times 50 is full delay
  delays[n]=delays[n]+(2*number*50);
  //read sensors
  int i = readsavg(number, n);//servo will be 0 to 5 but led is 14 to 19
  int j = readsavg(number, m);

  if((i<threshold)&&(i>0)){
    //you hit target n
    Serial.println("You hit n");
    scores(n);
    n=reset(n,m);
    /*delaysn=0;
    initialize(n);
    n=tworandom(m);//*/
  }
  if((j<threshold)&&(j>0)){
    Serial.println("You hit m");
    //you hit target m
    scores(m);
    /*delaysm=0;
    initialize(m);
    m=tworandom(n);*/
    m=reset(m,n);
  }
  if((delays[n]>time)&&(delays[m]>time)){
    Serial.println("ran out of time 0");
    /*delaysn=0;
    delaysm=0;
    initialize(m);
    initialize(n);
    n=random(targets);  //choose first random number
    m=tworandom(n);  //choose second random number based off of the first*/
    n=reset(n,m);
    m=reset(m,n);
  }
  if(delays[n]>time){
    Serial.println("ran out of time 1");
    //you ran out of time for target n
    scored(n);
    /*delaysn=0;
    initialize(n);
    n=tworandom(m);//*/
    n=reset(n,m);
  }
  if(delays[m]>time){
    Serial.println("ran out of time 2");
    //you ran out of time for target m
    scored(m);
    /*delaysm=0;
    initialize(m);
    m=tworandom(n);*/
    m=reset(m,n);
  }
  TIME_Played=TIME_Played+(2*number*50);
  if(TIME_Played<TIME){
    Serial.print("Game over.  Your score is");
    Serial.print(score);
    while(1){
      
    }
  }
}
//////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
///////////////////////////////////////////////////////
int tworandom(int i,int j){
    //i is the number staying the same j is the one you are changing
  //chooses second random number that is not the same as the fist or equal to that of its pair
  int k=0;
  k=random(targets);//not redundant--if i is not in the first position setting m to 0 at first would cause it to be 0 almost always
  while(((k%(targets/2))==(i%(targets/2)))||(k==j)){
    /*((k-3)==i)||(k==i)||((k+3)==i)||(k==j)*/
    k=random(targets);
  }
  return k;
}                            
  
int reads(int led){
  int val = 0;
  int vcc=anodePin;
  convert(led);//get address of led
  //set multiplexer's to read that address
  digitalWrite(Apin, A);
  digitalWrite(Bpin, B);
  digitalWrite(Cpin, C);
  digitalWrite(Dpin, D);
  digitalWrite(Epin, E);
  
  digitalWrite(vcc,   HIGH);
  digitalWrite(cathodePin0, LOW);
  
  /*Serial.print(A);
  Serial.print(B);
  Serial.print(C);
  Serial.print(D);
  Serial.println(E);*/
  
  //already emitting light
  
  delay(50);
  
  //switch potentials -- charge LED to -5V
  digitalWrite(vcc,   LOW);
  digitalWrite(cathodePin0, HIGH);
  
  //measure time for potential to equalize (for cathode to be LOW)
  
  //switch pinmode 
  pinMode(cathodePin0,  INPUT);
  
  //measure time it takes for cathodePin to go to zero
  //this value probably depends on the chip clock or something
  while((digitalRead(cathodePin0) != 0)&&(val<100)){
    delay(1);
    val++;      
  }
  pinMode(cathodePin0,  OUTPUT);
  
  digitalWrite(vcc,   HIGH);
  digitalWrite(cathodePin0, LOW);
  //Serial.println(val, DEC);
  return val;
}

int readsavg(int n, int led){
  int val=0;
  for(int i=0; i<n; i++){
    val=val+reads(led);//read n times and sum
  }
  val=val/n;//divide by n for average
  return val;
}
  
int reset(int servonum1, int servonum2){
  rotate(servonum1,90);//reset to position
  delays[servonum1]=0;//reset delays
  int j=tworandom(servonum2,servonum1);//change 1 based on 2
}  

int scores(int servonum){
  //scores==score when shot
  if(servonum<=(targets/2)){
    //servos 0, 1, 2 are humans
    score--;//don't shoot humans 
  }
  if(servonum>((targets/2))){
    //servos 3, 4, 5 are aliens
    score++;//do shoot aliens
  }
}
int scored(int servonum){
  //scored==scored when did not shoot
  if(servonum<=(targets/2)){
    //servos 0, 1, 2 are humans
    score++;//good you did not shoot the humans
  }
  if(servonum>((targets/2))){
    //servos 3, 4, 5 are aliens
    score--;//baka, you forgot to shoot the aliens--have you seen Independence Day?
  }
}

//////////////////////
////////////////////
//Servo Controller
void talk(int command, int servo, int data1, int data2){  
/*
This uses the pololu portocol for controlling the servos--the shorting block must be removed for 
these commands to work--I say this twice, because it is important.
The data 1 is lsb and data 2 is msb, it ignores the first bit, and the units in 1/4 micro seconds.
For example, the code uses 0x70, 0x2E->in binary 00111000, 00101110 to indicate 6000 1/4 micro seconds, which is  lsb:  0111000, msb:  
0101110, but together in proper oder reads as 0x1770.  
This is further 1500 microseconds which is the 90 degree position--The conversion from degrees to microseconds is covered below.
*/
  Servos.write(0xAA);  //start byte
  Servos.write(0x0C);  //device id which is 12 in decimal for the 24 serial servo controller
  Servos.write(command); //command number
  Servos.write((byte)servo);  //servo number (0-23)
  Servos.write((byte)data1);  //data 1--lsb--lowest 7 bits
  Servos.write((byte)data2);  //data 2--msb--highest 7 bits
  delay(75);
}

/*  I made this cheat sheet of postions and inputs until a proper conversion was found,
it discusses how to convert from degrees to microseconds and then to proper bits need to be sent:

Microseconds are found by multiplying by 11 and then adding 500 to degrees--remember that the controller
takes ins quarter of a microsecond (four times this number) though and discrads the 
first bit of data of each data byte (i.e. send the lowest 7 bits with a leading 0 and then
the highest 7 bits with a leading 0)

The afore said covnversion is found by noting that the signals to the servo controller vary
from 500 (0) to 2500 (180).  Thus to get zero subtract 500.  To get everything else divide 2000 by 180.
The result is not exactly 11, but the error is very slight.

(microseconds--least significant bit, most significant bit)
500--0X50,0X0F->about 0 degrees
700--0X0F,0X15->18
750--0X38,0X17->22
800--0X00,0X19->27
1000--0X20,0X1F->45
1200--0X40,0X25->63
1500--0X70,0X2E->about 90 degrees
1800--0X20,0X38->118
2500--0X10,0X4E->about 180 degrees
*/

/////////////////////////////////////////////////////

void rotate(int servo,int angle){
  //Uses talk() to send servo to some angle
  int converted=(angle*11+500)*4;//in quarter microseconds
  int data2=converted>>7;//most significant bit
  int data1=converted&0x7F;//least significant bit
  
  talk(0x04, servo, data1, data2);//sends data
}

void initialize(void){
  //set all servos to an inital 90 degrees.  Allows for rotation in either direction of 90 degrees
  for(int i=0; i<targets; i++){
    rotate(i,90);
  }
  delay(250);
}

int convert(int i){
  //converts a decimal number from 0 to 17, inclusively, to binary
  A=i/16;
  if(A==1){
    i=i-16;
    B=0;
    C=0;
    D=0;
    E=i;
  }
  if(A==0){
    B=i/8;
    if(B==1){
      i=i-8;
      C=i/4;
      if(C==1){
        i=i-4;
        D=i/2;
        if(D==1){
          i=i-2;
          E=i;
        }
        if(D==0){
          E=i;
        }
      }
      if(C==0){
        D=i/2;
        if(D==1){
          i=i-2;
          E=i;
        }
        if(D==0){
          E=i;
        }
      }
    }
    if(B==0){
      C=i/4;
      if(C==1){
        i=i-4;
        D=i/2;
        if(D==1){
          i=i-2;
          E=i;
        }
        if(D==0){
          E=i;
        }
      }
      if(C==0){
        D=i/2;
        if(D==1){
          i=i-2;
          E=i;
        }
        if(D==0){
          E=i;
        }
      }
    }
  }
}
 
classes/designandproto/me155a_groups/second_generation_of_the_game.txt · Last modified: 2013/03/08 20:04 by nmitchell
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki