madmark2150
Published © GPL3+

PO Box Combination Lock w/servo

Uses potentiometer and joystick for input of combination. Three 1 or two characters are each step in the combo with 8000 permutations.

BeginnerFull instructions provided245
PO Box Combination Lock w/servo

Things used in this project

Hardware components

Arduino Mega 2560
Arduino Mega 2560
Any controller with one AI, one DI, one PWM DO, & LCD can be used
×1
Analog joystick (Generic)
Only the push button part is needed. A real push button can be used.
×1
Alphanumeric LCD, 20 x 4
Alphanumeric LCD, 20 x 4
×1
Servo Module (Generic)
×1
Rotary potentiometer (generic)
Rotary potentiometer (generic)
5 or 10k, generic 5/16" shaft, single rotation, linear taper, with knob
×1

Software apps and online services

Arduino IDE
Arduino IDE
Tinkercad
Autodesk Tinkercad

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

Large Servo Mount 3D .STL print file

This mounts a large (3/4" x 1-9/16") servo. It has cable exit holes on both sides so the servo can be mounted in either direction. the base had f #6 thru holes for mounting. The servo attaches with four 6-32 x 1/2 screws. You should tap the four holes 6-32 before use.

Door pivot for far end of servo 3D .STL print file

Servo arm has 1/16" dia holes for connecting rod. This little piece has a matching 1/16" hole and two #6 thru holes for mounting on the door.

KY-023 Joystick Case 3D .STL print file

This mounts a standard Arduino starter kit KY-023 joystick. Four holes are to be tapped 4-40 for mounting the joystick. The top cover mounts with four 6-32 screws and ca be used without tapping, do not over torque!
A cable outlet is provided large enough to a five wire DUPONT5 connector shroud.

DuPont 5 station slip on connector shroud 3D .STL print file

Slips over cable to change five loose DuPont connections into a single, unified, connector.

5/16" shaft mini potentiometer 8-way mount - 3D .STL print file

Mounts any standard 5/16" shaft mini potentiometer commonly found in Arduino starter kits. Has four anti-rotation holes sized to fit the tab on the pot. Allows mounting in any of four positions from either side for universal 8-way mounting.

20 x 4 LCD front side panel mount - 3D .STL print file

Use this to mount 2004A type LCD displays

Arduino Uno/Mega 2560 wide mount for screw shield clearance - 3D .STL print file

Mounts Uno/Mega

Schematics

KY-023 Joystick

KY-023 Joystick

Door Linkage

How servo rotation angles were determined

Gadget block diagram - DOESN'T MATCH PINS IN CODE

Basic schematic with available components on TinkerCad. Match Z-axis DI wired to value in code.

LCD2004 I2C Address Jumpers

I2C addressing jumpering

Code

Running framework for your code and functional sub for combo lock

Arduino
This is the minimum required code to implement a three character PO Box combination lock - add to your own code
//
// Code excerpt from larger working sketch
// Copyright 2022 - Mark M. Lambert - Free Use with attribution
//
// Simulate a PO box lock.
// Turn pot to dial setting
// Click Joystick to enter #
//
// Presumes 20x4 LCD
//
const int LCD_COLS = 20;
const int LCD_ROWS = 4;
//
// Define strings for PO Box Combo Lock simulator
// 20 lock postitions
//
// Combination dial is pot on A15
//
const int Wiper   = A15;    //Wiper from 5k pot
//
// Servo needs a PWM output. Powered by Aux +5
//
const int PWM1      =  9;   // Big servo
//
// Servo angles for locking mechanism - see CAD drawing
//
const int LockAngle = 15;
const int UnLockAngle = LockAngle + 79;   //Desired rotation angle to open door from CAD
const int MidAngle = (LockAngle + UnLockAngle) /2;
//
// Joystick switch
//
const int Zaxis     = 44;       // Joystick Z (push sw)
//
// Key codes
//
char *LockTable[] = {
      "A", 
      "A-B", 
      "B", 
      "B-C", 
      "C", 
      "C-D", 
      "D", 
      "D-E", 
      "E", 
      "E-F", 
      "F", 
      "F-G", 
      "G", 
      "G-H", 
      "H", 
      "H-I", 
      "I", 
      "I-J", 
      "J", 
      "J-A"
    };
//
const String LockCombo = "ECB";   // Min combo is three chars
String LockEntryA;      // These could be combined but are separated for
String LockEntryB;      // easy test
String LockEntryC;
String LockEntry;       // Combined string
//    
// Code snippet begins with minimum needed includes
//
#include <Wire.h>               //I2C Driver
#include <LiquidCrystal_I2C.h>  //I2C LCD display driver for all LCD's
#include <Servo.h>              //PWM Servo motorServo DoorServo;  // create servo object to control large servo
//
// 0x27 is default address for I2C 20x4 LCD displays - adjust accordingly
//
LiquidCrystal_I2C lcd(0x27, LCD_COLS, LCD_ROWS);  // set the LCD object address to 0x27 and for a 20 chars and 4 line display
//
Servo DoorServo;  // create servo object to control large servo
//
void setup()
  {
  Serial.begin(9600);       //Warm up comm port
  //
  pinMode(Zaxis, INPUT_PULLUP);   // Push sw on joystick
  lcd.init();  //initialize the lcd
  }
//
// you will have your own code here to call this routine
// 
void loop()
  {
    // Your code goes here
  }
// =======================
//
// Door lock sub
//
void comboLock()
  {
  lcd.clear();
  lcd.backlight();
  //
  lcd.print("PO Box Sim");
  lcd.setCursor(0, 1);
  lcd.print("First Code &");
  lcd.setCursor(0, 2);
  lcd.print("Press Joystick Btn:");
  lcd.setCursor(0, 3);
  lcd.print("Code: ");
  //
  while (digitalRead(Zaxis) != 0)
    {
      //
      // show live reading - 3 chars
      //
      lcd.setCursor(6, 3);
      lcd.print("   ");
      lcd.setCursor(6, 3);
      //
      // We wanna map 0-1023 to 0-19 & display
      // letters
      //              
      lcd.print(LockTable[ map( analogRead(Wiper), 0, 1023, 0, 19) ] );
      //
      delay(20);  //Reduce display flicker
    }
  loop;
  // 
  // Wait fast for button release
  //
  while (digitalRead(Zaxis) == 0)
    {
    }
  loop;
  //
  // Button released, use last reading
  //
  LockEntryA = LockTable[map( analogRead(Wiper), 0, 1023, 0, 19)];
  //
  lcd.clear();
  lcd.print("PO Box Sim");
  lcd.setCursor(0, 1);
  lcd.print("Second Code &");
  lcd.setCursor(0, 2);
  lcd.print("Press Joystick Btn:");
  lcd.setCursor(0, 3);
  lcd.print("Code: ");
  //
  while (digitalRead(Zaxis) != 0)
    {
      //
      // show live reading - 3 chars
      //
      lcd.setCursor(6, 3);
      lcd.print("   ");
      lcd.setCursor(6, 3);
      //
      // We wanna map 0-1023 to 0-19 & display
      // letters
      //              
      lcd.print(LockTable[ map( analogRead(Wiper), 0, 1023, 0, 19) ] );
      //
      delay(20);  //Reduce display flicker
    }
  loop;
  // 
  // Wait fast for button release
  //
  while (digitalRead(Zaxis) == 0)
    {
    }
  loop;
  //
  // Button released, use last reading
  //
  LockEntryB = LockTable[ map( analogRead(Wiper), 0, 1023, 0, 19)] ;
  //
  lcd.clear();
  lcd.print("PO Box Sim");
  lcd.setCursor(0, 1);
  lcd.print("Final Code &");
  lcd.setCursor(0, 2);
  lcd.print("Press Joystick Btn:");
  lcd.setCursor(0, 3);
  lcd.print("Code: ");
  //
  while (digitalRead(Zaxis) != 0)
    {
      //
      // show live reading - 3 chars
      //
      lcd.setCursor(6, 3);
      lcd.print("   ");
      lcd.setCursor(6, 3);
      //
      // We wanna map 0-1023 to 0-19 & display
      // letters
      //              
      lcd.print(LockTable[ map( analogRead(Wiper), 0, 1023, 0, 19) ] );
      //
      delay(20);  //Reduce display flicker
    }
  loop;
  // 
  // Wait fast for button release
  //
  while (digitalRead(Zaxis) == 0)
    {
    }
  loop;
  //
  // Button released, use last reading
  //
  LockEntryC = LockTable[map( analogRead(Wiper), 0, 1023, 0, 19) ];
  //
  lcd.clear();
  lcd.print("PO Box Sim");
  lcd.setCursor(0, 1);
  lcd.print("Code: ");
  lcd.print(LockEntryA);
  lcd.print(" ");
  lcd.print(LockEntryB);
  lcd.print(" ");
  lcd.print(LockEntryC);
  lcd.setCursor(1, 2);
  // 
  LockEntry = LockEntryA;
  LockEntry += LockEntryB;
  LockEntry += LockEntryC;
  Serial.print(" Entered: ");
  Serial.println(LockEntry);
  Serial.print("Required: ");
  Serial.println(LockCombo);
  //
  if (LockEntry == LockCombo)
    {
    lcd.print("Access GRANTED.");
    DoorServo.write(UnLockAngle);
    delay(3000);
    DoorServo.write(LockAngle);
    }
  else
    {
    lcd.print("ACCESS DENIED!");              
    delay(3000);
    }
  //
  lcd.clear();
  //
  }
// ========================
// FIN
// ========================

Credits

madmark2150
5 projects • 1 follower
Contact

Comments

Please log in or sign up to comment.