Servo Movement Triggered By Analog Signal Without Delay

Hey all, first time poster here. Really tried my darndest to get this working on my own but I think there is a concept that I’m simply not understanding.

My project is a 3D printed mechanism used to detect whether or not a part inserted into it is oriented correctly, by using a QRD1114 optical detector to see if a long or a short side is present. In essence, if the detector sees the part within its range, a MG-90 servo-operated gate will open to accept the part, and if the part is not within sensor range they hit the closed gate and are rejected. Parts are fed to the sensor via a stepper-operated ‘chamber’ that is rotating constantly.

Currently I’m using an Arduino Nano and an EasyDriver to run the stepper (I know a stepper might not have been the best thing to use but here I am and I’m unsure if I want to change it at this point), using the AccepStepper library. That part works fine. My issue is using millis() in order to time the gate opening and closing based on feedback from the optical sensor.

The goal is to read the sensor constantly, and when the voltage coming from the sensor (proximityV) falls below a certain value, I want the gate to open about half a second later, accepting the ‘good’ part, and then closing just afterward until a new sensor read comes through. If the part doesnt trigger the sensor, the gate would simply stay closed and deflect a ‘bad’ part.

My code is below, and its probably a mess because I’m very much a novice:

#include <AccelStepper.h>
#include <Servo.h>

Servo myservo;              //declare MG90 servo

const int Sensor = A0;      //this is the prox sensor

unsigned long startMillis;

unsigned long currentMillis;

const unsigned long servoPeriod = 750;   // period between servo open and servo close

const unsigned long partPeriod = 900; // wait between parts coming in




// Define a stepper and the pins it will use
AccelStepper stepper(AccelStepper::DRIVER, 2, 3);

void setup()
{  
   stepper.setMaxSpeed(10000); //stepper max speed set to unreachable value for simplicity
   stepper.setSpeed(150);  // speed at which cylinder spins

  myservo.attach(12);     // servo attached at D12
  pinMode(Sensor, INPUT);
  myservo.write(15);        //setup an initial servo position
 
}

void loop()
{  
  
   stepper.runSpeed();    // start cylinder stepper

currentMillis = millis();    //setup millis

    //set up QRD sensor read value
   int proximityADC = analogRead(Sensor);   //read QRD1114 sensor
  float proximityV = (float)proximityADC * 5.0 / 1023.0;    //translate sensor output to voltage reading

// if the prox sensor sees a part, then it rotates the servo 'open' to accept the part
if (proximityV < 3.5){
  if (currentMillis - startMillis >= partPeriod){
    startMillis = currentMillis;
    myservo.write(70);
  }
}
//  after a period, the servo will reset back to initial 'closed' gate
  if (currentMillis - startMillis >= servoPeriod){
    startMillis = currentMillis;
    myservo.write(15);
  }
}

I know that the everything is hooked up correctly to my breadboard because they all work independantly of each other, and the reading from the sensor is accurate. The stepper motor runs just fine and isnt blocked. I just cannot for the life of me get the servo gate to behave how I’m trying to get it to.

Sorry if anything is unclear or rambly, I’ve thoroughly frustrated myself in trying to solve this myself.

Welcome to the forums. What you describe can easily implemented using a state machine. You wait for the signal, then you are opening the gate, then you are closing the gate.

If this is all you code is doing, you don’t really need to implement this as a state machine and using elapsed time since delay() would work just fine in this case. If it is part of a bigger project, it is always good to avoid delay()

Give this a try

#include <AccelStepper.h>
#include <Servo.h>

Servo myservo;              //declare MG90 servo

const int Sensor = A0;      //this is the prox sensor

unsigned long startMillis;
unsigned long currentMillis;

const unsigned long openTimePeriod = 750;   // amount of time to open the gate plus how long to keep it open
const unsigned long closeTimePeriod = 1750;   // amount of time to close the gate plus delay before checking again

const int openPosition = 70;   // servo position when gate is open
const int closedPosition = 15;  // servo position when gate is closed

const float GOOD_VALUE = 3.5; // max voltage to signal a good part

enum { WAITING, OPENING_GATE, CLOSING_GATE };
int state = WAITING;

// Define a stepper and the pins it will use
AccelStepper stepper(AccelStepper::DRIVER, 2, 3);

void setup()
{
  stepper.setMaxSpeed(10000); //stepper max speed set to unreachable value for simplicity
  stepper.setSpeed(150);  // speed at which cylinder spins

  myservo.attach(12);     // servo attached at D12
  pinMode(Sensor, INPUT);
  myservo.write(closedPosition);        //setup an initial servo position
}

void loop()
{
  currentMillis = millis();    //setup millis

  //set up QRD sensor read value
  int proximityADC = analogRead(Sensor);   //read QRD1114 sensor
  float proximityV = (float)proximityADC * 5.0 / 1023.0;    //translate sensor output to voltage reading

  switch (state) {
    case WAITING:    // waiting for sensor
      if (proximityV < GOOD_VALUE) {
        startMillis = currentMillis;
        myservo.write(openPosition);
        state = OPENING_GATE;
      }
      break;

    case OPENING_GATE:  // gate is opening
      stepper.runSpeed();    // step motor
      if (currentMillis - startMillis >= openTimePeriod) {
        startMillis = currentMillis;
        myservo.write(closedPosition);
        state = CLOSING_GATE;
      }
      break;

    case CLOSING_GATE:  // gate is closing
      stepper.runSpeed();    // step motor
      if (currentMillis - startMillis >= closeTimePeriod) {
        state = WAITING;
      }
      break;
  }
}

WOW! The only changes I had to make to your sample is to move the stepper.runSpeed() command to the start of the loop so it wouldnt stop running, and adjust the gate timing, but other than that it runs like a dream now!

And this really is the essence of all the code needs to do, but I needed to have the stepper running constantly so I couldnt use a delay which would stop the stepper. But this definitely did the trick, and it is a grand lesson for me as well, since I'm new. It looks like learning how to code a state machine might actually help my other projects down the pipeline as well. I really appreciate the help, thank you much!

Cool. I think I confused the stepper constantly running with the servo gate opening/closing. Two separate things.