Is there a simple quadrature decoder module?

I need to decode quadrature signals, from rotary and linear optical quadrature a/b signal encoders. The 16mhz cpu on standard 8 bit arduino is not fast enough to keep up with the speed of my tests.

Is there a quadrature module I can buy, that can handle high speed decoding, and send the signals out through a divided clock signal, or a register I could read?

What's the frequency of the signal it has to read? I'm amazed that an 8-bit avr is struggling there... 16mhz should be able to handle a pretty fast signal.

If you need to detect clock/anti-clock and counts a bit of 74HCT logic will do it for you.

If not fast enough a little FPGA with < 10nS gate delays might be good enough.

If not, how fast do you really need - ? what are you going to do with this data?

Allan

The 16mhz cpu on standard 8 bit arduino is not fast enough to keep up with the speed of my tests.

You are probably doing something wrong.

I was testing with a small motor and 512 ppm quadrature encoder on my desk. 10% duty cycle powering 12v (motor rated at 24v) I began losing steps - counted on my Arduino sketch, using both external hardware interrupts. I lost my notes for the RPM, it was way too slow. I have another encoder in my box to test with (I have to look up it's resolution PPM)

Is FPGA a different processor? I'm not interested yet to learn all that - it's a project itself with the bootloaders, extra hardware I have to buy (usually the wrong one the first 2, 3 times) then wrestle with libraries. I want to do this eventually, but it will distract me on accomplishing what I need, for now.

I'm going to process the data from the encoder for positioning a small motor attached to steering arm, on an 200 pound electric ATV. I also need this so I can fix the digital read-out on the milling machine at the shop with a glass-scale encoder installed.

Hi,

I can’t speak to whether the arduino should or can’t handle such a signal. But to your question U.S Digital makes such an IC.

John

10% duty cycle powering 12v (motor rated at 24v) I began losing steps - counted on my Arduino sketch, using both external hardware interrupts.

Definitely something wrong with your code. 511 posts and you still haven’t figured out how to use this forum?

Are you printing stuff on the serial monitor?

jremington:
Definitely something wrong with your code. 511 posts and you still haven't figured out how to use this forum?

Are you printing stuff on the serial monitor?

I spent a lot of my time studying the signaling, running many tests both with and without debug messages. Of course, I must be doing something wrong. 300 rpm = 5 rps. 512ppm encoder makes 4 rise signals each detent so that's 2048 interrupts each revolution. 5 revolutions in 1 second * 2,048 = 10,240 interrupts / second to process 10khz, if my calculations are correct.

I could not get my wheel to spin 3 revolutions before losing steps.

Post the code.

jremington:
Post the code.

Ok.

pid_mc.ino (12.2 KB)

If you are trying to learn how to rapidly read encoders, there is certainly no need for all the other crap in that file. Suggest you start over.

If you need precision and high speed when reading a quadrature encoder, Take a look at this.

This will allow you to decode 3 quadrature encoders, counting speed up to 20 MHz, and all you have to do is read the values. The chip does all the work. They also sell a 6 quadrature encoder board. These boards are compatible with Uno, mega and due.

the Arduino will work, but it is not really designed for this task and it will not give you the speed and accuracy that this board will give you.

correction, 20 MHz counting speed is for 3.3V applications. For the 5V applications, which is used for this board, counting speed is 40 MHz. Individual chips are available from US digital, $5.60 each.

www.usdigital.com

jremington:
If you are trying to learn how to rapidly read encoders, there is certainly no need for all the other crap in that file. Suggest you start over.

I can see how my file may be confusing. Unfortunately, the same program did not work on my first 100 attempts. My debugging "crap" was added to help me better understand what was going on. I can't really expect someone else to understand my program, I lost the original simple sample after I began to add my test points.

promacjoe: Thank you for the example! This is exactly the type of thing I was searching for! 3 whole encoder axis is perfect.

Doing this:

//  Serial.begin(9600);

and leaving active Serial.print() statements in your code will cause a failure when the serial buffer overflows. In time critical applications, Serial.print() to get debugging information out can make matters worse because of its execution time, but you could also try a higher baud rate.

6v6gt:
Doing this:

//  Serial.begin(9600);

and leaving active Serial.print() statements in your code will cause a failure when the serial buffer overflows. In time critical applications, Serial.print() to get debugging information out can make matters worse because of its execution time, but you could also try a higher baud rate.

That line of code is commented. I wrote my own library to handle common serial interface tasks, and use 115200 baud. I will always need debugging serial for my programs until I learn of some other way I can troubleshoot my own issues.

This part of the loop function is the guts of the serial debug interface:

if (sProcess.sRead())
{
	ProcessData();
}

It is the serial.available() / read function that stores return values, and the processData() function is the code that handles the basic serial commands.

I was not aware of buffer overflow failure issues - this is new to me. If my projects had buffer overflow failures, I would not know it or what happens. Thank you for pointing that out, I can go search on my own to study this and learn how to prevent or handle an overflow.

If the serial port isn't processing debug - it needs commands from the R/C receiver OR pass on the data to a different Arduino for processing.

Unfortunately, the same program did not work on my first 100 attempts.

You are certainly patient!

Since you are ill-advisedly using someone else's encoder library, start with the minimal example that comes with the library and learn how it works.

A better approach would be to write your own code, using ISR for the external interrupts. With this approach, quadrature encoders can be read and fully decoded using roughly a dozen lines of code.

Here is one approach.

Tutorial on interrupts here.

Ok thanks for the information. I should probably decode my own encoder. After reading over the documents that the author of that library took their time to write, I felt confident that their skills and experience to design that function surpassed my own skills with interrupt handling and the processing of fast code counters.

Making my own closed-loop Arduino motor driver is a fairly involved project that needs me to master the encoder and P.I.D. (or whatever) motor pulse output loop. Which is why I was searching for an open source, budget / beginner device / module to get me started and study, so that I can learn from that example and / or modify it so I can advance the actual project I'm trying to work on.

For the time being, I found this "KANGAROO" module, that connects right up to my Sabertooth driver, handles the quad-decoding, positing, and motor speed regulation that I was looking for, for the steering and traction control drive output to begin with.

I took another look at your code, and in addition to all the unnecessary code, you are definitely misusing the encoder library.

For example, you should NOT be using the "double" type for encPosition.

//Define Variables we'll be connecting to
//int32_t encPosition;
double encPosition, encPositionOld;

There is a short example program on the page describing that library. Try it. There are also speed tests which should be very informative.

Incidentally, that library appears to be well documented and coded. You would do very well to study the material.

jremington:
I took another look at your code, and in addition to all the unnecessary code, you are definitely misusing the encoder library.

For example, you should NOT be using the "double" type for encPosition.

//Define Variables we'll be connecting to

//int32_t encPosition;
double encPosition, encPositionOld;

ID myPID( &encPosition, &pidOutput, &target, Kp, Ki, Kd, DIRECT);

That is a stupid mistake, I have overlooked. I could not figure out how to pass that to the PID object, requires a DOUBLE. The program actually ran, and I was getting readings, I forgot about the issue, which probably presents problems. Thanks for bringing that up, I overlooked this.

ID myPID( &encPosition, &pidOutput, &target, Kp, Ki, Kd, DIRECT);

I went back and re-modified my code. I ran tests again. I find the encoder counting to be working exceptionally good.

Ok, so now I just need to work on the PID or motor pulse output part of the program.