Sketch seemingly "hangs" while executing



  • Hi everyone, recently I was trying to control some stepper motors using the S_COVER sensor. However, I have been running into this issue where the code seems to "hang" at consistent points in my code.

    In my case, the code consistently "crashes" at this section here:

    f(message.sensor == CHILD_ID){
        switch(message.type){
          case V_UP:
            desiredShutterLevel = 100;
            #ifdef MY_DEBUG
              Serial.println("Shutter State is UP");
              Serial.print("currentShutterLevel = "); Serial.println(currentShutterLevel);
              Serial.print("desiredShutterLevel = "); Serial.println(desiredShutterLevel);
            #endif
            break;
    

    I deduced this from the Serial monitor as the prints would cut off halfway printing this line:

    Serial.print("desiredShutterLevel = "); Serial.println(desiredShutterLevel);
    

    It does this consistently which baffles me as I can't seem to find anything wrong with my code (recursive loops) that may cause the code to crash.

    Serial Monitor.PNG

    Any advice would be greatly appreciated!

    Full Code:

    #include <AccelStepper.h>
    
    const byte dirPin1 = A0;
    const byte stepPin1 = A1;
    const byte enPin1 = A2;
    const byte dirPin2 = A3;
    const byte stepPin2 = A4;
    const byte enPin2 = A5;
    const byte dirPin3 = 4;
    const byte stepPin3 = 3;
    const byte enPin3 = 8;
    const byte dirPin4 = 7;
    const byte stepPin4 = 6;
    const byte enPin4 = 5;
    const bool enOne = true, enTwo = true, enThree = true, enFour = true;
    const bool dirOne = true, dirTwo = true, dirThree = true, dirFour = true;
    const int stepmmOne = 160, stepmmTwo = 160, stepmmThree = 160, stepmmFour = 160;
    
    const byte endstopup = A6, endstopdown = A7;
    
    //long timer = 0;
    
    #define motorInterfaceType 1
     AccelStepper stepperOne(motorInterfaceType, stepPin1, dirPin1);
     AccelStepper stepperTwo(motorInterfaceType, stepPin2, dirPin2);
     AccelStepper stepperThree(motorInterfaceType, stepPin3, dirPin3);
     AccelStepper stepperFour(motorInterfaceType, stepPin4, dirPin4);
    
    #define MY_DEBUG
    #define MY_RADIO_RF24
    #include <MySensors.h>
    #define CHILD_ID 0
    //#define MY_TRANSPORT_WAIT_READY_MS 1000
    
    int currentShutterLevel = 0, desiredShutterLevel = 0;
    enum currentState {
      STOP,
      UP,
      DOWN,
    };
    static int currentState = STOP; //the initial state is STOP because it is not moving
    boolean requested = false;
    boolean isAlrMoving = false;
    boolean initialValueSent = false;
    
    int totalDist = 150; //in mm
    int stepsPerMM = 160;
    int currentSteps = 0;
    int desiredSteps = 0;
    int stepsToMove = 0, oldStepsToMove = 0;
    
    MyMessage upMessage(CHILD_ID, V_UP);
    MyMessage downMessage(CHILD_ID, V_DOWN);
    MyMessage stopMessage(CHILD_ID, V_STOP);
    MyMessage percMessage(CHILD_ID, V_PERCENTAGE);
    
    void sendState(){
      send(upMessage.set(currentState == UP));
      wait(500);
      send(downMessage.set(currentState == DOWN));
      wait(500);
      send(stopMessage.set(currentState == STOP));
      wait(500);
      send(percMessage.set(currentShutterLevel));
    }
    void setup() {
    Serial.begin(115200);
    stepperOne.setEnablePin(enPin1);
    stepperOne.setPinsInverted(dirOne,false,enOne);
    stepperOne.setMaxSpeed(1000);
    stepperOne.setAcceleration(50);
    stepperOne.setSpeed(200);
    
    stepperTwo.setEnablePin(enPin2);
    stepperTwo.setPinsInverted(dirTwo,false,enTwo);
    stepperTwo.setMaxSpeed(1000);
    stepperTwo.setAcceleration(50);
    stepperTwo.setSpeed(200);
    
    stepperThree.setEnablePin(enPin3);
    stepperThree.setPinsInverted(dirThree,false,enThree);
    stepperThree.setMaxSpeed(1000);
    stepperThree.setAcceleration(50);
    stepperThree.setSpeed(200);;
    
    stepperFour.setEnablePin(enPin4);
    stepperFour.setPinsInverted(dirFour,false,enFour);
    stepperFour.setMaxSpeed(1000);
    stepperFour.setAcceleration(50);
    stepperFour.setSpeed(200);
    
    pinMode(endstopup, INPUT_PULLUP);
    pinMode(endstopdown, INPUT_PULLUP);
    }
    
    void presentation()
    {
      sendSketchInfo("Hydroponics Stepper Motors", "1.0");
      wait(1000);
      present(CHILD_ID, S_COVER);
    }
    
    void loop() {
      if(!initialValueSent){
        #ifdef MY_DEBUG
          Serial.println("Sending initial values!");
        #endif
        sendState();
        initialValueSent = true;
      }
      
      //requesting percentage of height
      if(!requested){
        request(CHILD_ID, V_PERCENTAGE);
        requested = true;
      }
      if(currentShutterLevel ==! desiredShutterLevel){
        int levelsToMove = desiredShutterLevel - currentShutterLevel;
        stepsToMove = map(levelsToMove,0,0,100,stepsPerMM * totalDist);
        if(stepsToMove ==! oldStepsToMove){
          Serial.print("Set distance to move for steppers: ");Serial.println(stepsToMove);
          //logic
          oldStepsToMove = stepsToMove;
        }
      }
    }
    void receive(const MyMessage &message)
    {
    #ifdef MY_DEBUG
      Serial.print("Received a message from sensor: ");
      Serial.println(String(message.sensor));
      Serial.print("Message type: ");
      Serial.println(String(message.type));
    #endif
      if(message.sensor == CHILD_ID){
        switch(message.type){
          case V_UP:
            desiredShutterLevel = 100;
            #ifdef MY_DEBUG
              Serial.println("Shutter State is UP");
              Serial.print("currentShutterLevel = "); Serial.println(currentShutterLevel);
              Serial.print("desiredShutterLevel = "); Serial.println(desiredShutterLevel);
            #endif
            break;
          case V_DOWN:
            desiredShutterLevel = 0;
            #ifdef MY_DEBUG
              Serial.println("Shutter State is DOWN");
            #endif
            break;
          case V_STOP:
            desiredShutterLevel = currentShutterLevel;
            #ifdef MY_DEBUG
              Serial.print("Halt called! Stopping all motors at pos: "); Serial.println(currentShutterLevel);
            #endif
            break;
          case V_PERCENTAGE:
            int pos = message.getInt();
            if(pos > 100) pos = 100;
            if(pos < 0) pos = 0;
            desiredShutterLevel = pos;
            #ifdef MY_DEBUG
              Serial.print("Shutter State is PERC = "); Serial.println(pos);
            #endif
            break;
        }
      }
      #ifdef MY_DEBUG
        Serial.print("Exiting this message with currentState = "); Serial.print(currentState);
      #endif
      return;
    }
    


  • I've had similar issues, which in the end was caused by too little memory.
    What's is the memory usage saying? All these print statements require a lot of memory.


  • Mod

    Printing to serial is quite slow, and happens sort of in the background. I say sort of, because the Arduino doesn't really support multitasking. But it may continue executing code after the print statement. To really determine where it hangs, add some wait() calls. Serial.flush might also work. Just to make sure you're not chasing shadows.

    I can't see anything in the sketch that looks off. It also looks like you're not currently actuating the steppers? Is that correct? A common cause for strange stuff is when something (like a stepper) draws power which causes the power supply to the Arduino to become unstable.

    Electric's suggestion on ram could be a culprit as well.



  • Hi there,

    Thanks for the replies! It seemed that the culprit was my stupidity. I forgot that the AccelStepper library's stepper.moveTo() function's argument was the absolute rather than the relative position of the stepper motor. As such my code would end up trying to push the stepper motor to extreme values (because I thought I needed to input a negative to move to the left etc) and this caused weird things to happen, most likely this crashing as well.

    In any case I'm glad the issue has been resolved.

    @electrik the programme takes up 72% of storage space and 64% of dynamic memory, so I will definitely cut out the Serial logs once I am done debugging.

    @mfalkvidd yikes you're right it seems I had forgotten to include the function to run the steppers. Anyways for reference sake I'll drop my final code here (from the last I tested it is working but with the minor issue of the motors having to travel to the end of their move before it can reverse direction, which I have no clue why it happens but I don't mind it):

    #include <AccelStepper.h>
    
    const byte dirPin1 = A0;
    const byte stepPin1 = A1;
    const byte enPin1 = A2;
    const byte dirPin2 = A3;
    const byte stepPin2 = A4;
    const byte enPin2 = A5;
    const byte dirPin3 = 4;
    const byte stepPin3 = 3;
    const byte enPin3 = 8;
    const byte dirPin4 = 7;
    const byte stepPin4 = 6;
    const byte enPin4 = 5;
    const bool enOne = true, enTwo = true, enThree = true, enFour = true;
    const bool dirOne = true, dirTwo = true, dirThree = true, dirFour = true;
    const int stepmmOne = 160, stepmmTwo = 160, stepmmThree = 160, stepmmFour = 160;
    
    const byte endstopup = A6, endstopdown = A7;
    
    //long timer = 0;
    
    #define motorInterfaceType 1
     AccelStepper stepperOne(motorInterfaceType, stepPin1, dirPin1);
     AccelStepper stepperTwo(motorInterfaceType, stepPin2, dirPin2);
     AccelStepper stepperThree(motorInterfaceType, stepPin3, dirPin3);
     AccelStepper stepperFour(motorInterfaceType, stepPin4, dirPin4);
    
    #define MY_DEBUG
    #define MY_RADIO_RF24
    #include <MySensors.h>
    #define CHILD_ID 0
    //#define MY_TRANSPORT_WAIT_READY_MS 1000
    
    int currentShutterLevel = 0, desiredShutterLevel = 0;
    enum currentState {
      STOP,
      UP,
      DOWN,
    };
    static int currentState = STOP; //the initial state is STOP because it is not moving
    boolean requested = false;
    boolean isAlrMoving = false;
    boolean initialValueSent = false;
    boolean receivedStop = false;
    
    int totalDist = 150; //in mm
    int stepsPerMM = 160;
    int currentSteps = 0;
    int desiredSteps = 0;
    int stepsToMove = 0, oldStepsToMove = 0;
    int levelsToMove = 0;
    int levelsToGo = 0;
    int savedShutterLevel = 0;
    int stepSpeed = 50;
    int stepAccel = 1000;
    
    MyMessage upMessage(CHILD_ID, V_UP);
    MyMessage downMessage(CHILD_ID, V_DOWN);
    MyMessage stopMessage(CHILD_ID, V_STOP);
    MyMessage percMessage(CHILD_ID, V_PERCENTAGE);
    
    void sendState(){
      #ifdef MY_DEBUG
        Serial.println("Sending states: ");
        Serial.print("UP: "); Serial.println(currentState == UP);
        Serial.print("DOWN: "); Serial.println(currentState == DOWN);
        Serial.print("STOP: "); Serial.println(currentState == STOP);
        Serial.print("PERC: "); 
        Serial.println(currentShutterLevel);
      #endif
      send(upMessage.set(currentState == UP));
      send(downMessage.set(currentState == DOWN));
      send(stopMessage.set(currentState == STOP));
      send(percMessage.set(desiredShutterLevel));
    }
    void setup() {
    Serial.begin(115200);
    stepperOne.setEnablePin(enPin1);
    stepperOne.setPinsInverted(dirOne,false,enOne);
    stepperOne.setMaxSpeed(stepSpeed);
    stepperOne.setAcceleration(stepAccel);
    //stepperOne.setSpeed(50);
    
    stepperTwo.setEnablePin(enPin2);
    stepperTwo.setPinsInverted(dirTwo,false,enTwo);
    stepperTwo.setMaxSpeed(stepSpeed);
    stepperTwo.setAcceleration(stepAccel);
    //stepperTwo.setSpeed(50);
    
    stepperThree.setEnablePin(enPin3);
    stepperThree.setPinsInverted(dirThree,false,enThree);
    stepperThree.setMaxSpeed(stepSpeed);
    stepperThree.setAcceleration(stepAccel);
    //stepperThree.setSpeed(50);;
    
    stepperFour.setEnablePin(enPin4);
    stepperFour.setPinsInverted(dirFour,false,enFour);
    stepperFour.setMaxSpeed(stepSpeed);
    stepperFour.setAcceleration(stepAccel);
    //stepperFour.setSpeed(50);
    
    pinMode(endstopup, INPUT_PULLUP);
    pinMode(endstopdown, INPUT_PULLUP);
    }
    
    void presentation()
    {
      sendSketchInfo("Hydroponics Stepper Motors", "1.0");
      wait(1000);
      present(CHILD_ID, S_COVER);
    }
    
    void loop() {
      /*if(!initialValueSent){
        #ifdef MY_DEBUG
          Serial.println("Sending initial values!");
        #endif
        sendState();
        initialValueSent = true;
      }
      */
      
      //requesting percentage of height
      if(!requested){
        request(CHILD_ID, V_PERCENTAGE);
        #ifdef MY_DEBUG
          Serial.println("Requesting initial position of lights");
        #endif
      }
        if(currentShutterLevel != desiredShutterLevel || receivedStop){ //allow the setting of new positions if a STOP is called 
        //currentShutterLevel and desiredShutterLevel are used to detect the change in parameters
        if(!isAlrMoving){ //this ensures the following code is only executed once
          enableAllSteppers();
          stepsToMove = map(desiredShutterLevel,0,100,0,totalDist*stepsPerMM);
          Serial.print("Moving to: "); Serial.println(stepsToMove);
          moveAllSteppers(stepsToMove);
          isAlrMoving = true; 
          sendState();
        }
        if(stepperOne.distanceToGo() != 0){
        } else{
            currentShutterLevel = desiredShutterLevel;
            currentState = STOP;
            sendState();
            disableAllSteppers();
        }
        receivedStop = false;
        }else{ //if desired and current are the same - either because there is no movement or when we call STOP, then check to see 
          //if there was a change in the state of STOP. If there was then send the state.
        if(receivedStop){
        sendState();
        receivedStop = false;
        }
        disableAllSteppers();
      }
      runAllSteppers();
      if(analogRead(endstopup)>10 && currentState == UP){ //if the top endstop is triggered and the shutter was moving up
          #ifdef MY_DEBUG
            Serial.println("Top Endstop has been activated!");
          #endif
        receivedStop = true;
        setCurrentPositionofAll(100);
        desiredShutterLevel = 100;
        currentShutterLevel = 100;
        currentState = STOP;
      } else if(analogRead(endstopdown)>10 && currentState == DOWN){ //if the bottom endstop is triggered and the shutter was moving down
        #ifdef MY_DEBUG
            Serial.println("Bottom Endstop has been activated!");
        #endif
        receivedStop = true;
        setCurrentPositionofAll(0);
        desiredShutterLevel = 0;
        currentShutterLevel = 0;
        currentState = STOP;
      }
     
    }
    void receive(const MyMessage &message)
    {
    #ifdef MY_DEBUG
      Serial.print("Received a message from sensor: ");
      Serial.println(String(message.sensor));
      Serial.print("Message type: ");
      Serial.println(String(message.type));
    #endif
    isAlrMoving = false; //since if we receive a message it means that we need to do something, we can allow the position to be reset
      if(message.sensor == CHILD_ID){
        switch(message.type){
          case V_UP:
            desiredShutterLevel = 100;
            currentState = UP;
            #ifdef MY_DEBUG
              Serial.println("Shutter State is UP");
              Serial.print("currentShutterLevel = "); Serial.println(currentShutterLevel);
              Serial.print("desiredShutterLevel = "); Serial.println(desiredShutterLevel);
            #endif
            break;
            
          case V_DOWN:
            desiredShutterLevel = 0;
            currentState = DOWN;
            #ifdef MY_DEBUG
              Serial.println("Shutter State is DOWN");
              Serial.print("currentShutterLevel = "); Serial.println(currentShutterLevel);
              Serial.print("desiredShutterLevel = "); Serial.println(desiredShutterLevel);
            #endif
            break;
            
          case V_STOP:
            receivedStop = true; //allow the loop to send states once
            currentShutterLevel = map(stepperOne.currentPosition(),-totalDist*stepsPerMM,totalDist*stepsPerMM,-100,100); //update the current state with the state that the stepper is actually at
            desiredShutterLevel = currentShutterLevel; //stop the steppers
            currentState = STOP;
            #ifdef MY_DEBUG
              Serial.print("Halt called! Stopping all motors at pos: "); Serial.println(currentShutterLevel);
            #endif
            break;
    
          case V_PERCENTAGE:
            int pos = message.getInt();
            if(pos > 100) pos = 100;
            if(pos < 0) pos = 0;
            if(!requested){
              currentShutterLevel = pos;
              desiredShutterLevel = pos;
              setCurrentPositionofAll(map(pos,0,100,0,totalDist*stepsPerMM));
              #ifdef MY_DEBUG
                Serial.print("Initialized! Current Shutter Level Set to: "); Serial.println(currentShutterLevel);
              #endif
              requested = true;
            } else{
              desiredShutterLevel = pos;
            }
            currentState = (desiredShutterLevel > currentShutterLevel)?UP:DOWN;
            #ifdef MY_DEBUG
              Serial.print("Shutter State is PERC = "); Serial.println(desiredShutterLevel);
              Serial.print("currentShutterLevel = "); Serial.println(currentShutterLevel);
              Serial.print("desiredShutterLevel = "); Serial.println(desiredShutterLevel);
            #endif
            break;
       }
      }
      #ifdef MY_DEBUG
        Serial.print("Exiting this message with currentState = "); Serial.println(currentState);
      #endif
    }
    void enableAllSteppers(void){
      stepperOne.enableOutputs();
      stepperTwo.enableOutputs();
      stepperThree.enableOutputs();
      stepperFour.enableOutputs();
    }
    void moveAllSteppers(int steps){
      stepperOne.moveTo(steps);
      stepperTwo.moveTo(steps);
      stepperThree.moveTo(steps);
      stepperFour.moveTo(steps);
    }
    void runAllSteppers(void){
      stepperOne.run();
      stepperTwo.run();
      stepperThree.run();
      stepperFour.run();
    }
    void disableAllSteppers(void){
      stepperOne.disableOutputs();
      stepperTwo.disableOutputs();
      stepperThree.disableOutputs();
      stepperFour.disableOutputs();  
    }
    void setCurrentPositionofAll(int pos){
      stepperOne.setCurrentPosition(pos);
      stepperTwo.setCurrentPosition(pos);
      stepperThree.setCurrentPosition(pos);
      stepperFour.setCurrentPosition(pos);
    }
    

    Thanks so much for your patience and suggestions!



Suggested Topics

20
Online

11.4k
Users

11.1k
Topics

112.7k
Posts