Pages: [1] 2   Go Down
Author Topic: Arduino as an encoder pulse divider?  (Read 2451 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have an application where I need to divide the number of pulses from an incremental encoder by either 2, 4 or 8 times. For instance, if the input encoder is a 1024 pulses per rev, I may need it to behave as a 128 pulse per rev encoder. I've looked through many variations on reading encoders but am not sure of the best way to implement this. Any ideas?

Thanks

Steve
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 224
Posts: 13921
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Where do the number of pulses come from, do you connect them to a digital input or to an interrupt line. ?

Did some pulsecounting @ http://www.arduino.cc/playground/Main/EEM12L-32AKWhMonitoring
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It needs to be accurate. The application is for Spindle control for CNC machines. The A/B channels are read in quadrature for direction and speed and the Z (index channel) is used for timing the start of movements like threading or tapping. The orginal electronics could read high value encoders, but as they break they become too expensive to repair with original parts, if available. Using a divider would allow the original hardware to work with readily available windows software.

It gets complicated as the pulse width space ratios must remain correct for quadrature detection within the control software to work properly.

I do have some code for a Xylinx CPLD that works for A/B channels but for some reason the index pulse part is broken. I don't understand it well enough to figure out where it's buggy and have no means of programming a Xylinx anyway.

It does however bear some resemblance to some of the arduino code I've seen, so maybe could be a basis for the code if I could translate it  smiley-wink
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
If your application is something as critical as CNC, then you need to deal with the actual quadrature pulses. If they are too fast, then you need to either slow down the machine or else use a faster microprocessor.

Hi Richard, I plan on using a mega2560. 16Mhz clock speed should be more than adequate, the Xylinx version was only set to run at 6Mhz.
Logged

Central Europe
Offline Offline
Edison Member
*
Karma: 7
Posts: 1220
Use the Source, Luke.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I plan on using a mega2560. 16Mhz clock speed should be more than adequate, the Xylinx version was only set to run at 6Mhz.

For your application, the ATmega2560 won't bring any real benefit over the ATmega328. The software of your system won't use much ram and you seem to have enough I/O and Serial ports for what you want to do. If it works on a ATmega2560 it'll also work on the smaller ATmega328.

The interesting part is the what you want to do.

If I understood you correctly, you have something with a 1024 pulse per revolution encoder on your shaft and it's not an option to change this. The system reading those encoders is dying on you and you want to replace it with something that can handle only 128 pulse per revolution encoders and you want the Arduino to process the 1024 pulses and create a proper 128 impulse signal, where care is taken that the relative position between both reading points is preserved to allow determining the speed. If that is so, the only solution I see at the moment is to completely parse the speed and direction information from the 1024 pulse encoders and fake the read values as 128 pulse signals. Simply skipping signals won't translate the quadrature pulses correctly.

To know whether this is possible with an Arduino, the critical information we need is: How fast are those shafts turning? Or put another way, how fast are the signals from the 1024 pulse encoders coming in?

Korman
« Last Edit: November 01, 2010, 01:57:57 am by Korman » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
To know whether this is possible with an Arduino, the critical information we need is: How fast are those shafts turning? Or put another way, how fast are the signals from the 1024 pulse encoders coming in?

The spindle is capable of 3200 rpm. The unknown is how many pulses the windows application is capable of reading reliably, hence the choices for division. I know it can't read 1024 pulses per rev at 3200 rpm, I need to divide until it works.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
But what we are saying is that if you must keep track of absolute position, you can not use dividing because at best, it can't handle "fractions", and even worse, it will drop pulses when reversing.  Dividing is a useful technique for sampling RPM, but NOT for keeping track of absolute position.

I never mentioned position  :-?

I simply need to divide the number of pulses output from the encoder by an as yet unknown amount and output a lesser number of pulses to the windows application.
Logged

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 637
Posts: 34609
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I simply need to divide the number of pulses output from the encoder by an as yet unknown amount and output a lesser number of pulses to the windows application.

Sadly it is not as simple as that. You could use a 74LS74 to divide pulses but that would not take into account any changes in direction. The best bet would be yo make the encoders give a step and direction pulse and use an up down counter and only take out the most significant count. Rather like this:-
http://www.thebox.myzen.co.uk/Workshop/Rotary_Max.html
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
But what is the windows application DOING with the information? You cannot expect a successful outcome if you treat something that important as an unknown black box

Richard

All I need is some help on how to solve the problem of dividing a quadrature count accurately. Not negative comments or a discussion on CAM.

Perhaps I should have asked

"Does anybody here know Xylinx code and can help me translate it to Arduino"
Logged

Offline Offline
Edison Member
*
Karma: 3
Posts: 1001
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The following is a link to a good software implementation of quadrature decoding that will run on any Arduino flavor board.

http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino

It should be within reach to accurately account for 1024 pulses per rev at 3200 RPM with the above code and even handle "fractions" if you need to slow down the pulse rate for your Windows app. Some clever low-level coding however is needed to pull this off for the additional logic needed to support the serial interface.

Note that interrupts are not used in the above code and you want to keep it that way as it is much more efficient when doing high-speed pulse counting.
Logged

St. Louis, Missouri
Offline Offline
Sr. Member
****
Karma: 1
Posts: 279
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Steve-
I think this may be of use to you: http://emergent.unpythonic.net/projects/01149094674

Some people on this forum can be quite snarky in their replies. This is in marked contrast to other forums I've frequented such as CNCzone.com or the EMC2 forum where I've always found people to be extremely helpful without copping an attitude.
Hope that link helps you.

-Greg
Logged

St. Louis, Missouri
Offline Offline
Sr. Member
****
Karma: 1
Posts: 279
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hmmmm... I just noticed all the posts by Richard disappeared. What's up with that?
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
It should be within reach to accurately account for 1024 pulses per rev at 3200 RPM with the above code and even handle "fractions" if you need to slow down the pulse rate for your Windows app. Some clever low-level coding however is needed to pull this off for the additional logic needed to support the serial interface.

Note that interrupts are not used in the above code and you want to keep it that way as it is much more efficient when doing high-speed pulse counting.

Hi BenF - I'd read that interrupts were the way to go for efficient code?

I see that a poster Leo suggested interrupt modified code down the page a bit?

I'm hoping not to use  serial, but use digitalWrite for the output, but hadn't though that far yet  smiley

Here's how the Xylinx code reads what to do with the input, looks to be similar to the array used in Oleg's code

int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};

Code:
if  (  
            (quada2 = '0' and quada1 = '1' and quadb2 = '0' and quadb1 = '0')  or
            (quada2 = '0' and quada1 = '0' and quadb2 = '1' and quadb1 = '0')  or
            (quada2 = '1' and quada1 = '1' and quadb2 = '0' and quadb1 = '1')  or
            (quada2 = '1' and quada1 = '0' and quadb2 = '1' and quadb1 = '1')) then              
                  qcountup <= '1';
            else
                  qcountup <= '0';
            end if;                  
            if  (
            (quada2 = '0' and quada1 = '0' and quadb2 = '0' and quadb1 = '1')  or
            (quada2 = '0' and quada1 = '1' and quadb2 = '1' and quadb1 = '1')  or
            (quada2 = '1' and quada1 = '0' and quadb2 = '0' and quadb1 = '0')  or
            (quada2 = '1' and quada1 = '1' and quadb2 = '1' and quadb1 = '0')) then
                  qcountdown <= '1';
            else
                  qcountdown <= '0';
            end if;
Logged

Offline Offline
Edison Member
*
Karma: 3
Posts: 1001
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Interrupts carry an overhead of some 50 machine cycles (calling, save/restore state) whereas with polling (as is used here) there is virtually no overhead. If interrupts occur at intervals down towards 50 machine cycles, your application would halt and fail. With polling however you would still be going strong. Interrupts are useful (and efficient) for a number of applications, but for this task it may not be.

I was thinking serial, but you may as well output a re-coded quadruple signal if that is what you need. digitalWrite however is a very slow function so you may need to look at direct port io.

The Xylinx code looks identical in function to the state loopkup table. Lookup is just a faster way to do the same.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The following is a link to a good software implementation of quadrature decoding that will run on any Arduino flavor board.

http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino

It should be within reach to accurately account for 1024 pulses per rev at 3200 RPM with the above code and even handle "fractions" if you need to slow down the pulse rate for your Windows app. Some clever low-level coding however is needed to pull this off for the additional logic needed to support the serial interface.

Hi Ben - tried that code, eventually got it to work when I realised that the port assignments are different on a Mega, but it has some problems.

It only reads the encoder as 0 to 255 counts CW then rolls over to 0 again, CCW it counts down.

It also gets confused at at anything but a crawl and looses it's count at times. Turning CW it may go, for example, 100, 101, 102, 101, 100, 101 etc.

Oleg does say on his page that this may happen with high count rates and suggests converting to an interrupt routine. I'll give that a go tomorrow and see how it performs.
Logged

Pages: [1] 2   Go Up
Jump to: