Need help with encoder...

roarkhen

Active member
I've got this encoder that a buddy pulled off a log processor head. It's apparently used to measure a tree as it's being cut up. His controller is in-op and a new one is quite expensive. He was wondering if I could get just this part working. So I've attached pictures of this encoder. It's got 4 wires. red (+5-15v), black (gnd), and a yellow & green for channel A & B. I've searched the google monster and found nothing for it.

I had a board lying around that has a tach sensor (hall or mag sensor) hookup, and a relay output. I run a simple ISR routine that counts the pulses, and determines RPM.
I've modified the software to work for the rating on this device. Which says right on the label 256ppr. I assume that means pulses per revolution.

Problem is I can't seem to get pulses from it. It has leds on it that show that it has power, and when i spin the shaft, there are channel A&B leds which show them fluttering. But, I get no interrupts.

I detect anywhere from 12-3v on the signal pins when spinning the shaft. I don't have a scope so I can't really look at the lines with anything other than a meter.

I'm wondering if the NCV1124DR2G (which is the tach input), is not allowing the pulse thru? I originally made this board with a teensy, but the one I'm testing has a nano on it.

Any guidance is appreciated... thanks!
 

Attachments

  • encoder1.jpg
    encoder1.jpg
    60.6 KB · Views: 40
  • encoder2.jpg
    encoder2.jpg
    101.5 KB · Views: 52
  • pic3.jpg
    pic3.jpg
    104.2 KB · Views: 41
Not too long ago I played with a similar looking 600 PulsePerRevolution encoder.
Powered it by 5V, connected the A & B signals to pin 5 & 6, and ran the following code on a Teensy 3.2 [which is 5V tolerant on its inputs]:
Code:
#include <Encoder.h>
Encoder myEnc(5, 6);

void setup() {
}

void loop() {
  long newPosition = myEnc.read();
  Serial.println(newPosition); // encoder lib will output 2400 pulses per rev
  delay(10);
}

Perhaps you need pullups on the A & B signals, see this thread.

Paul
 
Thanks Paul! I was able to learn a couple things:
1. These things put out a digital pulse! duh. I had it wired through a circuit that expects an analog wave (VRS). Not a big deal I can just bypass that input and solder a wire directly to the pin w/ pull up (thx).
2. I did my own ISR routines for the two pins (for channel A&B) instead of the library. It's nothing but a simple increment on the interrupt.
3. Both channels seem to give the same info? If I look at just one channel the results are valid. But basically the same. Each channel gives ~256 pulses per revolution.
4. When I roll an 8" wheel attached to the encoder I get valid results. Meaning ~25inches per revolution, and also 256 pulses.

I guess I just don't understand why 2 channels? or maybe the encoder could feed 2 distinct circuits giving the same info? I completely understand the newb question :)
 
If the encoder is open collector then you can pull up the signals to either +5V or +3.3V. I have a rotary encoder that can sink over 10mA, (Omron E6B2-CWZ6C,) so I used 330 ohms to +5V. I ran it through buffer 74LVT245 to clean it up and into a Teensy. Perhaps overkill, but it works very well up to 2000 RPM. I bought the encoder last year for about $30 USD.
 
A and B should be offset by 90 degrees, but have the same frequency. You need to look at them simultaneously to see this. If A and B are offset by 90 degrees, you can determine position AND direction. With one channel you cannot determine the direction. If A leads B then positive direction, if A lags B then negative direction.
 
Reading a bit. I think this is a quadrature encoder? Meaning the direction is the reason for the channel B. Now I'm off to figuring out how to determine direction in the interupt routines...
 
Thx clinker8, i got your post right after i hit enter! I found a site that describes it pretty well w/ some code. I'll read some more. I get the lead/lag of the A/B for direction. I just have to figure out how to code it :)
 
If you use luni's Encoder library, all that is figured out for you. Highly recommended. I am using his library for my electronic lead screw on my lathe. Works terrific. Use it for the spindle and for digital read outs, which are nothing but quadrature linear encoders instead of rotary. I have not used Paul's Encoder library, so cannot comment on it's ease of use or suitability.
 
Last edited:
I just have to figure out how to code it :)
For inspiration: the code for the Teensyduino-supplied Encoder library, which I used in the example above, is on your PC, here: C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Encoder\Encoder.h.
And yes, I'm pretty sure it's a quadrature encoder.

Paul
 
So, The encoder from paul seems to just give counts. either 0, 1, -1. I tried acumulating to get a count or rough number, and it's way off from my interupt routines which are spot on. Maybe i'm missing something, but the examples are super simple. Just not what I'm looking for.

I can't get the EncoderTool lib to work. Again, just trying to get the simple example working. Neither the polled, nor interupt routine give anything. No value returned from the getValue(). I'm guessing there is a lib conflict with something. I uninstalled both, and re-installed just the EncoderTool library. But nothing. I'll keep at it...
 
So, The encoder from paul seems to just give counts. either 0, 1, -1. I tried acumulating to get a count or rough number, and it's way off from my interupt routines which are spot on. Maybe i'm missing something, but the examples are super simple. Just not what I'm looking for.

I can't get the EncoderTool lib to work. Again, just trying to get the simple example working. Neither the polled, nor interupt routine give anything. No value returned from the getValue(). I'm guessing there is a lib conflict with something. I uninstalled both, and re-installed just the EncoderTool library. But nothing. I'll keep at it...

You used the file called singleEncCallback.ino ? That should do something. If you want an interrupt driven encoder, I believe you just substitute Encoder for PolledEncoder. Then there is no need for enc.tick() in loop. This is basically the way I started out.
 
Last edited:
So I have got something from the encodertool on a callback. works with halfAlt or full
Code:
encoder.begin(2,3,myCallback, CountMode::full); //CountMode::halfAlt);

my callback is simple but I don't understand how to interpret the data? I can't remember where I read it, but something about ignoring the value(position) and just counting based on the delta. But It doesn't work. All I end up with is a zero counter. Meaning ++ on a 1 and -- on a 0 basically it justs bounces back and forth. I would assume that if I spin the hub in one direction I would get mostly 1s with a few -1s (or vice-versa depending how cw & ccw are).

Here's my simple callback with a snippet of output:

Code:
long count = 0;

void myCallback(int position,int delta) {
  Serial.print("Position:");Serial.print(position); Serial.print(" Delta:"); Serial.println(delta);
  if(delta > 0) {
    count++;
  } else {
    count--;
  }
  Serial.print("count:"); Serial.println(count);
}

Position:0 Delta:-1
count:0
Position:-1 Delta:-1
count:-1
Position:0 Delta:1
count:0
Position:1 Delta:1
count:1
Position:0 Delta:-1
count:0
Position:-1 Delta:-1
count:-1
Position:0 Delta:1
count:0
Position:1 Delta:1
count:1
Position:0 Delta:-1
count:0
Position:-1 Delta:-1
count:-1
Position:0 Delta:1
count:0
Position:1 Delta:1
count:1
Position:0 Delta:-1
...
 
So I have got something from the encodertool on a callback. works with halfAlt or full
Code:
encoder.begin(2,3,myCallback, CountMode::full); //CountMode::halfAlt);

my callback is simple but I don't understand how to interpret the data? I can't remember where I read it, but something about ignoring the value(position) and just counting based on the delta. But It doesn't work. All I end up with is a zero counter. Meaning ++ on a 1 and -- on a 0 basically it justs bounces back and forth. I would assume that if I spin the hub in one direction I would get mostly 1s with a few -1s (or vice-versa depending how cw & ccw are).

Here's my simple callback with a snippet of output:

Code:
long count = 0;

void myCallback(int position,int delta) {
  Serial.print("Position:");Serial.print(position); Serial.print(" Delta:"); Serial.println(delta);
  if(delta > 0) {
    count++;
  } else {
    count--;
  }
  Serial.print("count:"); Serial.println(count);
}

Position:0 Delta:-1
count:0
Position:-1 Delta:-1
count:-1
Position:0 Delta:1
count:0
Position:1 Delta:1
count:1
Position:0 Delta:-1
count:0
Position:-1 Delta:-1
count:-1
Position:0 Delta:1
count:0
Position:1 Delta:1
count:1
Position:0 Delta:-1
count:0
Position:-1 Delta:-1
count:-1
Position:0 Delta:1
count:0
Position:1 Delta:1
count:1
Position:0 Delta:-1
...

It's hard to see if you left anything out, if you don't include the whole file. The rule at the very top of the page is there for a very good reason.
Forum Rule: Always post complete source code & details to reproduce any issue!
No one can determine what's wrong without the complete source code. How about the whole complete file, so someone could compile it?
 
Are you using interrupts? I suspect you are, but I can't tell from your code, because you didn't supply all of it. If you are using interrupts you need to use volatile for those variables.

Although it probably isn't necessary, I put in checks for the value of delta. If abs(delta)>1, it is a fault. I increment an error counter.
The only allowed values of delta should be -1, +1. If delta = 0, then you shouldn't have gotten a callback.
 
This might help some

Here's some code that I used to prototype reading a DRO, which is a linear quadrature encoder. Perhaps you can study it to understand how to use EncoderTool.
You need about 1K resistors pulling up to +3.3V on A and B. If you don't do that, it won't work. I had a display hooked up so I could read the information. You can just use Serial.print.
Code:
#include <EncoderTool.h>
#include <ILI9341_t3n.h>
#include <ili9341_t3n_font_Arial.h>
#include <ili9341_t3n_font_ArialBold.h>
#define thisGREY 0x3A07
#define TFT_DC  9
#define TFT_CS 10
#define TFT_RST -1
#define TFT_SCK 13
#define TFT_MISO 12
#define TFT_MOSI 11

using namespace EncoderTool;

Encoder DROZ_Enc;

ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO);

int errorcount, myacc;
float conversionfactor;
volatile float Zval, oldZval;
uint16_t cxg, cyg;

void onDROZ_Changed( int value, int delta )
{
  if (delta >0)
  {
    if (delta>1)
    {
      Serial.printf("Fault!  delta =% i\n", delta);
      errorcount+= 1;
    }
    else
    {
      myacc = myacc + delta;
    }
    oldZval = Zval;
    Zval = myacc * conversionfactor;
  }
  if (delta<0)
  {
    if (delta<-1)
    {
      Serial.printf("Fault!  delta = %i\n", delta);
      errorcount += 1;
    }
    else
    {
      myacc = myacc + delta;
    }
    oldZval = Zval;
    Zval = myacc * conversionfactor;
  }
}

bool initMyDisplay(int rotation)
{
  tft.begin();
  tft.setRotation(rotation);
  tft.fillScreen(ILI9341_BLACK);
  return true;
}

void mainMenu()
{
  tft.fillScreen(thisGREY);
  tft.setCursor(0,0);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextDatum(TL_DATUM);
  tft.setFont(Arial_18);
  tft.drawString("Digital Read Out V0.00", 0,0);
  tft.println();
  uint16_t cx = tft.getCursorX();
  uint16_t cy = tft.getCursorY();
  tft.setTextColor(ILI9341_GREEN);
  tft.drawString("Z axis", cx, cy);
  tft.println();
  cx = tft.getCursorX();
  cy = tft.getCursorY();
  cxg = cx;
  cyg = cy;
  tft.drawFloat(Zval, 4, cx, cy);
}

void setup() {
  // put your setup code here, to run once:
  while(!Serial && millis() < 4000);
  for(int i=5; i<8; i++) pinMode(i, OUTPUT);  // init these pins to outputs

  DROZ_Enc.begin(0,1, CountMode::full);
  DROZ_Enc.attachCallback(nullptr);  // don't attach the callback yet until everything is ready!
  DROZ_Enc.setValue(0);  // set initial value

  myacc = 0;
  errorcount = 0;
  conversionfactor = 1.0/5080.00;
  oldZval = 0.0;
  Zval = 0.0;

  if (!initMyDisplay(3))
  {
    Serial.println("Display failed to initialize");
    while(1);
  }
  mainMenu();
  DROZ_Enc.attachCallback(onDROZ_Changed);  // enable callback
}

void loop() {
  // put your main code here, to run repeatedly:
  
  if (Zval != oldZval)
  {
    // if count changed, update the display
    uint16_t x1, y1, w, h;
    oldZval = Zval;
    String newstr = "XXXXXXXX";
    tft.getTextBounds(newstr, cxg, cyg, &x1, &y1, &w, &h);
    tft.fillRect(x1, y1, w, h, thisGREY);
    tft.drawFloat( Zval, 4, cxg, cyg );
    //Serial.printf("Zval = %+7f4\n", Zval);  // uncomment for serial output
  } 
  delay(10);

}

Hope this helps.
 
I'm beginning to wonder whether the encoder is just broken or not a quadrature encoder at all.
Looking closely at the board photo I see 4 LEDs arranged in a quadrant style, columns A & B and rows IN & OUT.
The silkscreen on the board states: "IN MATCHES OUT ENCODER GOOD" and "IN NO(?) FLASH ENCODER BAD" and "OUT NO FLASH CHECK CABLE".
When you rotate the encoder very slow, can you make something up from the LED behaviour? And does the direction of rotating show a difference in the LED output?
Perhaps it's worth to borrow a scope somewhere...

Paul
 
This looks like a hardware issue. Did you measure the output voltage on A/B? Make sure that it isn't higher than 5V for T3.1, T3.5 and not higher than 3.3V for T3.6 or T4.x. You will destroy your controller if you apply more than those voltages to the input pins.

If the voltage is OK, I suggest to run something like the code below to check the connection (the pattern you observe look like only one of the two signals reaches the controller. )
Code:
void setup()
{
    pinMode(0, INPUT_PULLUP);  // Assume that the encoder is connected to 0/1, change as required (here and in loop)
    pinMode(1, INPUT_PULLUP);
}

int oldA, oldB;

void loop()
{
    int A = digitalReadFast(0);
    int B = digitalReadFast(1);
    if(A != oldA || B != oldB)
    {
        Serial.printf("%d %d \n", A, B);
        oldA = A;
        oldB = B;
    }
}

It needs to print something like
Code:
0 0
0 1
1 1
1 0
0 0 
0 1
1 1
1 0
...

If it does, you can try
Code:
#include "EncoderTool.h"
using namespace EncoderTool;

Encoder enc;

void setup()
{
    enc.begin(0, 1,CountMode::full); // adjust to your setup, use countMode::full for non mechanical encoders
}

void loop()
{
    if(enc.valueChanged())
    {
        Serial.println(enc.getValue());
    }
}

Or, if you prefer the stock Encoder library:
Code:
#include "Encoder.h"

Encoder enc(0, 1);

void setup()
{
}

int oldVal;

void loop()
{
    int val = enc.read();
    if (val != oldVal)
    {
        Serial.println(val);
        oldVal = val;
    }
}

This page might help identifiying your encoder: https://loggingencoders.com/
 
Thanks for all the feedback. Also, thx for that alternate source for the part!

I'll give all this a try and respond afterwards... Apologies for the cut-n-paste... Here's the sketch:

Code:
#include "EncoderTool.h"
using namespace EncoderTool;

Encoder encoder;          // interrupt based encoder

void setup()
{
  Serial.begin(115200);
  // pinMode(2, INPUT_PULLUP);
  // pinMode(3, INPUT_PULLUP);

   encoder.begin(2,3,myCallback, CountMode::full); //CountMode::halfAlt);
  //  encoder.setValue(0);
  //  encoder.setLimits(-300, 300);
  
   encoder.attachCallback(myCallback);
   Serial.println("Setup complete.");
}
long count = 0;

void myCallback(int position,int delta) {
  Serial.print("Position:");Serial.print(position); Serial.print(" Delta:"); Serial.println(delta);
  if(delta > 0) {
    count++;
  } else {
    count--;
  }
  Serial.print("count:"); Serial.println(count);
}
void loop()
{
    // if (encoder.valueChanged()) {
     //   Serial.println(encoder.getValue());
    // }
}
 
Yay!!! It was the voltage! I was driving the encoder separately from the breadboard. 12v supply, and had a range of 3-7v coming in on the pins. When I had looked at this before I never saw anything above 5. Which is why I thought it was ok. :-(

When I powered the encoder from the 5v line off the uC, I was getting a 1-2v sig on the A/B channels. Now the data looks valid... I'm getting solid +1 values in one direction, and -1 values in the other and my counter increments or decrements accordingly.

I'm still going to play w/ the values a little to get more up to speed. I also need to figure out how to hook this into the cab, w/ 20'+ of wire to the encoder. Not sure a 5v supply is going to do it. although maybe the turn around distance will have a big enough voltage drop where it's ok? Maybe I'll just drive it w/ 12v and put a lvl shifter in front of the line... anyway lots to think about.

Thx again for the help!
 
Back
Top