First, we tested the long-range and short-range distance sensors, determining that it would be best to use short-range sensors since it was more important to accurately sense walls directly in front of the robot than to sense walls farther away in advance. We mounted our sensors on the right and left of our robot, using only two to conserve analog ports. After testing the wall sensors on the arduino, printing the analog values to serial, we were able to determine a “wall threshold” of 200 - if an analog read from a distance sensor is greater than this value, there is a wall.
To follow walls on the right of the robot we handle the following cases at each line intersection:
When we first attempted to integrate IR into our completed wall following sketch, we noticed that the wheels moved much slower after implementing our fft function fft_loop(), even though we were only calling this function at line intersections. Eventually, we determined that this was a result of the adc (used for the fft) interfering with analog reads (used for the wheel servos). To fix this issue, we modified our fft subroutine to reset the ADCSRA (adc control/status) register to 0b10000111 before returning, effectively taking the ADC out of free running mode, which allowed us to accurately perform analog reads and writes outside of an fft subfunction call. After fixing this problem, we once again called our fft_loop() at intersections, ensuring accuracy by performing a simple average of two values read from the desired bin before checking that it met a threshold determined in lab 2. If we do meet the threshold (and detect another robot), we avoid as if it is a wall. Our logic (an adaptation of our earlier wall following code) follows:
To visualize our results, we attached two LEDs: red to indicate sensing another robot, and green to indicate right wall sensing. Our logic for this addition was simple - we just used a digital write when the desired outcome was detected, and another to turn the LED off when no longer detected.
#define LOG_OUT 1 // use the log output function
#define FFT_N 256 // set to 256 point fft
#include <FFT.h>
#include <Servo.h>
//proto-declarations
void ir_init();
void mic_init();
int fft_loop( int freq, int bin );
void right90( int dir );
void left90 ( int dir );
int fft_two( int freq, int bin){
int fft_i = fft_loop(freq,bin);
fft_i += fft_loop(freq,bin);
return fft_i>>1;
}
Servo left ;
Servo right ;
int t = 0 ;
int leftOn = 180 ;
int rightOn = 0;
int off = 90 ;
int rightS = 0;
int leftS = 0;
int leftW = 0; //analog values, 0 to 1023, read off of sensors
int rightW = 0;
int frontW = 0;
int thresh = 800; //potential threshold value, to stay on the lines
int wallthresh = 160;
int irthresh = 100;
int count=0;
uint8_t wall = 0;
unsigned long timer = 0;
int rightSense = 1;
int leftSense = 0;
// mic variables
int rStart = 0xf0;
int initl = 0xe0;
int freq = 0x07;
int cutoff = 130;
int count_mic = 0;
void right90(int dir){
timer = millis();
right.write(dir*rightOn);
left.write(off);
delay(700);
while(analogRead(dir==1?leftSense:rightSense) > thresh);
delay(100);
while(analogRead(dir==1?leftSense:rightSense) < thresh);
timer = millis()-timer-50;
}
void left90(int dir){
timer = millis();
right.write(off);
left.write(dir*leftOn);
delay(700);
while(analogRead(dir==1?rightSense:leftSense) > thresh);
delay(100);
while(analogRead(dir==1?rightSense:leftSense) < thresh);
timer = millis()-timer-50;
}
void initServo(){
left.attach(3) ;
right.attach(5) ;
}
void deinitServo()
{
left.detach();
right.detach();
digitalWrite(3,0);
digitalWrite(5,1);
}
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
Serial.begin(9600) ;
//pinMode(3, OUTPUT) ;
mic_init();
while (fft_mic_loop(freq, 19) == 0);
Serial.println("starting servo");
initServo();
pinMode(13,OUTPUT);
digitalWrite(13,0);
// indicator LEDs
pinMode(6,OUTPUT); // red LED for IR sensing
pinMode(7,OUTPUT); // green LED for wall sensing
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(13,1);
rightS = analogRead(rightSense);
leftS = analogRead(leftSense);
if (rightS < thresh && leftS < thresh)
{ // go straight
rightW = analogRead(3) ;
leftW = analogRead(2) ;
wall |= (rightW > wallthresh) | ((leftW > wallthresh) << 1); //11 = both walls, 01 = right wall, 10 = left wall
if (rightW > wallthresh) {
// flash green LED
digitalWrite(7,HIGH);
right90(1);
frontW = analogRead(3);
if (frontW < wallthresh) {
right.write(180-rightOn);
left.write(off);
delay(timer);
right.write(off);
if(fft_two(0xf5, 42) > irthresh){
digitalWrite(6,HIGH);
if(leftW > wallthresh){
right.write(rightOn);
left.write(rightOn);
delay(700);
while(analogRead(leftSense) > thresh);
delay(100);
while(analogRead(leftSense) < thresh);
}
else{
right90(1);
}
digitalWrite(6,LOW);
}
else{
left.write(leftOn);
right.write(rightOn);
delay(400);
}
}
else if(leftW > wallthresh){
right.write(180-rightOn);
left.write(off);
delay(timer);
right.write(rightOn);
left.write(rightOn);
delay(700);
while(analogRead(leftSense) > thresh);
delay(100);
while(analogRead(leftSense) < thresh);
}
digitalWrite(7,LOW);
} else {
left90(1);
left.write(off);
if (fft_two(0xf5, 42) > irthresh ){
digitalWrite(6,HIGH);
frontW = analogRead(2) ;
left.write(180-leftOn);
delay(timer);
if(frontW < wallthresh){
left.write(leftOn);
right.write(rightOn);
delay(400);
}
else if (leftW > wallthresh){
right.write(rightOn);
left.write(rightOn);
delay(700);
while(analogRead(leftSense) > thresh);
delay(100);
while(analogRead(leftSense) < thresh);
}
else{
right90(1);
}
digitalWrite(6,LOW);
}
}
if(fft_two(0xf5, 42) > irthresh){
digitalWrite(6,HIGH);
while(fft_two(0xf5, 42) > irthresh){
left.write(off);
right.write(off);
delay(500);
}
digitalWrite(6,LOW);
}
wall = 0;
}
else if (rightS > thresh && leftS <= thresh)
{ // turn left??
left.write(off+5) ; //ccw slow down
right.write(rightOn) ; //ccw
}
else if (rightS <= thresh && leftS > thresh)
{ // turn left??
left.write(leftOn); //ccw
right.write(off-5); //ccw slow down
}
else
{ // go straight
left.write(leftOn);
right.write(rightOn);
}
}
void ir_init() {
//TIMSK2 = 0; // turn off timer2 for lower jitter
//ADCSRA = 0xe5; // set the adc to free running mode
ADMUX = 0x44; // use adc4
DIDR0 = 0x08; // turn off the digital input for adc0
}
void mic_init() {
//TIMSK0 = 0; // turn off timer0 for lower jitter
ADCSRA = initl | freq; // set the adc to free running mode
ADMUX = 0x45; // use adc5
DIDR0 = 0x01; // turn off the digital input for adc0
}
int fft_loop( int freq, int bin ) {
deinitServo();
//TIMSK2 = 0; // turn off timer2 for lower jitter
ADCSRA = 0xe5; // set the adc to free running mode
ADMUX = 0x44; // use adc4
DIDR0 = 0x08; // turn off the digital input for adc0
cli(); // UDRE interrupt slows this way down on arduino1.0
for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
while(!(ADCSRA & 0x10)); // wait for adc to be ready
ADCSRA = 0xf0 | freq; // restart adc
byte m = ADCL; // fetch adc data
byte j = ADCH;
int k = (j << 8) | m; // form into an int
k -= 0x0200; // form into a signed int
k <<= 6; // form into a 16b signed int
fft_input[i] = k; // put real data into even bins
fft_input[i+1] = 0; // set odd bins to 0
}
fft_window(); // window the data for better frequency response
fft_reorder(); // reorder the data before doing the fft
fft_run(); // process the data in the fft
fft_mag_log(); // take the output of the fft
sei();
//Serial.println("start");
//for (byte i = 0 ; i < FFT_N/2 ; i++) {
// Serial.println(fft_log_out[i]); // send out the data
//}
ADCSRA = 0b10000111;
int ret = fft_log_out[bin];
initServo();
return ret;
}
int fft_mic( int freq, int bin ) {
cli(); // UDRE interrupt slows this way down on arduino1.0
for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
while(!(ADCSRA & 0x10)); // wait for adc to be ready
ADCSRA = rStart | freq; // restart adc
byte m = ADCL; // fetch adc data
byte j = ADCH;
int k = (j << 8) | m; // form into an int
k -= 0x0200; // form into a signed int
k <<= 6; // form into a 16b signed int
fft_input[i] = k; // put real data into even bins
fft_input[i+1] = 0; // set odd bins to 0
//for (int ii = 0; ii < 500; ii+=1) {
// __asm__("nop\n\t");
//}
}
fft_window(); // window the data for better frequency response
fft_reorder(); // reorder the data before doing the fft
fft_run(); // process the data in the fft
fft_mag_log(); // take the output of the fft
sei();
return fft_log_out[bin];
}
int fft_mic_avg(int freq, int bin){
int fft_i = fft_mic(freq,bin);
fft_i += fft_mic(freq,bin);
fft_i += fft_mic(freq,bin);
fft_i += fft_mic(freq,bin);
return fft_i>>2;
}
int fft_mic_loop(int freq, int bin){
for(int l = 0; l < 4; l++){
if (fft_mic_avg(freq, bin) < cutoff) {
Serial.println("off");
return 0;
}
}
Serial.println("on");
ADCSRA = 0b10000111;
return 1;
}