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 Sparkfun.com. 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.

Next:
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!



December 19, 2009

Using a quadrature encoder (rotary switch) with Arduino

I've found several sites and posts explaining how to use a quadrature encoder with an Arduino, but wasn't completely satisfied with any of the methods used. Perhaps part of the problem is with the encoder I'm using: it's part #COM-09117 at Sparkfun.com.

This encoder has twelve detents per rotation, and each detent covers one complete cycle of Gray code. This means that the most common method of reading the knob counts four steps per detent, which isn't what I wanted.

So, backing up a bit... Here's how one of these things works. Instead of separate pins for each position as the knob turns, there are two pins (A and B) that produce offset pulses. The direction of the offset indicates the direction of the rotation.
As you can see from the diagram, as you rotate the knob clockwise, the pulses from A lead the pulses from B. Rotating counterclockwise, the pulses from B come first.

The detent spacing is marked on the diagram as "one notch", and if you just keep track of changes on  A and B there are four steps between detent positions. There is an event that happens only once per detent, though: that is a falling (or rising) edge on either A or B. So what I did is run an interrupt on the falling edge of A. Clockwise, B is high when A has its falling edge (at point 1) and counterclockwise B is low when A has its falling edge (at point 2). The interrupt routine just reads B, and adjusts the recorded position of the knob accordingly.

I connected one quadrature pin to Arduino pin 2 and the other to Arduino pin 3. Pin 2 is interrupt 0 for the Arduino. Here's my code:

/* knobtest.pde
Test of optical encoder (Gray scale)
Eric Ayars
*/

byte Blinker = 13;
int Delay = 250;
byte A = 2;        // One quadrature pin
byte B = 3;        // the other quadrature pin
volatile int Rotor = 0;

void setup() {

    // set DIO pins
    pinMode(Blinker, OUTPUT);
    pinMode(A, INPUT);
    pinMode(B, INPUT);

    // Turn on pullup resistors
    digitalWrite(A, HIGH);
    digitalWrite(B, HIGH);

    // Attach interrupt to pin A
    attachInterrupt(0, UpdateRotation, FALLING);

    // Use serial port to keep user informed of rotation
    Serial.begin(9600);
}

void loop() {
    // Basic blink program here: interrupt comes in as needed.
    digitalWrite(Blinker, HIGH);
    delay(Delay);
    digitalWrite(Blinker, LOW);
    delay(Delay);
}

void UpdateRotation() {
    // This is the subroutine that runs every time pin 2
    // switches from high to low.

    if (digitalRead(B)) {
        Rotor++;
    } else {
        Rotor--;
    }
    Serial.println(Rotor, DEC);
}


The program blinks the LED on pin 13 at a frequency of roughly 2 Hz, but any time the knob is turned it sends the new position out the serial line and then goes back to blinking.

I wouldn't recommend this method if the exact position of the knob is critical. It works great as a user input device, though.

November 16, 2009

"Arduino for Artists" Workshop

The micro-course for art/sculpture students was fun, interesting, and generally worth the time and effort. Of course, I taught it so there may be some bias there. :-)

Here's code for the various examples we covered in the course.

And a big thank-you to Ellen Akimoto for instigating the event!