June
2006, Issue 191
Nontraditional
Cursor Control
ATmega32-Based
Motion Sensing
by
Andrew Sawchuk & Joseph Tanen
HIGH-LEVEL
DESIGN
Two
occasions during our senior year at Cornell University
provided inspiration for our project. The first was
when Bruce Land, our microcontroller programming professor,
exclaimed, “I have free accelerometers, and they can
be used to do cool things.” We immediately felt as though
we should explore the possibility of basing a design
on the accelerometers. We then thought for a while about
the kinds of interesting devices into which we could
integrate acceleration sensors. During our brainstorm
session, inspiration dealt us a swift right hook. We
agreed that a glove like the one Tom Cruise’s character
used in the movie Minority Report (2002) would be an
intuitive HCI that wouldn’t be impossible to make. Accelerometers
seemed to be the ideal sensors for constructing a hand-mounted
pointing device.
Our
original plan was to use accelerometers to measure the
acceleration of a user’s hand and then integrate that
acceleration into a change in position. The math is
simple. Using Verlet integration, we would approximate
the integral of the acceleration to the second degree.
Verlet integration interpolates between two measured
accelerations, using the average slope between them
to derive velocity. This is sometimes called trapezoidal
integration. The equations are:

This
approach, however, turned out to be a practical impossibility.
Although we successfully implemented the Verlet scheme
and watched a mouse cursor controlled by the scheme
move on the screen as we had expected it to, the glove
had to be held exactly at 0 g (or 1 g for Earth-normal)
in all three directions. If gravity were allowed to
affect the accelerometers at all, this acceleration
added to the integral. With no negative acceleration
to remove it, the change in position that we calculated
grew boundlessly.
We
needed gyroscopes to measure rotation from our calibration
point so that we could remove the effects of rotation
from our calculations and take into account only the
lateral motion of the glove. Gyroscopes, however, are
expensive. The cheapest ones come in ball-grid-array
(BGA) packaging and can’t be soldered by human hands.
We didn’t have access to a reflow soldering oven either,
which is needed to attach BGA components.
So,
we scrapped the idea of a gyroscope. Instead, we decided
to construct a tilt mouse. Although it isn’t as impressive
as a position-tracking device, the tilt mouse is easy
to use (after some practice) and almost as neat as a
position-tracking mouse. The process behind this scheme
is straightforward. Simply measure the acceleration
due to gravity on the mouse by sampling it with an ADC,
and then multiply the sampled value by some constant
to scale the output to a desirable level.
The
Microsoft serial mouse protocol uses an 8-bit two’s
complement number scheme to send data to the computer.
The numbers output by the ATmega32 microcontroller’s
ADC can be conveniently represented in the same number
of bits, albeit in an unsigned format. As a consequence,
we had to perform some bitwise math on the sampled values
to scale the 0-to-255 range of the ADC to –128 to 127.
We also had to make sure the output from the Analog
Devices’s ADXL203 accelerometer was centered in the
ADC sampling band. (In the next section, we’ll discuss
exactly how this was done.)
In
addition to scaling the output, we used a step filter
on the data to make the mouse easier to use. Our accelerometer
was so sensitive that the slightest hand motion would
cause the device to output a nonzero acceleration. To
give the user a more stable region around the zero point,
we quantized all outputs below a certain level to zero
and then normalized any outputs out of this cutoff range
by the breadth of the cutoff range. For example, if
the cutoff were |10|, the intersection of all numbers
greater than –10 and all numbers less than 10 would
define the cutoff region. Any outputs outside this range
would be normalized by 10 or –10, depending on whether
the output were negative or positive, respectively.
In
addition to position changes, the mouse detects button
presses. We implemented four buttons in our mouse: Output
On/Off, Left Click, Right Click, and Scroll Enable.
Each push button is connected to a port pin on the ATmega32
microcontroller. When the output on/off button is pressed,
the serial mouse output to the computer is enabled,
reenabled, or disabled. This allows you to move your
hand and not have the motion affect the mouse pointer.
The left click button functions as a left click on a
mouse. The right click button functions as a right click
on a mouse. The scroll enable button disables all motion
and other button outputs while it’s held down. It causes
the accelerometer’s y output to be interpreted as a
scroll wheel output to the computer.
The
only hardware/software trade-off with which we had to
deal was the sensitivity of our ADC. The granularity
per sampling division of the ADC is approximately 19.5
mV per division. When we used accelerometers with sensitivities
of approximately 50 mV/g for our position mouse, the
outputs of the devices had to be normalized to the full
ADC range of 0 to 5 V so that we would have good sensitivity
on our device. We’ll explain this in the next section.
The
ADXL2303 accelerometers we used for our tilt mouse output
1,000 mV/g, so the sensitivity was much higher. But
we decided to normalize the range to 2,000 mV/g to gain
even higher sensitivity, especially because we already
had the necessary circuits designed and constructed.
Another
hardware/software issue to consider is push button bouncing,
or the inconsistent state in which some push buttons
can remain for a certain amount of time after a transition.
Our buttons were internally debounced (see Photo 2).
This enabled us to remove the button press state machine
from our code. We could simply read the value of the
push button when we needed to measure it.
|

(Click
here to enlarge)
|
Photo
2—Using debounced push buttons, we cut the complexity
of our polling logic and code length significantly
because the buttons’ states would become consistent
more quickly than we polled them. |
Our
design follows two standards. We use the Microsoft serial
mouse protocol and an RS-232 serial connection. RS-232
uses –12 and 12 V for high and low signals, respectively,
and it idles at 12 V. The ATmega32 microcontroller outputs
5 V high and 0 V low serial (TTL level), so we had to
use a serial level shifter chip to enable it to properly
speak with the computer.
The
Microsoft serial mouse protocol works differently. When
the RTS line of the serial connection is pulled logic
high and then falls logic low, the computer expects
you to send an identifier string to determine the type
of device being used. The protocol expects data at 1,200
bps, 8 data bits, 1 stop bit, and no parity. The controller
sends it an “MZ” message, indicating the Microsoft serial
scroll mouse. The computer may query you for this information
multiple times; however, after approximately five times,
you can stop sending it the identifier code because
it will consider you to be identified.
The
packet format is shown in Figure 1. L, R, and M are
the left, right, and middle mouse buttons, respectively.
A one indicates pushed. A zero indicates not pushed.
Y7 (most significant) through Y0 (least significant)
represent the 8-bit two’s complement mouse delta Y,
with positive Y pointing to the bottom of the screen.
X is the same format as Y, with positive X pointing
to the right of the screen. Z is also in the same format
as Y, with positive Z being scroll up, except that Z
is measured in 4-bit two’s complement. The first 1 bit
in every packet is an extra stop bit. From what we’ve
seen, some implementations set this bit high and some
set it low. We listened to the data coming off of a
genuine Microsoft serial mouse. It set the bit high,
so we chose to set it high.
|

(Click
here to enlarge)
|
Figure
1—Each packet sent using the Microsoft serial mouse
protocol has this format. L, R, and M are the status
of the buttons. The 8-bit Y and X represent the
change in mouse position from the time of the previous
packet. |