I'm not sure where to begin, but I'll describe a project I've been trying to wrap my head around for the past couple of weeks.
I've been tasked with implementing essentially a frequency detector using arduino. The concept is I have a red laser pointer (650 ish nanometers) and I shine it onto a mirror that reflects the laser onto a photodiode. For the purposes of this project, I have this CJMCU-101 breakout board for the OPT101
photodiode.
Now, the catch is that this mirror is attached to a bluetooth speaker, which vibrates at any frequency I want from my phone. The idea is that by vibrating the mirror at some frequency, let's say 440Hz for now, the photodiode will pick up the frequency of the laser and I can modulate it, run it through an FFT or some spectrum analyzer on a microcontroller, and display the frequency of the light wave vibrating at 440Hz.
What hardware could I use for my setup? What software would I need?
I read online that an Arduino probably can't handle the frequency analysis, so I might need something beefier or I can just serial connect to matlab from my pc.
I moved your topic to an appropriate forum category @jim_stuart.
In the future, please take some time to pick the forum category that best suits the subject of your topic. There is an "About the _____ category" topic at the top of each category that explains its purpose.
If the mirror displaces the laser beam from being centered on the photodiode, you should be able to measure intensity differences, and it will be no problem to use FFT to analyze the audio frequencies associated with those differences.
Software depends on what Arduino you have. The OpenMusicLabs FFT works on AVR-based Arduinos like the Uno R3 and is the fastest for the class, while the ArduinoFFT library works best with newer Arduinos with faster CPU clocks and more memory.
However, it is a simple matter of fact the frequency of an amplitude modulated light beam DOES change, just as in radio communications, but indetectably so with Arduino.
In my current inventory, I only have the Arduino Uno R3, or the Arduino Nano V3 from Lafvin. I also have some ESP32-WROOMs, but for the purposes of the project, I've been tasked with keeping the hardware to Arduino only.
Apologies for not making it clear in my original post. But as far as detecting the laser beam, the only parameters I was given is that a sound/note is being played by an app called GarageBand on my phone from a MIDI keyboard to the bluetooth speaker.
Not sure if the CJMCU-101 is enough, but I'm open to buy any other light frequency sensors. Just has to be compatible with Arduino. Whatever light frequency sensor I choose to use, it just needs to be able to detect the frequency of the bluetooth speaker playing the note.
And to display the frequency the arduino is detecting, I can just display it on an LCD screen.
That is based on the OPT101 photodiode/amplifier, which has a detection bandwidth of 14 kHz. So it should be fine for picking up audio frequency variations in the received intensity of the laser beam.
From the OPT101 data sheet, you can see that the detector responds to the entire visible light spectrum and part of the near-infrared.
Alright so I've made some progress. I looked on this website to see how I can wire my arduino sensor to the CJMCU-101 board here.
According to the data sheet, I can also include an external capacitor in parallel on the "1M" line on the CJMCU-101. I'm not sure what for, but I presume it's for signal filtering.
So here's a schematic of what I setup so far on a breadboard. It seems to work so far since I'm getting some kind of output on the serial monitor:
I also borrowed some code from the ArduinoFFT library to perform an FFT and get the peak frequency. The code does not work; I'm getting a peak value of around 3.92Hz consistently even though I shine the modulated laser beam onto the OPT-101. I'm definitely sure I'm doing something wrong, but I pretty much copied and pasted from the ArduinoFFT examples.
Here's my code:
#include <arduinoFFT.h>
#define SAMPLES 512 // Number of samples (must be a power of 2)
#define SAMPLING_FREQUENCY 2000 // Sampling frequency in Hz
#define sensor 8
ArduinoFFT<double> FFT = ArduinoFFT<double>(); // FFT object
unsigned int samplingPeriod;
unsigned long microseconds;
double vReal[SAMPLES];
double vImag[SAMPLES];
// Change to your photosensor analog pin
int N = SAMPLES / 2;
double sum = 0.0;
double dcOffset = 0.0;
void setup() {
Serial.begin(115200);
samplingPeriod = round(1000000 * (1.0 / SAMPLING_FREQUENCY));
pinMode(sensor, INPUT);
for (int i = 0; i < SAMPLES; i++) {
sum += analogRead(sensor);
}
dcOffset = sum / SAMPLES;
// Store DC offset for use in loop
Serial.print("DC Offset: ");
Serial.println(dcOffset);
}
void loop() {
// Collect data from the photosensor
for (int i = 0; i < SAMPLES; i++) {
microseconds = micros(); // Track time
vReal[i] = analogRead(sensor) - dcOffset; // Read light sensor value
vImag[i] = 0; // Imaginary part is 0 for real input data
while (micros() < (microseconds + samplingPeriod)) {
// Wait for the next sampling period
}
}
// Perform FFT
FFT.windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD); // Apply window function
FFT.compute(vReal, vImag, SAMPLES, FFT_FORWARD); // Compute FFT
FFT.complexToMagnitude(vReal, vImag, SAMPLES); // Compute magnitudes
double peak = FFT.majorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY);
Serial.print("Peak Frequency: ");
Serial.println(peak);
delay(1000);
}
The 3.92 value may be a DC offset on the analog input. The peak search function is not useful, unless you already know that the setup is working properly, and what to expect.
However, you are getting way ahead of yourself. The first thing to do is to just print analogRead() values and determine if the sensor responds to light, and changes in light intensity.
Use the Arduino Serial Plotter to graph those values in real time, as you wave your hand through the beam.
This line is not correct:
while (micros() < (microseconds + samplingPeriod)) {
Replace it with
while (micros() - microseconds < samplingPeriod) {
Alright, just by printing AnalogRead() values, I'm getting:
#define sensor 8
void setup() {
Serial.begin(115200);
}
void loop() {
int value = analogRead(sensor);
value = map(value, 0, 1023, 300, 1100);
Serial.println(value);
double voltage = (value/1023.0) * 5.0;
Serial.print("Voltage: ");
Serial.println(voltage);
delay(1000);
}
Note: I put up a light shield made out of cardboard surrounding the OPT-101 sensor to limit ambient light from affecting the readings. I also rotated this configuration sideways so that the reflected laser light is directly hitting the sensor. However, I did keep my garage light on, so these readings may have been affected by ambient light.
On average, I noticed that I'm getting around 900 (around 4.75 volts when I perform the calculation in the line: (value/1023.0) * 5.0 ) when the reflected beam hits the sensor. I also get around 300 when I block the beam with my hand (around 2.5 volts).
So, the sensor definitely registers the change in light intensity.
If you remove the windowing in the fft the peak near 0 frequency disappears ( or with the windowing, set to zero the first few vReal values after calculating the magnitude ). I tested it with a sine wave input.
This is not shown on the diagram and you just can't ignore it because without a proper negative bias, the operational amplifiers which I assume are in the break out board, will not work correctly.
Many people, my self included, do not want our computers infested by more cookies. That site does not allow me to reject them all.
...to take @jremington's suggestion, but also account for the not insignificant time it takes to do the for loop, analogRead, any micros() resolution issues, and the rest of the processing with:
microseconds = micros(); // record start of sample
for (int i = 0; i < SAMPLES; i++) {
vReal[i] = analogRead(sensor) - dcOffset; // Read light sensor value
vImag[i] = 0; // Imaginary part is 0 for real input data
while (micros() -microseconds < samplingPeriod) {
// Wait for the next sampling period
}
microseconds += samplingPeriod; // advance timer
}
Thanks for that, but none of the images are visible.
It is a long long time since I used transimpedance amplifiers, back in the early 1980s in fact. So it looks like the V- might in fact be an output. But I am still not sure.
In your circuit you just ignored the -V inputs. Pin 3 should be connected to Ground. This being the most negative voltage in the system. Now don't confuse this with the common ground which is the midpoint of the voltage range powering the circuit.
So the pin 2 marked -In should not be connected at all, and pin 8 connected to the mid voltage point.