Benutzer-Werkzeuge

Webseiten-Werkzeuge


mbot_streckenfahren

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
mbot_streckenfahren [2025/03/01 11:15] – [Programm Steckenfahren] torsten.roehlmbot_streckenfahren [2025/03/02 14:38] (aktuell) – [Erklärungen zum Quellcode] torsten.roehl
Zeile 9: Zeile 9:
  
 {{ :inf:msr:steckenfahren-2.png?550 |}} {{ :inf:msr:steckenfahren-2.png?550 |}}
 +
 +
 +
 +  * siehe Abschnitt ☛ [[hello_mbot_infrared|Hello mBot Infrared]]
 +  * siehe Abschnitt ☛ [[hello_mbot_programmorganisation|Hello mBot Programmorganisation]]
  
  
Zeile 20: Zeile 25:
 Die spezifischen Action-Funktionen (z. B. für Bewegung oder Sensoren) müssen jedoch noch individuell implementiert werden.// Die spezifischen Action-Funktionen (z. B. für Bewegung oder Sensoren) müssen jedoch noch individuell implementiert werden.//
  
-<WRAP center round tip 90%> +<WRAP center round tip 95%> 
-👉 Im nächsten Abschnitt werden die Methoden implementiert, um das vollständige Programm zu erhalten.  +☛ Im nächsten Abschnitt werden die Methoden implementiert, um das vollständige Programm zu erhalten.   
 + 
 + 
 +Um eine elegante Steuerung zu ermöglichen, sollten die Methoden nicht-blockierend implementiert werden. 
 + 
 +siehe Abschnitt ☛ [[hello_mbot_blockierung|Blockierend vs. Nichtblockierende Mehoden]] 
 </WRAP> </WRAP>
  
Zeile 91: Zeile 102:
 }; };
 ExState exState       = EX_IDLE; ExState exState       = EX_IDLE;
-int     inputNumber   = 0;       // Anzahl der eingegebenen Stellen +int     inputNumber   = 0;    // Anzahl der eingegebenen Stellen 
-String  inputBuffer   = "";      // Sammeln der Ziffern als Text +String  inputBuffer   = "";   // Sammeln der Ziffern als Text 
-int     inputDistance = 0;       // Konvertierte Eingabe+int     inputDistance = 0;    // Konvertierte Eingabe
  
 void setup() { void setup() {
Zeile 135: Zeile 146:
   if (ir.decode()) {   if (ir.decode()) {
     uint32_t code = getIRCode();     uint32_t code = getIRCode();
-    // vermeiden wiederholender eingabe+    // Vermeidung wiederholter Eingaben
     unsigned long now = millis();     unsigned long now = millis();
     if (code == lastCode && (now - lastTime < COOL_DOWN))     if (code == lastCode && (now - lastTime < COOL_DOWN))
Zeile 349: Zeile 360:
 ====== Programm Steckenfahren ====== ====== Programm Steckenfahren ======
  
 +==== 🎮  Verwendung des Programms ====
 +//Hier ist das vollständige Programm. Die Bedienung bleibt dieselbe wie beim Grundgerüst. Der einzige Unterschied besteht darin, dass die Action-Funktionen nun implementiert wurden.
 +\\
 +Das Programm erfordert, dass die Variable ''calibrationDistance'' an die vorgegebene Kalibrierungsstrecke angepasst wird. Die Kalibrierungsstrecke muss zuvor noch erstellt werden (siehe Abbildung).
 +//
  
-FIXME  <color #ed1c24>ABSCHNITT ENTSTEHT GERADE! - CODE NICHT GETESTET! 
-</color> 
  
-^ Kalibrierung ^ +Step 1: Kalibrierung ^ 
-|{{ :inf:msr:mbot2.png?400 |}}| +|{{ :inf:msr:mbot2.png?550 |}}| 
-|Die Kalibrierung erfolgt, indem eine bestimmte Strecke (''calibrationDistance'' im Quellcode) abgefahren wird, die durch zwei schwarze Streifen begrenzt ist. ''calibrationDistance'' ist im Quellcode fest einprogrammiert (**hardcodiert**), daher müssen die schwarzen Streifen natürlich dazu passen. 🙂 |+|<WRAP>Die Kalibrierung erfolgt, indem eine bestimmte Strecke (''calibrationDistance'' im Quellcode) abgefahren wird, die durch zwei schwarze Streifen begrenzt ist. ''calibrationDistance'' ist im Quellcode fest einprogrammiert (**hardcodiert**), daher müssen die schwarzen Streifen natürlich dazu passen. 🙂 
  
 +🔹 Vorgehensweise:
 +  * 1️⃣ Stellen Sie den **mBot** auf die erste schwarze Linie.
 +  * 2️⃣ Kontrollieren Sie, dass die Sensoren des **Liniensensors** auf der schwarzen Linie befinden!
 +          * Tipp: Überprüfen Sie dies mit Hilfe der Hilfs-LEDs am Sensor. ☛ [[hello_mbot_linesensor|Hello mBot LineSensor]]
 +  * 3️⃣ Drücken Sie **C**, um die Kalibrierung zu starten. 
  
-^ Verwendung nach der Kalibrierung ^+Nach der Kalibrierung kann der mBot für die Distanzfahrt verwendet werden. Die Kalibrierung kann bei Bedarf jederzeit wiederholt werden. 
 +</WRAP>
 + 
 +^ Step 2: Roboter fahren lassen 8-) ^
 |{{ :inf:msr:steuerlogik.png?550 |}}| |{{ :inf:msr:steuerlogik.png?550 |}}|
 |Nach der Kalibrierung kann eine Distanz (**D**) eingegeben werden und anschließend beliebig oft mit **F** oder **B** vorwärts bzw. rückwärts gefahren werden. Drücken Sie **E**, um es vorzeitig zu beenden.| |Nach der Kalibrierung kann eine Distanz (**D**) eingegeben werden und anschließend beliebig oft mit **F** oder **B** vorwärts bzw. rückwärts gefahren werden. Drücken Sie **E**, um es vorzeitig zu beenden.|
 +
 +
 +
 +<WRAP center round tip 95%>Falls der Roboter nicht sauber geradeaus fährt, lässt sich das Programm dank seiner modularen Struktur leicht erweitern. Es ist möglich, eine zusätzliche Kalibriermethode zu implementieren, die sicherstellt, dass der Roboter präzise geradeaus fährt.“
 +</WRAP>
 +
 +
 ==== Quellcode (engl. Sourcecode) ==== ==== Quellcode (engl. Sourcecode) ====
  
Zeile 373: Zeile 402:
 MeDCMotor motor1(M1); MeDCMotor motor1(M1);
 MeDCMotor motor2(M2); MeDCMotor motor2(M2);
 +
 +// IR-Entprellen
 +static uint8_t lastCode       = 0xFF;
 +static unsigned long lastTime = 0;
 +const unsigned long COOL_DOWN = 1000; // in Millisekunden, also 1 Sekunde
  
 // Allgemein // Allgemein
-unsigned long calibrationTravelTime = 0+unsigned long calibrationTravelTime; 
-int calibrationLength = 100;  // cm+unsigned long currentTravelTime = 100;
  
-int travelDistance 0; +// ADJUST AREA START 
-unsigned long currentTravelTime+int calibrationDistance 40 // in cm 
-int speed = 180; // Motor speed+int speed               200; // Motor speed 
 +int dir                 = 1;   // change to -1 if forward drive backwards! 
 +// ADJUST AREA END
  
 // actionCalibration... // actionCalibration...
 unsigned long ac_movingStartTimeForward  = 0; unsigned long ac_movingStartTimeForward  = 0;
-unsigned long ac_movingTimeForward = 0;+unsigned long ac_movingTimeForward       = 0;
 unsigned long ac_movingStartTimeBackward = 0; unsigned long ac_movingStartTimeBackward = 0;
-unsigned long ac_movingTimeBackward = 0; +unsigned long ac_movingTimeBackward      = 0; 
- +bool ac_isMoving         = false; 
-bool ac_isMoving = false; +bool ac_isForwardMoving  = false;
-bool ac_isForwardMoving = false;+
 bool ac_isBackwardMoving = false; bool ac_isBackwardMoving = false;
-bool ac_calibrationDone = false;+bool ac_calibrationDone  = false;
  
 +// motor movement
 +bool mm_firstRunMotor = true;
 +bool mm_motorActive   = false;
 +unsigned long mm_motorStartTime = 0;
  
-// actionForward +//FSM
-unsigned long af_StartTime = 0; +
-bool af_done      = false; +
-unsigned long previousMillis = 0; +
-bool firstRun = true; +
 enum State { enum State {
   STATE_OFF,   STATE_OFF,
 +  STATE_BACKWARD,
   STATE_CALIBRATION,   STATE_CALIBRATION,
-  STATE_FORWARD+  STATE_DISTANCE
-  STATE_BACKWARD+  STATE_FORWARD
 }; };
-State state = STATE_OFF;+ 
 +State state     = STATE_OFF;
 State lastState = STATE_OFF; State lastState = STATE_OFF;
 +
 +enum ExState {
 +  EX_IDLE,
 +  EX_WAIT_FOR_INPUT
 +};
 +ExState exState       = EX_IDLE;
 +
 +int     inputNumber   = 0;    // Anzahl der eingegebenen Stellen
 +String  inputBuffer   = "";   // Sammeln der Ziffern als Text
 +int     inputDistance = 0;    // Konvertierte Eingabe
 +
 void setup() { void setup() {
   led.setpin(13);   led.setpin(13);
 +  //Serial.begin(9600);  // debugging
   ir.begin();   ir.begin();
 } }
  
 void loop() { void loop() {
-  // step: command+  // step: command (IR-Taste einlesen)
   int cmd = read();   int cmd = read();
-  // step: state+  // step: state bestimmen
   state  = decode(cmd);   state  = decode(cmd);
-  // step: action+  // step: zustandsabhängige Aktion
   switch (state) {   switch (state) {
     case STATE_CALIBRATION:     case STATE_CALIBRATION:
Zeile 424: Zeile 472:
       break;       break;
     case STATE_FORWARD:     case STATE_FORWARD:
-   //   actionForward();+      actionForward();
       break;       break;
     case STATE_BACKWARD:     case STATE_BACKWARD:
-   //   actionBackward();+      actionBackward(); 
 +      break; 
 +    case STATE_DISTANCE: 
 +      actionDistance();
       break;       break;
     case STATE_OFF:     case STATE_OFF:
-    //  actionOff();+      actionOff();
       break;       break;
   }   }
 } }
- 
  
 /* /*
-     Funktionen+  --------------------------- 
 +  Funktionen 
 +  ---------------------------
 */ */
 +void setLED(int r, int g, int b) {
 +  led.setColorAt(0, r, g, b);
 +  led.setColorAt(1, r, g, b);
 +  led.show();
 +}
  
 int read() { int read() {
   if (ir.decode()) {   if (ir.decode()) {
     uint32_t code = getIRCode();     uint32_t code = getIRCode();
 +
 +    // Vermeidung wiederholter Eingaben
 +    unsigned long now = millis();
 +    if (code == lastCode && (now - lastTime < COOL_DOWN))
 +      return -1;
 +    lastCode = code;
 +    lastTime = now;
 +
 +    //
     switch (code) {     switch (code) {
-      case IR_BUTTON_E:  buzzer.tone(1200, 600); return 0;   break; +      case IR_BUTTON_E: 
-      case IR_BUTTON_C buzzer.tone(1200, 600); return 1;   break; +        buzzer.tone(1200, 200); 
-      case IR_BUTTON_B{ +        return 0;  // STATE_OFF 
-          buzzer.tone(1200, 600); +        break; 
-          // TODO read value +      case IR_BUTTON_B: 
-          return 2; +        buzzer.tone(1200, 200); 
-          break; +        return 1;  // STATE_BACKWARD 
-        } +        break; 
-      case IR_BUTTON_F: { +      case IR_BUTTON_C
-          buzzer.tone(1200, 600); +        buzzer.tone(1200, 200); 
-          // TODO read value +        return 2;  // STATE_CALIBRATION 
-          return 3; +        break; 
-          break; +      case IR_BUTTON_D: 
-        }+        initInput(); 
 +        return 3;  // STATE_DISTANCE 
 +        break; 
 +      case IR_BUTTON_F: 
 +        buzzer.tone(1200, 200); 
 +        return 4;  // STATE_FORWARD 
 +        break;
  
-    }+      // Ziffern 0–9 
 +      case IR_BUTTON_0: handleInput(0); break; 
 +      case IR_BUTTON_1: handleInput(1); break; 
 +      case IR_BUTTON_2: handleInput(2); break; 
 +      case IR_BUTTON_3: handleInput(3); break; 
 +      case IR_BUTTON_4: handleInput(4); break; 
 +      case IR_BUTTON_5: handleInput(5); break; 
 +      case IR_BUTTON_6: handleInput(6); break; 
 +      case IR_BUTTON_7: handleInput(7); break; 
 +      case IR_BUTTON_8: handleInput(8); break; 
 +      case IR_BUTTON_9: handleInput(9); break;
  
 +      // Taste 'Setting' = Eingabe abschließen
 +      case IR_BUTTON_SETTING:
 +        finalizeInput();
 +        return -1;  // Kein direkter Zustandswechsel
 +        break;
 +    }
   }   }
-  return -1; // unknow cmd+  return -1; // keine bekannte/verwertbare Taste
 } }
  
-uint32_t  getIRCode() {+uint32_t getIRCode() {
   uint32_t value = ir.value;   uint32_t value = ir.value;
-  value = value >> 16 & 0xff;+  value = (value >> 16& 0xff;
   return value;   return value;
 } }
Zeile 473: Zeile 561:
 State decode(int cmd) { State decode(int cmd) {
   switch (cmd) {   switch (cmd) {
-    case 0: lastState = STATE_OFF; return STATE_OFF; +    case 0: 
-    case 1: lastState = STATE_CALIBRATION ; return  STATE_CALIBRATION+      lastState = STATE_OFF; 
-    case 2: lastState = STATE_FORWARD; return STATE_FORWARD+      return STATE_OFF; 
-    case 3: lastState = STATE_BACKWARD; return STATE_BACKWARD;+    case 1: 
 +      lastState = STATE_BACKWARD; 
 +      return STATE_BACKWARD
 +    case 2: 
 +      lastState = STATE_CALIBRATION; 
 +      return STATE_CALIBRATION
 +    case 3: 
 +      lastState = STATE_DISTANCE; 
 +      return STATE_DISTANCE; 
 +    case 4: 
 +      lastState = STATE_FORWARD; 
 +      return STATE_FORWARD;
   }   }
   return lastState;   return lastState;
 } }
  
-void  calculateTravelTime() {+/* 
 +  --------------------------- 
 +  Eingabemodus für EX-Befehle 
 +  --------------------------- 
 +*/ 
 +void initInput() { 
 +  buzzer.tone(1000, 200); 
 +  exState     = EX_WAIT_FOR_INPUT; 
 +  inputNumber = 0; 
 +  inputBuffer = ""; 
 +  setLED(0, 0, 255); // LED BLUE 
 +}
  
-  double v = (1.0 * calibrationLength/ (1.0 * calibrationTravelTime); +void handleInput(int number{
-  currentTravelTime = v * travelDistance;+
  
 +  if (exState != EX_WAIT_FOR_INPUT) return;
 +
 +  // Maximal 3 Stellen erlauben
 +  if (inputNumber >= 3) {
 +    buzzer.tone(300, 300);
 +    delay(200);
 +    buzzer.tone(300, 300);
 +    return;
 +  }
 +
 +  // Zahl anhängen
 +  inputBuffer += String(number);
 +  inputNumber++;
 +  buzzer.tone(1200, 80);
 } }
 +
 +void finalizeInput() {
 +  if (exState == EX_WAIT_FOR_INPUT) {
 +    exState = EX_IDLE;
 +    buzzer.tone(1200, 200);
 +    setLED(0, 0, 0); // LED OFF
 +  }
 +}
 +
 +/*
 +  ---------------------------
 +  Funktionen ...actionXXX
 +  ---------------------------
 +*/
 void actionCalibration() { void actionCalibration() {
  
Zeile 492: Zeile 629:
     return;     return;
  
-  led.setColorAt(1, 255, 0, 0); +  setLED(255, 0, 0); // RED ON
-  led.setColorAt(0, 255, 0, 0); +
-  led.show();+
   int sensorState = lineFinder.readSensors();   int sensorState = lineFinder.readSensors();
  
Zeile 501: Zeile 636:
     motor1.stop();     motor1.stop();
     motor2.stop();     motor2.stop();
-    motor1.run(-speed); +    motor1.run(-dir * speed); 
-    motor2.run(speed);+    motor2.run( dir * speed); 
     ac_movingStartTimeForward = millis();     ac_movingStartTimeForward = millis();
     ac_isMoving = true;     ac_isMoving = true;
Zeile 516: Zeile 652:
     motor2.stop();     motor2.stop();
     ac_movingTimeForward = millis() - ac_movingStartTimeForward;     ac_movingTimeForward = millis() - ac_movingStartTimeForward;
- +    motor1.run( dir * speed); 
-    motor1.run(speed); +    motor2.run(-dir * speed);
-    motor2.run(-speed);+
     ac_movingStartTimeBackward = millis();     ac_movingStartTimeBackward = millis();
     do {     do {
Zeile 524: Zeile 659:
     } while ( sensorState != S1_OUT_S2_OUT);     } while ( sensorState != S1_OUT_S2_OUT);
     ac_isBackwardMoving = false;     ac_isBackwardMoving = false;
-    ac_isForwardMoving = true;+    ac_isForwardMoving  = true;
   }   }
  
Zeile 534: Zeile 669:
     calibrationTravelTime = (ac_movingTimeForward + ac_movingTimeBackward) / 2.0;     calibrationTravelTime = (ac_movingTimeForward + ac_movingTimeBackward) / 2.0;
     ac_calibrationDone = true;     ac_calibrationDone = true;
-    led.setColorAt(1, 0, 0, 0); 
-    led.setColorAt(0, 0, 0, 0); 
-    led.show(); 
     buzzer.tone(1200, 600);     buzzer.tone(1200, 600);
 +    lastState = STATE_OFF;
   }   }
 +}
 +
 +void motorMovement(int go_forward ) {
 +  unsigned long currentMillis = millis();
 +
 +  // Wenn der Motor aktuell läuft, prüfen wir, ob die Zeit abgelaufen ist
 +  if (mm_motorActive) {
 +    if (currentMillis - mm_motorStartTime >= currentTravelTime) {
 +      motor1.stop();
 +      motor2.stop();
 +      mm_motorActive = false;
 +      state          = STATE_OFF;
 +      lastState      = STATE_OFF;
 +    }
 +    return;
 +  }
 +
 +  if (!mm_firstRunMotor)
 +    return;
 +
 +  setLED(0, 255, 0); // LED GREEN
 +  motor1.run(-go_forward * speed);
 +  motor2.run( go_forward * speed);
  
 +  mm_motorStartTime = currentMillis;
 +  mm_motorActive    = true;
 +  mm_firstRunMotor  = false;
 } }
  
 void actionForward() { void actionForward() {
 +  motorMovement(dir);
 } }
 void actionBackward() { void actionBackward() {
 +  motorMovement(-dir);
 } }
-void actionDistance(){ 
-} 
-void actionOff() { 
  
-  led.setColorAt(1, 0, 0, 0); +void actionDistance() { 
-  led.setColorAt(0, 0, 0, 0); +  //Serial.println("...actionDistance"); 
-  led.show();+  // noch in der Eingabe? 
 +  if (exState == EX_WAIT_FOR_INPUT) 
 +    return;
  
 +  // step: ...calculate distance
 +  inputDistance = max(0, min(200, inputBuffer.toInt()));
 +
 +  // step: calculate the travel time (for non blocking-method)
 +  double v = (1.0 * calibrationDistance) / (1.0 * calibrationTravelTime);
 +  currentTravelTime = inputDistance / v;
 +  // Serial.print("Eingegebene Distance: ");
 +  // Serial.println(inputDistance);
 +}
 +
 +void actionOff() {
 +  setLED(0, 0, 0); // LED OFF
   // reset   // reset
   motor1.stop();   motor1.stop();
Zeile 559: Zeile 731:
  
   // reset state calibration   // reset state calibration
-  ac_isMoving = false; +  ac_isMoving         = false; 
-  ac_isForwardMoving = false;+  ac_isForwardMoving  = false;
   ac_isBackwardMoving = false;   ac_isBackwardMoving = false;
-  ac_calibrationDone = false;+  ac_calibrationDone  = false;
  
-  // reset state forward +  // reset movement 
- +  mm_firstRunMotor    = true; 
-  // reset state backward+  mm_motorActive      = false; 
 +  mm_motorStartTime   = 0;
  
 +  // reset state distance
 +  exState       = EX_IDLE;
 } }
 </Code> </Code>
 ==== Erklärungen zum Quellcode ==== ==== Erklärungen zum Quellcode ====
-==== Programmbeispiel ====+=== ⚙️ Setup (setup()) === 
 +Initialisiert die IR-Fernbedienung und setzt den LED-Pin.   
 +  * ''ir.begin()'' → Startet die IR-Signalverarbeitung.   
 +  * ''led.setpin(13)'' → Setzt den LED-Steuerpin.   
 + 
 +=== 🔄 Loop (loop()) === 
 +  - **Liest IR-Signale (''read()'')**   
 +  - **Bestimmt den aktuellen Zustand (''decode()'')**   
 +  - **Führt die passende Aktion aus (`actionXXX()`)**   
 + 
 +=== 🚦 Zustandsbezogene Aktionen (actionXXX()) ==== 
 +  * **''actionForward()'' / ''actionBackward()''** → startet Motoren für Vorwärts-/Rückwärtsfahrt.   
 +  * **''actionDistance()''** → Berechnet die Fahrtzeit basierend auf eingegebener Distanz.   
 +  * **''actionCalibration()''** → Bestimmt die Fahrzeit für eine feste Strecke mit dem Linienfolger.   
 +  * **''actionOff()''** → Stoppt alle Motoren und setzt den Zustand zurück.   
 + 
 +=== ⌨️ Eingabeverarbeitung (handleInput(), finalizeInput()) === 
 +  - Ermöglicht die Eingabe einer numerischen Distanz per IR-Fernbedienung.   
 +  - ''handleInput(int number)'' → Fügt eine Zahl zur Eingabe hinzu.   
 +  - ''finalizeInput()'' → Wandelt den Eingabewert in eine Strecke um.   
 + 
 +=== ⚙️ Die ADJUST AREA === 
 +Hier können **drei zentrale Parameter** angepasst werden:   
 +  * **''calibrationDistance = 40''** → Standardstrecke für die Kalibrierung in cm.   
 +  * **''speed = 200''** → Geschwindigkeit der Motoren.   
 +  * **''dir = 1''** → Richtungskorrektur für Vorwärtsbewegung.  
 +          * Falls das Fahrzeug rückwärts fährt, auf ''-1'' setzen.   
 + 
 +Die Werte beeinflussen das Fahrverhalten direkt und sollten je nach Umgebung angepasst werden.   
 + 
mbot_streckenfahren.1740827745.txt.gz · Zuletzt geändert: 2025/03/01 11:15 von torsten.roehl