Documentation for the second PiFace GungTank, as constructed at Susi's over the week of May 13th 2019!
Old documentation for the first version from 2013 is here
Instead of using an overhead motor to pull a plug like in the first version, v2 uses a linear actuator underneath the bucket to open and close a slide valve. This makes it much easier to reset and fill compared to the tangle of strings and wires that had to be dealt with before.
This diagram will win absolutely no awards, nevertheless:
The aim here is to have one single assembly that can be kept together and have it as easy to set up as possible, without having to connect and plug in a ton of different things in a strict order.
The main components we used are:
Component | Item Name | Source | Price |
---|---|---|---|
Actuator | TS-LD-50 | Stroke 50mm 2" Inch Electric Linear Actuator DC 12 Volt 100N High Speed 50mm/s | $35 |
Valve | Valterra RV Sewer - T1002VPM | Valterra Bladex Waste Valve Body for RV Holding Tank - Aluminum Handle - 2" Diameter | $12 |
Microcontroller | Element14 Raspberry Pi/PiFace | The original PiFace is no longer made, so I'm going to have to relearn all this if we ever replace it | $67 |
5V 2.4A power supply | Insignia NS-AC1U2M | Best Buy in the phone charger section | $25 |
12V 5A power supply | Genuine LW-065/500/120/001 | 12V 5A 5 amp 60W DC POWER Supply ADAPTER Transformer | $7 |
Bucket | It's a bucket | Just a Home depot one | $18 |
The mechanism is mounted on a 2'x2' plywood board and is made up of a valve mounted to the bottom of a bucket, with its handle connected to a linear actuator that is set up to be controlled remotely through the Pi. The valve is bolted to the base of the bucket with sealant around the bolts and a rubber seal between the valve and the hole.
The actuator is linked to the valve with a wire tied through the actuator's hole and around the valve's handle. It's fastened to the board through the bottom - we replaced a screw that didn't seem to be doing much with a longer one that could reach through the board to the other side. A 1" pipe bracket holds it in place from the top.
Because the new version uses a linear actuator instead of a simple motor, it has to be able to both pull the valve out and push it back into place. We're also using a 12V wall adaptor instead of relying on batteries, so no need to worry about fiddling with those. The circuit uses both the Pi's relays which are numbered 0 and 1, wired up like this.
The relay has two modes - when not powered (or turned off), the circuit will flow between C (common) and NC (normally closed). It's important to remember here that "closed" in this context means that it allows electricity through it like an open door or gate would, but let's not dwell on this. When turned on, the relays will instead close the circuit between C and NO (normally open), leaving NC open (by which I mean "closed").
This ingenious arrangement came from Shift Automation. To the best of my understanding, this is approximately what's happening here:
In these diagrams, C is on the bottom of the boxes representing the relays, NO is left and NC is right (same as if you were facing them). When both relays are off, the circuit is incomplete and nothing happens. When just relay 0 is on, the arrangement of the circuit causes electricity to flow through the actuator in one direction, and when just relay 1 is on, it flows the opposite way. (Having both relays on also leaves the circuit incomplete).
The positive (red) wire from the actuator is connected to the common terminal of relay 0 here, and the negative (black) wire is connected to common on relay 1. Most of the automation uses the words "push" and "pull" here with the assumption that they're connected this way around, and that pulling will open the valve. If the valve opens with a push, connect the wires the other way around.
Oh dear god don't ask. Getting wifi to work with the D-Link Complete Bastard dongle is by far the most painful experience of this entire process - I tried to set it up for ages and in the end gave up and had wicd-curses do it all for me, so I'm still not sure how it works. The entire wlan0 config in /etc/network/interfaces file is commented out - somehow, the Pi is set up on Susi's home network, with the DHCP for the router set up to assign fixed address 192.168.1.13.
So, to set this up again in the future on a different wireless network, attach a keyboard and monitor (or use the direct connection method below), then start it up and type wicd-curses to enter the wifi setup utility. It stores its settings in /etc/wicd/wireless-settings.conf or thereabouts, but don't touch that.
I've got the direct connection to a place where it sort of works, although I'm not sure how (the intricacies of Linux networking escape me). To use it, you have to connect the pi directly to your PC with an ethernet cable, set your ethernet settings as below (somewhere in Adapter Settings in Windows) so that you're on the same subnet or something, and then access the Pi at address 169.254.0.2. It should be responsive exactly one minute after plugging it in, for reasons described below.
The way this works is ramshackle at best - I couldn't find a way to initialize eth0 properly at startup, so what I've done is to add a line to the crontab to run sudo /gt/networkup.sh on boot. This script will sleep for one minute, then run sudo ifdown eth0 and sudo ifup eth0 to kick it into working. Monumentally stupid as it is, I couldn't find the exact bit of network interface configuration that would just do this at startup in a cleaner way, so that's how it's going to work for now.
All the scripts from the first version are now deprecated, and have been moved to /gt/v1. Instead of having to execute individual Python scripts to carry out commands, the Pi now just runs just one script on boot that will listen for commands being sent and react to each one. With the service already running, this means that there's no delay while a Python instance starts up - reaction is instantaneous!
The listening script is started by the shell script /gt/runlistener.sh, which is run on startup with a @reboot line in the root's crontab. Switch to root and use crontab -e to see it.
The shell script will initialize the PiFace somehow with some lines about modprobe and setting ownership and I can't remember what they do, then run /gt/listener.py in the background. This is the script that will stay alive and listen - it will flash the LEDs on the Pi in a pattern to acknowledge that it's started up, and then watch for changes to the modified date of file /gt/signal. When this modified date changes, it will check the contents of the file and react according to the string inside.
You can write a command to the signal file and have it picked up by the listening script by using echo "commandhere" > /gt/signal - this is how the endpoints do it.
These are the strings that you can pass into the signal file to tell it to do something.
Command | Effect |
---|---|
toggle0 | Toggles relay 0 |
toggle1 | Toggles relay 1 |
toggle | Toggles both relays (so if currently opening it'll close and vice versa) |
open | Sets relay 0 on and 1 off, making the actuator pull and open the valve. |
close | Sets relay 1 on and 0 off, making the actuator push and close the valve. |
burst | Sets the valve opening, delays 1 second and then closes it. |
stop | Turns both relays off, leaving the actuator where it is. |
ping | Turns LED 7 on and then off again, to check response. |
ping2 | Run the sequence of LED toggles that happens at startup - a more elaborate ping! |
The Pi is running an apache2 server with PHP to provide HTTP endpoints for interacting with the tank remotely. The www root directory is /var/www - going to the index here by typing the IP of the Pi in your address bar will land you on a leftover test page that prints out bananas.
The really interesting bit is [ipaddress]/gt/sendcommand.php, which is the endpoint to call to send a signal. The script looks at the query parameter c and writes its contents to the signal file described above - therefore, hit the endpoint [ipaddress]/gt/sendcommand.php?c=open to open the valve, or replace "open" with any of the other commands. A safeguard of checking the string against the list of possible choices is provided, to avoid making it possible to execute arbitrary shell commands here and format your hard drive.
The index page of /gt has a single button which will open the valve when pressed and close it when released - this calls the relevant commands by firing off AJAX requests to sendcommand.php when the button is touched or clicked. This is the most straightforward way to activate the tank, but the endpoint allows any kind of game to be hooked up to it.
/gt/eyespy.html is a start to the booths game from Eyespy.
/gt/initlistener.php is a script that runs the runlistener.sh shell script in case the listener is no longer listening. I think I just set this up temporarily while I worked out how to get the real listener going on reboot - I haven't ever had to use this.
Test 1 on May 16th 2019: Basically a great success! The actuator mechanism allows the valve to be pulled open and pushed closed with no signs of leakage when a full tank of water is used. The only flaw is from water splashing on to the wood (and, more to the point, the electronics) around the centre hole after dropping from the valve. We could try expanding the hole in the wood, but a pipe attached to the bottom of the valve might be even better.
Some notes on things I'd like to do to improve the interface - I'd like to make some games for this on the phone without having to use an external program
Use Websockets - https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API - to keep a connection open between the client and the server
With a monitor connected, the Pi could open a page that consults with the backend to display the current status of the game. At its simplest, display a page that just reacts to the current status of the valve (opening or closing). The page could just listen to the same signal file that we use to transmit the open/close command.
Use a "mode" file to tell the screen what game loop it should be running. Each game loop should check occasionally for this "mode" changing and go back to awaiting a new mode if it changes (clear the screen)