Sunday, September 13, 2009

Digital Defocus - A Clock













The Concept

7-segment LED's form the digital readout (DRO). These are located on a moving sled that can move back and forth using a DC closed-loop motor control system. In front of the DRO is an array of lenses that allow for defocusing of the digits as they are shifted by the motor. This creates an unusual effect that can be implemented as desired in the programing. At this time the effect is randomized over the course of a single minute. The electronics clock is a real-time clock w/ battery so that when power is lost the time is retained. The overall controller makes use of a Dorkboard which is a version of the Arduino microcontroller. 2 buttons allow for changing minutes and hours and another 2 accessory buttons are used to disable the movement and to allow for triggering a 'night mode' that quiets the system in the evening. Everything is housed is a very sturdy, custom machined aluminum housing. A 32v DC power supply powers the system.

The Electronics

A complete schematic may be found here:

A Dorkboard was used as the microcontroller. This is an Arduino system based on the Atmel ATmega128 microcontroller.

The real time clock made use of a DS1307 board with battery backup. It communicates with the Arduino using an I2C interface. A MAX7219 LED driver IC was used to multiplex the LED digits. It communicates with the Arduino using a serial interface. The L298N dual full-bridge driver IC was used to drive the DC motor using a source voltage of 32v. The 32v supply fed into a LM2574 buck regulator IC to provide a 5v supply. A series of NOR gates are used to create 4 S-R latches that act as memory for button presses. The outputs of these latches feed into the Arduino as well as a series of OR gates to provide a single output for indication if a button has been pressed.

Here is an early breadboard of the LED setup w/ switches and the DS1307 real-time clock board:

Early testing of the drive system with breadboard:

Breadboard of the 32 to 5v power regulator circuit:

The final board, almost done:

The back side of the main board almost done:

I later switched from the L293D motor driver to the L298N as seen here. It is a much more bomber driver. I had been burning up many L293D's - I think because with my 32v supply I was operating close to the power dissipation limit. At this late stage, I only had room for the device on the back side of the board:

The inside of the clock w/ electronics and motor:

Inside the completed clock:

The Firmware

The code uses nearly all of the available memory of the ATmega128. Code is fully commented and may be found here:

Closed loop motor control is enabled by using Timer2 to generate the desired pwm to the motor. A PD controller algorithm was used. Encoder feedback is counted by setting up Timer1 as a hardware counter. These counts happen in the background and thus an interrupt is not necessary. With these timers taken, I was forced to use discrete IC's (S-R latches via NOR gates) as memory for any button presses since there were no interrupts available to capture the input.

The LedControl library was used for controlling the LED's.

The Mechanical Hardware

The drive system makes use of a 40:1 gear reduction off of a small DC motor. A DC motor was used to attempt to minimize noise in the system. Regular servos and steppers are LOUD. A linkage system drives a sled that rides on 2 sets of rods and bushings. The DC motor includes an optical encoder wheel w/ encoder which allows for closed-loop control of the drive system. Ball bearings form the user interface to the top two accessory switches and machined aluminum caps were used on the buttons for the rear time changing switches.

Here you can see the ball bearing switches:

There are 2 lenses per digit. The outer dome-shaped lenses were used for aesthetics but they also serve to magnify the digits. The inner, non-visible lenses are FOFP's or fiber optic faceplates. An FOFP is comprised of an optical mosaic of glass fibers which are fused together to form a cylindrical plate. The plate is effectively equivalent to a zero-thickness window since the image formed on one surface is precisely transmitted to the opposite surface with no change in focus and minimal loss of light. This device was used to induce an interesting defocusing effect. When the LED display is in contact with the FOFP, the image is transmitted sharply in focus. However when the display is moved away, a defocused image appears.

Here's an example of an FOFP:

The entire clock was designed and modeled in 3D CAD.



Almost all internal and external parts were custom machined from either aluminum or Delrin (drive parts). The gearing system and motor were obtained from an old optical scanner. The exterior parts were made with a combination of manual milling on a large Bridgeport and CNC milling on a Taig mill. The outer front housing was countour milled using the Taig mill with a Mach3 driven control system. The tool paths were generated using Pro/Engineer.

Here are some pics of the CNC process using the Taig milling machine.

The LED sled is being cut here:

Rough cut of the front faceplate:

Rough contouring on the faceplate:

Detail of the final contour pass on the faceplate:

The finished result of the faceplate (prior to adding the lens holes):

A lot of sanding and polishing was required to turn the relatively rough surfacing into the final smooth part.


Friday, June 19, 2009

DC Motor Closed-Loop PD Control Code

Here is code to do closed-loop DC motor control with the Arduino and the L293D motor driver IC:

http://docs.google.com/View?id=dhjz44fg_8f6sh7tcj

Features:
-- Makes use of the L293 motor driver; may easily be adapted to another
driver
-- Motor pwm'ing implemented by direct control of the ATmega Timer2
-- Closed-loop feedback via encoder wheel on the DC motor
-- Hardware counter implemented using Timer1 of the ATmega for
high-frequency capture of encoder counts - no interrupt
necessary!
-- PD control system implemented for motor control


My main source of info for implementing motor pwm'ing with the L293D was
this document:

http://www.arduino.cc/playground/Main/DirectionalMotorControlWithAL293D

The author is not listed so I can't provide specific credit. The code is
not particularly well-documented so I have attempted to remedy that in
my own code below.

Here is a link to the ATmega48/88/168 datasheet. I happen to be using the ATmega168. This resource is invaluable in gaining an understanding of the
hardware counters/timers. All page # references below are to this document
unless otherwise specified.

http://www.atmel.com/dyn/resources/prod_documents/doc2545.pdf

Here is a link to the L293D motor driver datasheet
http://www.robokitsworld.com/datasheets/l293d.pdf

User 'mem' from the Arduino forum was very helpful in giving me tips on implementing a hardware counter for the motor encoder. This link in
particular was exactly what was needed:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1231326297/all

Other links that were helpful:
http://letsmakerobots.com/node/2074
http://thecodebender.com/journal/2009/2/21/we-just-cant-leave-things-well-enough-alone.html
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235060559/8#8
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1234764073
http://abigmagnet.blogspot.com/2008/10/dc-motor-control-part-one.html
http://mil.ufl.edu/~achamber/servoPWMfaq.html


For the PD control: the P is for position and the D is for derivative (or
velocity). Other systems also make use of I (integral, which gives you a
PID controller) but it is not particularly helpful in this application.
You may want to explore it for your own application. Computing the PD
gains is left to you. These are highly dependent upon the specific motor,
load, encoder resolution, and sampling frequency. You could just knob
twiddle until you find a workable combination. There are also analytical
methods out there for determining these gains.


Specific application notes:

The code here is tailored for a system that drives a part along a slider
rod (linear motion). In my case, this is done via a worm gear and a
linkage. I have roughly a 40:1 gear ratio. A homing move is implemented
to find a hard stop at the end of travel. The part is repeatedly moved
away from and then back to the home position. I added control input for
experimental use. Slew distance, acceleration, acceleration ramp - all
of these may be specifically tailored to your own application.

My motor is a smallish DC motor with a 32v supply. The quadrature encoder
provides digital output. I am using only 1 of the outputs in this case.
You could use the 2nd output for additional accuracy. Note that some
encoders output an analog signal. I used one of these initially and was
able to square up the signal using a Schmitt trigger. However, I had
noise coupling problems as soon as any pwm was input to the motor which
yielded spurious encoder counts. I'm not an EE so I abandoned this for
the much easier-to-use digital output encoder. My motor/encoder may be
found in some printer and/or scanner products where DC motors are used.

The Timer1 counter has a 16-bit register so if you expect encoder counts
higher than 16 bits, you will need to deal with this in the code. My
application runs well below this so I did not need to account for it in
this code.

In the motor_forward subroutine, I zero out any positive move errors
since in my application all forward moves position the driven part to a
hard stop. You can remove this positive move error check and modification
if your application is different.

I am checking the encoder position every 3ms or 333Hz (sample_freq). I
have placed some debug lines within this sample countdown period to ensure
that we have sufficient processor bandwidth. It's best to apply control
at the highest frequency possible. If you have other interrupts or other
processes happening during the motor move, you will need to slow down the
sample frequency. Note that the encoder counts are being refreshed at the
speed of the counter (really fast). I am only speaking of the frequency by
which I am computing position and velocity errors and applying control
gains

My L293D / Arduino / Motor connections are as follows:

Arduino digital pin 5 to motor encoder output pin
Arduino digital pin 11 to L293D pin 7 (motor pwm)
Arduino digital pin 12 to L293D pin 2 (motor direction)
Motor + pin to L293D pin 6 (pins 3 & 6 may be swapped to flip
the motor direction)
Motor - pin to L293D pin 3
Motor encoder +5v and ground pins suitably connected
L293D pin 1 connected to +5v (enable)
L293D pins 4,5,12,13 connnected to ground
L293D pin 8 connected to +32v (motor power)
L293D pin 9 connected to +5v (logic power)
Filter caps added per: http://letsmakerobots.com/node/2074

Thursday, June 18, 2009

New Project Coming Soon...


Just a heads up: I have a very interesting and detailed project to report on very soon. It's a digital clock. But a digital clock unlike any other you've ever seen. It is Arduino-based, makes use of a 7-segment LED controller, real-time clock board, DC motor controller with closed-loop feedback (YES - A MOTOR), a sweet contour-milled, machined aluminum housing, some unique optics, and other fun stuff.

It will take awhile to fully document - expect to see it within a month or so. I may soon be posting the DC motor control code separately as this should have good general use for many people. I've yet to see a nicely packaged DC motor control system w/ closed-loop feedback (PD controller) fully documented for the Arduino.

Wednesday, January 14, 2009

Arduino Webcam Servo Project




Having received my first Arduino I had to come up with a good first microcontroller project.  Something not too complicated but more than just a book example.  I had just purchased a wireless webcam (Linksys WVC54GCA) and thought it would be cool if I could move it around on a pan & tilt mechanism.  And how much cooler would it be to be able to control it over the internet?

After I completed this project I looked around the internet and found several other examples of this type of thing.  But I hope the documentation here is still useful as I don't recall any examples showing detail of how to use the Arduino and more specifically, the Xport in the designs.

Here are the pieces I used:

* Arduino ethernet shield (http://ladyada.net/make/eshield/index.html)
* 2 servos from my crashed RC glider
* The mechanical bits.  I used machined aluminum but you can use anything you like

CODE

I started with Ladyada's examples (http://ladyada.net/make/eshield/examples.html)

You can find my Arduino code here:  http://docs.google.com/Doc?id=dhjz44fg_5ct5p2374

You'll need to make sure you include the necessary libraries (AF_Xport.h, AFSoftSerial.h, ServoTimer1.h) which are needed by the code.

The code is fairly straightforward except for the bits about the web page.  Being an HTML rookie, I struggled a bit, but keeping things simple and using MS Frontpage as a crutch, I managed to create a very simple webpage.  And it needs to be simple to fit within the limited memory of the Arduino.  The large char strings early on in the code store the HTML.  Note that for every quotation mark in your HTML, you need to add a \ before so that you don't terminate the string.

One key is to enable a variable via the webpage pushbuttons.  Each pushbutton assigns a different value to the variable which tells the program which servo to turn as well as the direction.  This line of code was important to understanding how web pages transmit user input:

found = strstr(linebuffer, "?servo="); // "?inputfield=" GET request

Printing out the line buffer in the serial window allows you to see exactly the info that your web page is sending out upon a button push.  You look for this information in the line buffer and then extract the useful part - in this case, the value to indicate which button was pushed.

Another slight glitch I found was that the baudrate had to be reduced from that used in ladyada's example.  I don't know why.

WEBPAGE SETUP

One more area of complication is accessing the webpages.  The Linksys webcam has its own internal webserver.  This is accessed remotely by enabling port forwarding on your router.  To access this remotely, make use of your computer's ip address (not your local network) followed by a colon, and then the port that the webcam uses.  For example (this is a fake ip addy):  http://208.168.201.37:1024 

The Linksys happens to use 1024 as its port.  You do exactly the same for the Xport, except it uses a different port which is specified during the Xport setup process (see the ladyada site for instructions).  In my case it was 10001.

Note that your ip provider probably provides a dynamic ip address to your computer, meaning that it may change over some time (days, weeks, months).  To deal with this situation you may want to make use of a DNS service provider.  I used dyndns.com which is a free service.  This allowed me to use a semi-custom name that is linked to your computer's ip address (for example, something like http://yourname.dnsdojo.net:10001/).  When your ip address changes, software on your computer updates the DNS service provider.

Here's an example of the router setup to enable the port forwarding:



ELECTRONICS

These are stupidly simple.  I merely plugged the servos into ground and pins 9 and 10.

MECHANICS

I was lucky to have access to aluminum scraps and a machine shop.  I have limited skills with the equipment but was able to fashion some workable parts.  You can easily use any material you like.  I happened to put the pan servo mechanism on the bottom and then attached the tilt mechanism to that.  

The entire mechanism was mounted on a tripod using a tapped 1/4" hole in the baseplate.  Here are some additional pics of the mechanism.