Andrew Morhan

PillDose

PillDose

Biometric pill dispensing system (Arduino + fingerprint auth + servo + LCD + LEDs).

Code Overview

The PillDose system is powered by an Arduino Uno and integrates multiple hardware components through structured and modular C++ code. The program initializes communication with the fingerprint sensor, LCD display, servo motor, and LED indicators during setup. In the main loop, the system continuously waits for a fingerprint scan. When a fingerprint is detected, the program converts the image into a digital template and searches the stored database for a match.

If a valid fingerprint is recognized, the system grants access by activating the green LED, displaying confirmation on the LCD, and actuating the servo motor to dispense a pill. If no match is found, access is denied and the red LED signals rejection. The logic is separated into helper functions such as getFingerprintID(), validAccess(), and invalidAccess() to keep the structure clean, readable, and easy to expand in future iterations (such as adding a true 24-hour lockout mechanism).

Planning

During the planning process for the PillDose project, I began by designing the base structure in SolidWorks, which allowed me to create a precise and functional housing for all core components, including the Arduino Uno, servo motor, fingerprint sensor, and LCD display. Using CAD software helped me visualize spacing, alignment, and mounting positions before physically assembling anything, reducing potential design errors. I also developed orthographic drawings to clearly represent the front, top, and side views of the base, ensuring accurate dimensions and improving overall structural planning. Alongside the design phase, I carefully researched and ordered all necessary components from Amazon while maintaining a strict budget of under $50, balancing affordability with functionality. This budgeting constraint required comparing prices, selecting compatible parts, and prioritizing essential components to keep the project both cost effective and practical.

Coding

pilldose.ino

#include <Adafruit_Fingerprint.h>
#include <SoftwareSerial.h>
#include <Servo.h>
#include <LiquidCrystal.h>


SoftwareSerial mySerial(4, 5);
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);


Servo myServo;


const int greenLED = 2;
const int redLED = 3;


LiquidCrystal lcd(12, 11, 6, 7, 8, 10);

void setup() {
  Serial.begin(9600);
  mySerial.begin(57600);
  finger.begin(57600);

  myServo.attach(9);
  myServo.write(92); 
  delay(50);
  myServo.detach(); 

  pinMode(greenLED, OUTPUT);
  pinMode(redLED, OUTPUT);
  digitalWrite(greenLED, LOW);
  digitalWrite(redLED, LOW);

  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Initializing...");

  if (finger.verifyPassword()) {
    Serial.println("Fingerprint sensor detected!");
    lcd.setCursor(0, 1);
    lcd.print("Sensor Ready");
  } else {
    Serial.println("Fingerprint sensor not found :(");
    lcd.setCursor(0, 1);
    lcd.print("Sensor Failed");
    while (1);
  }

  delay(2000);
  lcd.clear();
}

void loop() {
  lcd.setCursor(0, 0);
  lcd.print("Place Finger");
  Serial.println("Waiting for fingerprint...");

  while (finger.getImage() != FINGERPRINT_OK) {
    delay(100);
  }

  int result = getFingerprintID();

  if (result == FINGERPRINT_OK) {
    validAccess();
  } else {
    invalidAccess();
  }

  while (finger.getImage() != FINGERPRINT_NOFINGER) {
    delay(50);
  }

  delay(500);
}

int getFingerprintID() {
  if (finger.image2Tz() != FINGERPRINT_OK) return -1;
  if (finger.fingerSearch() != FINGERPRINT_OK) return -1;
  return FINGERPRINT_OK;
}

void validAccess() {
  Serial.println("Access Granted!");
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Access Granted");

  digitalWrite(greenLED, HIGH);
  digitalWrite(redLED, LOW);

  
  Serial.println("Spinning servo ~135 degrees to drop pill...");
  myServo.attach(9);
  myServo.write(180);    
  delay(375);            
  myServo.write(92);     
  delay(50);             
  myServo.detach();      

  delay(1000);
  digitalWrite(greenLED, LOW);

  for (int i = 5; i >= 0; i--) {
    lcd.setCursor(0, 1);
    lcd.print("Next in:");
    lcd.print(i);
    lcd.print("sec");
    delay(1000);
  }

  lcd.clear();
}

void invalidAccess() {
  Serial.println("Access Denied!");
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Access Denied!");

  digitalWrite(greenLED, LOW);
  digitalWrite(redLED, HIGH);
  delay(1000);
  digitalWrite(redLED, LOW);

  lcd.clear();
}


        

Competition

PillDose was presented at an invite-only engineering competition where selected students showcased independent projects to faculty and industry judges. Competing against multiple teams, I earned second place overall while being the only solo competitor in the event.

Unlike most participants who competed in groups, I independently handled the design, CAD modeling, component sourcing, programming, system integration, and presentation. This required managing both the technical development and the strategic communication of the project under competitive evaluation.

The project was formally presented through a technical poster, live demonstration, and Q&A session with judges. The recognition reinforced the system’s design quality, functionality, and practical application.