Programming Optical Encoders

We ordered some Digi-Key optical encoders for use on our robot’s stacking mechanism (for automatic positions). However, we have run into a snag in programming these little buggers. We have hooked the power up to the +5V for Potentiometers on the Analog Inputs, and the ground wire to this port as well. Then, we hooked Inputs A and B onto digital inputs 15 and 16, respectively. Our problem is that all the readings we get on a debug are zeros. Any ideas? Thanks.

Check your documentation. You most likely are missing a resistor. There should be two voltages, cmos and ttl, you want to use a correct resistor value for TTL voltage levels.

now correct me if im wrong but…

It won’t work the way you have it connected.

I believe that the only items you are allowed to connect to the analog ports are the pots and other analog related stuff, all other items requiring power must be hooked up into the main circuit breakers. For 5V power, what you need to do is get a 7805 voltage regulator and connect:

pin1: 12V (to fuse)
pin2: GND (to ground)
pin3: 5V (to the 5V power on encoder)

With the power connected as explained above, the encoder should function properly… and really this is something for the electrical forums anyway… :slight_smile:

We have now gotten readouts from the first sensor using Gyro power, but the second input reads a constant 1. We tried changing the variable to another digital input, but to no avail. Help!!! Also, our counts using the first input to determine position are very inaccurate. They are:
if sw_stacker >= 136 then stack_up
if sw_stacker <= 122 then stack_down
stack_pos = stack_pos + A_out
arm_out = sw_stacker
goto done_stack
stack_pos = stack_pos - A_out
arm_out = sw_stacker

in the above, sw_stacker is a pot on the OI control system, stack_pos is a counter for postion (=0 at the beginning of the loop), A_out is the first input from the encoder (0 or 1), and arm_out is the variable sent to the van door motor running our stacker.

How do these “encoders” of yours work ?

With the encoders that look like pots, that I just found on pages 830-831 of the DigiKey catalog, you have two “quadrature” outputs that you have to use to determine the direction, and also count one of them (or count all the transitions on both, for more resolution). The duration of the pulses is dependent on the speed of rotation, and the RC cannot be programmed to read them reliably if the pulses don’t last exactly 26 ms. To be better than a pot, you would want 128+ bits / rev, which would make the motion awfully slow. If in quadrature, you would need 52 ms x 128 = 6.6 seconds to turn one rev.

They have open collector outputs, and so they will need pull-up resistors, as mentioned in another reply, above. 10k from +5V to the encoder output ought to be ok.


A PIC operating on an interrupt-on-change is a real nice thing to have with these, because it can keep up with the pulses (it notices things every microsecond) and it could count the pulses, as does a mouse. Reporting back to the RC is possible too, possibly using the programming port of the RC.

Any other way for a PIC to talk to the RC via an analog input reduces the data to 8 bits anyway, so why not use a pot ?

For simplicity and cost reasons, we chose to use mechanical rather than optical encoders. These are basically rotary switches in quadrature; common to ground, A and B outputs to two digital inputs.

Timing is something you have to think about. Determine your maximum revolutions per second at the encoder, invert to get time per revolution, then divide by the number of encoder states to get time per state. Each state should last at least 26 milliseconds (longer is better - ours worked out to 55ms).

If you are trying to track absolute position, you will need to establish a reference point.

(In our implimentation, we attached the encoder to an earlier stage on the gearbox, which acts as a multiplier on the encoder - [N encoder states] times [gearing ratio] = #Effective states)

Given the above, the following code works great for us…

'table lookup using current and previous encoder state
temp.bit3 = fng_sensorA
temp.bit2 = fng_sensorB
temp.bit1 = fng_sns_lstA
temp.bit0 = fng_sns_lstB
read graydcd+temp.lownib, temp

'update current position with change in position (mod 256)
fng_sns_pos = fng_sns_pos + temp

'save current encoder bits for next time around
fng_sns_lstA = fng_sensorA
fng_sns_lstB = fng_sensorB

'finger zero established as 6 o'clock, +=ccw
fng_inp = (fng_inp */ fng_inp2sns_m) + fng_inp2sns_b	'scale OI control input to sensor units
if fng_sns_calib then fng_sns_pos = fng_inp 'reset calib
temp = (fng_sns_pos - fng_inp) */ fng_sns2mtr_scl   'to +-127
fng_motor = 254 - (127 + temp)

graydcd data 0,255,1,-0, 1,0,-0,255, 255,-0,0,1, -0,1,255,0 'state table for finger position decode

(The ‘-0’ entries are the cases where somehow you missed an encoder state change)