Erroneous Interrupt Triggered at High Frequencies

Hello, I am using an Arduino Mega 2560 and photoreflective sensors to measure the speed of 3 wheels of a small robot for a school project. (Due to budget constraints for the project, we are using photoreflective sensors and a small wheel with 8 slots in it instead of a premade optical/rotary encoder). I am using a Roboclaw 2x15A motor controller in Packet Serial mode. I have two 12V batteries connected in series powering two 24V Banebots RS775 motors through the roboclaw. My photoreflectors are powered at 5V, and their output signal is connected to 5V via a pull-up (I believe this is the proper term) resistor and then connected to the interrupt pin of the Arduino.

Below I have included the code that I am using to test this setup. So far, I have only connected one of the 3 photoreflective sensors. I wanted to test that the setup worked on at least one wheel before complicating it with 3 wheels. I have a single sensor aimed at Motor 1 and connected to pin 18, to which I have connected "Interrupt1". When driving motor 1 at a relatively low speed, say 20%, this code and setup works fine, and I can see the time interval between interrupts on my serial monitor.

My initial fear was that the arduino wouldn't be able to process interrupts quickly enough when the motors were driven at high speeds. However, I'm getting a different problem altogether. When I increase the speed of Motor 1, I can see on the serial monitor that Interrupt 2 is periodically triggered--maybe once or twice per second. This is extremely confusing to me, because there is no signal at all connected to Interrupt 2/Pin 19. The only sensor I have connected is from the sensor aimed at Motor 1, which goes to Arduino Pin 18 and is associated with Interrupt 1. How is it possible that Interrupt 2 would be triggered when there is nothing connected to its pin?

Can anyone help me diagnose what the issue might be? Thank you very much for your help!

// SingleDrivenWheelSpeedTest_Mega.ino
// Author: Will Cunningham
// Date: 11/19/19
// Serial Output pins:
// Arduino pin 11 to roboclaw s1
// Arduino pin 10 to roboclaw s2

//See BareMinimum example for a list of library functions

//Includes required to use Roboclaw library
#include <SoftwareSerial.h>
#include "RoboClaw.h"

//See limitations of Arduino SoftwareSerial
SoftwareSerial serial(10,11);  
RoboClaw roboclaw(&serial,10000);

#define address 0x80 // serial address used for the roboclaw packet serial mode 7

# define M_PI           3.14159265358979323846  /* pi */

// set up first interrupt pin
const byte interrupt1Pin = 18; // pin 18 on Arduino mega
volatile unsigned long ti1, tf1, dt1; // initial time 1, final time 1, and delta time 1
volatile byte interrupt1Flag = 0; // this is either 1 or 0, allows for entrance into if structure

// set up second interrupt pin
const byte interrupt2Pin = 19;
volatile unsigned long ti2, tf2, dt2;
volatile byte interrupt2Flag = 0;

// set up third interrupt pin
const byte interrupt3Pin = 20;
volatile unsigned long ti3, tf3, dt3, int3Counts;
volatile byte interrupt3Flag = 0;

// set up distance-counting variables
float distTraveled; // [inches]
int finalDistance = 240; // [inches]
int decelDistance = 15*12; // [inches]

void setup()
{
    // initialize serial monitor
    Serial.begin(38400);
    
    // setup interrupt pins on arduino
    // attach first interrupt pin
    pinMode(interrupt1Pin, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(interrupt1Pin), Interrupt_1, RISING);
    // attach second interrupt pin
    pinMode(interrupt2Pin, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(interrupt2Pin), Interrupt_2, RISING);
    // attach second interrupt pin
    pinMode(interrupt3Pin, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(interrupt3Pin), Interrupt_3, RISING);

    // initialize serial communication with RoboClaw---serial mode option 4 for baud rate = 38400
    roboclaw.begin(38400); 

    Serial.print("INITIAL TEST");
}
void loop()
{
    // Measure wheel speed
    if (interrupt1Flag){
        interrupt1Flag = 0;
        dt1 = tf1 - ti1;
//        Serial.println("Interrupt 1 Occurred");
//        Serial.print("Time1 Initial: ");
//        Serial.println(ti1,DEC);
//        Serial.print("Time1 Final: ");
//        Serial.println(tf1,DEC);
        Serial.print("dt1: ");
        Serial.println(dt1,DEC);
        //      noInterrupts();
        //      tf1 = ti1 = 0;
        //      interrupts();
    }
    else{
        // do nothing
    }
    
    if (interrupt2Flag){
        interrupt2Flag = 0;
        dt2 = tf2 - ti2;
        Serial.println("Interrupt 2 Occurred");
        Serial.print("Time2 Initial: ");
        Serial.println(ti2,DEC);
        Serial.print("Time2 Final: ");
        Serial.println(tf2,DEC);
        Serial.print("dt2: ");
        Serial.println(dt2,DEC);
        //      noInterrupts();
        //      tf2 = ti2 = 0;
        //      interrupts();
    }
    else{
        // do nothing
    }

    if (interrupt3Flag){
        interrupt3Flag = 0;
        dt3 = tf3 - ti3;
        Serial.println("Interrupt 3 Occurred");
        Serial.print("Time3 Initial: ");
        Serial.println(ti3,DEC);
        Serial.print("Time3 Final: ");
        Serial.println(tf3,DEC);
        Serial.print("dt3: ");
        Serial.println(dt3,DEC);
        //      noInterrupts();
        //      tf2 = ti2 = 0;
        //      interrupts();

        // update the distance
        distTraveled = (float)int3Counts*M_PI/2; // [inches]
    }
    else{
        // do nothing
    }

    // Control the speed (input range: 0 = full stop, 127 = full forward
    roboclaw.ForwardM1(address,20); //start Motor1 forward at 0 speed
//    roboclaw.ForwardM1(address,50); //start Motor1 forward at half speed


    // to readers of the arduino forum: When experiencing the problem I have described, I am not driving motor 2 at all, and there is no sensor at all hooked up to pin 19.
    roboclaw.ForwardM2(address,0); //start Motor2 forward at 0 speed
//    roboclaw.ForwardM2(address,50); //start Motor2 forward at half speed

    

    // Check if you have traveled far enough to start slowing down or stopping
    if(distTraveled > finalDistance){
      // stop
    }

    else if(distTraveled > decelDistance){
      // slow down
    }

    // print speed on either serial monitor or lcd

    
}
void Interrupt_1(void)
{
    ti1 = tf1;
    tf1 = micros();
    interrupt1Flag = 1;
}

void Interrupt_2(void)
{
    ti2 = tf2;
    tf2 = micros();
    interrupt2Flag = 1;
}

void Interrupt_3(void)
{
    ti3 = tf3;
    tf3 = micros();
    interrupt3Flag = 1;
    int3Counts++;
}

RoboClaw.cpp (25.3 KB)

RoboClaw.h (10.4 KB)

SingleDrivenWheelSpeedTest_Distance_Mega.ino (4.74 KB)

Is the pin on interrupt 2 held at a known voltage or is it floating and maybe picking up external interference ?

Hi UKHeliBob, thanks for your prompt reply. The interrupt 2 pin (19) is not connected to anything at all. I didn't know to account for external interference. I will test it again tomorrow with a constant voltage applied to pin 19 and see what happens.

When you say "external interference", do you mean electrical interference? Do you suspect that the issue comes from the higher frequency of the signal on interrupt 1 (pin 18) or from the mechanical vibration caused by a gearmotor and wheel spinning 2x-3x as fast?

Besides possibly picking up noise on the pin, you need to be making copies of your volatile variables to use in calculations inside looop() and do that while interrupts are disabled or else you risk getting bad data

// SingleDrivenWheelSpeedTest_Mega.ino
// Author: Will Cunningham
// Date: 11/19/19
// Serial Output pins:
// Arduino pin 11 to roboclaw s1
// Arduino pin 10 to roboclaw s2

//See BareMinimum example for a list of library functions

//Includes required to use Roboclaw library
#include <SoftwareSerial.h>
#include "RoboClaw.h"

//See limitations of Arduino SoftwareSerial
SoftwareSerial serial(10, 11);
RoboClaw roboclaw(&serial, 10000);

#define address 0x80 // serial address used for the roboclaw packet serial mode 7

# define M_PI           3.14159265358979323846  /* pi */

// set up first interrupt pin
const byte interrupt1Pin = 18; // pin 18 on Arduino mega
volatile unsigned long ti1, tf1; // initial time 1, final time 1, and delta time 1
volatile byte interrupt1Flag = 0; // this is either 1 or 0, allows for entrance into if structure

// set up second interrupt pin
const byte interrupt2Pin = 19;
volatile unsigned long ti2, tf2;
volatile byte interrupt2Flag = 0;

// set up third interrupt pin
const byte interrupt3Pin = 20;
volatile unsigned long ti3, tf3, int3Counts;
volatile byte interrupt3Flag = 0;

// set up distance-counting variables
float distTraveled; // [inches]
int finalDistance = 240; // [inches]
int decelDistance = 15 * 12; // [inches]

unsigned long ti, tf, dt;

void setup()
{
  // initialize serial monitor
  Serial.begin(38400);

  // setup interrupt pins on arduino
  // attach first interrupt pin
  pinMode(interrupt1Pin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interrupt1Pin), Interrupt_1, RISING);
  // attach second interrupt pin
  pinMode(interrupt2Pin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interrupt2Pin), Interrupt_2, RISING);
  // attach second interrupt pin
  pinMode(interrupt3Pin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interrupt3Pin), Interrupt_3, RISING);

  // initialize serial communication with RoboClaw---serial mode option 4 for baud rate = 38400
  roboclaw.begin(38400);

  Serial.print("INITIAL TEST");
}
void loop()
{
  // Measure wheel speed
  if (interrupt1Flag) {
    noInterrupts();
    tf = tf1;
    ti = ti1;
    interrupts();
    interrupt1Flag = 0;
    dt = tf - ti;
    //        Serial.println("Interrupt 1 Occurred");
    //        Serial.print("Time1 Initial: ");
    //        Serial.println(ti1,DEC);
    //        Serial.print("Time1 Final: ");
    //        Serial.println(tf1,DEC);
    Serial.print("dt1: ");
    Serial.println(dt, DEC);
    //      noInterrupts();
    //      tf1 = ti1 = 0;
    //      interrupts();
  }
  else {
    // do nothing
  }

  if (interrupt2Flag) {
    noInterrupts();
    tf = tf2;
    ti = ti2;
    interrupts();
    interrupt2Flag = 0;
    dt = tf - ti;
    Serial.println("Interrupt 2 Occurred");
    Serial.print("Time2 Initial: ");
    Serial.println(ti, DEC);
    Serial.print("Time2 Final: ");
    Serial.println(tf, DEC);
    Serial.print("dt2: ");
    Serial.println(dt, DEC);
    //      noInterrupts();
    //      tf2 = ti2 = 0;
    //      interrupts();
  }
  else {
    // do nothing
  }

  if (interrupt3Flag) {
    noInterrupts();
    tf = tf3;
    ti = ti3;
    interrupts();
    interrupt3Flag = 0;
    dt = tf - ti;
    Serial.println("Interrupt 3 Occurred");
    Serial.print("Time3 Initial: ");
    Serial.println(ti, DEC);
    Serial.print("Time3 Final: ");
    Serial.println(tf, DEC);
    Serial.print("dt3: ");
    Serial.println(dt, DEC);
    //      noInterrupts();
    //      tf2 = ti2 = 0;
    //      interrupts();

    // update the distance
    distTraveled = (float)int3Counts * M_PI / 2; // [inches]
  }
  else {
    // do nothing
  }

  // Control the speed (input range: 0 = full stop, 127 = full forward
  roboclaw.ForwardM1(address, 20); //start Motor1 forward at 0 speed
  //    roboclaw.ForwardM1(address,50); //start Motor1 forward at half speed


  // to readers of the arduino forum: When experiencing the problem I have described, I am not driving motor 2 at all, and there is no sensor at all hooked up to pin 19.
  roboclaw.ForwardM2(address, 0); //start Motor2 forward at 0 speed
  //    roboclaw.ForwardM2(address,50); //start Motor2 forward at half speed



  // Check if you have traveled far enough to start slowing down or stopping
  if (distTraveled > finalDistance) {
    // stop
  }

  else if (distTraveled > decelDistance) {
    // slow down
  }

  // print speed on either serial monitor or lcd


}
void Interrupt_1(void)
{
  ti1 = tf1;
  tf1 = micros();
  interrupt1Flag = 1;
}

void Interrupt_2(void)
{
  ti2 = tf2;
  tf2 = micros();
  interrupt2Flag = 1;
}

void Interrupt_3(void)
{
  ti3 = tf3;
  tf3 = micros();
  interrupt3Flag = 1;
  int3Counts++;
}

If you disconnect the input to pin 18 (so no interrupt connections at all) and increase the speed as before, do you see spurious interrupts?

Look at your wiring and power. Do you have noise-sensitive wiring close to motor/driver power wiring or the motor(s) themselves? Is the same supply powering both the Mega and the motor(s)?

When you say "external interference", do you mean electrical interference?

That is certainly what I had in mind