4-direction tilt sensor/Using it/10. A tip-over alarm
Using it · 10 of 11

A tip-over alarm

Stand the block on edge on the wall of a box, header edge down, and upright becomes a reading: header. The sketch filters out knocks, and if the box reads anything else for more than a second it lights a TK01 and keeps it lit, even after the box is stood back up, until someone resets the board.

Stand it on edge

Flat on a table, the block has no resting reading: the roller stays wherever it last rolled. So this build does not lay it flat. It stands on edge, fixed to the inside wall of a box, with the header edge pointing down.

Now gravity always has an opinion. While the box is upright, the roller sits on the header side and joins D and A, and the scan reads header. Tip the box onto its left or right side and the reading becomes left or right; turn it upside down and it becomes top. Anything but header means the box is not the way up it should be.

A clock, and a latch

Tipped, and it stays told
Box
upright
Believed
header
Alarm
off
The box is upright: the header edge is down and every scan reads header. Run eight seconds.

The sketch is the last article's filtered scan with two things added. When the believed reading stops being header, it notes the time. If it is still not header TIP_MS later, one second here, the alarm comes on. The filter has already thrown away knocks, and the one-second wait throws away a box that was bumped and rocked back.

Then the alarm stays on. Once alarmOn is set, nothing in the loop clears it, so a box that fell over and was quietly stood back up still says so. Pressing the board's reset button clears it. The timing in the figure is illustrative; the rule is the sketch's.

What it cannot see

The switch only feels tilts in the plane of the board. A box that falls straight forwards or backwards, away from the wall the block is on, lays the board flat, and a flat board keeps its last reading: header. The alarm never comes on.

If that direction matters, mount a second block on a wall at right angles to the first, and alarm on either. Each needs four pins of its own.

The wiring

The block is wired as in the first read. The alarm is a TK01 XL LED on a fifth pin: D9 on an Uno, GPIO 4 on an ESP32, GPIO 15 on an ESP32-S3, GP15 on a Pico. Its first blink shows the wires. Without one, watch the serial monitor, knock the box once, then tip it over for a couple of seconds:

left
tipped over: alarm
header

The knock never appears. LED_PIN is the only pin the sketch ever drives HIGH, and it is not one of the tilt lines.

The code

Watches a box with the block on its wall, header edge down. It filters every scan, and once the box has read anything but header for TIP_MS it lights a TK01 XL LED on a second pin and leaves it lit. No library, no long delay().

tilt_tip_over_alarm.ino
/*
  4-Direction Tilt Sensor - a tip-over alarm             TK19 / /p/tk19

  Wiring. Count from the square pad on the TinkerBlock board, parts
  up, header at the bottom:

    GND  -> GND
    VCC  -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
    A    -> D2 on an Uno, GPIO 25 on an ESP32, GPIO 4 on an
            ESP32-S3, GP10 on a Raspberry Pi Pico
    B    -> D3, GPIO 26, GPIO 5, GP11      (same order)
    C    -> D4, GPIO 27, GPIO 6, GP12
    D    -> D5, GPIO 32, GPIO 7, GP13

  The block stands on edge on the box's wall, header edge down.

  A TK01 XL LED on a second pin is the alarm (optional):
    GND    -> GND
    SIGNAL -> D9 on an Uno, GPIO 4 on an ESP32, GPIO 15 on an
              ESP32-S3, GP15 on a Raspberry Pi Pico

  Arduino IDE
    Tools > Board                 your board, e.g. ESP32S3 Dev Module
    Tools > Port                  the one that appears when you plug in
    Tools > USB CDC On Boot       Enabled   (ESP32-S3 only)
    No library needed.
*/

// The GPIO numbers A, B, C and D are wired to.
// Uno: 2 3 4 5. ESP32: 25 26 27 32. ESP32-S3: 4 5 6 7. Pico: 10 11 12 13.
const int PIN_A = 4;
const int PIN_B = 5;
const int PIN_C = 6;
const int PIN_D = 7;
// The GPIO number the TK01's SIGNAL is wired to.
// Uno: 9. ESP32: 4. ESP32-S3: 15. Pico: 15.
const int LED_PIN = 15;

const int STABLE_READS = 5;     // 5 scans, 10 ms apart: 50 ms
const int SCAN_MS = 10;
const unsigned long TIP_MS = 1000;

const int NO_SIDE = 0;
const int LEFT_DOWN = 1;
const int TOP_DOWN = 2;
const int RIGHT_DOWN = 3;
const int HEADER_DOWN = 4;
const char* SIDE_NAME[] = {"none", "left", "top", "right", "header"};
const int UPRIGHT = HEADER_DOWN;  // standing on edge, header down

void releaseAll() {
  pinMode(PIN_A, INPUT_PULLUP);
  pinMode(PIN_B, INPUT_PULLUP);
  pinMode(PIN_C, INPUT_PULLUP);
  pinMode(PIN_D, INPUT_PULLUP);
}

void holdLow(int pin) {
  digitalWrite(pin, LOW);       // LOW first, then output
  pinMode(pin, OUTPUT);
}

bool readsLow(int pin) {
  return digitalRead(pin) == LOW;
}

int scanTilt() {
  releaseAll();
  holdLow(PIN_A);
  delayMicroseconds(10);
  bool ab = readsLow(PIN_B);    // left
  bool da = readsLow(PIN_D);    // header

  releaseAll();
  holdLow(PIN_C);
  delayMicroseconds(10);
  bool bc = readsLow(PIN_B);    // top
  bool cd = readsLow(PIN_D);    // right

  releaseAll();
  if (ab) return LEFT_DOWN;
  if (da) return HEADER_DOWN;
  if (bc) return TOP_DOWN;
  if (cd) return RIGHT_DOWN;
  return NO_SIDE;
}

int candidate = UPRIGHT;
int count = 0;
int believed = UPRIGHT;
bool tipped = false;
unsigned long tippedAt = 0;
bool alarmOn = false;

void setup() {
  Serial.begin(115200);
  releaseAll();
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
}

void loop() {
  int side = scanTilt();
  if (side == candidate) {
    if (count < STABLE_READS) count++;
  } else {
    candidate = side;
    count = 1;
  }
  if (count >= STABLE_READS && candidate != believed) {
    believed = candidate;
    Serial.println(SIDE_NAME[believed]);
  }

  unsigned long now = millis();
  if (believed == UPRIGHT) {
    tipped = false;             // upright again: stop the clock
  } else if (!tipped) {
    tipped = true;              // just tipped: start the clock
    tippedAt = now;
  }

  if (tipped && !alarmOn && now - tippedAt >= TIP_MS) {
    alarmOn = true;             // latched: only a reset clears it
    digitalWrite(LED_PIN, HIGH);
    Serial.println("tipped over: alarm");
  }
  delay(SCAN_MS);
}

The alarm depends on time, not on one reading: a tip starts a clock, standing up stops it. Once alarmOn is set nothing in loop() clears it, so the alarm outlives the tip; only a reset does. LED_PIN is the only pin the sketch ever writes HIGH, and it is not a tilt line.

When it does not work

It alarms the moment it is switched on.

The block is not reading header at rest. Check that it stands on edge with the header edge pointing down, square to the floor, so gravity holds the roller on that side. Watch the serial monitor: the sketch starts out believing header and prints only changes, so a side printed straight after start-up means the block is not standing header-down.

It did not notice the box falling forwards.

It cannot. The switch only feels tilts in the plane of the board. Falling forwards or backwards lays the board flat, and a flat board keeps its last reading, which is header. Mount a second block on a wall at right angles to the first to cover that direction.

How do I clear the alarm?

Press your board's reset button, or power it off and on. The sketch latches the alarm on purpose, so a box that was tipped and stood back up still says so. To clear it from a button instead, reset alarmOn and turn LED_PIN off when the button is pressed.

Can I use a buzzer instead of the TK01?

Yes. The sketch drives LED_PIN HIGH for the alarm, so anything that switches on with a HIGH works on that pin unchanged; the active buzzer block is one. A passive buzzer needs tone() instead of digitalWrite().

Where this goes next

The short list of reasons, and why the dark LEDs are usually not one of them.

When a tilt reads nothing

Edit this page — content/books/four-direction-tilt-sensor/a-tip-over-alarm.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

4-Direction Tilt Sensor

Loading discussions…

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum