collision sensor/Reading it/07. One bump counts as several
Reading it · 07 of 10

One bump counts as several

A counter that adds one each time the pin changes to HIGH will sometimes add two, three or more for a single bump. The switch is not faulty: metal contacts bounce, making and breaking several times in a few milliseconds, and a fast loop sees every one.

Count the change, not the level

A hit is not "the pin is HIGH". The pin is HIGH for as long as the lever is held in, and loop() comes round thousands of times in that time. Counting every HIGH reading counts hundreds per hit.

A hit is the moment the pin changes to HIGH. So the sketch keeps the last reading, compares each new one with it, and counts only when they differ and the new one is HIGH. That is edge detection, and it is correct. Run it and flick the lever twenty times. The count will usually come out above twenty.

The metal bounces

One bump, three counts
Time since the contact touched
0.0 ms
Hits
0
Counted
0
The pin reads LOW: the lever is out and the pull-down holds SIGNAL at 0 V. Bump it.

The click you hear is a spring-loaded blade snapping from one contact to the other. It does not land once. It touches, springs apart, touches again and settles, within a few milliseconds.

Nobody can see that and nobody needs to. A microcontroller reading the pin tens of thousands of times a second sees every touch, and the edge detector counts each one. This switch's bounce has not been measured, so the waveform in the figure is illustrative: a few milliseconds is the figure commonly quoted for small switches, and it varies from one hit to the next.

A robot adds its own bounce

The push button has the same problem, and its book works through it for a finger. A robot adds a second kind. A rigid robot that drives into a wall can rebound a little and roll back into it, closing the switch twice, tens of milliseconds apart rather than a few. That is real motion, not contact bounce, and a debounce window long enough to hide it is long enough to miss a glancing hit.

The cure for that one is in the build: react to the first hit by reversing away, as stop and back off does, and there is no second touch.

The code

Counts hits by comparing each reading with the last one, and adding one when it changes to HIGH. No delay(), so it reads the pin tens of thousands of times a second. No library.

collision_count.ino
/*
  Collision Sensor - counting hits (no debounce yet)     TK17 / /p/tk17

  Wiring. Count from the square pad on the TinkerBlock board, switch
  at the top, header at the bottom:

    GND    -> GND
    VCC    -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
              (on a hit, SIGNAL gives your pin whatever VCC is)
    NC     -> nothing   (unconnected on the board)
    SIGNAL -> D2 on an Uno, GPIO 25 on an ESP32, GPIO 4 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 number SIGNAL is wired to.
// Uno: 2. ESP32: 25. ESP32-S3: 4. Pico: 15.
const int BUMPER_PIN = 4;

int lastReading = LOW;          // what the pin said last time round
unsigned long hits = 0;

void setup() {
  Serial.begin(115200);
  pinMode(BUMPER_PIN, INPUT);   // the block has its own pull-down
}

void loop() {
  int reading = digitalRead(BUMPER_PIN);

  if (reading != lastReading) { // the pin has changed
    lastReading = reading;
    if (reading == HIGH) {      // ...to HIGH: a hit, or a bounce
      hits++;
      Serial.print("hits: ");
      Serial.println(hits);
    }
  }
}

This sketch is deliberately naive: it counts a hit more than once whenever the contacts bounce. Flick the lever twenty times and compare the count with twenty. The next article adds the lines that fix it.

When it does not work

It counts correctly most of the time. Is it really bounce?

Yes, that is what bounce looks like. How much a contact bounces changes from hit to hit, with how hard and how squarely the lever is struck, so some hits count once and some count three times. A counter that is right most of the time is the classic sign.

It counts hundreds for one bump.

That is not bounce. The sketch is counting every pass of loop() while the pin is HIGH, rather than the moment it changes to HIGH. Compare the reading with the previous one, as this sketch does, and count only when they differ and the new one is HIGH.

Would an interrupt on D2 fix it?

No, it makes it more obvious. An interrupt fires on every edge, bounce included, and it is faster than any loop. A bumper needs debouncing either way, and reading it in loop() is simpler and fast enough for a robot.

The robot hits once and the count goes up by two, a moment apart.

That can be the robot rather than the switch: it touches, rebounds off the wall by a millimetre or two, and rolls into it again. A longer debounce window hides some of that, but the better fix is a sketch that reacts to the first hit by backing away, so there is no second touch to count.

Where this goes next

Believe a change only once the pin has held still, and one bump counts once.

Counting hits

Edit this page — content/books/collision-sensor/one-bump-counts-as-several.mdx

Community

Questions about this product

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

Ask a question ↗

Collision 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