[gelöst] "if-Abfrage" in einer "while-Schleife" Problem

Hallo

Ich habe ein Problem in der while Schlaufe.
Der Roboter soll mit 30counts/s fahren, sich um 90° drehen wenn der x-Wert im definierten Bereich ist und dann soll mit 80counts/s fahren bis der y-Wert im definierten Bereich ist und dann soll der Roboter anhalten.

Nur das anhalten funktioniert noch nicht und ich wollte fragen, ob das Problem in meinem Code liegt?
So wie es verstanden habe, wird ja die wenn die Bedingung stimmt die while-Schleife unendlich mal durchlaufen also sollte der Roboter, wenn das “Beacon” in der Nähe des Zielpunktes ist anhalten oder?

#include <ArloRobot.h>

float CURRENT_X = 0.0; // initialized with 0
float CURRENT_Y = 0.0;
float CURRENT_Z = 0.0;

float TARGET_X = -4.4060;  //Coordinates of measured target point
float TARGET_Y = +0.7050;

bool OkToTurnRight;
bool OkToStop;

ArloRobot Arlo;                               // Arlo object
SoftwareSerial ArloSerial(12, 13);            // Serial in I/O 12, out I/O 13
int countsLeft, countsRight;

void read_plt_data() {
  // align
  while (Serial.available() > 0 && Serial.peek() != '\n')
    Serial.read();
  // only parse data if we know there's at least the minimum packet length in the RX buffer.
  // otherwise we could end up blocking the thread and thus causing the motors to block.
  // 44 = length_timestamp (14) + space (1) + length_x (9) + space (1) + length_y (9) + space (1) + length_z (9)
  if (Serial.available() >= 44) {
    long timestamp = Serial.parseInt();
    CURRENT_X = Serial.parseFloat();
    CURRENT_Y = Serial.parseFloat();
    CURRENT_Z = Serial.parseFloat();
  }
}

void setup() {
  Serial.begin(9600);
  ArloSerial.begin(19200);                    // Start DHB-10 serial com
  Arlo.begin(ArloSerial);                     // Pass to Arlo object
  Arlo.clearCounts();                         // Clear encoder counts

}

void loop() {
  read_plt_data();
  // do something with CURRENT_X, CURRENT_Y, CURRENT_Z
  if ((CURRENT_X  < TARGET_X + 0.1 ) && (CURRENT_X  > TARGET_X - 0.1 ))
  {
    OkToTurnRight = true;
  }
  else
  {
    OkToTurnRight = false;
  }
  if ( OkToTurnRight == true)
  {
    Arlo.writeCounts(72, -72);
    while (OkToTurnRight == true)
    {
      if ((CURRENT_Y  < TARGET_Y + 0.1 ) && (CURRENT_Y  > TARGET_Y - 0.1 ))
      {
        Arlo.writeSpeeds(0, 0);
      }
      else
      {
        Arlo.writeSpeeds(80, 80);
      }
    }
  }

  if (OkToTurnRight == false)
  {
    Arlo.writeSpeeds(30, 30);
  }
}

wollte fragen, ob das Problem in meinem Code liegt?

Ja.

  1. while ist (fast) immer ein Problem und meist gar nicht erforderlich ( loop heisst Schleife )
  2. In "deinem" Code wird innerhalb der while - Schleife der Wert der Abbruch-Variablen OkToTurnRight nicht geändert, daher hast du eine Endlosschleife.

michael_x:
Ja.

  1. while ist (fast) immer ein Problem und meist gar nicht erforderlich ( loop heisst Schleife )
  2. In "deinem" Code wird innerhalb der while - Schleife der Wert der Abbruch-Variablen OkToTurnRight nicht geändert, daher hast du eine Endlosschleife.

Aber die Endlosschleife sollte ja kein Problem sein, denn dann wird ja immer eine if-Abfrage gemacht ob der gemessene y-Wert in der Nähe zum y-Wert des Zielpunktes ist und dann sollte ja sobald das zutrifft der Roboter anhalten nicht?

Hallo,

nö. Das ist deine while Schleife. Solange der Ausdruck OkToTurnRight == true wahr bleibt, solange bleibt das Programm in der while Schleife gefangen. Da dieser Ausdruck nie unwahr wird, du änderst OkToTurnRight nicht, solange bleibt das Programm in der while Schleife. Du kannst das bestimmt auch ohne while erschlagen. Ändere mal das while in if. Dann läuft die loop immer durch.

while (OkToTurnRight == true)
    {
      if ((CURRENT_Y  < TARGET_Y + 0.1 ) && (CURRENT_Y  > TARGET_Y - 0.1 ))
      {
        Arlo.writeSpeeds(0, 0);
      }
      else
      {
        Arlo.writeSpeeds(80, 80);
      }
    }

Aber wenn ich in dieser while Schleife gefangen bin, wird ja diese while Schleife unendlich mal ausgeführt oder? Ich möchte ja sobald der gemessene x-Wert in der Nähe des x-Wertes vom Zielpunktes in dieser while Schleife gefangen bleiben, sodass nur noch auf den y-Wert geschaut wird.

Dann musst Du innerhalb der Schleife das OkToTurnRight ändern.
Wie bereits gesagt, besser wäre auf while zu verzichten.

Gruß Tommy

Sentrinity:
Aber ...

Ein "Aber" an der Stelle heißt, du willst nicht runter von dem Pfad.

Dabei bin ich mir doch sicher, dass du eine recht triviale Ablaufsteuerung bauen möchtest.
Eine Schrittkette.

Über das Design Patern wurde hier im Forum schon viel geredet, denn nahezu alle Arduinoprogramme sind Ablaufsteuerungen.

Tipp:
Mache dich mit endlichen Automaten vertraut.

Übrigens, wenn ich ein Programm stoppen möchte(und das kommt nur extrem selten vor), sieht das so aus:

static void inline halt()
{
  while(1);
}


void setup() 
{
  Serial.begin(9600);      
  Serial.println("Start");
}

void loop() 
{
  Serial.println("Ausgabe 1");
  halt();
  Serial.println("Ausgabe 2"); // wird nie erreicht

}

Tommy56:
Wie bereits gesagt, besser wäre auf while zu verzichten.

combie:
Ein "Aber" an der Stelle heißt, du willst nicht runter von dem Pfad.

Dabei bin ich mir doch sicher, dass du eine recht triviale Ablaufsteuerung bauen möchtest.
Eine Schrittkette.

Ich habe denn Ansatz mit der while Schleife gewählt, weil mir sonst kein Möglichkeit eingefallen ist, wie dass der Roboter NUR beim ersten Mal wenn der gemessene x-Wert ähnlich dem gewählten x-Wert ist, sich um 90° drehen soll. Denn das soll ja nur einmal durchgeführt werden und als ich Lösungansätze für solche Probleme auf diesem Forum nachgeschauft habe, dachte ich dass dieser Variante für mich am einfachsten implementierbar ist. Wie vermeide ich es denn dass der Roboter sich nicht jedes mal dreht sondern nur einmal?

Indem Du Dir in einer Statusvariable merkst, dass er sich schon gedreht hat.
Wenn diese gesetzt ist, wird halt nicht mehr gedreht.

Gruß Tommy

Hallo,

auch wenn es nicht mehr 100% als Antwort passt, weil zu langsam getippt.

du hast demnach 2 Probleme
a) die while Schleife wird nicht beendet, weil die Bedingung nie geändert wird
b) der Robot hält nie an, weil der y Wert nie im Zielbereich ist

Lasse dir in der while die Werte serial ausgeben zum debuggen. Ich schätze die Grenzen sind zu eng gesetzt. Wenn der Stopp dann klappt, müsstest du nur nach dem stoppen die while Bedingung ändern damit du aus der Schleife rauskommst.

Wenn man den Blick darauf etwas zurücknimmt wird das alles blockierender Code. Bei einem Robot äußerst ungünstig. Am Ende wird das eine Ablaufsteuerung. Du kannst das mit der while korrigieren um die Arbeitsweise zuverstehen. Danach würde ich while nicht mehr verwenden und mich um eine Ablaufsteuerung oder Zustandsautomat genannt kümmern. Nimm ein Blatt Papier und male dir alle Zustände auf die du derzeit im Kopf hast. vor, zurück, stopp, drehen oder weiß der Geier. Dann erstellste ein Ablaufdiagramm was dabei alles passieren soll. Alles ohne eine Zeile Code.

Ergänzung zur letzten Antwort. Wie schon oft gesagt, entweder nutzt du Zustände, Merkvariablen, bool oder enum mit switch case für den Ablauf. Einmalige Aktionen beim Start können ins setup verfrachtet werden. Am Ende heißt es immer wieder Ablaufsteuerung, Ablaufsteuerung, Ablaufsteuerung ...

Wie vermeide ich es denn dass der Roboter sich nicht jedes mal dreht sondern nur einmal?

In dem du die Zustände (und ihre Änderungen), eines endlichen Automaten, genau so programmierst, wie du es brauchst.

Danke für die Tipps, ich versuche sie mal umzusetzen.

Mit der Hilfe vom Guide von agmue Ein endlicher Automat entsteht, war ich in der Lage das Problem zu lösen. Hier ist noch der neue Code. Jetzt funktioniert alles, vielen Dank für eure Hilfe.

#include <ArloRobot.h>

float CURRENT_X = 0.0; // initialized with 0
float CURRENT_Y = 0.0;
float CURRENT_Z = 0.0;

float TARGET_X = -4.4060;  //Coordinates of measured target point
float TARGET_Y = +0.6925;

enum ZUSTAENDE {losFahren, rechtsDrehen, anHalten};
byte zustand = losFahren;

ArloRobot Arlo;                               // Arlo object
SoftwareSerial ArloSerial(12, 13);            // Serial in I/O 12, out I/O 13
int countsLeft, countsRight;

void read_plt_data() {
  // align
  while (Serial.available() > 0 && Serial.peek() != '\n')
    Serial.read();
  // only parse data if we know there's at least the minimum packet length in the RX buffer.
  // otherwise we could end up blocking the thread and thus causing the motors to block.
  // 44 = length_timestamp (14) + space (1) + length_x (9) + space (1) + length_y (9) + space (1) + length_z (9)
  if (Serial.available() >= 44) {
    long timestamp = Serial.parseInt();
    CURRENT_X = Serial.parseFloat();
    CURRENT_Y = Serial.parseFloat();
    CURRENT_Z = Serial.parseFloat();
  }
}

void setup() {
  Serial.begin(9600);
  ArloSerial.begin(19200);                    // Start DHB-10 serial com
  Arlo.begin(ArloSerial);                     // Pass to Arlo object
  Arlo.clearCounts();                         // Clear encoder counts

}

void loop() {
  read_plt_data();
  // do something with CURRENT_X, CURRENT_Y, CURRENT_Z
  switch (zustand) {
    case losFahren:
      if ((CURRENT_X  < TARGET_X + 0.1 ) && (CURRENT_X  > TARGET_X - 0.1 ))
      {
        zustand = rechtsDrehen;
      }
      else
      {
        Arlo.writeSpeeds(30, 30);
      }
      break;
    case rechtsDrehen :
      Arlo.writeCounts(72, -72);
      zustand = anHalten;
      break;
    case anHalten:
      if ((CURRENT_Y  < TARGET_Y + 0.1 ) && (CURRENT_Y  > TARGET_Y - 0.1 ))
      {
        Arlo.writeSpeeds(0, 0);
        while (1)
        {

        }
      }
      else
      {
        Arlo.writeSpeeds(25, 25);
      }
      break;
  }
}

das finde ich schön von dir:

enum ZUSTAENDE {losFahren, rechtsDrehen, anHalten};

nur genau die nächste Zeile

byte zustand = losFahren;

würde ich ändern auf

ZUSTAENDE zustand = losFahren;

damit kannst du deiner Variable Zustand nicht irrtümlich einen anderen Zustand als aus der Enumeration zuweisen.

noiasca:

ZUSTAENDE zustand = losFahren;

damit kannst du deiner Variable Zustand nicht irrtümlich einen anderen Zustand als aus der Enumeration zuweisen.

Okay danke für den Tipp, ich habe es einfach wie aus dem Guide übernommen gehabt.