The objective of this project was to create an Internet of Things (IoT) device that could give pet access to a food bowl when a text message command was sent from a remote location.
I had never done an IoT project before, so I wanted to keep the rest of the build relatively simple. I decided on a box with a sliding lid on top, into which a bowl of pet food could be placed. When the user wished for their pet to be fed, they would be able to send a command from their mobile phone, causing the box’s lid to slide open giving the pet access to the food bowl.
The project consisted of four main parts: The box, the drive assembly, the controller and the client application.
I wanted to the finished product to look nice, so I decided to build the box out of timber. I initially envisioned it having rounded corners and a varnished wood finish, but I ended up having to go with a simple rectangular box due to time constraints.
The drive assembly was another area that I had limited experience with, but I didn’t think it would be overwhelmingly difficult. I was wrong, but the initial design worked well enough. Its function was to move the wooden lid of the box from one side to the other.
The controller was the area that I was most comfortable with, especially considering the simplicity of the program. However, as previously mentioned, giving the project connectivity was new ground for me, and did prove to be the most difficult part of the project. Initially, I tried to use the GSM/LTE connection, but I was unable to get the module to work and ended up using wifi instead.
The client application was an addition to the project due to the need to access a system connected to the internet through a router with local DNS.
Parts List
- 2x Treated pine planks 19x235x2100 mm
- 1x Drawer sliders 300mm pair
- Plaster screws
- 1x Arduino Uno R3
- 1x ESP8266 Wifi Module
- 1x DC Motor Driver HR8833
- 1x Hobby Motor – Gear
- 2x Micro Switches
- 1x Set of Stacking Headers
- 1x 1 mm screws
- 2x Cans Spray Paint
Tools
- Drop saw
- Measuring tape and square
- Rasp
- Jigsaw
- 3D printer
- Various screwdrivers
- Laptop with Autodesk Fusion 360
- Drill with 3.2 mm drill bit
- Multimeter
Construction
Box
I sketched out the dimensions for the box and tried to make as many of the mistakes as possible on paper. I cut the plans to size with a drop saw. Everything fit together fine except for the sliding lid, which I had cut too narrow due to an incorrect measurement of the sliders.
Although I was going to glue everything together, I changed my mind at the last minute and opted for screws so that I could take panels on and off (a decision that I was very thankful for later on).
Overall the box design and construction was simple, but I spent some time on it so that all the sides joined up properly. The only tricky bit was cutting out the door in the side panel where the pet bowl is inserted. I made a few cuts with a handsaw and then used a (hand) jigsaw to cut finer lines and angles. I finally used a rasp and sandpaper get the edges straight and square. Granted, there are probably easier ways of doing this, but woodwork is not my forte and I was quite pleased with the outcome.
Drive Assembly
I designed the drive assembly with the following assumptions:
- The DC motor would be spinning fast and must be slowed down
- The sliding lid should offer minimal resistance
- The rack and pinion should have coarse teeth (I have no idea if this was correct, but it was my vibe and I went with it).
Based on these I came up with the design pictured below:
I started out with the measurements for the teeth on the motor’s spur gear and designed a compatible gear that would convert some of the motor’s speed into torque, and output a course-toothed rotation. I wanted course teeth so that the mounting precision of the unit (to mesh with the rack) wouldn’t be too critical.
Control
The control system (aka the fun bit) was comprised of an H-bridge motor driver controlled by an Arduino Uno, which interfaced to the world through an ESP8266 wifi module.
I started out by assembling the motor driver on a breadboard, along with a 5V power supply. There weren’t any hitches with that part, so I went ahead and copied the breadboard wiring into a diagram. Referencing the diagram, I transferred the components on veroboard and soldered them in. After I fixed my obligatory mistake of soldering the voltage regulator backwards the board worked fine. I decided to mount the motor driver in PCB header sockets so that I could change it out later if I needed to.
I attached two microswitches onto the lid. One was placed at each end of the lid in such a way that they would be triggered when the lid was fully open or fully closed. I soldered wires onto these and ran them to the Arduino. The microswitches provide some feedback on when the lid is open or shut.
The Blynk’s ESP8266 code didn’t work with the Arduino Uno setup I had. Changes had to be made to the Blynk ESP8266 example code, which I quickly learned through this thread:
Code
The code is essentially very simple. There are two functions: Open and Close and the Blynk function.
The Open and Close functions activate the motor driver, causing the lid to open for 500ms. If one of the microswitches is pressed during this time the motor will stop.
The Blynk function monitors the Open/Close button on the phone app and calls the Open/Close functions when appropriate.
The main loop calls the Blynk function and maintains the desired lid state by checking the microswitches every few milliseconds and activating the motor to correct any discrepancies (ie if the dog noses the lid open the program will immediately shut it again).
The code is a bit lengthy so I have attached it a the end of this document.
The Blynk App was about as simple as it gets, with a single button toggling to a ‘virtual pin’.
Full Code at the end of the project.
Testing
I tested the Blynk functionality using an ethernet shield that I had lying around. Once I got the ethernet library working the Blynk application was very straightforward. When the wifi shield arrived in the mail I exchanged it for the ethernet shield and changed the few lines of code.
All was going well until I pulled the USB programming cable out of the Arduino. I believe that the system had been drawing power from the computer as well as the 12 VDC I had plugged into the Arduino 12V jack. After I pulled the cable I assume all the current was drawn through the onboard voltage regulator, which was too much for it to handle and leaked the magic smoke.
Even though the board no-longer powered up from the 12V jack (the voltage regulator was visibly damaged) the rest of the circuitry was intact and I was able to power the board from the external 5V voltage regulator (which I had intended to be solely for running the motor), connected to the Arduino’s 5V pin.
There was also an open circuit in the veroboard where a copper track had broken and lifted, but after that was sorted out the system worked more or less as intended.
Tuning and Finishing
I ended up having to make some adjustments to the speed of the motor, as the lid rails were quite stiff at one end. I was never able to work out why this was, even though I completely took apart the rails and adjusted the spacing and placement. Getting the motor to run full tilt when opening gave the lid enough momentum to overcome the increased friction in the rails.
The friction in the rails on the opposite side is much less so I was able to get away with running to motor slower, which closes the lid with a little more grace.
I wanted the finished product to look a bit "sphancy", so I gave the box three layers of red spray paint. I was quite happy with how it looked, but since the red was very…there, I decided to make the lid a bit gentler by giving by sanding the plywood smooth and varnishing it. The varnished wood and red paint made a nice contrast.
Code
#define BLYNK_PRINT Serial // Define Blynk serial number #define SHUT 0 // Define the value for when the lid is shut #define OPEN 1 // Define the value for when the lid is open #define MIDDLE 2 // Define the value for when the lid is neither open nor closed #include // Library for using multiple serial channels #include <ESP8266_Lib.h> // Library for WIFI module #include // Library for using ESP8266 with Blynk char auth[] = "********************************"; // Blynk authentication key // WiFi credentials. char ssid[] = "*************"; char pass[] = "*************"; // Hardware Serial on Mega, Leonardo, Micro... #define EspSerial Serial1 // or Software Serial on Uno, Nano... SoftwareSerial EspSerial(8, 9); // RX, TX. This value had to be changed from the default 0,1 // ESP8266 baud rate: #define ESP8266_BAUD 9600 ESP8266 wifi(&EspSerial); // constants. They're used here to set pin numbers: const int openLimit = 2; // the number of the pushbutton pin const int closeLimit = 4; const int M1 = 3; // the number of the motor control pin const int M2 = 5; // the number of the second motor control pin // variables int openState = 0; // variable for reading the pushbutton status int closeState = 0; int desired_lid_status = MIDDLE; // The desired lid status is set when the user presses the Open/Close button on the Blynk app. After the desired state has been set, the device will strive to maintain this state /* Function for opening the lid of the box */ void open_lid(int motor_timer) { for(int i = 0;i < motor_timer;i++) { digitalWrite(M1, HIGH); digitalWrite(M2, LOW); if(digitalRead(openLimit)==LOW) // If the limit switch has been pressed (ie the lid is fully open) stop the motor { digitalWrite(M1, LOW); digitalWrite(M2, LOW); break; } delay(1); digitalWrite(M1, LOW); digitalWrite(M2, LOW); } } void close_lid(int motor_timer) { for(int i = 0;i < motor_timer;i++) // Run the motor for the length of time specified by the "motor_timer" variable { digitalWrite(M1, LOW); digitalWrite(M2, HIGH); if(digitalRead(closeLimit)==LOW) // If the limit switch has been pressed (ie the lid is fully shut) stop the motor { digitalWrite(M1, LOW); digitalWrite(M2, LOW); break; } delay(5); // Slow down the lid when closing Part I digitalWrite(M1, LOW); digitalWrite(M2, LOW); delay(4); // Slow down the lid when closing Part II. This is basically PWM } } /*Function to process presses of the "Open/Shut" button on the Blynk app */ BLYNK_WRITE(V1) { int pinValue = param.asInt(); Serial.print("pinValue: "); // For debugging only Serial.println(pinValue); if (pinValue == 1) // Check the value of the (virtual) pin { desired_lid_status = OPEN; // If the button value is high, set the desired status of the device to Open. open_lid(600); // Run the open lid function. The function will run the motor continually for 600 milliseconds before beginning a hunting routine. } if (pinValue == 0) // If the button value is low, set the desired status of the device to Closed { desired_lid_status = SHUT; close_lid(600); } } void setup() { //Debug console Serial.begin(9600); delay(10); // Set ESP8266 baud rate EspSerial.begin(ESP8266_BAUD); delay(10); Blynk.begin(auth, wifi, ssid, pass); // initialize the motor pins as an output: pinMode(M1, OUTPUT); pinMode(M2, OUTPUT); // initialize the pushbutton pin as an input: pinMode(openLimit, INPUT_PULLUP); pinMode(closeLimit, INPUT_PULLUP); Serial.println("status"); } void loop() { Blynk.run(); closeState = digitalRead(closeLimit); // Check the status of the close microswitch openState = digitalRead(openLimit); // Check the status of the open microswitch if((desired_lid_status==SHUT)&&(closeState==HIGH)) // If the lid is meant to be shut but for some reason it has been forced open: { Serial.println("Closing lid"); delay(100); // Wait 100 ms and close the lid. This will result in 100ms pauses between motor pulses. close_lid(10); // Run the motor for 10ms at a time. This value was found to effectively 'debounce' the lid, ie deliver such small amounts of movement that the lid dounced rebound when it hits the end of the box. } else if ((desired_lid_status==OPEN)&&(openState==HIGH)) // If the lid is meant to be open but for some reason it has been forced shut: { delay(100); open_lid(10); } }