Building a tilt-controlled prototype? First make sense of the accelerometer readings

You want someone to tilt an object and move a cursor, adjust a sound or change a light. The sensor example looks encouraging: connect four wires, run the program and watch three numbers change. But one example shows values near one, another near ten, and a third prints pitch and roll. Which one gets you closer to the interaction you want?

For a design or education team building its first working object, the useful starting point is the meaning of those numbers. Units, sensor orientation and filtering change how a reading should be interpreted. Comparing screenshots without those details can lead you to choose a component, or a movement threshold, for the wrong reason.

On our bench we ran five GraftSense accelerometer modules (MMA7660FC, LIS3DH, MMA8452Q, MMA8451 and BMA220) on a GraftPort-RP2040 controller board under MicroPython, each on I2C with GP4 as SDA and GP5 as SCL. These were separate demonstrations, not a controlled comparison of five sensors. Each one helps explain a different step toward a tilt control.

Decide what tilting should do

Start with a simple behavior: lean the object left and the cursor moves left; return it to a comfortable resting position and the cursor stops. That is a different requirement from counting a sharp shake or following the path of an object through a room. A basic accelerometer test can help with the first decision without settling the others.

This distinction often confuses new developers. In an Arduino forum question from April 2020, a user expected acceleration data to describe movement directly and instead found readings that changed with tilt. A readable mapping from movement to feedback is a better first goal than a long list of sensor features.

A stationary sensor does not normally read zero on every axis

For an ordinary unfiltered reading, a sensor resting on a table responds to the support force associated with gravity. Depending on orientation, one axis may sit near +1 g or −1 g while the other two are near zero. Tilt it slowly and that contribution moves between axes. Here g is a unit of acceleration, not grams: 1 g is about 9.81 m/s².

The MMA7660 test made the units visible. The program scanned the bus for address 0x4C, initialized the driver, then printed acceleration in g and in m/s² every half second. In our output, a Z value near 0.99 g appeared alongside a value near 9.68 m/s². Those are roughly the same acceleration in two units, not two levels of performance.

There is a subtlety: the two printouts came from separate acquisitions. The m/s² function reads the sensor again before multiplying by 9.81, so if the module moves between calls, the two lines are not exact conversions of one sample. Acquire once and convert the stored values. The driver also returns three zeros when a register read fails; your interface should treat that as missing data, not as a physical position.

Calculating an angle adds assumptions, and an axis convention

The LIS3DH test went a step further. It looked for address 0x19, selected the ±2 g range, and printed acceleration followed by two calculated angles.

The calculation uses the relationship between the three axes to estimate tilt. That works when gravity dominates the reading. During a push, shake or other substantial movement, the motion itself affects the estimated angle. Analog Devices explains this and the effect of filtering in AN-1057, Using an Accelerometer for Inclination Sensing.

There was also a labeling error in our test program: the angle function returns roll then pitch, but the caller printed the first value as pitch and the second as roll. So the on-screen angles were not verified measurements of the quantities named. The program also read acceleration again for the angle calculation; read once when you want both values to describe the same sample. That matters more during movement than on a quiet tabletop.

For your object, define "left," "forward" and the neutral position in terms a person recognizes. Then relate those directions to the sensor axes after the board is mounted. A sensor rotated inside an enclosure can produce correct readings that drive the interface the wrong way.

Choose the filter for the behavior, not for a cleaner-looking number

The MMA8452Q test was a configuration tour. It changed standby/active mode, measurement range, output data rate and high-pass filter settings, printing readings along the way.

A high-pass filter reduces steady or slowly changing components. That can help detect a change in motion, but the steady gravity contribution is exactly what a slow tilt estimate relies on. A setting suited to a shake detector is not automatically suited to holding a cursor at a tilt.

The program finished with the high-pass filter on, an 8 g range and the lowest data-rate setting in its loop. Do not copy that final state as a tilt-control configuration because the run printed "completed." Even the filter label needs context: a constant named CUTOFF_2HZ does not by itself give a 2 Hz cutoff, because the MMA8452Q datasheet's cutoff table varies with output data rate and oversampling mode.

For a slow tilt interaction, keep the steady component you need and decide how much smoothing makes the feedback comfortable. More smoothing can make a control calmer but slower to settle. Test that tradeoff with the intended movement and feedback, not only from a terminal trace.

Small numbers are not automatically a quieter sensor

The BMA220 test offered a menu for range, bandwidth and event-related tests, and showed changing values. The acceleration conversion in the driver we used needs fixing before those numbers are compared with anything.

The driver divides signed counts by both the counts-per-g factor and 9.80665. To express the result in m/s², the g value should be multiplied by 9.80665 instead. For example, 16 counts at 16 counts/g represent 1 g, about 9.81 m/s²; the driver's expression gives about 0.102. We found this by reading the code against the manufacturer's sensitivity table, not by a new hardware test. It is a good example of why a small displayed number cannot establish low noise or small movement.

Nor does a menu entry for double-tap or orientation detection show that the feature works reliably in a finished enclosure. Your trigger and mounting arrangement need a test that connects a person's action to what they see.

Match the reading schedule to the interaction

The MMA8451 test selected an 800 Hz sensor data rate, but the program printed a reading and slept half a second, changing the selected rate after each group of ten readings. A fast internal sensor setting does not mean the application records or displays 800 samples a second.

For a slowly adjusted control, a modest application update rate may be enough. A quick flick is a different task. Decide how quickly the person expects feedback, then check the whole path: reading the sensor, calculating the control value and updating the display, sound or light. Printed values do not measure that response.

So the five tests answer different questions. MMA7660 makes units easy to inspect; LIS3DH shows an angle calculation; MMA8452Q explores settings that change the signal; BMA220 shows why conversion code deserves a check; MMA8451 separates the sensor's rate from the program's schedule. None is a winner on this evidence.

Make the next test about the object in someone's hands

Mount the chosen board in its intended orientation and record a neutral position. Slowly tilt left, right, forward and back while showing the resulting control value. Check sign, units and the point where the interface starts responding. A small neutral region can stop visible movement while the object is held still; choose its size from observation, not a copied threshold.

Then try the handling the object will actually get. Does a brief shake produce an unwanted command? Does the feedback settle after a tilt? Does changing grip or setting the object down cause a confusing response? We have not run these tests yet.

Keep a short record of board orientation, driver version, range, filter settings and reading schedule next to the observed behavior. That gives designer and engineer a shared starting point instead of an argument over numbers taken from different setups.