Test and familiarize yourself with the sensors and signal processing needed for your robot to detect acoustic and optical signals and interface with the Arduino Uno. The Acoustic sub-team will work on the microphone circuit, which will detect a 660 Hz whistle blow, signifying the start of the maze mapping competition. The Optical sub-team will work on the IR sensor circuit, which will detect nearby robots emitting IR at 6.08 kHz and distinguish them from decoys emitting at 18 kHz.
To begin, we split into two groups of two. Each group progressed through the lab individually, as described below.
Both the Acoustic and Optical parts of this lab used Fast Fourier Transforms (FFT) to determine the frequency components of the sampled input signal from the sensors. For pure sinusoids, this is not so difficult, as one can simply read off the period in the time domain. However, for more complicated signals, it is not necessarily clear what frequencies are present, and certainly not clear if a given frequency is present. To make this process easier, a signal can be inspected in the frequency domain.
In the frequency domain, we can observe a signals “spectrum”. A spectrum is an interpretation of a signal which assigns a magnitude (an importance) to a given frequency. The standard way to compute this is with a Discrete Fourier Transform (DFT):
The DFT equation
The DFT computes a change of basis, assigning the weight X(k) to a given radial frequency (2*pi*k/N) by computing the inner product of the original signal with the complex exponential at that frequency.
Note that to compute one X(k) value, we need N multiplications, and N - 1 additions. To get useful information about a signal of size N, you generally need N values of k. This makes the DFT computation an O(n^2) operation, which can get very slow for large values of N.
To speed this process up, the Fast Fourier Transform (FFT) is used. The FFT is an algorithm for computing the DFT efficiently—the best speed up is achieved when N is a power of 2. The algorithm uses a “divide-and-conquer” method to compute the DFT. It first isolates the even and odd terms of the original DFT sum. Then it evaluates these sums as two independent FFTs of length N/2.
The FFT divide-and-conquer approach
FFT Butterfly diagram
A key to this process is that the odd sum gets transformed into a N/2 FFT by pulling out an overall constant phase. This process of splitting up into two FFTs can continue down all the way until you have reached a series of FFTs, each acting on only two values. This splitting action occurs log2(N) - 1 times. At each stage, there are N multiplications and additions, so our computational complexity has decreased to O(N * log2(N)).
The FFT algorithm was implemented using Open Music Labs Arduino FFT
Library. By default, the library takes in an analog signal from Arduino
pin A0, samples it at 256 equally spaced intervals, and returns an array
with 128 values, which represent the magnitude of the frequency content
for frequenices up to half of the samping frequency. Since the FFT of a real signal is
symmetric over zero, only half of the outputs are unique, and thus 128
bins are returned (not 256).
The FFT code can be modified to alter the performance of the ADC
(information from the ADC section of the ATmega328 datasheet [page 305]).
The important ADC characteristics are:
GOAL: use an Arduino and the FFT library to detect a 660 Hz whistle blow
Circuit from datasheet
Circuit on breadboard
Results from oscilloscope
void setup() {
Serial.begin(115200); // use the serial port
TIMSK0 = 0; // turn off timer0 for lower jitter - delay() and millis() killed
ADCSRA = 0xe7; // set the adc to free running mode, set prescaler=128 (default e5=32)
ADMUX = 0x40; // use adc0
DIDR0 = 0x01; // turn off the digital input for adc0
}
void loop() {
while(1) { // reduces jitter
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 = 0xf7; // restart adc --> set prescaler=f7=128 (default f5=32)
Circuit diagram
Breadboard circuit
Breadboard circuit
Microphone amplifier circuit FFT test results
/**
* [detect_660hz]
* OUTPUT = returns TRUE if a 660hz signal is detected by the Arduino,
* & FALSE otherwise
* Uses THRESHOLD to determine whether the tone is playing or not
*/
bool detect_660hz(){
byte * fft_log_out = get_fft_bins();
if (fft_log_out[17] > THRESHOLD && fft_log_out[18] > THRESHOLD) //bins 18 & 19, but 0 based so subtract 1
return true;
else
return false;
}
#include "mic.h"
#include "ir_hat.h"
int counter = 0;
void setup() {
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
fft_setup();
}
void loop() {
int count = 0;
Serial.println(detect_660hz());
if(detect_660hz())
counter++;
else
counter = 0;
if(counter>6)
digitalWrite(LED_BUILTIN, HIGH);
else
digitalWrite(LED_BUILTIN, LOW);
}
Demo:
GOAL: use an Arduino and the FFT library to detect another robot emitting IR at 6.08 kHz and ignore decoys (18 kHz)
Band-pass filter schematic (from Professor Shealy, ECE2100 course notes)
IR filter bode plot
Silence
IR Hat
IR Decoy
IR Hat + IR Decoy
Our concurrent testing software works as follows