(This post was originally done back in 2007, everyone was after me to start blogging my projects so I converted the web page to a blog)

 

Ever Diligent Ever Watching

 

1[1]

Once upon a time a subdivision swimming pool caused a minor problem, but to a problem solving geek a problem is a problem that needs an answer.  So what were the problem and the solution?  Well for all you legal types it is rabbits eating in my garden.  So for the sake of this discussion we are talking about rabbits, however I must make a disclaimer that in motion detection and auto fire if an unwitting person is trespassing on my property and happens to walk into the field of fire... well we will refer to them as collateral damage.  Well the problem was Adult rabbits and little rabbits cutting between two houses instead of just walking an extra few feet to the pathway to the concrete pond. The little rabbits were never really the problem, it was the adults, there is nothing like being on your deck and some adult rabbit cutting between your house and the neighbor's and they just look at you like "What is there something wrong?" Never asking if it was ok, just doing it.  Some how I have to believe they would have an issue if I say ran laps around their house for my exercise program, but I digress... So I have this problem of rabbits cutting in my yard, it does not matter the time and of course it is from Memorial day to Labor day, before and after that time frame the traffic reduces greatly.  Of course the most active time is during swim meet season when I also have to deal with an extra 100 rabbits or so from different subdivisions.  Ok I have a problem, so I must have goals or objectives that have to be met in order for the ROI to be there.  So my defined goals were:

      • Must have automatic fire ability
      • Must be able to detect motion
      • Must be able to record the event
      • Must be able to turn off auto fire mode and take on manual control
      • Must be able to "Water the Lawn"
      • Must be able to cover a 30 foot field of fire
      • Must have a range of about 25 to 35 feet
      • Must have the ability to work at night with all of the above features
      • Must be able to Play back any recordings and laugh while sitting on the deck drinking a beer.

So what was the solution?  This I pondered and opened up my book of knowledge called the Internet and using the glorious thing called searching, I started to come up with an idea.  The picture above is actually prototype number two.  I will briefly talk about Prototype one, but since media player in a browser has a 5 second buffer(yes I tried to override it, but it ignored my override values) that I can not override anywhere, I had to move on to version two.  To meet the requirements/objectives I decided the first prototype needed the following items.

      • X10 120 volt outlet
      • X10 Transmitter and Receiver
      • X10 Libraries that would work with C#
      • In ground sprinkler solenoid
      • Phidget single servo board with servo
      • Phidget C# libraries
      • PVC pipe, Copper Ice maker pipe, and a few other plumbing parts
      • Old computer, 1.7 GHz with a gig of ram
      • USB Web camera

Like I said above I ran into a problem with media player in a browser, so if anyone know the answer to this problem please let me know.  Here is some photos and video of prototype one.

Video of version 1 from the console, note the delay in the video

**** Video is a 6 meg file, still learning on making the format "Web" friendly  ***

As you can see I have met a bunch of my goals in prototype 1, I can shoot about 30 feet and can cover a field of fire of about 30 feet.  I can also control the movement of the barrel by a servo and a Phidget device.  In this version in the top bunker "Window" I have a web camera mounted to the barrel and it shows the video of what it sees as the barrel moves. I control this all via a web page that was written in C# and using ASP 2.0 with a little bit of Ajax thrown in.  But as I have said before media player force me to version 2.

One issue that I did want to point out is when dealing with controlling your phidget devices from a web page, I ran into a state problem.  the solution was to declare the phidget variable as a static variable.  This allowed me to maintain control over the servos between postbacks.  I do believe a better answer which I am working on is to create all calls to the servo and X10 from a web service.  I have included the code to the web service, it still needs some work on it, namely turning everything into a singleton type call, I do not want multiple instances of the object.

static Phidgets.Servo enc1;

So what is version 2 and what lessons did we learn in version 1?  Well in version 1, I found out latency is not your friend; you have about 6 seconds to before target was out of range and also that cheap water hoses will burst under pressure. "Rabbits" are stupid, if they walk to close to either house they feel enclosed, so they walk right down the middle, giving a great field of fire.  They also react to sound, it will either make them stop and look for the sound or at the least keep walking but look for the sound, and this offers great photo shoot opportunities.    Another lesson learnt was that X10 works, but could work better, in time I will just switch to relays.  The in ground sprinkler solenoid worked great, it offered almost instant on, and has only a 2 second wait to turn off (time for solenoid to release). Version 2 needed to do everything version 1could do and then some, so back to the drawing board. 

I decided to go back to a thick client, dump the web camera and moved to an Infrared camera.  The most important upgrade was to an open source library that I found called Aforge.  Andrew Kirillov has done a fantastic job with his library .  It held the foundation of version 2's code base.  It provided me with the motion detection I needed plus had an avi writer sample.  He also had some great topics on "codeproject.com" on uses of his library.  This is what had me replace the web camera with an IP camera. Other thing that I did was replace all hoses with PVC pipe, I liked the easy setup and flexibility of the hose, but they can not hold up to the pressure day after day.  So to recap I still am using the same turret concept in version 1 that was in version 2.  I removed the mobile web camera and now have a fixed infrared camera, replaced all hoses with PVC pipes.  Added Aforge libraries and his Camera control.  Added in sound and ability to record from the point of motion to a fixed time after motion is no longer detected.  And finally switched to a thick windows client.  This is some finished photos:

Yes I know that the plumbing could be better, but this is only a prototype, in fact some of it will disappear based on lessons/enhancements that will be made to version 2 that is why it is called a prototype so we can learn.

The code is very simple most of the complexity was already done for me by some of the others who created the libraries that I am using.  I simply put a bunch of parts together, some of the things that I did, plus some of the changes to the libraries; I will go over.  Like I stated before, each of the libraries have good working samples and I would suggest you start there.  From that point you can work any of the code I did into your projects as you like.

This method shows all of the functionality in one call so I am showing it for its simplicity.

   1: MyGun myGun = new MyGun();  //defined at the form level as I use this object for manual control also.
   2:  
   3:          public void HolyHandGrenade() 
   4:         { 
   5:             log += "In Holy Grenade " + DateTime.Now.ToString() + " ,"; 
   6:             SoundPlayer sp = new SoundPlayer("Daffy04.wav"); 
   7:             sp.Play(); 
   8:             myGun.Grenade(); 
   9:             sp = new SoundPlayer("Sam35.wav"); 
  10:             sp.Play();
  11:  
  12:             // leave  on for 10 seconds, servo is moving back and forth at this time 
  13:             Thread.Sleep(10000); 
  14:             try 
  15:             { 
  16:                 if (thread.IsAlive) 
  17:                 { 
  18:                     thread.Abort(); 
  19:                 } 
  20:                 // kill the current thread 
  21:             } 
  22:             catch (Exception e) 
  23:             { 
  24:                 bridgeErrMsg += ",BridgeViewer.HolyGrenade => " + e.Message + " " + myGun.errmsg; 
  25:                 log += "In Holy Grenade execp " + DateTime.Now.ToString() + " ,"; 
  26:             } 
  27:             finally 
  28:             { 
  29:                 myGun.ReLoadGun(); 
  30:                 log += "In Holy Grenade finally " + DateTime.Now.ToString() + " ,"; 
  31:             } 
  32:         }   
  33:  

   One of the more important things (this is also demonstrated in the Aforge samples, it is what I followed ) is that you will need to setup some events in your code that will be triggered by the Camera control.  The events that I am currently using are the "NewFrame" and "Alarm" events. They are setup by the OpenVideoSource and CloseVideoSource method calls.  Needless to say the Alarm event is fired every time motion is detected.  The key thing to remember here is that the alarm is firing with every new frame that the camera takes that is many in a second.  I only want to fire the gun if it is not currently firing and motion is detected.  In the NewFrame event this is fired every time the camera takes a picture, again remember this is many times a second.  This event is where the code is writing to an AVI file frame by frame, but this too I wanted to control, so if I did not want to capture everything to video I could override the defaults.  My future plan here will be to replace the current AVI writer with one using Directx so I will be able to capture video and sound.  Also I plan to add a gun site to the frames here so in manual mode you will be able to see a cross hair and it would move as you would move a joystick.

   1: // On alarm Event 
   2:     private void camera_Alarm(object sender, System.EventArgs e) 
   3:     { 
   4:         timeLastAlarm = DateTime.Now; 
   5:         AlarmOn = true;
   6:  
   7:         if (AutoFire == true) 
   8:         { 
   9:            if (gunOn == false) 
  10:             { 
  11:                 log += "Gun on " + DateTime.Now.ToString() + " ,"; 
  12:                 gunOn = true; 
  13:                 thread = new Thread(new ThreadStart(HolyHandGrenade)); 
  14:                 thread.Start(); 
  15:             }
  16:  
  17:         }
  18:  
  19:     }
  20:  
  21:     // On new frame 
  22:     private void camera_NewFrame(object sender, System.EventArgs e) 
  23:     { 
  24:         DateTime now = DateTime.Now;
  25:  
  26:         if(timeLastAlarm.AddMinutes(minsAfterLastAlarm) < now && writer != null) 
  27:         { 
  28:             writer.Close(); 
  29:             writer.Dispose(); 
  30:             writer = null; 
  31:             AlarmOn = false; 
  32:         }
  33:  
  34:         if (Rec == true && AlarmOn == true) 
  35:         { 
  36:             // lets save the frame
  37:  
  38:             if (writer == null) 
  39:             { 
  40:                 // create file name 
  41:                 DateTime date = DateTime.Now; 
  42:                 String fileName = String.Format("{0}-{1}-{2} {3}-{4}-{5}.avi", 
  43:                     date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second);
  44:  
  45:                 try 
  46:                 { 
  47:                     OpenWriter(fileName, cameraWindow.Camera.Width, cameraWindow.Camera.Height); 
  48:                 } 
  49:                 catch 
  50:                 { 
  51:                     if (writer != null) 
  52:                     { 
  53:                         writer.Dispose(); 
  54:                         writer = null; 
  55:                     } 
  56:                 } 
  57:             }
  58:  
  59:             // save the frame 
  60:             try 
  61:             { 
  62:                 // save the frame 
  63:                 MotionDetector.Camera camera = cameraWindow.Camera;
  64:  
  65:                 camera.Lock();
  66:  
  67:                 // dispose old frame 
  68:                 if (bmpLastFrame != null) 
  69:                 { 
  70:                     bmpLastFrame.Dispose(); 
  71:                 }
  72:  
  73:                 Bitmap bmpSource = camera.LastFrame; 
  74:                 bmpLastFrame = (Bitmap)bmpSource.Clone(); 
  75:                 writer.AddFrame(bmpLastFrame); 
  76:                 camera.Unlock(); 
  77:                 timeLastSavedFrame = DateTime.Now;
  78:  
  79:             } 
  80:             catch (Exception ex) 
  81:             { 
  82:                 System.Diagnostics.Trace.WriteLine(ex.ToString()); 
  83:             }
  84:  
  85:         }
  86:  
  87:     }
  88:  
  89:     // Open video source 
  90:     private void OpenVideoSource(IVideoSource source) 
  91:     { 
  92:         // set busy cursor 
  93:         this.Cursor = Cursors.WaitCursor;
  94:  
  95:         // close previous video source 
  96:         CloseVideoSource();
  97:  
  98:         // create camera 
  99:         MotionDetector.Camera camera = new MotionDetector.Camera(source, detector); 
 100:         // start camera 
 101:         camera.Start();
 102:  
 103:         // attach camera to camera window 
 104:         cameraWindow.Camera = camera;
 105:  
 106:         // set event handlers 
 107:         camera.NewFrame += new EventHandler(camera_NewFrame); 
 108:         camera.Alarm += new EventHandler(camera_Alarm); 
 109:         camera.VideoSourceError += new EventHandler(camera_VideoSourceError); 
 110:         // start timer 
 111:         timer.Start();
 112:  
 113:         this.Cursor = Cursors.Default; 
 114:     }
 115:  
 116:     // Close current video source 
 117:     private void CloseVideoSource() 
 118:     { 
 119:         MotionDetector.Camera camera = cameraWindow.Camera;
 120:  
 121:         if (camera != null) 
 122:         { 
 123:             // stop timer 
 124:             timer.Stop();
 125:  
 126:             camera.NewFrame -= new EventHandler(camera_NewFrame); 
 127:             camera.Alarm -= new EventHandler(camera_Alarm); 
 128:             camera.VideoSourceError -= new EventHandler(camera_VideoSourceError);
 129:  
 130:             // detach camera from camera window 
 131:             cameraWindow.Camera = null; 
 132:             Application.DoEvents();
 133:  
 134:             // signal camera to stop 
 135:             camera.SignalToStop(); 
 136:             // wait 2 seconds until camera stops 
 137:             for (int i = 0; (i < 20) && (camera.IsRunning); i++) 
 138:             { 
 139:                 Thread.Sleep(100); 
 140:             } 
 141:             if (camera.IsRunning) 
 142:                 camera.Stop(); 
 143:             camera = null;
 144:  
 145:             // reset motion detector 
 146:             if (detector != null) 
 147:                 detector.Reset();
 148:  
 149:         } 
 150:     }
 151:  

 Like I have already stated, most all of the samples from AForge are pretty straight forward and easy to use, almost all of the above snipit of code came from one of the samples.  One thing I did do was break the camera control out into a project by itself.  Once this was created I just had to simply drag and drop the control on a form like any other .Net control and do whatever I wanted from with in my application.  One change I did implement in the Camera control was to setup a property to give me more control on the sensitivity for motion detection, I felt the default was way to sensitive for my needs and wanted a way to adjust it.

   1: public double AlarmLevel 
   2:        { 
   3:            get 
   4:              { 
   5:                 return alarmLevel; 
   6:              }
   7:  
   8:              set 
   9:              { 
  10:                  alarmLevel = value; 
  11:              } 
  12:        }
  13:  

As for my Gun class, it is made up of two other classes.  One of these classes handles the Phidget devices the other handles the X10 devices.  The Gun Class just puts it all together.  The web service I have enclosed demostrates all of this and it is pretty straight forward to understand.  If you still have questions feel fee to send me an email.  web service code is here .  

So with version 2 where are we and what did we learn? 

  • Motion detection works great, sometimes to good. 
  • We now have video and it is meeting the goal of having something to laugh about.
  • Auto fire works and combine it with "Holy Hand Grenade" mode and you cover a lot of territory.
  • You can teach "Rabbits" new tricks.
  • PVC was the right move.
  • Servo controller boards do not like thunder storms, keep it water tight
  • A lot more "Rabbits" cut through than I thought, some even riding bikes on my lawn
  • Do not shoot your wife, even by accident (might not be a version 3 :) ).
  • Your kid will use it like running through a lawn sprinkler
  • Using sound effects from Star Trek, Mars Attacks, Daffy Duck and Yosimini Sam added to the fun
  • Infrared camera's are not all built the same

Ok so what type of enhancements are we talking here (some of these are already in the works)?  Well just brain storming...

  • Create a click once client so I can deploy to friends to have manual fun.
  • Add in Microsoft's new Robot SDK
  • Put functionality of servo and X10 control in a web service (already did this and it opens oh so many ideas. cell phones come to mind...also what waterhobo.com is needed for...)
  • Have motion detection that goes to motion tracking.
  • Switch from only horizontal to both horizontal and vertical (Pan and Tilt) for barrel
  • Switch to directX avi recording, I want to record sound and video
  • Using directX, add in Joystick capability even from remote over the web (using web service)
  • Make it more portable
  • Add in pop up in ground sprinklers
  • Create Infrared Spot light to help cameras at night.

In closing I have learnt a great deal and have a great deal of rework to do, in some cases things were to complex and in others there was just not enough functionality for what I wanted to do, but I do know it can be done, and I do love a challenge, so it will be. And finally a note from the WaterHobo, well I did not catch any rabbits, but man you would not believe all of the collateral damage or people that "Just" happened to trespass on my yard, some as late as 11:30 at night.  They choose to ignore my "Pest" control signs, I guess that is why we call them collateral damage....

Stay tuned for more videos and version 3, its coming...