There And Back Again, A Servo Project

Apologies to Tolkien, of course! (There really is nothing too geeky for my blog, though.)  This project lets you set two positions for a standard hobby servo and switch between them.  It brings together most of the things I’ve learned about the AVR thus far: digital I/O, switch debouncing, analog-to-digital conversion, servo control and persistent storage in the onboard eeprom.  It doesn’t currently use interrupts, but they are pretty similar to the timer that drives the servo.  I built it on one of my EMSL mini dev boards so I’ve only tried the code on the ATmega168, but it should be pretty portable to other AVRs.

At some point I’d like to write up a tutorial series, but this article belongs somewhere around lesson 4 or 5.  If you’re just starting out, you’re welcome to dive in here, just be aware that it’s not really intended as a first project.  I assume at least some familiarity with C, microcontroller concepts and schematics.  I comment my code quite liberally and intend that to provide detailed explanations; what follows here is meant to provide some high-level descriptions and references for the major facets of the project and I recommend opening the code and schematic files below and referring to them as you read this.

My copy of X11 got pooched so I sketched the schematic in CreateThereAndBackSchematic.pdf (did I mention I desperately want a native Mac OS X schematic editor?); the code to drive it: ThereAndBack.c; helpers: bit_helpers.havrbuildavrpush

The circuit is pretty straightforward: a couple of buttons, “Go” tells the servo to go to the other position, “Set” switches into or out of set-mode; a potentiometer acts as a variable voltage divider, feeding an analog-to-digital converter input a voltage between ~0 and ~Vcc (plus it has a couple of extra resistors to limit current at the extremes); some LEDs to display the approximate value being read by the ADC because blinky lights rock; and finally, a standard hobby servo, I’m using a Futaba S3003 because it’s cheap and reasonably strong.  I have been powering the circuit from a USB port via my (patchedUSBtinyISP or with 3 AA batteries, but I have not been putting any load on the servo; note that the stall current is pretty close to the 500ma USB spec, so the batteries are the (slightly) safer alternative.

The code depends on a collection of bit manipulation convenience macros I’ve accumulated into bit_helpers.h.  The switches are debounced with a vertical stack counter (thanks, Bill!)  Both the ADC and timer are flexible but complex peripherals, requiring a fair amount of setup and configuration to have them do what you want. This page helped me a lot with understanding and using timers for pulse-width modulation and servos, the ADC I mostly had to piece together from the datasheet.  Fortunately, both can be really easy to use once you have their 10-or-so lines of setup: just set the right OCR register to adjust the width of the pulse that controls the servo or read the ADCH register to get the most recent converted value.  Finally, to make it remember the set positions even if it loses power, I followed this tutorial for the use of EEMEM / eeprom_read_byte, though it kinda glosses over loading the initial values into the chip.  The first step is to copy the eeprom data out of the .elf file with another avr-objcopy step: 

avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 -O ihex $ElfFile $EepFile

and push it to the chip with an extra -U to avrdude: 

-U eeprom:w:$EepFile

 I added those lines to the shell scripts I use to build avr projects and push them through to the chips (linked above.)

Finally, a couple notes on using it: when it powers on or goes into set-mode, it always starts in position A. When setting a new pair of positions, if the potentiometer is still where you left it after programming position B last time, the servo will move to that position, nevertheless it is setting position A. Also, when setting the positions the “Go” button still simply switches to the other position; in general, you want to hit “Set”, dial in position A, hit “Go”, dial in position B, then hit “Set” again (if you hit “Go” again after setting position B, you’re back to setting position A which will immediately get the current value from the ADC.)

One Response to “There And Back Again, A Servo Project”

  1. ubot studio says:

    Super information,I have Digged this site to my seo list for future and will keep a eye on your other postings.

Leave a Reply