Skip to content

Final Project

Final Project Slide

Final Project Video

Liscense

This work is licensed under the Creative Commons License-NonCommercial-ShareAlike, which allows others to “enables reusers to distribute, remix, adapt, and build upon the material in any medium or format for noncommercial purposes only, and only so long as attribution is given to the creator” (This copyright blurb was written by Angelina Yang).

Download Design Files

Click here to download my design files folder

Bill of Materials

Link to Google Sheets Bill of Materials

Early Project Ideas

My final project idea is a smart medicine box that is designed specifically for college students and dorm rooms. It will resemble a safe with an electronic programmable lock and will mount to a wall with rear panel mounting holes so the medicine box can only be removed (easily) from the wall if you know the lock combination.

Where my design will deviate from the typical safe is I want to add a sensor that records when the door is opened (marking this as a way to record when a person takes their medications).

For example, if a person needs to take a medication twice daily, they would open the door two times a day.

Current Products/Inspiration

  1. Medicus Health’s Narcotics Cabinet, Double Door, Double Lock, Electronic Programmable Lock (12”W x 8”D x 15”H)

Constraints

  • Overall Size: Small College Dorm Rooms

The safe needs to fit on a college dorm room wall, not take up too much of the limited space these students already have, and needs to not be too bulky/in the way of students.

  • Inner, Necessary Size: Number and Size of Prescriptions

Need to consider the number of medications taken on average by a college student and the average size of a prescription bottle.

Research:

Single Care states that the average American takes ~4 medications.

Statistica states that “Between 2022 to 2023, around 37.5 percent of college and university students who received mental health services took medication for their mental health concerns.”

The image is from The Vial Company

CAD Model

Below is my first Fusion360 CAD design of the smart medicine box:

    Early Medicine Box Model     by Alana Duffy

Channel for wiring:

Weeks My Project Will Use

Method How it will apply in my project
Week 2: Computer-aided design Design the medicine box in Fusion360 along with the shelving, wooden wire covers, and PCB board cases
Week 3: Computer controlled cutting Laser cut shelving & wooden wire covers and vinyl cut sticker for box
Week 4: Electronics production Mill the two PCB boards that will design
Week 5: 3D scanning and printing 3D print PCB board cases
Week 6: Embedded programming Program the electronics via PCB boards with microcontrollers
Week 7: Computer controlled machining CAM then CNC Medicine Box
Week 8: Electronics design Create the PCB Boards in KiCad for the I2C LCD + Time of Flight Sensor board and Keypad Matrix + Solenoid Lock board
Week 9: Output devices The I2C LCD will display information given to it from the Time of Flight Sensor and the solenoid lock will open/close based on information sent to its microcontroller
Week 10: Input devices The Time of Flight board records and sends distance data to its microcontroller and the keypad matrix records the buttons being pressed and sends that data to its microcontroller
Week 12: Moulding and Casting 3D print or mill a mould and then cast a case for the I2C LCD to protect it

System Diagram & Gantt Chart

I created this system diagram with Lucid App to help visualize what needed to be done in each step of the process for my final project:

Below is the Gantt Chart I made so that I can stay on track and complete my final project:

Note: this was a very optimistic plan

Tasks to be completed

Per my teachers reccomendations, I also made a list of tasks to be completed:

☐ Determine what type of material I will use for the box (metal, wood, etc.)

☐ Design CAD file for med box that will import to Aspire (CAM software) well

☐ Design Aspire file for box

☐ CNC box

☐ Assemble box

☐ Place order for components that are not provided in the lab

☐ Program electronics

☐ Design, mill, solder, and wire PCB boards that I need

☐ Establish communication between electronics

☐ TROUBLESHOOT

Box Frame

Fusion360 Design

In Fusion360, I designed a box with tabs and slots that would later use dogbone jointery. The tabs/slots were designed with the width of the plywood. I had to measure the thickness of the 4’ x 8’ plywood in multiple places with callipers as the thickness of the plywood is never exactly what it is said to be; my “0.5 inch thick” wood was actually 0.45 inches thick. In Fusion, I clicked letter “s” to open the search bar, searched for “parameters,” and opened the define parameters tab. I then entered value 0.45 inches for the width of the tab parameter.

    Final Box Design     by Alana Duffy

CAM & Milling

Laser Cut Test

Before milling, I tested my Fusion360 design by laser cutting it first. I knew the slots would be too big for the cardboard, however, I left them as I had designed them for the wood as I wanted to be sure that there was enough room in the slots for the wood to fit in.

My laser cutting steps:

1.save the fusion sketch as a .dxf

2.Import the file into Corel draw (hairline and black for cutting lines)

3.Click control and P

4.Move the design over the material in bed in the epilogue software

5.Click the folder with a down arrow to import a material (I did a cardboard cut)

6.On the laser cutter, Click the joystick with a light icon, move the laser over the material with the joystick, and then click autofocus

7.Next, click the play button to have it run

Problems: First the tabs didn’t exactly align, realized I had a tab I forgot to specify the distance from the side of the material in my Fusion360 sketch. I went back in and dimensioned it and re-saved the file. Then the top wasn’t long enough so I increased the length by 1 in. Finally, the pieces fit and aligned properly.

Aspire File Setup

First, I needed to take my Fusion360 design (CAD) and bring it into Aspire (CAM). I started by uploading the .dxf file of my fusion sketch into Aspire.

This is what it looked like when I first loaded the sketch in:

In the “Job Setup” tab, I selected the following settings:

  • Job Type: Single Sided

  • Job Size: Width (X) = 96 inches; Height (Y) = 48 inches; Thickness (Z) = 0.45 inches

My material:

  • Units: inches

  • Z Zero Position: Machine Bed

  • XY Datum Position: from bottom left corner and unchecked “Use Offset” box

  • Design Scaling: Unchecked “Scale design with job size” box

  • Modeling Resolution: Standard (fastest)

I then clicked “OK”

Next, I created dog bone fillets. Under the “Design” tab, I selected the “Fillet” tool under the “Edit Objects” section. I set the Fillet/Tool Radius to 0.1875 inches for the 3/8” Compression Spiral bit, 0.125 inches for the End Mill (1/4”) Bit, and 0.0625 inches for the 1/8” End Mill Bit (generally, the dog bone fillet radius should be half the diameter of your bit). I then selected the “‘Dog-Bone’ Fillet” under the “Fillet Type” section. I then clicked on the corners of all of the tabs in my design to give them dog-bone fillets.

Toolpaths

1) Alana Profile 1

I created a 2D Profile Toolpath for the outline of my box.

My settings were:

  • Cutting Depths: Start Depth = 0 inches; Cut Depth = 0.45 inches; Checked “Show advanced toolpath options” box

  • Tool: 3/8” Compression Spiral; Passes = 3

Note: I increased the suggested passes number by one for my toolpaths to ensure I did not break the bit

  • Machine Vectors: Outside/Right; Direction = Climb; Allowance offset = 0 inches

  • Unchecked “Do Seperate Last Pass” box

  • Checked “Add tabs to toolpath” box; Length = 0.5 inches; Thickness = 0.125 inches; Unchecked “3D tabs” box

*I added about one tab to each side of the outline

  • Unchecked “Add ramps to toolpath” box

I then clicked “Calculate” and named it “Alana Profile 1”

2) Tab Pocket 1

Next, I created a Pocket for the Tabs. My settings were the same as the first profile except for the following:

  • Tool: End Mill (1/4”)

  • Unchecked “Add tabs to toolpath” box

I then clicked “Calculate” and named it “Tab Pocket 1”

3) Wire Management Pocket 2

I also created a Pocket for the Wire Management on the door. My settings were the same as the first profile except for the following:

  • Cutting Depths: Cut Depth = 0.3 inches

  • Tool: End Mill (1/4”)

  • Unchecked “Add tabs to toolpath” box

I then clicked “Calculate” and named it “Wire Management Pocket 2”

4) Door Profile 2

Next, I created a Profile for the door. My settings were the same as the first profile except for the following:

  • Tool: 1/8” End Mill

I then clicked “Calculate” and named it “Door Profile 2”

5) Matrix wire connect Profile 3

Then, I created a Profile for the Keypad Matrix’s wires. My settings were the same as the first profile except for the following:

  • Tool: 1/8” End Mill

I then clicked “Calculate” and named it “Matrix wire connect Profile 3”

6) ToF Pocket 3

Next, I created a Pocket for the Time of Flight Sensor. My settings were the same as the first profile except for the following:

  • Cutting Depths: Cut Depth = 0.3 inches

  • Tool: 1/8” End Mill

  • Unchecked “Add tabs to toolpath” box (I did not need any for the pocket as it was not going all the way through the material)

I then clicked “Calculate” and named it “ToF Pocket 3”

7) LCD Pocket 4

Then, I created a Pocket for the LCD. My settings were the same as the first profile except for the following:

  • Cutting Depths: Cut Depth = 0.4 inches

  • Tool: 1/8” End Mill

  • Unchecked “Add tabs to toolpath” box (I did not need any for the pocket as it was not going all the way through the material)

I then clicked “Calculate” and named it “LCD Pocket 4”

8) LCD Profile 4

Finally, I created a Profile for the LCD. My settings were the same as the first profile except for the following:

  • Tool: 1/8” End Mill

  • Unchecked “Add tabs to toolpath” box (I did not need any for the pocket as it was not going all the way through the material)

I then clicked “Calculate” and named it “LCD Profile 4”

This is how the finished toolpaths looked on the Aspire Simulation:

Milling

The Charlotte Latin Lab CNC Workflow details the milling process, however, I have also made one from the processes I did while milling:

For the Material:

  1. Move material onto Shopbot bed, aligning it with the right front corner (front meaning the side of the wood closest to you)

  2. Attatch the brad-er to the air compression hose, ensuring the air compressor is on

  3. Brad the material onto the Shopbot bed

Running the File:

  1. Open and check file in aspire

  2. Save file

  3. Save tool path

  4. Open file in shopbot software

  5. Run an aircut

    1. Bring to origin (JH)

    2. Set z-zero height to 1 in above material (JZ1.5 then Zz)

    3. Click ‘Start’ (run the file)

    4. Then when done enter C3 do rehome the machine and reset z-zero height to the machine bed

  6. Then can turn on dust collector

  7. Re-open file

  8. Click ‘Start’ with no offset (when machine changes bit to the one you want/has the one you want already in it, need to click the green button when prompted to start spindle and will hear a sound to know that it’s turned on)

  9. When its done, enter “J2 48,24” to move the spindle back and out of the way. Then use the vaccuum to remove dust shavings before using the multi tool to remove the tabs. Once you’ve removed the pieces you milled, use a crowbar to pry the wood sheet off the CNC bed (remember to remove any nails/brads sticking out when your done)

Milling in Process:

Milling Completed:

Pieces Freed!

I checked to make sure that my pieces fit together before I started sanding.

I then sanded the pieces down. I started with an 80-grit sandpaper and worked my way up to a 320-grit.

Unfortunately, I later realized one of the pieces actually did not fit so I had to re-mill. I adjusted the side length and followed the same process as before (only differing in deleting pieces I did not need to mill again) to make the new pieces:

Milling Completed:

Pieces Freed!

I checked (more diligently this time) to make sure that my pieces fit together before I started sanding.

The Final CNC Results:

The Door

Hinges

After watchng The NotSoCivilEngr’s Door Hinge YT video, I decided on the type of hinges I wanted to use on the door/front of the medicine box.

I couldn’t fit a drill in the door hole so I had to do 4 of the 8 screws by hand. After that, I was able to use a drill without much trouble.

Door Handle

I also installed a door handle on the door (after painting). The threads in the handle I bought were a bit messed up so I had to use two split lock washers to help hold the handle in place. I drilled two holes for the screws to go through and twisted them into the handle on the other side. It came out very nice and sturdy!

Painting

After using a coat of primer, I purchased French Blue Rust-oleum from Home Depot and spray painted the box. I taped off some sections I did not want the spray paint to get on. I let the first coat dry for 30 minutes then applied a second coat. I waited 2 hours after the second coat.

Primer:

Taping:

Results:

Shelving

Fusion360 Design

I measured the inside of the box and made my shelves a little shorter to allow for some wiggle room. I made two shelves that were 10.5” x 6” and an electronics hiding box/shelf that had a base that’s 10.5” x 10” and a front that’s 10.5” x 2.5” which have slots and tabs to slide together. The tabs are 0.12” wide, the thickness of the laser cut wood.

    Box Shelves     by Alana Duffy

Laser Cutting

My laser cutting steps:

1.save the fusion sketch as a .dxf

2.Import the file into Corel draw (hairline and black for cutting lines)

3.Click control and P

4.Move the design over the material in bed in the epilogue software

5.Click the folder with a down arrow to import a material (I did a wood cutting 1/8” (3mm))

6.On the laser cutter, Click the joystick with a light icon, move the laser over the material with the joystick, and then click autofocus

7.Next, click the play button to have it run

Cut in progress:

Finished Cut:

Electronic Hiding Box:

The Shelves:

I then tested to make sure they all fit well in the box:

Painting

I used primer to paint the wood and give it a nice look. I decided to not paint it blue like the outside of the box because I wanted the inside to be a lighter, more spacious feeling color.

Installation

Shelf Pins

I used a drill to make 0.2 inch holes in the wood where I wanted my pins to go and then inserted Everbilt’s 5 mm Brass Plated Steel Shelf Support Spoon Pins in the holes.

Shelves!

Shelf pins and shelving:

I then decided to sand a divet in the side of the electronic hiding box’s front piece so that more wires could pass through the channel next to the box.

Electronics: getting it to work

I2C LCD

You can visit my Week 9 Documentation (Output Devices) to see how I got the I2C LCD working.

Time of Flight Sensor

You can visit my Week 11 Documentation (Input Devices) to see how I got the Time of Flight Sensor working.

Keypad

At first, I tried to use the ATtiny84 Keypad Human Interface Qwiic Platform Evaluation Expansion Board.

Later, however, I used Adafruit Industries 3x4 Matrix Keypad.

Getting it to Work

From this link I was able to get my keypad matrix working.

I wired the keypad to an Arduino Uno as shown below:

I then installed the keypad library “Adafruit Keypad” by Adafruit in the library manager tab. When installing it, it popped up that “The library Adafruit Keypad:1.3.2 needs another dependency currently not installed: Adafruit NeoPixel.” I clicked “Install All” and installed both the Adafruit Keypad and Adafruit NeoPixel libraries.

Then, I went to File>Examples>Adafruit Keypad>keypad_test

At the top of the code, I changed the keypad id to my keypad’s id, “KEYPAD_PID3845”

// define your specific keypad here via PID
#define KEYPAD_PID3845

I then uploaded the sketch and opened the serial monitor.

When I first did this, boxes were showing in the serial monitor instead of the corresponding number and “pressed” or “released” when I pressed the buttons on the keypad. I asked ChatGPT to first explain the code itself and then asked it why this issue might be happening. It had many suggestions but the one that fixed my issues was the reccomendation to check that my baud rate in the serial monitor was the same as in the code. I then realized that my serial monitor was set to a baud rate of 115200 instead of 9600.

Once I changed the baud to 9600 and re-uploaded the code, it worked! I was able to see the number corresponding to the button I pressed and released in the serial monitor.

The code I used was as follows:

// Use this example with the Adafruit Keypad products.
// You'll need to know the Product ID for your keypad.
// Here's a summary:
//   * PID3844 4x4 Matrix Keypad
//   * PID3845 3x4 Matrix Keypad
//   * PID1824 3x4 Phone-style Matrix Keypad
//   * PID1332 Membrane 1x4 Keypad
//   * PID419  Membrane 3x4 Matrix Keypad

#include "Adafruit_Keypad.h"

// define your specific keypad here via PID
#define KEYPAD_PID3845
// define your pins here
// can ignore ones that don't apply
#define R1    2
#define R2    3
#define R3    4
#define R4    5
#define C1    8
#define C2    9
#define C3    10
#define C4    11
// leave this import after the above configuration
#include "keypad_config.h"

//initialize an instance of class NewKeypad
Adafruit_Keypad customKeypad = Adafruit_Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);

void setup() {
Serial.begin(9600);
customKeypad.begin();
}

void loop() {
// put your main code here, to run repeatedly:
customKeypad.tick();

while(customKeypad.available()){
    keypadEvent e = customKeypad.read();
    Serial.print((char)e.bit.KEY);
    if(e.bit.EVENT == KEY_JUST_PRESSED) Serial.println(" pressed");
    else if(e.bit.EVENT == KEY_JUST_RELEASED) Serial.println(" released");
}

delay(10);
}

Additionally, this code needs to be used as well (in another tab) as it is referenced by the previous code as “keypad_config.h”:

// This file contains predefined setup for various Adafruit Matrix Keypads.
#ifndef __KEYPAD_CONFIG_H__
#define __KEYPAD_CONFIG_H__

#if defined(KEYPAD_PID3844)
const byte ROWS = 4; // rows
const byte COLS = 4; // columns
// define the symbols on the buttons of the keypads
char keys[ROWS][COLS] = {{'1', '2', '3', 'A'},
                         {'4', '5', '6', 'B'},
                         {'7', '8', '9', 'C'},
                         {'*', '0', '#', 'D'}};
byte rowPins[ROWS] = {R1, R2, R3,
                      R4}; // connect to the row pinouts of the keypad
byte colPins[COLS] = {C1, C2, C3,
                      C4}; // connect to the column pinouts of the keypad
#endif

#if defined(KEYPAD_PID1824) || defined(KEYPAD_PID3845) || defined(KEYPAD_PID419)
const byte ROWS = 4; // rows
const byte COLS = 3; // columns
// define the symbols on the buttons of the keypads
char keys[ROWS][COLS] = {
    {'1', '2', '3'}, {'4', '5', '6'}, {'7', '8', '9'}, {'*', '0', '#'}};
byte rowPins[ROWS] = {R1, R2, R3, R4};         // connect to the row pinouts of the keypad
byte colPins[COLS] = {C1, C2, C3}; // connect to the column pinouts of the
                                   // keypad
#endif

#if defined(KEYPAD_PID1332)
const byte ROWS = 1; // rows
const byte COLS = 4; // columns
// define the symbols on the buttons of the keypads
char keys[ROWS][COLS] = {
    {'1', '2', '3', '4'},
};
byte rowPins[ROWS] = {R1}; // connect to the row pinouts of the keypad
byte colPins[COLS] = {C1, C2, C3,
                      C4}; // connect to the column pinouts of the keypad
#endif

#endif

Working off the Arduino

Next, I wanted to get the keypad matrix working just as it did with the Arduino Uno with a different microcontroller. I decided to use a seeed XIAO RP2040 as I am familiar with them and they have many benefits to them.

I wired it as follows:

My wiring cheat sheet:

Keypad Pin XIAO RP2040 Pin Wire Color
C2 D9 Orange
R1 D2 Yellow
C1 D8 Green
R4 D5 Blue
C3 D10 Purple
R3 D4 Brown
R2 D3 White

I then gave ChatGPT the code I was using for the keypad on the Arduino Uno and asked it to change it to work with a XIAO RP2040. The only issue I encountered in this was that C4 was defined in the code but was not an actual pin on the keypad matrix. I just left it undefined and it worked just fine.

The code:

/ Use this example with the Adafruit Keypad products.
// You'll need to know the Product ID for your keypad.
// Here's a summary:
//   * PID3844 4x4 Matrix Keypad
//   * PID3845 3x4 Matrix Keypad
//   * PID1824 3x4 Phone-style Matrix Keypad
//   * PID1332 Membrane 1x4 Keypad
//   * PID419  Membrane 3x4 Matrix Keypad

#include "Adafruit_Keypad.h"

// define your specific keypad here via PID
#define KEYPAD_PID3845
// define your pins here



// can ignore ones that don't apply
#define R1    D2
#define R2    D3
#define R3    D4
#define R4    D5
#define C1    D8
#define C2    D9
#define C3    D10
#define C4    
// leave this import after the above configuration
#include "keypad_config.h"

//initialize an instance of class NewKeypad
Adafruit_Keypad customKeypad = Adafruit_Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);

void setup() {
Serial.begin(9600);
customKeypad.begin();
}

void loop() {
// put your main code here, to run repeatedly:
customKeypad.tick();

while(customKeypad.available()){
    keypadEvent e = customKeypad.read();
    Serial.print((char)e.bit.KEY);
    if(e.bit.EVENT == KEY_JUST_PRESSED) Serial.println(" pressed");
    else if(e.bit.EVENT == KEY_JUST_RELEASED) Serial.println(" released");
}

delay(1);
}

AND with “keypad_config.h” as the following code in a seperate tab:

// This file contains predefined setup for various Adafruit Matrix Keypads.
#ifndef __KEYPAD_CONFIG_H__
#define __KEYPAD_CONFIG_H__

#if defined(KEYPAD_PID3844)
const byte ROWS = 4; // rows
const byte COLS = 4; // columns
// define the symbols on the buttons of the keypads
char keys[ROWS][COLS] = {{'1', '2', '3', 'A'},
                         {'4', '5', '6', 'B'},
                         {'7', '8', '9', 'C'},
                         {'*', '0', '#', 'D'}};
byte rowPins[ROWS] = {R1, R2, R3,
                      R4}; // connect to the row pinouts of the keypad
byte colPins[COLS] = {C1, C2, C3,
                      C4}; // connect to the column pinouts of the keypad
#endif

#if defined(KEYPAD_PID1824) || defined(KEYPAD_PID3845) || defined(KEYPAD_PID419)
const byte ROWS = 4; // rows
const byte COLS = 3; // columns
// define the symbols on the buttons of the keypads
char keys[ROWS][COLS] = {
    {'1', '2', '3'}, {'4', '5', '6'}, {'7', '8', '9'}, {'*', '0', '#'}};
byte rowPins[ROWS] = {R1, R2, R3, R4};         // connect to the row pinouts of the keypad
byte colPins[COLS] = {C1, C2, C3}; // connect to the column pinouts of the
                                   // keypad
#endif

#if defined(KEYPAD_PID1332)
const byte ROWS = 1; // rows
const byte COLS = 4; // columns
// define the symbols on the buttons of the keypads
char keys[ROWS][COLS] = {
    {'1', '2', '3', '4'},
};
byte rowPins[ROWS] = {R1}; // connect to the row pinouts of the keypad
byte colPins[COLS] = {C1, C2, C3,
                      C4}; // connect to the column pinouts of the keypad
#endif

#endif

It worked well and the same as it did with the Arduino Uno.

Solenoid Lock

The solenoid lock I used was Adafruit Industry’s Lock-style Solenoid - 12VDC

Info from the websites:

  • “Solenoids are basically electromagnets: they are made of a big coil of copper wire with an armature (a slug of metal) in the middle. When the coil is energized, the slug is pulled into the center of the coil. This makes the solenoid able to pull from one end.”

  • “This solenoid in particular is nice and strong, and has a slug with a slanted cut and a good mounting bracket. It’s basically an electronic lock, designed for a basic cabinet or safe or door. Normally the lock is active so you can’t open the door because the solenoid slug is in the way. It does not use any power in this state. When 9-12VDC is applied, the slug pulls in so it doesn’t stick out anymore and the door can be opened.”

  • “To drive a solenoid you will a power transistor and a diode, check this diagram for how to wire it to an Arduino or other microcontroller. You will need a fairly good power supply to drive a solenoid, as a lot of current will rush into the solenoid to charge up the electro-magnet, about 500mA, so don’t try to power it with a 9V battery!”

This solenoid requires a 12V power source so I used my one we had in my lab, a Ledmo Power Supply.

Stats About the Power Bank:

  • Input Voltage: AC 100-240V, 50-60HZ

  • Output Voltage: DC12V

  • Electrical Current: 5A/6A

  • Power: 60W/70W

Getting it to Work

The video that I used that actually helped me figure out how to get the solenoid to work was this video: DIY Tech Guy’s Arduino Lesson 4 - Solenoid control using a Transistor. I followed this video pretty much to tea.

In the video, he uses this code:

// Code written by DIY Tech Guy YouTube in his "Arduino Lesson 4 - Solenoid control using a Transistor" video (https://www.youtube.com/watch?v=Yh3TLXihUps) 

int solenoidPin = 7;

void setup() {

  pinMode(solenoidPin, OUTPUT);


}

void loop() { 

  digitalWrite(solenoidPin, HIGH);
  delay(2000);
  digitalWrite(solenoidPin, LOW);
  delay(2000);
}

I wired my the Arduino Uno and solenoid with a breadboard, TIP102 Transistor, 1K resistor, and IN4001 Diode as follows:

In the picture below you can see the wiring as shown in the video:

I then plugged the Arduino Uno in to the computer, uploaded the code, and waited for it to successfully upload (at this point, nothing should happen with the solenoid). Then, I unplugged the Arduino from the computer, plugged it into the 12V Ledmo Power Supply, and voila! it worked!

Video of it working:

Working off the Arduino

Getting the solenoid off the Arduino Uno and working proved to be much more difficult than I expected. In the process I ended up ordering a large assortment of various components (90% of which I did not use) and frying an Arduino Nano :’) I talked to Richard Shan and Collin Kanofsky who were also struggling with their solenoids. They had explored the same options as I had and had moved to trying to make a mosfet board… of which they did not have any success. They did, however, find a mosfet board in the lab and had gotten their solenoids to work with it. Although we all knew that, ideally, we should make the board ourselves, we could not get them working and were running out of time before we needed to be done.

So, once Collin Kanofsky had finished with his final project, he bestowed me with thy’s magical ~mosfet board~

After I talked to Collin about how he used it, I started experimenting! He had soldered the mosfet board wires to that of a 9V battery and had it set up so that you just needed to connect the wires of the solenoid to the blue wire inserting box (the one across from the one with the 9V battery wires in it) and connect the power and ground pins at the end of the mosfet board to the power and ground pins on the microcontroller you were using. Then, all you needed to do is toggle on and off the power wire from the mosfet board to the microcontroller to activate the solenoid and have it open and close (opens when power connected, closes when power disconnected).

Thanks Collin for helping explain the mosfet board to me!

The mosfet board was vastly easier to use, setup, and get working than any of my other attempts!

Heres the board set up with one of my XIAO RP2040 breakout boards:

Electronic Systems

I2C LCD + Time of Flight Sensor

Programming with Arduino Uno

After researching how to get the ToF Sensor and LCD to communicate (starting the process by getting the ToF’s distance reading to display on the LCD screen) I came upon RoboJax’s Lesson 82: Using VL53L1X 400cm Laser Distance sensors with LCD site and Youtube video.

I watched this video and wired the ToF sensor, LCD, and Arduino as shown below:

I then created a new sketch in Arduino IDE with the code from RoboJax’s website:

/* 
*
* Lesson 82: Using VL53L1X 400cm Laser Distance Sensor LCD with Arduino  
Watch full video details of this code https://youtu.be/Lt-Zhm_XY38

Library used: http://librarymanager/All#SparkFun_VL53L1X

* This Arduin sketch display distnace using VL53L1X distance sensor on LCD1602 or LCD2004 with I2C module (4 wires)
* 
The distance is can be selected to ba in "mm", "inches", "feet", "cm" and "meter"


* Written by Ahmad Shamshiri on Jun 18, 2020 in Ajax, Ontario, Canada
* in Ajax, Ontario, Canada. www.robojax.com
*

This video is part of Arduino Step by Step Course which starts here: https://youtu.be/-6qSrDUA5a8



If you found this tutorial helpful, please support me so I can continue creating 
content like this. You can support me on Patreon http://robojax.com/L/?id=63

or make donation using PayPal http://robojax.com/L/?id=64

* This code is "AS IS" without warranty or liability. Free to be used as long as you keep this note intact.* 
* This code has been download from Robojax.com
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

VL53L1X distance reading from Sparkfun https://github.com/sparkfun/SparkFun_VL53L1X_Arduino_Library
*   Reading distance from the laser based VL53L1X
By: Nathan Seidle
Revised by: Andy England
SparkFun Electronics
Date: April 4th, 2018

*/
#include  
#include

// Set the LCD address to 0x27 for a 16 chars and 2 line display


const uint8_t I2C_ADDRESS =0x27;
const uint8_t LCD_CHAR= 16;
const uint8_t LCD_ROW= 2;
LiquidCrystal_I2C lcd(I2C_ADDRESS, LCD_CHAR,LCD_ROW);

#include "SparkFun_VL53L1X.h" //Click here to get the library: http://librarymanager/All#SparkFun_VL53L1X

//Optional interrupt and shutdown pins.
#define SHUTDOWN_PIN 2
#define INTERRUPT_PIN 3

SFEVL53L1X distanceSensor;
//Uncomment the following line to use the optional shutdown and interrupt pins.
//SFEVL53L1X distanceSensor(Wire, SHUTDOWN_PIN, INTERRUPT_PIN);

int distance=0;
void setup()
{
    Wire.begin();
    lcd.begin();

    // Turn on the blacklight and print a message.
    lcd.backlight();


if (distanceSensor.begin() != 0) //Begin returns 0 on a good init
{
    lcd.print("Sensor failed");
    lcd.setCursor(0,1);
    lcd.print("check wiring!");      
    while (1)
    ;
}

//distanceSensor.setDistanceModeShort();
distanceSensor.setDistanceModeLong();
    lcd.print("Robojax VL53L1X");
    lcd.setCursor(0,1);
    lcd.print("Mode: Medium"); 
    //lcd.print("Mode: Long");          
    delay(2000);       
    clearCharacters(LCD_ROW-1,0, LCD_CHAR-1);
    lcd.setCursor(0,1);
    lcd.print("Distance: ");

}//setup() end



void loop()
{
getDistance();
    printDistance('m');

// if distance is greator thatn 185mm do something
if(distance >185)
{
    // somethig here
}
delay(300);
}




/*
* getDistance()
* displays gets the distance for VL53L1X laser sensor
* updates the "distance" variable with distance in mm
* 
*/
int getDistance()
{
distanceSensor.startRanging(); //Write configuration bytes to initiate measurement

while (!distanceSensor.checkForDataReady())
{
    delay(1);
}
distance = distanceSensor.getDistance(); //Get the result of the measurement from the sensor
distanceSensor.clearInterrupt();

distanceSensor.stopRanging();

}//getDistance()  end


/*
* printDistance(char unit)
* displays value and title on LCD1602
* How to use:
* printDistance('m');

*/
void printDistance(char unit)
{
// Robojax.com LCD1602 for VL53L1X d
float distanceInches = distance * 0.0393701;
float distanceFeet = distanceInches / 12.0;
float distanceMeter = distance/1000.00;
float distanceCm= distance/10.00;


clearCharacters(1,9, LCD_CHAR-1 );
lcd.setCursor (9,1); //
if(unit =='i')
{
    lcd.print(distanceInches);    
    lcd.print("in");

}
if(unit =='m')
{
    lcd.print(distance);    
    lcd.print("mm");

}
if(unit =='f')
{
    lcd.print(distanceFeet);    
    lcd.print("ft");
}
if(unit =='c')
{
    lcd.print(distanceCm);    
    lcd.print("cm");
}  
if(unit =='a')
{
    lcd.print(distanceMeter);    
    lcd.print("m");
}         
// Robojax.com LCD1602 for LM35 Demo
}

/*
clearCharacters(uint8_t row,uint8_t start, uint8_t stop)
* @brief clears a line of display (erases all characters)
* @param none
* @return does not return anything
* Written by Ahmad Shamshiri
* www.Robojax.com code May 28, 2020 at 16:21 in Ajax, Ontario, Canada
*/
void clearCharacters(uint8_t row,uint8_t start, uint8_t stop )
{
    for (int i=start; i<=stop; i++)
    {
    lcd.setCursor (i,row); //  
    lcd.write(254);
    }

}//clearCharacters

I needed to download the “SparkFun_VL53L1X.h” library in the libraries manager (link of the library is: http://librarymanager/All#SparkFun_VL53L1X).

There were some errors with the code with its libraries and such so I tried including libraries I had used previously with the LCD and ToF sensor; the code ended up looking as follows after I tinkered with it:

/* 
*
* Lesson 82: Using VL53L1X 400cm Laser Distance Sensor LCD with Arduino  
Watch full video details of this code https://youtu.be/Lt-Zhm_XY38

Library used: http://librarymanager/All#SparkFun_VL53L1X

* This Arduin sketch display distnace using VL53L1X distance sensor on LCD1602 or LCD2004 with I2C module (4 wires)
* 
The distance is can be selected to ba in "mm", "inches", "feet", "cm" and "meter"


* Written by Ahmad Shamshiri on Jun 18, 2020 in Ajax, Ontario, Canada
* in Ajax, Ontario, Canada. www.robojax.com
*

This video is part of Arduino Step by Step Course which starts here: https://youtu.be/-6qSrDUA5a8



If you found this tutorial helpful, please support me so I can continue creating 
content like this. You can support me on Patreon http://robojax.com/L/?id=63

or make donation using PayPal http://robojax.com/L/?id=64

* This code is "AS IS" without warranty or liability. Free to be used as long as you keep this note intact.* 
* This code has been download from Robojax.com
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

VL53L1X distance reading from Sparkfun https://github.com/sparkfun/SparkFun_VL53L1X_Arduino_Library
*   Reading distance from the laser based VL53L1X
By: Nathan Seidle
Revised by: Andy England
SparkFun Electronics
Date: April 4th, 2018

*/
#include <Wire.h> 
#include "VL53L1X.h"
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>

// Set the LCD address to 0x27 for a 16 chars and 2 line display


const uint8_t I2C_ADDRESS =0x27;
const uint8_t LCD_CHAR= 16;
const uint8_t LCD_ROW= 2;
LiquidCrystal_I2C lcd(I2C_ADDRESS, LCD_CHAR,LCD_ROW);

#include "SparkFun_VL53L1X.h" //Click here to get the library: http://librarymanager/All#SparkFun_VL53L1X

//Optional interrupt and shutdown pins.
#define SHUTDOWN_PIN 2
#define INTERRUPT_PIN 3

SFEVL53L1X distanceSensor;
//Uncomment the following line to use the optional shutdown and interrupt pins.
//SFEVL53L1X distanceSensor(Wire, SHUTDOWN_PIN, INTERRUPT_PIN);

int distance=0;
void setup()
{
    Wire.begin();
    lcd.begin();

    // Turn on the blacklight and print a message.
    lcd.backlight();


if (distanceSensor.begin() != 0) //Begin returns 0 on a good init
{
    lcd.print("Sensor failed");
    lcd.setCursor(0,1);
    lcd.print("check wiring!");      
    while (1)
    ;
}

//distanceSensor.setDistanceModeShort();
distanceSensor.setDistanceModeLong();
    lcd.print("Robojax VL53L1X");
    lcd.setCursor(0,1);
    lcd.print("Mode: Medium"); 
    //lcd.print("Mode: Long");          
    delay(2000);       
    clearCharacters(LCD_ROW-1,0, LCD_CHAR-1);
    lcd.setCursor(0,1);
    lcd.print("Distance: ");

}//setup() end



void loop()
{
getDistance();
    printDistance('m');

// if distance is greator thatn 185mm do something
if(distance >185)
{
    // somethig here
}
delay(300);
}




/*
* getDistance()
* displays gets the distance for VL53L1X laser sensor
* updates the "distance" variable with distance in mm
* 
*/
int getDistance()
{
distanceSensor.startRanging(); //Write configuration bytes to initiate measurement

while (!distanceSensor.checkForDataReady())
{
    delay(1);
}
distance = distanceSensor.getDistance(); //Get the result of the measurement from the sensor
distanceSensor.clearInterrupt();

distanceSensor.stopRanging();

}//getDistance()  end


/*
* printDistance(char unit)
* displays value and title on LCD1602
* How to use:
* printDistance('m');

*/
void printDistance(char unit)
{
// Robojax.com LCD1602 for VL53L1X d
float distanceInches = distance * 0.0393701;
float distanceFeet = distanceInches / 12.0;
float distanceMeter = distance/1000.00;
float distanceCm= distance/10.00;


clearCharacters(1,9, LCD_CHAR-1 );
lcd.setCursor (9,1); //
if(unit =='i')
{
    lcd.print(distanceInches);    
    lcd.print("in");

}
if(unit =='m')
{
    lcd.print(distance);    
    lcd.print("mm");

}
if(unit =='f')
{
    lcd.print(distanceFeet);    
    lcd.print("ft");
}
if(unit =='c')
{
    lcd.print(distanceCm);    
    lcd.print("cm");
}  
if(unit =='a')
{
    lcd.print(distanceMeter);    
    lcd.print("m");
}         
// Robojax.com LCD1602 for LM35 Demo
}

/*
clearCharacters(uint8_t row,uint8_t start, uint8_t stop)
* @brief clears a line of display (erases all characters)
* @param none
* @return does not return anything
* Written by Ahmad Shamshiri
* www.Robojax.com code May 28, 2020 at 16:21 in Ajax, Ontario, Canada
*/
void clearCharacters(uint8_t row,uint8_t start, uint8_t stop )
{
    for (int i=start; i<=stop; i++)
    {
    lcd.setCursor (i,row); //  
    lcd.write(254);
    }

}//clearCharacters

When trying to upload this new code, I got the error “Compilation error: ‘LiquidCrystal_I2C’ does not name a type.” I was confused what this meant so I went to ChatGPT for help. I gave ChatGPT the code I was using and then asked it “why am I getting this error: Compilation error: ‘LiquidCrystal_I2C’ does not name a type” to which ChatGPT replied as follows:

The error `'LiquidCrystal_I2C' does not name a type` usually indicates that the library needed for `LiquidCrystal_I2C` is either not included correctly or is missing. The `LiquidCrystal_I2C` library is used for interfacing with I2C LCDs.

To fix this issue, ensure that you have the correct `LiquidCrystal_I2C` library installed. Here are the steps to resolve this:

1. **Install the LiquidCrystal_I2C Library:**

- Open the Arduino IDE.
- Go to `Sketch` > `Include Library` > `Manage Libraries`.
- In the Library Manager, type `LiquidCrystal_I2C` in the search box.
- Install the library by Marco Schwartz or any other compatible `LiquidCrystal_I2C` library.

2. **Include the Correct Library in Your Code:**

Ensure that you have the correct include statement at the top of your code. If you installed the library by Marco Schwartz, the include statement should look like this:

```cpp
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
```

3. **Code Adjustments:**

Ensure your code correctly initializes and uses the `LiquidCrystal_I2C` object. Here's a slightly modified version of your code with the correct library includes:

```cpp
/*
*
* Lesson 82: Using VL53L1X 400cm Laser Distance Sensor LCD with Arduino
* Watch full video details of this code https://youtu.be/Lt-Zhm_XY38

Library used: http://librarymanager/All#SparkFun_VL53L1X

* This Arduino sketch displays distance using VL53L1X distance sensor on LCD1602 or LCD2004 with I2C module (4 wires)
* 
The distance can be selected to be in "mm", "inches", "feet", "cm" and "meter"

* Written by Ahmad Shamshiri on Jun 18, 2020 in Ajax, Ontario, Canada
* in Ajax, Ontario, Canada. www.robojax.com
*

This video is part of Arduino Step by Step Course which starts here: https://youtu.be/-6qSrDUA5a8

If you found this tutorial helpful, please support me so I can continue creating 
content like this. You can support me on Patreon http://robojax.com/L/?id=63

or make donation using PayPal http://robojax.com/L/?id=64

* This code is "AS IS" without warranty or liability. Free to be used as long as you keep this note intact.* 
* This code has been download from Robojax.com
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

VL53L1X distance reading from Sparkfun https://github.com/sparkfun/SparkFun_VL53L1X_Arduino_Library
    *   Reading distance from the laser based VL53L1X
    By: Nathan Seidle
    Revised by: Andy England
    SparkFun Electronics
    Date: April 4th, 2018
*/

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include "SparkFun_VL53L1X.h" //Click here to get the library: http://librarymanager/All#SparkFun_VL53L1X

// Set the LCD address to 0x27 for a 16 chars and 2 line display
const uint8_t I2C_ADDRESS = 0x27;
const uint8_t LCD_CHAR = 16;
const uint8_t LCD_ROW = 2;
LiquidCrystal_I2C lcd(I2C_ADDRESS, LCD_CHAR, LCD_ROW);

//Optional interrupt and shutdown pins.
#define SHUTDOWN_PIN 2
#define INTERRUPT_PIN 3

SFEVL53L1X distanceSensor;
//Uncomment the following line to use the optional shutdown and interrupt pins.
//SFEVL53L1X distanceSensor(Wire, SHUTDOWN_PIN, INTERRUPT_PIN);

int distance = 0;

void setup()
{
    Wire.begin();
    lcd.begin(LCD_CHAR, LCD_ROW);

    // Turn on the backlight and print a message.
    lcd.backlight();

    if (distanceSensor.begin() != 0) //Begin returns 0 on a good init
    {
        lcd.print("Sensor failed");
        lcd.setCursor(0, 1);
        lcd.print("check wiring!");      
        while (1);
    }

    //distanceSensor.setDistanceModeShort();
    distanceSensor.setDistanceModeLong();
    lcd.print("Robojax VL53L1X");
    lcd.setCursor(0, 1);
    lcd.print("Mode: Medium"); 
    //lcd.print("Mode: Long");          
    delay(2000);       
    clearCharacters(LCD_ROW-1, 0, LCD_CHAR-1);
    lcd.setCursor(0, 1);
    lcd.print("Distance: ");         
}

void loop()
{
    getDistance();
    printDistance('m');

    // if distance is greater than 185mm do something
    if (distance > 185)
    {
        // something here
    }
    delay(300);
}

/*
    * getDistance()
    * gets the distance from VL53L1X laser sensor
    * updates the "distance" variable with distance in mm
    * 
    */
int getDistance()
{
    distanceSensor.startRanging(); // Write configuration bytes to initiate measurement

    while (!distanceSensor.checkForDataReady())
    {
        delay(1);
    }
    distance = distanceSensor.getDistance(); // Get the result of the measurement from the sensor
    distanceSensor.clearInterrupt();
    distanceSensor.stopRanging();
}

/*
    * printDistance(char unit)
    * displays value and title on LCD1602
    * How to use:
    * printDistance('m');
    */
void printDistance(char unit)
{
    // Robojax.com LCD1602 for VL53L1X d
    float distanceInches = distance * 0.0393701;
    float distanceFeet = distanceInches / 12.0;
    float distanceMeter = distance / 1000.00;
    float distanceCm = distance / 10.00;

    clearCharacters(1, 9, LCD_CHAR-1);
    lcd.setCursor(9, 1);
    if (unit == 'i')
    {
        lcd.print(distanceInches);    
        lcd.print("in");
    }
    if (unit == 'm')
    {
        lcd.print(distance);    
        lcd.print("mm");
    }
    if (unit == 'f')
    {
        lcd.print(distanceFeet);    
        lcd.print("ft");
    }
    if (unit == 'c')
    {
        lcd.print(distanceCm);    
        lcd.print("cm");
    }  
    if (unit == 'a')
    {
        lcd.print(distanceMeter);    
        lcd.print("m");
    }
}

/*
    clearCharacters(uint8_t row, uint8_t start, uint8_t stop)
    * @brief clears a line of display (erases all characters)
    * @param none
    * @return does not return anything
    * Written by Ahmad Shamshiri
    * www.Robojax.com code May 28, 2020 at 16:21 in Ajax, Ontario, Canada
    */
void clearCharacters(uint8_t row, uint8_t start, uint8_t stop)
{
    for (int i = start; i <= stop; i++)
    {
        lcd.setCursor(i, row);  
        lcd.write(' ');  // Use ' ' (space) to clear characters
    }
}
```

In this code:
- The correct `LiquidCrystal_I2C` library is included.
- `lcd.begin(LCD_CHAR, LCD_ROW);` is used to initialize the LCD with the specified dimensions.

Make sure you have the `LiquidCrystal_I2C` library installed and included correctly in your Arduino sketch to avoid the compilation error.

I tried the Code Adjustment it suggested and it worked!

Programming with XIAO RP2040

I actually got the LCD and Time of Flight sensor working with the XIAO RP2040 a lot easier than I expected.

Here’s how I wired it:

ChatGPT Code Editing Convo

For the code, I went to ChatGPT again. I was in the same conversation as I was earlier for editing the code. The following is the conversation I had with ChatGPT:

Color Code Key: ChatGPT and Me, Alana Duffy

Me, Alana Duffy

do you think I can do this code on a seeed studio XIAO RP2040

ChatGPT

The Seeed Studio XIAO RP2040 is a powerful and compact board based on the Raspberry Pi RP2040 microcontroller. It has a lot of features and capabilities, including I2C support, which makes it suitable for interfacing with the VL53L1X sensor, the LCD display, and the DS3231 RTC module.

Here are the steps and considerations for using the XIAO RP2040 with the provided code:

I2C Support: The XIAO RP2040 has I2C support, which is necessary for communicating with the VL53L1X sensor, the LCD display, and the DS3231 RTC module.

Library Compatibility: Ensure the libraries used (SparkFun VL53L1X, LiquidCrystal_I2C, and RTClib) are compatible with the RP2040. Most popular libraries have been updated to support the RP2040, but it is always good to check.

Pin Configuration: The default I2C pins on the XIAO RP2040 are SDA on pin 4 and SCL on pin 5. You need to connect the VL53L1X sensor, LCD, and RTC module to these pins.

Here is how you can adapt the code for the XIAO RP2040:

Adapted Code for Seeed Studio XIAO RP2040

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include "SparkFun_VL53L1X.h" // Click here to get the library: http://librarymanager/All#SparkFun_VL53L1X
#include <RTClib.h>  // Include RTClib library for DS3231

// Set the LCD address to 0x27 for a 16 chars and 2 line display
const uint8_t I2C_ADDRESS = 0x27;
const uint8_t LCD_CHAR = 16;
const uint8_t LCD_ROW = 2;
LiquidCrystal_I2C lcd(I2C_ADDRESS, LCD_CHAR, LCD_ROW);

// Optional interrupt and shutdown pins
#define SHUTDOWN_PIN 2
#define INTERRUPT_PIN 3

SFEVL53L1X distanceSensor;
RTC_DS3231 rtc;  // Initialize RTC

int distance = 0;
int counter = 0;
bool displayUpdate = false;
DateTime lastDate;  // Variable to store the last date

void setup()
{
  Wire.begin();
  lcd.begin(LCD_CHAR, LCD_ROW);

  // Turn on the backlight and print a message
  lcd.backlight();

  if (distanceSensor.begin() != 0) // Begin returns 0 on a good init
  {
    lcd.print("Sensor failed");
    lcd.setCursor(0, 1);
    lcd.print("check wiring!");      
    while (1);
  }

  // distanceSensor.setDistanceModeShort();
  distanceSensor.setDistanceModeLong();
  lcd.print("Good Morning :)");
  lcd.setCursor(0, 1);

  delay(2000);       
  clearCharacters(LCD_ROW - 1, 0, LCD_CHAR - 1);

  if (!rtc.begin()) {
    lcd.print("Couldn't find RTC");
    while (1);
  }

  if (rtc.lostPower()) {
    lcd.print("RTC lost power");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));  // Set RTC to the date & time this sketch was compiled
  }

  lastDate = rtc.now();  // Initialize the last date
}

void loop()
{
  DateTime now = rtc.now();  // Get current date and time

  // Check if the date has changed
  if (now.day() != lastDate.day()) {
    counter = 0;  // Reset the counter
    lastDate = now;  // Update the last date
  }

  getDistance();

  float distanceInches = distance * 0.0393701;

  // If distance is greater than 3 inches, update the counter and display the corresponding word
  if (distanceInches > 3.0 && !displayUpdate)
  {
    counter++;
    lcd.clear();
    lcd.setCursor(0, 0);
    displayWord(counter);
    displayUpdate = true;
  }
  else if (distanceInches <= 3.0)
  {
    displayUpdate = false;
  }

  delay(300);
}

/*
 * getDistance()
 * gets the distance from VL53L1X laser sensor
 * updates the "distance" variable with distance in mm
 * 
 */
int getDistance()
{
  distanceSensor.startRanging(); // Write configuration bytes to initiate measurement

  while (!distanceSensor.checkForDataReady())
  {
    delay(1);
  }
  distance = distanceSensor.getDistance(); // Get the result of the measurement from the sensor
  distanceSensor.clearInterrupt();
  distanceSensor.stopRanging();
}

/*
  clearCharacters(uint8_t row, uint8_t start, uint8_t stop)
 * @brief clears a line of display (erases all characters)
 * @param none
 * @return does not return anything
 */
void clearCharacters(uint8_t row, uint8_t start, uint8_t stop)
{
  for (int i = start; i <= stop; i++)
  {
    lcd.setCursor(i, row);  
    lcd.write(' ');  // Use ' ' (space) to clear characters
  }
}

/*
 * displayWord(int count)
 * displays the word corresponding to the count
 * 
 */
void displayWord(int count)
{
  lcd.print("Times Opened: ");
  lcd.print(count);
}

Steps for Connecting Components
Connect the I2C pins:

SDA of VL53L1X, LCD, and RTC to SDA pin (pin 4 on XIAO RP2040)
SCL of VL53L1X, LCD, and RTC to SCL pin (pin 5 on XIAO RP2040)
Power and Ground:

Connect VCC of all I2C devices to 3.3V or 5V (depending on the module specifications)
Connect GND of all I2C devices to GND
Additional Notes
Ensure you have installed all necessary libraries (SparkFun VL53L1X, LiquidCrystal_I2C, and RTClib) in your Arduino IDE.
The XIAO RP2040 operates at 3.3V logic level. Ensure your I2C devices are compatible with 3.3V or use level shifters if required.
Test the connections and code thoroughly to ensure proper functionality.
By following these steps and making sure all connections and libraries are properly set up, you should be able to run the provided code on your Seeed Studio XIAO RP2040.

Me, Alana Duffy

can you remove the stuff for the DS3231 RTC module from the code

ChatGPT

Certainly! If you want to remove the code related to the DS3231 RTC module, you can simplify the code as follows:

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include "SparkFun_VL53L1X.h" //Click here to get the library: http://librarymanager/All#SparkFun_VL53L1X

// Set the LCD address to 0x27 for a 16 chars and 2 line display
const uint8_t I2C_ADDRESS = 0x27;
const uint8_t LCD_CHAR = 16;
const uint8_t LCD_ROW = 2;
LiquidCrystal_I2C lcd(I2C_ADDRESS, LCD_CHAR, LCD_ROW);

// Optional interrupt and shutdown pins
#define SHUTDOWN_PIN 2
#define INTERRUPT_PIN 3

SFEVL53L1X distanceSensor;

int distance = 0;
int counter = 0;
bool displayUpdate = false;

void setup()
{
  Wire.begin();
  lcd.begin(LCD_CHAR, LCD_ROW);

  // Turn on the backlight and print a message
  lcd.backlight();

  if (distanceSensor.begin() != 0) // Begin returns 0 on a good init
  {
    lcd.print("Sensor failed");
    lcd.setCursor(0, 1);
    lcd.print("check wiring!");      
    while (1);
  }

  // distanceSensor.setDistanceModeShort();
  distanceSensor.setDistanceModeLong();
  lcd.print("Good Morning :)");
  lcd.setCursor(0, 1);

  delay(2000);       
  clearCharacters(LCD_ROW - 1, 0, LCD_CHAR - 1);
}

void loop()
{
  getDistance();

  float distanceInches = distance * 0.0393701;

  // If distance is greater than 3 inches, update the counter and display the corresponding word
  if (distanceInches > 3.0 && !displayUpdate)
  {
    counter++;
    lcd.clear();
    lcd.setCursor(0, 0);
    displayWord(counter);
    displayUpdate = true;
  }
  else if (distanceInches <= 3.0)
  {
    displayUpdate = false;
  }

  delay(300);
}

/*
 * getDistance()
 * gets the distance from VL53L1X laser sensor
 * updates the "distance" variable with distance in mm
 * 
 */
int getDistance()
{
  distanceSensor.startRanging(); // Write configuration bytes to initiate measurement

  while (!distanceSensor.checkForDataReady())
  {
    delay(1);
  }
  distance = distanceSensor.getDistance(); // Get the result of the measurement from the sensor
  distanceSensor.clearInterrupt();
  distanceSensor.stopRanging();
}

/*
  clearCharacters(uint8_t row, uint8_t start, uint8_t stop)
 * @brief clears a line of display (erases all characters)
 * @param none
 * @return does not return anything
 */
void clearCharacters(uint8_t row, uint8_t start, uint8_t stop)
{
  for (int i = start; i <= stop; i++)
  {
    lcd.setCursor(i, row);  
    lcd.write(' ');  // Use ' ' (space) to clear characters
  }
}

/*
 * displayWord(int count)
 * displays the word corresponding to the count
 * 
 */
void displayWord(int count)
{
  lcd.print("Times Opened: ");
  lcd.print(count);
}

This code removes all the parts related to the RTC module, including initialization, checking for date changes, and resetting the counter. Now the code focuses solely on interfacing with the VL53L1X sensor and updating the LCD display based on the distance measurements.

Me, Alana Duffy

ok so this is currently my code: #include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include "SparkFun_VL53L1X.h" // Click here to get the library: http://librarymanager/All#SparkFun_VL53L1X


// Set the LCD address to 0x27 for a 16 chars and 2 line display
const uint8_t I2C_ADDRESS = 0x27;
const uint8_t LCD_CHAR = 16;
const uint8_t LCD_ROW = 2;
LiquidCrystal_I2C lcd(I2C_ADDRESS, LCD_CHAR, LCD_ROW);

// Optional interrupt and shutdown pins
#define SHUTDOWN_PIN 2
#define INTERRUPT_PIN 3

SFEVL53L1X distanceSensor;


int distance = 0;
int counter = 0;
bool displayUpdate = false;


void setup()
{
  Wire.begin();
  lcd.begin(LCD_CHAR, LCD_ROW);

  // Turn on the backlight and print a message
  lcd.backlight();

  if (distanceSensor.begin() != 0) // Begin returns 0 on a good init
  {
    lcd.print("Sensor failed");
    lcd.setCursor(0, 1);
    lcd.print("check wiring!");      
    while (1);
  }

{
  // distanceSensor.setDistanceModeShort();
  distanceSensor.setDistanceModeLong();
  lcd.print("Good Morning :)");
  lcd.setCursor(0, 1);

  delay(2000);       
  clearCharacters(LCD_ROW - 1, 0, LCD_CHAR - 1);


}

void loop()
{
  DateTime now = rtc.now();  // Get current date and time

  // Check if the date has changed
  if (now.day() != lastDate.day()) {
    counter = 0;  // Reset the counter
    lastDate = now;  // Update the last date
  }

  getDistance();

  float distanceInches = distance * 0.0393701;

  // If distance is greater than 3 inches, update the counter and display the corresponding word
  if (distanceInches > 3.0 && !displayUpdate)
  {
    counter++;
    lcd.clear();
    lcd.setCursor(0, 0);
    displayWord(counter);
    displayUpdate = true;
  }
  else if (distanceInches <= 3.0)
  {
    displayUpdate = false;
  }

  delay(300);
}

/*
 * getDistance()
 * gets the distance from VL53L1X laser sensor
 * updates the "distance" variable with distance in mm
 * 
 */
int getDistance()
{
  distanceSensor.startRanging(); // Write configuration bytes to initiate measurement

  while (!distanceSensor.checkForDataReady())
  {
    delay(1);
  }
{  distance = distanceSensor.getDistance(); // Get the result of the measurement from the sensor
  distanceSensor.clearInterrupt();
  distanceSensor.stopRanging();
}

/*
  clearCharacters(uint8_t row, uint8_t start, uint8_t stop)
 * @brief clears a line of display (erases all characters)
 * @param none
 * @return does not return anything
 */
void clearCharacters(uint8_t row, uint8_t start, uint8_t stop)
{
  for (int i = start; i <= stop; i++)
  {
    lcd.setCursor(i, row);  
    lcd.write(' ');  // Use ' ' (space) to clear characters
  }
}

/*
 * displayWord(int count)
 * displays the word corresponding to the count
 * 
 */
void displayWord(int count)
{
  lcd.print("Times Opened: ");
  lcd.print(count);
}

ChatGPT

It seems like there's a mix-up in your code. You still have references to the DS3231 RTC module (DateTime, now, lastDate) in your loop() function, but you removed the RTC-related code from the setup.

Here's the corrected code without the RTC module:

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include "SparkFun_VL53L1X.h" // Click here to get the library: http://librarymanager/All#SparkFun_VL53L1X

// Set the LCD address to 0x27 for a 16 chars and 2 line display
const uint8_t I2C_ADDRESS = 0x27;
const uint8_t LCD_CHAR = 16;
const uint8_t LCD_ROW = 2;
LiquidCrystal_I2C lcd(I2C_ADDRESS, LCD_CHAR, LCD_ROW);

// Optional interrupt and shutdown pins
#define SHUTDOWN_PIN 2
#define INTERRUPT_PIN 3

SFEVL53L1X distanceSensor;

int distance = 0;
int counter = 0;
bool displayUpdate = false;

void setup()
{
  Wire.begin();
  lcd.begin(LCD_CHAR, LCD_ROW);

  // Turn on the backlight and print a message
  lcd.backlight();

  if (distanceSensor.begin() != 0) // Begin returns 0 on a good init
  {
    lcd.print("Sensor failed");
    lcd.setCursor(0, 1);
    lcd.print("check wiring!");      
    while (1);
  }

  distanceSensor.setDistanceModeLong();
  lcd.print("Good Morning :)");
  lcd.setCursor(0, 1);
  delay(2000);       
  clearCharacters(LCD_ROW - 1, 0, LCD_CHAR - 1);
}

void loop()
{
  getDistance();

  float distanceInches = distance * 0.0393701;

  // If distance is greater than 3 inches, update the counter and display the corresponding word
  if (distanceInches > 3.0 && !displayUpdate)
  {
    counter++;
    lcd.clear();
    lcd.setCursor(0, 0);
    displayWord(counter);
    displayUpdate = true;
  }
  else if (distanceInches <= 3.0)
  {
    displayUpdate = false;
  }

  delay(300);
}

/*
 * getDistance()
 * gets the distance from VL53L1X laser sensor
 * updates the "distance" variable with distance in mm
 * 
 */
void getDistance()
{
  distanceSensor.startRanging(); // Write configuration bytes to initiate measurement

  while (!distanceSensor.checkForDataReady())
  {
    delay(1);
  }

  distance = distanceSensor.getDistance(); // Get the result of the measurement from the sensor
  distanceSensor.clearInterrupt();
  distanceSensor.stopRanging();
}

/*
  clearCharacters(uint8_t row, uint8_t start, uint8_t stop)
 * @brief clears a line of display (erases all characters)
 * @param none
 * @return does not return anything
 */
void clearCharacters(uint8_t row, uint8_t start, uint8_t stop)
{
  for (int i = start; i <= stop; i++)
  {
    lcd.setCursor(i, row);  
    lcd.write(' ');  // Use ' ' (space) to clear characters
  }
}

/*
 * displayWord(int count)
 * displays the word corresponding to the count
 * 
 */
void displayWord(int count)
{
  lcd.print("Times Opened: ");
  lcd.print(count);
}

Now the code doesn't have any references to the RTC module and should work properly with just the VL53L1X sensor and the LCD display.

Final Code

basically to get this to work i went back to my inputs ToF documentation and then I… 

  1. unplugged it 

  2. plugged it back in while holding down the bootloader button on the RP2040

  3. had the computer show 

“RPI-RP2 (D:) 

Select to choose what happens with removable drives” 

  1. went to Tools>Port and selected “UF2 Board”

  2. then I uploaded it again AND IT WORKED <3

// Authored by Alana Duffy
// Licensed under MIT
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include "SparkFun_VL53L1X.h" // Click here to get the library: http://librarymanager/All#SparkFun_VL53L1X

// Set the LCD address to 0x27 for a 16 chars and 2 line display
const uint8_t I2C_ADDRESS = 0x27;
const uint8_t LCD_CHAR = 16;
const uint8_t LCD_ROW = 2;
LiquidCrystal_I2C lcd(I2C_ADDRESS, LCD_CHAR, LCD_ROW);

// Optional interrupt and shutdown pins
#define SHUTDOWN_PIN 2
#define INTERRUPT_PIN 3

SFEVL53L1X distanceSensor;

int distance = 0;
int counter = 0;
bool displayUpdate = false;

void setup()
{
  Wire.begin();
  lcd.begin(LCD_CHAR, LCD_ROW);

  // Turn on the backlight and print a message
  lcd.backlight();

  if (distanceSensor.begin() != 0) // Begin returns 0 on a good init
  {
    lcd.print("Sensor failed");
    lcd.setCursor(0, 1);
    lcd.print("check wiring!");      
    while (1);
  }

  distanceSensor.setDistanceModeLong();
  lcd.print("Good Morning :)");
  lcd.setCursor(0, 1);
  delay(2000);       
  clearCharacters(LCD_ROW - 1, 0, LCD_CHAR - 1);
}

void loop()
{
  getDistance();

  float distanceInches = distance * 0.0393701;

  // If distance is greater than 3 inches, update the counter and display the corresponding word
  if (distanceInches > 3.0 && !displayUpdate)
  {
    counter++;
    lcd.clear();
    lcd.setCursor(0, 0);
    displayWord(counter);
    displayUpdate = true;
  }
  else if (distanceInches <= 3.0)
  {
    displayUpdate = false;
  }

  delay(300);
}

/*
 * getDistance()
 * gets the distance from VL53L1X laser sensor
 * updates the "distance" variable with distance in mm
 * 
 */
void getDistance()
{
  distanceSensor.startRanging(); // Write configuration bytes to initiate measurement

  while (!distanceSensor.checkForDataReady())
  {
    delay(1);
  }

  distance = distanceSensor.getDistance(); // Get the result of the measurement from the sensor
  distanceSensor.clearInterrupt();
  distanceSensor.stopRanging();
}

/*
  clearCharacters(uint8_t row, uint8_t start, uint8_t stop)
 * @brief clears a line of display (erases all characters)
 * @param none
 * @return does not return anything
 */
void clearCharacters(uint8_t row, uint8_t start, uint8_t stop)
{
  for (int i = start; i <= stop; i++)
  {
    lcd.setCursor(i, row);  
    lcd.write(' ');  // Use ' ' (space) to clear characters
  }
}

/*
 * displayWord(int count)
 * displays the word corresponding to the count
 * 
 */
void displayWord(int count)
{
  lcd.print("Times Opened: ");
  lcd.print(count);
}

Here’s it working:

PCB Board

Schematic:

PCB:

Milled board:

Component Quantity
Seeed Studio XIAO RP2040 1
1x4 Male Header 2
Milled PCB 1
kapton tape 1

I had to cut some of the headers pins that touch the board to be shorter so that way there were no shorts or touching traces (I couldn’t find the shorter headers -_-)

Also, it’s important to put kapton tape on the bottom of the RP2040 so that it does not overheat!

Final board:

Board Wired:

Board Working:

PCB Board Case

I designed the PCB Board Case below in Fusion360:

    ToF and LCD PCB Case     by Alana Duffy

I then downloaded the file, brought it into Prusa Slicer, re-arranged and sliced the file, saved it as a .gcode, and then uploaded it to one of my lab’s Prusa Minis.

(The one on the right is the PCB case for the Time of Flight sensor and LCD board and the one on the left is the PCB case for the keypad and solenoid PCB)

I2C LCD Case

Week 12 Documentation - Moulding and Casting

I made the following Mould model in Fusion360:

    LCD Mould     by Alana Duffy

I sliced my stl file in PrusaSlicer to create my gcode and then sent it to the Prusa 3D printer.

The mould 3D printed:

Casting

The mould material I used was 15 Slow Mold Star Series which would create a soft cast. It is necessary that I did a soft cast because I made a hard mold.

Parts A and B need to be mixed together in a 1:1 ratio. Before I put them together, though, I took part A and part B and put them in seperate cups (while wearing gloves!). I stirred them for a few minutes each with their own popsicle sticks. I then poured them together in a cup and mixed them together with a third, clean popsicle stick.

I then slowly poured the mix into the mold that was placed on a sheet of cardboard to protect the table. Once it was poured in, I carefully hit the mold on the table a couple of times to help remove bubbles.

I then took a popsicle stick and carefully removed the cast from the mold.

Here’s it on the IC2 LCD; it worked perfectly!

I wanted to see if I could put screws through the silicon so I tested it on this one. It worked well! I want to be able to protect the LCD and also secure it in my final project so this working was a big relief for me.

Installation

To install the Time of Flight sensor, I drilled 2 mm holes for M2 screws in the Time of Flight pocket in the milled wood. I then inserted the M2 screws and secured them with nuts.

Here you can see that it’s not visible from the front/outside as I designed it to be:

To install the LCD, I actually just had to pop it into the pocket I milled. It was tight enough of a fit that I did not have to use screws or anything else to help hold it in place.

Keypad Matrix + Solenoid Lock

Programming with XIAO RP2040

As I had both the keypad and solenoid working with the XIAO RP2040, I skipped getting them to work together first with the Arduino Uno as I did with the LCD and time of flight sensor and just went straight in with the RP2040.

Here’s how I wired it:

ChatGPT Code Editing Convo

For the code, I went to ChatGPT again. The following is the conversation I had with ChatGPT:

Color Code Key: ChatGPT and Me, Alana Duffy

Me, Alana Duffy

hey so i have this code: // Use this example with the Adafruit Keypad products.
// You'll need to know the Product ID for your keypad.
// Here's a summary:
//   * PID3844 4x4 Matrix Keypad
//   * PID3845 3x4 Matrix Keypad
//   * PID1824 3x4 Phone-style Matrix Keypad
//   * PID1332 Membrane 1x4 Keypad
//   * PID419  Membrane 3x4 Matrix Keypad

#include "Adafruit_Keypad.h"

// define your specific keypad here via PID
#define KEYPAD_PID3845
// define your pins here



// can ignore ones that don't apply
#define R1    D2
#define R2    D3
#define R3    D4
#define R4    D5
#define C1    D8
#define C2    D9
#define C3    D10
#define C4    
// leave this import after the above configuration
#include "keypad_config.h"

//initialize an instance of class NewKeypad
Adafruit_Keypad customKeypad = Adafruit_Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);

void setup() {
Serial.begin(9600);
customKeypad.begin();
}

void loop() {
// put your main code here, to run repeatedly:
customKeypad.tick();

while(customKeypad.available()){
    keypadEvent e = customKeypad.read();
    Serial.print((char)e.bit.KEY);
    if(e.bit.EVENT == KEY_JUST_PRESSED) Serial.println(" pressed");
    else if(e.bit.EVENT == KEY_JUST_RELEASED) Serial.println(" released");
}

delay(1);
}

ChatGPT

To use this code with an Adafruit keypad, you need to complete the configuration specific to your keypad. The code you provided sets up the library and hardware for a 3x4 Matrix Keypad (PID3845). I'll guide you through the steps to make sure everything is correctly defined.

Include Necessary Libraries:
Make sure you have the Adafruit_Keypad library installed in your Arduino environment.

Define Keypad Constants and Pins:
Update the pin definitions and other constants according to the specific keypad you are using.

Define Keymap:
Create a keymap array that maps the keypad button layout.

Include Configuration:
Ensure keypad_config.h contains the correct configurations for your keypad.

Here’s a more complete version of your code with these points in mind:

Complete Code:

// Use this example with the Adafruit Keypad products.
// You'll need to know the Product ID for your keypad.
// Here's a summary:
//   * PID3844 4x4 Matrix Keypad
//   * PID3845 3x4 Matrix Keypad
//   * PID1824 3x4 Phone-style Matrix Keypad
//   * PID1332 Membrane 1x4 Keypad
//   * PID419  Membrane 3x4 Matrix Keypad

#include "Adafruit_Keypad.h"

// define your specific keypad here via PID
#define KEYPAD_PID3845  // 3x4 Matrix Keypad

// Define your pins here
#define R1    D2
#define R2    D3
#define R3    D4
#define R4    D5  // Not used in 3x4 keypad
#define C1    D8
#define C2    D9
#define C3    D10
#define C4    -1  // Not used in 3x4 keypad

// Define the keymap for a 3x4 keypad
const char keys[3][4] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins[4] = {R1, R2, R3, R4}; // Connect to the row pinouts of the keypad
byte colPins[4] = {C1, C2, C3, C4}; // Connect to the column pinouts of the keypad

// Initialize an instance of class Adafruit_Keypad
Adafruit_Keypad customKeypad = Adafruit_Keypad(makeKeymap(keys), rowPins, colPins, 4, 4);

void setup() {
  Serial.begin(9600);
  customKeypad.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
  customKeypad.tick();

  while (customKeypad.available()) {
    keypadEvent e = customKeypad.read();
    Serial.print((char)e.bit.KEY);
    if (e.bit.EVENT == KEY_JUST_PRESSED) Serial.println(" pressed");
    else if (e.bit.EVENT == KEY_JUST_RELEASED) Serial.println(" released");
  }

  delay(1);
}

Key Points:
Pin Definitions:
Ensure that the pins (R1, R2, R3, R4, C1, C2, C3, C4) are correctly defined based on your actual wiring.

Keymap Array:
The keys array should match the layout of your keypad. The provided keymap assumes a standard 3x4 layout. Adjust the array if your keypad has a different layout.

Column Pins:
For a 3x4 keypad, the fourth column pin (C4) is not used, so it's set to -1.

By following these steps and ensuring that the pin definitions and keymap match your keypad, this code should allow you to interact with your Adafruit keypad correctly.

Me, Alana Duffy

can you add a part to my original code so that if the keys 1234 are hit a solenoid lock activates?

ChatGPT

Sure! To add the functionality where pressing the keys 1234 activates a solenoid lock, we need to:

Define a pin for the solenoid lock.
Keep track of the sequence of keys pressed.
Check if the sequence matches 1234.
Activate the solenoid lock if the sequence is correct.
Here's the updated code with these changes:

Complete Code:

// Use this example with the Adafruit Keypad products.
// You'll need to know the Product ID for your keypad.
// Here's a summary:
//   * PID3844 4x4 Matrix Keypad
//   * PID3845 3x4 Matrix Keypad
//   * PID1824 3x4 Phone-style Matrix Keypad
//   * PID1332 Membrane 1x4 Keypad
//   * PID419  Membrane 3x4 Matrix Keypad

#include "Adafruit_Keypad.h"

// Define your specific keypad here via PID
#define KEYPAD_PID3845  // 3x4 Matrix Keypad

// Define your pins here
#define R1    D2
#define R2    D3
#define R3    D4
#define R4    D5  // Not used in 3x4 keypad
#define C1    D8
#define C2    D9
#define C3    D10
#define C4    -1  // Not used in 3x4 keypad

// Define the solenoid lock pin
#define SOLENOID_PIN D11

// Define the keymap for a 3x4 keypad
const char keys[4][4] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins[4] = {R1, R2, R3, R4}; // Connect to the row pinouts of the keypad
byte colPins[4] = {C1, C2, C3, C4}; // Connect to the column pinouts of the keypad

// Initialize an instance of class Adafruit_Keypad
Adafruit_Keypad customKeypad = Adafruit_Keypad(makeKeymap(keys), rowPins, colPins, 4, 4);

// Store the key sequence
String keySequence = "";

// Define the correct key sequence
const String correctSequence = "1234";

void setup() {
  Serial.begin(9600);
  customKeypad.begin();
  pinMode(SOLENOID_PIN, OUTPUT);
  digitalWrite(SOLENOID_PIN, LOW); // Ensure solenoid is initially off
}

void loop() {
  // Put your main code here, to run repeatedly:
  customKeypad.tick();

  while (customKeypad.available()) {
    keypadEvent e = customKeypad.read();
    char key = (char)e.bit.KEY;

    if (e.bit.EVENT == KEY_JUST_PRESSED) {
      Serial.print(key);
      Serial.println(" pressed");

      // Append the pressed key to the sequence
      keySequence += key;

      // Check if the sequence matches
      if (keySequence.length() >= 4) {
        if (keySequence.substring(keySequence.length() - 4) == correctSequence) {
          Serial.println("Correct sequence entered! Activating solenoid.");
          digitalWrite(SOLENOID_PIN, HIGH); // Activate solenoid lock
        }
      }

      // Clear the sequence if more than 4 keys have been pressed
      if (keySequence.length() > 4) {
        keySequence = keySequence.substring(1);
      }
    } else if (e.bit.EVENT == KEY_JUST_RELEASED) {
      Serial.print(key);
      Serial.println(" released");
    }
  }

  delay(1);
}

Key Points:
Solenoid Lock Pin Definition:
The solenoid lock is connected to D11. Adjust this if you connect it to a different pin.

Key Sequence Tracking:
The code appends each pressed key to keySequence. If the last four keys match 1234, it activates the solenoid lock.

Solenoid Activation:
The solenoid lock is activated by setting SOLENOID_PIN to HIGH.

Key Sequence Length Management:
The code ensures that only the last four keys are kept in keySequence to avoid overflow.

This setup will activate the solenoid lock when the keys 1234 are pressed in sequence. Adjust the pin definitions and keymap if needed based on your specific hardware configuration.

Me, Alana Duffy

so when the 3V3 pin on the XIAO RP2040 is connected to the power on the solenoid, it activates it. I want it so only when you enter 1234 on the keypad does the solenoid activate

ChatGPT

To ensure that the solenoid only activates when the correct sequence 1234 is entered on the keypad, we'll modify the code so that the solenoid pin (connected to a GPIO pin) will be set high only when the correct sequence is entered.

Since the XIAO RP2040 board works with 3.3V logic, and assuming the solenoid can be controlled by a GPIO pin driving a transistor or MOSFET, we will use one of the GPIO pins to control the solenoid.

Here is the revised code to achieve this:

Complete Code:

// Use this example with the Adafruit Keypad products.
// You'll need to know the Product ID for your keypad.
// Here's a summary:
//   * PID3844 4x4 Matrix Keypad
//   * PID3845 3x4 Matrix Keypad
//   * PID1824 3x4 Phone-style Matrix Keypad
//   * PID1332 Membrane 1x4 Keypad
//   * PID419  Membrane 3x4 Matrix Keypad

#include "Adafruit_Keypad.h"

// Define your specific keypad here via PID
#define KEYPAD_PID3845  // 3x4 Matrix Keypad

// Define your pins here
#define R1    D2
#define R2    D3
#define R3    D4
#define R4    D5  // Not used in 3x4 keypad
#define C1    D8
#define C2    D9
#define C3    D10
#define C4    -1  // Not used in 3x4 keypad

// Define the solenoid lock pin
#define SOLENOID_PIN D11

// Define the keymap for a 3x4 keypad
const char keys[4][3] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[4] = {R1, R2, R3, R4}; // Connect to the row pinouts of the keypad
byte colPins[3] = {C1, C2, C3}; // Connect to the column pinouts of the keypad

// Initialize an instance of class Adafruit_Keypad
Adafruit_Keypad customKeypad = Adafruit_Keypad(makeKeymap(keys), rowPins, colPins, 4, 3);

// Store the key sequence
String keySequence = "";

// Define the correct key sequence
const String correctSequence = "1234";

void setup() {
  Serial.begin(9600);
  customKeypad.begin();
  pinMode(SOLENOID_PIN, OUTPUT);
  digitalWrite(SOLENOID_PIN, LOW); // Ensure solenoid is initially off
}

void loop() {
  // Put your main code here, to run repeatedly:
  customKeypad.tick();

  while (customKeypad.available()) {
    keypadEvent e = customKeypad.read();
    char key = (char)e.bit.KEY;

    if (e.bit.EVENT == KEY_JUST_PRESSED) {
      Serial.print(key);
      Serial.println(" pressed");

      // Append the pressed key to the sequence
      keySequence += key;

      // Check if the sequence matches
      if (keySequence.length() >= 4) {
        if (keySequence.substring(keySequence.length() - 4) == correctSequence) {
          Serial.println("Correct sequence entered! Activating solenoid.");
          digitalWrite(SOLENOID_PIN, HIGH); // Activate solenoid lock
        } else {
          Serial.println("Incorrect sequence.");
          digitalWrite(SOLENOID_PIN, LOW); // Deactivate solenoid lock if sequence is incorrect
        }
      }

      // Clear the sequence if more than 4 keys have been pressed
      if (keySequence.length() > 4) {
        keySequence = keySequence.substring(1);
      }
    } else if (e.bit.EVENT == KEY_JUST_RELEASED) {
      Serial.print(key);
      Serial.println(" released");
    }
  }

  delay(1);
}

Key Points:
Solenoid Lock Pin Definition:
The solenoid lock is connected to D11. This pin is set to OUTPUT and initially set to LOW to ensure the solenoid is off at the start.

Key Sequence Tracking:
The code appends each pressed key to keySequence. If the last four keys match 1234, it activates the solenoid lock by setting SOLENOID_PIN to HIGH.

Solenoid Activation:
The solenoid lock is activated by setting SOLENOID_PIN to HIGH when the correct sequence is entered. If the sequence is incorrect, the solenoid remains or is set to LOW.

Key Sequence Length Management:
The code ensures that only the last four keys are kept in keySequence to avoid overflow and correctly manage the sequence.

Correct Keymap Array:
The keymap array has been corrected for a 3x4 keypad, and the column pins array is updated accordingly.

By following these changes, the solenoid will only activate when the correct sequence 1234 is entered on the keypad. Adjust the pin definitions and keymap if needed based on your specific hardware configuration.

Me, Alana Duffy

so the SOLENOID_PIN needs to be the 3V3 pin on the RP2040

ChatGPT

The 3V3 pin on the RP2040 provides a constant 3.3V power output, which is not directly controllable through code. Instead, to control the solenoid with the keypad input, you'll need to use a GPIO pin to control a transistor or a relay that, in turn, controls the power to the solenoid.

Here’s how you can achieve this:

Control Solenoid Using GPIO Pin:
Use a GPIO pin to drive a transistor (NPN or N-channel MOSFET) that can switch the 3.3V power to the solenoid. This way, the GPIO pin can control the solenoid by turning the transistor on and off.

Circuit Design:

NPN Transistor: Connect the emitter to ground, the collector to the solenoid (which then connects to the 3V3 pin), and the base to the GPIO pin through a current-limiting resistor.
N-channel MOSFET: Connect the source to ground, the drain to the solenoid (which then connects to the 3V3 pin), and the gate to the GPIO pin through a current-limiting resistor.
Updated Code for Controlling the Solenoid:
Here’s the code with a GPIO pin controlling the transistor or relay:

// Use this example with the Adafruit Keypad products.
// You'll need to know the Product ID for your keypad.
// Here's a summary:
//   * PID3844 4x4 Matrix Keypad
//   * PID3845 3x4 Matrix Keypad
//   * PID1824 3x4 Phone-style Matrix Keypad
//   * PID1332 Membrane 1x4 Keypad
//   * PID419  Membrane 3x4 Matrix Keypad

#include "Adafruit_Keypad.h"

// Define your specific keypad here via PID
#define KEYPAD_PID3845  // 3x4 Matrix Keypad

// Define your pins here
#define R1    D2
#define R2    D3
#define R3    D4
#define R4    D5  // Not used in 3x4 keypad
#define C1    D8
#define C2    D9
#define C3    D10
#define C4    -1  // Not used in 3x4 keypad

// Define the solenoid control pin (connected to the transistor base or MOSFET gate)
#define SOLENOID_CONTROL_PIN D11

// Define the keymap for a 3x4 keypad
const char keys[4][3] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[4] = {R1, R2, R3, R4}; // Connect to the row pinouts of the keypad
byte colPins[3] = {C1, C2, C3}; // Connect to the column pinouts of the keypad

// Initialize an instance of class Adafruit_Keypad
Adafruit_Keypad customKeypad = Adafruit_Keypad(makeKeymap(keys), rowPins, colPins, 4, 3);

// Store the key sequence
String keySequence = "";

// Define the correct key sequence
const String correctSequence = "1234";

void setup() {
  Serial.begin(9600);
  customKeypad.begin();
  pinMode(SOLENOID_CONTROL_PIN, OUTPUT);
  digitalWrite(SOLENOID_CONTROL_PIN, LOW); // Ensure solenoid is initially off
}

void loop() {
  // Put your main code here, to run repeatedly:
  customKeypad.tick();

  while (customKeypad.available()) {
    keypadEvent e = customKeypad.read();
    char key = (char)e.bit.KEY;

    if (e.bit.EVENT == KEY_JUST_PRESSED) {
      Serial.print(key);
      Serial.println(" pressed");

      // Append the pressed key to the sequence
      keySequence += key;

      // Check if the sequence matches
      if (keySequence.length() >= 4) {
        if (keySequence.substring(keySequence.length() - 4) == correctSequence) {
          Serial.println("Correct sequence entered! Activating solenoid.");
          digitalWrite(SOLENOID_CONTROL_PIN, HIGH); // Activate solenoid lock
        } else {
          Serial.println("Incorrect sequence.");
          digitalWrite(SOLENOID_CONTROL_PIN, LOW); // Deactivate solenoid lock if sequence is incorrect
        }
      }

      // Clear the sequence if more than 4 keys have been pressed
      if (keySequence.length() > 4) {
        keySequence = keySequence.substring(1);
      }
    } else if (e.bit.EVENT == KEY_JUST_RELEASED) {
      Serial.print(key);
      Serial.println(" released");
    }
  }

  delay(1);
}

Key Points:
Solenoid Control Pin:
Define a GPIO pin (SOLENOID_CONTROL_PIN) to control the transistor or relay that switches the solenoid. This pin will be set to HIGH to activate the solenoid and LOW to deactivate it.

Circuit Design:

NPN Transistor: Connect the emitter to ground, the collector to the solenoid's negative terminal, and the base to the GPIO pin through a resistor.
N-channel MOSFET: Connect the source to ground, the drain to the solenoid's negative terminal, and the gate to the GPIO pin through a resistor.
The solenoid's positive terminal is connected to the 3V3 pin on the RP2040.
Control Logic:
The code activates the solenoid by setting the control pin to HIGH when the correct sequence 1234 is entered. It deactivates the solenoid by setting the control pin to LOW for any other sequence.

By following these steps, the solenoid will only activate when the correct sequence 1234 is entered on the keypad, using the GPIO pin to control the power to the solenoid through a transistor or relay. Adjust the pin definitions and keymap if needed based on your specific hardware configuration.

Me, Alana Duffy

so can you make that the keypad sequence 1234 will toggle the solenoid_control_pin from high to low

ChatGPT

Certainly! To toggle the state of the solenoid control pin when the sequence "1234" is entered, we can keep track of the state of the solenoid and toggle it accordingly. Below is the updated code to achieve this:

// Use this example with the Adafruit Keypad products.
// You'll need to know the Product ID for your keypad.
// Here's a summary:
//   * PID3844 4x4 Matrix Keypad
//   * PID3845 3x4 Matrix Keypad
//   * PID1824 3x4 Phone-style Matrix Keypad
//   * PID1332 Membrane 1x4 Keypad
//   * PID419  Membrane 3x4 Matrix Keypad

#include "Adafruit_Keypad.h"

// Define your specific keypad here via PID
#define KEYPAD_PID3845  // 3x4 Matrix Keypad

// Define your pins here
#define R1    D2
#define R2    D3
#define R3    D4
#define R4    D5  // Not used in 3x4 keypad
#define C1    D8
#define C2    D9
#define C3    D10
#define C4    -1  // Not used in 3x4 keypad

// Define the solenoid control pin (connected to the transistor base or MOSFET gate)
#define SOLENOID_CONTROL_PIN D11

// Define the keymap for a 3x4 keypad
const char keys[4][3] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[4] = {R1, R2, R3, R4}; // Connect to the row pinouts of the keypad
byte colPins[3] = {C1, C2, C3}; // Connect to the column pinouts of the keypad

// Initialize an instance of class Adafruit_Keypad
Adafruit_Keypad customKeypad = Adafruit_Keypad(makeKeymap(keys), rowPins, colPins, 4, 3);

// Store the key sequence
String keySequence = "";

// Define the correct key sequence
const String correctSequence = "1234";

// Store the state of the solenoid
bool solenoidState = false;

void setup() {
  Serial.begin(9600);
  customKeypad.begin();
  pinMode(SOLENOID_CONTROL_PIN, OUTPUT);
  digitalWrite(SOLENOID_CONTROL_PIN, LOW); // Ensure solenoid is initially off
}

void loop() {
  // Put your main code here, to run repeatedly:
  customKeypad.tick();

  while (customKeypad.available()) {
    keypadEvent e = customKeypad.read();
    char key = (char)e.bit.KEY;

    if (e.bit.EVENT == KEY_JUST_PRESSED) {
      Serial.print(key);
      Serial.println(" pressed");

      // Append the pressed key to the sequence
      keySequence += key;

      // Check if the sequence matches
      if (keySequence.length() >= 4) {
        if (keySequence.substring(keySequence.length() - 4) == correctSequence) {
          Serial.println("Correct sequence entered! Toggling solenoid state.");
          solenoidState = !solenoidState; // Toggle solenoid state
          digitalWrite(SOLENOID_CONTROL_PIN, solenoidState ? HIGH : LOW); // Activate or deactivate solenoid
        }
      }

      // Clear the sequence if more than 4 keys have been pressed
      if (keySequence.length() > 4) {
        keySequence = keySequence.substring(1);
      }
    } else if (e.bit.EVENT == KEY_JUST_RELEASED) {
      Serial.print(key);
      Serial.println(" released");
    }
  }

  delay(1);
}

Key Points:
Solenoid Control Pin:
The solenoid control pin (SOLENOID_CONTROL_PIN) is toggled between HIGH and LOW states when the correct sequence 1234 is entered.

Toggling Solenoid State:
A boolean variable solenoidState is used to keep track of the current state of the solenoid. When the correct sequence is entered, the state is toggled using !solenoidState. Then, the solenoid is activated or deactivated based on this state.

Correct Keymap Array:
The keymap array has been corrected for a 3x4 keypad, and the column pins array is updated accordingly.

With this code, each time the sequence "1234" is entered, it toggles the state of the solenoid control pin, effectively toggling the solenoid's activation state. Adjust the pin definitions and keymap if needed based on your specific hardware configuration.

Final Code

After some debugging of my own, I had my final, working code:

// This code is authored by Alana Duffy with the help of Chat GPT
// It is based off of an example code from the "Adafruit Keypad" library by Adafruit 
// Licensed under MIT
// Use this example with the Adafruit Keypad products.
// You'll need to know the Product ID for your keypad.
// Here's a summary:
//   * PID3844 4x4 Matrix Keypad
//   * PID3845 3x4 Matrix Keypad
//   * PID1824 3x4 Phone-style Matrix Keypad
//   * PID1332 Membrane 1x4 Keypad
//   * PID419  Membrane 3x4 Matrix Keypad

#include "Adafruit_Keypad.h"

// Define your specific keypad here via PID
#define KEYPAD_PID3845  // 3x4 Matrix Keypad

// Define your pins here
#define R1    D2
#define R2    D3
#define R3    D4
#define R4    D5  // Not used in 3x4 keypad
#define C1    D8
#define C2    D9
#define C3    D10
#define C4    // Not used in 3x4 keypad

// Define the solenoid control pin (connected to the transistor base or MOSFET gate)
#define SOLENOID_CONTROL_PIN D1

// Define the keymap for a 3x4 keypad
const char keys[4][3] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[4] = {R1, R2, R3, R4}; // Connect to the row pinouts of the keypad
byte colPins[3] = {C1, C2, C3}; // Connect to the column pinouts of the keypad

// Initialize an instance of class Adafruit_Keypad
Adafruit_Keypad customKeypad = Adafruit_Keypad(makeKeymap(keys), rowPins, colPins, 4, 3);

// Store the key sequence
String keySequence = "";

// Define the correct key sequence
const String correctSequence = "1234";

// Store the state of the solenoid
bool solenoidState = false;

void setup() {
  Serial.begin(9600);
  customKeypad.begin();
  pinMode(SOLENOID_CONTROL_PIN, OUTPUT);
  digitalWrite(SOLENOID_CONTROL_PIN, LOW); // Ensure solenoid is initially off
}

void loop() {
  // Put your main code here, to run repeatedly:
  customKeypad.tick();

  while (customKeypad.available()) {
    keypadEvent e = customKeypad.read();
    char key = (char)e.bit.KEY;
    
    if (e.bit.EVENT == KEY_JUST_PRESSED) {
      Serial.print(key);
      Serial.println(" pressed");

      // Append the pressed key to the sequence
      keySequence += key;

      // Check if the sequence matches
      if (keySequence.length() >= 4) {
        if (keySequence.substring(keySequence.length() - 4) == correctSequence) {
          Serial.println("Correct sequence entered! Toggling solenoid state.");
          solenoidState = !solenoidState; // Toggle solenoid state
          digitalWrite(SOLENOID_CONTROL_PIN, solenoidState ? HIGH : LOW); // Activate or deactivate solenoid
          digitalWrite(SOLENOID_CONTROL_PIN, HIGH); 
          delay(240000);
 digitalWrite(SOLENOID_CONTROL_PIN, LOW); 
        }
      }

      // Clear the sequence if more than 4 keys have been pressed
      if (keySequence.length() > 4) {
        keySequence = keySequence.substring(1);
      }
    } else if (e.bit.EVENT == KEY_JUST_RELEASED) {
      Serial.print(key);
      Serial.println(" released");
    }
  }

  delay(1);
}

For some reason it wasn’t working at first, so then I asked Richard if he could look at it and, when he walked over, stared at it for .2 seconds, it magically started working! Although I was baffled and confused, I was happy nonetheless!

PCB Board

Schematic:

PCB:

Milling in Process:

Component Quantity
Seeed Studio XIAO RP2040 1
1x2 Male Header 1
1x7 Male Header 1
Milled PCB 1

Final board:

Board Working:

PCB Board Case

I designed the PCB Board Case below in Fusion360:

    Keypad and Solenoid PCB Case     by Alana Duffy

I then downloaded the file, brought it into Prusa Slicer, re-arranged and sliced the file, saved it as a .gcode, and then uploaded it to one of my lab’s Prusa Minis.

(The one on the right is the PCB case for the Time of Flight sensor and LCD board and the one on the left is the PCB case for the keypad and solenoid PCB)

Installation

To install the keypad, I drilled four holes about 2 mm in diameter to insert M2 screws into. I used 4 nuts on the other side to secure the screws and keypad in place.

I later painted over the bolts on the inside for a more aesthetic look.

To install the solenoid lock, I used four standard screws and used a screwdriver to screw them in.

Wire Management

Dremel-ed & Sanded Crevices

While CNC-ing, I did mill some pockets so that I could hide wires in them, however, I did not mill enought pockets :(

To fix this, I used the dremel to make some make-shift pockets that I could push and hide wires in. Although it took awhile, it actually turned out pretty nicely! I used a tile cutting bit and a sanding bit on the dremel.

Lengthening

To make it so I could hide my wires, I had to first lengthen them so they could reach the electronics hiding box in the top part of the medicine box. To do this, I measured the length of wire I needed, got and cut a new wire to length, cut a jumper wire in half, stripped a small bit of both the jumper wire ends and the new wire ends, twisted and tinned the wire ends, solered them together, and then slid heat shrink over the exposed wire and used a heat gun to shrink the heat shrink.

Example:

This

To this!

Solenoid wires lengthened:

Braiding

To keep my wires together more efficiently and in a more organized manner, I actually braided some of them together! I braided six of them (in pairs of 3).

Tubes

Taking the wires I had previously braided, I used a flexible clear tube and wrapped it around the wires to give it a more polished look.

I then was able to fit the tube of wires through the dremeled and sanded hole in the front/side of the electronics hiding box.

I then cut the tube to a length best suited for where the wires in the tube needed to come out. You can see that, for the wires for the keypad and solenoid, the tube is longer than the tube for the time of flight sensor and LCD.

Wire Mount

I actually bought wire mounts instead of making them because it was so close to presentation day. I had hoped to make them, but I needed a quick solution (it was the day before presentations). I used three types of wire mounts:

1.A big mount for the keypad and solenoid wire tube to hide it behind the door/front of the box

2.Medium sized mounts that I could take the wires in and out of for the USB-C to lightning cables

3.Small mounts for holding small portions of the wires from the tubes in place

Wood Covers

I also made a wood cover to hide the wires behind

    Wire Cover     by Alana Duffy

My laser cutting steps:

  1. save the fusion sketch as a .dxf

  2. Import the file into Corel draw (hairline and black for cutting lines)

  3. Click control and P

  4. Move the design over the material in bed in the epilogue software

  5. Click the folder with a down arrow to import a material (I did wood cutting 1/8” (3mm))

  6. On the laser cutter, Click the joystick with a light icon, move the laser over the material with the joystick, and then click autofocus

  7. Next, click the play button to have it run

Here’s it after being laser cut and spray painted:

It fit really nicely in the door:

After getting the wires situated the way I wanted, I taped the wire cover in place and slowly went around and superglued it into place:

I then sanded the glue down a little after it finished drying and cleaned up the paint job:

The Final Touch: A Vinyl Sticker

For a final touch, I vinyl cut a “The Smart Medicine Box” sticker in the same font as on my final project slide.

To create my sticker, I screenshoted the text form the final project slide. The picture had a background to it, so I uploaded the image to removebg, clicked remove background, and downloaded the new file.

I then imported the image into Silhouette Studios. I then resized the image to make it bigger so when I trace it I can easily see details. I opened the trace tab, clicked “Select Trace Area,” and positioned the trace area so that all of the image was inside. I then fiddled around with the settings to find the trace that best captures the image (keep in mind that the trace lines will be cut out from the vinyl). I decided on the following settings:

Trace Preview: solid fill

Threshold: 46%

Despeckle Threshold: 0%

High Pass (Off): 0%

Low Pass (Off): 0%

Scale: 10

Trace Style: Trace

I then clicked “Trace.” Once the image is traced, it will remain in the document so I pulled it to the side and deleted it. I was then left with the trace outline (in red).

Next I scaled the trace outline so that the width was 1.721 inches and height 5.965 inches. I then saved the design and named it. I then retrieved a cut mat, a weeding tool, scissors, and a piece of pink vinyl. I lined the vinyl up with the top left corner of the cutting mat and used a squeegee to adhere it to the mat and ensure no air bubbles were between the vinyl and cut mat. I then clicked “Load” on the vinyl cutter.

The “Send” tab settings are as follows:

Material: Vinyl, Glossy (1)

Action: Cut

Tool: Manual blade, 1mm; Cut

Blade depth: 3

Passes: 1

Force: 10

Speed: 5

I then hit “send” on the computer and the vinyl cutting starts! Once the job was complete, I hit “Unload.”

I used the weeding tool to remove parts of the sticker I did not want.

I then used transfer tape to remove the words from the excess vinyl.

I used the transfer tape to stick the sticker to where I wanted on my box and I then slowly removed the transfer tape.

Design Flaws

Originally, I had planned to have my time of flight sensor detect each time someone opened the door to the medicine box. However, upon reflection, I believe my future iteration will either need a change in sensor used or a change in time of flight sensor location and/or code. The reason I say this is because, at 10PM the night before presentation day, I realized a major design flaw in my project: the time of flight sensor, although recording correctly how many times you open the door to the pill box as I had wanted it to, also records if you put your hand into the box to retrieve the pills. In all of my testing, I never thought to put my hand through the door ._. . Yea, not my best moment. But, with quite literally 16 hours left to present and 0 brain cells left working, I decided to just go with it – if I broke my project at this point just trying to fix this issue, I would risk not being ready to present and rolling over which, as a student applying to colleges next year, would mean I would have no way to explain why I took an easier course load, what I was doing all those hours, why I was apart of less clubs, why my sports stopped for 6 months, etc. Not only would I not be able to put Fab Academy on my resume, I would have an absolutly massive black hole of “what the heck happened here?”

In summary, I couldn’t risk trying to change it and I had absolutly no brain power left after a week straight of 12-13 hour days in the lab. So, I decided that I would, after graduating Fab, return to my project and make it better. I plan to either do this by using a different sensor, such as a Hall sensor that Neil recommended (a cheaper sensor), or change the location or code for the time of flight sensor to only record one incident of the door ‘opening’ for each time a person takes their pills.

Additional Q&A

1) What worked? What didn’t?

Everything in my project worked, however, some of it didn’t work perfectly. As I mentioned above, the Time of Flight sensor, although it did work how I wanted it to, does have some major flaws to it that I just didn’t realize when making my project. Additionally, the hinges are a little misaligned which required my door to be a little crooked.

2) How was it evaluated?

My project passed Neil’s requirements, however, he did have some feedback. He suggested I better show the process of making my project in the video and pointed out the flaws in my Time of Flight sensor, suggesting I use a cheaper alternative like a Hall sensor.

3) What are the implications?

The implications of my project include a step in the right direction for keeping college students safer. Keeping prescription medications properly administered will help with overall student health and reduce the amount of incorrect medication use. Additionally, I believe my project could also have a use for dementia patients. And finally, my project helped me to dip my feet into the world of making a final project from start to finish, exposing me and challenging me to get out there!

Reflection

This sucked. I got no sleep, I wanted to cry all the time, I would feel super happy and proud one minute and super sad and embarassed of my project the next. It was nerve wracking and I spent a solid week of 12-13 hour days at the lab. Summer had just started and exams were finally over and all I wanted to do was relax. But, I knew I couldn’t let the almost $6k and all the hard work I spent thus far on Fab Academy go to waste. So, I pushed through ᕦ(ò_óˇ)ᕤ !

And let me tell you, I’m so happy to be at the bottom of my final project documentation writing this paragraph right now. It’s two days before local evaluation is due to be at 100% and I was really stressing – I’ve been working on this documentation for way too long but I think it’s good and I’m proud of what I’ve accomplished. Don’t get me wrong though, I’m excited to go outside, see friends (if I still have any after fab), and sleep :3

I couldn’t have gotten through this without my fab class mates, my friends from the previous year of fab graduates at my school, my teachers, parents, and Garrett <3

And now, I can use all the lab’s tools AND NOT HAVE TO DOCUMENT ANY OF IT!!!! …till next school year starts

References

https://www.youtube.com/watch?v=Yh3TLXihUps

https://www.instructables.com/Controling-a-sxolenoid-valve-with-an-Arduino/

https://learn.adafruit.com/secret-knock-activated-draweXr-lock/parts-and-tools

https://www.adafruit.com/product/1501

Creative Commons License-NonCommercial-ShareAlike

Angelina Yang

Medicus Health’s Narcotics Cabinet, Double Door, Double Lock, Electronic Programmable Lock

Single Care

Statistica

The Vial Company

Lucid App

Charlotte Latin Lab CNC Workflow

The NotSoCivilEngr’s Door Hinge YT video

Everbilt’s 5 mm Brass Plated Steel Shelf Support Spoon Pins Alana Duffy Week 9 Documentation

Mr. Durrett

Angelina Yang output devices documentation

serial LCD display

I2C/IIC serial adapter

https://lastminuteengineers.com/i2c-lcd-arduino-tutorial/

LiquidCrystal I2C library

hd44780 library

ChatGPT 3 and 4

Alana Duffy Week 11 Documentation

SeeedStudio

Adam Stone Week 11 input devices documentation

Adafruit VL53L1X Time-Of-Flight sensor

https://www.adafruit.com/product/3967

Arduino and CircuitPython/Python code so you can use this sensor with an Arduino Uno, Feather M4, Raspberry Pi or anything in between

this Instructables article

Adrian Torres’ code

ATtiny84 Keypad Human Interface Qwiic Platform Evaluation Expansion Board

Adafruit Industries 3x4 Matrix Keypad

https://www.adafruit.com/product/3845

Datasheet

https://learn.adafruit.com/matrix-keypad/arduino

Adafruit Industry’s Lock-style Solenoid - 12VDC

https://www.adafruit.com/product/1512

Datasheet

Diagram

Ledmo Power Supply

DIY Tech Guy’s Arduino Lesson 4 - Solenoid control using a Transistor

https://www.youtube.com/watch?v=Yh3TLXihUps

Richard Shan

Collin Kanofsky

Mosfet board

RoboJax’s Lesson 82: Using VL53L1X 400cm Laser Distance sensors with LCD

Youtube video

http://librarymanager/All#SparkFun_VL53L1X

Alana Duffy Week 12 Documentation

15 Slow Mold Star Series

Data sheet for Moldstar 15

Best video compressor I’ve found yet


Last update: July 14, 2024