The purpose of this lab is to spin the servo to find an IR emitter, which is in the center of a target. Once the IR emitter has been located, the goal is to fire a laser at the center of the target. The robot could be in any position, such that the target could be anywhere in a 180 degree range in front of the robot.
First we were asked to make an algorithm based on the recorded data of the servo making a sweep.
Here is an example of what the robot sees when it sweeps its servo
Note: We are using a moving average. As a result, we have to account for the error in degrees. The lowest point is not seen right away. Rather, it must make its way through the moving average first.
Since we are using a moving average of size 4, it is off by about two degrees. You will see corrections for this n our code.
Our basic idea for code is:
void target() {
delay(200); //wait for button to lift
if (!myservo.attached()) myservo.attach(servoPin);
myservo.write(0); //move servo to beginning
long now=millis();
while(millis()-now<2000); //wait for it to get there
//setup moving average for readings
int iravg[4] = {0,0,0,0};
int total=0;
for (byte i=0; i<4;i++) total+=iravg[i]=analogRead(analogIRPin);
byte iravgindex=0;
int lowestDegree=0; //for keeping track of the lowest point
int readings[180]; //keeps every reading so we don't have to sweep again
for (byte degree=0;degree<180;degree++) { //for every degree
myservo.write(degree); //move the servo to that degree
now=millis();
while(millis()-now<20); //wait for it to get there
//update the moving average
total=total-iravg[iravgindex]+(iravg[iravgindex]=analogRead(analogIRPin));
iravgindex=(iravgindex+1)%4;
readings[degree]=analogIRSensor=total/4; //and store that reading
if (readings[degree]<readings[lowestDegree]) lowestDegree=degree; //if the new reading is lower, save it
if (useSave) saveData(useSave); //logs data if enabled
}
myservo.write((lowestDegree-4<0)?0:lowestDegree-4); //go to lowest point. -4 accounts for moving average.
now=millis();
while(millis()-now<2000); //delay for servo to get there
digitalWrite(laserPin, HIGH); //turn on laser
now=millis();
while(millis()-now<5000); //for five seconds
digitalWrite(laserPin, LOW); //and turn it off again.
//code for 2nd and 3rd targets. simply a repeat of what's above without the servo sweep.
for (int i =0; i<2; i++) {
while (digitalRead(button)==LOW) digitalWrite(ledPin, HIGH); //the light comes on when it's ready for the next pass
digitalWrite(ledPin,LOW); //after button is pressed, turn off the light and cont.
for (byte index=((lowestDegree-15<0)?0:lowestDegree-15); index<((lowestDegree+15>180)?180:lowestDegree+15); index++)
readings[index]=1000; //fill in array +/- 15 degrees on either side of the previous lowest point.
lowestDegree=0;
for (byte degree=0;degree<180;degree++) {
if (readings[degree]<readings[lowestDegree]) lowestDegree=degree; //find the new lowest point
if (useSave) saveData(useSave); //log data
}
myservo.write((lowestDegree-4<0)?0:lowestDegree-4); //go to lowest point. -4 accounts for moving average.
now=millis();
while(millis()-now<2000); //delay for servo to get there
digitalWrite(laserPin, HIGH); //turn on laser
now=millis();
while(millis()-now<5000); //for five seconds
digitalWrite(laserPin, LOW); //and turn it off again.
}
servoOff();
currentMenu = draw; //back to main menu
}
Could we do it with three targets? Watch below to find out.