# Incorrectly calculating elapsed time between interrupts.

I’m designing a motor controller and am having issues calculating the velocity. The motor has an encoder that’s wired in to one of the arduino’s interrupts. I’m calculating my relative velocity by measuring the time between encoder “ticks”, which tells me how far the motor has travelled in the given span of time (the measure of my velocity is ticks/microsecond).

Having said that, I’ve been getting odd values at intermittent intervals. They look something like this (keep in mind the motor is moving at a constant velocity).

``````1668
1664
1664
1664
1644
1644
1644
1636
1636
1636
1648
1648
1648
1648
1664
1664
1668
========>1404
========>240
========>240
1640
1640
1644
1644
1644
1644
1668
1668
1664
========>1404
========>1404
========>240
1636
1636
1648
1648
1648
1664
1664
1664
1664
1668
1668
1668
1644
1644
1644
1640
1640
1640
1644
1644
1644
1644
1668
1668
1672
``````

You’ll notice they are all average about the same value, except for the groups of outliers. I’m using the code below to generate this output.

``````#define MAX_POWER 255

//
// Pin definitions
//
#define ENCODER_A 2
#define ENCODER_B 3

#define MOTOR_CURRENT_1 A0
#define MOTOR_CURRENT_2 A1
#define MOTOR_VOLTAGE   A2

#define MOTOR_DIRECTION 10
#define MOTOR_PWM       11
#define MOTOR_FAULT     12
#define MOTOR_ENABLE    13

#define RING 10

volatile uint8_t i = -1;
volatile unsigned long elapsed[RING];
volatile unsigned long tick_prev = 0;

void tick(){
if(++i == RING) i = 0;

unsigned long tick_curr = micros();
elapsed[i] = tick_curr - tick_prev;
tick_prev = tick_curr;
}

void setup(){

Serial.begin(115200);

// Pin setup
pinMode(MOTOR_DIRECTION, OUTPUT);
pinMode(MOTOR_PWM      , OUTPUT);
pinMode(MOTOR_ENABLE   , OUTPUT);
pinMode(MOTOR_FAULT    , INPUT );
pinMode(ENCODER_A      , INPUT );
pinMode(ENCODER_B      , INPUT );

// Set motor state
digitalWrite(MOTOR_ENABLE   , HIGH);
digitalWrite(MOTOR_DIRECTION, LOW);

attachInterrupt(0, tick, RISING);

analogWrite(MOTOR_PWM, MAX_POWER);
}

void loop(){
uint8_t j = i - 1;
if(j == 255) j = RING - 1;

unsigned long delta = elapsed[j];

if(delta < 1600) Serial.print("========>");
Serial.println(delta);
}
``````

I’m using a ring buffer to store my values. I’m not disabling interrupts, which is fine, because I’m never reading and writing from the same blocks of memory at the same time. The index is a single byte which I’m assuming can be read and written to in a single operation (therefore, it can not be “interrupted”).

You’re welcome to scrutinize the methodology and execution of this technique, but ultimately, whether I’m disabling interrupts or not, I’m getting the same sets of odd values.

Does anyone have any idea what might be causing this?

Probably want to fix this?
if(++i = 4) i = 0;

++i == 4, or
++i >= 4

assignment vs comparison, get you every time.

Whoops! That wasn't the current code. I updated my post.

``````  unsigned long delta = elapsed[i-1];
``````

When i = 0 which element of the array will the value of delta be taken from ?

UKHeliBob:
When i = 0 which element of the array will the value of delta be taken from ?

Ring-1 by the looks of things:

``````if(j == 255) j = RING - 1;
``````

The odd values could potentially be noise on your interrupt pin. Do you have more info about what is connected to the interrupt pin and how?
(Interestingly, if you add up pairs of the odd readings you get 3 correct values -> [1404+240 = 1644])

I’d still go with >=, just in case you didn’t hit 10 (RING) dead on each time.

RING never changes - why not just say 9 here?

if(j == 255) j = RING - 1;

I fixed all the issues with the ring buffer. I'm not worried about optimizing the code. The buffer is just a means to an end to print the elapsed times, which are the real concern here.

I'm guessing no one's been focusing on that because it's the hardest piece to figure out. There doesn't seem to be anything wrong with the code. It has to be an interrupt issue of some sort. I don't know if it's in the micros() or ..... I just don't know.

What's the motor encoder connection like? Perhaps enabling the pullup resistor on EncoderA (B does not seem to be used) will help.

pinMode(ENCODER_A , INPUT_PULLUP );
pinMode(ENCODER_B , INPUT_PULLUP );

There's already a pull-up resistor on the line.

Just curious, have you tried to install the interrupt without using Arduino's attachInterrupt() function?

Also, there is a known issue with calling micros() with IRQs disabled and the potential for timer0 rollover, however, I don't believe this to be your issue.

Your loop() code will potentially print each element multiple times to serial, because it doesn’t wait until a new value id available before printing a value. Perhaps what you meant to do was something like this:

``````void loop(){
static uint8_t j = 0;     // static so it only gets initialized once
if (j != i)
{
unsigned long delta = elapsed[j];
if(delta < 1600) Serial.print("========>");
Serial.println(delta);
}
++j;
if(j == RING) j = 0;
}
``````

If you make that change, you will only print each value once (if I have got the code right) and the problem may be easier to diagnose. However, I suspect the problem is noise causing additional interrupts, because in the example you gave, 1404 + 240 = 1644 which is in line with the normal values.