Está en la página 1de 5

06/05/2019 arduino - Calculate RPM with a quadrature rotary encoder - Stack Overflow

Calculate RPM with a quadrature rotary encoder Ask Question

I have written the following code to


calculate the RPM of a DC motor
0 using a quadrature rotary encoder
and an Arduino Mega:

int N3 = 7; //N3 sur la L298N motor shield


int N4 = 8; //N4 sur la L298N motor shield
int ENB = 9; //ENB sur la L298N motor shield
int potPin = A0; //analog pin 0 sur la carte arduino
int valeurLu = 0; //valeur lu du potentiomètre
int valeur_a_ecrire = 0; //valeur à envoyer au moteur
int pin_A_encodeur = 3;
int etat_courant_encodeur = 0;
int etat_precedant_encodeur = 0;

void setup() {
attachInterrupt(digitalPinToInterrupt(3),updatePosition,CHANGE);
pinMode(N3, OUTPUT);
pinMode(N4, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(A0, INPUT);
pinMode(pin_A_encodeur, INPUT);
Serial.begin(9600);
}

void loop() {
valeurLu = analogRead(potPin);
valeur_a_ecrire = (255.0/1023.0)*valeurLu;
digitalWrite(N4, HIGH);
digitalWrite(N3, LOW);
analogWrite(ENB, valeur_a_ecrire);
etat_courant_encodeur = digitalRead(pin_A_encodeur);
Serial.print(valeur_a_ecrire);
Serial.print(" ");
Serial.println(etat_courant_encodeur);
}

I'm able to read read information that


the encoder sends but it's just a
series of ones and zeros (11000111...
etc). How can I use this information to
calculate the RPM of the motor? My
encoder has a resolution of 64 counts
per revolution. Thanks in advance for
any help on how to solve this
problem.

arduino

edited Jul 28 '17 at 13:26


dda
5,504 2 20 32

asked Jul 28 '17 at 1:52


Derick Ghoda
3 1 3

2 Answers
By using our site, you acknowledge that you have read and understand our Cookie Policy, Privacy Policy, and our
Terms of Service.
Since you are only reading pin A
https://stackoverflow.com/questions/45363634/calculate-rpm-with-a-quadrature-rotary-encoder 1/5
06/05/2019 arduino - Calculate RPM with a quadrature rotary encoder - Stack Overflow

from the encoder, you will only get 16


0 impulses per turn.

Here's one way to do it...

//...
#define SAMPLE_DELAY (1000) // thi
// adj
#edfine PULSES_PER_TURN (32) // 32
unsigned int pulseCount;
bool lastState;
unsigned int lastTime;
float rpm; // spee
point.

void setup()
{
// ...
pinMode(pin_A_encodeur, INPUT);
lastState = digitalRead(pin_A_enc
}

void loop()
{
bool curState = digitalRead(pin_A
if (curState != lastState)
{
++pulseCount;
lastState = curState;
}

if ((unsigned int)millis() - last


{
rpm = (pulseCount * (60000.f
PULSES_PER_TURN;
pulseCount = 0;
lastTime = (unsigned int)mil
}
//...
}

The casting of the return value of


milis() is because we don't need all
32 bits of the millis counter to count
to 1000, saves 2 bytes of memory.

By playing with SAMPLE_DELAY,


you will notice that there is a trade-
off between the stability of the
readings, and the sampling
frequency. The best value for
SAMPLE_DELAY will depend on
your application, and the speed
range of your motor.

The results depend on what else is in


your main loop. Your loop should not
have any delay(), opr you may miss
some pulses. If you cannot avoid
that, you should move the pulse
detection code in an ISR.

Another way to do it:

//...
#define SAMPLE_DELAY (1000) // thi
// adj
#define PULSES_PER_TURN (32) // 32
volatile unsigned int pulseCount; //
unsigned int lastTime;
By using our site, you acknowledge
float rpm; that you have read and understand our Cookie Policy, Privacy Policy, and our
// spee
point.
Terms of Service.

https://stackoverflow.com/questions/45363634/calculate-rpm-with-a-quadrature-rotary-encoder 2/5
06/05/2019 arduino - Calculate RPM with a quadrature rotary encoder - Stack Overflow
void setup() {
// ...
pinMode(pin_A_encodeur, INPUT);
lastState = digitalRead(pin_A_enc
attachInterrupt(digitalPinToInter
}

void loop() {
if ((unsigned int)millis() - last
{
unsigned int pulses;
noInterrupts();
pulses = pulseCount; // the
pulseCount = 0; // to
interrupts(); // re-

// 600
rpm = (pulses * (60000.f / (
PULSES_PER_TURN;
lastTime = (unsigned int)mil
}
//...
}

void onPulse() {
++pulseCount;
}

Note that digital sampling will always


lead to some variations in readings.
Remember that if you decide to store
RPMs in an integer, you have to use
an unsigned long type , including for
the millis per minute constant
60000ul , to avoid overflows.

Note also that not all pins are


created equal. only some pins that
can be linked to an interrupt. See the
arduino doc at:
https://www.arduino.cc/en/Reference
/AttachInterrupt

edited Aug 1 '17 at 17:12

answered Jul 28 '17 at 2:57


Michaël Roy
4,056 1 8 14

Thanks for your quick response. I've


been trying the above solution but I'm
not getting the expected result. When
I sent a 100% duty cycle command to
my motor which is connected to a
12V DC source, I expect the motor's
RPM to start from zero (from rest),
increase and then attain a constant
value (at steady state). But the
programme keeps giving me varying
values of motor RPM (e.g, 16, 117,
100, 50, ect) . I there something I'm
doing right ? Also why the value of
60000.f in the formular: rpm =
(pulseCount * (60000.f / ((unsigned
int)millis() - lastTime))) /
PULSES_PER_TURN; –
Derick Ghoda Jul 31 '17 at 19:19
By using our site, you acknowledge that you have read and understand our Cookie Policy, Privacy Policy, and our
Terms of Service. Please see new details in answer
above... – Michaël Roy Aug 1 '17 at
https://stackoverflow.com/questions/45363634/calculate-rpm-with-a-quadrature-rotary-encoder 3/5
06/05/2019 arduino - Calculate RPM with a quadrature rotary encoder - Stack Overflow
17:05

Thanks for the updates and the


clarifications, I've been able to get a
0 stable value for the motor RPM after
steady state is reached. Considering
the fact that it's impossible to write
arduino data to file from the arduino
IDE, I've decided to programme the
encoder from within MATLAB, write
the encoder data to file which I will
later decode in order to determine the
RPM of the wheel which is attached
to the motor (there's a 100:1 gearbox
between the motor and the wheel).

MATLAB code to command the


Arduino board:

clear;
clc;
close all;

a = arduino('COM5','Uno')
writeDigitalPin(a, 'D7', 1), writ
writePWMDutyCycle(a,'D9',0.7)

%Create a file for storing simula


fID = fopen('DemoUnoVmatlab2.txt'

startTime = datetime('now');

try
while(1)
t = datetime('now') - st

%Write simulation data to


fprintf(fID, '%f\t%f\n',
double(readDigitalPin(a,'D2')));
end
fclose(fID);
catch
fclose(fID);
end

MATLAB Function to treat the


acquired data and calculate
angular position

function [] = counterVmatlab(signal_A
count = 0;
previousState = 0;
angularPos = 0;
ppr = 32; % encoder resolution, 3
(see encoder's data sheet)
gearRatio = 100;
results = fopen('resultsVmatlab.t

for i = 1:length(signal_A)
presentState = signal_A(i);
By using our site, you acknowledge that you ~=
if presentState have read and understand our Cookie Policy, Privacy Policy, and our
previousSt
Terms of Service. count = count + 1;
previousState = presentSt

https://stackoverflow.com/questions/45363634/calculate-rpm-with-a-quadrature-rotary-encoder 4/5
06/05/2019 arduino - Calculate RPM with a quadrature rotary encoder - Stack Overflow
fprintf(results,'%f\t%f\t
at what time did a change in state oc
angularPos = angularPos +
end
end
fclose(results);

By plotting graphs of angular position


and angular velocity, I find that the
angular velocity varies about a stable
value of about 5 degrees/second (see
the attached screen capture below).
Considering that I have a small motor
running on a 12V dc source, I expect
the angular velocity to be about 360
degrees/second (which is what one
can observe by looking at the motor
turning). So I'm wondering if my
above decoding algorithm is good?
Any help will be very appreciated.

GRAPH Angular position and angular


velocity

answered Aug 9 '17 at 22:50


Derick Ghoda
3 1 3

At this line: angularPos =


angularPos +
360/(ppr*gearRatio); It the encoder
is on the motor shaft, you are
calculating the rpm of the wheel. If the
encoder is on the wheel, the motor
RPM would be angularPos =
angularPos + ((360 * gearRatio) /
ppr); – Michaël Roy Aug 11 '17 at
8:26

Also, the graph for angular velocity is


all over the place. There are gaps in
the graph. It looks like you are missing
some state changes. I don't know if
these are due to the way matlab
generates the graph. I wouldn't trust
readings with an external program
reading the pin remotely. Have you
tried using a diiferent serial monitor
like PuTTy to capture the serial output
from the arduino to file? Using Matlab
as you do can never be reliable
enough to get stable, reliable real-time
readings. ... – Michaël Roy Aug 11 '17
at 8:38

... For best results in capturing this


data to generate the graphs, you
should use solution #2 above, do not
reset the pulseCount counter, and
send the difference between two
sends, along with the return value
from millis() over the serial port. –
Michaël Roy Aug 11 '17 at 8:43

By using our site, you acknowledge that you have read and understand our Cookie Policy, Privacy Policy, and our
Terms of Service.

https://stackoverflow.com/questions/45363634/calculate-rpm-with-a-quadrature-rotary-encoder 5/5

También podría gustarte