Go Down

Topic: 8x verschachteltes if...then...else (Read 292 times) previous topic - next topic

themanfrommoon

#8 hab ich leoder nicht so ganz verstanden, bzw. kann das spontan nicht umsetzen

noiasca

#16
Aug 04, 2019, 10:30 am Last Edit: Aug 04, 2019, 10:32 am by noiasca
du sollst Code-Duplikate vermeiden und das was du über Iterationen schaffen kannst z.B. in eine For-Schleife packen:

das ersetzt 4 mal

Code: [Select]

  for (byte echtSoSchwer = 0; echtSoSchwer < 4; echtSoSchwer++)
  {
    if (Pos[echtSoSchwer] - encoder.getPosition() == 0) {
      Serial.println(F("Steht bereits auf Startposition"));
    }
    else if (Pos[echtSoSchwer] - encoder.getPosition() > 0) {
      Serial.print(F("Pos"));
      Serial.print(echtSoSchwer);
      Serial.print(F(" ist am naechsten: "));
      Serial.println(Pos[echtSoSchwer]);
      Serial.print(F("fahre weiter steps: "));
      Serial.println(Pos[echtSoSchwer] - encoder.getPosition());
      stepper.runToNewPosition(map(Pos[echtSoSchwer] - encoder.getPosition(), 0, 4095, 0, StepsPerRevolution));
    }
  }
DE: Wie man Fragen postet:
1. was hat man (Sketch und Hardware)
2. was SOLL es machen
3. was macht es: IST (Fehlverhalten, Fehlermeldungen, Serial.Output ...)
4. Eine Frage stellen bzw. erklären was man erwartet

agmue

Gibt es vielleicht eine elegantere Lösung?
Ich denke ja, es ist eine Frage der Formulierung.

... ob die zufällige Startposition mit einer der vier absoluten Positionen übereinstimmt. Wenn ja, soll nichts passieren.
Wenn nein, dann soll die Distanz zur nächsten Position berechnet werden und der Stepper dort hin fahren.
Der Motor soll sich bewegen, wenn die Ist-Position nicht mit einer der vier absoluten Positionen übereinstimmt. Die boolsche Algebra hilft.

Übrigens ist encoder.getPosition() immer ein zeitaufwändiger Zugriff mittels I2C, das muß nicht sein. Mal ein Versuch:

Code: [Select]
int aktPos = encoder.getPosition();
if( (Pos[0] != aktPos) && (Pos[1] != aktPos) && (Pos[2] != aktPos) && (Pos[3] != aktPos) )
{
  stepper.move(...);
}

Sieht eleganter aus, wenn es dann noch funktioniert ...
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

postmaster-ino

Hi

Du berechnest zu jeder der Positionen die Entfernung.
Von den ganzen Entfernungen suchst Du Dir die Kleinste aus (und merkst Dir dieses Ziel).
Wenn diese Entfernung kleiner als Deine halbe tolerierbare Abweichung ist: fertig.
(Halbe Abweichung, da Du ja links wie rechts davon stehen kannst und das Ziel in der Mitte liegen soll)
Sonst: Fahrt zum eben gemerkten Ziel, dem Endpunkt, Der der aktuellen Position am Nahesten liegt - nur in die richtige Richtung starten.

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

themanfrommoon

#19
Aug 04, 2019, 11:42 am Last Edit: Aug 04, 2019, 11:48 am by themanfrommoon
@noiasca:
tja, so hab ich am Anfang auch gedacht. So funktioniert es aber leider nicht.
In meinem verschachtelten if..then..else Konstrukt kommt immer nur EINE Aktion zum tragen. Nur ein Ausgang der Schleifen wird TRUE und somit wird nur eine Bewegung gemacht.
In deiner Variante werden je nach aktueller Position bis zu 3 (oder4?!) Positionen neu angefahren.
Die anderen werden nicht verriegelt.

Es soll aber bei jedem Start nur einmal bis zur nächsten der jeweils 4 möglichen Startpositionen gedreht werden.

Man könnte das als switch case bauen, aber dann ist der Aufwand doch noch größer als mit dem if..then..else?!
Oder in deiner Schleife ne flag setzen. Aber dann sind es ja noch mehr if's die durchlaufen werden müssen?!


@agmue:
Das stimmt, daran hatte ich auch schon gedacht, es war etwas quick&dirty die Position mehrfach abzufragen. Da es nur im Setup war hatte ich mal darüber hinweggesehen. Falls das Signal verrauscht sein sollte (war es bis jetzt nicht), könnten da möglicherweise komische Effekte zustande kommen.
Ich baue das also schnell um und frage den Wert wie von dir vorgeschlagen zum Start nur noch 1x ab.

-> muss ich noch machen

@postmaster-ino:
Die Richtung muss prinzipbedingt immer die gleiche sein, ich darf nicht rückwärts drehen, sonst verklemmt etwas oder ist nicht da wo es sein soll.
Bis auf die tolerierbare Abweichung mache ich das ja momentan schon (funktioniert ja auch).
Ein reboot vom ESP scheint leider einen Schritt auszulösen (Messwert steigt um 5 an), daher dreht er bei jedem reboot etwas weiter, ansonsten müsste er ja beim nächsten reboot stehenbleiben, wenn er einmal eine der 4 möglichen Starpositionen erreicht hat und danach nicht weitergedreht hat.

Tatsächlich habe ich momentan den Fall, dass bei Position 0 der Messwert und der Sollwert übereinstimmt und die Meldung "Steh bereits auf Startposition" kommt. Und zwar reproduzierbar bei jeder Umdrehung. ....warte ich mal ein wenig bis der Motor warm wird und der Messwert möglicherweise um 1/4096stel Umdrehung (0,0879°) driftet....

noiasca

@noiasca:
tja, so hab ich am Anfang auch gedacht. So funktioniert es aber leider nicht.
In meinem verschachtelten if..then..else Konstrukt kommt immer nur EINE Aktion zum tragen. Nur ein Ausgang der Schleifen wird TRUE und somit wird nur eine Bewegung gemacht.
In deiner Variante werden je nach aktueller Position bis zu 3 (oder4?!) Positionen neu angefahren.
Die anderen werden nicht verriegelt.

Es soll aber bei jedem Start nur einmal bis zur nächsten der jeweils 4 möglichen Startpositionen gedreht werden.



du kannst gern am ende der zwei IF-Bedingugen mit einem Break aus dem For ausbrechen (und somit "beenden")


Code: [Select]


  for (byte echtSoSchwer = 0; echtSoSchwer < 4; echtSoSchwer++)
  {
    if (Pos[echtSoSchwer] - encoder.getPosition() == 0) {
      Serial.println(F("Steht bereits auf Startposition"));
      break;
    }
    else if (Pos[echtSoSchwer] - encoder.getPosition() > 0) {
      Serial.print(F("Pos"));
      Serial.print(echtSoSchwer);
      Serial.print(F(" ist am naechsten: "));
      Serial.println(Pos[echtSoSchwer]);
      Serial.print(F("fahre weiter steps: "));
      Serial.println(Pos[echtSoSchwer] - encoder.getPosition());
      stepper.runToNewPosition(map(Pos[echtSoSchwer] - encoder.getPosition(), 0, 4095, 0, StepsPerRevolution));
      break;
    }
  }
DE: Wie man Fragen postet:
1. was hat man (Sketch und Hardware)
2. was SOLL es machen
3. was macht es: IST (Fehlverhalten, Fehlermeldungen, Serial.Output ...)
4. Eine Frage stellen bzw. erklären was man erwartet

themanfrommoon

#21
Aug 04, 2019, 12:13 pm Last Edit: Aug 04, 2019, 12:20 pm by themanfrommoon
nope, nu läufts gar nicht mehr
….Debugging...

Er bleibt in der 4. Position hängen, weil die sich anders berechnet

1,2 und 3 funktionieren

0-3 geht so:
Code: [Select]
stepper.runToNewPosition(map(Pos[0] - encoder.getPosition(), 0, 4095, 0, StepsPerRevolution));
stepper.runToNewPosition(map(Pos[1] - encoder.getPosition(), 0, 4095, 0, StepsPerRevolution));
stepper.runToNewPosition(map(Pos[2] - encoder.getPosition(), 0, 4095, 0, StepsPerRevolution));
stepper.runToNewPosition(map(Pos[3] - encoder.getPosition(), 0, 4095, 0, StepsPerRevolution));
4 geht so:
Code: [Select]
stepper.runToNewPosition(map(4095 - encoder.getPosition() + Pos[0], 0, 4095, 0, StepsPerRevolution));

themanfrommoon

Ich habs jetzt so:
Code: [Select]
  int StartupPos = encoder.getPosition();
  if ( (Pos[0] != StartupPos) && (Pos[1] != StartupPos) && (Pos[2] != StartupPos) && (Pos[3] != StartupPos) ) {
    if (Pos[0] - StartupPos > 0) {
      stepper.runToNewPosition(map(Pos[0] - StartupPos, 0, 4095, 0, StepsPerRevolution));
    }
    else if (Pos[1] - StartupPos > 0) {
      stepper.runToNewPosition(map(Pos[1] - StartupPos, 0, 4095, 0, StepsPerRevolution));
    }
    else if (Pos[2] - StartupPos > 0) {
      stepper.runToNewPosition(map(Pos[2] - StartupPos, 0, 4095, 0, StepsPerRevolution));
    }
    else if (Pos[3] - StartupPos > 0) {
      stepper.runToNewPosition(map(Pos[3] - StartupPos, 0, 4095, 0, StepsPerRevolution));
    }
    else {
      stepper.runToNewPosition(map(4095 - StartupPos + Pos[0], 0, 4095, 0, StepsPerRevolution));
    }
  }


Das hat nun zwar die Hysterese noch nicht drinnen, aber es funktioniert so wie ich es brauche, und ich denke es ist ausreichend kurz und ausreichend übersichtlich.

agmue

#23
Aug 04, 2019, 12:57 pm Last Edit: Aug 04, 2019, 01:06 pm by agmue
@noiasca:
In deiner Variante werden je nach aktueller Position bis zu 3 (oder4?!) Positionen neu angefahren.
Die anderen werden nicht verriegelt.
Mit break; sieht es gut aus. Ich habe gerade auch etwas Zeit gebraucht, um die Priorisierung in (Pos[echtSoSchwer] - aktPos > 0) zu verstehen. Das ist clever :)

Das hat nun zwar die Hysterese noch nicht drinnen, ...
Mit dem Vorschlag von noiasca geht auch die Hysterese einfach (Testprogramm zur Veranschaulichung ohne Sensor):

Code: [Select]
#define Microstepping 4                    // Stepperdriver is set to 1/n microsteps (here 1/4)
#define StepperStepsPerRevolution 200           //one revolution of the stepper is 200 steps
int StepsPerRevolution = StepperStepsPerRevolution * Microstepping;         // results in 800 steps per one revolution of the stepper
#include <AccelStepper.h>
//#include <AS5600.h>
int n;
int Pos[4] = {0, 1024, 2048, 3072}; // Der Winkelsensor hat Werte für 0-360° Sensorradposition von 0-4095. Diese vier Werte in dem Array markieren im Wertebereich 0-4095 die Positionen der vier Mulden im Sensorrad
#define STEPpin  14
#define DIRpin   12
unsigned long previousMillis = 0;
unsigned long stepperMillis = 0;
const long interval = 10;
//AS5600 encoder;
int output;
AccelStepper stepper(AccelStepper::DRIVER, STEPpin, DIRpin);
void setup()
{
//  Wire.setClock(400000L); //setzt die I²C Taktfrequenz auf 400kHz
  Serial.begin(9600);
  stepper.setMaxSpeed(10000); // 10000 ist wunderbar
  stepper.setAcceleration(100000); // 100000 ist schön schnell, 200 ist schön langsam
  Pos[0] = (map(Pos[0], 0, 4095, 0, StepsPerRevolution));
  Pos[1] = (map(Pos[1], 0, 4095, 0, StepsPerRevolution));
  Pos[2] = (map(Pos[2], 0, 4095, 0, StepsPerRevolution));
  Pos[3] = (map(Pos[3], 0, 4095, 0, StepsPerRevolution));
 
  test(400);
  Serial.println(F("-------------"));
  test(603);
  Serial.println(F("-------------"));
  test(597);
  Serial.println(F("-------------"));
  test(222);
  Serial.println(F("-------------"));
}
void test(int aktPos)
{
  const int toleranz = 4;
  for (byte echtSoSchwer = 0; echtSoSchwer < 4; echtSoSchwer++)
  {
    if (abs(Pos[echtSoSchwer] - aktPos) < toleranz) {
      Serial.println(F("Steht bereits auf Startposition"));
      break;
    }
    else if (Pos[echtSoSchwer] - aktPos > 0) {
      Serial.print(F("Pos"));
      Serial.print(echtSoSchwer);
      Serial.print(F(" ist am naechsten: "));
      Serial.println(Pos[echtSoSchwer]);
      Serial.print(F("fahre weiter steps: "));
      Serial.println(Pos[echtSoSchwer] - aktPos);
      stepper.runToNewPosition(map(Pos[echtSoSchwer] - aktPos, 0, 4095, 0, StepsPerRevolution));
      break;
    }
  }
}
void loop() {
}
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

uwefed

#8 hab ich leoder nicht so ganz verstanden, bzw. kann das spontan nicht umsetzen
Du mußt kontrollieren ob die Werte des Encoder in einem bestimmten Bereich liegen.
also zB wenn der Wert 1000 sein soll dann kontrollierst Du ob der Istwert größer 1000-10 und kleiner als 1000+10 ist, also zwischen 990 und 1010 liegt.
Grüße Uwe

Go Up