Millis() and booleans does not update and leave first stage

I am trying to run a stepper to pull something up and release it again.
After some time a solenoid is used to release an object attached to a string and after some time it should be pulled up again by a stepper. The stepper runs constantly until a limit switch is activated. After that the loop should start all over again.
I've got the hardware and setup running, but I am stuck in the first stage of my loop. I guess it must be a problem on how I update the millis().

Can someone help me with this?


#include <AccelStepper.h>

#define limit_switch 2

int sensorVal = digitalRead(2);
#define solenoid 8

AccelStepper stepper(1, 13, 12);
bool shouldOnTree;
bool shouldLoose;
bool shouldPull;
bool shouldStop;

// {StepperAa, StepperAb, stepperB, StepperC}
long position0[2] = { 0, 6400};

long position1[2] = { 0, 6400};


// ---------------------interval ---------------------

unsigned long IntervalStart = 1000 * 2;
unsigned long IntervalOnTree = 1000 * 5;
unsigned long IntervalDown = 1000 * 10;


// ---------------------millis ---------------------
unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()
unsigned long previousMillis = 0;   // will store last time the steppers were updated
// unsigned long previousStepperBMillis = 0;


//================================================================================

void setup()
{
  pinMode(limit_switch, INPUT_PULLUP);

  pinMode(solenoid, OUTPUT);


  // Set stepper default speeds and accelerations
  stepper.setMaxSpeed(4000);
  stepper.setAcceleration(1000);

  Serial.begin(115200);
}


//================================================================================

void loop()
{
  currentMillis = millis();    // capture the latest value of millis()
  // this is equivalent to noting the time from a clock

  //Serial.println(sensorVal);

  if (currentMillis - previousMillis >= IntervalStart) {
    onTree();
    previousMillis = currentMillis;
  }

  if (shouldLoose) {
    letLoose();
  }

  if (shouldPull) {
    pullUp();
  }

  if (shouldStop) {
    stopPull();
  }

}

//========================================

void onTree() {
  Serial.println("on tree");
  if (currentMillis - previousMillis >= IntervalOnTree) {
    shouldLoose = true;
  }

}

void letLoose() {
  digitalWrite(solenoid, HIGH);
  Serial.println("loose");
  if (currentMillis - previousMillis > IntervalDown) {
  }
  shouldPull = true;
}


void pullUp() {
  stepper.runSpeed();
  stepper.setSpeed(4000);
  Serial.println("up");
  if (sensorVal == LOW) {
    shouldStop = true;
  }
}

void stopPull() {
  stepper.runSpeed();
  stepper.setSpeed(0);
  Serial.println("stop");
  shouldOnTree == true;
}

In that case a stepper motor was the wrong choice. A simple dc motor, perhaps with a gearbox, is appropriate. Can I suggest you use Google to read up on the different types of motor and their appropriate uses?

where are your flags (e.g. shouldOnTree, shouldLoose) ever set to false?

and in this case, wouldn't delay() be simpler?

It is, yes.

  if (currentMillis - previousMillis >= IntervalStart) {
    onTree();
    previousMillis = currentMillis;
  }

As soon as onTree() has been called, just once, you update previousMillis. That prevents onTree() from being called for a further 2 seconds.

void onTree() {
  Serial.println("on tree");
  if (currentMillis - previousMillis >= IntervalOnTree) {
    shouldLoose = true;
  }

}

Each time onTree() is called, the difference between currentMillis and previousMillis is 2 seconds. It never gets to 5 seconds, so shouldLoose never gets changed to true.

I agree. There is no sign from what @julius-me has described so far, that a simple solution using delay() would not work. The logic would be much simpler and easier to write correctly for a beginner.

If there is some reason, not mentioned yet, why using delay() would cause problems, then I would suggest using a "state machine" approach in the code. Instead of multiple Boolean flags, use one state variable. This is much less error prone, because a single variable can only have one value. Multiple Boolean flags can have many combinations between them, some of which are not valid (for example, shouldLoose and shouldPull both being true at the same time).

can't/shouldn's initialize a variable outside a function and certainly need to read it more than once.

where does solenoid get set LOW?

certainly nothing more than a delay()

where is sensorVal read (i.e. digitalRead ())?

perhaps intended: shouldOnTree = true;

how about (simulated)

#undef MyHW
#ifdef MyHW
# define limit_switch   A1
# define solenoid       13

class AccelStepper {
    int speed;
  public:
    AccelStepper (int a, int b, int c)  { };
    void setAcceleration (int a)        { };
    void setMaxSpeed (int a)            { };
    void setSpeed (int a)            { speed = a; };
    void runSpeed ()                 {
        Serial.print    ("  runSpeed: ");
        Serial.println  (speed);
    }
};

#else

#include <AccelStepper.h>
# define limit_switch 2
# define solenoid     8
#endif

AccelStepper stepper (1, 13, 12);

//==============================================================================
void setup ()
{
    pinMode (limit_switch, INPUT_PULLUP);
    pinMode (solenoid, OUTPUT);

    // Set stepper default speeds and accelerations
    stepper.setMaxSpeed (4000);
    stepper.setAcceleration (1000);

    Serial.begin (115200);
}

//==============================================================================
void loop ()
{
    Serial.println ("up");
    stepper.setSpeed (4000);
    stepper.runSpeed ();

    // wait for limit 
    while (HIGH == digitalRead (limit_switch))
        ;

    Serial.println ("stop");
    stepper.setSpeed (0);
    stepper.runSpeed ();

    Serial.println ("loose");
    digitalWrite (solenoid, HIGH);
    delay (250);
    digitalWrite (solenoid, LOW);

    delay (3000);
}

I made a version using delay and combined it with your suggestion. It is now switching between the different parts as I want to, but my motor is not running anymore. Any suggestions?


#include <AccelStepper.h>

#define limit_switch 2 // Pin 9 connected to Home Switch (MicroSwitch)
#define solenoid 8
AccelStepper stepper(1, 13, 12);

//================================================================================

void setup()
{
  pinMode(limit_switch, INPUT_PULLUP);
  pinMode(solenoid, OUTPUT);

  // Set all default speeds and accelerations
  stepper.setMaxSpeed(4000);
  stepper.setAcceleration(4000);

  Serial.begin(115200);
}


//================================================================================

void loop()
{

  int sensorVal = digitalRead(limit_switch);
  Serial.println("onTree");
  delay(2000);

    Serial.println ("loose");
    digitalWrite (solenoid, HIGH);
    delay (3000);
    digitalWrite (solenoid, LOW);


    Serial.println ("up");
    stepper.setSpeed (4000);
    stepper.runSpeed ();
   // wait for limit 
    while (digitalRead (limit_switch) == HIGH);


if( digitalRead(limit_switch) == LOW){
    Serial.println ("stop");
    stepper.setSpeed (0);
    stepper.runSpeed ();
}
delay(4000);
}

What I did not tell( -probably should have) it is part of a greater concept and which is why I am using a stepper because I want to expand the concept of my project and will probably use certain locations to move to as well.
They will be triggered by sensor data provided by an external esp32 that is sending the data. While that the loop is constantly moving and sometimes falls out of line because of the incoming data.

    int sensorVal = digitalRead(limit_switch);

isn't it unnecessary to read the limit_switch at this point. is there a need for sensorVal?

    Serial.println("onTree");
    delay(2000);

why is there a 3 sec delay here when there is a 4 sec delay later?

    Serial.println ("loose");
    digitalWrite (solenoid, HIGH);
    delay (3000);
    digitalWrite (solenoid, LOW);

doesn't this release the line and shouldn't it be after the limit switch is reached (and the motor stopped)?

    Serial.println ("up");
    stepper.setSpeed (4000);
    stepper.runSpeed ();

    // wait for limit
    while (digitalRead (limit_switch) == HIGH)
        ;

the above seems correct

    if( digitalRead(limit_switch) == LOW){
        Serial.println ("stop");
        stepper.setSpeed (0);
        stepper.runSpeed ();
    }

is there a need to check that the limit switch is deactivated? shouldn't you stop the motor immediately when the limit switch is reached?

    delay(4000);
}

Any ideas why my stepper is not moving anymore. Have i blocked it anywhere or not initialised?

#include <AccelStepper.h>

#define limit_switch 2 // Pin 9 connected to Home Switch (MicroSwitch)
#define solenoid 8
AccelStepper stepper(1, 13, 12);

//================================================================================

void setup()
{
  pinMode(limit_switch, INPUT_PULLUP);
  pinMode(solenoid, OUTPUT);

  stepper.setMaxSpeed(4000);
  stepper.setAcceleration(4000);


  Serial.begin(115200);
}


//================================================================================

void loop(){

    Serial.println ("up");
    stepper.setSpeed (4000);
    stepper.runSpeed ();
   // wait for limit 
    while (digitalRead (limit_switch) == HIGH);

    Serial.println ("stop");
    stepper.setSpeed (0);
    stepper.runSpeed ();

    Serial.println ("loose");
    digitalWrite (solenoid, LOW);
    delay (3000);
    digitalWrite (solenoid, HIGH);

    delay(4000);
}

did i confuse the issue by reversing these line in the code I posted?

if not sure, put those lines in setup() and comment everything out in loop()

are you sure the limit_switch is reading LOW when you start?

looking at the AFMotor_constantSpeed example, does runSpeed() need to be repeatedly called?

should the code be?

    while (digitalRead (limit_switch) == HIGH)
        stepper.runSpeed ();

Yes, that seems to be right.

Seems to be working for now.

thank you

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.