I am currently using a motor with an integrated speed controller, the speed controller is able to provide feedback on the current speed of the motor. The datasheet states that the output is 6 lines per revolution, I assume this means 6 pulses per revolution, I've used an oscilloscope to check this and I do see pulses. (I've attached the datasheet if you're keen on seeing it, look at page 2 of the datasheet)
Currently I'm using the millis() function to detect the number of pulses every 100ms and then calculate the rotation speed in rpm from that value. However I have heard that the millis() function is often quite inaccurate, and also noticed that I get quite a large error between the measured and theoretical speed at low speeds (Around 100-300RPM), there is roughly a 20% difference. But at higher speeds this error seems to decrease to below 5%.
As such, I was thinking of using interrupts to read the rising edges of each pulse to compute the speed of the motor and see if I get better readings. But I have no idea how to do this.
I am also wondering if I could use interrupts to continuously calculate the instantaneous speeds and then return an average value whenever I want it to.
However I have heard that the millis() function is often quite inaccurate
Incorrect. The millis() function accurately returns the number of milliseconds that the processor has been running, by counting clock ticks.
The clock can be inaccurate.
As such, I was thinking of using interrupts to read the rising edges of each pulse to compute the speed of the motor and see if I get better readings. But I have no idea how to do this.
I'm sure google does. What part of the process seems difficult? Attaching the interrupt handler is not. Writing the function is not. Making the function record the time that the pulse arrived (using millis() or micros()) is not. Incrementing the number of pulses is not.
But I honestly have no idea how the speed is being calculated, or why they are using half revolutions.
I'm having more of an issue translating my current code which is dependent on millis() into an interrupt. Currently I'm using something simple like :
int lasttime = 0;
int pulsecounter=0;
int revpersec = 0;
int rpm;
//Use pulsein function to detect a pulse and then increment my pulsecounter ( pulsecounter++)
void loop()
{
if((millis()-lasttime) == 1000)
{
revpersec = pulsecounter/6;
rpm = revpersec * 60;
Serial.println(rpm);
}
}
So how should I rewrite this such that the interrupt returns me the averaged rpm value? Instead of calculating it only when I require it.
There are some problems with the snippet you posted. First, exact values from millis() are not to be expected. The value returned by millis() does not always increase by 1. Even if the only thing you do in loop() is called millis(), the number of ticks (1024) in a second is not the same as the number of milliseconds in a second (1000). So, periodically, the value returned by millis() will increase by 2 from the previous value. Therefore, you need to allow for >= 1000 milliseconds, not == 1000 milliseconds.
Second, the time to reset the value of lasttime is in the body of that statement, not later.
So how should I rewrite this such that the interrupt returns me the averaged rpm value?
You don't. An interrupt is like being whacked up side the head. While your head is ringing is not the time to calculate the average rate of being whacked up side the head. All that the interrupt does is increment the count of whacks.
In loop(), you calculate the speed, based on the number of whacks over some time interval, unless all that you need is an instantaneous speed, based on just two whacks and the time between them.
Thanks for the replies. I think I get it now. I've thought about it and I think I should actually detect falling edges cause that tells you when the pulse has ended.
So basically you use an interrupt that increments a counter (pulsecounter) every time a falling edge is detected. Then whenever you want to Serial.println the speed, you just use the current value of pulsecounter and calculate the speed from there.
But in that case, I doubt using interrupts should change much? As previously I was just using the pulseIn function to increment my pulsecounter whenever pulseIn returned a number greater than 0. As pulseIn simply returns the duration of the pulse.
Also, PaulS your analogy did help me understand interrupts better, thanks for that. Although I can't say I'm fond of getting whacked in the head.
If you want an accurate RPM value, use one of the hardware timers to do the counting for you, measuring the actual time, in CPU clocks, between rising edges of the encoder signal. Some very simple math will convert that directly to RPM. There is a library out there, FreqMeasure, that does exactly that, and works very well.
This ISR (taken from a working program I am developing) calculates the number of microseconds between pulses and then you can use that to calculate the speed