Code is skipping past my if statements

Thank you in advance to anyone who considers helping me here.

I'm working on my first programming project in Senior Design (I'm in Mechanical Engineering so I don't know much about programming).

I'm going to attempt to explain my issue as best I can with my little knowledge on the subject. Essentially I have two stepper motors and a solenoid actuator attached to my Arduino Uno, and I need them to move in a very basic manner ONLY when my laser receiver ISN'T being struck by my laser.

I have been running the attached code, and the resulting actions tell me that when the Arduino gets to an if statement and that statement is false, it merely skips on to the next portion of the code rather than waiting for the if statement to become true, so every time I take the laser off the sensor, it basically is random which part of my code will be activated.

I have found it difficult to search for this question online (I'm probably not looking correctly). Any help with this would be greatly appreciated.

whole_system_test.ino (4.4 KB)

welcome to the forums. Please read the sticky post at the top of the forum about how to post your code. If you put it in the message using code tags, it makes it easier for people to help you. like this:

/*
  Stepper Motor Demonstration 4
  Stepper-Demo4.ino
  Demonstrates NEMA 17 Bipolar Stepper with A4988 Driver

  DroneBot Workshop 2018
  https://dronebotworkshop.com
*/

// Define Constants

// Connections to A4988
const int dirPin = 2;  // Direction
const int stepPin = 3; // Step
const int dirPin_2 = 4;
const int stepPin_2 = 5;
const int solenoidPin = 7;
const int Detector = 8;

// Motor steps per rotation
const int STEPS_PER_REV = 200;

void setup() {

  // Setup the pins as Outputs
  pinMode(stepPin, OUTPUT);
  pinMode(stepPin_2, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(dirPin_2, OUTPUT);
  pinMode(solenoidPin, OUTPUT); //Sets that pin as an output
  pinMode(Detector, INPUT);
}

void loop() {

  if (digitalRead(Detector) == LOW) {
    //solenoid control
    digitalWrite(solenoidPin, HIGH);      //Switch Solenoid ON
    delay(1000);                          //Wait 1 Second
    digitalWrite(solenoidPin, LOW);       //Switch Solenoid OFF
    delay(100);  //Wait 1 Second

    // Set motor direction clockwise
    digitalWrite(dirPin, HIGH);

    // Spin motor_1 one rotation slowly
    for (int x = 0; x < STEPS_PER_REV; x++) { //controls number of rotations
      digitalWrite(stepPin, HIGH); //I believe this is the control of the unique coils, it goes between high and low to drive the motor with a puny microsecond delay.
      delayMicroseconds(500); //controls amount of time revolution takes
      digitalWrite(stepPin, LOW);
      delayMicroseconds(500);
    }
  }
  delay(200);

  if (digitalRead(Detector) == LOW) {
    //solenoid control
    digitalWrite(solenoidPin, HIGH);      //Switch Solenoid ON
    delay(1000);                          //Wait 1 Second
    digitalWrite(solenoidPin, LOW);       //Switch Solenoid OFF
    delay(100);  //Wait 1 Second

    // Set motor direction clockwise
    digitalWrite(dirPin, HIGH);

    // Spin motor_1 one rotation slowly
    for (int x = 0; x < STEPS_PER_REV; x++) { //controls number of rotations
      digitalWrite(stepPin, HIGH); //I believe this is the control of the unique coils, it goes between high and low to drive the motor with a puny microsecond delay.
      delayMicroseconds(500); //controls amount of time revolution takes
      digitalWrite(stepPin, LOW);
      delayMicroseconds(500);
    }
  }
  delay(200);

  if (digitalRead(Detector) == LOW) {
    //solenoid control
    digitalWrite(solenoidPin, HIGH);      //Switch Solenoid ON
    delay(1000);                          //Wait 1 Second
    digitalWrite(solenoidPin, LOW);       //Switch Solenoid OFF
    delay(100);  //Wait 1 Second

    // Set motor direction clockwise
    digitalWrite(dirPin, HIGH);

    // Spin motor_1 one rotation slowly
    for (int x = 0; x < STEPS_PER_REV; x++) { //controls number of rotations
      digitalWrite(stepPin, HIGH); //I believe this is the control of the unique coils, it goes between high and low to drive the motor with a puny microsecond delay.
      delayMicroseconds(500); //controls amount of time revolution takes
      digitalWrite(stepPin, LOW);
      delayMicroseconds(500);
    }
  }
  delay(200);

  if (digitalRead(Detector) == LOW) {
    //solenoid control
    digitalWrite(solenoidPin, HIGH);      //Switch Solenoid ON
    delay(1000);                          //Wait 1 Second
    digitalWrite(solenoidPin, LOW);       //Switch Solenoid OFF
    delay(100);  //Wait 1 Second

    // Set motor direction clockwise
    digitalWrite(dirPin_2, HIGH);

    // Spin motor_1 one rotation slowly
    for (int x = 0; x < STEPS_PER_REV; x++) { //controls number of rotations
      digitalWrite(stepPin_2, HIGH); //I believe this is the control of the unique coils, it goes between high and low to drive the motor with a puny microsecond delay.
      delayMicroseconds(500); //controls amount of time revolution takes
      digitalWrite(stepPin_2, LOW);
      delayMicroseconds(500);
    }

    // Set motor direction counter-clockwise
    digitalWrite(dirPin, LOW);

    // Spin motor_1 one rotation slowly
    for (int x = 0; x < (600); x++) { //controls number of rotations
      digitalWrite(stepPin, HIGH); //I believe this is the control of the unique coils, it goes between high and low to drive the motor with a puny microsecond delay.
      delayMicroseconds(500); //controls amount of time revolution takes
      digitalWrite(stepPin, LOW);
      delayMicroseconds(500);
    }
  }
}

A couple of things stand out. How is your detector wired up? You have it defined as an input but it may need to be an INPUT_PULLUP so that it is not floating.

I hope you are not trying to drive a solenoid directly with an arduino pin. They can ony deliver 40mA and a solenoid will take way more than that.

A schematic, even hand drawn, would be useful.

Yes, if statements do not wait to be true, that is the expected behavior.

My advice is to pull your repeated code into its own function, it looks like the motor code is all the same except the direction, so that can be passed to the function.

void spinMotor(int dir)
{
  if (digitalRead(Detector) == LOW) {
    //solenoid control
    digitalWrite(solenoidPin, HIGH);      //Switch Solenoid ON
    delay(1000);                          //Wait 1 Second
    digitalWrite(solenoidPin, LOW);       //Switch Solenoid OFF
    delay(100);  //Wait 1 Second

    // Set motor direction to passed direction
    digitalWrite(dirPin, dir);

    // Spin motor_1 one rotation slowly
    for (int x = 0; x < STEPS_PER_REV; x++) { //controls number of rotations
      digitalWrite(stepPin, HIGH); //I believe this is the control of the unique coils, it goes between high and low to drive the motor with a puny microsecond delay.
      delayMicroseconds(500); //controls amount of time revolution takes
      digitalWrite(stepPin, LOW);
      delayMicroseconds(500);
    }
  }
}

In loop() keep a count of how many times you've turned the motor and call the spinMotor() function appropriately, reset the count when you want to go back to the first first action.

Thank you for the super quick response. Some of what you are saying is going over my head, by turning my repeated blocks of code into a function I'm basically creating a variable that can be called on more cleanly than simply repeating these big chunks of code.

Can I use the function you made with this in both directions, and for a different number of revolutions? Or do I have to make an entirely new function every time I need to tweak it a little bit?

That actually sounds like the solution to a problem I had foreseen but haven't ran into yet, are you saying I can keep track of the number of revolutions I have made using the code rather than something along the lines of a physical rotation sensor?

I apologize if it is rude of me to ask so many questions, I may be able figure this out on my own using forums, but being able to ask someone knowledgeable directly is a lot easier. :smiley:

blh64:
A couple of things stand out. How is your detector wired up? You have it defined as an input but it may need to be an INPUT_PULLUP so that it is not floating.

I hope you are not trying to drive a solenoid directly with an arduino pin. They can ony deliver 40mA and a solenoid will take way more than that.

A schematic, even hand drawn, would be useful.

I attached a basic schematic of my system.

This is the solenoid driver I'm using:

Also, I'm not sure what you mean by my input is "floating".

Again, thank you all for your help. I have learned more in 30 minutes of reading your tips than I would have in multiple hours of trying to figure this out on my own.
++

Thanks for the schematic. What laser sensor are you using? Your schematic shows power,ground and a signal connected. Often times, sensors like that only actively pull the signal low or else they let to "float" so if you don't have pull-up resistors enabled on the Arduino, you read noise. Is there a part number for that? Check the datasheet.

The functions delay() and delayMicroseconds() block the Arduino until they complete.
Have a look at how millis() is used to manage timing without blocking in Several Things at a Time.

And see Using millis() for timing. A beginners guide if you need more explanation.

The same techniques can be applied to micros() for shorter timing intervals.

...R

blh64:
Thanks for the schematic. What laser sensor are you using? Your schematic shows power,ground and a signal connected. Often times, sensors like that only actively pull the signal low or else they let to "float" so if you don't have pull-up resistors enabled on the Arduino, you read noise. Is there a part number for that? Check the datasheet.

I actually don't see any sort of part number in the product description, here is an amazon link:

Maybe this has been explained and I haven't recognized it, but what sort of control type should I use to make sure that the Arduino waits for the input before moving on to the next function?

Here is something along the lines of what I want to do:

do {
  delay(10);
} while (digitalRead(Detector) == HIGH);

If I put that before each of my functions, it should make the Arduino halt until the laser receiver sends a LOW signal, correct? I tried using this before and it seemed to completely halt the code until I reset the Arduino.

macbathie:
I actually don't see any sort of part number in the product description, here is an amazon link:
https://www.amazon.com/Icstation-5V-Laser-Sensor-Module/dp/B01M8PFZRC/ref=sr_1_3?keywords=laser+receiver+arduino&qid=1556294062&s=gateway&sr=8-3#customerReview

Right there in the link:
B01M8PFZRC

To answer questions in #4 - you would make a new function (not a variable). Variables can be passed into the function to tweak the behavior, so instead of changing several blocks of code you're just changing a few variables here and there.

If the direction is passed into the function then you don't need to write two functions for cw and ccw, just pass the desired direction as a variable and use that to set the direction pin. Same goes for # of revolutions, pass the number in as a variable.

As others have pointed out, once you call a function with delays you cannot read the laser until the motor has gone through all the revolutions and the function returns. I'm not sure that is a problem for your situation.

I wrote a small program to demonstrate what I was talking about. The trigger in this case is characters entered into the serial monitor in place of the sensor reading the laser. Upload it to your board and open the serial monitor. Each time you enter something in the monitor you will see print statements showing the motor moves. There are only three moves, so the 4th trigger returns to move #1.

Hopefully you can see how to plug the passed variables for direction and number of revolutions into the motor moving code that you have written.

const int STEPS_PER_REV = 200;
int count = 0;

void setup() {

  Serial.begin(9600);
}

void loop() {

  // simulate laser move by typing in serial monitor
  if ( Serial.available() )
  {

    // increment count
    count = count + 1;

    // if count is at end of moves, back to start
    if(count > 3) count = 1;

    // move motor based on how many triggers we've seen
    if ( count == 1 )
    {
      spinMotor(HIGH, STEPS_PER_REV);

    } else if ( count == 2) {

      spinMotor(HIGH, STEPS_PER_REV * 2);

    } else if ( count == 3) {

      spinMotor(LOW, STEPS_PER_REV * 3);
      spinMotor(HIGH, STEPS_PER_REV);
    }

    // remove any left over characters in serial buffer
    while ( Serial.available() ) Serial.read();

  } // if


}

// direction to move and # of steps are passed in
void spinMotor(int direction, int revs)
{

  if ( direction == HIGH )
  {
    Serial.print("Spinning clockwise - revs = ");
    
  } else {

    Serial.print("Spinning ccw - revs = ");
  }

  Serial.println(revs);
  
}