-         
Seite 2 von 2 ErsteErste 12
Ergebnis 11 bis 17 von 17

Thema: pulseIn Klappt nicht

  1. #11
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    07.03.2011
    Beiträge
    1.478
    Anzeige

    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 !

  2. #12
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    09.10.2014
    Beiträge
    2.856
    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.
    ·±≠≡≈³αγελΔΣΩ∞ Schachroboter:www.youtube.com/watch?v=Cv-yzuebC7E Rasenmäher-Robot:www.youtube.com/watch?v=z7mqnaU_9A8

  3. #13
    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

  4. #14
    Erfahrener Benutzer Robotik Einstein Avatar von i_make_it
    Registriert seit
    29.07.2008
    Ort
    Raum DA
    Alter
    49
    Beiträge
    2.771
    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);
      }
    }

  5. #15
    Erfahrener Benutzer Roboter Genie Avatar von Rabenauge
    Registriert seit
    13.10.2007
    Ort
    Osterzgebirge
    Alter
    49
    Beiträge
    1.309
    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..

  6. #16
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    18.03.2013
    Beiträge
    242
    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.
    Das ergibt doch schon mal 450 µs und erst danach wartet der Sensor auf den Empfang. Wenn ich statt mit 540 µs mit 450 µs korrigiere, ändert sich eine beispielhaft gemessene Entfernung von 43 auf 44 cm. Wenn ich das noch mal nachmesse, ist das zienlich genau die Entfernung bis zur Mitte der silbernen Kapseln. Damit kann ich leben.

    Der Rest- hm- ist FALLING wirklich richtig?
    Ja, RISING klappt nicht.

    Insgesamt scheint aber in deinem Programm einiges nicht ganz korrekt zu sein, denn:
    bei jedem Durchlauf bindest du den Interrupt wieder ein-warum?
    Weil ich es nicht besser wusste. Habe ich ins SETUP verschoben.

    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).
    einfach nur vertan, habe ich geändert.

    Danke für die umfangreiche Hilfe. Einen schönen Tag noch.

    Gruß

    fredyxx

  7. #17
    Erfahrener Benutzer Roboter Genie Avatar von Rabenauge
    Registriert seit
    13.10.2007
    Ort
    Osterzgebirge
    Alter
    49
    Beiträge
    1.309
    Klasse.
    Besonders, dass es funktioniert.
    Natürlich hast du recht: wenn das "aufladen" (oderwasauchimmer) schon 250 dauert, und dann das Signal auch 200, ehe gelauscht wird, sind wir bei 450.
    Das hatte ich irgendwie übersehn.
    Grüssle, Sly
    ..dem Inschenör ist nix zu schwör..

Seite 2 von 2 ErsteErste 12

Ä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
  •