If you want to detect when something is moved, tilted, or shaken without getting into the complexities of an accelerometer, the ball tilt sensor might be the cheapest option.
Overview
A ball tilt sensor is more of a switch that can detect basic motion, orientation or inclination. These switches are designed in such a way that a sufficient level of inclination makes or breaks the electrical connection. Such a signal can either be used as an indicator or can be used to turn something ON or OFF.
They are small, cheap, easy to use and never wear out. Their simplicity makes them popular for use in toys, gadgets, robots, and other devices whose functioning depends on inclination. This is why they are sometimes called the “poor man’s accelerometer“.
Although all tilt sensors work pretty much the same, their sizes and specifications may differ slightly.
Dimensions | 5.5mm (0.22″) diameter & 13.5mm (0.53″) long |
Maximum operating voltage (VCC) | Up to 20V |
Maximum operating current (Imax) | 30mA |
Sensitivity range | Movements of around 5 to 10 degrees |
Lifetime | 50,000+ cycles (switches) |
Tilt Sensor vs. Accelerometer
While not as accurate or flexible as an accelerometer, the tilt sensor can detect motion or orientation quite well. Another advantage of using a tilt sensor is that it can be used as a standalone sensor. The accelerometer, on the other hand, outputs a digital or analog voltage that must be analyzed with additional circuitry.
How Do Ball Tilt Sensors Work?
A ball tilt sensor is typically made up of a metal tube with a little metal ball that rolls around in it. One end of the cavity has two conductive elements (poles). The sensor is designed in such a way that a sufficient level of tilt allows the ball to roll, making or breaking an electrical connection.
When the sensor is upright the ball touches the poles and makes an electrical connection. And when the sensor is tilted the ball rolls off the poles and the connection is broken.
Testing a Ball Tilt Sensor
Testing a ball tilt sensor is very simple. Put your multimeter in ‘continuity-test’ mode and touch the probes to the two leads. Then tilt it to determine the angle at which the switch opens and closes.
When pointing up, the switch is closed (full continuity).
When pointing down, the switch is open (no continuity).
Wiring up a Ball Tilt Sensor to an Arduino
Wiring the tilt sensor up to your Arduino is pretty straightforward. All you need to do is connect one pin to any digital pin of the Arduino and the other to GND.
If you connect the sensor this way, you will need to activate the arduino’s ‘built-in’ pull-up resistor for the input pin. Otherwise, you must use an external 10K pull-up resistor in your circuit.
The following illustration shows the wiring.
Arduino Code – Reading a Ball Tilt Sensor
Below is a very basic Arduino sketch that will switch-on the built-in LED (attached to pin 13) when the tilt sensor is tilted one way, and switch-off when it is tilted the other way.
const int tiltPin = 2; // tilt sensor pin is connected to pin 2
const int ledPin = 13; // built-in LED is connected to pin 13
void setup() {
pinMode(tiltPin, INPUT); // set sensor pin as an INPUT pin
digitalWrite(tiltPin, HIGH); // turn on the built in pull-up resistor
pinMode(ledPin, OUTPUT); // set LED pin as an OUTPUT pin
}
void loop() {
if (digitalRead(tiltPin)) { // check if the pin is high
digitalWrite(ledPin, HIGH); // turn on the LED
}
else { // if it isn't
digitalWrite(ledPin, LOW); // do the opposite
}
}
The code is quite self-explanatory. Initially two constants are defined which declare the Arduino pins to which the tilt sensor and built-in LED are connected. In the setup, the sensor pin is configured as an input while the LED pin is configured as an output. Also the internal pull-up is enabled for the sensor pin. In the loop, the built-in LED is turned ON if the sensor pin is HIGH, otherwise turned OFF.
It’s a pretty short sketch, works great, but there is a problem. If you have looked at the LED while tilting the sensor, you may have noticed it flickering. That’s because something called ‘switch bounce‘.
What is switch bounce and How to Deal with It?
When the sensor is pointing up, the ball rolls onto the poles and shorts them, acting as a switch throw. In an ideal world, if we hooked this up to a signal analyzer we should get a signal that would look like this:
That’s the way a ball tilt sensor should work and that’s what most people think. However, in reality it looks more like this:
Ideally the contact should be instant. Instead the ball bounces around a bit, making the contact open, closed, open, closed, etc. It’s purely a mechanical phenomenon known as ‘Switch Bounce‘, like dropping a ball – it bounces before finally landing on the ground.
So the signal goes up and down several times before finally stabilizing. It does this over a period of time (t). While this period of time is very fast, and seems almost instantaneous to us, but for an Arduino, it is a huge period of time. It can execute multiple instructions in that time period.
The process of eliminating switch bounces is called ‘Debouncing‘ which can be achieved programmatically. Usually the switch bounce occurs within a 50ms window. So, a 50mS delay after a switch change is detected, is enough to eliminate it.
Arduino Code – Reading a Ball Tilt Sensor (More Reliably)
Here’s a new sketch rewritten to demonstrate how to debounce an input. In this sketch we read the tilt sensor twice in a short period of time to make sure it is definitely tilted.
Go ahead and upload it to your Arduino. Now you can see that the LED no longer flickers when you tilt the sensor (if the problem persists just try increasing the debounce time).
const int tiltPin = 2; // tilt sensor pin is connected to pin 2
const int ledPin = 13; // built-in LED is connected to pin 13
int ledState = HIGH; // the current state of the LED
int tiltState; // the current reading from the sensor
int lastTiltState = LOW; // the previous reading from the sensor
unsigned long time = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time, increase if the output flickers
void setup() {
pinMode(tiltPin, INPUT); // Set sensor pin as an INPUT pin
digitalWrite(tiltPin, HIGH); // turn on the built in pull-up resistor
pinMode(ledPin, OUTPUT); // Set LED pin as an OUTPUT pin
}
void loop() {
// read the state of the tilt sensor
tiltState = digitalRead(tiltPin);
// If the sensor really tilted?
if (tiltState != lastTiltState) {
// reset the debouncing timer
time = millis();
}
if ((millis() - time) > debounceDelay) {
// whatever the switch is at, its been there for a long time
// so lets settle on it!
ledState = tiltState;
}
digitalWrite(ledPin, ledState);
// Save the last tiltState so we keep a running tally
lastTiltState = tiltState;
}
Code Explanation:
The sketch starts by declaring the Arduino pins to which the tilt sensor and built-in LED are connected.
const int tiltPin = 2;
const int ledPin = 13;
Three integers viz. ledState
, tiltState
and lastTiltState
are defined to store the current state of the LED, the current reading from the sensor and the previous reading from the sensor resp.
int ledState = HIGH;
int tiltState;
int lastTiltState = LOW;
In that same global area, two variables are defined to store the last-tilt-event and the debounce time. Note that these variables are unsigned longs because the time (measured in milliseconds) quickly becomes a bigger number and overflows an integer.
unsigned long time = 0;
unsigned long debounceDelay = 50;
The setup section is the same as before where we configure the sensor pin as an input and the LED pin as an output; and enable the internal pull-up for the sensor pin.
void setup() {
pinMode(tiltPin, INPUT);
digitalWrite(tiltPin, HIGH);
pinMode(ledPin, OUTPUT);
}
In the loop, we first read the state of the tilt sensor and check if this state is different from the last tilt-state (either due to tilt or noise). If it is different, we log this state-change event by storing the current time. For this purpose we use the millis() function which keeps track of the time elapsed since the Arduino board began running the current program.
tiltState = digitalRead(tiltPin);
if (tiltState != lastTiltState) {
time = millis();
}
Next, we see if the sensor changes its state within a 50ms (debounceDelay
) window, if it doesn’t, it means the sensor is indeed tilted (and not due to switch bounce). Then we toggle the LED and save the last tilt-state so that we can keep a running tally.
if ((millis() - time) > debounceDelay) {
ledState = tiltState;
}
digitalWrite(ledPin, ledState);
lastTiltState = tiltState;