ACROBOTIC Industries ACROBOTIC Industries

Arduino Activity 5: Tilt Sensor

Overview

Time to complete: 2–5min; Level of difficulty: Beginner

In this activity we’ll build an electronic circuit with a tilt sensor that will control the on/off state of an LED using our Arduino board.

List of Materials


Obtaining the Code

For this activity, we'll be loading a program to our Arduino Uno board, it's available in our Github repository:

We can open a new window in the Arduino environment and copy-paste the code.


How Tilt Sensors Work

These ball switch-type tilt sensors are a type of digital switch that change state from open to closed based on its inclination relative to the earth's gravitational field vector.  Electrically, they behave much like the push button we've used in the past where contacts are conducting when the switch closes, and not conducting when it opens.  Mechanically, they usually consist of a hollow shell (typically cylindrical) and a conductive free mass inside (typically a blob of mercury or a rolling, metallic ball); on one end of the shell the sensor has two or more conductive elements that become shorted when the sensor's orientation is such that the free mass inside rolls and makes physical contact with them.

Tilt Sensor Gutted

Depending on the shape and size of the sensor's shell, and the weight of the free mass inside, the angle at which a sensor opens/closes is different.  This, of course, is not as precise as say accelerometer-based inclinometers, but they offer a very inexpensive solution for detecting when something tilts past a set angle.  In addition, they can switch power on and off (like any other switch) without the additional circuitry that typical accelerometer-based inclinometers need.

The ball switch tilt sensor we'll use on this tutorial features:

  • Type: Cylindrical 
  • Size: 4mm (0.16") diameter & 12mm (0.45") long 
  • Sensitivity range: > ±15 degrees 
  • Lifetime: 50,000+ cycles (switches) 
  • Power supply: Up to 24V, switching less than 5mA

Testing the Tilt Sensor's Operation

Using a Digital Multimeter tool, we can quickly test the operation of this sensor.  Selecting the continuity option, we can connect each test probe to one of the sensor leads.

Open Tilt Sensor Tested with Voltmeter

Next, we notice that when the sensor is upright, the mulitmeter reads a low resistance value.  This means that the 2 leads are in contact, and thus the switch is closed. 

Closed Tilt Sensor Tested with Voltmeter

As we gently incline the sensor from its upright position, there comes a moment when the Mutltimeter indicates a large reading of resistance.  At this point the switch is open, and the angle at which the transition occurs determines the tilt threshold of the sensor.


Example Project: Tilt-activated LED Candlelight

These little sensors can be seen out in the wild at restaurants or cafes in which flameless candles are used for decoration.  Although some will have standard slide switch for powering it on or off, a number of these tabletop LED candlelights include a ball switch. Simply flip them over to turn them on or off.

Tilt Activated LED Candles

We also carry in our store a custom DIY Kit for building your own flameless candles!

 

A video posted by ACROBOTIC (@acrobotic) on


Wiring: Tilt Detector

The wiring for this exercise is identical to the one we used for the Push Button tutorial.  We connect one pin of the tilt sensor to GND (ground) using one of the side columns on the breadboard.  Then, we connect the other pin to pin 2 on the Arduino board using a jumper wire connected to the same row as the sensor pin.

Wiring Diagram for Arduino Tilt Sensor Activity

We'll use the same circuit for the LED as in previous tutorials.  The LED, as usual, will serve as a visual indicator for when the tilt detector switches states (open or closed).


Interrupts: A Brief Introduction

As their name implies interrupts—in the context of software and embedded electronics hardware—are signals emitted to the processor that indicate an event requiring immediate attention.  When these signals are generated (whether by software or hardware) the processor stops the normal execution of its current program, saves its state, and executes an Interrupt Service Routine (ISR) to handle the event.  After the event is handled, the processor resumes the normal execution of its program until a new event occurs. 

There are two types of interrupts: hardware (a.k.a external) interrupts and software interrupts.  In this activity, we'll be using a hardware interrupt to detect a change in the state of the tilt sensor.  The interrupt will trigger an ISR that will wake up the microcontroller and return to the normal execution of the loop() function.

The main advantage in this case is that we do not have to worry about monitoring the state of pin 2 inside the loop() function (as we did previously using the digitalRead() function).  This way, our program doesn't waste any time polling the pin, allowing it to perform (almost) any other task without us worrying whether the event will get detected (it always will!).  In fact, the Tilt Detector program sets the microcontroller to a low-power (sleep) mode, saving power until an interrupt is emitted.

Check out the full list of interrupt vectors on the AVR Libc package's page.


Code Walkthrough: Tilt Detector

Given that the tilt sensor behaves much like the push button in our previous tutorials, we take the opportunity to introduce the concept of interrupts, and explore the microcontroller's low-power (sleep) modes.  For using the low-power features of the microcontroller we'll need to include an external library available through our default installation of the Arduino IDE:

#include 

As for interrupts, the microcontroller on the Arduino Uno has two external/hardware ones: number 0 on pin 2 and number 1 on pin 3.  We use the function attachInterrupt() to specify another function—no arguments/parameters allowed—that'll be called when the interrupt occurs (referred to as an Interrupt Service Routine or ISR for short).  In this case, the function enableSleep() will be called when the state of pin 2 (interrupt 0) changes from HIGH to LOW or viceversa.  This is set up inside the setup() function by:

attachInterrupt(0, enableSleep, CHANGE);

In the loop() function we make our microcontroller go to sleep until an interrupt event occurs.  To do this we make use of the variable sleep_flag. The variable is initialized to true, making the program call the user-defined function system_sleep()

  // Check whether the flag has been enabled by the ISR (true for the first 
  // run)
  if (sleep_flag)
    system_sleep(); // function to configure and execute low power mode

The function system_sleep() is responsible for configuring and putting the microcontroller into low-power (i.e., sleep) mode:

void system_sleep()
{
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep mode
  digitalWrite(led_pin, LOW); // Make sure the LED is turned off
  sleep_mode(); // System sleeps here
  //
  // Code resumes here on wake!
  //
  sleep_flag = false; //Reset sleep flag on wake
}

When the interrupt event occurs, 2 things should happen: the sleep_flag variable should be set to true inside the ISR, and the code should return to execution right after the sleep_mode() function call.  We know that the ISR should occur first, thus we expect for the sleep_flag variable to be set to true, and then the code should resume inside the user-defined function system_sleep().

// Named Interrupt Service Routine attached to int.0 will
// set the sleep_flag variable to true, thus the main
void enableSleep()
{
  sleep_flag = true;
}

At this point the variable sleep_flag is set to false and the code returns to the loop() function.  If our logic is sound, the system_sleep() function call should now be ignored, and the loop() function code should make the LED display a heartbeat animation until a new interrupt occurs.

  // Code only gets to this point if/when the sleep flag is false, indicating
  // that an interrupt event was generated
  analogWrite(led_pin, value); //set the current LED brightness
  delay(step_delay_ms); //hold the value for a short time
  value+=step_size; //increase the current value for the next iteration

  // if we've reached the maximum or minimum value, change direction of
  // change in brightness (i.e., increasing -> decreasing or viceversa)
  if( (value>value_max)||(value<0) )
  {
    step_size *= -1;
    value+=step_size; // ensure that value stays within bounds
    if(value == 0)
      delay(cycle_delay_ms); // hold 1 second off starting each cycle
  }

Troubleshooting

Noticing some erratic behavior when the sensor changes from open to closed? Make sure to read about Debouncing in our Push Button tutorial for more info!


Comments, questions, or concerns? Drop us a line!.