Using Stepper Motors to move a 24 well plate (XY table mover)

I’m trying to make it easier for me to image a 24 well plate under a microscope, so that each image comes out to be almost exactly the same. To do so, I am planning on using two stepper motors to move the 24 well plate into the different locations so that each well is centered under the microscope.

I initially intended to just have a preset path for the motors to move the plate along; however, I realized that it would be more practical for me to use some kind of user input to dictate which well that I would want to be positioned above. Therefore, I decided to use two potentiometers (one for each axis) that would dictate the user specified location (ie. user turns potentiometer to Position A so that the motor rotates to position A).

The problem that I am running into now is that I would have to create 24 different if statements to house all of the conditions that I want to see. I was wondering if there is an easier way to do this, as well as if there is an easier way to home my device?

This is my code thus far. I started on writing the conditions, but wanted to get y’alls opinion before I moved forward.

Here is a picture of a 24 well plate for reference.

/*
Utilize this sketch to image a 24 well plate automatically. It will move the well plate around
so that it creates an identical image every time. 
*/

#include <AccelStepper.h> //include accellstepper library

#define limitXPin 11  //limit pin for X direction
#define limitYPin 12  //limit pin for Y direction

#define colPotPin A0  // Potentiometer for moving to the next letter on the plate
#define rowPotPin A1  // Potentiometer for moving to the next number on the plate

#define stepXPin 6  //defining the pins for the easy motor driver
#define dirXPin 7
#define stepYPin 8
#define dirYPin 9


const int colPotStep = 1.25; //Moving across the columns
const int rowPotStep = 0.833; //Moving down the rows

const int fullRev = 200;  // change this value once you know what motor you are using
const int xStep = 20;  // number of steps needed to move one step in the x direction 
const int yStep = 10;  // number of steps needed to move one step in the y direction

AccelStepper stepperX(AccelStepper::DRIVER, dirXPin, stepXPin);  //change pins if necessary
AccelStepper stepperY(AccelStepper::DRIVER, dirYPin, stepYPin); 

void setup() {
    Serial.begin(9600);// initialize the serial port:
    pinMode(limitXPin, INPUT); //setting these pins to input data from the limit pins
    pinMode(limitYPin, INPUT);

    stepperX.setMaxSpeed(1000); //setting speeds and accelerations for the motors
    stepperX.setAcceleration(500); // make sure these aren't too high/ too low
    stepperY.setMaxSpeed(1000);
    stepperY.setAcceleration(500);

    while(digitalRead(limitXPin)) { //run the X axis motor until it touches the limit switch
      digitalWrite(dirXPin, HIGH); //HIGH = CCW , LOW = CW  (This could be false depending on the way the motor is oriented)
      digitalWrite(stepXPin, HIGH); 
      delay(5);
      digitalWrite(stepXPin, LOW);
      delay(5);
    }

    while(!digitalRead(limitXPin)) {  //run the Y axis motor until it just stops pressing the limit switch
      digitalWrite(dirXPin, LOW); //HIGH = CCW , LOW = CW  (This could be false depending on the way the motor is oriented)
      digitalWrite(stepXPin, HIGH); 
      delay(10);
      digitalWrite(stepXPin, LOW);
      delay(10);
    }

    while(digitalRead(limitYPin)) { //run the Y axis motor until it touches the limit switch
      digitalWrite(dirYPin, HIGH); //HIGH = CCW , LOW = CW  (This could be false depending on the way the motor is oriented)
      digitalWrite(stepYPin, HIGH); 
      delay(5);
      digitalWrite(stepYPin, LOW);
      delay(5);
    }

    while(!digitalRead(limitYPin)) { //run the Y axis motor until it just stops pressing the limit switch
      digitalWrite(dirYPin, LOW); //HIGH = CCW , LOW = CW  (This could be false depending on the way the motor is oriented)
      digitalWrite(stepYPin, HIGH); 
      delay(10);
      digitalWrite(stepYPin, LOW);
      delay(10);
    }
    
    
}

void loop() {
    int colPot = analogRead(colPotPin);
    int rowPot = analogRead(rowPotPin);

    if( (colPot >=0 && colPot <= colPotStep ) && (rowPot >= 0 && rowPot<= rowPotStep)){
      
    }
    
}

saahilm:
The problem that I am running into now is that I would have to create 24 different if statements to house all of the conditions that I want to see.

I don't see it like that.

If one Pot is for the columns then there are 6 positions each of which corresponds with a position of the X stepper motor. And the other Pot for the rows corresponds with the 4 positions of the Y stepper motor.

...R
Stepper Motor Basics
Simple Stepper Code

Why not calculate the column and row numbers from the analog reading? i.e. row number is

analogRead(rowPotPin)/256;

Then keep track of where the plate is currently by counting steps and calculate what steps you need to execute to get to the new position.

Thanks Robin for your input.

So you are saying to do it as nested if statements?

Wildbill:
I'm using the analog potentiometers as a means to direct where the plate will sit. I figured that the pots would be easier to implement than a GUI. I want to use this so that I can control what well is under the microscope in real time.

Also, I’m realizing that I have implemented no way to record the location of each of the cells. I know how many steps it will take to move over to the next cell; however, I have no idea how to go from cell A1 to D6.

Would I just count how many steps it takes for the stepper motor to go to the D column and then how many it takes to go down to the 6th row and then save those values? Not quite sure how to do this tactfully.

You can model it as an XY coordinate system based on steps. Let's assume that A1 is your origin where your homing routine puts you. If it takes e.g. 200 steps to move over or down one cell then D6 will be at 1000,600.

Keep track of your current position in steps. If your X destination is greater than your position now, step right. If it's less, step left, otherwise stop. Same thing for the Y axis.

So there's no need for nested ifs; read the pots, calculate the destination coordinates and then go there one step at a time.

Most people have used stepper motors attached to lead screws that are attached to the microscope stage.

Paul

Post a diagram and some details of the mechanism that will support and move the plate. If you don't have one yet, Google will show you lots of "XY stages", for example:

Consider also having the user type or enter B3 on a keypad to move to position B3.

That sounds like what print bed of a 3D printer does. Stepper motor with a gear drives a rubber belt to move the table in very small increments.
Attached you can see an end-view of the X-drive stepper motor, it's drive gear, the belt it drives, it's limit switch for homing the bed, and the bars on one side that moves it up & down in Z-asix.

This might not fit what you need, as the table is fixed in X-axis, moves in and out in Y-axis, and the plastic extruder is moved back and forth in X-axis and up and down in Z axis. You probably need the microscope head fixed in position and the table moved in X and Y.

But it does show that very small, repeatable movements can be commanded as 3D printers do it all time using '1284P and '2560 processors to control the motor movements, read the limit switches, and pull data from SD card, or receive via USB, to move things around pretty precisely.

This motorized drawing might be what you need. Remove the pen, program it to move your slide around.
The control board looks like a CH340 & '328P with a couple of motor driver boards.

https://usa.banggood.com/EleksMaker-EleksDraw-XY-Plotter-Pen-Drawing-Writing-Robot-Drawing-Machine-p-1125222.html?gmcCountry=US&currency=USD&createTmp=1&utm_source=googleshopping&utm_medium=cpc_bgcs&utm_content=garman&utm_campaign=pla-usg-brand-eleksmaker-pc&ad_id=350580579796&gclid=EAIaIQobChMIob2_4Lbn4gIVgo3ICh1btgHJEAQYHCABEgLtOfD_BwE&cur_warehouse=CN

More info on the board:
http://wiki.eleksmaker.com/doku.php?id=eleksmana_se#eleksmana_se

saahilm:
Would I just count how many steps it takes for the stepper motor to go to the D column and then how many it takes to go down to the 6th row and then save those values? Not quite sure how to do this tactfully.

Something like that, indeed.

I'd use an x, y coordinate system. Two arrays: one with the 6 x values, the other with the 4 y values (both expressed in number of steps).
Then have two variables where you keep track of where your stepper is exactly, in terms of either x and y values or the array index.
Homing would be manual in this case - the first coordinate in your array would be (0, 0). Then you manually move the table to that position, so the first opening is nicely centred, and you make sure the plate itself is placed square.
Then with e.g. a button press you tell your Arduino that it's now at it's home position and ready to start moving to the next position.