Here's a fun way to make some extra coin from all those sweet tooths around you at home or in the office.
BUILD TIME:6 Hours + 3d printing time
DIFFICULTY RATING: Intermediate
Getting up from your desk and digging around in the lolly cupboard is far too much effort for a quick sugar fix. Why not bring the snacks to you with this tiny Arduino-powered vending machine? It even includes a 20-cent coin slot for collecting some spare change from colleagues, friends and family! Just fill up the dispenser racks with your favourite lollies, insert the included coin basket and watch the money roll in!
The broad overview
In the age of 3D printing and readily-available consumer microcontrollers, desk gadgets are cooler-looking, more customised and more innovative than ever. Okay, we admit, a vending machine isn’t exactly innovative. But a vending machine you can put in your palm, powered by your computer and can accumulate coins from your co-workers or family? Now that’s not just good design, that’s a miniature business – literally!
Since we’re going to be adding six individually selectable lolly racks, you can put virtually whatever you want in them to appeal to your target demographic – which may or may not involve yourself! Think Starbursts, Lifesavers, Gobstoppers, Red Skins, or any small lollies of that type. We’ll also add a full coin tallying system, allowing your customers to put in multiple coins and then keep choosing lollies until they run out of credit.
Now, if you’re like us, you don’t like your hard-earned vending machine business revenue being stolen by opportunists. So, we’ll add a coin collection tray complete with a padlock and key! Sure, it might not be the most secure security solution in the world - considering that we were able to pick it open with a paperclip - but it will certainly stop your friends and family digging into your pocket money.
How It Works
What we’re essentially doing in this project is downsizing most of the same machinery a real vending machine uses and making it work with Arduino-compatible hardware. We’ll build the dispensing racks, coin detector and selector keypad all from commonly-available parts from your favourite electronics and hardware stores.
Dispensing Racks
You’ve no doubt seen these in actual vending machines – the metal coils that dispense a single snack off the rack.
As you might expect, the concept is fairly simple to retrieve the lollies. To push a single lolly off of the rack, we just need to rotate the coil one revolution! For this, we’re going to use six micro continuous servo motors, all of which are controlled by our Arduino microcontroller. The ‘continuous’ part is important, and this differs from a regular servo found in many Arduino kits. Continuous essentially means that the servo can rotate indefinitely – there is no limit to the range of its motion. It’s also super easy to drive with the Arduino Servo library – we can treat it the same as any other servo, but the ‘angle’ we feed to the code is actually the speed of the Servo motor in one direction or the other.
The most tricky part of this is actually finding the racks! Depending on the size and shape of your lollies, correct dimensions need to be used to allow the lolly to move freely on the rack. If the rack does not have enough space to fit the lolly, it could jam and stall the servo motor. If the rack has too much space, the lolly could end up falling out without being controlled by the motor.
The best bet for finding these racks is using compression springs from your local hardware store – these are general-purpose springs that can be used for just about anything. Since we aren’t using the springs for any actual compression or energy storage, the strength and build quality of the coil doesn’t matter. What does matter, though, is checking that the lollies you plan to stock the machine with actually fits into the spring and holds the lolly in place without jamming it there.
Coin Slot
At first glance, making a device that can effectively recognise, count and store coins should be a simple task. However, once you start to consider the variety of coins that could be inserted and the speed and manner in which users may insert coins, it may become apparent that this is a difficult task. Commercial coin readers used in full-sized vending machines are very advanced!
For example, to avoid the use of ‘slug coins’ – counterfeit coins or objects intended to be treated as real coins (like a metal washer), real vending machines use a variety of variables to ensure that coins inserted into the machine are real. Through measuring the thickness, weight, fall time and diameter of sample coins, commercial-grade coin acceptors are capable of consistent and reliable operation – including automatically rejecting coins if the user inserts too many.
Unfortunately, implementing even some of this clever functionality is well out of the grasp of our DIY project. We’re going to be using a simple IR-emitter and IR-detector setup, which detects when an object passes between them. This prevents our project from differentiating between different types of coins, so if we want to only accept 20-cent coins, we need to design the coin slot with this in mind!
The only real way we can regulate the coins that are inserted into the machine is by changing the width and height of the coin slot itself – this will ensure that only 20 cent-size coins or smaller can be inserted. Therefore, 50 cent (diameter too large) and 1 or 2 dollar coins (too wide) can’t be inserted into the device.
The Fundamental Build: Testing Circuit
Parts Required: | Jaycar | ||
---|---|---|---|
1 x Arduino Nano or Compatible Board | XC4414 | ||
3 x FEETECH FS90R Micro Continuous Servo | - | ||
1 x 3x4 Matrix Keypad | - | ||
1 x 10kΩ Resistor * | RR0680 | ||
1 x 200Ω/220Ω Resistor * | RR0680 | ||
1 x Reflective Infrared Sensor * | - |
* Quantity shown, may be sold in packs. You’ll also need a breadboard and prototyping hardware.
To make sure the electronics chosen for this project will work as expected, we’re building a functional prototype on a breadboard.
This step is optional but if you’re interested in how the circuit works and why we’ve chosen these specific parts, read on!
Coin Detector
There are many different parts you could choose to accomplish the task of detecting passing coins, but we’ve chosen the ITR2001/T optical sensors from Adafruit. While these units may look a little intimidating with the four pins on the bottom, it really is just an infrared LED and a photodiode sensitive to IR light. To hook up the infrared LED, simply connect a 200Ω (or the closest size you have available) resistor in series with its anode and cathode – as you would with any other small hobbyist LED.
When connecting the photodiode in series with a resistor, it acts as a voltage divider, allowing us to sample a voltage with our microcontroller. To hook it up, connect one end of a 10kΩ resistor to 5V and the other end to the collector of the photodiode. The emitter of the diode can then be connected to ground. Then, all that is left is to just connect an Arduino analogue pin to the centre of the divider – between the photodiode and resistor.
To test if the circuit is working, you’ll need to hook up the output of the voltage divider to a multimeter or write a plotting program on your Arduino to ensure that the voltage divider responds to light changes.
By the way, you won’t be able to see the purple-tinted infrared light as can be seen in these photos – the spectrum the LED produces is out of the wavelengths that can be observed with the naked eye. However, your phone or DSLR camera will be able to pick it up – they are receptive to near-IR light, hence why you can see them here. You can use this trick to figure out whether the IR LED is working correctly – it also works for other devices like your TV’s remote control!
Since the photodiode is not sensitive to only IR light, you will notice that the circuit responds to lighting changes within your environment, but much less than infrared lighting sources, especially so if they are nearby. To test that the circuit is working, compare the difference between a black object – preferably the black 3D printer filament you plan to print with – and a 20c coin. As expected, the closer these objects are, the more significant the voltage change is in relation to the normal environmental reading. Since the coin is much more reflective than the black filament, you should find that the voltage readings between these objects are drastically different.
Rack Servos
The servos we are using for this project are physically identical to standard tower micro servos available for robotics and general controlled movement. However, since ours are continuous rotation, these servos will continually rotate in a given direction and speed when given a signal from a microcontroller. They are also wired identically to any standard tower servo, requiring a 5V, Ground and Signal wire. To connect it on our breadboard, we connect the ground and 5V to the long breadboard rails and the signal to analogue pins A1, A2 and A3.
Keypad
We’re going to hook up our 12-button keypad to our fundamental prototype to check it is capable of providing the user input we require of the project. The one we’ve chosen is the Adafruit 3x4 Matrix from Core Electronics, but there are many similar keypads that have very similar or identical dimensions and pinouts.
It’s worth noting that there are official and unofficial Arduino libraries available for handling these matrix keypads, but we’re going to implement our own code since the task of handling multiple rows and columns in this manner is a very common one in the electronics world. Our code won’t be as functionally advanced as these libraries but will accomplish the same task of recognising user inputs with roughly the same performance. If you don’t fancy digging into the low-level electronics of how it works, you can either pop our code into your project or download the Keypad library from the Arduino Library Manager.
It’s actually very important that the digital pins for this project are initialised appropriately. As discussed many times before in DIYODE, a pin that doesn’t have the correct pullup or pulldown resistors can cause major problems for reading digital pins. When the pin is not ‘connected’ to any voltage, such as when no buttons are pressed in a row or column, we don’t reliably know the state of our pins. The result is an intermittently fluctuating pin, creating unreliable results. For this reason, we are initialising our column pins as INPUT_PULLUP and our row pins as OUTPUT within the Arduino IDE. While we could our own external pulldown or pullup resistors, the 20kΩ pullup resistors built into the ATmega328 are strong enough for our purposes. The only hurdle with using the internal pullup resistors is that we need to invert our digital reading code – LOW (0V) is actually when the button is pressed, and HIGH (5V) is when the button is left untouched.
for(int row = 0; row < 4; row ++) {
pinMode(9 + row, OUTPUT);
digitalWrite(9 + row, HIGH);
}
for(int col = 0; col < 3; col ++) {
pinMode(6 + col, INPUT_PULLUP);
}
With our inputs correctly initialised, we can then work on implementing our method that will test whether any buttons are pressed. If no buttons are pressed when the method is called, it will return -1, and will otherwise return an index between 0 and 11 representing the button that has been pressed. To begin, we iterate over each of the four rows in our matrix keypad, setting each row pin to LOW. We then wait a short amount of time to ensure that the pin state has stabilised – considering that there can be some residual capacitance when dealing with button presses – and then scan through each column to see whether any buttons have been pressed.
If we read any column as low, this means that the row connected to this column is connected and hence the button has been pressed. So, we’re looking for a digitalRead of LOW, which is why we have an inverting ‘!’ in front of our digitalRead. In the case that we successfully find a location where a button is pressed, we can then translate it into the index where the button is located and set it to ‘i’. If no columns were read as LOW, we set the row back to HIGH and move onto the next row.
int get_button_pressed() {
int i = -1;
for(int row = 0; row < 4; row++) {
digitalWrite(9 + row, LOW);
delayMicroseconds(10);
for(int col = 0; col < 3; col++) {
if(!digitalRead(6 + col)) {
i = row * 3 + col;
}
}
digitalWrite(9 + row, HIGH);
}
return i;
}
To help illustrate what is going on here, we used a quad-channel oscilloscope to plot the states of our row pins as the code scans through each. You can see above that each row is temporarily set to LOW and then back to HIGH again – in this time, the microcontroller is scanning through each of the three columns to test whether the resulting low voltage was detected on the column pins.
The Main Build:
Now that we’ve tested all of our electronics, it’s time to work on the Main Build!
The Main Build is electronically identical to the fundamental build, with the addition of 3 more servos, some status lights and some code to get it all running together.
Parts Required: | Jaycar | ||
---|---|---|---|
1 x Breadboard Layout Prototyping Board | HP9570 | ||
1 x Arduino Nano | XC4414 | ||
1 x 40-pin 2.54mm Female Header | HM3230 | ||
1 x 40-pin 2.54mm Male Header | HM3212 | ||
6 x FEETECH FS90R Micro Continuous Servo | - | ||
1 x 3x4 Matrix Keypad | - | ||
2 x 5mm LED Holders | HP1102# | ||
Mini USB Panel Mount Extension Cable | - | ||
1 x 10kΩ Resistor * | RR0680 | ||
3 x 200Ω/220Ω Resistors * | RR0680 | ||
1 x 3mm Clear Acrylic Sheet (min. 14cm x 10cm) | HM9509 | ||
8 x M3 Brass Inserts ^ | - | ||
1 x Reflective Infrared Sensor * | - | ||
1 x 1000uF Electrolytic Capacitors | RE6316 | ||
Solid-Core Breadboard Wire | WH3032 | ||
8 x 5mm to 8mm M3 Screws | HP0401 | ||
3x C-756 Compression Springs | Check your local hardware store. |
* Quantity shown, may be sold in packs. # While these holders will support 5mm LEDs, we have only tested the Core-Electronics LED holders in the main build. Others may differ in dimensions. ^ If using brass inserts. If not, use self-tapping screws that suitably fit into the diameter.
Arduino Control Board
In terms of soldering the control board for this project, we are choosing a slightly different approach rather than using a blank prototyping board and redesigning our circuit layout from the fundamental build. By using a solderable PCB breadboard, we can directly transfer our components from the solderless breadboard to what is essentially a prototyping board with exactly the same spacing and behaviour.
Compared to a prototyping board with individually solderable holes, this board makes mounting the servo headers in particular super easy. Since we need a shared 5V and ground line between all six servos, the two centre copper lines of the board can be used for these two connections with minimal soldering.
To begin, we soldered two rows of 18-long female headers spaced 5 holes apart, which will fit an Arduino Nano. We suggest soldering the rows with the Nano already in place to align the headers properly.
Next up, we need to add the headers for the six continuous servos that control the lolly racks. To do this, cut 6 lots of 3-wide male headers. This will create a 3x6 block of headers, which can be soldered one at a time vertically across the board. Since the order of servo pins is Ground, 5V, Signal, the first two columns of our header block need to be soldered to the 5V power and ground traces underneath. The remaining signal wires have their own vertical traces that we’ll connect to the Arduino individually later. If this is confusing, refer to the Fritzing diagram. We used the same wiring layout in Issue 26 for our Servo Power project for connecting multiple servos!
We’re not done with the headers yet! We still need to add three more sets of headers to control the other interfaces of our vending machine. The first and second sets of these headers are both three-long, and are for controlling our IR coin detector and faceplate LEDs respectively. We’ll get into the wiring shortly, but we just want to get all the headers soldered in before we start adding wires. The two three-long headers were added in between the Servo header block and the Arduino Nano. Each header pin should have its own row of copper trace, shown vertically in the Fritzing!
Finally, we added a 7-long header parallel with the Arduino headers that allow us to connect the 3x4 button keypad. There isn’t any careful placement tricks like with the Servo block, just solder in the headers to connect to pins D6 through D12.
To get started with connecting everything up, we’re going to add the resistors for our status lights. We won’t add the LEDs directly to the control board – they’ll be mounted on the front faceplate. We’re using standard 220Ω resistors, which will limit the LEDs to about 20mA of current. From pins D2 and D3, connect these resistors to the middle and right-most male headers. Remember, because we are using a prototyping board with copper traces, we don’t need to solder the resistors directly to the headers, just to the same trace! Finally, add a black wire or a solder joint to connect the left-most header pin to the centre ground row.
It’s a similar process for our infrared emitter and detector, with the exception that the IR detector needs to be connected in a voltage divider configuration. With a 10kΩ high-side resistance, the variable voltage drop of the detector will allow the Arduino Nano to accurately detect changes in voltage. We soldered a 10kΩ resistor to the left-most male header and from there, another wire to the female header where the Arduino Nano’s A7 pin connects. Like the LED headers, the IR emitter can be easily connected to the 5V rail by adding a 220Ω resistor. Finally, a black wire can be added to connect the middle pin back to ground.
We added a 1000μF decoupling capacitor between the 5V and Ground rails, near the servo connections. Instead of drawing a large amount of current from the Arduino’s onboard voltage regulator or the 5V USB rail, the servos can get access to energy by discharging this large capacitor.
Note: When testing the board, use a good quality 5V supply to provide a capable current supply to power the six servo motors. e.g. lab bench power supply.
Connecting the servo data wires is a fairly simple process, but follow the instructions carefully so you don’t have to de-solder everything and do it again! Refer to the Fritzing or the schematic if you need any clarification. The premise of this step is to follow each consecutive servo to the corresponding Analog pin on the Arduino – for example, Servo 1 is connected to Analog Pin 1, Servo 2 to Analog Pin 2 and so forth.
However, we found out that Pin A6 (and Pin A7 for that matter) on the Arduino can’t be written to as a digital pin – unfortunately, after we soldered the wire! To fix this, we added a bridging wire to connect pins A0 and A6 together, and instead used A0 to control the sixth servo. While the photos below show this small white wire, follow the Fritzing and instead wire the first servo to A0, the second to A1, and so forth. This is also reflected in the code provided in the project files.
Coin Detector
Our coin detector is very simple to wire up, considering that we’ve already done most of the circuitry on the main control board. To get it put together, use a stripped end of 3 female header wires and solder one to the two ground pins of the ITR2001/T detector/emitter. There is a small divot in the corner with the IR emitter's cathode lead, the two opposite wires to this is the Ground wire. Once the ground wire has been soldered, just connect the other two to the cathodes of the emitter and detector. Use heatshrink for protecting both the individual wires and the grouped wires, which will provide some strain relief once we insert it into the chassis.
3D Printing
The main enclosure consists of three parts – the main body, the faceplate, and the rear panel. The main body is the largest and is designed for the other components to screw directly into. It contains the mounting for the lolly rack servo motors, the coin slot and enough space to fit all of our electronics into.
The faceplate is the front panel that screws over the main enclosure, which holds the keypad, clear acrylic panel and status LEDs. The rear panel is the piece that screws on the back of the main enclosure to hold everything together.
The Faceplate
There are a couple of components that make up the faceplate, and so assembling it requires a bit of cutting, soldering and sanding. The first step to assemble the faceplate is to cut out the clear acrylic sheet that prevents your customers from shoplifting – i.e. just reaching in and pulling out lollies! Since the sheet won’t extend all the way to the bottom of the front window, the only way to get the lollies out is to pay for one and have it drop down to the bottom chute.
The dimensions we need for the rectangular sheet is 100 x 74mm, and 2-3mm thick will do the trick. If you have access to a laser cutter, consider using it as it’ll avoid the fuss of cutting and sanding the sheet to size. We’ve included an Adobe Illustrator file that can be exported directly to a laser cutter control program. If you don’t, don’t worry! Just use a blank acrylic sheet and cut it to size. We used a Dremel with a reinforced cutting bit, using eye protection and working in an area that we were willing to get messy. The acrylic throws up a rather large amount of shavings when cut, so be aware of what you have to clean up after.
After test fitting the sheet, sand down any sides to make it as close to square as possible. You may find the plastic slightly bowing by a millimetre or so when the acrylic sheet is inserted, however, this ensures that the sheet is held tight. If your 3D printer has trouble with overhanging prints like ours did, you may find that a 3mm sheet won’t sit properly flush due to excess plastic. You may need to sand down both the bottom and the sides of the plastic lip for the acrylic sheet to get it to properly fit. Ideally, it should sit snugly without the risk of being pushed back into the machine.
Next up, we’re going to insert the keypad for selecting lollies. The dimensions we chose for our keypad fit very well into the faceplate, but depending on the tolerance of your printer and its printing inaccuracies – e.g. “elephant footing” – you may have to pull out some files and sandpaper to get it fitting properly. While ours did fit with a reasonable amount of pushing force, the keypad tends to fall out of the faceplate. We fixed this by adding a strip of duct tape across the back of the keypad before screwing it onto the main chassis.
We’ll add the status lights on the faceplate next, which indicates whether we’ve inserted coins in the machine and whether our payment was accepted. We used a 5mm yellow LED for the “current credit” of the user, which will glow when there is at least 20c of credit left in the machine. A 5mm green LED will also be used, illuminating when a lolly is currently being dispensed.
As our Arduino control board already has the current-limiting resistors and ground connection for these LEDs, it is as simple as connecting three wires to their leads. The LEDs will be set up to have a common cathode, meaning their shorter cathode (negative) leads will be soldered together. The two anode (positive) leads will be connected separately to two digital pins.
To secure the LEDs properly in the holes, we’re using two 5mm LED holders that will both provide a nice bevel and take some structural strain off of the LEDs. When inserting, be sure to position their cathode leads towards the centre and the anode leads downwards.
Three wires can then be soldered to the LEDs, with female Dupont headers on the other end. We also used heatshrink in an attempt to insulate the leads, but there is still some bare metal showing on the ground wire.
LEDs, especially when mounted in a panel, are notorious for breaking their leads, particularly when moved around frequently. To help reduce the chances of this occurring, and hence having to disassemble the entire project, we added an adhesive cable guide and a zip tie facing upwards for strain relief. This way, even if we move the end of the cable around to connect to the main Arduino board, the zip tie should prevent too much stress on the LED leads.
Main Chassis
Now that the faceplate is all finished, we can work on the main chassis to insert the control electronics.
Assembling the Lolly Racks
Our vending machine uses six individual lolly racks, which are essentially small compression springs available from your local hardware store, cut in half and stuck to a 3D-printed base. We sourced three sets of C-756 springs from Bunnings Warehouse, but we encourage you to look around and find some springs that will suit your lollies. You may want to design and print your own 3D-printed mounts that will work with your springs and mount them to the heads of the servos.
Once you’ve got the springs of your choice, stretch them to comfortably fit the lollies you wish to use. They should be tight enough that they don’t fall out just by wiggling the spring around, but loose enough so that the lolly can easily make its way through the spring with minimal torque. Keep in mind that a micro servo needs to be able to rotate against the force of four to five lollies resisting the movement.
If you find that the springs you are using aren’t deforming significantly from stretching by hand, you may need to use an intense heat source to do so. A micro blow torch will work well for this, which will reform the metal and make it more convenient to work with. Once heated up, it can be worked to expand it to a suitable length. As with any work involving heat sources, make sure that the metal has fully cooled before touching it – dangerously hot materials may not be glowing red! Take care and avoid burns.
We then cut our springs in half using a Dremel with a rotary bit and made sure they fit appropriately into the enclosure. If the springs end up sticking out too far, you may find that lollies from the shelves above will get stuck on the protruding spring when falling.
After the springs are finished, we can then work on fixing the springs to the servo heads. We modelled a small disc-shaped 3D printable mount that makes it easy to push in a spring and stick it onto the horns included with the micro servos. After printing six of these mounts, use superglue to mount the springs into the groove, ensuring that the springs point as straight as possible upwards.
Once the superglue holding the spring is dry, do the same with the circular plastic horns, sticking it in with a small amount of superglue. Note that if you do not have the circular horns, the other cross-shaped horns can be used if the ends are cut off as shown below.
Awesome, but before we insert our spring racks we need to mount the servos that will actually hold them! The chassis mounts for these servos should have sufficient tolerance to snugly them in, but since our printer had some problems with the plastic melting and expanding on the first layer, we had to sand some of the edges down.
While we have included screw holes for the servos, we didn’t worry about using them as there seemed to be enough grip to keep them in. If yours are loose, use the included self-tapping screws to hold them into the plastic.
After all the servos are mounted, use some cable ties to keep everything neat and tidy. We routed our cables upwards which would keep them out of the way of the coin tray. Finally, pop in your spring racks! We found the springs were just wide enough to be able to push a finger through the centre and press until the horn clicks into place.
Mounting the Control Board
On the home stretch now! We now need to mount the Arduino control board, which we’ve conveniently added a bevelled rectangle for in the main chassis, behind the keypad. Use some double-sided tape (or any non-conductive adhesive method you prefer) to mount the board with the Arduino’s USB port facing downwards. We also suggest connecting the servo wires, the keypad and the IR detector wires before doing this, as it is a lot easier when the board is outside the enclosure!
You may notice in the chassis 3D model we’ve moved the mounting rectangle up towards the roof of the vending machine. After connecting the mini-USB cable to the Arduino, we found that its length interfered with the coin tray below. The adjustment to the model should fix this issue.
Alright, all we have to do now is to mount the faceplate! After you’ve connected the keypad wires to the keypad and the status lights to the control board, peel off the protective tape and push it onto the enclosure. While our models should support M3 brass inserts, we did not have any on hand at time of building, so we used self-tapping screws instead. Bear in mind self-tapping screws are not the best option due to the thread degradation associated with them – especially when using plastic. If you do choose to use brass inserts, check the diameter of the hole matches the inserts you are using and drill out if necessary.
Rear Enclosure
The rear enclosure cleans up the aesthetic of the project, hiding the ugly wires. It also houses the Mini-USB extension cord to provide power and programming ability to the microcontroller. The extension cord is a panel mount cable, so simply use the included screws to secure it to the included mounting holes on the rear enclosure.
The rear enclosure can now be screwed onto the main chassis, again using either self-tapping screws or M3 screws with brass inserts. Make sure as you are doing this that you aren’t interfering with any of the moving parts of the vending machine – cables in the way of the coin tray or slot will cause problems with operation, for example.
Coin Tray
The tray we’ve designed sits in the bottom-right corner of the machine and can be emptied out at any time by simply unhinging the padlock, sliding out the tray and tipping the coins out. The size of the collection tray should be big enough to hold coins from when the machine is completely stocked to completely empty – which should net you a total of around 24 twenty-cent coins, totalling to a healthy $4.80!
The Code
With our vending machine put together, it’s time to add the code to our Arduino Nano. As usual, we’re using the Arduino IDE to write and upload our program. We’re only using the default Servo library here, as we’re writing our own functionality to control the vending machine. The library and setup definitions are shown below. The full code file is too long to include here, hence why we are only showing the most important snippets – if you wish to view or upload it yourself, head over to the Project Files.
#include <Servo.h>
#define NUM_SERVOS 6
Servo servos[NUM_SERVOS];
int servo_pins[NUM_SERVOS] = {A1, A2, A3, A4, A5, A0};
If you’re using a larger vending machine with more lollies, go ahead and increase the definition of NUM_SERVOS, as well as adding entries to the servo_pins array.
The servo_pins array will depend on the order of your servo data pins from Analog Pin 0 to Analog Pin 5. Because we weren’t aware that pin Analog Pin 6 was read-only during the main build, we had to reroute its connection to A0. Therefore, the last servo on the block is listed last on our array as A0. In the code we’ve provided in the project files, we’ve listed the analog pins A0-A6 in order unlike what’s shown above. If you’re using different pins for controlling your servos, or a different Arduino board entirely, you may need to rename these pins in order of your first to last servos.
Detecting Coins
Next, we need to write the code for registering when the IR detector reads an incoming coin into the slot. Since we’re reading the state of the IR detector as an analogue signal, we need to filter and correctly handle this data to both avoid false positives (detecting a coin where there isn’t one) and avoid false negatives (not detecting a coin when there is one).
To begin, we read our analogue signal from pin A7 – a 10-bit value from 0 to 1023 – and test whether the value reaches above our threshold value. If this is the case, we can assume that the nearby IR emitter’s light is reflecting off a passing coin and hence raising the reading value of our sensor. Depending on exactly how your IR detector is positioned, how reflective your 3D printer filament is, and even how clean your 20c coins are, there is no one size-fits-all method for this threshold value – you will likely need to change the global “coin_threshold” variable to make your coin system work reliably.
However, this introduces a problem. If we observe the raw 10-bit readings from the Analogue pin using a simple Arduino program, there are multiple signal peaks from the same coin. The graph below shows 3 consecutively inserted coins into the machine.
If we wrote code that only operates on the threshold of the IR detector, crediting a 20c coin each time into the program’s memory, we could experience multiple coin detections in the space of a single coin falling through the slot. To rectify this issue, we added a debouncing feature that prevents the further reading of any more coins for a short amount of time – 500ms seems to work well in our case. This is what the last half of the IF condition handles in the code below – testing whether the last time a coin was recorded was more than half a second ago.
Note: Be aware that if you assign an “int” variable to the value of millis() (the current program runtime) as we are doing below, it will default to a range of only about 33 seconds (2^15 milliseconds) as the maximum reading. You must define last_coin_timestamp in this case as an “unsigned long” variable so we can handle times up to about 50 days.
int coin_value = analogRead(A7);
if(coin_value > coin_threshold &&
abs(millis() - last_coin_timestamp)
> coin_debounce_time) {
last_coin_timestamp = millis();
coin_credit++;
Serial.println("New credit: "
+ (String)coin_credit);
detect_coin();
}
While there are likely more robust solutions involving running averages or data deviation, this is a simple method that can be used to trigger actions based on just about any analogue data source!
Handling Credit
We can’t let our customers just press buttons and grab whatever lollies they want! We need to implement some code to make sure they pay for whatever lollies they select on the keypad. This is what the code below is responsible for.
if(last_pressed >= 0 && last_pressed <= 5 && selected_lolly != last_pressed) {
selected_lolly = last_pressed;
Serial.println("Selecting Lolly "
+ (String)selected_lolly);
Serial.println("Checking credit...");
if(coin_credit > 0) {
Serial.println("Dispensing Lolly "
+ (String)selected_lolly);
coin_credit--;
Serial.println("New credit: "
+ (String)coin_credit);
dispense_lolly(selected_lolly);
} else {
Serial.println("Not enough credit.
Insert more coins.");
flash_no_coins();
}
}
selected_lolly = -1;
You will notice we are tossing around the variables “last_pressed” and “selected_lolly” a lot in this code. These two variables effectively detect changes in button states – i.e. when the user presses a button. If we dispensed lollies without this state detection, customers would accidentally purchase thousands of lollies in a split second! By comparing the states of these two variables, both of which change during our loop program, we can detect when we press or release a button, rather than continuously hold it. Since we have only six lollies in our vending machine, we’re only interested when the user presses any of the buttons between index 0 (Number 1) and index 5 (Number 6).
Once we’ve figured out which lolly the user wants, we then check whether they’ve added enough coins. Since our machine allows users to first insert multiple coins and then select multiple lollies, we need to keep track of the credit. If the user has 0 credit, they’ve exhausted all of the coin credit they’ve inserted, and so we rapidly flash the yellow status light at them.
Dispensing Lollies
After we’ve checked the user is paying up, we now can dispense the lolly they’ve requested! We turn off the yellow status light and turn on the green status light to let the user know the machine is working. We can then get the servo that corresponds to the requested lolly rotating anti-clockwise. Since 90 is the “zero” point for continuous servos, we need to add a small offset to 90 to get it to move. The faster the dispensing_speed variable is, the faster the servo will move and the more inaccurate it may be. We chose quite a slow rate to get as close to a full rotation as possible. The delay(1600) function can be modified to increase the rotational distance – we suggest experimenting until you find a value that reliably dispenses lollies. Since this machine isn’t perfect and tends to over or undershoot the distance often (each servo is likely to be calibrated slightly differently), we suggest leaving it on the side of the customer possibly receiving two lollies rather than none. Unhappy customers are not repeat customers!
void dispense_lolly(int lolly) {
digitalWrite(3, LOW);
digitalWrite(2, HIGH);
servos[lolly].write(90 + dispensing_speed);
delay(1600);
servos[lolly].write(90);
digitalWrite(2, LOW);
}
Finally, we stop the servo and turn off our green status light.
Testing
To load the vending machine, we set up some functionality in our code to change to “Loading Mode” after 1.5 seconds of holding the asterisk button, which causes the yellow and green lights to flash rapidly. We then held each button corresponding to servos to run them in reverse, loading lollies as we held them next to the racks. After we loaded all six racks up, we screwed back on the faceplate with the acrylic cover added and tested it out! Just connect any powered mini-USB cable to the rear of the vending machine (we recommend a phone charger for 5V power capable of reasonable current) and pop in a 20c coin to the vending machine. The yellow light should start glowing softly, and then it’s just a matter of choosing your favourite lolly and pressing the corresponding button – the servos are in reading order from 1 (top left) to 6 (bottom right).
We also tested inserting multiple coins and selecting multiple lollies, which is handy when you want to dump some coins out of your wallet! This worked without any issues. One problem we did have was that when several coins have already been inserted into the machine, occasionally a coin refuses to fall horizontally into the coin tray and obstructs further coins from being fully inserted. A little bit of “percussive therapy” should help with this – just shake the machine! This fixed virtually all problems we had with the coin tray.
What’s handy about having a direct mini-USB connection to the Arduino Nano is that there isn’t any need for disassembling the machine when reprogramming is desired. Just plug the mini-USB cable into your computer and open up the Arduino IDE.
Where To From Here?
While we designed this machine to support our favourite lollies in a small package, there is a lot you could do to spice up the project! The most obvious improvement to the machine is adding more lollies. Since we’ve included a twelve button keypad in the project, you could double the width or height of the vending machine with your own 3D model and add a much greater variety of lollies.
It would also increase the amount of sellable stock, decreasing the time between restocking the racks and therefore increasing your profits!
If you’re feeling adventurous, it may be worth looking into upgrading the payment system for the project. Right now, the payment system can’t differentiate between various coins so it adds 20c of credit no matter what. There are coin acceptors available from electronics retailers that could be used to securely identify specific coins!
Lighting makes a huge difference to the products customers buy. Why not add a multicoloured LED strip to the interior of the vending machine? A slowly-changing rainbow LED strip would draw plenty of attention to the lollies inside! A NeoPixel strip would do the trick, and could be connected directly to the Arduino Nano using a single digital data pin.
Besides adding more features, there are also some functionality improvements that could be made to the machine to increase reliability. Most commercial vending machines have an optical sensor placed near the bottom collection bucket that detects whether a product fell. The benefit of this is that the machine knows whether a lolly was successfully dispensed or not. Problems such as no stock in a certain rack slot, a stuck product, or a malfunctioning rack prevent the customer from being charged credit. This would be an awesome addition to this project and would also make the code closed-loop – the servos could have feedback and will only stop when a lolly has been detected falling out of the machine.