Evolution of a Blog

This blog has evolved as I have as a maker. It starts at the beginning of my journey where I began to re-tread my tires in the useful lore of micro electronics and the open-source software that can drive them. While building solutions around micro-electronics are still an occasional topic my more recent focus has been on the 3D Printing side of making.

Tuesday, April 9, 2013

CritterCam Version 2


I have now refined my "CritterCam" based on experiences to date and am pretty happy with the result.   It meets most requirements of the brief though there are one or two refinements that might get added.

In short, the CritterCam is a RPi based device that will operate as a wireless motion detector, capturing images using either a WebCam for 720p resolution or a DSLR for 12mb resolution.  It is integrated with a small PHP application that also runs on the RPi courtesy of a LAMP install.   The device will operate in either of two modes, the first being the most portable, using a 720p webcam and being based on the OpenCV library.   The second uses a USB connected DSLR, in my case a Canon 500D, and relies on the gphoto2 library (libgphoto2) augmented by a wrapper called "piggyphoto".  Obviously, portability goes down when you add a DSLR!

The options provided by the CritterCam are shown below:
Usage: CritterCam.py [options]

Options:
  -h, --help            show this help message and exit
  -k, --keep            Save a static file (/var/www/camimages/stream.jpg) 

                        and do nothing else
  -d DELAY, --delay=DELAY
                        Delay between captures
  -s, --stream          Stream timestamped images
  -m, --motion          Stream time stamped images triggered by motion
  -r, --dslr            Use DSLR capture rather than using webcam

  -t THRESHOLD, --threshold=THRESHOLD
                        Motion threshold
  -v, --verbose         Produce extra status and progress messages

Within it's processing loop CritterCam will check for the existance of several action generating flag files left in the /var/www/ by it's PHP partner:
  • Restart.flg - Causes an exit with a zero return code.  Invoking shell script  loops
  • Shutdown.flg - Causes an exit with a one return code.  Invoking shell script  exits
  • Reset.flg - Causes a reset of the current base image to the most recent capture.  Useful in case the app itself has not detected a change in background.
  • Force.flg - Causes the app to capture a full resolution image even without the motion trigger.
To detect motion the CritterCam uses  a very simple, ok maybe rudimentary, approach of using the OpenCV absdif function to compare the matrice from the current image and that of the base image.  If the mean difference is greater than a threshold we assume motion.   While processing, the script will attempt to detect a change in the conditions of the base image and will replace it if necessary.

Here is a link to the source code for the CritterCam.   It still does some weird stuff now and again and will continue to be enhanced.    It is partnered with a PHP application but that app is based on my own forms development environment so is a little complicated to easily make available for download.

The most major enhancement that I would like to add would be an external batter for the DSLR.   I know that I could buy one but I already have the AC adapter and am thinking I would just hijack it, add a couple of 5.2mm plugs and sockets, splice in a DC power regulator and have something that could also live on the tripod.

I have to confess to a major issue with my CritterCam.   Namely that it has a hard time detecting a change to the ambient light.   Unless I manually reset the base image it will decide that the change is motion......bad CritterCam!

RPi as a Remote Control for a Canon DSLR - Part 5

Note that this is an update to Part 4 of the same story.

In the previous post I mentioned the following changes:

smsc95xx.turbo_mode=N in /boot/cmdline.txt
dwc_otg.microframe_schedule=1 in /boot/cmdline.txt
vm.min_free_kbytes=16384 in /etc/sysctl.conf
reboot

With a little experimentation I have determined that the first two changes must both be present for my sought after stability to be achieved.   If they are not both in place we will get the following error:

piggyphoto.libgphoto2error: Unspecified error (-1)

This will happen at some point and probably pretty quickly (within a minute).

The fourth change does not seem to be needed for my stability purposes.  I have tried with it at half the above and without it at all.  The vm.min_free_kbytes argument is actually part of a pair of tweeks in the sysctl file.   I have not detected any change with them in or out...but I am leaving them in at this time.

# rpi tweaks (16384 suggested though not conclusive over 8192)
vm.swappiness=1

vm.min_free_kbytes = 16384

There is one other thing that I am doing that is a left over from when I was working with a webcam.   The shell script that I run my Python code within is shown below:

#bin/bash
sudo rmmod uvcvideo < rpw
sudo modprobe uvcvideo nodrop=1 timeout=5000 quirks=0x80 < rpw
sudo rm /var/www/camimages/*.jpg  < rpw > /dev/null 2>&1
sudo rm /var/www/camimages/loop/*.*  < rpw > /dev/null 2>&1
sudo rm /var/www/shutdown.flg < rpw > /dev/null 2>&1
sudo rm /var/www/restart.flg < rpw > /dev/null 2>&1
if sudo python -B CritterCamDSLR.py $1 $2 $3 $4 $5 < rpw; then
    echo ""
    echo "Restarting CritterCam"
    echo ""
    ./CC $1 $2 $3 $4 $5
fi

I know, I know, it is ugly with all that running as root but let's leave that alone for now!

Note the two uvcvideo lines.   Without these two lines it takes my Python script twice as long to recognize motion (from about 1 second to about 3 seconds).  I guess libgphoto2 uses uvcvideo?   When I compare 'top' output between the two executions I do not see a difference...but...the response time difference is very noticeable.

Lastly (but not finally), I do still get the above libphoto2 error on occasion when I am starting my script a second or third time.   I might be able to solve this with a usb reset, and I do have a script to do this, but I think this confirms what I wrote in an earlier post.  For now I am happy with doing a power cycle on the camera now and again though I may work on the usbreset at some point.

Finally, in my next post I will describe my scripts a little more and make them available for download.  I would now but the capture script is still doing a couple weird things.

Monday, April 8, 2013

RPi as a Remote Control for a Canon DSLR - Part 4

I have made some progress with libgphoto2 driving my DSLR without going belly up.  I have modified CritterCam such that the DSLR does both the preview and the motion activated shots and it has been stable for the past ten minutes (previously it would only run for less than a minute before going boom).

Here are the changes that I made:

smsc95xx.turbo_mode=N in /boot/cmdline.txt
dwc_otg.microframe_schedule=1 in /boot/cmdline.txt
vm.min_free_kbytes=16384 in /etc/sysctl.conf
reboot

These are courtesy of the Raspberry Pi Forum and user elatllat.  This forum rocks in terms of helpful and responsive feedback.

I do still have a bit of an issue with the method that I am using for motion detection but I am hoping it is because of the conditions within which I am currently testing (indoors without a lot of light).

There is an update to the above based on some experimentation.

Sunday, April 7, 2013

LAMP

I have installed LAMP on my CritterCam RPi so I can host a little web application written in PHP.   I am not using MySQL at this point but being able to run it on the RPi is kinda cool.   It is slow but still...!

I followed the install instructions at this link.   They are great and so don't need repeating.  You can see the results here where LAMP is delivering the preview web page for my CritterCam.


RPi as a Remote Control for a Canon DSLR - Part 3

I am at an impasse with trying the get the DSLR to capture the motion being detected by the RPi.   Namely because there is a two second delay between the time the motion is detected by my Python script and when it actually occurred!   I have installed 'motion' on the RPi and it also suffers from the same delay.   Hmmm.  What to do?

I guess I will see what the delay is when using PiggyPhoto to grab preview images.  If that looks to be working then I will go back to pondering stability of the DSLR interface across libgphoto2.

Friday, April 5, 2013

CritterCam Version 1 in Action

Having solved the power problem (got a new battery in the mail) I have been able to get the CritterCam into action.   Here are some images from a test run.   First the web preview page.   This is a tiny little PHP app that runs on the RPi along side the Python script that does the captures.   It is kind of funny to think about the RPi running a SQL server and PHP behind Apache.   I am not using mySQL but I could!   In any case...


The large image at the top is the last image saved due to motion being detected.  The four images at the bottom are the last four images captured with the difference calculated between each image shown at the bottom.   The threshold specifies the point at which this difference between images triggers a capture.

I do have the DSLR triggering working with one major issue...there is a two second delay between when the Python script sees the motion and when the motion actually occurred.  No clue as to why yet.   Even without the DSLR the little 720p webcam does a decent job at the image capture.






Yes, that bench is in dire need of painting.   If it were not so bloody cold it would get pressure washed and painted!

Thursday, April 4, 2013

RPi as a CritterCam - Ultimately Remoting a DSLR

I have made some progress on a CritterCam based on one of my RPi's.   Here are a couple pictures of the device:

  • The base is a four battery holder for 3.7v 1850 Lithium Ion flashlight batteries with an output of 14.8v.
  • At the top is an adjustable power regulator that drops the 14.8v to 5v and delivers it via a 5.2mm power plug.
  • The power regulator is sitting on a powered USB hub that provides power to the RPi and also supports a Wi-Fi dongle (and a keyboard during debugging).  The hub is a cheap one but compatible with the RPi and is smaller than the more expensive ones I find on Amazon.
  • As mentioned above the Hub supports a USB Wi-FI dongle.   The one shown in the picture is an Edimax (larger of the two that I have).  I also have the small one but have been having some issues with dropped packets that I will discuss elsewhere.
  • In front of the USB Hub is the a 720p WebCam that is compatible with the RPi...but in my case only if plugged directly into the RPi.
  • Inside the Adafruit case is, of course, the Raspberry Pi that drives the CritterCam and it's web interface.
My goal is to use some Python code to detect motion in front of the webcam and trigger a shot by the DSLR which will be connected to the CritterCam.   The CritterCam will also support a web server running a little PHP application that will provide a preview of what the CritterCam sees.   I will talk about all of this a little later.

Right now I have a couple of issues.  First is one of power, on a couple of fronts, one being that I am using four Lithium Ion batteries to power the CritterCam and one of them has turned itself off!  I guess this is a good feature but I only have four right now but am waiting for an order from China for some more.  The other power related issue is that while I had a good test run with the Lithium Ion batteries driving the RPi for almost three hours...since then I can't get the power regulator to reliable support the RPi when connected to wall power of a variety of voltages.   The power does not seem sufficient to drive both the Hub and the RPi.   I am baffled as it worked so well with the batteries but can not retest with batteries again as I am missing one!

The other issue relates to driving the DSLR.   I have the Python code working well with the webcam on its own.   It detects motion and saves the current image.   Alas, when I try to trigger a DSLR capture at that point using the code I discuss here, it fails.   More work to do here but first I want to get the power issue sorted.