Tutorial · Beginner · 25 min lezen
Botsingsensoren en contactdendering bij robotbotsingen
Een schakelaar die sluit geeft negen flanken, niet één. Hoe kaatsen een interrupt misleidt, wat een dempvenster kost en hoe je een langdurige bumper bouwt.
Een schakelaar is geen schone flank
Druk een hefboomschakelaar in en het metalen contact komt aan, buigt uit, laat los en komt opnieuw aan — meerdere keren, in de eerste paar milliseconden, voordat het zich stabiliseert. Dat heet contactdendering, en dat is mechanisch: geen hoeveelheid software ervoor en geen condensator erna maakt het metaal ophouden met bewegen.
Het gevolg telt alleen omdat de pin wordt uitgelezen door iets dat veel sneller is dan het metaal. Een microcontroller die met 16 MHz bemonstert ziet elk van die overgangen als een echte flank.
Het onderste paneel is de ontwercurve. Het aantal flanken daalt in stappen naarmate het venster groeit, bereikt één op het moment dat het kaatsen eindigt, en blijft daar. Alles korter telt te veel; alles langer is vertraging waar je niets voor terugkrijgt.
Typische kaatsduur, de moeite waard om te meten in plaats van te vertrouwen:
| Schakelaar | Kaatsduur |
|---|---|
| Kwaliteitshefboomschakelaar | 0,5–2 ms |
| Goedkope tactiele knop | 2–10 ms |
| Reedcontact | 0,1–1 ms |
| Relaiscontact | 1–20 ms |
Het gebruikelijke advies “5 ms is genoeg” is een gok in het midden van die tabel. Meet die van jou: het is één regel code en het maakt van een bijgeloof een getal.
Bedrading, voordat dit allemaal van belang is
Een botsschakelaar wil normaal-open contacten naar aarde, met de pin omhoog getrokken:
pinMode(BUMP_L, INPUT_PULLUP); // idle HIGH, LOW when the bumper is pressed
Drie redenen voor deze opstelling in plaats van de andere:
- Actief laag faalt veilig. Een gebroken draad leest HOOG, en dat is niet ingedrukt, dus een losgeknelde bumperleiding doet de robot niet geloven dat hij permanent botst. Een opstelling met pull-down faalt de andere kant op.
- De interne pull-up is gratis. Geen weerstand, geen extra onderdeel op een robot waarvan de voorkant steeds opnieuw geraakt wordt.
- Ruis wordt afgevoerd, niet opgevangen. Een lange bumperdraad is een antenne; het laagohmige pad naar aarde bij gesloten contact is wat voorkomt dat de motordriver ernaast wordt opgepikt.
Gebruik in plaats daarvan het normaal-gesloten contact van de schakelaar en je krijgt het omgekeerde faalgedrag — een gebroken draad lijkt op een permanente botsing, wat de juiste keuze is voor een noodstop en de verkeerde voor een bumper.
Demptijd: kies er één van drie
Negeren-na-accepteren. De luie versie, en juist voor een bumper. Accepteer de eerste flank direct en kijk dan het hele venster lang niet meer:
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;
}
Nul vertraging op de flank die ertoe doet, en het kaatsen wordt erachter weggegooid. Dit is wat je wilt als de reactie motoren stoppen is — 6 ms wachten om zeker te zijn betekent 6 ms lang in de meubels rijden.
Wachten-op-stabiliteit. De aanpak van het Arduino-voorbeeld: onthoud wanneer de uitlezing voor het laatst veranderde en accepteer hem pas als hij het hele venster lang stil heeft gestaan. Kost het volle venster aan vertraging en is de juiste vorm voor een knop in een menu, waar een valse indruk erger is dan een trage.
Hardware. Een condensator van 100 nF over de contacten plus de pull-up geeft een RC van ongeveer 10 ms bij een interne pull-up van 100 kΩ — maar de flank die dat oplevert is langzaam, en een langzame flank in een digitale ingang kan door de drempel heen en weer oscilleren. Kies je deze route, volg hem dan met een Schmitt-trigger-ingang. Meestal de onderdelen niet waard.
Merk op wat alle drie gemeen hebben: ze zijn niet-blokkerend. Een delay(20) na de flank dempt perfect, maar houdt de robot 20 ms lang op van al het andere lezen, wat op een machine die 0,3 m/s rijdt 6 mm blinde verplaatsing is — zie timing met millis().
Interrupts en kaatsen gaan slecht samen
Een interrupt aan een bumper hangen lijkt vanzelfsprekend kloppen, en klopt het meestal niet.
Negen overgangen betekent dat de ISR negen keer vuurt. Verhoogt die een teller, dan heb je nu negen botsingen; zet die een vlag, dan heb je er één, onschadelijk. Gebruik alleen een interrupt als de afhandelaar idempotent is — een vlag zetten, een tijdstempel vastleggen — en nooit als die telt.
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() loopt op een AVR niet vooruit binnen een ISR, wat dit veilig maakt voor de duur van één kaatsbeurt maar onjuist voor alles wat langer duurt — gebruik micros() als het venster nauwkeurig telt.
Eerlijk gezegd heb je voor een bumper zelden de interrupt nodig. Een lus die op 200 Hz draait merkt een botsing binnen 5 ms, en de robot legt in die tijd 1,5 mm af. Poll hem, en besteed de interrupt-pins aan de encoders die je echt niet kunt pollen.
Een bumper bouwen die werkt
De schakelaar is de makkelijke helft. Het mechanisme ervoor bepaalt of de robot een stoelpoot detecteert die hij schuin raakt.
- Eén bewegende schaal, twee schakelaars. Eén voorpaneel op twee buigpunten, met een schakelaar achter elke kant. Alleen de linkse schakelaar betekent dat het obstakel links zit, en dat is de informatie die het vermijdingsgedrag nodig heeft om te kiezen welke kant op te draaien.
- Buig hem om de hoeken. Een vlakke voorbumper mist alles wat met meer dan ongeveer 30° wordt geraakt, en schuine treffers zijn de meeste. Buig de schaal aan elke kant minstens 45° om.
- Veren zorgen voor de terugkeer, schakelaars niet. De eigen veer van een microschakelaar is 50–100 g en duwt een schaal niet betrouwbaar terug. Gebruik rubberbanden of lichte drukveren, en laat de schakelaar alleen waarnemen.
- Geef hem slag en een harde aanslag. 3–5 mm beweging voordat de schakelaar aanspreekt, en een aanslag die de impact opvangt in plaats van de schakelaar. Schakelaarbehuizingen zijn het onderdeel dat breekt.
- Combineer hem met iets contactloos. Een bumper is een laatste middel — hij meldt een botsing die al heeft plaatsgevonden. Een ultrasone of time-of-flight-sensor ervoor voorkomt de meeste; de bumper vangt de zwarte stoelpoot, het glas en het ding op de verkeerde hoogte.
Je eigen kaatsduur meten
// 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);
}
Stel het venster in op de stabilisatietijd die je meet, plus ongeveer 50%. Meet opnieuw als de schakelaar oud is — contacten worden slechter, niet beter.
Het gaat mis
| Symptoom | Meestal |
|---|---|
| Eén botsing geteld als meerdere | geen demping, of een venster korter dan het kaatsen |
| Botsingen volledig gemist | ergens een blokkerende aanroep; de lus keek niet |
| Robot draait willekeurig om | lange onafgeschermde bumperdraad vlak bij de motordriver |
| Meldt een permanente botsing | gebroken draad op een normaal-gesloten contact, of geen pull-up |
| Detecteert alleen frontale treffers | bumperschaal te vlak — buig hem om de hoeken |
| Schakelaar werkt na een week niet meer | de schakelaarbehuizing ving de impact op in plaats van een harde aanslag |
| Detecteert de muur maar niet de stoelpoot | niets mis met de schakelaar; de schaal heeft een gat |
Voor waar een bumper in een hele robot thuishoort: de robot die kamers bestrijkt is gebouwd op twee van die en verder niets — en de bestrijkssimulator laat precies zien hoe ver een robot komt met één bit waarneming.
Verken de graaf
Onderdeel van deze bouwprojecten
Projecten en leerroutes waarin deze tutorial voorkomt.
Verder lezen