Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

April Fool's Day with Bouncy Balls

 

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!
Better Than Everyone

Difficulty: Intermediate
Time Required: 3-6 hours
Cost: $100-$200
Software: Visual Basic or Visual C# Express Editions
Hardware: Control Anything USB Relay Board, a drill, a ton of super bouncy balls and some zippie ties
Download: Download
 

Introduction

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.

The Prank Setup

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

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.

Relay Code

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

 

Comport

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

Deployment

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.

Summary

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. 

Thanks

A special thanks to Dave Dahl for being such a good sport and Andy Konkol for helping out.

Bio

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.

Tags:

Follow the Discussion

  • Bouncy BallsBouncy Balls

    this is a kick * trick. too much work for dropping some bouncy balls though... Sad

  • Bulk Vending GuyBulk Vending Guy

    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 Smiley

    I'll have to get my tech guys to help me out with some better high-tech pranks now.

    Charles

  • LissaLissa

    That is soooooo AWESOME!!!!  I have to try that on my friends!!!  Great prank!!!

  • ErinErin

    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

Comments Closed

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.