Bummer! failed to call stepper

Hello, someone could help me with a firmware to control a STEPPER MOTOR, is a bipolar STEPPER MOTOR, the driver is L298, I’m trying to control it using a function in a cloud, the idea is to send a command from the console:

“right” the STEPPER MOTOR turns to the right; ¨ “left” the STEPPER MOTOR turns to the left;
but I want the STEPPER MOTOR turns in a loop with any command, the console sent me an error and for a moment the LED of my photon turned red, I received an error message.
image

The code is:

// variables y pines BobinaA 
#define ENA D0 
#define IN1 D1   
#define IN2 D2  

// variables y pines Bobina B
#define IN3 D3
#define IN4 D4  
#define ENB D5 

// variables de entrada
int inti=0;
int i=0;

void setup() {
    pinMode(ENA, OUTPUT);
    pinMode(ENB, OUTPUT);
    pinMode(IN1, OUTPUT);
    pinMode(IN2, OUTPUT);
    pinMode(IN3, OUTPUT);
    pinMode(IN4, OUTPUT);
    Particle.function("stepper",stepperToggle);
}

void loop() {
}

int stepperToggle(String command) {
  if (command=="derecha" )  {
    for(inti = 0; i<12; i++){
      digitalWrite(IN1,LOW);
      digitalWrite(IN2,HIGH);
      digitalWrite(IN3,HIGH);
      digitalWrite(IN4,LOW);
      delay(300);
    
      digitalWrite(IN1,LOW);
      digitalWrite(IN2,HIGH);
      digitalWrite(IN3,LOW);
      digitalWrite(IN4,HIGH);
      delay(300);
    
      digitalWrite(IN1,HIGH);
      digitalWrite(IN2,LOW);
      digitalWrite(IN3,LOW);
      digitalWrite(IN4,HIGH);
      delay(300);
   
      digitalWrite(IN1,HIGH);
      digitalWrite(IN2,LOW);
      digitalWrite(IN3,HIGH);
      digitalWrite(IN4,LOW);
      delay(300);     
    }
   
    return 1;
  }
  else if (command=="izquierda") {
    for(int j = 0; j<12; j++){
      digitalWrite(IN1,HIGH);
      digitalWrite(IN2,LOW);
      digitalWrite(IN3,HIGH);
      digitalWrite(IN4,LOW);
      delay(300);
   
      digitalWrite(IN1,HIGH);
      digitalWrite(IN2,LOW);
      digitalWrite(IN3,LOW);
      digitalWrite(IN4,HIGH);
      delay(300);
    
      digitalWrite(IN1,LOW);
      digitalWrite(IN2,HIGH);
      digitalWrite(IN3,LOW);
      digitalWrite(IN4,HIGH);
      delay(300);
   
      digitalWrite(IN1,LOW);
      digitalWrite(IN2,HIGH);
      digitalWrite(IN3,HIGH);
      digitalWrite(IN4,LOW);
      delay(300);
    }
    return 2;
  }
    
  return -1;
}

The error in console comes from the fact that your function is running too long so the request times out.

BTW, this seems wrong

  for(inti = 0; i<12; i++){ 

it should rather be

  for(int i = 0; i<12; i++){ 

Before, I tried without the For loop, what I really want to do is that the stepper motor continues to turn until the command changed to turn in another direction, but each code fragment only run once, and for the stepper motor continues rotating I have to send the command repeatedly

// variables y pines BobinaA 
  
    #define ENA D0 
    #define IN1 D1   
    #define IN2 D2  

    
// variables y pines Bobina B
  
    #define IN3 D3
    #define IN4 D4  
    #define ENB D5 
// variables de entrada

void setup() {
    pinMode(ENA, OUTPUT);
    pinMode(ENB, OUTPUT);
    pinMode(IN1, OUTPUT);
    pinMode(IN2, OUTPUT);
    pinMode(IN3, OUTPUT);
    pinMode(IN4, OUTPUT);
    Particle.function("stepper",stepperToggle);
}

void loop() {

}
int stepperToggle(String command) {
if (command=="derecha" )  {

    digitalWrite(IN1,LOW);
    digitalWrite(IN2,HIGH);
    digitalWrite(IN3,HIGH);
    digitalWrite(IN4,LOW);
    delay(300);
    
    digitalWrite(IN1,LOW);
    digitalWrite(IN2,HIGH);
    digitalWrite(IN3,LOW);
    digitalWrite(IN4,HIGH);
    delay(300);
    
    digitalWrite(IN1,HIGH);
    digitalWrite(IN2,LOW);
    digitalWrite(IN3,LOW);
    digitalWrite(IN4,HIGH);
    delay(300);
   
    digitalWrite(IN1,HIGH);
    digitalWrite(IN2,LOW);
    digitalWrite(IN3,HIGH);
    digitalWrite(IN4,LOW);
    delay(300);     

   
    return 1;
}

   
else if (command=="izquierda") {

    digitalWrite(IN1,HIGH);
    digitalWrite(IN2,LOW);
    digitalWrite(IN3,HIGH);
    digitalWrite(IN4,LOW);
    delay(300);
   
    digitalWrite(IN1,HIGH);
    digitalWrite(IN2,LOW);
    digitalWrite(IN3,LOW);
    digitalWrite(IN4,HIGH);
    delay(300);
    
    digitalWrite(IN1,LOW);
    digitalWrite(IN2,HIGH);
    digitalWrite(IN3,LOW);
    digitalWrite(IN4,HIGH);
    delay(300);
   
    digitalWrite(IN1,LOW);
    digitalWrite(IN2,HIGH);
    digitalWrite(IN3,HIGH);
    digitalWrite(IN4,LOW);
    delay(300);
    
   return 2;
    }
   
else { return -1;}
  
}

That's to be expected.
Since the function only is called once.

If you want the process to repeat you should just set a "flag" which direction you want to turn (e.g. -1, 0, +1) and then act according to that flag in loop().

BTW, could you please format your code by use of this button image and also try to have adopt a consistent indenting scheme (e.g. code inside a function should not anchor on the leftmost column, or your return 2; is un-indented, ...).

1 Like

very interesting, that flag could take a integer or binary value, couldn´t it? ; Well, I do not really know many details of the programming, I do not know where to apply those buttons <> but I will try and then share the code

You could do this

// variables y pines BobinaA 
const int ENA = D0; 
const int IN1 = D1;   
const int IN2 = D2;  
    
// variables y pines Bobina B
const int IN3 = D3;
const int IN4 = D4;  
const int ENB = D5; 

enum dir_t {
  STOP  = 0,                      // to stop and depower the stepper
  STEPS = 4,                      // this will cause the stepper to stop and hold torque
  RIGHT = (STEPS + 1),            // step increment
  LEFT  = (STEPS - 1),            // in conjunction with % STEPS is equal to -1 causing a step decrement
};
dir_t myDirection = STOP;

int doStep(dir_t direction, uint32_t stepDelay = 300);

void setup() {
    Particle.function("stepper", stepperToggle);

    pinMode(ENA, OUTPUT);
    pinMode(ENB, OUTPUT);
    pinMode(IN1, OUTPUT);
    pinMode(IN2, OUTPUT);
    pinMode(IN3, OUTPUT);
    pinMode(IN4, OUTPUT);
}

void loop() {
  if (myDirection) doStep(myDirection);
}

int stepperToggle(String command) {
  if     (command == "derecha"  ) 
    myDirection = RIGHT;
  else if(command == "izquierda") 
    myDirection = LEFT;
  else {
      myDirection = STOP;
      doStep(myDirection, 0);     // immediately stop
  }

  return myDirection;
}

int doStep(dir_t direction, uint32_t stepDelay) {
  static uint32_t msLastStep = 0; // when did the last step happen?
  static int      lastStep   = 0; // which step did we do last?
  int             step;

  // keep the code non-blocking - so when the time is *not* up bail out immediately
  if (millis() - msLastStep < stepDelay && msLastStep) return lastStep;
  msLastStep = millis();          // remember the time when we performed that step

  if (direction) {
    step = lastStep + direction;  // increment or decrement the step count 
    step %= STEPS;                // wrap round on over-/underflow
  }
  else                            // when direction == STOP
    step = -1;                    // depower stepper coils
 
  switch(step) {                  // power stepper coils accoring to step count
    case 0:
      pinSetFast(IN1);
      pinResetFast(IN2);
      pinSetFast(IN3);
      pinResetFast(IN4);
      break;
    case 1:
      pinSetFast(IN1);
      pinResetFast(IN2);
      pinResetFast(IN3);
      pinSetFast(IN4);
      break;
    case 2:    
      pinResetFast(IN1);
      pinSetFast(IN2);
      pinResetFast(IN3);
      pinSetFast(IN4);
      break;
    case 3:   
      pinResetFast(IN1);
      pinSetFast(IN2);
      pinSetFast(IN3);
      pinResetFast(IN4);
      break;
    default:                      // invalid step count causes stepper coils to be powered off
      pinResetFast(IN1);
      pinResetFast(IN2);
      pinResetFast(IN3);
      pinResetFast(IN4);
      return lastStep;
  }

  lastStep = step;
  return step;
}

(had some syntax errors - now corrected)

1 Like

excellent great support, but I still do not understand this very well

int step(dir_t direction, uint32_t stepDelay = 300) {
static uint32_t msLastStep = 0; // when did the last step happen?
static int lastStep = 0; // which step did we do last?
int step;

The second paramter is optional. When you don't pass it in the default value of 300ms will be used.

static variables keep their value even when you leave the function.
When you want to know about the state of the function when it was last called but don't want to use a global variable you can use static.

Anything else that's unclear?

1 Like

pinSetFast ???

https://docs.particle.io/reference/device-os/firmware/photon/#low-level-input-output

One word of caution - if you should ever happen to mechanically drive the motor, you may backfeed voltage to the GPIO pins which may damage them, especially if you are driving a LOW pin into negative - but that’s true regarless of pinSetFast()/pinResetFast().

1 Like

I read the references and I see that there are many resources that are unknown for me, I think I need to read more, Why (my Direction) does not have a comparison with a == sign?
if (myDirection) doStep(myDirection);

I thank you

if (myDirection) is short hand for if (myDirection != 0) and if (!myDirection) would be short hand for if (myDirection == 0)

1 Like

that is to check if the stepper motor should continue to rotate in one direction or should stop according to "enum", isn't it?

I have learned a lot this day thanks to you scruff

1 Like

Amongst other things enum is a way to make your code a bit more readable. Instead of “abstract” numeric values you can use the “names” for these values.
Another advantage of using enum as parameter type is to restrict the possible values without the need to check for invalid entries.

I have chosen these values for RIGHT and LEFT to make the “over-/underflow” treatment as simple as possible when using the modulo operator (%). With +1/-1 underflow would be more difficult since (0 - 1) % 4 would give you -1 instead of 3 which would be the next step after 0 on left rotation. But with 0 + (4 - 1) % 4` is 3 - as expected.

I have slightly changed the code above to also allow STEPS as possible parameter for doSteps() which would make the stepper stop but also keep the torque by keeping the coils powered. But that needs to be done with care since the permanent current will cause the coils to heat more than during rotation.

1 Like

I find this information very interesting, that can help me to add a DC motor and a servo, in the case of the servo we would have to work with the angles

1 Like

on the other hand to the program that you shared with me, add a small html application, with the following details and it works great for me:

but every time I activate the options, the web page returns a value of enum, I would not like that it appears to me every time I activate the STEPPER MOTOR, how can I make that notification stop appearing?, although that is not a problem, only that I must return to the previous page to select another option.
image

1 Like

WIth a successful POST request for a Particl.function() the cloud will always hand you back the return value of that function - that’s by design. Your page has to deal with the response and act accordingly.

1 Like

But that does not happen with Android, do it?

I will try to modify the code to control the servo, thanks you have been very helpful for me and I have learned a lot.
How I could train at your level, in addition to reading the references?, I would like to be able to program and create products.
Thanks
best reggards