Disabling interrupts on a certain section of a code

Hi guys,

I am trying to disable interrupts for a small section of my codes. I am using 2 encoders on the front two wheels of my car and I want to use all four wheels to adjust the car and move it in a straight line when it deviates with the help of a compass. I have tried to use the detachInterrupt and attachInterrupt, but the program runs the same even without it.

void drive(int power_a, int power_b)
{
  int Camp_Speed = 100;
  getCompass();                                                     // Update Compass Heading
  bluetooth();

  // Constrain power to between -255 and 255
  power_a = constrain(power_a, -255, 255);
  power_b = constrain(power_b, -255, 255);

  if ( abs(desired_heading - compass_heading) <= compass_dev )      // If the Desired Heading and the Compass Heading are within the compass deviation, X degrees of each other then Go Forward
    // otherwise find the shortest turn radius and turn left or right
  {

    // Left motor direction
    if ( power_a < 0)
    {
      int Power_A = abs(power_a);
      motor2.setSpeed(Power_A);       
      motor2.run(BACKWARD);

      motor1.run(RELEASE);
      motor3.run(RELEASE);
    }
    else
    {
      int Power_A = abs(power_a);
      motor2.setSpeed(Power_A);       
      motor2.run(FORWARD);

      motor1.run(RELEASE);
      motor3.run(RELEASE);
    }

    // Right Motor direction
    if ( power_b < 0)
    {
      int Power_B = abs(power_b);
      motor4.setSpeed(Power_B);       
      motor4.run(BACKWARD);

      motor1.run(RELEASE);
      motor3.run(RELEASE);
    }
    else
    {

      int Power_B = abs(power_b);
      motor4.setSpeed(Power_B);       
      motor4.run(FORWARD);

      motor1.run(RELEASE);
      motor3.run(RELEASE);
    }
  }

  [b]else
  {
    detachInterrupt(digitalPinToInterrupt(enc_l_pin));
    detachInterrupt(digitalPinToInterrupt(enc_r_pin));

    int x = (desired_heading - 359);                          // x = the GPS desired heading - 360
    int y = (compass_heading - (x));                          // y = the Compass heading - x
    int z = (y - 360);                                        // z = y - 360

    if ((z <= 180) && (z >= 0))                               // if z is less than 180 and not a negative value then turn left
    { // otherwise turn right
      TurnLeft();
    }
    else
    {
     TurnRight();
    }
    attachInterrupt(digitalPinToInterrupt(enc_l_pin), countLeft, CHANGE);
    attachInterrupt(digitalPinToInterrupt(enc_r_pin), countRight, CHANGE);
  }[/b]
}
noInterrupts();
// critical, time-sensitive code here
interrupts();
// other code here

Copied straight from the arduino reference.

During the time that the undefined interrupt handlers are detached, the only thing you do is call TurnLeft() or TurnRight().

If you expect us to tell you why they behave the same with the interrupt handlers detached as when they are attached, you need to send each of us a PROVEN-TO-WORK crystal ball.

NoName12221:
I am trying to disable interrupts for a small section of my codes.

Why ?

...R

Yes Paul, you are right. With only using detachInterrupt(), once the program enters the else statement it tries to make it turn left or turn right without increment the counter in the ISR. However, once the car is within the compass deviation, I want to re-enable the interrupts so that the car can move straight for a certain distance with the help of interrupts. I will include the rest of the codes:

volatile unsigned long enc_l = 0;
volatile unsigned long enc_r = 0;

// Pins
const int enc_l_pin = 18;          // Motor A
const int enc_r_pin = 19;          // Motor B

void setup()
{
  Serial.begin(115200);                                            // Serial 0 is for communication with the computer
  Serial3.begin(9600);                                             // Serial 1 is for Bluetooth communication - DO NOT MODIFY - JY-MCU HC-06 v1.40
  //Serial1.begin(9600);                                             // Serial 3 is for GPS communication at 9600 baud - DO NOT MODIFY - Ublox Neo 6m

  Serial.println("Test!");
  Serial.print("\n");

  Wire.begin();                                                    // Join I2C bus used for the HMC5883L compass
  compass.begin();                                                 // initialize the compass (HMC5883L)
  compass.setRange(HMC5883L_RANGE_1_3GA);                          // Set measurement range
  compass.setMeasurementMode(HMC5883L_CONTINOUS);                  // Set measurement mode
  compass.setDataRate(HMC5883L_DATARATE_30HZ);                     // Set data rate
  compass.setSamples(HMC5883L_SAMPLES_8);                          // Set number of samples averaged
  compass.setOffset(118, 473);                                      // Set calibration offset

  // Buzzer
  pinMode(Buzzer_pin, OUTPUT);

  // Set up pins
  pinMode(enc_l_pin, INPUT_PULLUP);
  pinMode(enc_r_pin, INPUT_PULLUP);

  // Set up interrupts
  attachInterrupt(digitalPinToInterrupt(enc_l_pin), countLeft, CHANGE);
  attachInterrupt(digitalPinToInterrupt(enc_r_pin), countRight, CHANGE);

//Main Loop

void loop()
{
 setHeading();
 driveStraight(drive_distance, motor_power);                                                  
}

void driveStraight(float drive_distance, int motor_power)
{
  Serial.print("\n");
  Serial.println("num_tick_l \t num_tick_r \t diff_l \t diff_r \t enc_1_prev \t enc_r_prev \t Power_l \t Power_r \t Power_a \t Power_b ");
  Serial.println("=============================================================================================================================================");
  unsigned long num_ticks_l;
  unsigned long num_ticks_r;

  // Set initial motor power
  int power_l = motor_power;
  int power_r = motor_power;

  // Used to determine which way to turn to adjust
  unsigned long diff_l;
  unsigned long diff_r;

  // Reset encoder counts
  enc_l = 0;
  enc_r = 0;

  // Remember previous encoder counts
  unsigned long enc_l_prev = enc_l;
  unsigned long enc_r_prev = enc_r;

  // Calculate targer number of ticks
  float num_rev = (drive_distance * 10) / wheel_c;   // Convert to mm
  unsigned long target_count =  29; //num_rev * counts_per_rev;

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

  /*
    // Debug
    Serial.print("Driving for ");
    Serial.print(drive_distance);
    Serial.print(" cm(");
    Serial.print(target_count);
    Serial.print(" ticks) at ");
    Serial.print(motor_power);
    Serial.println(" Motor Power");
  */

  //Drive until on of the encoders reaches desired count
  while ((enc_l < target_count) && (enc_r < target_count))
  {

    bluetooth();                                // if new bluetooth value received break from loop
    if (blueToothVal == 5) {
      break;                                    // If a 'Stop' Bluetooth command is received then break from the Loop
    }

    // Sample number of encoder ticks
    num_ticks_l = enc_l;
    num_ticks_r = enc_r;

    /*
        Serial.println("enc_l = \t enc_r = ");
        Serial.print(enc_l_prev);
        Serial.print("\t");
        Serial.println(enc_r_prev);
    */


    // Sample out current number of ticks
    Serial.print(num_ticks_l);
    Serial.print("  \t\t");
    Serial.print(num_ticks_r);


    /*
        // Bluetooth terminal testing
        Serial1.print(num_ticks_l);
        Serial1.print(" \t");
        Serial1.print(num_ticks_r);
    */

    // Drive
   [b] drive(power_l, power_r);[/b]

    // Number of ticks counted since last time
    const int StraightDriveOffset = 1;                    // Increase this or even make it a negatie number to tweak the

    diff_l = num_ticks_l - enc_l_prev;                    // + StraightDriveOffset;
    diff_r = num_ticks_r - enc_r_prev;


    Serial.print("  \t\t");
    Serial.print(diff_l);
    Serial.print(" \t \t");
    Serial.print(diff_r);


    // Store current ticks counter for next time
    enc_l_prev = num_ticks_l;
    enc_r_prev = num_ticks_r;


    Serial.print("   \t \t");
    Serial.print(enc_l_prev);
    Serial.print(" \t \t");
    Serial.print(enc_r_prev);


    // If left is faster, slow it down and speed up right
    if ( diff_l > diff_r) {
      power_l -= motor_offset;
      power_r += motor_offset;
    }

    // If right is faster, slow it down and speed up right
    if ( diff_l < diff_r) {
      power_l += motor_offset;
      power_r -= motor_offset;
    }

    // Debugging
    Serial.print(" \t\t");
    Serial.print(power_l);
    Serial.print(" \t\t");
    Serial.println(power_r);


    // Brif pause to let motors respond
    delay(20);
  }

  StopCar();
  //Buzzer();
}

void drive(int power_a, int power_b)
{

  getCompass();                                                     // Update Compass Heading
  bluetooth();

  // Constrain power to between -255 and 255
  power_a = constrain(power_a, -255, 255);
  power_b = constrain(power_b, -255, 255);

  if ( abs(desired_heading - compass_heading) <= compass_dev )      // If the Desired Heading and the Compass Heading are within the compass deviation, X degrees of each other then Go Forward
    // otherwise find the shortest turn radius and turn left or right
  {

    // Left motor direction
    if ( power_a < 0)
    {
      int Power_A = abs(power_a);
      motor2.setSpeed(Power_A);       
      motor2.run(BACKWARD);

      motor1.run(RELEASE);
      motor3.run(RELEASE);
    }
    else
    {
      int Power_A = abs(power_a);
      motor2.setSpeed(Power_A);       
      motor2.run(FORWARD);

      motor1.run(RELEASE);
      motor3.run(RELEASE);
    }

    // Right Motor direction
    if ( power_b < 0)
    {
      int Power_B = abs(power_b);
      motor4.setSpeed(Power_B);       
      motor4.run(BACKWARD);

      motor1.run(RELEASE);
      motor3.run(RELEASE);
    }
    else
    {

      int Power_B = abs(power_b);
      motor4.setSpeed(Power_B);       
      motor4.run(FORWARD);

      motor1.run(RELEASE);
      motor3.run(RELEASE);
    }
  }

  [b]else
  {
    detachInterrupt(digitalPinToInterrupt(enc_l_pin));
    detachInterrupt(digitalPinToInterrupt(enc_r_pin));

    int x = (desired_heading - 359);                          // x = the GPS desired heading - 360
    int y = (compass_heading - (x));                          // y = the Compass heading - x
    int z = (y - 360);                                        // z = y - 360

    if ((z <= 180) && (z >= 0))                               // if z is less than 180 and not a negative value then turn left
    { // otherwise turn right
      TurnLeft();
    }
    else
    {
     TurnRight();
    }
    attachInterrupt(digitalPinToInterrupt(enc_l_pin), countLeft, CHANGE);
    attachInterrupt(digitalPinToInterrupt(enc_r_pin), countRight, CHANGE);
  }[/b]
}

void TurnLeft()
{
  motor1.setSpeed(200);
  motor2.setSpeed(200);
  motor3.setSpeed(200);
  motor4.setSpeed(200);

  motor1.run(BACKWARD);
  motor2.run(BACKWARD);
  motor3.run(FORWARD);
  motor4.run(FORWARD);
}

void TurnRight()
{
  motor1.setSpeed(200);
  motor2.setSpeed(200);
  motor3.setSpeed(200);
  motor4.setSpeed(200);

  motor1.run(FORWARD);
  motor2.run(FORWARD);
  motor3.run(BACKWARD);
  motor4.run(BACKWARD);
}

// Interrupts service routine:

void countLeft()
{
  enc_l ++;
}

void countRight()
{
  enc_r ++;
}



}

Robin2, I am using encoders for the two wheels on the front of the car, which require interrupts . I want to disable interrupts when the car deviates left or right and adjust it back with all four wheels without effecting the increment in the ISR. The purpose of this is to keep the car moving straight for a certain distance.

Can you just post the whole of the code? Pretty hard to follow snippets like this.

I have re-edited my post.

NoName12221:
Robin2, I am using encoders for the two wheels on the front of the car, which require interrupts . I want to disable interrupts when the car deviates left or right and adjust it back with all four wheels without effecting the increment in the ISR. The purpose of this is to keep the car moving straight for a certain distance.

I am far from convinced that pausing interrupts is the solution.

How long do you want them paused for? 100 microseconds would be extremely long and the car won't go very far in that time.

If you just want to stop an ISR from incrementing a count why not just have a boolean variable controlled from somewhere else in your program. If it is TRUE the ISR increments the count. If it is FALSE it doesn't.

...R

If you just want to stop an ISR from incrementing a count why not just have a boolean variable controlled from somewhere else in your program. If it is TRUE the ISR increments the count. If it is FALSE it doesn't.

I'm not convinced that this is the solution, either.

It seems to me that you want to use the encoder counts when going straight, and the compass reading when explicitly turning.

So, when you complete a turn, record what the current encoder values are, and use the changing values to keep you on the straight and narrow.

When you are turning, the changing encoder values don't matter. What matters is the actual values when you start going straight.

PaulS:
I'm not convinced that this is the solution, either.

It seems to me that you want to use the encoder counts when going straight, and the compass reading when explicitly turning.

So, when you complete a turn, record what the current encoder values are, and use the changing values to keep you on the straight and narrow.

That sounds sensible. I had not thought that far ahead.

OP should also note that your approach does not require interrupts to be paused.

...R

Thanks for the replies,

Sorry just to clarify I am using the compass throughout the entire process and by turn right or turn left I don't mean that its an actual 90 degree turn. They are there to keep the car back on track and drive it straight. I am using the compass as a reference point for the car to move straight and when it deviates, which is over 5 degrees the car will adjust itself by turning slightly left or right. When the program is executing "TurnLeft()" or "TurnRight()", I want to pause the increments on ISR.

How about posting your entire code in one shot so we don't have to stitch things together ourselves just to look at it in the IDE?

i re-edited my post #4

Still incomplete. No loop() function. Turnleft() and Turnright() are undefined.
EDIT:
Why not just reset the wheel counters to 0 after making your right / left adjustment? Then there's no need to disable the interrupts.

PS - From the code it doesn't seem like you're really using (quadrature) encoders, right? More like rotation counters?

I’ve included the functions in post#4. I could not put the “setHeading()” and “getCompass()” because it would exceed the maximum amount of letters you can write in a post, but I will include it here:

void getCompass()                                               // get latest compass value
{

  Vector norm = compass.readNormalize();
  float heading = atan2(norm.YAxis, norm.XAxis);
  float declinationAngle = (11 + (16.0 / 60.0)) / (180 / M_PI);
  heading += declinationAngle;

  if (heading < 0)
  {
    heading += 2 * M_PI;
  }

  if (heading > 2 * PI)
  {
    heading -= 2 * PI;
  }

  compass_heading = (int)(heading * 180 / M_PI);                 
  delay(100);
}
void setHeading()
{
  for (int i = 0; i <= 5; i++)                                  // Take several readings from the compass to insure accuracy
  {
    getCompass();                                            // get the current compass heading
   //   Serial.print("getCompass: ");
   //   Serial.println(getCompass());
  }

  desired_heading = compass_heading;                           // set the desired heading to equal the current compass heading

I have a set number of counts that I would need to achieve for a certain distance. If I were to reset the counters each time the car deviates it would probably not make required distance. I want to hold the number of counts when the car deviates and resume it back once the car is moving straight. Yes, I am using rotation counters that are attached to the motors shaft.

So isn't turning part of the distance?

Disabling interrupts is absolutely the wrong thing to do. Using your code to decide when to increment or decrement a particular variable is the best way to do it.

void countLeft()
{
  enc_l ++;
  if(turning) {
    distanceLeftWhileTurning++;
  } else {
    distanceLeftWhileStraight++;
  }
}

NoName12221:
I've included the functions in post#4. I could not put the "setHeading()" and "getCompass()" because it would exceed the maximum amount of letters you can write in a post,

First, please don't make significant changes to previous Replies - it makes reading the Thread very difficult because comments will have referred to the earlier version. (Editing a Reply to correct a typo is fine)

Second, if your program is too long just add the complete .ino file as an attachment. I'm not going to join snippets together in case I introduce an error.

...R

Constantly attaching / detaching the interrupts is kludgey / hacky. @Robin2's suggestion is probably the cleanest:

Robin2:
If you just want to stop an ISR from incrementing a count why not just have a boolean variable controlled from somewhere else in your program. If it is TRUE the ISR increments the count. If it is FALSE it doesn't.

That way all interrupts are serviced and there's none pending when you want to restart the counting. Be sure to declare the bool flag as volatile. Since bools are one byte, accesses to them in your non-interrupt code will be atomic. So, you don't need to protect them with a critical section.

Thanks for the help everyone. Got it working by simply using a Boolean variable in an if/else condition :slight_smile: .