Hammerheads-Smart Drink Dispenser- The Big Picture

Protect the Brew. After a bad experience with collecting money for a Beer Olympics I came up with the idea for our project, a smart beverage dispenser. One that would limit access to the delicious golden ale inside. Despite my original intentions this project can also be implemented to prevent underage drinking and to keep track of how much people drink. So don’t tell me you had 6 beers when you only drank 4.

The key aspect to this project is the fingerprint scanner. It provides the security we wanted for the project at an affordable price. With two microcontrollers, a Homebrew Draft System, the fingerprint scanner and a solenoid valve the project began. The system is designed so the beverage will only dispense after your fingerprint is verified. We used an Arduino to communicate between the scanner and the A3BU which controlled the other functions. The system will identify who accessed the system and display it on the A3BU LCD. It will also activate one of the LED’s that indicate the status of the fingerprint, red if denied and green if approved. Assuming the approval signal is received by the A3BU it will send a signal that activates a solenoid motor through a transistor circuit. The System will then dispense the beverage for 20 seconds which at 15 psi will fill up a cup.

 

Creation of PCB’s (Drink Dispenser) by Hammerheads

For our project, we did not want wires to be loose, so we decided to create our own pcb’s and to solder the components and wires onto them so minimize the amount of wires being unplugged and for simplicity. In order to create pcb’s, we used a freeware called eaglecad to create a schematic and then from the schematic, layout a board. The board has to be designed by a person and there are some tricks to help create the board. The first thing to know is that there is a top and bottom copper pours. In practice, it is good to have one side ground and the other as the input voltage. These pours are created by creating a polygon around the components and having the pours layered as top or bottom. The pours need to be named as Vcc or grnd (or whatever is named as vcc or grnd). After the pours and components are placed, traces need to be created. There should already be yellow lines that show which traces need to be created. Use the trace tool on the left in eagle to start making traces and be aware of which layer the trace is being created on, either top or bottom. Also make sure to not overlap two of the same layered traces or to have a trace where a component will be. After all of that is done, hit the ratsnest button and see if there are any traces that is not created. Lastly, do the error check in eaglecad to make sure that the board is printable. Now that the board is designed, we need to extract the gerber files to send to the pcb machine in first build to print the board. Sparkfun has a great guide to extract the gerber files. Here is the URL the guide. https://learn.sparkfun.com/tutorials/using-eagle-board-layout/generating-gerbers .

Once the files are created, email it in a zip file to yourself and head over to firstbuild to print. Ask an employee for help to use the pcb machine, because it takes a good day of learning to use the machine. If you want to print the board yourself, I will give a brief explanation of how to do that. Log into your email on the computer next to the machine and download the gerber files. Open the SPK software on the desktop and select the double sided no through hole template. Import the files, and make sure that they are defined. Select technology dialog and set the settings to how you would like them to be. Next, click on the fiducials button and create three fiducials. The fiducials is reference holes for the machine to keep track of where everything for when you flip the board over. Next, make sure that the pcb machine has all of the tools that you need for the print. Now, click on production wizard and go through with the print. There is a pdf of a more descriptive guide on the desktop of the computer. Be aware that there is a $2 fee to use the machine and $12 to purchase a double sided copper board.

 

 

Motor_LED Motor_LED_Brdimage1

Hammerheads A3BU code (Drink Dispenser)

We used the A3BU to receive signals from an Arduino Uno, to turn on a green LED, to match ID’s with the name of the person whose finger was scanned, and to power a solenoid motor. This code will consistently check the ADC pin on the A3BU for some kind of voltage signal. If a signal of 120mV or higher is detected, the A3BU will start a counter and increase it for every 100ms that the signal is detected. This counter would become the ID number, transmitted from the Arduino. Once the A3BU detects a Low signal (under 120mV) it would turn on a green LED using a PWM signal. It would also take the ID and match it with the name of the person scanned. These ID’s were programmed into the fingerprint scanner and the names to be matched with the ID’s were hard coded into this code. After the match, the name will be displayed on the LCD screen of the A3BU along with the matching ID. Once this had been done, the A3BU would send a signal to the solenoid motor for a 20 second period in order to dispense the liquid.

 

 

A3BU Code:

#include <asf.h>

#include <stdio.h>

#include <conf_example.h>

#include <util/delay.h>

#include <string.h>



int count = 0; //count will keep track of id number

bool check = false; //check to make sure that the if statement is entered only once at a time



struct pwm_config mypwm[4];

static void adc_handler(ADC_t *adc, uint8_t ch_mask, adc_result_t result)

{

#ifdef CONF_BOARD_OLED_UG_2832HSWEG04

 gfx_mono_draw_filled_rect(0,0,128,32,GFX_PIXEL_CLR); //set light on LCD

#endif

char out_str[OUTPUT_STR_SIZE];

result += 10; //make sure result does not go negative

//we were having result go to single digit negatives every now and then which would turn on dispenser



snprintf(out_str, OUTPUT_STR_SIZE, "Voltage: %4d mV", result); // Write voltage from ardunio to display

gfx_mono_draw_string(out_str, 0, 0, &sysfont);   

if(result > 40 ) //If High

{

count++; //increment id number

check = true; //allow dispenser to be active

_delay_ms(15); //delay to check for high from arduino to increment id to the correct id number

}



if(result < 40 && result >= 0 && check == true) //If Low

{

 if ((count-1) == 0) //Cory

 {

  snprintf(out_str, OUTPUT_STR_SIZE, "Cory Lentz id = %i",count-1);

  gfx_mono_draw_string( out_str,0,20,&sysfont);

 }

 if ((count-1) == 1) //Brandon

 {

  snprintf(out_str, OUTPUT_STR_SIZE, "Brandon S. id = %i",count-1);

  gfx_mono_draw_string( out_str,0,20,&sysfont);

 }

 if ((count-1) == 2) //Nick

 {

  snprintf(out_str, OUTPUT_STR_SIZE, "Nick Glass  id = %i",count-1);

  gfx_mono_draw_string( out_str,0,20,&sysfont);

 }

 if ((count-1) == 3) //Dalton

 {

  snprintf(out_str, OUTPUT_STR_SIZE, "Dalton H. id = %i",count-1);

  gfx_mono_draw_string( out_str,0,20,&sysfont);

 }

 

 gfx_mono_draw_string( out_str,0,20,&sysfont);

 

 //Start Green LED and solenoid motor, delay for 20 seconds to dispense, then turn off

 pwm_init(&mypwm[0], PWM_TCC0, PWM_CH_A, 500);//this is SDA on J1 on the A3BU Xplained

 pwm_start(&mypwm[0], 150);

 pwm_init(&mypwm[2], PWM_TCC0, PWM_CH_B, 500);

 pwm_start(&mypwm[2], 150);

 _delay_ms(20000);

 pwm_start(&mypwm[0], 0);

 pwm_start(&mypwm[2], 0);

 gfx_mono_init();

 count = 0; //reset id value

check = false; //ensure if statement is not unwantedly repeated



}

adc_start_conversion(adc, ch_mask);

}



int main(void)

{

struct adc_config      adc_conf;

struct adc_channel_config adcch_conf;



board_init();

sysclk_init();

sleepmgr_init();

struct pwm_config mypwm[4];

irq_initialize_vectors();

cpu_irq_enable();

gfx_mono_init();



// Enable backlight

#ifndef CONF_BOARD_OLED_UG_2832HSWEG04

 ioport_set_pin_high(LCD_BACKLIGHT_ENABLE_PIN);

#endif



// Initialize configuration structures.

adc_read_configuration(&ADCB, &adc_conf);

adcch_read_configuration(&ADCB, ADC_CH0, &adcch_conf);



adc_set_conversion_parameters(&adc_conf, ADC_SIGN_ON, ADC_RES_8,//Changed resolution from 12 to 8

  ADC_REF_VCC);

adc_set_clock_rate(&adc_conf, 200000UL);

adc_set_conversion_trigger(&adc_conf, ADC_TRIG_MANUAL, 1, 0);

adc_enable_internal_input(&adc_conf, ADC_INT_TEMPSENSE);



adc_write_configuration(&ADCB, &adc_conf);

adc_set_callback(&ADCB, &adc_handler);



adcch_set_input(&adcch_conf, ADCCH_POS_PIN1, ADCCH_NEG_NONE,

  1);

adcch_set_interrupt_mode(&adcch_conf, ADCCH_MODE_COMPLETE);

adcch_enable_interrupt(&adcch_conf);



adcch_write_configuration(&ADCB, ADC_CH0, &adcch_conf);



// Enable the ADC and start the first conversion.

adc_enable(&ADCB);

adc_start_conversion(&ADCB, ADC_CH0);



do {

 // Sleep until ADC interrupt triggers.

 sleepmgr_enter_sleep();

} while (1);

}

Beverage Dispenser: Arduino Code for GT-511C3 Fingerprint Scanner

Attached below is the code we used on for our Arduino board. We used this board primarily because the fingerprint scanner used already had a library developed that was for the Arduino board. FPS_GT511C3, available here: https://github.com/sparkfun/Fingerprint_Scanner-TTL

Our code opens the Serial with a baud rate of 115200. It then proceeds to set up the GT-511C3 fingerprint scanner and execute the loop. This loop waits for a finger to be scanned. In the event that a finger is detected on the scanner, the print is identified with the Identify1_N command and the corresponding id (a value less that 200 if the print is recognized) is copied to an “id” variable. If the fingerprint is successfully identified, a success message and the id read is sent through serial. The way we sent the different IDs to the A3BU was rather ingenious, I believe.  The Arduino sends a high pin value to the A3BU, waits for an amount of time equal to 100 multiplied by the ID found plus one, then transitions the pin back to low. The A3BU can then read how long the pin is high and translate that to the corresponding user using a similar formula to the one mentioned earlier. This emulates a duty cycle and is, in my opinion, a clever way to communicate with the A3BU, since sending just an integer proved to be much more complicated than it sounds. Lastly, the id is set to 201, which prevents duplicate data from being sent to the A3BU. Without this line, the loop would constantly send this duty cycle, causing duplication of data.

 

Arduino Code:



#include "FPS_GT511C3.h"

#include "SoftwareSerial.h"

FPS_GT511C3 fps(10,11); //Serial pins

void setup()

{

Serial.begin(115200); //Set baud rate

fps.Open(); //initialize finger print scanner library

fps.SetLED(true); //Turn on FPS backlight

pinMode(3,OUTPUT); //A3BU output pin

pinMode(5, OUTPUT); //Red LED pin

delay(100); //give time for initialization

}

&nbsp;

void loop()

{

int delay_comm; //value used to delay to set id to a3bu

int id; //id for each person

if (fps.IsPressFinger()) //check to see if finger is on scanner

{

fps.CaptureFinger(false); //

id = fps.Identify1_N(); //set id to id of fps

if (id <200)

{

Serial.print("Verified ID:");

Serial.println(id);

}

else

{

Serial.println("Finger not found");

delay(3000);

digitalWrite(5,LOW); //make sure a3bu does not get signal

}

}

else

{

Serial.println("Please press finger");

}

&nbsp;

delay_comm = ( 100 *( id + 1 )); //set amount of delay of signals to a3bu

if( id >= 0 && id < 200 )

{

&nbsp;

Serial.println("Pin High"); //test to see if pin goes high

digitalWrite(3,HIGH);

delay(delay_comm);

Serial.println("Pin Low"); //make pin low to give mulitple signals to a3bu

digitalWrite(3,LOW);

delay(1000);

}

id = 201; //set id to value that cannot be in if statement above

}