Tutorial · Beginner · 17 min lezen
Toestandsmachines voor het gedrag van een robot
Ontwerp een toestandsmachine voor robotgedrag: expliciete overgangen, timeouts, hersteltoestanden, niet-blokkerende updates en toetsbare veiligheidsregels.
Robotprogramma’s beginnen vaak als een lus vol if-statements: volg de lijn tenzij er een obstakel dichtbij is, draai tot het pad vrij is, stop als de accu bijna leeg is, en herstel op de een of andere manier als een sensor zijn tijd overschrijdt. Naarmate het gedrag groeit, kan dezelfde voorwaarde tegenstrijdige commando’s uitlokken.
Een toestandsmachine (FSM) maakt het actieve gedrag expliciet. Op elk moment bevindt de robot zich in één toestand; gebeurtenissen en voorwaarden bepalen wanneer hij naar een andere overgaat. Het patroon is klein genoeg voor een Arduino en gestructureerd genoeg om te toetsen.
Scheid toestand, gebeurtenis en actie
Een toestand beschrijft wat de robot over de tijd doet: FOLLOW_LINE, AVOID, SEARCH of FAULT. Een gebeurtenis is iets waargenomens: een obstakel komt binnen de stopzone, de lijn valt weg, een timeout verloopt, of de operator drukt op stop. Een actie is de uitvoer: wielsnelheden instellen, een integrator resetten, of een alarm geven.
Maak geen toestanden voor momentane feiten. OBSTACLE_DETECTED is meestal een gebeurtenis of voorwaarde; AVOIDING_OBSTACLE is een toestand omdat die aanhoudt terwijl de robot een gedrag uitvoert.
Begin met een overgangstabel vóór de code:
| Huidige toestand | Voorwaarde of gebeurtenis | Volgende toestand | Actie bij binnenkomst |
|---|---|---|---|
| Idle | Start aangevraagd en sensoren geldig | Follow | Regelaar resetten |
| Follow | Obstakel binnen de stopdrempel | Avoid | Voorwaartse aandrijving stoppen |
| Follow | Lijn ontbreekt al 200 ms | Search | Laatste gekozen zijde onthouden |
| Avoid | Pad is 500 ms vrij | Follow | Regelaar resetten |
| Elke actieve toestand | Sensortimeout | Fault | Motoren stoppen |
| Fault | Operatorreset en systeem gezond | Idle | Fout wissen |
De tabel laat ontbrekende gevallen zien en maakt de veiligheidsprioriteit zichtbaar.
Houd de updatelus niet-blokkerend
Een toestand hoort een kleine update uit te voeren en terug te keren. Een delay() van twee seconden binnen AVOID zorgt ervoor dat het programma die twee seconden lang geen stopverzoek of sensorstoring ziet.
enum class State { Idle, Follow, Avoid, Search, Fault };
State state = State::Idle;
unsigned long enteredAt = 0;
void transitionTo(State next) {
state = next;
enteredAt = millis();
}
void loop() {
Sensors s = readSensors();
if (!s.healthy && state != State::Fault) transitionTo(State::Fault);
switch (state) {
case State::Idle: updateIdle(s); break;
case State::Follow: updateFollow(s); break;
case State::Avoid: updateAvoid(s); break;
case State::Search: updateSearch(s); break;
case State::Fault: updateFault(s); break;
}
}
Elke update leest de al vastgelegde sensormomentopname en schrijft één samenhangend actuatorcommando. Zo voorkom je dat verschillende toestanden binnen één cyclus op verschillende tijdstippen veranderende waarden lezen.
Zet overgangen op duidelijke grenzen
Kies één eigendomsregel. Een eenvoudig embedded ontwerp laat elke toestand zijn uitgaande overgangen aanvragen, terwijl een veiligheidscontrole op het hoogste niveau elke actieve toestand kan overschrijven.
void updateFollow(const Sensors& s) {
if (s.obstacleMm < stopThresholdMm) {
setWheels(0, 0);
transitionTo(State::Avoid);
return;
}
if (s.lineMissingForMs > 200) {
transitionTo(State::Search);
return;
}
followLine(s.lineError);
}
Keer onmiddellijk terug na een overgang, zodat de oude toestand de actuatoren niet alsnog kan aansturen. Bij binnenkomst in een regeltoestand reset je historie die niet naar ander gedrag mag lekken, zoals een PID-integrator of een afgeleide-sample.
Gebruik uitstapacties met mate. De meeste opschoning kan plaatsvinden in de centrale functie transitionTo() of in het binnenkomstpad van de volgende toestand. Afzonderlijke functies onEntry, onUpdate en onExit worden pas nuttig wanneer meerdere toestanden ze werkelijk nodig hebben.
Gebruik timeouts en hysterese als voorwaarden
Fysieke gebeurtenissen zijn ruisachtig. Verlaat AVOID het moment dat de afstand boven dezelfde drempel komt die er hem binnen bracht, dan kan meetruis snelle wisselingen tussen toestanden veroorzaken. Gebruik twee drempels of een aanhoudtijd: ga bij minder dan 250 mm naar binnen, maar er pas uit nadat de afstand 500 ms boven 350 mm is gebleven.
Elke toestand die vooruitgang verwacht heeft een timeout nodig. Gaat de robot naar SEARCH maar vindt de lijn nooit, dan mag hij niet eindeloos blijven draaien. Ga na een beproefd interval over op FAULT of op een begrensd herstel.
Baseer timers op de tijd sinds binnenkomst, of op de tijd sinds de laatste vooruitgang. Gebruik aftrekken zoals now - enteredAt >= timeout, dat correct blijft over de grens van een unsigned timer zolang de typen consistent zijn.
Geef veiligheidsovergangen prioriteit
Definieer wat alles kan onderbreken: een noodstop, ongeldige gegevens van een kritieke sensor, een storing van de motordriver, of een watchdog-timeout. Beoordeel deze voorwaarden vóór de gedragsspecifieke overgangen en maak de veilige uitvoer expliciet.
Een FAULT-toestand moet blijven hangen als automatisch herstel gevaarlijke beweging op gang zou kunnen brengen. Een operatorreset vereisen nadat de oorzaak is weggevallen, is vaak veiliger dan meteen terug te springen naar FOLLOW.
Laat niet twee onafhankelijke toestandsmachines dezelfde motorcommando’s schrijven zonder een regel voor arbitrage. Als navigatie en batterijbeheer beide invloed hebben op de beweging, moet één eigenaar het eindcommando kiezen en de veiligheidsgrenzen toepassen.
Test overgangen zonder motoren te laten draaien
Verplaats beslissingen naar functies die een sensormomentopname en een tijd accepteren en vervolgens een volgende toestand of een commando teruggeven. Voer een reeks synthetische momentopnames in:
- Een geldige lijn en een vrij pad blijft in
FOLLOW. - Eén ruisachtige dichte meting triggert niets wanneer aanhoudtijd vereist is.
- Een aanhoudend dicht obstakel voert
AVOIDbinnen, met eerst een stopcommando. - Een vrij pad dat het uitstapinterval vasthoudt, keert terug naar
FOLLOW. - Een sensortimeout bereikt
FAULTvanuit elke actieve toestand.
Log toestandswisselingen als old → new, de uitlokkende gebeurtenis en een tijdstempel. Doorlopende logs per lus verstoppen de overgangen in ruis; overgangslogs verklaren waarom het gedrag veranderde.
Weten wanneer een FSM niet meer het eenvoudigste model is
Een FSM werkt goed als de robot een bescheiden aantal onderling uitsluitende toestanden heeft. Hij wordt lastig zodra de toestanden zich vermenigvuldigen om combinaties af te beelden zoals “navigeren terwijl de accu wordt bewaakt terwijl de lokalisatie opnieuw wordt geprobeerd”. Het aantal overgangen kan sneller groeien dan het gedrag zelf.
Gedragsbomen stellen herbruikbare acties samen met een structuur van sequentie, terugval en herstel, en daarom gebruiken navigatiesystemen zoals Nav2 ze voor complexe taken. Introduceer geen gedragsboomframework voor vier toestanden. Stap over wanneer de overgangstabel werkelijk lastig te beoordelen wordt of wanneer gedrag hiërarchisch hergebruikt moet worden.
Diagnoseer veelvoorkomende ontwerpfouten
- De robot negeert stop terwijl hij draait: een toestand bevat een blokkerende lus of een delay.
- De motoren krijgen twee commando’s per cyclus: de overgangscode blijft draaien nadat de toestand is gewijzigd.
- De machine ratelt: ruisachtige voorwaarden missen hysterese of aanhoudtijd.
- Herstel eindigt nooit: de toestand heeft geen voorwaarde voor vooruitgang en geen timeout.
- Een storing start de beweging meteen opnieuw: veiligheidsfouten zijn niet blijvend vastgezet, of de resetvoorwaarden zijn te zwak.
- Toetsen vereist de hele robot: beslissingen en hardwaretoegang zijn door elkaar gegooid in plaats van sensormomentopnames en commandouitvoer te gebruiken.
De Obstacle Avoidance Simulator levert een nuttige gedragsreeks om te modelleren: cruisen, uitwijken om een dreiging heen, aankomen, of stoppen wanneer er geen veilige beweging overblijft. De Maze Solver Simulator laat een andere scheiding zien tussen waarnemen, kaart bijwerken, plannen en één vakje bewegen. De mini sumo robot is de scherpste toets van de regel hierboven dat veiligheidsfouten blijven hangen: de randreflex moet elke andere toestand voorafgaan, vanuit elke toestand, of de robot rijdt zichzelf de ring uit.
Verken de graaf
Onderdeel van deze bouwprojecten
Projecten en leerroutes waarin deze tutorial voorkomt.
- ProjectBouw een grijp-en-plaatsrobot die weet wanneer hij misgreep
- ProjectBouw een mini-sumo robot: grip, wig en randherkenning
- ProjectBouw een robotwagen die je via Bluetooth of wifi bestuurt
- ProjectBouw een ROS 2-robot die een marker ziet en er naartoe rijdt
- LeerrouteGrijpen en eind-effectoren: daadwerkelijk oppakken
- LeerrouteReactieve navigatie: leer een robot obstakels vermijden
Verder lezen