Earlier this month, AdaFruit released a nice little TTL camera, perfect for security and remote monitoring applications. The camera supports three resolutions (640×480, 320×240 and 160×120), has a built-in motion detection circuit and can output an NTSC signal, all in a fairly compact form factor. The communication with the camera is done over a TTL UART @ up to 115200 bauds. In many respects, this device is very similar to the LinkSprite camera, which has been out there for some time now.
As I’m working on a security-related project involving the Netduino, it was the perfect opportunity to put this camera to the test, starting with writing a C# driver. While interfacing with the camera over the TTL UART of the Netduino is straight forward, the datasheet describing the protocol and commands required to control the camera functions is painfully sketchy and sometime inaccurate. In some instances, some camera functions such as OSD (text overlay) are not supported in the firmware even though the datasheet documents them or only behave properly if called in a particular sequence, which of course, is not documented…
Connecting the camera to the Netduino
Limor’s tutorial on how to interface the camera with the Arduino outlines the required steps rather well, so I won’t re-iterate them here. The only difference worth mentioning is that the voltage divider configuration shown in the adafruit tutorial is not necessary on the Netduino, since its GPIO pins are 5 volt tolerant. So, you can simply connect the TX pin of the camera to PIN 0 (RX) on the Netduino and the RX pin of the camera to PIN 1 (TX) on the Netduino. To make things a bit easier while testing the camera with a breadboard, I built a connector using a standard 0.1″ pitch right-angle header and a small section of prototyping board: unfortunately, the breakout board of the camera uses a different pitch. In addition, you’ll want to connect an SD card reader to your Netduino so that you can store snapshots. Please refer to my earlier post on how to connect an SD card reader to the Netduino if you aren’t familiar with the procedure. If you’re using a Netduino Plus, don’t worry about that part :)
Using the Netduino driver
The Netduino driver currently implements 4 major functions.
Initializing communication and the camera’s resolution
- Initialize(string port, PortSpeed baudRate, ImageSize imageSize): This call must be the first call in the application. It takes care of initializing the UART and the resolution of the camera at the same time. The reason for keeping these two functions together is that changing resolution requires a reset of the camera, which also resets the camera’s baud rate to the factory default of 38400 bauds. In addition, if the baud rate is set to something other than the default and the program is interrupted while debugging, the next time the program runs, it will have to remember what the last baud rate was (unless the camera is hardware-reset). To avoid all this trouble, the initialization function automatically figures out the proper baud rate needed to communicate with the camera before applying new settings.
Controlling TV output
- TvOutput(bool enable): Passing ‘true’ will tell the camera to output a composite video signal showing whatever the camera is looking at. Passing ‘false’ turns it off.
- TakePicture(string path): This function will tell the camera to take and store a snapshot, in JPEG format, to the location specified by the path argument. You need to have an SD card reader connected to the Netduino for this to work. You can control the quality of the image using the SetCompression(byte compression) function where the compression is a value between 0 and 100, with the default being 53.
- StartAutoMotionDetection(int imageSequenceNumber, string storagePath, MotionDetectedHandler motionDetectionHandler): This function will activate the motion detection circuit of the camera and will return immediately. Whenever motion is detected by the camera, the driver will callback the application through the motionDetectionHandler delegate. If the handler returns ‘true’, a snapshot will be automatically taken and stored to the location indicated by the storagePath parameter. The filename is sequentially incremented, starting with the number provided by the imageSequenceNumber argument. The motion detection can be stopped using a call to StopAutoMotionDetection(). Click on the image below to see a sample on how this can be used.
Testing the camera
To put the camera to the test, I wrote a sample taking a set of 100 pictures using each of the resolutions supported by the camera. The sample also tests motion detection and the camera’s composite output. During the test, the camera was set outside on a tripod, pointed at a neighbor’s house about 200 feet away around 8PM on August 11th. The goal of the test was to gauge the overall video quality of the camera in lower light conditions as well as evaluating the error-rate when taking snapshots.
The composite video quality, shown here on a small CRT TV, is generally quite good and stable.
The snapshots, on the other hand, often show compression artifacts like this:
Out of 100 pictures taken at the higher resolution, only one did not have any artifacts. Please note that I did not tweak the color saturation of the camera before using it: colors can be greatly improved with some tuning with the tool coming with the camera. Limor covers this in her tutorial as well but I’ll post updated snapshots with tuned color saturation when I get the chance.
In the large and medium resolutions, 1 picture out of 100 is generally corrupt and cannot be viewed. There could be several root causes for these artifacts and data corruptions:
- The connection I’m using between the camera and the Netduino is not shielded or twisted to minimize radio and electromagnetic interference. I haven’t had the chance to validate this yet.
- The serial buffer size vs. the baud rate is critical in minimizing errors: I was able to read a maximum of 120 bytes at a time @ 115200 baud without losing data with the current connection to the camera. Larger buffers only seem to increase the error rate to unacceptable levels which makes reading large images a slow process. Again, a shielded and twisted cable would likely help using larger buffers.