Incorporating an Accelerometer

The accelerometers that I ordered from SparkFun arrived late last week. I got two of them: one analog (ADXL335) and one digital (ADXL345). The analog one is supposed to be much simpler to use, and it’s a little bit ($3) cheaper, but the digital one requires less power, is less prone to errors, and has more features (including a 0g detection interrupt). I ordered the analog one, then decided to give the digital one a shot even though they said it’s more complicated. I considered cancelling the order for the analog one, but I realized that I’d really like both so I can see the differences in capability first-hand.

So, all that being said, I tried to make the digital one work first, because I know I’ll be able to make the other one work. I do love a challenge.

It turned out to be much easier than I was afraid it would be, thanks to detailed information from Euristic at Live Fast, Code Young. With his code and instructions (with slight modifications for the Mega board pin differences), I had a test program reading data from the accelerometer in 10 minutes of effort. Amazing.

The ADXL345 has a total of 8 pins on the breakout board, which are labeled GND, VCC, CS, INT1, INT2, SDO, SDA, and SCL. For my purposes (and the test program), it is safe to completely ignore INT1 and INT2. Connect GND to the Arduino board ground (obviously), and VCC to the 3.3v pin (not 5V, this can damage the accelerometer). Short CS to VCC right on the breakout board, and solder a small jumper wire between GND and SDO. Finally, plug SDA and SCL into pins 20 and 21 respectively of the board. Note these pins are specific to the Mega; on other Arduino boards, SDA and SCL are analog pins 4 and 5 respectively. With this arrangement and the source code on the above linked blog, I had a steady stream of data flowing in.

Euristic’s schematic has two 10k resistors acting, I believe, as pull-ups from VCC to SDA and SCL. I am honestly not sure what their purpose is, since the behavior seems to be the same whether they are there or not. I left them in though.

After getting the device to work using Euristic’s code, I switched over to the slightly cleaner and more complete ADXL345 library from user kstevenard on Google Code. It works the same and has methods to make use of all the settings available on the accelerometer.

Next, I wrote some code that converts the measurements into angles for each axis. It isn’t perfect, but it’s certainly pretty close. I think a sharp movement would generate unusable data, but we’ll see. I’m still trying to get the PS/2 mouse code to actually move the mouse on my computer; it’s giving me a lot more trouble than the keyboard code did. I figured it would just work since I have the active PS/2 adapter and everything.

Types of motion detection

However, there’s another conceptual problem to solve here: how exactly should your physical motion be translated into mouse movement? There are three main approaches here, and I’ll try to explain each. Two are tilt-based, and one is movement-based.

First, tilt translated to velocity is where the speed of cursor movement matches the steepness of tilt. This is kind of like the way the Trackpoint mouse on ThinkPads work, and it’s also kind of like how a game console controller works (imagine moving a small hand or crosshairs around using the D-pad). Interestingly, I love the Trackpoint, and I can’t stand D-pad cursor movement. I think the Trackpoint must be implemented extremely well, but I know it’s still something people have to get used to.

Using this method is simple to understand but difficult to master with precision. You have to speed up and slow down the cursor at just the right moment in order to “land” on the desired target. It’s very easy to overshoot (or undershoot). It would feel something like the cursor is a marble on a table, and you have to tilt and then re-balance the table at just the right moment. Personally, this sounds terrible to me for normal cursor movement. On the other hand, if you wanted to use the tilt of your hand to control lateral movement in a 3D game, you might prefer this method.

Second, tilt translated to position is where the cursor position changes directly based on the orientation of your hand. If you turn your hand to the right and leave it there, the cursor will move to the right and stay there. In contrast to the previous method, it won’t keep moving until you make your hand level again. This movement can be tracked on any axis. This seems much more intuitive to me than the previous option for normal cursor movement.

The downside of this approach is that you can only rotate your hand about 180 degrees left/right and more like 90 degrees up/down. This means one of two things: either the range of motion would have to be calibrated so you could reach all edges of the screen through one full sweep of each axis, or else you would need a way to temporarily disable motion while you reoriented your hand.

This second “fix” is much the same as when you’re using a desktop mouse and you run out of space while moving across the desk, you simply pick up the mouse (to prevent backwards movement) and put it back down on the desk so that you have more room to move. Most of us do this without thinking about it. For this reason, I believe a similar solution could be used in the Keyglove, perhaps by having a simple “hold” touch combination that would leave you in “mouse” mode but prevent any motion. Then, when you release the “hold” touch, you would be free to continue moving.

Third, movement translated to position is where the speed of the cursor movement matches the speed of your hand movement. This is the easiest to implement in the code, but requires a lot more effort and available space. It does feel very Minority-Report-esque though. Essentially, if you move your hand up and down, the cursor moves up and down with it. Left and right movement function the same way. The downside of this approach is that you need more room to move around, it’s far more visually distracting, and it is also far more physically demanding than the alternatives. It might be nice for a vigorous presentation though. I would think that if you can master the first or second approaches using tilt (which are much more subtle by definition), there’s no reason you’d ever want to use this approach—at least not for mouse cursor movement. Obviously, movement-based gestures could still be very valuable.

So what’s the plan?

I want to build support for all three of these methods into the glove code. Maybe there can be three different “mouse-on” toggle combinations, one for each method, so you can switch between them as you wish. All three methods should have a temporary “hold” combination (like picking up the desktop mouse off the desk).

Now If I can just get this PS/2 mouse emulation code working, I’ll be able to really test it out.

6 Comments

That depends on what your project is actually doing–specifically, whether it is moving linearly at all (up/down, left/right, forward/backward), or whether it is holding still except for in-place rotation. A 3-axis accelerometer can give you very good orientation data as long as it isn’t moving, because acceleration due to gravity is constant, and all you have to do is apply a couple of atan() or atan2() trig functions to perpendicular axes. But if some linear movement is introduced, then an extra acceleration component throws off the calculation. This is why good orientation systems (IMU or MARG devices) incorporate a combination of multiple sensors, such as accel+gyro, or accel+gyro+compass, or even accel+gyro+compass+barometer.

If all you have is an accelerometer, and your measurements are held in “x”, “y”, and “z” variables, try this: