Linear optical encoder missing ticks using Quadrature Encoder Engine
hughes
Posts: 5
Hello everyone,
I am building a measuring device. I am trying to read a US Digital EM1 Linear optical encoder with 500 lines per inch resolution. I am using QuadratureEncoderEngine.spin, ASCII0_STREngine.spin & FullDuplexSerial.spin with the code I wrote below at the top object. The code works and displays my height variable as expected on the lcd screen. The height is not accurate though. There seems to be a random error of + or a handful of ticks as I move through about half an inch of stroke. I put an oscilloscope on the encoder outputs and I am seeing two very clean 5 volt square waves 90 degrees out of phase. I have used resistors to pull up, pull down and capacitors to try and clean up the signal. No matter how I move the square wave around the code misses ticks. I am convinced its the code because I tried averaging both channels A & B of the quadrature encoder engine even though they are reading the same pins. This improved accuracy by about 50%. The encoder engine is said to be good to 100,000 ticks/sec thats well below my input speed. I honestly do not understand Assembly yet, but I believe the problem lies in my Spin code. Any ideas on how I can make this work?
Thanks,
-Hughes
My Top Object file is below:
CON
I am building a measuring device. I am trying to read a US Digital EM1 Linear optical encoder with 500 lines per inch resolution. I am using QuadratureEncoderEngine.spin, ASCII0_STREngine.spin & FullDuplexSerial.spin with the code I wrote below at the top object. The code works and displays my height variable as expected on the lcd screen. The height is not accurate though. There seems to be a random error of + or a handful of ticks as I move through about half an inch of stroke. I put an oscilloscope on the encoder outputs and I am seeing two very clean 5 volt square waves 90 degrees out of phase. I have used resistors to pull up, pull down and capacitors to try and clean up the signal. No matter how I move the square wave around the code misses ticks. I am convinced its the code because I tried averaging both channels A & B of the quadrature encoder engine even though they are reading the same pins. This improved accuracy by about 50%. The encoder engine is said to be good to 100,000 ticks/sec thats well below my input speed. I honestly do not understand Assembly yet, but I believe the problem lies in my Spin code. Any ideas on how I can make this work?
Thanks,
-Hughes
My Top Object file is below:
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
TX_PIN = 0
BAUD = 19_200
VAR
_xinfreq = 5_000_000
TX_PIN = 0
BAUD = 19_200
Long Ticks 'Initialize counter A variable
Long Tocks 'Initialize counter B variable
OBJ
LCD : "FullDuplexSerial.spin" 'Call LCD object
Encoder : "QuadratureEncoderEngine" 'Call encoder engine object
Decimal : "ASCII0_STREngine_1" 'Call ASCII encoder object
PUB Start | idx
Encoder : "QuadratureEncoderEngine" 'Call encoder engine object
Decimal : "ASCII0_STREngine_1" 'Call ASCII encoder object
LCD.start(TX_PIN, TX_PIN, %1000, 19_200) ' Start LCD on TX pin with a baud rate of 19,200
waitcnt(clkfreq / 100 + cnt) ' Pause for FullDuplexSerial.spin to initialize
lcd.tx($0C) ' Clear LCD screen.
waitcnt(clkfreq / 100 + cnt) ' Pause for LCD to clear screen.
lcd.tx($11) ' backlight on
' Start Up Display
waitcnt(clkfreq / 100 + cnt) ' Pause for FullDuplexSerial.spin to initialize
lcd.tx($0C) ' Clear LCD screen.
waitcnt(clkfreq / 100 + cnt) ' Pause for LCD to clear screen.
lcd.tx($11) ' backlight on
lcd.tx(22)
waitcnt(clkfreq / 100 + cnt) ' Pause for FullDuplexSerial.spin to initialize
LCD.str(string("KEM Equipment")) ' Display Startup string line 1.
lcd.tx(148) ' Move curser to line 2 position 0.
LCD.str(string("Please Tare")) ' Display Startup string line 2.
waitcnt(clkfreq * 1 + cnt) ' Hold startup massage on display for 1 seconds.
PUB Main
waitcnt(clkfreq / 100 + cnt) ' Pause for FullDuplexSerial.spin to initialize
LCD.str(string("KEM Equipment")) ' Display Startup string line 1.
lcd.tx(148) ' Move curser to line 2 position 0.
LCD.str(string("Please Tare")) ' Display Startup string line 2.
waitcnt(clkfreq * 1 + cnt) ' Hold startup massage on display for 1 seconds.
lcd.tx($0C) ' Clear LCD screen.
waitcnt(clkfreq / 100 + cnt) ' Pause for LCD to clear screen.
Encoder.QEDEngine ' Start QuadratureEncoderEngine.
Ticks := (Encoder.getDeltaA) ' Get tick count A since startup write value to Ticks.
Tocks := (Encoder.getDeltaB) ' Get tick count B since startup write value to Tocks.
LCD.str(string("Height")) ' Print the word "Height" to screen.
lcd.tx(135) ' Send cursor to line 1 position 14.
LCD.str(string("(in/1000)")) ' Show units
waitcnt(clkfreq * 1 + cnt) ' Pause for display.
waitcnt(clkfreq / 100 + cnt) ' Pause for LCD to clear screen.
Encoder.QEDEngine ' Start QuadratureEncoderEngine.
Ticks := (Encoder.getDeltaA) ' Get tick count A since startup write value to Ticks.
Tocks := (Encoder.getDeltaB) ' Get tick count B since startup write value to Tocks.
LCD.str(string("Height")) ' Print the word "Height" to screen.
lcd.tx(135) ' Send cursor to line 1 position 14.
LCD.str(string("(in/1000)")) ' Show units
waitcnt(clkfreq * 1 + cnt) ' Pause for display.
repeat
Ticks := Ticks + (Encoder.getDeltaA) ' Set "Ticks" to accumulate encoder delta A
Tocks := Tocks + (Encoder.getDeltaB) ' Set "Tocks" to accumulate encoder delta B
lcd.tx(148) ' Move curser to second line position 0
LCD.str(Decimal.integerToDecimal((Ticks*2), 3)) ' Display Ticks in units of in/1000
LCD.str(Decimal.integerToDecimal((Tocks*2), 3)) ' Display Tocks in units of in/1000
LCD.str(Decimal.integerToDecimal((Ticks+Tocks),3)) ' Display Average of Ticks & Tocks units in/1000
lcd.tx(148) ' Move curser to second line position 0
Tocks := Tocks + (Encoder.getDeltaB) ' Set "Tocks" to accumulate encoder delta B
lcd.tx(148) ' Move curser to second line position 0
LCD.str(Decimal.integerToDecimal((Ticks*2), 3)) ' Display Ticks in units of in/1000
LCD.str(Decimal.integerToDecimal((Tocks*2), 3)) ' Display Tocks in units of in/1000
LCD.str(Decimal.integerToDecimal((Ticks+Tocks),3)) ' Display Average of Ticks & Tocks units in/1000
lcd.tx(148) ' Move curser to second line position 0
Comments
Normally I'd assume an error made by you or myself before thinking Kye's code could be the problem but in this case I think it's Kye's code causing the problem. Kye's object doesn't keep track of the transitions correctly. Here's a thread on the subject.
I'd suggest trying a different encoder object. I haven't added my own quadrature code to the OBEX yet. I have an encoder only version attached to post #2 in this thread. The code attached to post #1 includes PWM motor control algorithms.
-Hughes
having an immediate use so its testing wasn't exhaustive.
http://obex.parallax.com/object/737
For a single encoder I'd expect it to function up to about 250kHz (10^6 counts/second).
It should follow the rules correctly and even acrue an error count (catches when A & B
both change in too short a timespan to detect the order).
@ hughes - Sorry about that object wasting your time. Please use the Parallax developed object.
What's the "default" object?