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.

Twee grafieken boven elkaar. Het bovenste toont een schakelaarsignaal over ongeveer zes milliseconden: de ruwe pin zakt laag, schakelt vervolgens negen keer heen en weer tussen hoog en laag gedurende 4,7 milliseconden voordat hij laag blijft, terwijl de gedempte uitgang hoog blijft tot het venster verstrijkt en dan schoon zakt. De onderste grafiek toont het aantal flanken dat een interrupt zou tellen, dat in stappen van negen naar één daalt naarmate het dempvenster van nul naar acht milliseconden groeit, en bij 4,7 milliseconden één bereikt.
Eén indruk van een gemodelleerde hefboomschakelaar: negen overgangen over 4,7 ms. Een dempvenster korter dan het kaatsen telt het kaatsen mee — en een venster dat lang genoeg is om het te laten uitdempen kost precies zijn eigen lengte aan vertraging, de afweging die niemand noemt. SVG downloaden

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

Bronnen