- Akku Tests und Balkonkraftwerk Speicher         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 17

Thema: pulseIn Klappt nicht

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    07.04.2015
    Beiträge
    903
    Dein "digitalWrite (13, HIGH);" am Ende der Funktion wird nie ausgeführt. "Return" springt aus der Funktion. Mag es daran liegen (Triggersignal) oder ist das nur zu Dekozwecken?
    Abhilfe: schiebe die entsprechende Return -Zeile ans Ende der Funktion.

    Frage noch (bin kein Arduino-Progger): Was ist ein TAB?

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von Rabenauge
    Registriert seit
    13.10.2007
    Ort
    Osterzgebirge
    Alter
    56
    Beiträge
    2.210
    Ausserdem ist pulseIn() blockierend...
    Das wird oft übersehen, wenn die Entfernung grösser ist als die Reichweite des Sensors, tut sich ne volle Sekunde- gar nichts, während der Rechner nur wartet ob da noch was kommt. Da nix kommt, ist das Ergebnis 0.0.
    Daher kann (und sollte man, wenns einigermassen zügig laufen soll) ein sinnvolles Timeout festgelegt werden.
    Grüssle, Sly
    ..dem Inschenör ist nix zu schwör..

  3. #3
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    18.03.2013
    Beiträge
    242
    Zitat Zitat von Rabenauge Beitrag anzeigen
    Ausserdem ist pulseIn() blockierend...
    Das wird oft übersehen, wenn die Entfernung grösser ist als die Reichweite des Sensors, tut sich ne volle Sekunde- gar nichts, während der Rechner nur wartet ob da noch was kommt. Da nix kommt, ist das Ergebnis 0.0.
    Daher kann (und sollte man, wenns einigermassen zügig laufen soll) ein sinnvolles Timeout festgelegt werden.
    Hallo,
    es ist schon so weit, dass mich diese Blockierung stört.
    Kann man da was anderes machen, dass das Programm weiterläuft, während der US-Sensor auf den Antwortimpuls wartet?

    Gruß

    fredyxx

  4. #4
    HaWe
    Gast
    Zitat Zitat von fredyxx Beitrag anzeigen
    Hallo,
    es ist schon so weit, dass mich diese Blockierung stört.
    Kann man da was anderes machen, dass das Programm weiterläuft, während der US-Sensor auf den Antwortimpuls wartet?

    Gruß

    fredyxx
    ja, mit Multithreading.
    Es gibt dazu z.B. die Scheduler Lib von M. Patel, mit der man mehrere loops() parallel, unabhängig voneinander laufen lassen kann, und die sogar auch auf AVRs funktioniert.
    Da sie nicht pre-emptives, sondern kooperatives MT bieten und die loops dauerhaft parallel laufen, können z.B. Semaphoren zur Thread-Steuerung benutzt werden: Diese werden vom Haupt-loop() aus gesetzt und beginnen zu messen, sobald ein Semaphor einen bestimmten Wert besitzt, ansonsten können sie auch "leer" laufen. Erfordert nt ein wenig Übung und ERfahrung, zugegebenermaßen.
    Mit pulsin habe ich es noch nicht getestet, wäre aber einen Versuch wert:

    https://github.com/mikaelpatel/Arduino-Scheduler

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von Rabenauge
    Registriert seit
    13.10.2007
    Ort
    Osterzgebirge
    Alter
    56
    Beiträge
    2.210
    Was du tun kannst ist, ein timeout für pulseIn festzulegen.
    Dazu rechnest du anhand der Schallgeschwindigkeit die nötige Laufzeit für deine maximal nötige Entfernung aus (bei den billigen hc-sr04 sind das maximal 4m, aber nimm das doppelt, da das Echo auch zurückmuss, wenn du nur kürzere Entfernungen zu nutzen gedenkst, umso besser), und hast dein Timeout. Länger wartet der Prozessor dann nicht!
    Lies dazu mal die Doku zu Pulsein, da steht dann auch, ob man es in Millisekunden (ich glaub schon, habs aber nicht im Kopf) angeben muss, und auch, wie man das macht- müsste der dritte, optionale Parameter bei pulseIn() sein...
    In der Regel kommst du dann auf Wartezeiten, mit denen man gut leben kann (8m dauern bei Schallgeschwindigkeit ja nicht so wirklich lange).
    Oder du nimmst eben was schnelleres als Ultraschall-prinzipbedingt ist das ein bissel lahmarschig.

    Alternativ guckst du dir mal die NewPing- (oder ähnlich...) Bibliothek an, die arbeitet angeblich nicht-blockierend.

    So ganz theoretisch _könnte es sogar gehen, als Eingang einen der Hardware-Interrupt-Pins zu benutzen.
    Dann ist da definitiv nix blockierend, wenn man es ungefähr so macht:

    -Ping senden (wie das beim HC nötig ist, über einen normalen Digitalpin)- den Eingang (Echo) aber auf einen der Interrupt-Pins legen. Der müsste dann so konfiguriert werden, dass er bei High den Interrupt auslöst.
    Beim Senden die aktuellen Millisekunden (oder auch die Microsekunden, geht auch) merken, und in der ISR wiederum die aktuellen merken.
    Wenn dann "das andere"- was nebenbei laufen soll, abgearbeitet ist kann man MillisSenden von MillisEmpfangen abziehen und hat- die Laufzeit (aus der man wiederum die Entfernung errechnen kann). Da dank dem Interrupt sofort reagiert wird, können in der Zwischenzeit durchaus andere Dinge erledigt werden....
    Kann man dann noch verfeinern, indem man z.B. den Interrupt nur aktiviert, wenn auch gemessen werden soll usw.
    Müsste eigentlich funktionieren-probiert hab ich es aber noch nicht!
    Wenn du es probieren willst (nicht besonders schwierig, aber aus unverständlichen Gründen haben viele Angst vor Interrupts), halt mich mal auf dem Laufenden, die Idee kam mir grade beim schreiben erst.

    *notiz an mich selber: das ^^ mal im Hinterkopf behalten, hat was...
    Grüssle, Sly
    ..dem Inschenör ist nix zu schwör..

  6. #6
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    18.03.2013
    Beiträge
    242
    Zitat Zitat von Rabenauge Beitrag anzeigen

    So ganz theoretisch _könnte es sogar gehen, als Eingang einen der Hardware-Interrupt-Pins zu benutzen.
    Dann ist da definitiv nix blockierend, wenn man es ungefähr so macht:

    *notiz an mich selber: das ^^ mal im Hinterkopf behalten, hat was...
    Hallo,


    ich hab's mal mit dem Interrupt probiert. Klappt aber nur mit einem merkwürdigen Haken.

    Prinzip:

    stoße alle 500 ms den US-Sensor an, speichere "mikrosanf = micros()" und erwarte mit "attachInterrupt(1, Interruptaktion, FALLING)" das Echo des US's, speichere "mikrosend = micros()".

    So weit so gut.

    Der Haken ist, dass die von Hand gemessene Entfernung, die sich auch mit der Variante "pulseIn" ergibt, nur dann mit dem Ergebnis in "Entf_int" übereinstimmt, wenn ich von den ermittelten Mikrosekunden "mikrosec = mikrosend - mikrosanf" 540 µs abziehe. Zwischen Start US-Sensor und Interrupt kommen also irgendwo 540 µs dazu. Nur wo???

    Das sind die Porgrammteile:

    Code:
    int Ausg_US_Trigger = 13;
    volatile int Eing_US_Signal = 3;
    
    int US_Zykluszeit = 500;   //Messintervall für die Ultraschallmessung
    
    unsigned long millis_alt;
    unsigned long mikrosend;
    
    int Entf_int;
    
    
    
    void setup() {   //    SETUP   SETUP   SETUP   SETUP   SETUP
    
      Serial.begin(250000);
      while (!Serial);
    
      pinMode (Ausg_US_Trigger, OUTPUT);  // Ausgang für das US-Triggersignal
    
      pinMode (Eing_US_Signal, INPUT);  //   Rückmeldungesignal vom US-Sensor
    
    }    //    ENDE SETUP
    
    
    
    void loop() {     //     LOOP     LOOP     LOOP     LOOP     LOOP
    
      attachInterrupt(1, Interruptaktion, FALLING);    //  1 ist hier das zum Eingang 3 gehörige Interruptsignal
    
      if ((millis() - millis_alt) >  US_Zykluszeit) {  //   in dieser if wird das UP Entfernung() alle 0,5s aufgerufen
        
        millis_alt = millis();
    
        Entf_int = Entfernung();             // Ergebnis aus dem UP Entfernung() wird nach Entf_int übertragen
    
        Serial.print ( " Entf_int  =  ");
        Serial.println (Entf_int);
    
      }     //   >>>>>   ENDE   if (millis() - millis_alt > US_Zykluszeit)
    
    
    }   // >>>>   ENDE LOOP

    Code:
    int Entfernung ()
    {
      static unsigned long mikrosec;
      static unsigned long mikrosanf;
    
      mikrosec = mikrosend - mikrosanf;
    
      digitalWrite (Ausg_US_Trigger, LOW);        //negative Flanke für Triggersignal
    
      mikrosanf = micros();         //    micros() beim ersten Durchlauf dieses UP's; der nächste folgt erst nach 500 ms
      mikrosec = mikrosec - 540;         //  540 = Korrektur für eine unerklärbare Zeitverzögerung = Messverfälschung
    
      return mikrosec / 58;                       //  Entfernung in cm;  sieh Buch Seite 230
    
    
    }       //   >>>>>   ENDE    int Entfernung()

    Code:
    void Interruptaktion() {
    
      mikrosend = micros();
      digitalWrite (Ausg_US_Trigger, HIGH);
    
    }
    Gruß

    fredyxx

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von i_make_it
    Registriert seit
    29.07.2008
    Ort
    Raum DA
    Alter
    56
    Beiträge
    2.814
    Hier mal mein Code für zwei hc-sr04 an Arduino Nano mit Interrupts.

    Eventuell kann das bei dem Problem mit der Interruptvariante helfen.

    Code:
    //Zielplatform Arduino Nano
    // zwei HC-SR04, ein Fundurino 3 Kanal line Tracking Modul
    //Nutzt beide Interrupteingänge
    const int us1_echo = 2; //Interrupteingang für Echo
    const int us2_echo = 3; //Interrupteingang für Echo
    const int us1_trig = 4; //Digitalausgang für Trigger
    const int us2_trig = 5; //Digitalausgang für Trigger
    //Linienfolger mit IR Reflexlichtschranken
    const int lf_le = 8;
    const int lf_ce = 9;
    const int lf_ri = 10;
    int lf_le_state = LOW;
    int lf_ce_state = LOW;
    int lf_ri_state = LOW;
    unsigned long us1_echo_st;
    unsigned long us2_echo_st;
    unsigned long us1_echo_et;
    unsigned long us2_echo_et;
    volatile unsigned long us1_srt;
    volatile unsigned long us2_srt;
    unsigned long us1_dist;
    unsigned long us2_dist;
    unsigned long prev1micros = 0;
    const long toggleinterval = 1000;
    int togglestate = LOW;
    volatile int us1_flag = 0;
    volatile int us2_flag = 0;
    char* string_[]={"Linefollow:", "US-Echo1:", "US-Echo2:", "Cycletime:"};
    unsigned long prev2micros = 0;
    
    void setup() {
      Serial.begin(9600);
      pinMode(us1_echo, INPUT);
      pinMode(us2_echo, INPUT);
      pinMode(us1_trig, OUTPUT);
      pinMode(us2_trig, OUTPUT);
      pinMode(lf_le, INPUT);
      pinMode(lf_ce, INPUT);
      pinMode(lf_ri, INPUT);
      attachInterrupt(0, US1_ISR, CHANGE);
      attachInterrupt(1, US2_ISR, CHANGE);
    }
    
    void loop() {
      lf_le_state = digitalRead(lf_le);
      lf_ce_state = digitalRead(lf_ce);
      lf_ri_state = digitalRead(lf_ri);
      unsigned long cur1micros = millis();
      if (cur1micros - prev1micros >= toggleinterval) { //alle 10ms umschalten
        prev1micros = cur1micros;
        if (togglestate == LOW){
          togglestate = HIGH;
          digitalWrite(us1_trig, HIGH);
          digitalWrite(us2_trig, LOW);
          us1_echo_st = 0;
          us1_flag = 0;
        }else{ 
          togglestate = LOW;
          digitalWrite(us1_trig, LOW);
          digitalWrite(us2_trig, HIGH);
          us2_echo_st = 0;
          us2_flag = 0;     
        }
      }
      us1_dist = (us1_srt / 58); // Umrechnung des Sensorwerts, ungefähr in cm (für 343m/s bei trockner Luft und 20° wäre 58,3 der genaue Wert)
      us2_dist = (us2_srt / 58);
      //=== Beginn Ausgabe ===
      Serial.print(string_[1]);
      Serial.println(us1_dist);
      Serial.print(string_[2]);
      Serial.println(us2_dist);
      Serial.print(string_[0]);
      Serial.print(lf_le_state);
      Serial.print(lf_ce_state);
      Serial.println(lf_ri_state);
      unsigned long cur2micros = micros(); //Zykluszeit Messung
      Serial.print(string_[3]);
      Serial.println(cur2micros - prev2micros);
      prev2micros = cur2micros;
      //=== Ende Ausgabe ===
    }
    
    // Inerrupt Serviceroutine Für US Zeitmessung
    void US1_ISR(){
      if (us1_echo_st == 0) {
        us1_echo_st = micros();
      } else {
        us1_echo_et = micros();
        ++us1_flag;
      }
      if (us1_flag == 1) {
        us1_srt = (us1_echo_et - us1_echo_st);
      }
    } 
    
    // Inerrupt Serviceroutine Für US Zeitmessung
    void US2_ISR(){
      if (us2_echo_st == 0) {
        us2_echo_st = micros();
      } else {
        us2_echo_et = micros();
        ++us2_flag;
      }
      if (us2_flag == 1) {
        us2_srt = (us2_echo_et - us2_echo_st);
      }
    }

  8. #8
    Erfahrener Benutzer Robotik Einstein Avatar von Rabenauge
    Registriert seit
    13.10.2007
    Ort
    Osterzgebirge
    Alter
    56
    Beiträge
    2.210
    Ach siehste- den US-Sensor wollt ich ja im aktuellen Gebastel auch noch....hm, mal gucken ob der Pro Mini nachher noch nen passenden Pin frei hat...

    Zum Problem: so ganz verstehe ich dein Programm nicht: wieso triggerst du den US-Brüllausgang da in der ISR?
    Das _könnte_ Probleme machen, denn eine ISR sollte so schnell wie nur möglich abgelaufen sein.
    Beispielsweise wär es ja denkbar, dass in der Zwischenzeit ein weiterer Interrupt ausgelöst wird oder so.

    Gestartet wird eine Messung (also das aussenden) mit High(10ms);LOW
    Das Timing scheint da halbwegs wichtig zu sein, also würd ich das (wenn denn die Zeit mal wieder reif ist) auch da direkt so machen, wie empfohlen:
    -Trigger=HIGH;
    delay(10);//kann man natürlich auch smarter lösen
    Trigger=LOW;
    // nun lauschen

    Ahja- da haben wir es vielleicht schon:

    Die eigentliche Messung wird über den Anschluss Trigger (Pin 2) gestartet. Der Messvorgang wird durch eine fallende Flanke am Trigger-Eingang ausgelöst. Das vorhergehende High-Signal muss dabei eine Mindestzeit von 10 uS anliegen.
    Der Ultraschallsensor hc-sr04 sendet daraufhin nach ca. 250 µs ein 40 kHz Burst-Signal für die Dauer von 200 µs zur eigentlichen Sensorkapsel (Transducer). Danach geht der Ausgang Echo (Pin 3) sofort auf H-Pegel und der Ultraschallsensor wartet auf den Empfang des akustischen Echos. Sobald das Echo registriert wird, fällt der Ausgang auf Low-Pegel. Nach 20 ms kann die nächste Messung erfolgen.


    Quelle
    Das würde die Verzögerung erklären, zumindest Ansatzweise.Eventuell muss da erst irgendein Kondensator aufgeladen werden oder sowas (irgendwoher muss der Bursche ja bissel Leistung kriegen, irgendwo las ich mal, dass die mit 20V an der Kapsel laufen). Das wären also schonmal 250µs.
    Der Rest- hm- ist FALLING wirklich richtig?
    Ich hatte mal massiv Probleme mit irgendeinem Programm, weil ich da auch FALLING benutzen wollte (weil es das von der Logik her war), und habs dann damit beheben können, indem ich stattdessen RISING genommen hatte (oder umgekehrt)- jedenfalls war damit das Problem vom Tisch->verstanden hab ich das aber nie. Manches ist eben doch bissel Magie.

    Insgesamt scheint aber in deinem Programm einiges nicht ganz korrekt zu sein, denn:
    bei jedem Durchlauf bindest du den Interrupt wieder ein-warum?
    Man _kann_ das durchaus machen, wenn man z.B. in der ISR weitere Interrupts unterbinden möchte, indem man ihn dort zuerst lahm legt, mit detachInterrupt().
    Generell übrigens ne gute Idee, aber ich glaube, nicht ganz so gut, wie sie klingt. Wenn ich mich recht entsinne, wird damit zwar ein weiterer Aufruf der ISR (der dann schlimmstenfalls innerhalb der bereits laufenden ISR käme) verhindert, jedoch wird der Interrupt quasi "gespeichert" und dann beim neuen aktivieren sofort ausgelöst. Bin da aber nicht ganz sicher...
    Dann muss man ihn anschliessend natürlich wieder aktivieren.
    Sonst aber ergibt das keinen Sinn, und du könntest das _einmal_ machen, im setup()-Teil nämlich.

    Weiters hast du zwar volatile int Eing_US_Signal = 3; deklariert (wozu-hast du dich da einfach nur vertan?), aber _nicht_ mikrosend...._die_ aber wird in der ISR geändert (und sollte somit volatile sein).

    Mal gucken, was die Tage wird bei mir, die Geschichte wär ein bisschen herumprobieren allemal wert- weil man damit eben die (eigentlich lahmarschigen) US-Messungen doch etwas beschleunigen könnte.

    Irgendwo hab ich noch paar solche Dinger herumliegen, und nen UNO könnt ich auch mal frei machen, zum testen.
    Grüssle, Sly
    ..dem Inschenör ist nix zu schwör..

  9. #9
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.899
    Zitat Zitat von fredyxx Beitrag anzeigen
    Hallo,
    es ist schon so weit, dass mich diese Blockierung stört.
    Kann man da was anderes machen, dass das Programm weiterläuft, während der US-Sensor auf den Antwortimpuls wartet?
    Aus einem Forum

    PulseIn is a function available with the Arduino that implements an approach know as 'poling'. It essentially sits around waiting for something to happen, until something happens the rest of your code is blocked. This is okay for a simple lab exercise to read and print values from a receiver but it is a hopeless approach for a real world application. Fortunately there are better approaches that do not require a major learning curve.
    Kurz zusammengefasst, PulseIn ist eigentlich unbrauchbar.

    Um Pulselängen zu messen gibt es bei den meisten µC die "input capture" Hardware. Wie sich das aber in die Arduino Welt einordnet, kann ich mangels Erfahrung nicht sagen. Aber eine Google-Suche nach "arduino input capture" oder "avr input capture" fördert einiges zu Tage, die arduino-Prozessoren scheinen diese Funktion zu besitzen.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  10. #10
    HaWe
    Gast
    bei Robotern hat man immer wieder das Problem, dass irgendwelche notwendigen Pausen für Events bei anderen Events stören, wenn Ereignisse quasi-simultan registriert und bearbeitet werden müssen. Das gilt ntl auch für andere Datenverarbeitungsprobleme. Daher ist mE Multithreading per time-slice-scheduling sowieso unumgänglich, was ja auch der Grund dafür ist, dass MT von den allermeisten Programmiersprchen (besonders auch für Roboter-Plattformen) unterstützt wird (gcc C POSIX pthread, C++ std::thread, Java, C#, sogar Lego NXT-G und EV3-G (alle pre-emptiv) und Fischertechnik RoboPro (kooperativ). Tatsächlich nutzt MT bei Arduino nur bestimmte Interrupts sehr geschickt, um Daten, Datenregister und Speicherbereiche zu sichern und wiederherzustellen, was man auch bare-metal tun kann, aber MT libs machen das eben sehr elegant und user-freundlich per high-level-API-Funktionen, die auch zusätzlich sehr "failsafe" programmiert und getestet sind.

    Von daher würde ich mich eher um Multithreading kümmern, wie ich es oben verlinkt habe, dann klappt es auch mit diesen und anderen blockierenden Funktionen.
    Auch wenn die Scheduler Lib bereits für Nano und Uno geeignet sind, würde ich dennoch eher einen Mega empfehlen als MCU, besser noch einen SAMD oder SAM (Arduino Zero/M0, Due, Teensy).
    Robotik ist nun mal etwas anspruchsvoller als simple Katzenklappensteuerungen, und z.B. auch Lego- oder FT "bricks" besitzen ja keine AVRs sondern ARM Prozessoren, aus gutem Grund.
    Aber wie erwähnt, der Scheduler funktioniert dennoch auch bei kleinen AVRs.

Seite 1 von 2 12 LetzteLetzte

Ähnliche Themen

  1. RP6 (M32) -- ISP klappt nicht ?!?
    Von AsuroPhilip im Forum Robby RP6
    Antworten: 3
    Letzter Beitrag: 24.03.2012, 05:53
  2. Warum klappt das nicht!
    Von Philsuro im Forum Robby RP6
    Antworten: 10
    Letzter Beitrag: 29.12.2010, 01:56
  3. SPI klappt nicht
    Von p_mork im Forum Assembler-Programmierung
    Antworten: 0
    Letzter Beitrag: 22.04.2007, 13:10
  4. C Motorsteuern klappt!?!?!pwm nicht!!!
    Von patti16 im Forum C - Programmierung (GCC u.a.)
    Antworten: 15
    Letzter Beitrag: 25.01.2006, 21:36
  5. I2C klappt bei mir nicht
    Von Matthias Mikysek im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 14
    Letzter Beitrag: 16.02.2005, 06:27

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen