Go Down

Topic: Beschleunigungsmessung (Read 3420 times) previous topic - next topic

Doc_Arduino

Hallo,

enum eignet sich wunderbar für eine Ablaufsteuerung, man kann mit leichter lesbarer Zustandsbenennung arbeiten statt hunderte Variablen und dessen Namen die nur true oder false kennen. Man hat eine enum Variable und beschreibt diese mit einem neuen Zustand oder fragt den Zustand ab. Würde denken das passt zu deiner Aufgabe. Es gibt aber sicherlich verschiedene Lösungen.

Deine if Abfrage wird entweder nie gültig oder sie wird immer aufs neue gültig. Die Frage ist, wie werden state_Start und state_Ende behandelt im restlichen Code.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Doc_Arduino

Hallo,

wenn dich das jetzt hoffentlich nicht zu sehr verwirrt, ein Bsp. vielleicht passend für dich.
Code: [Select]
typedef enum {
  STOP, START, ENDE, CALC
} state;                    // Name vom neuen Datentyp
state Zustand = STOP;       // Variable vom Datentyp 'state' initialisiert mit Wert 'STOP'


Die neue Variable kannste nun jederzeit auf die Werte bzw. Zustände  STOP, START, ENDE, CALC setzen und auf diese hin abfragen.
Du kannst dir auch mal den Spass machen die Zuweisungen zu ändern und die Variable mit Serial.print dir anzeigen lassen. Dann weißt du was hinter der Kulisse abläuft.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Medolino73

Mit allerhöchster wahrscheinlichkeit ist das hier falsch
Code: [Select]
#include <FlexCAN.h>

static CAN_message_t rxmsg;
int VSS = 0;
unsigned long startMillis = millis();
unsigned long endMillis = millis();
float time = 0.00;

typedef enum {STOP, START, ENDE, CALC} state;                 // Name vom neuen Datentyp

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200);
  Can0.begin(500000);
  state Zustand = STOP;                                         // Variable vom Datentyp 'state' initialisiert mit Wert 'STOP'
}

void loop() {
  serieller_Monitor();
  if (Can0.read(rxmsg)) {
    switch (rxmsg.id) {
      case 1562:
        VSS = (int)(word(rxmsg.buf[0], rxmsg.buf[1]) / 2.76);
        Serial1.print("t401.txt=");
        Serial1.write(0x22);
        Serial1.print(VSS);                                   //Geschwindigkeit
        Serial1.write(0x22);
        Serial1.write(0xff);
        Serial1.write(0xff);
        Serial1.write(0xff);
        break;
    }

    if (VSS == 0 &&  STOP ) {                  // Startzeit speichern
      startMillis = millis();
    }

    if (VSS > 0 && STOP) {                     // Startzeit sperren
      state Zustand = START;
    }

    if (VSS >= 100 && START) {                 // Endzeit
      endMillis = millis();
      state Zustand = ENDE;
    }

    if (ENDE) {                                // Zeitenberechnung
      time = endMillis - startMillis;
      time = time / 1000;
      state Zustand = STOP;
      Serial1.print("t403.txt=");
      Serial1.write(0x22);
      Serial1.print(time);
      Serial1.write(0x22);
      Serial1.write(0xff);
      Serial1.write(0xff);
      Serial1.write(0xff);
    }
  }
}



finde leider auch kaum beispiele die für einen Anfänger verständlich erklärt wird

Doc_Arduino

#18
Mar 27, 2017, 09:08 pm Last Edit: Mar 27, 2017, 09:11 pm by Doc_Arduino
Hallo,

naja, Bsp. gibts sicherlich wie Sand am Meer, es wird nur fast nie die 100% Vorlage für einen existieren. Man muss immer lesen, verstehen und abändern, wenn man andere Bsp. als Vorlage verwenden möchte.

Du möchtest 2 Dinge abfragen, den Wert von VSS und den Zustand, nur fragst du den Zustand nicht ab ...
Zustand ist durch enum genau so eine Variable wie VSS.
Code: [Select]
if (VSS > 0 && STOP) {


Da ich gefallen daran gefunden hatte, habe ich ein allgemeines Bsp. erstellt. Den Rest musste selbst machen.
Anschauen, testen, verstehen, ausbauen ...
Code: [Select]
/*
  Doc_Arduino - german Arduino Forum
  27.03.2017
  Zeit der Beschleunigung wird gemessen
  Ereignissteuerung / Ablaufsteuerung
*/

typedef enum {
  STOP, READY, RUN, CALC, ENDE
} state;                        // Name vom neuen Datentyp
state Zustand = STOP;           // Variable vom Datentyp 'state' initialisiert mit Wert 'STOP'

const byte analogPin = A0;
unsigned int VSS = 0;

unsigned long startMillis = 0;  // nur für seriellen Monitor global
unsigned long endMillis = 0;
unsigned long Zeit = 0;

void setup() {
  Serial.begin(250000);
 
}

void loop() {
 
  VSS = analogRead(analogPin)/4;  // 0 ... 255
 
  Verarbeitung();

  serieller_Monitor();
 
}

void Verarbeitung ()
{
    //static unsigned long startMillis = 0;   // nur für seriellen Monitor global
    //static unsigned long endMillis = 0;
    //unsigned long Zeit = 0;
   
    if (VSS == 0 && Zustand == STOP) {        // Stillstand erkannt
      Zustand = READY;
      Serial.println("READY");                // Debugausgabe
    }
   
    if (VSS > 0 && Zustand == READY) {         // Start erkannt
      startMillis = millis();                  // Zeit merken
      Zustand = RUN;                           // nächster Schritt
      Serial.println("RUN");                   // Debugausgabe
    }

    if (VSS > 100 && Zustand == RUN) {         // Endmarke erkannt
      endMillis = millis();                    // Zeit merken
      Zustand = CALC;                          // nächster Schritt
      Serial.println("ENDE");                  // Debugausgabe
    }

    if (Zustand == CALC) {                     // Zeit berechnen
      Zeit = endMillis - startMillis;
      Zeit = Zeit/1000;
      Zustand = ENDE;
      Serial.println("CALC");                  // Debugausgabe
    }

    if (VSS < 1 && Zustand == ENDE) {          // zurück auf Anfang warten
      Zustand = STOP;                          // nächster Schritt
      Serial.println("STOP");                  // Debugausgabe
    }
 
}


void serieller_Monitor ()
{
  static unsigned int intervall = 500;
  static unsigned long last_millis = 0;

  if ( millis() - last_millis > intervall )  {    // aller x [ms] frische Daten
    last_millis = millis();
    Ueberschriftszeile();
    Serial.print(VSS); Serial.print('\t');
    Serial.print(startMillis); Serial.print('\t');
    Serial.print(endMillis); Serial.print('\t');
    Serial.print(Zeit); Serial.print('\t');
    Serial.print(Zustand); Serial.print('\t');
    Serial.print(millis() ); Serial.print('\t');
    Serial.println();
  }
}


void Ueberschriftszeile ()
{
  static int counter = 33;

  counter++;
 
  if (counter<25) return; // Zeit noch nicht erreicht, Funktion abbrechen
 
  counter = 0;
  Serial.print("VSS"); Serial.print('\t');
  Serial.print("start"); Serial.print('\t');
  Serial.print("ende"); Serial.print('\t');
  Serial.print("Zeit"); Serial.print('\t');
  Serial.print("state"); Serial.print('\t');
  Serial.print("millis"); Serial.print('\t');
  Serial.println();
}



Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Medolino73

Alles klar, vielen dank und sorry das ich so auf die nerven fall

Doc_Arduino

Hallo,

du nervst mich noch nicht.  ;)   Habe die Code Kommentare nochmal angepasst. Wenn du noch Verständnisprobleme hast, vielleicht nochmal die Grundlagen durchgehen. Wünsche maximale Erfolge.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Medolino73


Medolino73

Hallo, so langsam dämmerts wie der enum eingesetzt wird, der code läuft perfekt,
um die ganze geschichte abzurunden versuch ich jetzt die bestzeit im eeprom abzulegen,
dafür nutz ich die eeprom.put und eeprom.get oder doch die read und write,

michael_x

Quote
eeprom.put und eeprom.get oder doch die read und write
Wenn du mehr als 1 Byte brauchst, nimmt dir put/get die Mehr-Arbeit ab.

Ich würde mir das mit dem Zeit= Zeit/1000; aber nochmal ansehen.
Bei long Zeit; ist das eine Ganzzahl-Division und du kriegst nur ganze Sekunden-Werte (abgerundet).
Ausserdem ist es immer Mist wenn man nicht weiss, was eine Variable bedeutet (Sekunden oder Millisekunden)

Warum du die Zustände CALC und ENDE nicht zusammenfasst, weiss ich übrigens nicht.
STOP und READY sind auch ziemlich gleich ( das eine ist bei VSS == 0, das andere bei VSS < 1 )

Aber prinzipiell ist so eine Zustands-enum schon hübsch  ;)

Medolino73

na klar könnte man den code noch etwas verkürzen, aber es dient der veraunschaulichung und jemmand wie mich der noch nicht so begabt ist in arduino programmiern, die einzelnen schritte besser zu verstehen, und ohne die Hilfe von Doc_Arduino hät ich das nie hinbekommen

michael_x

na klar könnte man den code noch etwas verkürzen, aber es dient der veraunschaulichung und jemmand wie mich der noch nicht so begabt ist in arduino programmiern, die einzelnen schritte besser zu verstehen, und ohne die Hilfe von Doc_Arduino hät ich das nie hinbekommen
Wenn du das auf meine Bemerkung "statt 5 Zustände reichen auch 3" beziehst, gebe ich dir Recht.
Wenn es für dich anschaulicher ist, ist es gut !

Ich wollte auch nicht an Docs Hilfe herumkritisieren...
... na ja, das mit dem   Zeit = Zeit / 1000;   würde ich wirklich überarbeiten.   ;)
( Um was für Größenordungen geht es eigentlich ? )

   
Code: [Select]
   if (Zustand == CALC) {                     // Zeit berechnen, evtl. neue BestZeit speichern und ausgeben
      unsigned int aktZehntel = (endMillis - startMillis) / 100;
      Zustand = ENDE;
      if ( aktZehntel < BestZeit ) {
         BestZeit = aktZehntel;
         eeprom.put(0, BestZeit);
         Serial.print( "Neue Bestzeit : ");
         Serial.print( BestZeit / 10 ); Serial.write('.'); Serial.println(BestZeit%10);
      }
   }

long Zeit wird nicht gebraucht. 
Eine globale unsigned int Bestzeit; würde ich in setup() aus dem eeprom lesen.

Medolino73

ja also am anfang wußte ich nichts mit dem enum anzufangen, aber jetzt begreif ich einiges, hab auch den code entsprechend verkürzt, geht um 1/100sec also 0.00 ausgabe, was mir aber noch nicht ganz klar ist, wie speicher ich die bestzeit im eeprom ab tu das ganze auch gleich per serialprint anzeigen
hier mal der jetzige verkürze code
Code: [Select]
#include <FlexCAN.h>
#include <EEPROM.h>

static CAN_message_t rxmsg;
typedef enum {
  STOP, RUN, ENDE
} state;
state Zustand = STOP;
int VSS = 0;

unsigned long startMillis = 0;
unsigned long endMillis = 0;
float Zeit = 0.00;

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200);
  Can0.begin(500000);
}

void loop() {
  display();
  Verarbeitung();
}

void Verarbeitung () {
  if (VSS >= 0 && Zustand == STOP) {
    startMillis = millis();
    Zustand = RUN;
  }

  if (VSS > 100 && Zustand == RUN) {
    endMillis = millis();
    Zeit = endMillis - startMillis;
    Zeit = Zeit / 1000;
    Zustand = ENDE;
  }

  if (VSS < 1 && Zustand == ENDE) {
    Zustand = STOP;
  }
}


die serialprint hab ich vorerstmal auf ein tab gelegt damits übersichtlicher wird

Code: [Select]
void display() {
  if (Can0.read(rxmsg)) {
    switch (rxmsg.id) {
      case 1562:
        VSS = (int)(word(rxmsg.buf[0], rxmsg.buf[1]) / 2.76);
        break;
    }
    Serial1.print("t401.txt=");
    Serial1.write(0x22);
    Serial1.print(VSS);
    Serial1.write(0x22);
    Serial1.write(0xff);
    Serial1.write(0xff);
    Serial1.write(0xff);

    Serial1.print("t403.txt=");
    Serial1.write(0x22);
    Serial1.print(Zeit);
    Serial1.write(0x22);
    Serial1.write(0xff);
    Serial1.write(0xff);
    Serial1.write(0xff);

    Serial1.print("t404.txt=");
    Serial1.write(0x22);
  //  Serial1.print(   );
    Serial1.write(0x22);
    Serial1.write(0xff);
    Serial1.write(0xff);
    Serial1.write(0xff);
  }
}

michael_x

#27
Mar 28, 2017, 06:31 pm Last Edit: Mar 28, 2017, 06:37 pm by michael_x Reason: Nachtrag
Entweder so wie ich es mit Zehntel gezeigt habe (das kannst du leicht auf Hundertstel ändern)
oder  mit
Code: [Select]
 float zeit =(endemillis - startmillis) /1000.0 ; // Dies ist eine float - Division !
  if (zeit < bestzeit) {
     eeprom.put(0, zeit);

bestzeit ist dann natürlich auch ein float...

Nachtrag: Nachteil ist, dass ein  jungfräulicher eeprom als float nicht so eine schöne Zahl ist wie als unsigned int ( 655.35 hundertstel )

Medolino73

#28
Mar 28, 2017, 06:49 pm Last Edit: Mar 28, 2017, 11:57 pm by Medolino73
um den vergleich zu machen was im eeprom steht, muß er das ganze erstmal auslesen oder, und da müßte eigentlich auch vorher was drinstehen ??

Nachtrag, so jetzt funktioniert auch die Bestzeit im eeprom ablegen
Code: [Select]
if (VSS > 100 && Zustand == RUN) {
    endMillis = millis() - startMillis;
    Zeit = endMillis / 1000.00;
    if (Zeit < EEPROM.get( 0, eep )) {
      EEPROM.put( 0, Zeit );
    }


jetzt gibts da aber ein kleines problemchen hab ich wärend dem Testen gemerkt,
angenommen man steht an der startlinie und würgt den Motor ab, die Zeit läuft aber schon, jetzt müßte man über 100 erstmal fahren damit er wieder resetet, dafür gibts bestimmt auch eine lösung hoffe ich mal, dann wäre die geschichte absolut perfekt

michael_x

Quote
damit er wieder resetet, dafür gibts bestimmt auch eine lösung hoffe ich mal
Nennt sich Reset ;) Warum sollte man diesen Arduino-Taster nicht entsprechend verwenden?

Kann man natürlich auch mit einem anderen Taster realisieren, der dann in der Programm-Logik den Zustand entsprechend setzt.

(Was passiert, wenn du bei fahrendem Auto den Arduino resettest ?)


Ansonsten: Das wichtigste fehlt in deinem Sketch: die Variablen-Definition ( Zeit , eep )
Schön zu lesen, dass
Code: [Select]
float eep;
float zeit = 999.99;
if (zeit < EEPROM.get(0,eep) {
  Serial.println("EEPROM initialisert");
  EEPROM. put(0,zeit);
}

auch funktioniert, wenn das get bei jungfräulichem eeprom erstmal NaN liefert ... (?) ...


Na gut, das zweitwichtigste (die eindeutige Definition der verwendeten Libraries) fehlt auch bei mir ;)

Go Up