Are interrupts the right thing to use for my robot?

Hello all,
So I have this old motorized wheelchair that I am trying to convert into a robot. I replaced the original motor driver with a sabertooth 2x12 and I’m using an Arduino micro to talk to it. The motors shaft goes all the way threw so I attached a magnet and a Hall Effect sensor to the back side to act as a rotary encoder. My current goal is to be able to tell the robot to move forward a certain amount of feet then stop. I wrote some code to do this linearly however this didn’t work so well. Then I learned about interrupts and that sounded like exactly what I needed. So I tried my hand at that and things went wrong on several different levels.

LEVEL ONE: I have never seemed to be able to properly drive the motors it seems like any time I put the command to turn them on inside of a loop or if statement they decide to do what they want and move sporadically and unpredictably

LEVEL TWO: I feel like the interrupts are interrupting themselves and the thing I set in place to stop the wheels from moving forward because I can tell it to move 14 rotary encoder clicks forward and one wheel will continue moving way past 1000 clicks while the other stops

LEVEL THREE: couple times I guess I placed my interrupts wrong because when I uploaded the code windows would stop recognizing the Arduino and my driver would break until I uploaded the blink sketch after pressing the reset button which also reloaded and fixed my drivers. Then if I deleted one of my interrupts it would upload normally.

LEVEL FOUR: my Hall Effect sensors seem to not work right when the motors are on. They tend to jump from 1 to 200 clicks in a matter of seconds. This in turn floods my serial port and crashes the Arduino ide.

So as you can see there are several flaws somewhere in the system whether it’s hardware or software I don’t know. Am I approaching this the right way or is there some Arduino secret I don’t know about that would make my life easier? If I am approaching this right could you take a look at my code below and see what I’m doing wrong.

  #include <Servo.h>//the motor driver uses this library
    
    Servo LEFT, RIGHT;//left wheel right wheel
    
    int RclickNum=0;//used for the rotory encoder
    int LclickNum=0;//these are the number of "clicks" each wheel has moved
    
    int D =115;//Drive
    int R =70;//Reverse
    int B =90;//Break
    
    int Linterrupt = 1;//these are the interrupt numbers. 0 = pin 3 and 1 = pin 2
    int Rinterrupt = 0;
    
    int clickConvert = 7;// how many rotery encoder clicks equal a foot
    
    void setup()
    {
      Serial.begin(9600); //starting serial communication 
      LEFT.attach( 9, 1000, 2000);//attaching the motor controller that is acting like a servo
      RIGHT.attach(10, 1000, 2000);
      attachInterrupt(Linterrupt, LclickCounter, FALLING);//attaching the rotory encoders as interrupts that will 
      attachInterrupt(Rinterrupt, RclickCounter, FALLING);//trip when the encoder pins go from high to low
    
    
    }
    void loop()
    {//This is for controling the robot using the standard wasd format
      int input= Serial.read();
      if(input == 'a')
        left(2);
      if(input == 'd')
        right(2);
      if(input == 'w')
        forward(2);
      if(input == 's')
        backward(2);
      if(input == 'e')
        STOP();
    }
    
    void forward(int feet)//this is called when w is sent threw the serial port and is where i am testing all of my code. 
    {
      interrupts(); //turn on the interrupts
      while(RclickNum < feet * clickConvert || LclickNum < feet * clickConvert)// while either the left or right wheel hasnt made it to the desired distance
      {
        if(RclickNum < feet * clickConvert)//check if the right wheel has gone the distance
          RIGHT.write(D); //make the right wheel move
        else
          RIGHT.write(B);//stop the right wheel
    
        if(LclickNum < feet * clickConvert)
          LEFT.write(D);
        else
          LEFT.write(B);
      }
      noInterrupts();//stop the interrupts 
      resetCount();//set the click counters back to zero
    }
    
    //once i have the forward function working i will implament it through out the other functions
    //----------------------------------------------------------------------
    
    void backward(int feet)
    {
      RIGHT.write(R);
      LEFT.write(R);
    }
    
    void left(int feet)
    {
      RIGHT.write(D);
      LEFT.write(R);
    }
    
    void right(int feet)
    {
      RIGHT.write(R);
      LEFT.write(D);
    }
    
    void STOP()
    {
      resetCount();
      RIGHT.write(B);
      LEFT.write(B);
    }
    
    void LclickCounter()//this is called by the left encoder interrupt
    {
      LclickNum++; 
      Serial.print("L");
      Serial.println(LclickNum); 
    }
    
    void RclickCounter()//this is called by the right encoder interrupt
    {
      RclickNum++;
      M Serial.print("R");
      Serial.println(RclickNum);
    }
    
    
    void resetCount()
    {
      RclickNum=0;
      LclickNum=0;
    }

If a thing behaves erritacally when motors are turned on the cause is almost always lack of power supply decoupling.

Hi, you need to declare RclickNum and LclickNum as volatile because they are updated by the interrupt routines. Also not a good idea to use Serial.print in an interrput routine. Use high baud rate and keep the messages short. As soon as you are confident the routines are working, take the Serial.prints out.

Paul

Take the Serial.print statements out of the interrupt routines NOW.

If you want to see the number of clicks put a suitable print statement inside loop().

...R

If your "loop" code is not cycling fast enough to catch events - such as the opto-interrupter - then there is something wrong with the code.

The problem here is the use of serial communications. The standard serial operations are very slow and because they are themselves interrupt-driven, cannot be used in an interrupt routine. In general, you should not be calling functions in an interrupt routine.

You then have the choice - you can either perform serial communications - listening for commands - or execute time and event-critical actions, but not both. Even using interrupts, it is difficult to perform counting functions whilst executing communications as it would be necessary to make decisions within the interrupt routine on the basis of the event and time counts.

If you can possibly arrange your program to either count something or communicate at any particular time, that is what you need to do and if you can do that, then it follows that you do not need interrupts in the first place.

Ok I will take the serial commands out of the interrupts, set my variables to volitile, and question my use of interrupts all together. About the decoupling cap in my power supply, I am using two 12v sealed led acid batteries powering the motors and driver alone would I need a cap, could there really be that much noise in that circuit? What about the hall effect sensor? Could the magnets in the motor be causing such a large jump in the click count? or is there something else happening?

If you suspect you have an electrical problem such as an overload or noise on the circuit caused by the motors, you can investigate by disconnecting the wires to the motors (leave the sketch the same) and see whether the problems stop. That would give you an idea whether it was genuinely an electrical problem, or some other logical fault in your sketch or hardware circuit.

am using two 12v sealed led acid batteries powering the motors and driver alone would I need a cap, could there really be that much noise in that circuit?

You have a motor, and a big one at that, what can generate more interference than a motor?

what can generate more interference than a motor?

A spark gap? :D

I have two thing to your project.

On on the motor and battery:

  • How much current do your motor draw when runing?
  • How much current do your motor draw when it stalls?

My bet is that the Sabertooth motorcontroller is too small for your motors.

On one your Hall Effect sensor and magnet: What does a motor run? is it magnets? You have only one point in your encoder right now, how accurate do you thing you can drive your motors with one point in the encoder?

Have you tried just to run your motors without your encoders?

I would also drive your arduino from a different battery than you motors.