I am working on a project with a collimator using and ESP32 Max V1.0 and stepper motors to move the collimator to scan for the highest voltage reading from a photodiode in the collimator in the X axis, returning to that location and then scanning the Z axis to perform the same function from that point.
I have a momentary scan button that initiates the scan and a home button send the motors back for another test run.
The United Detector Photodiode in the collimator is connected to a Thorlabs PDA 200 photodiode amplifier. The analog output goes to pin 32 and ground on the ESP32. The output also goes to a multimeter to get another data point for the test runs. As the motors step through both axes in 5 degree increments the voltage readings on the multimeter and PDA 200 seem to increase and decrease appropriately with signal strength. The maximum reading seen on the PDA 200 is approximately 3.40 nA and 180 mV on the multimeter.
However, the serial monitor steps are erratic with widely varying values including zeros.
Below is an example:
Z: 55 Voltage: 2.40
Z: 60 Voltage: 1.10
Z: 65 Voltage: 0.00
Z: 70 Voltage: 0.00
Z: 75 Voltage: 0.00
Z: 80 Voltage: 0.00
Z: 85 Voltage: 14.10
Z: 90 Voltage: 0.00
Z: 95 Voltage: 4.00
Z: 100 Voltage: 3.35
Z: 105 Voltage: 0.00
Z: 110 Voltage: 0.00
Z: 115 Voltage: 0.00
Z: 120 Voltage: 0.00
Z: 125 Voltage: 6.85
Z: 130 Voltage: 1.35
Z: 135 Voltage: 3.30
I would expect the values to remain close to each other. I am looking for a reason why the voltage appears so erratic which makes it difficult to consistently find and return to the highest reading.
Here is the code I am using:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <AccelStepper.h>
// Define stepper motor connections and interface type
#define motorInterfaceType 1 // 1 means using a driver with STEP/DIR pins
AccelStepper motorX(motorInterfaceType, 19, 23); // Step pin on GPIO 19, Dir pin on GPIO 23
AccelStepper motorZ(motorInterfaceType, 12, 13); // Step pin on GPIO 12, Dir pin on GPIO 13
// Define constants and variables
const int buttonPin = 36; // Define the scan button pin
const int homeButtonPin = 39; // Define the home button pin
const int sensorPin = 32; // Analog pin for voltage sensor on ESP32
const int stepsPerRevolution = 1600; // Defines the number of steps per rotation based on each motor (1.8° motor is 200/360°)
float maxVoltage = 0.0;
int maxX = 0;
float maxZVoltage = 0.0;
int maxZ = 0;
bool scanTriggered = false; // Variable to track if a scan is triggered
// Set the LCD address (I2C address) and dimensions (columns, rows)
LiquidCrystal_I2C lcd(0x27, 20, 4);
void setup() {
Serial.begin(115200);
pinMode(buttonPin, INPUT_PULLUP); // Initialize the scan button pin with internal pull-up resistor
pinMode(homeButtonPin, INPUT_PULLUP); // Initialize the home button pin with internal pull-up resistor
motorX.setMaxSpeed(2000); // Set Max Speed
motorZ.setMaxSpeed(2000);
motorX.setAcceleration(2000); // Set Max Acceleration
motorZ.setAcceleration(2000);
// Initialize the LCD
lcd.init();
lcd.backlight(); // Turn on the backlight (if your display has one)
lcd.print("Voltage = ");
}
void loop() {
// Check if the scan button is pressed
if (digitalRead(buttonPin) == LOW) { // Button pressed (active LOW)
// Debounce the button press
delay(50); // Simple debounce delay
if (digitalRead(buttonPin) == LOW) { // Check if still pressed
if (!scanTriggered) { // Only trigger if not already scanning
scanTriggered = true; // Set flag to indicate a scan is in progress
maxVoltage = 0.0; // Reset maxVoltage for new scan
maxX = 0; // Reset maxX for new scan
maxZVoltage = 0.0; // Reset maxZVoltage for new scan
maxZ = 0; // Reset maxZ for new scan
// Start scanning process
runScanningProcess(); // Call your scanning function
}
}
} else {
// Reset the scanTriggered flag when button is released
scanTriggered = false;
}
// Check if the home button is pressed
if (digitalRead(homeButtonPin) == LOW) { // Home button pressed (active LOW)
// Debounce the home button press
delay(50); // Simple debounce delay
if (digitalRead(homeButtonPin) == LOW) { // Check if still pressed
homeMotors(); // Call the homing function
}
}
}
// Function for scanning process
void runScanningProcess() {
// Step 1: Scan the X-axis
for (int x = 0; x <= 360; x += 10) {
motorX.moveTo(x * stepsPerRevolution / 360);
while (motorX.distanceToGo() != 0) {
motorX.run();
}
float voltage = analogRead(sensorPin) * 5.0 / 100; // Read voltage previously 5.0/4096
Serial.print("X: ");
Serial.print(x);
Serial.print(" Voltage: ");
Serial.println(voltage);
// Display on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("X: ");
lcd.print(x);
lcd.setCursor(0, 1);
lcd.print("Voltage: ");
lcd.print(voltage);
if (voltage > maxVoltage) {
maxVoltage = voltage;
maxX = x;
}
}
// Step 2: Return to the highest X-axis position
motorX.moveTo(maxX * stepsPerRevolution / 360);
while (motorX.distanceToGo() != 0) {
motorX.run();
}
// Step 3: Scan the Z-axis at the highest X position
for (int z = 0; z <= 360; z += 5) {
motorZ.moveTo(z * stepsPerRevolution / 360);
while (motorZ.distanceToGo() != 0) {
motorZ.run();
}
float voltage = analogRead(sensorPin) * 5.0 / 100; // Read voltage Previously 5.0/4096
Serial.print("Z: ");
Serial.print(z);
Serial.print(" Voltage: ");
Serial.println(voltage);
if (voltage > maxZVoltage) {
maxZVoltage = voltage;
maxZ = z;
}
}
// Step 4: Return to the highest Z-axis position
motorZ.moveTo(maxZ * stepsPerRevolution / 360);
while (motorZ.distanceToGo() != 0) {
motorZ.run();
}
// Display highest voltage readings in the Serial Monitor
Serial.print("Highest Voltage: ");
Serial.println(maxVoltage);
Serial.print("At X: ");
Serial.println(maxX);
Serial.print("Highest Z Voltage: ");
Serial.println(maxZVoltage);
Serial.print("At Z: ");
Serial.println(maxZ);
// Display results on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Max Voltage: ");
lcd.print(maxVoltage);
lcd.setCursor(0, 1);
lcd.print("At X: ");
lcd.print(maxX);
lcd.setCursor(0, 2);
lcd.print("Max Z Voltage:");
lcd.print(maxZVoltage);
lcd.setCursor(0, 3);
lcd.print("At Z: ");
lcd.print(maxZ);
}
// Function to home the motors
void homeMotors() {
// Move both motors to the home position (0 degrees)
motorX.moveTo(0); // Move motorX to home position
motorZ.moveTo(0); // Move motorZ to home position
// Run motors to home position
while (motorX.distanceToGo() != 0 || motorZ.distanceToGo() != 0) {
motorX.run();
motorZ.run();
}
// Optionally, reset the maximum values after homing
maxVoltage = 0.0;
maxX = 0;
maxZVoltage = 0.0;
maxZ = 0;
Serial.println("Motors homed to position 0.");
}
[Photodiode collimator diagram.pdf|attachment](upload://j5cG1vJuWSJ0g5h9tvA0okr3Xw5.pdf) (488.8 KB)
[Photodiode collimator layout.pdf|attachment](upload://hmVutq9HowP78tYuJmrIEvQKlE5.pdf) (292.7 KB)