April Fool's Day with Bouncy Balls
- Posted: Apr 02, 2007 at 2:00 AM
- 599 Views
- 4 Comments
Loading User Information from Channel 9
Something went wrong getting user information from Channel 9
Loading User Information from MSDN
Something went wrong getting user information from MSDN
Loading Visual Studio Achievements
Something went wrong getting the Visual Studio Achievements
| In this article, Clint Rutkas builds a relay application that will drop 1,000 super bouncy balls from the ceiling as an April Fools gag! | |
|
Difficulty: Intermediate
Time Required:
3-6 hours
Cost: $100-$200
Hardware: Control Anything USB Relay Board, a drill, a ton of super
bouncy balls and some zippie ties
Download: Download
|
|
I'm tend to go a bit crazy when it comes to pranks. April Fool's day is almost like Christmas to me. So bombarding someone with 1,000 super bouncy balls seemed like the proper thing to do come the first possible moment.
But that someone was a bit harder than I thought. I needed a victim however but with how SpringCM's executive offices are designed, I quickly found him. My victim for this task is my CTO, Dave Dahl. I wasn't alone in this prank, I had my friend / co-worker, Andy Konkol, help out with the final assembly and testing of the application.
Here is the video of the final outcome over at YouTube.
You need a laptop, a rigging system, a WiFi network, a ton of bouncy balls, a drill, a spare ceiling tile, some string and a relay board. Here is the picture of the system finally done. The ceiling tile was modified with the sides shaved and gluing a piece of wood to the back to apply anchors into. To figure out how to wire up relay boards, I suggest reading Brian Peek's holiday lighting article. Brian provides diagrams and wiring safety information.
And we mustn't forget the balls. How does one buy super bouncy balls? It was surprisingly simple with Google and searching for "Super Bouncy balls". I got mine from Gumball Machine Warehouse for about $70 if memory serves. Each bag weights about 5 pounds I'd guess and is about a foot by a foot. Apply them gingerly onto the shaven tile since it isn't supported by the orginal 1/4" lip anymore.
Andy Konkol admiring the release rig. You can see we've mounted the drill to the fire system. You'll also notice the drill's trigger is tied down so all we need to do is hit the relay and the drill will be on.
So as every good programmer knows is to test often, and as this picture shows, it is well earned. Cleaning up the mess took about five minutes. A video of this test can be found over on YouTube. Since we didn't know how much it would hurt or cause damage, a human test subject was needed. I stepped up to plate and had the crap freaked out of myself even knowing the balls were going to be deployed.
![]()
The application is fairly simple and uses a Control Anything USB relay board and has a laptop placed on a ceiling tile. The laptop was left on and with Remote Desktop Connection, the application will be triggered.
I'm using the relay board for another project so currently it is a fairly simple codebase. This application was the test bed for the next project. How the relay board works is by sending a sequence of commands. 254 will prepare for a command, 29 then will turn all the relays off, 30 on. The Control Anything relay board has a host of other features I haven't had time yet to implement but will soon so you can check back for a richer API for the relay board. The company does provide Visual Basic 6 code examples and uses the chr$ command instead of a byte array.
C#
public bool AllRelaysOff() { ComPort.WriteBuffer(new byte[] { 254, 29 }); return relaySuccess(); } public bool AllRelaysOn() { ComPort.WriteBuffer(new byte[] { 254, 30 }); return relaySuccess(); } private bool relaySuccess() { return (ComPort.ReadBufferChar() == 85); }
VB
Public Function AllRelaysOff() As Boolean ComPort.WriteBuffer(New Byte() {254, 29}) Return relaySuccess() End Function Public Function AllRelaysOn() As Boolean ComPort.WriteBuffer(New Byte() {254, 30}) Return relaySuccess() End Function Private Function relaySuccess() As Boolean Return (ComPort.ReadBufferChar = 85) End Function
The comport code is actually a slightly refractored version from my dance floor application. The class itself is a wrapper for the .Net SerialPort object which can be found in System.IO.Ports. Furthermore, it now inherits off IDisposable to help auto close the serial port and is designed aimed to help ease use for multiple applications.
C#
public class ComPortIO : IDisposable { #region varibles public SerialPort ComPort { get { return _comPort; } set { _comPort = value; } } private SerialPort _comPort; public bool DoneWriting { get { return _doneWriting; } set { _doneWriting = value; } } private bool _doneWriting; public bool DisableWriting { get { return _disableWriting; } set { _disableWriting = value; } } private bool _disableWriting; #endregion public void Dispose() { if (ComPort.IsOpen) ComPort.Close(); } #region constructors public ComPortIO(string ComPortName, int BaudRate, bool DisableComWriting) { DisableWriting = DisableComWriting; if (!DisableWriting) { if (!doesPortExist(ComPortName)) throw new ArgumentException("The serial port used is not valid", ComPortName); ComPort = new SerialPort(ComPortName, BaudRate, Parity.None, 8, StopBits.One); if (!ComPort.IsOpen) ComPort.Open(); ComPort.ReadTimeout = 100; } } #endregion #region public functions public void WriteBuffer(char[] Buffer) { if (!DisableWriting) ComPort.Write(Buffer, 0, Buffer.Length); } public void WriteBuffer(byte[] Buffer) { if (!DisableWriting) ComPort.Write(Buffer, 0, Buffer.Length); } public void WriteBuffer(string Buffer) { if (!DisableWriting) ComPort.Write(Buffer); } public string ReadBuffer() { try { if (!DisableWriting && ComPort.IsOpen) { return ComPort.ReadLine(); } } catch (Exception) { } return null; } public int ReadBufferChar() { try { if (!DisableWriting && ComPort.IsOpen) { return ComPort.ReadChar(); } } catch (Exception) { } return -1; } public int ReadBufferByte() { try { if (!DisableWriting && ComPort.IsOpen) { return ComPort.ReadByte(); } } catch (Exception) { } return -1; } #endregion #region private functions private static bool doesPortExist(string ComPortName) { string[] serialPortNames = SerialPort.GetPortNames(); for (int i = 0; i < serialPortNames.Length; i++) { if (string.Compare(serialPortNames[i], ComPortName, true) == 0) return true; } return false; } #endregion }
VB
Public Class ComPortIO Implements IDisposable Private _comPort As SerialPort Private _doneWriting As Boolean Private _disableWriting As Boolean Public Sub New(ByVal ComPortName As String, ByVal BaudRate As Integer, ByVal DisableComWriting As Boolean) MyBase.New() DisableWriting = DisableComWriting If Not DisableWriting Then If Not doesPortExist(ComPortName) Then Throw New ArgumentException("The serial port used is not valid", ComPortName) End If ComPort = New SerialPort(ComPortName, BaudRate, Parity.None, 8, StopBits.One) If Not ComPort.IsOpen Then ComPort.Open() End If ComPort.ReadTimeout = 100 End If End Sub Public Property ComPort() As SerialPort Get Return _comPort End Get Set(ByVal value As SerialPort) _comPort = value End Set End Property Public Property DoneWriting() As Boolean Get Return _doneWriting End Get Set(ByVal value As Boolean) _doneWriting = value End Set End Property Public Property DisableWriting() As Boolean Get Return _disableWriting End Get Set(ByVal value As Boolean) _disableWriting = value End Set End Property Public Overloads Sub Dispose() Implements IDisposable.Dispose If ComPort.IsOpen Then ComPort.Close() End If End Sub Public Overloads Sub WriteBuffer(ByVal Buffer() As Char) If Not DisableWriting Then ComPort.Write(Buffer, 0, Buffer.Length) End If End Sub Public Overloads Sub WriteBuffer(ByVal Buffer() As Byte) If Not DisableWriting Then ComPort.Write(Buffer, 0, Buffer.Length) End If End Sub Public Overloads Sub WriteBuffer(ByVal Buffer As String) If Not DisableWriting Then ComPort.Write(Buffer) End If End Sub Public Function ReadBuffer() As String Try If (Not DisableWriting _ AndAlso ComPort.IsOpen) Then Return ComPort.ReadLine End If Catch End Try Return Nothing End Function Public Function ReadBufferChar() As Integer Try If (Not DisableWriting _ AndAlso ComPort.IsOpen) Then Return ComPort.ReadChar End If Catch End Try Return -1 End Function Public Function ReadBufferByte() As Integer Try If (Not DisableWriting _ AndAlso ComPort.IsOpen) Then Return ComPort.ReadByte End If Catch End Try Return -1 End Function Private Shared Function doesPortExist(ByVal ComPortName As String) As Boolean Dim serialPortNames() As String = SerialPort.GetPortNames Dim i As Integer = 0 Do While (i < serialPortNames.Length) If (String.Compare(serialPortNames(i), ComPortName, True) = 0) Then Return True End If i = (i + 1) Loop Return False End Function End Class
As soon as Dave Dahl sat down, I clicked the drop button and the everything worked like clock work. If you want to see the video, once again it is over at YouTube for your April Fools Day pleasure.
Before you do such a prank, please be sure you your victim will be cool with it so you won't get fired. Thankfully, I wasn't and Dave is cool ... I hope. I wasn't happy totally with our deployment solution since it was partially visible due to the string. I'd also like to have had the entire system automated with maybe an IR sensor or a force sensor hidden in the seat. Given a few more weekends and actually planning this prank out a bit more, I think Andy and myself could have come up with a more robust system.
A special thanks to Dave Dahl for being such a good sport and Andy Konkol for helping out.
Clint is an application developer for SpringCM, an on-demand, web-based document and content management system. His two primary development languages are C# and JavaScript. Prior to the ball drop project, he worked on his Disco Dance Floor. In his off time, he whips up other random weird projects and does twenty something activities with his friends. Clint's blog is betterthaneveryone.com and can be emailed at clint@rutkas.com.
Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation,
please create a new thread in our Forums,
or
Contact Us and let us know.
Follow the Discussion
Oops, something didn't work.
What does this mean?
Following an item on Channel 9 allows you to watch for new content and comments that you are interested in. You need to be signed in to Channel 9 to use this feature.What does this mean?
Following an item on Channel 9 allows you to watch for new content and comments that you are interested in and view them all on your notifications page.sign up for email notifications?
this is a kick * trick. too much work for dropping some bouncy balls though...
I like the trick. We play pranks on each other in our office all the time but they usually pretty low-tech. This year at Christmas we wrapped a guys entire cubicle in wrapping paper. Computer, chair, pencils...everything
I'll have to get my tech guys to help me out with some better high-tech pranks now.
Charles
That is soooooo AWESOME!!!! I have to try that on my friends!!! Great prank!!!
Clint, this is AWESOME! I'm going to have to try this next year, or something like it.
Remove this comment
Remove this thread
close