Incremental Encoder Combination Lock

So I am making a combination lock that uses a Rotary Incremental Encoder for the device. I have 90% of the code done but some things aren’t working like I expect. I have been beating my head against a wall for a few weeks now so decided time to open it up to the collective mind.

First here is a list of components:

  • Arduino Nano Clone
  • TRDA-20R1N100VD Encoder from Automation Direct (using 3 wires, A+ B+ and Z+
  • Sparkfun Rotary Switch Potentiometer (for the combination pots)

Second a list of what is not working as expected:

  • The encoder is counting and resetting when it passes 0 but if you spin fast it doesn’t always keep up. I am using interrupts and are really quick but don’t know about accuracy.
  • I am still having trouble getting the true position out of the wheel when going in reverse. After it passes 0 it goes into negative numbers but if I am looking for position 2 I need it the same going in reverse or forward. ABS and reversing numbers does not seem to work. I have 100 counts on this encoder, when they work as expected.
  • Compare and Overshoot seem to be glitching (technical term for not always doing what I expect) For some reason if I just move the encoder without landing on the actual numbers at some point it just solves the lock. And that’s with the Reverse direction not working either.

And lastly the code itself. A large amount so not opposed to assistance on cleaning it up but right now more worried about getting it working first.

(Had to attach the code since it is too large for the forum)

Ships_Wheel_Combo_Lock_cleanup.ino (8.77 KB)

Most of the encoders I've used only have the A and B signals to determine the direction of rotation. What does the Z pin do with your encoder? Also, while this is not likely a problem, normally all variables used in an ISR are defined with the volatile type qualifier. Finally, it's unusual to need a comment on every line of code, plus shoving them "tight against the code" makes it harder to read.

void EncRead() {  //Run anytime the Encoder Pin A or B changes
  encoderRun = true;                            // Setting that we have engaged the Encoder
  if (digitalRead(encZ) == HIGH) currentPos = 0;                         //If Encoder passes Z Point reset to 0
  pinA = digitalRead(encA);                             //Reads the State of Encoder Pin A, places it in Variable
  //    encALast = LOW;                                                  //Set's Initial state of Encoder Pin A to LOW
  if ((encALast == LOW) && (pinA == HIGH)) {                            //If Enocder A moved from previous location
    if (digitalRead(encB) == false) {                              //If Encoder B is LOW then it moved CCW
      --currentPos;                           //Subtract from Current Position
      direction = false;                          //Set direction of travel
    } else {                                                             //If Encoder B is HIGH then it moved CW
      ++currentPos;                           //Add to Current Position
      direction = true;                       //Set direction of travel
  encALast = pinA;                                                  //Updates variable for next time through the loop

First here is a list of components:

  • Arduino Nano Clone
  • TRDA-20R1N100VD Encoder from Automation Direct (using 3 wires, A+ B+ and Z+
  • Sparkfun Rotary Switch Potentiometer (for the combination pots)

What do you want to do with your rotary encoder?

Mimic a mechanical safe lock with a a100-digit rotary dial?

Inner working maybe like that: Safe combination consists of 3 numbers in the 0…99 range example code:

And for opening the lock, you will have to do four steps, maybe:

  • rotate four full turns fleft (clear all)
  • wait one second (or longer)
  • rotate right 14 steps
  • wait one second (or longer)
  • rotate left 53 steps
  • wait one second (or longer)
    -rotate right 22 steps
  • wait one second, if everything is OK, lock opens

Such logic, or similar?

The Z pin is a zero position indicator. When it goes HIGH it tells me that the encoder passed 0. That way I can gather an absolute position on the device (as long as it passes 0 at least once)

Most of the comments are there for troubleshooting purposes and because I will probably have to end up coming back years down the road to do updates or troubleshooting so I want to make sure I know what everything did without having to spend much time on it. More comments aren't an issue and save time later.

And yes the encoder will operate like a mechanical combinations lock with 10 positions. I have 100 positions with the encoder, but only using 10 so dividing the wheel in sections to make up the numbers. That's why I added the range in compare (if compare number is within +-5 then still ok)

Right now the clear all is just going clockwise past 0 but it will probably add a few turns to make sure it is clear.

I was not using a delay, was thinking if they turned the device to the number (say 6) then immediately (or as fast as a human can which isn't very fast in processing time) turned it counter clockwise to the second number (say 3) but passing 0 (hence the negative number situation) and then back clockwise for the last number (say 4). Once you land on the last number it needs to "unlock"

Adding a delay will help a bit with reading the numbers and making sure they don't overshoot.

One way to keep your counter in range is to use modulo math:

Turning left: count = (count + 1) % 100; Turning right: count = (count + 99) % 100;

Are you trying to emulate a physical combination lock or just using the knob to input numbers? The physical lock requires multiple turns so you would need to keep track of the number of complete turns. If you are just entering numbers you need a way to indicate that you have reached a desired number, maybe by a pause or a button press.

Thanks yeah I am trying to emulate an actual combination lock. I spent most of last night redoing the read and compare sections so see the updated one attached. Still working on them but that is a step in the right direction. I added a counter that tells me whenever it passes 0 so I can control that, I also fixed the counter clockwise read so it now outputs an absolute number.

I redid the read from scratch so now using a grey code version to read the encoder. It is much more accurate and now I get 397 steps in the encoder before it reaches the 0 point. Which is plenty. Still having the issue of it skipping sometimes when I go real fast but I think that is fast enough it won’t matter for this project.

Please keep offering suggestions I am trying to get this finished and out the door soon.


Ships_Wheel_Combo_Lock__Ver_2_.ino (8.97 KB)