Can't get LED to blink rapidly during stepper movement (and other issues!)

Hello,

I’m basically brand new to Arduino and coding in general, but up until now i’ve always been able to work-though my bugs and errors by searching forums/google/etc.
On my current project i’ve hit a real snag, and haven’t made any progress after a full day of trying stuff out.
My project is meant to be a carpark boom-gate(stepper motor) + pedestrian crossing system with a status RGB LED light that changes to reflect the current status of the system.
The problem I am stuck on is:

  • Stepper motor is blocking - The LED blink functions [ blinkRed() specifically ] need to run DURING motor movement, but I can’t get this to work by nesting both within a single function or using if/while statements.
  • After boom-gate lowers, the “gateSequence” function should end. What actually happens is the instant the boom-gate lowers, the blinkRed and blinkGreen functions just go bananas and blink over eachother, and the stepper motor randomly advances downwards.
  • The “boom-gate” system can’t start its sequence if the “pedestrian crossing” is in use, and I think the way I attempted to account for this is causing further errors…
    Individually, my functions for blinking, stepper motor movements, etc all work. I think my issues are caused my by (awful) attempts to get around blocking issues. I don’t know how to make my sequences wait until the “crossing is clear” (crossingState == 0 is clear, crossingState == 1 is occupied).
    I’m in pretty desperate need of help, on any of the above issues.

Thankyou.

Code:

//Output
  const int Red = 11;
  const int Blue = 10;
  const int Green = 9;
  //steppermotor
  const int step1 = 2;
  const int step2 = 3;
  const int step3 = 4;
  const int step4 = 5;
   
//Input
  const int proxSensor = 6;
  const int buttonIn = 7;
  const int lightIn = A0;

//

//time constants
  const unsigned long tA = 3000;
  const unsigned long tB = 4500;
  const unsigned long tC = 10000;
  const unsigned long tD = 5000;
  const unsigned long tE = 1000;
  const unsigned long tF = 7000;
  const unsigned long tX = 1000;
  const unsigned long tW = 5000;
  const unsigned long tBlink = 200;             //5hz blink 200ms/2
  const unsigned long monitorInterval = 2000;

//Variables
  unsigned long previousMonitorTime = 0;
  unsigned long buttonPressLast = 0;
  unsigned long currentTime = 0;
  unsigned long previousRedBlink = 0;
  unsigned long previousGreenBlink = 0;
  unsigned long previousBlueBlink = 0;
  unsigned long gateStart;
  unsigned long gateTiming;
  
// unsigned long startCountdown;
  int blinkState = 0;
  int brightness = 255; //50% or 100%
  int lightValue; //LDR sensor read
  int lightState;  
  int redState = 1;
  int greenState = 0;
  int blueState = 0;
  int buttonState;
  int gateState = 0;  // 0 = down, 1 = up
  int proxValue;
  int crossingState = 0;

#include <Stepper.h>
const int stepsPerRevolution = 2048;
Stepper myStepper(stepsPerRevolution, 2, 4, 3, 5);
int stepCount = 0;


//==
void setup() {
//pinMode
  pinMode(Red,OUTPUT);
  pinMode(Green,OUTPUT);
  pinMode(Blue,OUTPUT);
  pinMode(lightIn,INPUT);
  pinMode(proxSensor,INPUT);
  pinMode(buttonIn,INPUT);
  pinMode(step1,OUTPUT);
  pinMode(step2,OUTPUT);
  pinMode(step3,OUTPUT);
  pinMode(step4,OUTPUT);

   
//initial State (LED, Gate, ?)
  analogWrite(Red,brightness);
  analogWrite(Green,0);
  analogWrite(Blue,0);

Serial.begin(9600);

}

//==
void loop() {

  currentTime = millis();       
  monitorRefresh();
  buttonPress();
  if (proxValue == 0){
    gateSequence();
  }
  analogWrite(Red,brightness);
  analogWrite(Green,0);
  analogWrite(Blue,0);

}
//=
void pedestrianSequence(){
  
  monitorRefresh();

  if (gateState == 0){
      monitorRefresh();
      
  }

  
}

//==
void gateSequence(){
  
  monitorRefresh();
  gateStart = millis();
  
  if (crossingState == 0){
    monitorRefresh();
    
    while (gateStart + 1500 > millis() ) {     
     blinkRed();
     gateUp();
    }
    while (gateState == 1){
      while (proxValue == 0){
        analogWrite(Red, 0);
        analogWrite(Blue, 0);
        analogWrite(Green, brightness);
        redState = 0;
        greenState = 1;
        monitorRefresh();
        }
      if (proxValue == 1) {
        monitorRefresh();
        gateTiming = millis();        
          while (millis() - gateTiming <= tC) {
            monitorRefresh();
            blinkGreen();
            redState = 0;
            greenState = 1;   
            }
          while (millis() - gateTiming <= tC + 1500) {
            analogWrite(Green, 0);
            monitorRefresh();
            blinkRed();           
            gateDown(); 
            }       
      }    
    } 
  }

  if (crossingState == 1){
    while (crossingState == 1){
      monitorRefresh();     
    }
      if (crossingState == 0){
    monitorRefresh();
    
    while (gateStart + 1500 > millis() ) {     
     blinkRed();
     gateUp();     
    }
    while (gateState == 1){
      while (proxValue == 0){
        analogWrite(Red, 0);
        analogWrite(Blue, 0);
        analogWrite(Green, brightness);
        redState = 0;
        greenState = 1;
        monitorRefresh();
        }
      if (proxValue == 1) {
        monitorRefresh();
        gateTiming = millis();        
          while (millis() - gateTiming <= tC) {
            monitorRefresh();
            blinkGreen();
            redState = 0;
            greenState = 1;   
            }
          while (millis() - gateTiming <= tC + 1500) {
            analogWrite(Green, 0);
            monitorRefresh();
            blinkRed();           
            gateDown(); 
            gateState = 0;
            }       
        }    
      } 
    }
  }
 analogWrite(Red, brightness);
 analogWrite(Green, 0);
 analogWrite(Blue, 0);
}

//=
void ambientLight(){
  lightValue = analogRead(lightIn);
  lightState = map(lightValue, 900, 1023, 255, 0);
  if (lightState > 125){
    brightness = 100;
  } else {
    brightness = 255;
  }
}

//==
void gateUp(){
  monitorRefresh();
  buttonPress();
  gateState = 1;
    
  myStepper.setSpeed(10);
  myStepper.step(stepsPerRevolution/4);
  
}

//==
void gateDown(){
  monitorRefresh();
  buttonPress();
        
  myStepper.setSpeed(10);
  myStepper.step(-stepsPerRevolution/4);
  
}

//==
void buttonPress() {

  if(digitalRead(buttonIn) == HIGH){
    if (millis() - buttonPressLast >= tF){
      buttonPressLast = millis();
      monitorRefresh();
      //pedestrianSequence             
    }
    else if(buttonPressLast == 0){
      buttonPressLast = millis();
      monitorRefresh();     
     //pedestrianSequence
    }
  }
  analogWrite(Red,brightness);
  analogWrite(Green,0);
  analogWrite(Blue,0);
  redState = 1;
  greenState = 0;
  blueState = 0;
  
}

//Red Blink Cycle=
void blinkRed(){

  unsigned long redStart = millis();
    while (millis() - redStart <= 1500){ 
      if (millis() - previousRedBlink >= tBlink/2) {    
        previousRedBlink = millis();
        monitorRefresh();
        if (blinkState == 0) {
            blinkState = brightness;
            redState = 1;
            
          }else {
            blinkState = 0;
            redState = 0;
          }          
       analogWrite(Red, blinkState);            
      }
  }
}

//Green Blink Cycle=
void blinkGreen(){
  
unsigned long greenStart = millis();
    while (millis() - greenStart <= tC){      
      if (millis() - previousGreenBlink >= tBlink/2) {    
        previousGreenBlink = millis();
        monitorRefresh();
        if (blinkState == 0) {
            blinkState = brightness;
            greenState = 1;
            
          }else {
            blinkState = 0;
            greenState = 0;
          }
          
       analogWrite(Green, blinkState);            
      }
    }
}

//Blue Blink Cycle=
void blinkBlue(){
  analogWrite(Red, 0);
  analogWrite(Green, 0);
  
    if (millis() - previousBlueBlink >= tBlink/2) {    
      previousBlueBlink = millis();
      monitorRefresh();
      if (blinkState == 0) {
          blinkState = brightness;
          blueState = 1;
          
        }else {
          blinkState = 0;
          blueState = 0;
        }
        
     analogWrite(Blue, blinkState);            
    }
}


//======
void monitorRefresh(){

  ambientLight();
  buttonState = digitalRead(buttonIn);
  proxValue = digitalRead(proxSensor);
     
  if (millis()-previousMonitorTime>= monitorInterval) {    

    previousMonitorTime += monitorInterval;
        
    Serial.print ... etc ([i]character limit, deleted serial monitor readout[/i])
   }
}

Stepper motor is blocking

That would be the first thing to fix. There are nonblocking stepper libraries, like AccelStepper. Implementing it will require significant changes to your code, so start by studying the examples, getting the stepper to do what you want, then add in the blinking lights.

Karma++ for using code tags in Your first post!

jremington:
That would be the first thing to fix. There are nonblocking stepper libraries, like AccelStepper. Implementing it will require significant changes to your code, so start by studying the examples, getting the stepper to do what you want, then add in the blinking lights.

I'll definitely give the AccelStepper library a try, thankyou!
Do you have any suggestions for how I can delay the "boomgate" sequence while the crossing is occupied / delay the crossing sequence while the boomgate is in-use.
I think if I can get that worked out + implement the new library i'll be able start making progress again.

Attempting to fix to a fundamentally flawed approach is not a very useful way to spend your time.

jremington:
Attempting to fix to a fundamentally flawed approach is not a very useful way to spend your time.

The description of the project guidance forum is "Advice on general approaches or feasibility", so perhaps you could expand a little on that?
As stated, my experience with Arduino/programming is basically zero; I wrote my first "hello world" a month ago. If my approach is bad, it would be helpful to know how someone else would approach the same type of problem.

I outlined a suggested approach as "project guidance" in reply #1.

I do not recommend that you try to fix your current program, because the initial approach is fundamentally flawed. Don't take this personally, most beginners (including me, some time ago) make the mistake of using blocking code, because the answer is not obvious.

Okay, i've re-wrote using AccelStepper and the sequence works much better!

One major problem remaining:

  • When the linetrace module (labelled proxSensor, read of 0 means "car" is detected") detects ANYTHING, the whole program freezes (serial monitor stops). If the "car quickly moves infront of the sensor (producing a short period of proxSensor == 1), the "gateSequence" runs smoothly as intended... but if the "car" is held infront of the sensor, the program stops responding until reset (powered off/on).

The intended sequence should be:

  1. Linetrace detects "car" and crossingState == 1
  2. blinkRed() and gateUp() run in a loop until stepper.DistanceToGo() == 0 (ie; gate is up).
  3. Green (an LED) is set to analogWrite(brightness) UNTIL Linetrace no longer detects "car" (ie; proxValue ==1).
  4. blinkGreen() runs for duration tC after linetrace no longer detects "car".
  5. blinkRed() and gateDown() loop while stepper.DistanceToGo() != 0 (ie; blink + move stepper until gate is down)

Currently, Step 3 listed above does not work at all, due to the program and Serial monitor freezing any time the line trace module is active for more than an instant.

I'm totally lost as to why the line-trace is freezing everything. Any additional help would be MUCH appreciated.

Thankyou!

(Code length exceeds character limit for posting, so it is in the next reply.)

//Output
  const int Red = 11;
  const int Blue = 10;
  const int Green = 9;
  //steppermotor
  const int step1 = 2;
  const int step2 = 3;
  const int step3 = 4;
  const int step4 = 5;
   
//Input
  const int proxSensor = 6;
  const int buttonIn = 7;
  const int lightIn = A0;

//

//time constants
  const unsigned long tA = 3000;
  const unsigned long tB = 4500;
  const unsigned long tC = 10000;
  const unsigned long tD = 5000;
  const unsigned long tE = 1000;
  const unsigned long tF = 7000;
  const unsigned long tX = 1000;
  const unsigned long tW = 5000;
  const unsigned long tBlink = 200;             //5hz blink 200ms/2
  const unsigned long monitorInterval = 2000;

//Variables
  unsigned long previousMonitorTime = 0;
  unsigned long buttonPressLast = 0;
  unsigned long currentTime = 0;
  unsigned long previousRedBlink = 0;
  unsigned long previousGreenBlink = 0;
  unsigned long previousBlueBlink = 0;
  unsigned long gateStart = 0;
  unsigned long gateTiming = 0;
  unsigned long crossingStart = 0;
  
// unsigned long startCountdown;
  int blinkState = 0;
  int brightness = 255; //50% or 100%
  int lightValue; //LDR sensor read
  int lightState;  
  int redState = 1;
  int greenState = 0;
  int blueState = 0;
  int buttonState;
  int gateState = 0;  // 0 = down, 1 = up
  int proxValue;
  int crossingState = 1;

#include <AccelStepper.h>
const int stepsPerRevolution = 2048;
AccelStepper stepper(AccelStepper::FULL4WIRE, 2, 4, 3, 5);
 

//==
void setup() {
  Serial.begin(9600);

  stepper.setMaxSpeed(512);
  stepper.setAcceleration(100);
  
//pinMode
  pinMode(Red,OUTPUT);
  pinMode(Green,OUTPUT);
  pinMode(Blue,OUTPUT);
  pinMode(lightIn,INPUT);
  pinMode(proxSensor,INPUT);
  pinMode(buttonIn,INPUT);
  pinMode(step1,OUTPUT);
  pinMode(step2,OUTPUT);
  pinMode(step3,OUTPUT);
  pinMode(step4,OUTPUT);

   
//initial State (LED, Gate, ?)
  analogWrite(Red,brightness);
  analogWrite(Green,0);
  analogWrite(Blue,0);  
}

//==
void loop() {

  currentTime = millis();
  monitorRefresh();
  if (crossingState == 1 and gateState == 0){
    analogWrite(Red,brightness);
    analogWrite(Green,0);
    analogWrite(Blue,0);
  }
}

//=
void pedestrianSequence(){
  monitorRefresh();

  while (millis() - buttonPressLast < tF){
    monitorRefresh();   
  }
  if (millis() - buttonPressLast >= tF){    
      monitorRefresh();
      while (proxValue == 0 or gateState == 1){
        monitorRefresh(); 
      }
      if (proxValue == 1 and gateState == 0){
        crossingState = 2;                                      //crossingState == 2 when active
        crossingStart = millis();
        while (millis() - crossingStart <= 3000){
            monitorRefresh();
            analogWrite(Red,0);
            analogWrite(Green,0);
            analogWrite(Blue,brightness);
        }
        while (3000 < millis() - crossingStart and millis() - crossingStart <= 5000){      
          blinkBlue();
          monitorRefresh();
      }            
    }
  }
crossingState = 1;    
}

//==
void gateSequence(){

  if (proxValue == 0 and crossingState == 1){

    gateState = 1;
    monitorRefresh();
//    gateStart = millis();
    stepper.moveTo(512);
  
    while (stepper.distanceToGo() != 0 and gateState == 1) {     
     blinkRed();
     gateUp();          
      }
    while (stepper.distanceToGo() == 0 and proxValue == 0){    //car detected
      analogWrite(Red, 0);
      analogWrite(Blue, 0);
      analogWrite(Green, brightness);
      redState = 0;
      greenState = 1;
      monitorRefresh();
      }
    if (stepper.distanceToGo() == 0 and proxValue == 1) {    //car has moved forward
      monitorRefresh();      
      gateTiming = millis();
      stepper.moveTo(0);        
      while (millis() - gateTiming <= tC) {
        monitorRefresh();
        blinkGreen();
        redState = 0;
        greenState = 1;   
       }
      while (tC < millis() - gateTiming and stepper.distanceToGo() != 0) {
        analogWrite(Green, 0);
        monitorRefresh();
        blinkRed();           
        gateDown();
        gateState = 0;      
      }       
    }
  }   
}

//=
void ambientLight(){
  lightValue = analogRead(lightIn);
  lightState = map(lightValue, 900, 1023, 255, 0);
  if (lightState > 125){
    brightness = 100;
  } else {
    brightness = 255;
  }
}

//==
void gateUp(){
  monitorRefresh();
  stepper.run();         
}

//==
void gateDown(){
  monitorRefresh(); 
  stepper.run();  
}

//==
void buttonPress() {

  if(digitalRead(buttonIn) == HIGH){
    if (millis() - buttonPressLast >= tF + 100){
      buttonPressLast = millis();
      monitorRefresh();      
      Serial.println("Button Pressed!");
      pedestrianSequence();            
    }
    else if(buttonPressLast == 0){
      buttonPressLast = millis();
      monitorRefresh();
      Serial.println("Button Pressed!");     
      pedestrianSequence();       
    }
  } 
}

//Red Blink Cycle=
void blinkRed(){

    if (millis() - previousRedBlink >= tBlink/2) {    
      previousRedBlink = millis();
      monitorRefresh();
      if (blinkState == 0) {
          blinkState = brightness;
          redState = 1;            
        }else {
          blinkState = 0;
          redState = 0;
        }          
     analogWrite(Red, blinkState);
     analogWrite(Blue, 0);
     analogWrite(Green, 0);            
    }
}

//Green Blink Cycle=
void blinkGreen(){
  
    if (millis() - previousGreenBlink >= tBlink/2) {    
      previousGreenBlink = millis();
      monitorRefresh();
      if (blinkState == 0) {
          blinkState = brightness;
          greenState = 1;
          
        }else {
          blinkState = 0;
          greenState = 0;
        }
     analogWrite(Red, 0);
     analogWrite(Blue, 0);
     analogWrite(Green, blinkState);             
    }
}

//Blue Blink Cycle=
void blinkBlue(){
  analogWrite(Red, 0);
  analogWrite(Green, 0);
  
    if (millis() - previousBlueBlink >= tBlink/2) {    
      previousBlueBlink = millis();
      monitorRefresh();
      if (blinkState == 0) {
          blinkState = brightness;
          blueState = 1;
          
        }else {
          blinkState = 0;
          blueState = 0;
        }
     analogWrite(Red, 0);
     analogWrite(Blue, blinkState);
     analogWrite(Green, 0);            
    }
}


//===INCOMPLETE===
void monitorRefresh(){

  buttonState = digitalRead(buttonIn);
  proxValue = digitalRead(proxSensor);
  ambientLight();
  buttonPress();
  gateSequence();
    
  if (millis()-previousMonitorTime>= monitorInterval) {    

    previousMonitorTime += monitorInterval;

    Serial.print("ProxSensor: ");
    Serial.println(digitalRead(proxSensor));
    Serial.print("Pedestrian: ");
    Serial.print("Red = ");
        if(redState > 0){
      Serial.print("On");
    } else {
      Serial.print("Off");
    }
    Serial.print("\t");
    Serial.print("Green = ");
        if(greenState > 0){
      Serial.print("On");
    } else {
      Serial.print("Off");
    }
    Serial.print("\t");
    Serial.print("Blue = ");
        if(blueState > 0){
      Serial.println("On");
    } else {
      Serial.println("Off");
    }
    Serial.print("Ambient Light Level: ");
        if (lightState > 125){
      Serial.println("Night");
    } else {
      Serial.println("Day");
    }
    Serial.print("Button: ");    
    if(millis()>2000 and millis()-buttonPressLast<=2000){
            Serial.println("Pressed");   
          } else{
            Serial.println("Unpressed");
          }
    Serial.print("Pedestrian Crossing: ");
    if (crossingState == 2){
            Serial.println("Active");
    } else {
            Serial.println("Inactive");
    }
    Serial.print("Boom Gate: ");
    if (gateState == 1){            
            Serial.println("Open");           
    } else {
            Serial.println("Closed");
    }
    Serial.println("\t");
  }  
}

This is the line-trace module i’m using if it matters: https://www.jaycar.com.au/medias/sys_master/images/images/9427972685854/XC4474-dataSheetMain.pdf

Please add comments to your code, explaining the logic and what each section is supposed to do.

In six months, you won't remember what you did, and with no guiding comments, you should not expect forum members to make the effort.

I had to delete most of my comments to get it to fit in the 9000 character limit!

That's why in the preceding reply, I attempted to explain intended action and logic of the sequence that I am troubleshooting.
I guess the other section I didn't explain was the "monitorRefresh();" function. I am using it to update values such as ambient light level, the state of the button used to activate "pedestrianSequence()", and the state of the line-trace sensor "proxValue = digitalRead(proxSensor);".

Is there anything specific that is unclear and looks questionable to you?

I WORKED IT OUT YESSSSSSSS.

Source of Problem:

  • Calling "gateSequence();" function inside the same function used to update the line trace module "monitorRefresh()" caused some kind of logic short-circuit?

SOLUTION:

  • Simply moved "gateSequence();" from monitorRefresh() to the "loop()" function. There is no logical reason why I need to try and run the gateSequence() while it's already running.
  • Line-trace module still is updated within monitorRefresh(), meeting the needs of the gateSequence() function.

/thread

Great! For future reference, append large programs to your post.

For future Reference #2 ...

Fix problems before your program gets big.

Or write a short program that does nothing but illustrate the problem.

...R