Lab 2: Analog circuitry and FFT

Goals

  • Design a microphone circuit that detects a 660Hz whistle blow signifying the beginning of maze mapping.
  • Design a circuit using an IR sensor to detect nearby robots emitting IR at 6.08kHz, and distinguish them from decoys emitting at 18kHz.

FFT Library

The FFT library basically computes the fourier transform of the input signal and returns the magnitudes of each frequency with frequencies based on the sampling rate and sample size. We decided to use another FFT library that we have more experience with, called “arduinoFFT”.


Robot Collision Avoidance and decoy detection

IR sensors

The IR circuit is shown below. The IR sensor acts like a switch: it’s open (high resistance) when no IR light is received.

IR Voltage with Oscilloscope

We measured the output voltage from our IR sensor with oscilloscope and viewed the FFT. The problem is that the robots IR oscillates at 6.08kHz fundamental frequency and its harmonics 12kHz, 18kHz, etc… . This is a problem because decoys also generate 18kHz light. So it might be hard to tell if decoy is there because it could be just a robot’s 18kHz frequency, but it’s much easier to tell if a robot is there because we can only check for the 6.08kHz oscillation. Note that if we can tell if a robot is there, we can just ignore the decoys and not react to them, and only stop when facing a robot.

Filtered IR signal

We decided to implement a RC low-pass filter with corner frequency slightly larger than 6.08kHz to detect the signal from the IR hat, filter out the decoys and account for some error. Ultimately we decided to find values of for a corner frequency of 7kHz. At first, we tried designing the filter with a fixed 100nF capacitor, which yielded a value of approximately 220Ω for the series resistor we needed to achieve the 7kHz frequency. We used the formula fc=1/(2πRC). However, these values didn’t filter out the 18kHz signal, so we decided to use a larger resistor (10kΩ), with a corresponding capacitor of approximately 2.2nF, which succeeded to filter the 18kHz decoy signal, and the harmonic components of the 6.08kHz IR hat. The filter was implemented as follows:

Amplification stage

The detection of the 6.08kHz signal and filtering of the 18kHz were successful, however the signals were noticeably different only at a short range of approximately 4 inches. Thus, we decided to design an amplification stage after the low pass filter, to detect the 6.08kHz signal at a greater distance. The amplification stage was designed as follows:

With this implementation, the sensing ability of the circuit increased significantly, as observed in the amplitude of the signal in the picture below:

Since the Arduino can’t handle negative voltages, we had to make sure to include a positive voltage offset. The IR sensor added a DC offset on its own, but since we couldn’t control it, we decided to include a series capacitor to eliminate that offset, and use a voltage divider to control the voltage we wanted at the positive input of the amplifier. We introduced an offset of approximately 2.5V, hence making sure that the signal would never take values underneath 0V.

Observe in the picture how the magnitude of the sensor readings of the 6.08kHz are significantly larger than the readings of the 16kHz at distances up to 9 inches. This ensures our little guy will detect other robots far enough that it will have time to avoid a collision.

Time for Arduino to shine

We used an analog pin on the Arduino to read the output signal after the amplification stage, so that we can use the data to trigger when our robot detects an IR hat. The code was implemented as follows:


(...)
void PrintVector(double *vData, uint16_t bufferSize, uint8_t scaleType)
{
  for (uint16_t i = 0; i < bufferSize; i++)
  {
    double abscissa;
    /* Print abscissa value */
    switch (scaleType)
    {
      case SCL_INDEX:
        abscissa = (i * 1.0);
	break;
      case SCL_TIME:
        abscissa = ((i * 1.0) / samplingFrequency);
	break;
      case SCL_FREQUENCY:
        abscissa = ((i * 1.0 * samplingFrequency) / samples);
	break;
    }
    Serial.print(abscissa, 6);
    if(scaleType==SCL_FREQUENCY)
      Serial.print("Hz");
    Serial.print(" ");
    Serial.println(vData[i], 4);
  }
  Serial.println();
}
						

Click here to see full code for this part


660Hz whistle blow detection

We designed and built the circuitry for this during lab 1. However, we didn’t set it to detect the 660Hz whistle blow. The FFT code was slightly modified to reflect the new threshold, as seen below:


void setup()
{
  sampling_period_us = round(1000000 * (1.0 / samplingFrequency));
  Serial.begin(115200);
  Serial.println("Hello 2300");
}

(...)

void compute(){
  FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);  /* Weigh data */
  FFT.Compute(vReal, vImag, samples, FFT_FORWARD); /* Compute FFT */
  FFT.ComplexToMagnitude(vReal, vImag, samples); /* Compute magnitudes */
  f = FFT.MajorPeak(vReal, samples, samplingFrequency); //find the dominant frequency
  mag = vReal[(int)(f * samples / samplingFrequency)]; //find the magnitude of dominant frequency
}	
						

Click here to see full code for this part

The following video shows the detection of the 660Hz signal:


New Mechanical Design!!

In order to improve the robustness of our robot we designed and used Ian’s 3D printer to make a custom robot frame. This design holds all of our components in place where we would want them and also allows for future flexibility through its many mounting points.