Tutorial · Principiante · 25 min
Sensori di urto: eliminazione del rimbalzo nelle collisioni
Chiusura, rimbalzo e eliminazione del rimbalzo: scopri perché un interruttore genera nove fronti, come ingannano un interrupt e come proteggere un paraurti.
Un interruttore non è un fronte pulito
Premi un microswitch a leva e il contatto metallico arriva, si flette, si separa e arriva di nuovo—più volte, nei primi millisecondi, prima di stabilizzarsi. Questo è il rimbalzo del contatto ed è meccanico: nessuna quantità di software prima e nessun condensatore dopo può far smettere al metallo di muoversi.
La conseguenza conta solo perché il pin viene letto da qualcosa molto più veloce del metallo. Un microcontrollore che campiona a 16 MHz vede ognuna di quelle transizioni come un fronte reale.
Il pannello inferiore è la curva di progetto. Il numero di fronti scende a gradini all’aumentare della finestra, arriva a uno quando il rimbalzo termina e ci resta. Una finestra più breve conta troppi fronti; una più lunga è latenza pagata senza vantaggio.
Durate tipiche del rimbalzo, da misurare invece che da dare per scontate:
| Interruttore | Rimbalzo |
|---|---|
| Microswitch a leva di qualità | 0.5–2 ms |
| Pulsante tattile economico | 2–10 ms |
| Interruttore a reed | 0.1–1 ms |
| Contatto di relè | 1–20 ms |
Il consueto consiglio «5 ms bastano» è una stima fatta al centro di quella tabella. Misura il tuo: è una riga di codice e trasforma una superstizione in un numero.
Cablaggio, prima che tutto questo conti
Un interruttore di urto vuole contatti normalmente aperti verso terra, con il pin mantenuto alto:
pinMode(BUMP_L, INPUT_PULLUP); // idle HIGH, LOW when the bumper is pressed
Tre motivi per preferire questa disposizione all’altra:
- Il livello basso attivo è sicuro in caso di guasto. Un filo rotto legge HIGH, che significa non premuto, quindi un filo del paraurti spezzato non fa credere al robot di essere sempre in collisione. Una disposizione con pull-down fallisce nel modo opposto.
- Il pull-up interno è gratis. Nessuna resistenza, nessun componente in più su un robot il cui fronte sarà colpito ripetutamente.
- Il rumore viene deviato, non raccolto. Un filo lungo del paraurti è un’antenna; il percorso a bassa impedenza verso terra quando è chiuso è ciò che gli impedisce di captare il driver del motore accanto.
Se usi invece il contatto normalmente chiuso, ottieni il comportamento di guasto opposto—un filo rotto sembra una collisione permanente, che è la scelta corretta per un arresto di emergenza e quella sbagliata per un paraurti.
Eliminazione del rimbalzo: scegline uno tra tre
Ignora-dopo-accetta. Quello pigro, corretto per un paraurti. Accetta subito il primo fronte, poi rifiuta di controllare per la durata della finestra:
const unsigned long BOUNCE_MS = 6;
unsigned long lastBumpAt = 0;
bool bumped() {
if (digitalRead(BUMP_L) == HIGH) return false; // not pressed
if (millis() - lastBumpAt < BOUNCE_MS) return false; // still inside the window
lastBumpAt = millis();
return true;
}
Latenza zero sul fronte che conta e il rimbalzo viene scartato dietro di esso. È ciò che vuoi quando la reazione è fermare i motori—aspettare 6 ms per essere sicuri significa percorrere 6 ms prima di sbattere contro l’arredo.
Aspetta-che-stia-fermo. L’approccio dell’esempio Arduino: ricorda quando l’ultima lettura è cambiata e accettala solo dopo che è rimasta ferma per la finestra. Costa l’intera finestra in latenza ed è la forma giusta per un pulsante di un menu, in cui una pressione falsa è peggio di una lenta.
Hardware. Un condensatore da 100 nF tra i contatti più il pull-up dà una costante di tempo RC di circa 10 ms con un pull-up interno da 100 kΩ—ma il fronte che produce è lento e un fronte lento in ingresso digitale può oscillare attraverso la soglia. Se scegli questa strada, seguilo con un ingresso con trigger di Schmitt. Di solito non vale la pena aggiungere i componenti.
Nota ciò che tutti e tre hanno in comune: sono non bloccanti. Un delay(20) dopo il fronte effettua un’eliminazione del rimbalzo perfetta e impedisce al robot di leggere qualsiasi altro segnale per 20 ms, che su una macchina che viaggia a 0.3 m/s sono 6 mm di percorso alla cieca—vedi la temporizzazione con millis().
Interrupt e rimbalzo sono una coppia sbagliata
Collegare un interrupt a un paraurti sembra ovviamente corretto e solitamente non lo è.
Nove transizioni significano che la ISR viene eseguita nove volte. Se incrementa un contatore, ora hai nove collisioni; se imposta un flag, ne hai una, innocua. Usa un interrupt solo se il gestore è idempotente—impostare un flag, catturare una marca temporale—e mai se conta.
volatile bool bumpFlag = false;
volatile unsigned long bumpAt = 0;
void onBump() { // idempotent: nine calls do what one call does
if (millis() - bumpAt < BOUNCE_MS) return;
bumpAt = millis();
bumpFlag = true;
}
millis() non avanza dentro una ISR su un AVR, il che rende questo sicuro per la durata di un rimbalzo ma sbagliato per qualsiasi cosa più lunga—usa micros() se la finestra deve essere precisa.
Sinceramente, per un paraurti raramente hai bisogno dell’interrupt. Un ciclo a 200 Hz nota una collisione entro 5 ms e il robot percorre 1.5 mm in quel tempo. Fai polling e usa i pin di interrupt per gli encoder che non possono davvero essere interrogati tramite polling.
Costruire un paraurti che funziona
L’interruttore è la metà facile. Il meccanismo davanti a lui decide se il robot rileva una gamba di sedia che colpisce di traverso.
- Una scocca mobile, due interruttori. Un unico pannello frontale su due punti flessibili, con un interruttore dietro ciascun lato. Il solo interruttore sinistro significa che l’ostacolo è a sinistra, l’informazione che serve al comportamento di evitamento per scegliere da quale parte girare.
- Avvolgilo attorno agli angoli. Un paraurti frontale piatto manca tutto ciò che viene colpito a più di circa 30°, e sono la maggior parte degli impatti laterali. Porta la scocca almeno a 45° su ciascun lato.
- Le molle lo riportano indietro, gli interruttori no. La molla di un microswitch è di 50–100 g e non riporterà una scocca indietro in modo affidabile. Usa elastici o molle di compressione leggere e lascia che l’interruttore faccia solo da sensore.
- Dagli una corsa e un fermo rigido. 3–5 mm di movimento prima dell’attuazione dell’interruttore e un fermo che riceva l’impatto invece del corpo dell’interruttore. I corpi degli interruttori sono ciò che si rompe.
- Abbinalo a qualcosa senza contatto. Un paraurti è l’ultima risorsa—segnala una collisione già avvenuta. Un sensore a ultrasuoni o a tempo di volo davanti evita la maggior parte delle collisioni; il paraurti cattura la gamba nera della sedia, il vetro e ciò che si trova all’altezza sbagliata.
Misurare il proprio rimbalzo
// Count transitions in the 20 ms after the first edge. Run it, press the switch,
// read the number. That number is your debounce window, in your robot, with your wiring.
void loop() {
if (digitalRead(BUMP_L) == HIGH) return;
unsigned long start = micros();
int last = LOW, edges = 0;
while (micros() - start < 20000) {
int now = digitalRead(BUMP_L);
if (now != last) { edges++; last = now; lastEdgeAt = micros(); }
}
Serial.print(edges); Serial.print(" edges, settled after ");
Serial.print(lastEdgeAt - start); Serial.println(" us");
delay(500);
}
Imposta la finestra sul tempo di stabilizzazione misurato, più circa il 50%. Rimisura quando l’interruttore è vecchio—i contatti peggiorano, non migliorano.
Quando qualcosa va storto
| Sintomo | Di solito |
|---|---|
| Un urto viene contato come diversi | Nessuna eliminazione del rimbalzo oppure una finestra più breve del rimbalzo |
| Gli urti vengono persi completamente | Una chiamata bloccante da qualche parte; il ciclo non stava controllando |
| Il robot indietreggia a caso | Filo lungo del paraurti non schermato vicino al driver del motore |
| Segnala una collisione permanente | Filo rotto su un contatto normalmente chiuso oppure nessun pull-up |
| Rileva solo gli impatti frontali | Scocca del paraurti troppo piatta—avvolgila attorno agli angoli |
| L’interruttore smette di funzionare dopo una settimana | Il corpo dell’interruttore ha ricevuto l’impatto invece che un fermo rigido |
| Rileva il muro ma non la gamba della sedia | L’interruttore è a posto; la scocca ha una fessura |
Per capire dove si colloca un paraurti in un robot completo, il robot per la copertura della stanza è costruito su due di questi e nient’altro—e il simulatore di copertura mostra esattamente quanto lontano arriva un robot con un solo bit di informazione.
Esplora il grafo
Fa parte di queste costruzioni
Progetti e percorsi di apprendimento che includono questo tutorial.
Per approfondire