The PIX-6T4 has a dedicated site!

 With the growing amount of information that we have to share with the community about the Netduino-powered PIX-6T4 Game Console / DevBoard, keeping it all in blog-format has been increasingly challenging. So, we have created a dedicated site @ http://www.pix6t4.net, where you can find it all easily. To start with, we’ve added schematics, part lists and in-depth tutorials on working with the Netduino Mini. We hope that you enjoy the site and have fun building and learning with your own console.

Cheers,

-Fabien & Bertrand.

 

Channel 9: http://channel9.msdn.com/coding4fun/blog/Building-your-own-hand-held-game-console-with-Netduino-C-and-the-PIX-6T4-project

Driving an ‘Adafruit ST7565 Negative LCD Display’ with a Netduino

 I have been waiting for an excuse to use a Nyan Cat in a blog post and the ‘ST7565 Negative LCD Display’ released by Adafruit being equipped with RGB LED backlights was the perfect occasion. After all, RGB LEDs can create a ‘rainbow’, right? All that’s needed is a cat to go with it and Voila!

Since Nyan Cat needed some friends, Hello Kitty and a Space Invader joined in. Eventually, Darth Vader was called in to scare the Nyan Cat away. But I digress…

Connecting the Adafruit ST7565 to the Netduino

The breakout board supporting the LCD display won’t accommodate a standard 0.1″ header unfortunately, so I had to build my own adapter to use it on a breadboard. No big deal but it’s time consuming.

No, really, this is not a squid.

The back of the connector.

The ST7565 is hooked up to the Netduino, ready for development.

The length of the wires that I used for this test were a bit long and limited the communication on the SPI bus to 22 MHz. With shorter connections, this display is capable of supporting much higher speeds, even though the LCD refresh rate can’t keep up at such high speeds and creates ghosting effects between frames.

Pin Connection Map

Here’s the pin mapping I chose from the LCD connector to the Netduino:

  • LCD B-: Netduino D5 (PWM) (LED Blue)
  • LCD G-: Netduino D6 (PWM) (LED Green)
  • LCD A+: Netduino 3.3v (LED anode)
  • LCD R-: Netduino D9 (PWM) (LED Red)
  • LCD GND: Netduino GND
  • LCD VDD: Netduino 3.3v
  • LCD SID: Netduino D11 (SPI MOSI)
  • LCD SCLK: Netduino D13 (SPI CLK)
  • LCD A0: Netduino D7 (Data / Command)
  • LCD /RST: Netduino D4
  • LCD /CS: Netduino D10 (SPI CS) or us Netduino D8 if D10 used for the SD card CS pin

Using the Netduino’s PWM pins is not a requirement: the B-, G- and R- LCD pins can just be connected to the Netduino’s GND pin instead, which results in a bright white backlight.

The C# driver

As always, reading the datasheet for the LCD module is a must before starting on the driver details which is part of the netduino helpers library as usual.

According to the datasheet, the Display Memory Map is divided into 8 pages of 128 bytes each, laid out like this:

There are 2 implications of this memory organization on the Netduino:

  1. The page that needs to be updated must be selected prior to sending a block of 128 bytes over SPI. This requires switching the LCD A0 pin between Command and Data mode constantly, which is limited to ~8.1KHz on the Netduino.
  2. In addition, because SPI.Write() only takes a byte[] or a ushort[] argument, it is necessary to copy the 128 bytes of the page to an intermediate buffer usable by SPI from the buffer actually storing the 128×64 image bitmap. It would be very useful to add relative buffer addressing capability to SPI.Write() in a future version of the .Net MF to avoid shuffling data around like this.

As it turned out, the display frames still get refreshed quickly.

Sex, Lies and Datasheets

In practice, the Display Memory Map pages are not organized as the datasheet describes. Instead, this is how the pages are actually organized:

  • Line zero is in the middle of the display, where page zero starts
  • The image wraps at the bottom of page 3 and continues displaying from the top in page 4
This wacky display memory layout requires maintaining a logical to physical mapping of the pages. Here’s what the final display refresh function looks like:

Re-using the Netduino SSD1306 driver code

The ST7565 Netduino driver is very similar to the SSD1306 Netduino driver: except for the Display Memory Map layout, they’re both monochrome displays and have the same resolutions, therefore it was natural to re-use all the existing drawing routines previously written for the SSD1306. The significant differences are in the Initialize() and Refresh() functions.
In addition, the Netduino ST7565 driver supports these functions:
  • PowerSaveMode(): which places the display in a mode where its current draw is minimal. It is recommended in the datasheet to enter power save mode before switching the display’s power off. A call to Initialize() is required to get out of the power save mode.
  • SetContrast(): adjusts the contrasts of the LCD display.
    • The driver provides three constants to set the contrast to High, Medium and Low
    • Medium is the default

Controlling the backlight

In order to manage the RGB backlight easily, a new RGBLed class was also added to the netduino helpers library. It can be configured to work with RGB LEDs that have a common anode or common cathode configuration as indicated in the constructor of the RGBLed class. To use it, simply call SetColor() with a hex RGB value and an optional delay expressed in milliseconds before the function returns. The class also defines 12 handy common color constants, which is particularly useful in ‘Nyan Cat Animation’ scenarios 😉

Conclusion

The Adafruit ST7565 is a beautiful, crisp, graphic display with pixels large enough to be seen without a magnifying glass (I’m looking at you, SSD1306…) and small enough to display images or multiple lines of text. The built-in RGB LED backlight makes for an effective method of communicating application status conditions at a glance and from a good distance, without having to read text. The screen appears to be made out of thin glass and is fragile, so be sure to handle the display with care: I inadvertently put a small dent in mine while soldering the connector and did not notice it until I turned the display on. My only wish is for the breakout board to support the common 0.1″ header pitch. Finally, because it only takes ~1.1KB to manage the display buffer, it is very usable for Netduino Plus applications without jumping through hoops.

Building your own Netduino-powered Game Console – Part 1

So, you’ve decided to build your own PIX-6T4 game console and you’re excited about learning C#?

Awesome! Buckle up, you’re in for a wild ride 🙂

The first step of your journey starts with gathering a few parts, which you can find listed in this spreadsheet along with their current retail price and links to the suppliers. In a nutshell, you’ll need about $95 to get all the required parts.

In an effort to keep the number of suppliers down to a minimum for your convenience, most of the parts for the PIX-6T4 prototype come from Sparkfun Electronics.

However, there are many alternative suppliers out there and with some research in Octopart, you will be able to reduce the cost of building this prototype.

Next time, we’ll cover the first step of the build, laying out the IC sockets, the analog joysticks, and some headers on the prototyping board, just like this:

 

 

Cheers,

-Fabien.

 

Driving an adafruit VC0706 TTL Serial JPEG Camera with a Netduino

HAL 9000


 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.

Taking pictures

  • 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.

Detecting motion

  • 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 results

The composite video quality, shown here on a small CRT TV, is generally quite good and stable.

NTSC output

The snapshots, on the other hand, often show compression artifacts like this:

Artifacts

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.

No artifact

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:

  1. 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.
  2. 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.

Conclusion

The VC0706 camera, with proper tuning, is a nice addition to any project where remote monitoring, motion detection and security are needed and it will pretty much work ‘out of the box’. It would be great to see future versions of this camera offering access to the SPI and High Speed UART interfaces: while it is possible to force the camera to use ‘out of spec’ UART speeds above 115200 bauds, it is unlikely to be very reliable.
As always, you can find the camera driver and the test code as part of the Netduino Helpers library.

Build a Netduino-powered Game Console

Over the past few months, my friend Bertrand and I have been working on a game console, the PIX-6T4, which is powered by a Netduino mini.

The console is designed as platform for learning digital electronics and C#: we’re in the process of writing a book covering all aspects of building the console, how its components work and how to write games for it with our framework.

Here’s a video of the prototype of the console below:

and here, as we presented it during the Ask An Engineer Show-And-Tell run by AdaFruit on Google+ last weekend: http://vimeo.com/26943990

As always, it’s entirely open source / open hardware and we hope that you’ll have as much fun building your own and making games as we did, which we will cover in a series of upcoming posts, often referring to past articles on this blog.

Cheers,
-Fabien.

Make Blog: http://blog.makezine.com/archive/2011/07/build-a-netduino-powered-game-console.html

MSDN Bloghttp://blogs.msdn.com/b/netmfteam/archive/2011/08/10/netmf-student-and-hobbyist-projects.aspx

Build a ‘Klout Klock’, track your influence and time.

Recently, my friend Bertrand wrote an interesting article about how he came to realize that we have become a “Society of Many Tribes”. Go ahead and read the article. It will be worth your time Smile The core concept of the article centers around “Thinking locally first and sharing your ideas with your tribes will eventually result in your impact becoming global”. This is a fascinating idea, begging to be experimented with. But how can one actually measure the breadth, depth and impact of one’s ideas as they travel and evolve through social networks?

Curiously, it turns out that the Klout team has come up with a set of metrics to do just that. If you have a Twitter, Facebook or LinkedIn account, you should try to link them to Klout to understand how this works: in a nutshell, Klout applies a set of algorithms, similar to Google’s page ranking algorithm, to your interactions and relationships within social networks and comes up with a synthetic score on a scale of 1 to 100, representing your overall influence a.k.a your “Klout Score”. A “Klout Score” is itself broken down into multiple data points, described in details here.

Klout’s metrics are interesting from a self-development standpoint because they can be used as a feedback loop: with them, you can evaluate within days or hours the effect of your communications, measuring what works vs. what doesn’t and learn to focus a message in the areas where it will resonate with a target audience. This is a valuable tool for individual bloggers and businesses alike.

Building a Klout Klock

Klout  exposes a web service enabling developers to build mash-up applications around its metrics and all that is required to play is an API key which is easily obtained when registering an application. My application is the “Klout Klock” device and before getting into the details of building it, you can see it how it works in this video:

The clock is built using a Netduino Plus and an AdaFruit ST7735 TFT screen. I have described how to connect them together in a previous post here. In that post, I had indicated that managing such a TFT screen from a Netduino was sub-optimal due to the memory requirements involved. That statement is even more true with a Netduino Plus which has roughly 28KB of RAM available for an application. This means that allocating a 40KB buffer to manage the TFT display as I was doing it previously is out of the question. Also, this time I am using the Netduino Plus’ SD card reader instead of the one built into the AdaFruit ST7735 breakout board. In addition, the screen’s back light is hooked up to a PWN pin to achieve the fade-in / fade-out effect based on the iCuffLink breathing effect 🙂

So, what do you do when you need to fit 10 lbs of crap in a 5 lbs bag? You use a virtual bag, of course! 🙂

Using an SD card as Virtual Memory

The Netduino Plus, in addition to its Ethernet connector, features a handy micro SD card reader for storage which I turned into virtual memory to get around the RAM constraints.

The virtual memory concept is straight forward: instead of reading and writing to/from a RAM buffer matching the size of the AdaFruit TFT display, all reading and writing operations happen against a file whose size matches the size of the display. In this case, that file is exactly 40960 bytes, the size required to hold a 128*160*16 bit/pixel image.

To actually refresh the screen with the image contained in virtual memory, the physical display is updated in ‘segments’, reading the data for each segment into a small RAM buffer, then blasting its content over SPI to the display. For each segment update, a display address window is positioned to cover the proper range of pixels.

The trade-off here is speed since file I/Os are orders of magnitude slower than operations in RAM but speed is not the main concern in this scenario. In addition, the more memory segments are used to chop up a virtual memory block, the slower it gets.

The following diagram shows how the process of updating the display from segmented virtual memory works:

I have added two classes to the Netduino Helpers library, respectively called “VirtualMemory.cs” and “VirtualFrame.cs” which make this process simple. I also refactored the driver that I had previously written for the AdaFruit ST7735 to make use of virtual memory if desired:

In this snippet, a virtual frame the size of the display is created and divided into 16 segments, ensuring that the I/O buffer used to read the image will only require 2560 bytes. The number of segments should be determined by a balance between performance and the overall memory constraints for the rest of the application. The reference to the newly minted VirtualFrame object is then passed to the instance of the display driver. Everything else about the driver works exactly as it did previously when actual RAM was being used.

The VirtualFrame class

This class is the workhorse driving the display and it’s worth explaining its core functions:

  • Copy: this method clones a virtual memory object into the current one. The two copies are identical afterwards.
  • Merge: this method takes a ‘background’ frame and a ‘sprite’ frame and combines them into the current virtual frame, effectively making this method a ‘BitBlit‘ function. Note that sprite transparency is not yet implemented. This method is used to display arbitrary graphics as well as printing strings on the display.
  • GetPathFromCharacter: given a character, this method returns the full path to the file containing the bitmap representing the character. This is heavily used by the Print method to print strings on the display. It relies on the ‘BitmapDirectory’ property to determine the final path.
  • Print: prints a character string at an arbitrary location on the display. Font transparency is not yet supported (see Merge). The dimensions of the font bitmaps must be provided as well. Also, the font is strictly limited to what is required by the clock application.
The following snippet shows how these methods are used to display the time and date on the display:

Strategies employed to dodge the dreaded “Out Of Memory” exceptions

In many ways, the “Klout Klock” application really pushes the envelope of what is possible on a Netduino Plus. To put things into perspective, here are the application requirements that needed to fit in 28KB of RAM:

  • Use NTP time to update the internal clock of the Netduino Plus
  • Use HTTP REST calls to fetch Klout metrics
  • Parse JSON responses containing the Klout metrics
  • Display the date, the time and the Klout metrics
  • Drive the AdaFruit ST7735 TFT screen
To make it all fit, none of the standard .Net Micro Framework classes supporting HTTP requests and JSON parsing could be used without systematically running out of memory and they had to be substituted: HTTP requests are made by the application using plain old TCP socket connections to the Klout web services, caching the responses to the SD card.
Being unable to find a suitable embedded JSON parser written in C#, I implemented a lightweight, non-recursive, JSON parser designed to process data directly from file streams. Finally, it was also necessary to explicitly manage the lifetime of C# objects and invoking the Garbage Collector along the way. In the end, this constant focus on being as lean as possible led to a C# application structured a bit like an application written in C 🙂

Source Code and Configuration

The source code for the “Klout Klock” is part of the netduino Helpers library on CodePlex and is located under the \Samples folder. To get your own “Klout Klock” going, you will need to edit the ‘resources.txt’ file located under \Samples\KloutKlock\KloutKlock\SD Card Resources.
You will need to register a Klout user name and acquire a Klout API key for yourself and substitute them for the user and key values highlighted in red below. The NTP servers referenced in the ntpServers value are tailored for folks living on the West Coast of the U.S, in the Pacific time zone, so you should probably select a set of servers closer to your actual location for best results. Likewise, the timeZone value should reflect your own time zone. Finally, if Daylight Savings Time is ON where you live, you should set the dst value to 1 and 0 otherwise.
* NTP Server list: http://tf.nist.gov/tf-cgi/servers.cgi
string:name=ntpServers;value=nist1-lv.ustiming.org,nist1.aol-ca.symmetricom.com,nist1.symmetricom.com,nist1-sj.ustiming.org,nist1-la.ustiming.org,utcnist.colorado.edu,utcnist2.colorado.edu,ntp-nist.ldsbc.edu
*
string:name=user;value=<KLOUT user name>
string:name=key;value=<KLOUT API Key>
string:name=host;value=api.klout.com
string:name=port;value=80
string:name=timeZone;value=-8
string:name=dst;value=1
Konclusion
For folks interested and actively participating in social networks, for fun or for profit, Klout has valuable insights to offer. As Klout integrates their services with more and more social networks, the relevance and accuracy of their metrics is bound to improve as well. Given their overlap, focus and methods, I would not be surprised if Google acquired Klout one of these days.
 
Now, if you excuse me, I need to go build an ‘EnKlosure’ for my Klock 😉

Links:

Using a MAX7219/MAX7221 LED display driver with a netduino

LED Matrix Glow

In a previous post, I described how to drive an LED matrix relying on persistence of vision. While beautifully minimalist, this method has drawbacks: it requires 11 digital pins on the netduino and takes constant CPU cycles to refresh the matrix. This can potentially put tough resource constraints on the rest of the application.

This is where a chip like the MAX7219/MAX7221 LED display driver comes in handy: all you need to do is to send it the data that you want to display over SPI and it will drive LEDs without further involvement from the micro controller.

The chip offers 2 display modes: ‘Decode Mode’ is intended to manage 7 segment displays (plus a dot) and another which displays raw bitmaps instead, perfect for controlling an 8×8 LED matrix.

Multiple MAX72xx chips can be daisy-chained together to form larger displays as well.

Being a popular chip, a great deal has been written about the Max7219 and after you familiarize yourself with the datasheet, you should check out this article on the Arduino Playground and come back here when you’re done.

Connecting the MAX72xx to the netduino

Here are the hardware components that you’ll need:

  • 1 Max72xx chip
  • 1 monochrome LED matrix (for example)
  • 1 Logic-level shifter (DigiKey) (optional: see note below)
  • 1 10K resistor minimum
  • 1 100 uF capacitor
  • 1 0.1 uF ceramic capacitor
  • many hookup wires (as short as possible)

Note: The MAX72xx requires 3.5 volt logic levels minimum and because the netduino uses 3.3 volt logic level on its digital output pins, you may need to place a logic-level shifter between the netduino SPI interface and the Max72xx SPI interface. Check out this article if you’re not sure how this works.

While the Max72xx SPI clock can go up to 10 MHz based,  I was unable to get stable communications above 2 MHz when using the MAX7219 with a logic-level shifter. Without the shifter, SPI @ 10 MHz works flawlessly but because this is out of the chip’s specifications, so your mileage may vary.

The following summarizes the connections. It doesn’t matter which pins you choose on the logic-level shifter provided that they’re matching low-level input/high-level output pins.

  • SPI CLK: netduino pin 13 -> Logic-level shifter -> Max72xx pin 13 (CLK)
  • SPI MOSI: netduino pin 11 -> Logic-level shifter -> Max72xx pin 1 (DIN)
  • SPI CS: netduino pin 10 -> Logic-level shifter -> Max72xx pin 12 (LOAD/CS)

Note: the MAX72xx is extremely sensitive to EMI and power fluctuations. So, be sure to:

  • Place the capacitors as close as possible to the V+ and GND pins of the chip
  • Connect both GND pins to ground
  • Use the shortest possible hookup wires

If EMI is an issue, reducing the speed for the SPI bus and/or using shorter hookup wires may help. If you still have EMI issues, the MAX7221 is likely the right alternative.

Connecting the Max72xx to the LED matrix

The LED matrix that I’m using is wired like this:

LED matrix

Connecting it to the MAX72xx is straight forward:

  • The MAX72xx’s SEG pins correspond to the columns of the LED matrix
  • The MAX72xx’s DIG pins correspond to the rows on the LED matrix

Max72xx -> LED matrix Wiring

Using the netduino.helpers Max72xx C# driver

The C# driver attempts to stick to the Max72xx datasheet as closely as possible. It presents properties matching the various registers of the chip and a simple overloaded ‘Display’ method. Be sure to check out the unit tests in the /Samples for usage details.

Max72xx C# Interface

Action shot

Happy hacking!

-Fabien.

Saving energy with a netduino

Bamboo leaf

Our home is equipped with a relatively old gas heater, built in 1996. It still works great, has been serviced regularly since it was installed and there is no good reason to replace it yet. However, it isn’t as energy efficient as more recent models.

The other aspect of this gas water heater is that it keeps the water hot 24/7, 365 days a year whether we need it or not. In my home, we generally only need hot water in the morning between 7 and 9 AM and in the evening, from 5 to 9 PM. On weekends, our schedule is a bit whacky and we need hot water from 8 AM to 9PM.

So, 30 hours for week days + 26 hours for weekends, that’s 56 hours / week where hot water is actually needed, as opposed to 168 hours / week when the heater is just left alone. In order words, in our house, we only really need a third of the water heater energy that we normally consume.

To make matters worse, the water heater was installed in the garage by the builder and it gets pretty cold during the winter time.

Considering that ~25% of our heating bill goes into heating water, I felt compelled to stop this senseless waste.

The idea that I came up with was to design a scheduler, configured to follow our weekly hot water usage pattern and capable of lowering the water heater temperature down to a minimum during off-hours.

I wanted it to be cheap to build with easy-to-find parts and very reliable as my wife does not appreciate cold showers: I decided to use a netduino-mini micro-controller, an AdaFruit DS1307 real-time clock and a servo to adjust the temperature of the water heater.

Here’s what the end result looks like in action:

Startup Sequence

Manual Override

The slow moving speed of the servo is intentional in the application in order to minimize wear and tear on the servo’s gears and the overall assembly.

The configuration of the clock and the schedule is done over a serial interface. Here’s a sample output:


[02/19/2011 19:29:40]
Water Heater Controller v1.0

[02/19/2011 19:29:40] Initializing...
[02/19/2011 19:29:40] Loading schedule
[02/19/2011 19:29:40] Centering servo
[02/19/2011 19:29:41] Setting heater on high heat by default
[02/19/2011 19:29:51] Running...
-------------------------------------------------------------
Time: Saturday, 19 February 2011 19:29:51
Heater Schedule Today: Sat [8-21] [0-0] [0-0] [0-0]
Heater Status: ON [scheduled]

Main Menu:
1 : Show Schedule
2 : Set Schedule
3 : Set Clock
4 : Swith Heater ON / Resume Schedule
X : Shutdown

[02/19/2011 19:29:52] Heater state change
[02/19/2011 19:29:52] Setting heater on high
1
-------------------------------------------------------------
Heater Weekly Schedule:

Sun [8-21] [0-0] [0-0] [0-0]
Mon [6-9] [17-21] [0-0] [0-0]
Tue [6-9] [17-21] [0-0] [0-0]
Wed [6-9] [17-21] [0-0] [0-0]
Thu [6-9] [17-21] [0-0] [0-0]
Fri [6-9] [17-21] [0-0] [0-0]
Sat [8-21] [0-0] [0-0] [0-0]

You can find the C# code for this project at http://netduinohelpers.codeplex.com.
Look for the “/Samples/WaterHeaterController (netduino)” folder.

The rest of this post documents the implementation details of the system you should be inclined to build your own.

Actuating the water temperature knob

Our gas water heater is equipped with a thermostat control like this one The knob has a large dial, with a fairly flat hand-grip surface.

I needed to figure out how much torque was required to turn the dial in order to buy an appropriate servo. The method I used was simple: mount a lever on the knob, attach a light container to the lever, pour water into the container until the knob turns, measure the amount of water poured and derive the appromixate amount of torque based on the length of the lever and the amount of water.

Using various Internet resources to calculate torque, I determined that I needed an absolute minimum of 12 oz-inch of torque to get the knob to turn. To be on the safe side, I selected a servo with nearly 6 times as much torque and purchased a HiTech HS-6635HB servo for about $30.

Why de-rate the servo requirements so much? A few reasons:

    The servo needs to be robust and reliable for many years and must not strain moving the load.
    Having too much torque is better than not enough and it is easy to control in software.
    High-torque servos have better ball bearing systems and stronger gears made of metal or heavy duty resin.

Mounting the servo on the water heater

I chose to anchor the servo to the gas pipe of the water heater, using the section of the pipe to the left of the gas valve. To do so, I cut a piece of wood from left-over hardwood flooring material to fit the lower left area of the pipe. I drilled holes on the top and left sides of the board so that it could be secured to the gas pipe using zip ties. I also drilled 4 holes to secure the servo to the board with long thin screws and locking nuts.

Connecting the servo to the control knob

The parts for this phase are easy to come by at hardware stores and craft stores:

Parts:

    2 popsicle sticks
    A spool of thin metal wire
    A thin but sturdy brass rod
    A section of rubber gasket long enough to fit around the circumference of the water heater knob. Make sure that the width of the rubber gasket doesn’t exceed the width of the knob’s hand-grip
    An adjustable metal ring
    Hand-craft a bracket the length of the popsicle stick from a thin strip of brass

Instructions:

    Drill two holes near the end of the popsicle sticks.
    Make sure that the thin brass rod fits easily through the holes but doesn’t have wiggle room either.
    Secure one of the popsicle sticks to the brass bracket with some tape then with the metal wire wrapped tightly around it.
    Insert the brass bracket between the rubber gasket strip and the metal ring
    Tighten the metal ring around the water heater knob.

The final assembly should feel tight and strong while turning the knob.

To secure the other popsicle stick to the arm of the servo, drill a few holes into the stick, matching the holes in the servo’s arm. Then weave the thin metal wire through the holes, then wrap the metal wire tightly around the stick and the servo’s arm. The final assembly should also be tight and strong while turning the servo’s arm.

Connect the popsicle sticks together with the brass rod and secure it by bending it carefully around the ends of the sticks. It’s easier to do this while the servo’s arm is not attached to the servo.

Finally, re-attach the arm to the servo and test the assembly by moving the servo’s arm slowly.

The knob should turn in sync with the servo with ease.

Building the Water Heater Controller board

This controller board is built around a netduino-mini, a DS1307 real-time clock by AdaFruit Industries and a few other components:

    2 1N4001 rectifier diodes
    4 LEDs of different colors
    4 ~220 Ohm resistors (for the LEDs)
    1 2N2222 transistor
    1 300 Ohm resistor
    1 momentary switch
    1 100 Ohm resistor (to be used with the switch)
    1 10K resistor (to be used with the switch)
    1 9 volt / 1A power wall-wart supply
    1 generic proto board
    straight and angled pin headers
    1 barrel jack connector for the power supply

Simple Wiring diagram

To further increase the life of the servo, I decided to control the power supply to the servo through a 2N2222A transistor. It works well because the servo doesn’t need to hold the water heater knob into place all the time: once positioned, the knob stays where it is and the servo no longer needs power to maintain its position.

The base of the transistor is connected to the ‘Servo Power Enable’ (pin 16 of the netduino mini) through a 300 Ohm resistor in series with a 1N4001 rectifier diode. The diode is there to eliminate 0.7 volts present on the pin even when it is turned off.

Here’s the thread on the netduino forums discussing the 0.7 volts issue which seems specific to the netduino mini.

To be on the safe side, I also added a 1N4001 rectifier diode on pin 23 (power ground) of the netduino mini to prevent any potential damage to the micro-controller if the power were connected backwards. I did not see such protection on the schematics of the mini.

Building the board:

The final board:

Operation

Connect a dumb-terminal to COM2 on the netduino mini (or to COM1 on the regular netduino).

Using the serial interface:

Set the clock’s date and time and define a schedule when the heater should turn ON.

The schedule tracks 7 days, with 4 timeslots for each day. Each timeslot has a begin time defining when the heater should turn itself ON and an end time, defining when the heater should turn itself OFF.

Setting a timeslot to 0 resets the timeslot and the heater stays OFF.

Keep in mind that the heater timeslots and the clock expect to work on a 24 hour schedule.

Heater Weekly Schedule:

Sun [8-21] [0-0] [0-0] [0-0]
Mon [6-9] [17-21] [0-0] [0-0]
Tue [6-9] [17-21] [0-0] [0-0]
Wed [6-9] [17-21] [0-0] [0-0]
Thu [6-9] [17-21] [0-0] [0-0]
Fri [6-9] [17-21] [0-0] [0-0]
Sat [8-21] [0-0] [0-0] [0-0]

The schedule data takes 56 bytes, which happens to fit perfectly into the 56 bytes of battery-backed user-memory in the DS1307 clock. Funny how this worked out 😉

The push button (High heat override) on the board forces the water heater into high heat, overriding the pre-defined schedule settings.

Meaning of the LEDs

    High heat LED: ON indicates that the water heater is set to high heat.
    Low heat LED: ON indicates that the water heater is set to low heat.
    Servo Active LED: ON indicates that the servo is changing position.
    High heat override LED: ON indicates that the push button was used to override the schedule.

Starting the water heater controller the first time

Before you apply power to the board, make sure that the arm of the servo is centered (vertical position). This will ensure that the startup sequence is smooth. From there, the controller will slowly set the water heater knob on high heat before tracking to the schedule.

I’ve been running the controller on the gas water heater for a few weeks now and I’m anxious to see what our next water heating bill will look like 🙂

Happy Hacking!

PS: a number of readers have mentioned the potential risk of Legionellae bacteria development in the water. While this bacteria is more of a concern with cooling systems, to be on the safe side make sure that you tune the system so that the water temperature reaches at least ~130 degrees Fahrenheit when the system is ON.