Vending Machine with Arduino UNO

 Vending Machine with Arduino UNO

The goal of this project is to make a controller for a vending machine based in Arduino UNO and using the sensors and the stuff contained in the given Arduino KIT:

Components:

The components and sensor used from the KIT in order to make this project are the following ones:

  • Arduino UNO

  • LCD

  • Joystick

  • DHT11 (Temperature/Humidity sensor)

  • HC-SR504 (Ultrasonic Sensor)

  • Button

  • Red Led (LED1)

  • Green Led (LED2)

  • Resistors

  • Male-to-male wires

Connection:

Now we detail the connection scheme for the project. This connection scheme was made using fritzing:

NOTE: The joystick model used in fritzing has a different model, and the pins from left to right are: VCC-VRX-VRY-SW-GND, while the one used in the project (the one from the arduino KIT) is: GND-VCC-VRX-VRY-SW. Take this in consideration for the connection of your project.

Code design. General concepts:

In order to follow all the steps and specifications of the exercise, I decided to make the following things:

  • In the loop main we will have a switch-case with different states for the program. This was made in order to avoid doing tasks that we just need to do only once or in a specified time of the program all the time. For the different states, I created a enum with the different states for the program.

  • For taking the measures of the main sensors (DHT11, HC-SR504), I created a thread for each that runs every 300ms (this period can be modified in the constant of the program). This threads are added in a controller that runs in every loop.

  • In order to detect in any point of the "Service" state if the button is pressed and how long is pressed, I created a hardware interrupt for the button, using a de-bounce system to avoid detecting false alarms in the button.

  • To avoid using delay() or delayMicros(), we use timestamps for the tasks that runs only once for a specified time period. These are: blinking the LED1 for 1s 3 times and print "CARGANDO..." in the LCD, preparing drink time [4-8s], show humidity/temperature for 5s... etc.

    SECTION 1) START-UP:

    The setup() will establish the global variable "state" to START. During this state, in the loop we will blink the LED1 every second (using timestamps as specified above). In every blink, we will increase the blinks_count variable till we reach N_BLINKS*2 times (this is because we increase every time we turn on and off the led). Once we reach that, we change to SERVICE state.

    SECTION 1) SERVICE:

    Service a) Start checking if the distance to the person is less or more than 1 meter. If its more, show "ESPERANDO CLIENTE".

    Service b) If the distance to the person is less than 1 meter, show for 5 seconds (using timestamps) the values measures from the DTH11

    Important: As it is not specified in the exercise, if the person is at less than 1 meter but in any point of this state is at more than 1 meter, the LCD will show "ESPERANDO CLIENTE" again till the person is again at less than 1 meter.

    For the LCD cafe menu, I created a function show_products().

    Inside the function, we check if the joystick has been moved down or up or if the switch has been pressed. If the joystick is moved we change the 2 products that shows the LCD, "moving" (increasing/decreasing) the product_pointer variable of the products arrays (We have an array for the product name, and other array for the prices. The position x of the product name array corresponds to the position x of the product price array).

    Important: The show_products() function executes in ever MENU_UPDATE_INTERVAL millis of this state, establish in 200 millis as recommendation. This is because, if we don't specify an interval and we execute the function in every loop iteration, a single down/up scroll of the joystick can be interpreted as 3-5 scrolls, and it will be very difficult to select a desired product. Also, if the interval is to high (>300 millis), some scrolls could not been detected.

    In the LCD, we will show an arrow "->" to know which product we are selecting. If the product if selected pressing the switch, we will increase in each iteration the brightness of the LED2 and we will show in the LCD the corresponding text. Once the drink is prepared and the 3 seconds for the drink withdraw are passed, the program will return again to show the humidity/temperature info and then will show again the product menu from the beginning (the products 0 and 1 of the array, and not from the last selected product). 

    HARDWARE INTERRUPTION TREATMENT FOR THE BUTTON:

    As we specified above, we use a hardware interruption for the button detection. 

    Every time the button is pressed will set the variable button_pressed to true. As it might been "pressed" by the bounce time, we handle the de-bounce system in check_button(), that will be call in all the iterations of the loop() for all the states except the START one. We will check with a timestamp if the BOUNCE_TIME (~20ms) has been passed or not to check if the button has rising or fallen and for how long has been pressed. Depending in that time period we change the state variable (if has been pressed for >5s, enter/exit from ADMIN mode, if was pressed for 2-3s, restart SERVICE state).

    SECTION 3) ADMIN:

     For the admin state I create a sub-switch-case to handle what to do if some of the options of the admin menu has been pressed checking the admin_menu_pointer (this is, the pointer to the array of the admin menu options). If its 0 it means that the user want to see the humidity/temperature info. If its 1, the distance info, and if its 2, the seconds counter.

    Important: To avoid using millis() / MILLIS_TO_SECS as the seconds counter  I created a new variable that will be updated in one of the threads that has a 1s rate.

    Finally, if the pointer value is 3, the LCD will show the modify-prices menu. It will apear the products exactly as in the SERVICE menu. In the moment that one of the products its clicked the LCD will show in the first row the product name and price to change and in the second row the instructions to do it ( "^" for +0.05€, "v" for -0.05€). The user is able to abort this operation if he turns the joystick to the left and confirm the operation if it press the joystick switch (the new price for that product will appear in the SERVICE menu). 

    USE OF WATCHDOG FOR SECURITY CODE:

    In order to avoid the code being blocked in any point of the program I use the watchdog mechanism. I set a Watchdog time of 2seconds. That means if the program is blocked or it doesn't make the desired behavior in that time, the system will be reset.

    AUTO-SCROLL FOR THE LCD TEXT:

    The LCD dimension is 16x2, so long strings such as the menu products and their prices doesn't fit in the LCD dimension. To allow the user see the complete information of each of the products and other long strings I implement an autoscroll mechanism.

    This basically prints in the LCD a sub-string of the string, that starts from a pointer "i" that it is updated every SCROLL_INTERVAL millis and finished in the last characted of the string.

    It start always in the first column and the row depends in the parameter (see the parameters: scroll_text(String, row))

    VIDEO DEMONSTRATION:


 

Comentarios