Go Down

Topic: Optical encoder: read engine speed (Read 2017 times) previous topic - next topic

adanilo90

Hello,
I have been working on finding the RPM of a motor using an optical encoder. I have a motor "maxon DC motor 9V 118742" connected to an encoder "Avago HEDS 5540#A02" by which I would need to know the number of revolutions the engine makes. I have an "Arduino Uno" and turning between the forum I understand how to make connections, but I have not found a code that worked. Could you help me write a code that works? Thank you.

MarkT

Well you haven't presented any of the sketches you've already tried... Perhaps you should show us
one that you've tried so we can fix it or work out why.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

adanilo90

I have tried several codes, including this one that I found here on the forum. But this does not always work well.
 
Code: [Select]
[code]
int tick = 0;
int oldIn = 0;
int currentIn = 0;
float mins = 0;
float timeMillis = 0;
float oldTimeMillis = 0;
float rpmReturn = 0;
float rpmPrint;
void setup() {
  // put your setup code here, to run once:
  // attachInterrupt(digitalPinToInterrupt(2), readRPM, CHANGE);
  pinMode(2, INPUT);
   Serial.begin(9600);
}

void loop() {
  currentIn = digitalRead(2);
  if(currentIn != oldIn){
    tick++;
  }
 
  timeMillis = millis();
  if (tick >= 360){
    tick = 0;
    rpmPrint = rpm();
    Serial.println(rpmPrint);
    oldTimeMillis = timeMillis;
  }
  oldIn = currentIn;
}
void readRPM(){
  tick++;
}
float rpm() {
  timeMillis = timeMillis - oldTimeMillis;
  mins = (timeMillis / 1000) / 60;
  rpmReturn = 1/mins;
  return rpmReturn;
}
[/code]

cattledog

You should be using the external interrupt for this application.

You have the 5540 model which has an index pulse on its pin #2. If you connect that to pin 2 or 3 of the UNO you should be able to read the count with an external interrupt.

There are many projects for tachometers and speedometers to be found.

This might get you started
http://playground.arduino.cc/Main/ReadingRPM

With the motor you have the rpm should be high enough that simply counting the pulses over a fixed period of time might be accurate enough for your application. Here's very simple code which counts pulses for one second.

Code: [Select]

volatile unsigned long  count = 0;
unsigned long copyCount = 0;

unsigned long lastRead = 0;
unsigned long interval = 1000;//one second

void setup()
{
  Serial.begin(115200);
  Serial.println("start...");
 
  pinMode(2,INPUT_PULLUP);
  attachInterrupt(0, isrCount, RISING); //interrupt signal to pin 2
}

void loop()
{
  if (millis() - lastRead >= interval) //read interrupt count every second
  {
    lastRead  += interval;
    // disable interrupts,make copy of count,reenable interrupts
    noInterrupts();
    copyCount = count;
    count = 0;
    interrupts();
 
    Serial.println(copyCount);

  }
}

void isrCount()
{
  count++;
}






 






adanilo90

Thank you cattledog!! With your code rotating by hand the motor I visualize the number of turns (which should be) corrected on the serial monitor. I will test this code when I provide a specific voltage value to the motor at the laboratory.
One last question: Do you know why when I turn from vertical position in the horizontal position the motor the value of speed varies by 2-3 orders of magnitude?

MarkT

I have tried several codes, including this one that I found here on the forum. But this does not always work well.
No it won't its not correct.  The 'tick' variable should be declared volatile, and should be accessed from
the main sketch with interrupts disabled:

Code: [Select]

  noInterrupts () ;
  if (tick >= 360)    // read and
  {
    tick = 0;            // write access to tick is protected.
    interrupts () ;
    rpmPrint = rpm();
    Serial.println(rpmPrint);
    oldTimeMillis = timeMillis;
  }
  else
    interrupts () ;   // mustn't forget to enable interrupts again whatever the if condition.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

adanilo90

No it won't its not correct.  The 'tick' variable should be declared volatile, and should be accessed from
the main sketch with interrupts disabled:

Code: [Select]

  noInterrupts () ;
  if (tick >= 360)    // read and
  {
    tick = 0;            // write access to tick is protected.
    interrupts () ;
    rpmPrint = rpm();
    Serial.println(rpmPrint);
    oldTimeMillis = timeMillis;
  }
  else
    interrupts () ;   // mustn't forget to enable interrupts again whatever the if condition.


Hi MarkT, I've tried to implement your correction, but there is something wrong in the code and I do not understand where. The complete code is below:

Code: [Select]

volatile int tick = 0;
int oldIn = 0;
int currentIn = 0;
float mins = 0;
float timeMillis = 0;
float oldTimeMillis = 0;
float rpmReturn = 0;
float rpmPrint;
void setup() {
  // put your setup code here, to run once:
  // attachInterrupt(digitalPinToInterrupt(2), readRPM, CHANGE);
  pinMode(2, INPUT);
   Serial.begin(9600);
}

void loop() {
  currentIn = digitalRead(2);
  if(currentIn != oldIn){
    tick++;
  }
 
  timeMillis = millis();

  noInterrupts () ;
  if (tick >= 360)    // read and
  {
    tick = 0;            // write access to tick is protected.
    interrupts () ;
    rpmPrint = rpm();
    Serial.println(rpmPrint);
    oldTimeMillis = timeMillis;
  }
  else
    interrupts () ;   // mustn't forget to enable interrupts again whatever the if condition.
  oldIn = currentIn;
}
void readRPM(){
  tick++;
}
float rpm() {
  timeMillis = timeMillis - oldTimeMillis;
  mins = (timeMillis / 1000) / 60;
  rpmReturn = 1/mins;
  return rpmReturn;
}

adanilo90

You should be using the external interrupt for this application.

You have the 5540 model which has an index pulse on its pin #2. If you connect that to pin 2 or 3 of the UNO you should be able to read the count with an external interrupt.

There are many projects for tachometers and speedometers to be found.

This might get you started
http://playground.arduino.cc/Main/ReadingRPM

With the motor you have the rpm should be high enough that simply counting the pulses over a fixed period of time might be accurate enough for your application. Here's very simple code which counts pulses for one second.

Code: [Select]

volatile unsigned long  count = 0;
unsigned long copyCount = 0;

unsigned long lastRead = 0;
unsigned long interval = 1000;//one second

void setup()
{
  Serial.begin(115200);
  Serial.println("start...");
 
  pinMode(2,INPUT_PULLUP);
  attachInterrupt(0, isrCount, RISING); //interrupt signal to pin 2
}

void loop()
{
  if (millis() - lastRead >= interval) //read interrupt count every second
  {
    lastRead  += interval;
    // disable interrupts,make copy of count,reenable interrupts
    noInterrupts();
    copyCount = count;
    count = 0;
    interrupts();
 
    Serial.println(copyCount);

  }
}

void isrCount()
{
  count++;
}





Hi cattledog, I tried your code by connecting the motor to a voltage source and giving them input values from 2 to 5 volts, but I got completely the wrong values. Do you know why?




cattledog

Quote
I got completely the wrong values. Do you know why?
I do not think you are connected to the correct pins for GND(1), index(2), and Vcc(4). See figure 1 of the data sheet. http://docs.avagotech.com/docs/AV02-1046EN

adanilo90

I do not think you are connected to the correct pins for GND(1), index(2), and Vcc(4). See figure 1 of the data sheet. http://docs.avagotech.com/docs/AV02-1046EN
Yes you are right! I've made the right connection and now everything works! Thank you so much.

basmakhaled6050

i need the right  connection of this encoder after editing

cattledog

Quote
i need the right  connection of this encoder after editing
I do not understand what "after editing" means.

If you are trying to read the index pulse?

encoder pin1 to arduino ground
encoder pin4 to arduino 5volts
encoder pin2 to arduino external interrupt pin

If you are trying to read quadrature it will be different.

The data sheet is pretty simple. What are you having difficulty understanding?


basmakhaled6050

#12
Apr 26, 2017, 05:55 pm Last Edit: Apr 26, 2017, 06:09 pm by basmakhaled6050
Yes you are right! I've made the right connection and now everything works! Thank you so much.
i mean this right connection , but thanks i saw the data sheet and apply it in my encoder .

 i have another question please, i try to control my IAC and i don't know what is the suitable driver to connect with it and depending on what?

if any one know the electrical signal cable of IAC ( idle air control )  connect with driver motor , did you know what is the type of driver and it's connection with IAC and thanks :D


Go Up