December 5, 2010

Christmas-tree water-level sensor

UPDATE, 4 DAYS LATER: Don't build this one. The problem is the sensor: as a couple folk over at Hack-A-Day predicted, the copper sensor strips grow crystals that conduct enough to short out the sensor and give a false "ok" reading. One predicted it'd last a month, which would have been fine, but no... 4 days. That's it. I'll look into other metals (Stainless steel? Platinum? :-) ) as well as other ways of driving the sensor such as the polarity-reversal ideas mentioned by Tom and jpa below. Other suggestions are welcome too, of course.

Meanwhile, it's back to trying to just reach down into the stand to feel the water level.

-- --- ----- ------- ----------- -------------

Well, it's that time of year again. I'm not allowed to go into stores between Thanksgiving and Christmas — it's a long story involving singing Santa dolls, inflatable snowmen, and spandex bike shorts; and I won't tell it here — so since I can't go shopping I use my time more productively. Or at least I do some hardware hacking...

We have a very nice Christmas-tree stand: it's a tall, heavy, cast-iron chunk that does a wonderful job of holding our tree up. The problem is that it's difficult to determine how much water is in the stand, or whether the tree is getting any water at all. Occasionally our tree will drop all its needles, or spontaneously combust, at which point it becomes obvious that the tree needed more water; but it'd be nice to have some earlier indicator.

I discovered MIT's "High-low tech" site recently, and they have a nice tutorial on using the Arduino to program ATTiny45/85 chips. So I decided to use an ATTiny85 to make a Christmas-tree water-level sensor.

The circuit itself is dirt simple: Battery, ATTiny85, LED, resistor, buzzer, and water sensor. That's it.
The battery is a 3-cell AA battery pack (4.5V), and the buzzer is some random piezo buzzer that's been sitting in my parts bins for years.

The sensor consists of a strip of proto-board with three traces: two long, and one cut about an inch shorter. The way the water sensor works is the pull-up resistors in the ATTiny85 (about 20k) hold the inputs high by default. If a sensor wire and the ground wire are immersed, the small current through the water pulls the corresponding input low. If the water covers all three traces, that's good. If the water gets below the level of the short trace then pin PB3 goes high to indicate low water level, and if the water gets below everything then pin PB4 goes high to indicate very low water level.

The program checks the state of lines PB3 and PB4, and makes the LED blink repeatedly if the level is low. Should the level get very low, the program turns on the buzzer as well. Note: if you're making one of these yourself, make sure the difference in length between sensor wires PB3 and PB4 is enough that the tree won't go from "fine" to "buzzer" in one night. Otherwise the thing wakes you up early in the morning!

Here's the device, as I was testing it in a cup of water. The ground strip is becoming slightly discolored due to something electrochemically interesting going on, even with the low voltage and low current of this application. That discoloration should not interfere with operation, though.

To mount the device, I hot-glued magnets to the back of each piece.

The magnets make it easy to mount the sensor and circuit:
Here's the final product, tucked up under the branches at the top of the stand. It's out of sight unless you duck to look under the tree, and it's much easier to check the water level than before!

The same method could be used with an Arduino instead of the ATTiny85, and the program would work with an ATTiny45 or -25 also. (The compiled code uses fewer than 900 bytes.) If you re-wrote the program in PICAXE Basic, a PICAXE-08M would also work.

November 19, 2010

Improved Fan Cart

In an earlier post I described an Arduino-controlled fan cart. The driver I used was an L293D quad half-H chip, because I had one handy and was out of simpler parts at the time. It's always bugged me that I was just controlling speed on that cart, since it's possible to control direction with an H-bridge also.

I'd also gotten several suggestions of other features the fan-cart could have; and I've learned a bit about EagleCAD recently too, so I went back and re-did the device. Here it is: Fancart v2.1. I sized the board so that it fits in the board-holder notches on the top of the PASCO fan cart.

The three buttons set the mode, speed, and time. Any of the three parameters can be read by pressing the corresponding button: the setting will blink on the corresponding LED. For example, if the speed is 2/3, then pressing the speed button will cause the green LED to blink twice.

Any parameter can be set by holding the corresponding button for two seconds and then releasing it. The parameter LED will turn off, and each subsequent press of the button advances the parameter through its cycle of values. For example: to change the speed from two (default) to one (lower speed), hold the speed button for two seconds then release it. The green LED will turn off. Press the speed button again and the green LED will blink three times (speed is now 3). Press the speed button once more and the green LED will blink once (speed is now 1). Press either of the other buttons to accept the change and go back to normal run mode.

There are three modes available in the current program:
Mode 1: The fan toggles between on and off each time the sensor sees a magnet. This is what the previous fancart did.
Mode 2: The fan turns on when it sees a magnet, and then turns off T seconds later, where T is the time setting. The current program has available T settings of 1-4 seconds, although that's easy to change.
Mode 3: The fan reverses each time it sees a magnet. This is kind of fun: one magnet in the center of the track results in anharmonic oscillation.

It's easy to put in other modes, or even to completely change what the buttons and LEDs do. The Arduino has 30k of memory, and this program uses only 2.5k so far...

One note about the magnetic sensor: instead of the reed switch on the previous version I'm now using an AH182 Hall effect sensor. The advantage of this sensor is that it's more sensitive, it has hysteresis so no debouncing is necessary, it's completely insensitive to vibration, and it's much smaller. The disadvantage is that it takes three wires instead of two, and the polarity of the magnet matters. But overall, it's a great improvement!

Here's the code, and here are the EAGLE files.

August 31, 2010

Network-status indicator

I run a NFS/NIS network under a combination of OS's for the upper-division physics lab here at CSUC, and one source of irritation is when one machine goes down and nobody lets me know until suddenly that machine is absolutely necessary NOW! So I figured an Arduino, living in the machine on my desk, might serve as an early-warning system for network problems.

I used red/green common-cathode LEDs for my indicators: that way the Arduino can set them to be green if the machine is fine, red if the Arduino notices a problem, and both (yellow-orange) if the computer status is "iffy" or "unable to determine due to other problems."

With 13 computers I wanted to track and effectively 2 LEDs for each, that gave me a bit of a problem with the number of outputs on the Arduino. Here's how I took care of it:
The Arduino cycles through the "bank select" outputs (1G-2R), sending each one high for 2ms in turn. While each bank is high, the "LED select" outputs (A-F) go LOW to turn on whichever LEDs I want on in that bank. Persistence of vision makes it look as if everything is on when it's supposed to be, although each one is actually on for only 25% of the time.

Example, just for clarity: if you want the third LED from the left in the top row to be green, then when bank select 1G is high, make C low; and when bank select 1R is high, make C high also.

I used the "Ports" on the Arduino to quickly and efficiently turn the pins to the correct values all at once. Port D is pins 0-7, and port B is pins 8-13. Port B (six outputs) runs the LED Select pins (A-F), but port D is a bit less direct since I also want to use the serial port (pins 0-1) for communication with the host machine. So... Pins 2-5 of port D are the "bank select" pins, and I did not change anything on pins 0-1 so as to leave the serial port alone. Pins 6 & 7 were still unused, so since I still had one bicolor LED to drive I just put that on those last two pins.

That's the idea: here's the hardware:
I used an Arduino Pro because (a) it was sitting around and (b) Sparkfun had shipped me a defective one in which two of the analog ports were solder-bridged together at the µcontroller. (Watch the quality control there, guys!) This particular application doesn't use the analog inputs anyway, so I didn't mind hardwiring the defective board into an assembly that wasn't affected by the defect. I used a spare mini-USB adaptor for communications with the host computer: it was either that or dedicate my one remaining USB-Serial FTDI cable to the innards of the host. The front panel (black, to the upper right in the picture) is just a removable bay panel from the front of the host machine.

The software requires two separate programs: one to run on the host machine and determine the status of the various machines on my network, one to run on the Arduino and control the lights based on the information it gets from the host.

Here's the host program, in Python; and here's the Arduino program.

It works quite nicely! The host program runs as a cron-job once every minute, and the Arduino program sets the lights. If the Arduino doesn't hear from the host for more than 90 seconds, it assumes the host is down and lights things accordingly.

Here's a picture of the final product, with everything working smoothly. The position of the lights is indicative —to me— of the computer's location in the lab. Admittedly this is not immediately obvious to anyone else, but I made this for my convenience and I'm a very visual/spatial thinker so it works nicely for my needs!

In retrospect... I have a 2x16 LCD display sitting in my parts-box. Why didn't I use that? :-7 Ah, well, this works.

July 11, 2010

Arduino datalogging accelerometer with µ-SD storage

Thanks to Will Greiman's Fat16 library for the Arduino, I finally got a useful version of this datalogger working! Here's the schematic:

And here's the code.

The code is highly configurable: it can save raw A/D values or converted values, it allows software-defined gain, it can collect for a set time or until user input, and of course the collection interval is user-defined. It also includes a "DEBUG" mode, in which it tells the serial line everything that's happening. It can collect multiple data files (up to 100) per card, and will tell you about any errors it encounters.

All this in a small enough program to fit on an ATMega168! The data collection rate is not as high as I'd like on this 8MHz chip, and the sync() calls to the µSD card cause missed data intervals when the sample period is below 100ms, but for slower data-collection situations it works great. (Does anyone make a 32MHz 3.3V Arduino? That would be nice, here...)

Now to go do some physics with it!

June 22, 2010

Arduino-Controlled Physics Lab Fan-Cart

A "fan cart" is a roughly constant-force device used in introductory physics labs. It consists of a fan (usually a model airplane propeller on a brushed DC motor) mounted on top of a low-friction cart. Students use it to pretend they're learning something about force, acceleration, energy, etc. If you've ever taken an introductory physics lab, there's a good chance you've seen one.

A couple weeks ago I was at a physics teachers' conference where Mark Masters and Tim Grove, from Indiana Purdue Fort Wayne, suggested modifying a fan cart so that it turned on or off at certain positions on its track. This would allow some interesting lab exercises in which students could look at the change in kinetic energy of the fan cart over a distance interval, relate it to the force applied by the fan, and pretend to learn even more about force and energy.

So here's my take on it.
The fan cart comes with a quad-AA battery holder and a switch, which I used for the power supply. The Arduino used was a 8MHz ATMega168 3.3V version, not that it matters much. I used 1/4 of a quad H-bridge to drive the motor —a single MOSFET would have worked fine— because I didn't have a MOSFET handy that would turn completely on with a 3.3V input.

The three LEDs indicate power level. The pushbutton cycles through PWM power settings: 0, 150/255, 200/255, 255/255. The reed switch (salvaged from a bike computer after a fairly spectacular mountain-biking "incident") toggles the motor on or off each time it passes a magnet.

Here's the program.

So... Put this on top of a Pasco (or Vernier) cart, mount the reed switch on the cart so it can "see" magnets taped to the side of the track, and carry on pretending to learn physics...

February 16, 2010

Simple Datalogger

Here's a simple Arduino-based datalogger I'm currently developing:
This test-of-concept model is based on the Arduino Pro Mini (ATMega168). It runs on a 1.5-V battery, using a voltage up-converter from For a sensor, it's using a 3-axis accelerometer on a breakout board, also from Sparkfun.

It has one button for control. When the device is reset, it waits until the button is pressed. When the button is pressed, it collects data at roughly 10 Hz for a brief interval, then goes into a wait state again. When the button is pressed a second time, it sends the data out the serial port. The red LED lights up during the data collection period, just so you can see what's going on.

Here's the Arduino code.

The corresponding computer program takes the data-dump from the Arduino and plots/saves it. I wrote mine in Python, but any language that allows communications via serial line —and they all do— will work fine.

The device has serious limitations, though. For starters, the A/D conversion on the ATMega chip is only 10-bit, so the precision of the measurement is limited to one part in 1024. More importantly, the memory of the ATMega is severely limited. There may be 16k or 32k of flash on the microprocessor, but that memory is not available to variables. The data has to be stored in the microprocessor RAM, which is only 1-2k depending on which Arduino is being used.

To make this more useful, I need to add memory: either in the form of an external memory chip or a micro-SD card. But the basic idea shows promise.

January 14, 2010

Clock Update

I've posted an updated version of the "overkill clock" code.

This update takes care of a major bug in the alarm-sensing code that made any day's alarm go off every day. There's also a couple of minor code-cleanups and the addition of a time-out on the DealWithButton() function. (Without the time-out, accidentally bumping the button in the night prevented the alarm from going off in the morning. Now you have to accidentally bump it twice for the same effect.) One could add the same sort of time-out mechanism to the rest of the user interface code in SetAlarm() and SetClock(), but I chose not to.

January 1, 2010

Alarm Clock Overkill

I don't get up at the same time every day, so I thought it'd be nice to have an alarm clock that would drag me out of bed at different times on different days. That was the initial idea: things got out of hand, of course, and this is the result.

What it does:
1) It displays the time, day, and date. It also keeps track of the year, leap years, and adjusts automatically for daylight savings time.
2) It displays the temperature.
3) It has seven independent alarms, each of which can be set for different days of the week. For example, one alarm can go off at 5am on Tuesday, Wednesday, and Friday while another can go at 6am Monday and Thursday and a third can allow me to sleep until 7 on weekends.
4) In the event of power failure, the clock keeps time anyway. The alarms and display don't work when the power's off of course, but when power comes back on the time will be correct and it remembers the alarm settings.
5) It announces special events. Today is New Year's Day, so the bottom line of the display alternates between day/date (shown above) and the message shown below.

There are over 150 of these special events programmed into the clock, including family birthdays, oddball holidays (Squirrel Appreciation Day, anyone?) and so on. On my kids' birthdays it even tells me the age of the kid. (A useful bit of information that sometimes escapes the geek mind, as you probably have noticed —or forgotten— already.)

How it does it:

The brains of the unit are supplied by an ATMega328 Boarduino  (Arduino clone). This keeps the display up to date, turns alarms on and off, and runs the user interface. It also stores and displays the various special events for the year.

Accurate timekeeping is provided by a DS1307 real-time-clock chip. This chip also has 56 bytes of spare EEPROM which I use to store the alarm information in the event of power loss. Communication with the microcontroller is via I2C bus.

The alarm beeper itself is a simple piezo buzzer from Radio Shack, driven off the 9V supply line with a 3904 NPN transistor. The Boarduino can make the buzzer sound without the help of the transistor, but the goal is to not just sound the buzzer but get me out of bed!

Temperature sensing is via an LM35 temperature-sensitive zener diode. This is a great little component! Put in 5V, and the signal line puts out 10mV/°C. It's that easy. I use these, or the similar LM335, in my physics lab quite often.

User input is via a pushbutton/quadrature knob. The user presses the knob to select an action or set a number, and turns the knob to dial in the option of his choosing. Much better than the usual 4-button combination on the top of most alarm clocks.

Here's a cut-down version of the code. I trimmed the getMessage() function in this sample code to just show an example of how the "special events" code works — you'll have to put in the special events of your own choosing. (Or you can email me and I'll send the uncut version.)

Notes about the hardware:
1) The 2x16 character LCD uses the standard Hitachi HD44780 driver and the LiquidCrystal.h library. With some modification you could make it work with other LCDs, although this code is optimized for 16-character lines.
2) I put 0.1µF caps to ground on each of the three switch lines on the rotary switch, in addition to the usual 10k pull-up resistors. This combination nicely debounces the quadrature signal.
3) The DS1307 clock chip requires 3V on the "battery backup" line. It will not work without this.
4) I soldered the crystal directly to the DS1307 chip to minimize any clock error due to crappy breadboard connections.
5) As written, the code requires an ATMega328 or larger microcontroller. The "stock" ATMega168 does not have enough memory to run this program unless you get rid of the alarms or most of the daily specials.

It needs an appropriate case of some kind. I'm planning to etch a small batch of boards for these, driven with bare ATMega328's instead of the Boarduino I used for this prototype, and I'm thinking some sort of retro-steampunk case. I'll post pictures when it's done.

Want to build one yourself?
Download the code here. The hardware is very straightforward, here's an electrical diagram. I don't recommend this as a first Arduino project, though!