Introduction: Android-Controlled Pneumatic Cannon Powered by Arduino
The project entailed a pneumatic cannon with valves controlled electronically. When the cannon electronics receive a certain message over Bluetooth, the appropriate barrel fires. On the other side, an Android app uses the phone's Bluetooth modem to send messages to the cannon. This approach allows the cannon to be fired from around a 30-foot range, line-of-sight.
Here is a brief video describing what we'll be making:
We started the project on a Friday night and finished the bulk of by Saturday night. We worked pretty much non-stop, and all had experience working on this kind of stuff. With that said, we'd recommend carving out a whole week if you're working on this by yourself. So now that you're enticed beyond your wildest imagination, let's get started.
Please remember to be safe while building and using this device. You are entirely responsible for what you do with this information.
Step 1: Shopping List
Here's a list of all the parts you'll need:
Arduino Uno (1x, $29.95 each)
BlueSmirf Silver Bluetooth Modem (1x, $39.95 each)
Male Break Away Headers (1x, $2.95 each)
Solid Hookup Wire (1x, $10.95 each)
150-psi Inline Sprinkler Valve (2, $11.99 each)
Bicycle Tire Inner Tube (2x, $3.99 each)
6" x 4" x 2" Project Box (1x, $5.29 each)
SPST Relay (2x, $3.19 each)
Breadboard-Style Prototyping Board (1x, $2.19 each)
2" Diameter PVC
3" Diameter PVC
1" Diameter PVC
2" PVC Endcap
2" PVC Elbow
3" to 2" Reducer Bushing
1" Schedule 40 PVC Adapter
3" to 2" PVC Adapter Coupler
2" 45 degree PVC Coupler
PVC Primer and Cement
You'll also need some tools:
Soldering iron with solder
Solder sucker (unless you're really good)
Flush cutters (optional, for a professional finish)
Heat gun and heatshrink tubing (optional, for a more durable finish)
Also, please note that you can get ranges up to 350 feet if you are willing to spend an extra $25 on a Bluetooth modem, assuming your phone's hardware also supports that range. The BlueSmirf Gold is also available from SparkFun with a very similar interface. Please note, however, that the pin order is slightly different between the silver and gold models. It shouldn't be too bad to convert from one to the other though.
Step 2: Hardware Is Red, Software Is Blue...
We built a cannon, and so can you!
If you like block diagrams, you can think of our project like this.
Step 3: Build the Cannon
**Safety Note: PVC is not designed to be used with air pressure. If the PVC is damaged and air pressure is applied, the PVC can explode releasing shrapnel. For this project, we would recommend using a tank designed to hold air pressure. If you use PVC, you do so at your own risk**
On these tanks we used bicycle inner tubes with Presta valves. Presta valves were chosen primarily because we already had a good bike pump designed to use Presta valves, however, the locknut they include also makes it easier to secure them when building the tank.
1. Drill a 1/4" hole in the center of the 2" PVC end cap.
2. Cut out the valve from the bicycle inner tube. Cut the tube so a 1 1/2" diameter rubber circle remains around the valve.
3. Apply plastic epoxy to the rubber around the valve, and to the inside of the endcap.
4. Push the valve through the hole you drilled in the end cap, with the valve pointing away from the end which will be glued to the pipe. Make sure the epoxy forms a good seal the whole way around the rubber.
5. Ensure that there is no epoxy on the screw at the top of the Presta valve.
6. Try to get epoxy into the drilled hole, between the PVC and the threads on the valve.
7. Screw down the Presta locknut, holding the valve in place while the epoxy cures.
Once the valve is installed, you can begin building the cannon.
1. You will need the following lengths of PVC per barrel:
1 - 18" piece of 2" PVC
1 - 12" piece of 2" PVC
3 - 4" piece of 2" PVC
2 - 2" piece 1" PVC
1 - 18" piece of 3" PVC
2. We will begin at the end with the valve you just installed, and work our way to the barrel.
3. When using PVC cement, always apply the primer to both pieces, then apply cement to both pieces. Quickly push the pieces together, and rotate the joint 45 degrees while continuing to hold them close for 30 seconds. Rotating the pipe ensures good coverage of the cement, and you should hold the parts to ensure the cement does not push the apart. Never use PVC cement in a poorly ventilated area.
4. Glue the endcap with valve installed onto the 18" piece of 2" PVC.
5. Glue a 2" coupler onto the other end of the 18" PVC.
6. Glue a 2" to 1" reducer bushing into the other of the coupler.
7. Glue a 2" piece of 1" PVC into the reducer bushing.
8. Glue a 1" PVC adapter onto the 1" PVC
Now, working the barrel bend:
9. Glue the 2" to 3" PVC adapter coupler on one end of the 18" piece of 3" PVC.
10. Glue a 4" piece of 2" PVC into the other end of the coupler.
11. Glue a 45" coupler onto the other end of the 4" PVC.
12. Glue a 4" piece of 2" PVC into the other end of the 45" coupler.
13. Glue a 2" pvc 90 degree elbow onto the end of this piece.
14. Glue of 4" piece of 2" PVC into the elbow.
15. Glue a 2" coupler on the other end of this piece.
16. Glue a 2" to 1" reducer bushing in the coupler.
17. Glue a 1" piece of PVC into the reducer bushing.
18. Glue a 1" adapter onto the end of this piece of PVC.
If everything goes as planned, you should now have 2 PVC pieces: a pressure tank and a barrel.
1. Remove the solenoid (black piece) from the inline sprinkler valve.
2. Apply teflon tape onto the ends of both threaded pieces of PVC.
3. Screw both pipes into the valve. Be sure air will flow through the valve in the direction of the arrows located on the bottom of the valve.
4. Make sure the seals are tight, and adjust their orientation to ensure the cannon is pointed in the desired direction.
5. Reinstall the solenoid valve.
Repeat the previous steps again to build the second barrel.
You are now ready for the controlling electronics!
Step 4: Solder Your Board
The purpose of the board is to hold all the necessary electronics that aren't available on the Arduino. This amounted to the power units, Bluetooth modem and two relays. Here's what you need to know about each component:
The Arduino is capable of running on any DC voltage from 7 to 12 V, but the valve requires at least 24 V to operate. As a result, we decided to make one power unit for each device. The Arduino was powered off a 9V battery. To get enough voltage to drive the valve, we wired three 9V batteries in series (9V * 3 = 27 V).
We cut off six of those male breakaway headers, and soldered them onto this board. Then, we soldered the other side of the headers to our prototyping board. To make connections to the Arduino, we soldered one end of the wire in the same column as each of the pins on the Bluetooth modem, and plugged the other end into the corresponding Arduino port. On an Arduino Uno, here are the connections you'll have to make:
VCC on the BlueSmirf to 5V on the Arduino
GND on the BlueSmirt to GND on the Arduino
TX-0 on the BlueSmirt to RX (digital pin 0) on the Arduino
RX-1 on the BlueSmirf to TX (digital pin 1) on the Arduino
These connections are fairly straightforward. The VCC and GND pins power the board. The TX and RX pins are swapped (TX connected to RX and RX to TX) because the Arduino listens to what the Bluetooth modem says, and vice-versa.
Also keep in mind that the Arduino Uno only has one hardware serial port. That means that using the Bluetooth modem will take out your USB debug logging. If this is a real problem for you because you absolutely need to be able to collect debug logs while the Bluetooth modem is active, consider moving the Bluetooth modem to other pins and using the SoftwareSerial library. Alternatively, you can buy an Arduino that has multiple hardware serial lines, such as the Arduino Mega.
A relay is an electromechanical switch that allows you to control high voltages (27 Volts required by the valve) with low voltage control signals (5V provided by the Arduino). An image showing the innards of a relay is provided on this page.
The relays we used are single pole, single throw (SPST), which really just means that it acts like a switch. When the switch is closed, the valve is connected to the three 9-Volt batteries, and current can flow. When the switch is open, current cannot flow to the valve. To open the relay, apply 0V to it (digital 0). To close it, apply 5V (digital 1). Please note that this is only true for the relays we used, not all relays in general. Furthermore, our valve is normally closed. When the 27 V from the batteries is applied across it, then it opens and permits air to flow from the pressurized chamber to the barrel. As soon as the voltage is removed, the valve will shut itself again.
On an Arduino Uno, here are the connections you'll have to make:
Relay Power: 27 V signal
Relay Ground: Arduino GND pin (the Uno has two, so you don't have to mess with the Bluetooth's ground connection)
Left (maroon) control pin: digital output pin 6
Right (orange) control pin: digital output pin 7
Step 5: Pick a Profile
Among the three of us who worked on this project, we had the hardware to support both an Android and an iOS app. However, due to time limitations, we decided to only write one app. Furthermore, the Bluetooth modem we used supported the serial port profile (SPP) right out of the box. We wanted to use SPP for several reasons, not the least of which being that it's simple. Under SPP, the Bluetooth link acts just like a serial cable replacement. That means you can talk to the transfer and receive pins on the Bluetooth modem just like you would the corresponding lines on a physical serial cable. Furthermore, Arduino has dedicated hardware and a built-in software library for communicating via serial, and Android supports it as well. Since these three key components all supported the use of SPP, we went with that option.
On the other hand, no version of iOS supports SPP . Your next best bet on iOS would be the Human Interface Device (HID) profile, but you'll have to find a different Bluetooth modem, and probably write a lot more Arduino code.
Another cool thing to take into account is that since your phone is talking over Bluetooth, it is physically separated from the hardware that you'll be building. This is a good thing, since it means the odds of breaking your phone because of this project are essentially negligible. Unless, of course, you decide to go suicidal with the cannon. But let's assume you won't go there.
Step 6: Prepare the Android Development Environment
If you've already developed an Android app before, you may skip this step.
Otherwise, head over to Google's Android Development Setup Guide and follow their instructions to install the Eclipse IDE and Android plugin.
Step 7: Soup Up Your Phone
If you're not interested in developing your own Android app or learning how ours works, you can just download the attached application and deploy it from Eclipse on your phone. It seemed like too much of a niche target audience to release the app on the Android Market, so you'll have to install the application through Eclipse.
If you are interested in learning how the app works, read on. When the application launches, it will immediate try to connect to the cannon. For simplicity's sake, we hard-coded the MAC address of our BlueSmirf modem instead of developing a picker. This approach works, but it means you'll have to pair with the modem before launching the app.
To pair with the BlueSmirf from your Android phone, go to Settings >> Wireless & networks >> Bluetooth settings, and make sure Bluetooth is enabled. Then, tap "Scan for devices", and choose the BlueSmirf modem when it shows up (ours was named RN42-07EA). By default, the passcode will be either "1234" or "0000".
Now, back in the Android app, if the connection attempt times out, then the buttons will remain disabled. Pressing the menu button brings up the option to attempt to reconnect. This is convenient for when you're testing the range of your setup. Also note that it's important to make sure all the Bluetooth communication happens in a separate thread. Like most network operations, Bluetooth communication doesn't have many timing guarantees. On a typical microcontroller, you can usually guarantee that one instruction will execute in one clock cycle. However, in this case, the amount of time taken the establish a connection and send data depends on a variety of factors, including physical characteristics such as the distance between the transmitter and receiver, the radio interference in the room (which the BlueSmirf handles by a technique known as frequency hopping )
In order to get access to Android's SPP interface, we had to use some Java reflection to retrieve a member function. More information on this hack can be found in this detailed StackOverflow conversation , which we benefited from but did not participate in. If you come up with a better approach by analyzing the BluetoothSocket documentation better than we did, then feel free to leave a comment letting us know what you did.
Once the connection is established, the buttons are enabled. When a button is tapped, a byte is attempted to be sent over the network. The maroon button sends an ASCII character '1' (0x31 if you look at the individual bits), and the orange button sends '2' (0x32). This very well may be the simplest protocol you'll ever see in your life. If a data transfer ever fails, the buttons are disabled and the user is notified via a Toast message .
Step 8: Prepare the Arduino Development Environment
If you're already familiar with developing on the Arduino platform, then you can skip this step.
Otherwise, head over to Arduino's detailed tutorial , which will tell you everything you need to know to get started with Arduino.
Step 9: Program Your Arduino
If you plan on developing your own Arduino code, then it makes sense to develop it in conjunction with the hardware. That way, you can develop incrementally and test each component as you go. It makes debugging a whole lot easier than if you were to attempt to write the entire project at once and test at the end.
The entire Arduino source code is attached. If you're not interested in modifying it or learning how it works, you can just download and deploy it. If you'd like to see how it works, read through this step and then browse through the code.
Starting in evt_loop.cpp, the program first calls evt_loop_init. Then, it repeatedly calls event_loop_proc indefinitely, until the Arduino loses power. Looking at these two functions, you'll see that most of the Arduino code is centered around the idea of message queues . Message queues are useful in situations where one system needs to talk to another in an asynchronous manner. In our situation, we have a Bluetooth modem that can receive data at any time. In general, a lot of work goes into making sure that data never gets lost, regardless of what the device is doing when the message arrives. Thankfully, the Arduino Uno has a built-in 128-byte hardware serial buffer. Since each one of our Bluetooth messages are 1 byte, this buffer will probably be more than enough for our application. So our application sits in a loop, waiting for a message to come in from Bluetooth. In a commercial product, it is typical for the microcontroller to go into a low-power sleep mode here to save energy. For simplicity, we did not do that here (see bt.cpp's bt_wait_for_msgs function).
When a message arrives in the Bluetooth queue (see bt.cpp's bt_check_for_msgs function), the data is read in and added to a message queue dedicated to handling data coming in from the Bluetooth module. We do this because we wanted our microcontroller to be free to do other things when it's not processing messages. The message queue is like a mailbox. The next time the program gets a chance, it'll check the mailbox and see if there are any messages for it. Not using a message queue is like yelling loudly from across the room. In that case, everything would have to stop and immediately service the command before returning to what it was doing. The msgq_push function (defined in msgq.cpp) returns a variety of response codes (defined in msgq.h) that indicate a various number of queue conditions. For example, if the program never checked its mailbox, it is possible for this queue to fill up. In that case, the response value would indicate that the queue was full. This allows for error handling, which is an essential part of embedded system development.
Back in evt_loop_proc, the message is read into a local variable. Additionally, a pointer to a response type is passed in. The ampersand (&) before the variable rsp means that rsp's address in memory is being paseed into msgq_pop, as opposed to its value. If you haven't heard of this concept before, IBM knows a whole lot about it, and they'd love to divulge that information to you. This pointer tells msgq_pop a location in memory where it can put the response value. It's sort of like a way to get a function to return two values-- the message, and the status.
After taking the message from the queue (similar to taking the letter out of the mailbox), the response is checked. If the operation was not successful, the entire Bluetooth message queue is reset, and the program continues. There's not really a whole lot else the program could do in this state.
If the program makes it past that error back, it looks at the value of the message. If the message was a '1', it handles one relay. If it was a '2', it handles the other one. Anything else, and it ignores the message.
Our device did not have a pressure gauge, so there is no way for the Android app to know whether the canisters are pressurized or not. As a result, given enough pressurized air, it is possible for there still be enough pressure left to shoot twice without having to refill the tank. To account for this, the Arduino will automatically close the relay one second after it is opened. This prevents extra air from being wasted when the barrel is empty. The code that handles switching the relays is available in relay.cpp.
To handle this automatic closing, we use a timer. Most microcontrollers have hardware timers for high-precision timing, so this example is a good introduction. Take a look at timer.h and timer.cpp if you're interested in learning more about how the timer works. Once a valid Bluetooth message has been received, the corresponding relay is immediately closed (evt_loop.cpp's evt_loop_proc function), allowing current to flow from the battery to the sprinkler valve. Then, a timer is set to expire in one second (1,000,000 microseconds in the code). Then, the callback function is set to be evt_loop_handle_timer, which the timer module will call once the specified amount of time has elapsed.
Inside evt_loop_handle_timer, both relays are opened, which stops the flow of air from both canisters. We figured this would be the simplest approach to take. Once a command has been processed, evt_loop_proc is called again (from cannon.pde) and the process repeats.
Once your Arduino is programmed, it will automatically start running your program when you apply power via a 9V battery.
Step 10: Put It All Together
Program your Arduino one last time, and seal it up in its box.
Screw the valves into the canisters, and attach the barrels.
Connect the valve wires to their relays.
Pump up the canisters and test it out!
Step 11: Fire!
Now you have a ballistic projectile launcher ... cool! With much firepower comes much responsibility, so remember to be safe! Be smart about what you put in the cannon, and never shoot dangerous items at people, animals, or fragile items.
If you have any suggestions or comments, please feel free to let us know. Have fun and happy remote detonating!