Introduction: Lego Head Safe
This instructable was created in fulfillment of the project requirement of the Makecourse at the University of South Florida (www.makecourse.com). This oroject was done by Kaitlin Bellerose, a student in the course.
The idea behind the safe is that a servo spins into place in an aperture, either opening or closing the Lego head safe. The Arduino code controls the functionality of the safe and password entry/storage.
The following materials and tools are needed for successful creation of the project:
1) Arduino Uno
2) 4x4 matrix keypad
3) Jumper wires and resistors
4) 9V battery and connector to Arduino Uno
5) Black box or similar secure box
6) LCD screen
7) Mini servo and stand
8) Mini breadboard
9) Square oak dowel
10) Black acrylic paint
11) White acrylic paint
12) Dremel and pads
13) Super glue
14) Philips head screwdriver with small head
15) 3D printer to make head
16) Fine paintbrush
17) Fine-grain and coarse-grain sandpaper
Step 1: Circuit Schematic
The circuit is pinned out as follows:
The LCD is hooked to pins AREF and GND.
The servo is attached to pin 11.
The 4x4 matrix keypad is tied to pins 8, 7, 6, 5, and 4, 3, 2, 10. I have a dead pin at 9, so the wiring is a bit jumbled. Wire yours the way it makes sense to you and what pins you have available. Keep in mind that pins 1 and 0 are reserved for TX and RX.
Attachments
Step 2: 3D Printed Parts
The dimensions were scaled from the example found on the Instructables site of a Lego figurine: https://www.instructables.com/id/LEGO-Man-Costume/s...
The head was scaled in millimeters to approximately 4 times the size of the example. As for the actual printing of the part, I did not have much of a decision with regard to the orientation of the item prior to print. I received the head parts from the university visualization lab.
Once you print out the required part, super glue the pieces together. I initially tried to print out the heads that would fit snugly inside each other, but I could not get the tolerances correct to fit.
The opening at the bottoms of the Lego head is rectangular, allowing for the oblong horn (wings) of the servo. The wing is short on the vertical axis and longer on the horizontal. You may need to adjust the width of the rectangular hole (or trim the servo horn as a last resort).
The MAKE project for our class required that we use a DC-47 enclosure case. The box can be found here: http://www.polycase.com/dc-47p.
Attachments
Step 3: Physical Construction
After you finish wiring the components outside of the enclosure, you will realize that choices have to be made to get the wiring to fit. But before you ever put the case together, you have to mark and cut the apertures needed to have the LCD fit into the side of the box and the servo arm fit through the top of the box.
When cutting with the Dremel, please take great care to have proper ventilation because the fumes that come off the heated-up plastic box are noxious. A safe route would be to redesign and reprint the box.
The stand I used was a castaway item provided by a classmate that happened to serve its purpose. For your purposes, find a stand or stack of stable items (like connected Lego blocks) to place the servo on.
The mess of wires is difficult to control. You will need to attach the matrix pad to the Arduino via a female-to-female connector. The servo will also need to be attached to its stand so it does not fall over due to the item being knocked or the twisting wires settling, causing it to fall. Super glue is a good choice, though, again, watch for the fumes.
The Lego head needs to have the support material removed and the roughness sanded off. I cannot recommend any particular kind or grain of sandpaper because I just used leftover fine and coarse grain sandpaper I had left over when I painted my car. As with most things, test sand in a spot that will not be visible prior to completely sanding the whole area completely.
For the cosmetic portion of the project, reference the look of a Lego head before proceeding. I recommend that you practice your strokes on a paper plate or any older iterations prior to committing the paint to the final product.
The Lego head as it is designed can easily be twisted and picked off the servo regardless of whether the servo is in closed or locked position. To stop this ability to defeat this lock by twisting the head, I glued a small piece of square dowel to the neck of the head and glue two corresponding pieces on the box lid that would straddle the dowel to prevent the head from being twisted. I painted the dowel pieces black to match the box. The dowel was obtained from Home Depot.
The matrix keypad has adhesive on the back of it, but I elected to apply the matrix keypad with super glue. To ensure that the keypad stays in place, put something heavy on top that would not necessarily set off the keypad itself (like the water glass I used).
Once done, completely fasten the screws of the box. Please keep in mind that the life of the safe is not very long because the 9V battery lasts about four hours of continuous use To keep it constantly powered, you will have to use the USB cable and cut a corresponding hole in the box for it. For the purposes of the demo, I used the 9V to have an independent system to present.
Step 4: Code
The code used existing libraries for the LCD, Servo, and Keypad. I created my own code with regard to the password system and overall functionality. The code provides three options for the safe: open, close, and set password. In order to change the password, the user has to know the existing password. The code is fully commented for the ease of a person new to programming.
The following and attached is my code. Please feel free to use it!
/***************************************************************************************************************************
Title: Lego Head Safe
Author: Kaitlin Bellerose
Date: 11/01/2014
Updated: 12/03/2014
Purpose: This sketch provides the control system for the Lego Head safe.
This sketch borrows from multiple sources. The original sources will be cited here in the title block when general approaches were followed.
1) Keypad.h library written by Mark Stanley and Alexander Brevig (mstanley@technologist.com, alexanderbrevig@gmail.com)
2) There is a password.h library available on Instructables and similar sites. I did not care for the implementation, so I created my own. ****************************************************************************************************************************/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include <Keypad.h>
LiquidCrystal_I2C lcd(0x27,16,2); // Instantiate a 16x2 I2C LCD display with address 0x27
Servo myServo; // Instantiate a servo
int pos; // Declare variable to hold servo position value (NOTE: "position is a reserved word)
int servoSpeed; // Declare variable to hold servo speed value (NOTE: "speed" is a reserved word) char password[3]; // Array that holds master password. Set to length you would like. I chose 3 for ease of demo char entry[3]; // Array that holds the user-entered password attempt
boolean isAlreadyOpen; // Flag that tracks whether safe is already open
boolean isAlreadyClosed; // Flag that tracks whether safe is already closed
const byte ROWS = 4; // Four rows in 4x4 keypad matrix
const byte COLS = 4; // Four columns in 4x4 keypad matrix
char keys[ROWS][COLS] = { // Maps the keypad values {'1','2','3', 'A'}, {'4','5','6', 'B'}, {'7','8','9', 'C'}, {'*','0','#', 'D'} };
byte rowPins[ROWS] = {8, 7, 6, 5}; // Connect to the row pinouts of the keypad
byte colPins[COLS] = {4, 3, 2, 10}; // Connect to the column pinouts of the keypad
// Use 1 or more appropriate pin for what I have labeled as "10"
// My Arduino has many dead ports I have to navigate around
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); // Instantiates a keypad with the values passed.
/********************Set-up Function*********************/
void setup(){ Serial.begin(9600); // Set serial to 9600 baud
myServo.attach(11); // Set servo to pin 11
isAlreadyOpen = 0; // Sets open flag to false
isAlreadyClosed = 1; // Sets closed flag to true
pos = 90; // Sets value for servo arm position at 90 degrees
servoSpeed = 3; // Sets servo speed to 3 degrees per second
myServo.write(pos); // Sets servo arm to 90 degrees
password[0] = '1'; // Be sure to put initial value in single quotes due to its char nature
password[1] = '2'; // Second value in password array
password[2] = '3'; // Last value in password. The password will default to "123" when // power is lost.
keypad.setDebounceTime(250); // Sets the button debounce time for the keypad
lcd.init(); // Initialize the LCD
lcd.backlight(); // Set the display to be backlit
lcd.print("Welcome Home!"); // Print welcome message to LCD
delay(1000); // Have message display for 1000 milseconds
lcd.clear(); // Clear the display
lcd.print("1) Open 2) Close"); // Print menu options
lcd.setCursor(0,1); // Move cursor to second line
lcd.print("3) Set Code"); // Print second part of menu options
delay(3000); // Delay
}
/***************Main Loop*****************/
void loop(){
entry[0] = NO_KEY; // Reset the entry array with each loop or else
entry[1] = NO_KEY; // you'll get "false" entries from existing values
entry[2] = NO_KEY; // Set the final keypad to NO_KEY (similar to setting //
value to NULL in C++)
char key = keypad.getKey(); // Get the first key press with regard to menu.
if (key == '1'){ // Initiates logic if "Open safe" option is selected
if(isAlreadyOpen == 1) // Checks to see if the safe is already open. No point in opening something already open
{
lcd.clear(); // Clear LCD
lcd.print("Safe is already"); // Prints message
lcd.setCursor(0,1); // Move cursor to second line
lcd.print("open."); // Print second part of menu options
delay(2000); // Delay 2000 miliseconds }
else // If the safe is not already open, the following code engages {
lcd.clear(); // Clear the LCD
lcd.print ("Enter 1st key:"); // Message to solicit the first key press
lcd.setCursor(0,1); // Moves cursor to second line
while (entry[0] == NO_KEY) // The loop runs until a valid key press is made
`{
entry[0] = keypad.getKey(); // Stores the first value of the user-entered attempt at password
}
lcd.print(entry[0]); // Prints value for display on LCD. Use for debugging and ease of use. delay(1000); // Delays for 1000 miliseconds
lcd.clear(); // Clears LCD
lcd.print("Enter 2nd key:"); // Enter the second key press
lcd.setCursor(0,1); // Move curosr
while (entry[1] == NO_KEY) // Another loop that will run endlessly unless a valid keypress is made
{ entry[1] = keypad.getKey(); // Stores the second value of the user-entered attempt at password }
lcd.print(entry[1]); // Prints value for display on LCD. Use for debugging and ease of use. delay(1000); // Delay for 1000 miliseconds
lcd.clear(); // Clear LCD
lcd.print("Enter 3rd key:"); // Solicit third key press
lcd.setCursor(0,1); // Moved the cursor
while (entry[2] == NO_KEY) // Again, a while loop to continuously poll unti a valid key press is made. {
entry[2] = keypad.getKey(); // Gets the final key press
}
lcd.print(entry[2]); // Prints value for display on LCD. Use for debugging and ease of use. delay(1000); // Delay for 1000 miliseconds
lcd.clear(); // Clear LCD
if ((entry[0] == password[0]) && entry[1] == password[1] && entry[2] == password[2]) // If what the user entered matches the stored password, this loop executes
{
isAlreadyOpen = 1; // Set isAlreadyOpen flag to true/high
isAlreadyClosed = 0; // Set isAlreadyClosed flag to false/low
pos = 180; // Set position to 180 degrees
myServo.write(pos); // Set the servo to 180 degrees
lcd.clear(); // Clear LCD in anticipation of message
lcd.print("Safe is open."); // Message that the safe is open
delay(2000); // Delay of 2000 miliseconds }
else // If the wrong code was entered, this executes
{
lcd.clear(); // Clear LCD
lcd.print("Invalid code."); // Invalid code message
delay(1000); // Delay 1000 miliseconds
lcd.clear(); // Clear LCD } }
mainLCDMenu(); // Regardless of whether password entry was successful, this kicks back to the main menu functions }
else if (key == '2')
{ // Initiates if "Close safe" is selected
if(isAlreadyClosed == 1) // If the head is already closed, why close it again?
{
lcd.clear(); // Clear LCD
lcd.print("Safe is already"); // Begin message that the safe is already closed lcd.setCursor(0,1); // Move cursor to second line
lcd.print("closed."); // Finish message
delay(2000); // Delay for 2000 miliseconds delay }
else // If the safe is not already closed, this executes
{ isAlreadyOpen = 0; // Sets isAlreadyOpen flag to false/low
isAlreadyClosed = 1; // Sets isAlreadyClosed flag to true/high
pos = 90; // Sets pos to 90 degrees
myServo.write(pos); // Sets servo to 90 degrees
lcd.clear(); // Clears LCD
lcd.print("Safe is closed."); // Message that the safe is closed
delay(2000); // Delay 2000 miliseconds }
lcd.clear(); // Clear LCD
mainLCDMenu(); // Either way, go back to main menu }
else if (key == '3'){ // If "Set code" option is selected
lcd.clear(); // Clear LCD
lcd.print ("Enter 1st key:"); // The code that follow is a repeat of code in option 1 lcd.setCursor(0,1); // The user has to enter the password successfully before changing it
while (entry[0] == NO_KEY)
{ entry[0] = keypad.getKey(); }
lcd.print(entry[0]);
delay(1000);
lcd.clear();
lcd.print("Enter 2nd key:");
lcd.setCursor(0,1);
while (entry[1] == NO_KEY)
{ entry[1] = keypad.getKey(); }
lcd.print(entry[1]);
delay(1000);
lcd.clear();
lcd.print("Enter 3rd key:");
lcd.setCursor(0,1);
while (entry[2] == NO_KEY)
{ entry[2] = keypad.getKey(); }
lcd.print(entry[2]);
delay(1000);
lcd.clear();
if ((entry[0] == password[0]) && entry[1] == password[1] && entry[2] == password[2]) // If the password was correctly entered, this logic executes
{ password[0] = NO_KEY; // Reset the password value 0 to NO-KEY password[1] = NO_KEY; // Reset the password value 1 to NO-KEY password[2] = NO_KEY; // Reset the password value 2 to NO-KEY
lcd.print ("Set 1st key:"); // Set first key value
lcd.setCursor(0,1);
while (password[0] == NO_KEY) // Loops endlessly until valid key press received { password[0] = keypad.getKey(); // Sets password[0] to new value } lcd.print(password[0]); // Prints out new value
delay(1000);
lcd.clear(); // Clear LCD
lcd.print("Set 2nd key:"); // Message for 2nd key
lcd.setCursor(0,1); // Move code
while (password[1] == NO_KEY) // Loops endlessly until valid key press received { password[1] = keypad.getKey(); // Sets password[1] to new value } lcd.print(password[1]); // Prints out new value
delay(1000); // Delay 1000 miliseconds
lcd.clear(); // Clear LCD
lcd.print("Set 3rd key:"); // Message for third key
lcd.setCursor(0,1); // Move cursor
while (password[2] == NO_KEY) // Loops endlessly until valid key press received { password[2] = keypad.getKey(); // Sets password[2] to new value }
lcd.print(password[2]); // Prints out new value
delay(1000); // Delay 1000 miliseconds
lcd.clear(); // Clear LCD }
else // This executes if the user enters the wrong password for verification prior { // to changing the password. User cannot change password without knowing the password
lcd.clear(); // Clear LCD
lcd.print("Invalid code."); // Invalid code message
delay(1000); // Delay 1000 miliseconds
lcd.clear(); // Clear LCD }
mainLCDMenu(); // Regardless of outcome, go back to the main menu
} }
Attachments
Step 5: Final Product
Once the final screw is tightened, enjoy!
Discussions
6 years ago on Introduction
Nicely done!