- Akku Tests und Balkonkraftwerk Speicher         
Seite 17 von 25 ErsteErste ... 71516171819 ... LetzteLetzte
Ergebnis 161 bis 170 von 246

Thema: Autonom in kleinen Dosen: R2_D03 + Nachfolger R3D01

  1. #161
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Anzeige

    Powerstation Test
    Hallo Dosen-Dompteur.

    Wenn ich das so lese, dann kommen mir irgendwie Rechen- und Grübelfunktionen durcheinander.
    Ich kann aktuelle nicht mithalten, was du genau bei den 1,22 kHz machst.
    Ich bin mir sicher, dass du da einen Timerinterrupt laufen hast.
    Wie sieht es mit den Motorencodereingängen aus. Sind die per Interrupt bearbeitet, oder kommt da auch der Timer mit den: " ... jeder vierte; jeder achte; von 12 Aufrufen ... " ins Spiel.
    Wenn du per 4/12 bzw. 8/12 vom Timer die Encodereingänge bearbeitest, dann habe ich bei dem Speed der Motoren echt Probleme damit ob dein Timer nicht zu lahm ist.
    Ich weiß, ich weiß. Mathe ist nicht mein Ding, Aber wenn da 20-, 30-Tausend UpM drin sind, dann ist ein Messtakt von 1.22 kHz so kurz vor dem theoretischen Grenzwert um die Encoderschlitze zu sehen. Hapert es hier?

    Also rüber mit den Tatsachen:
    Werden die Encoderdaten per Interrupt in den AVR gebaggert, oder 'pollst' du anhand des Timerinterrrrrupts die Eingänge? Code, Code, Code, ...

    Der mit Fragezeichen versehene
    Sternthaler
    Lieber Asuro programieren als arbeiten gehen.

  2. #162
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.653
    Hallo ?ternthaler¿

    Zitat Zitat von Sternthaler
    ... Der mit Fragezeichen versehene ... Sternthaler
    Tut mir leid, dass ich Dich mitternächtlicher Weise ins Grübeln und zum Durcheinanderrechnen bringe. Die 1220 Hz stammen primär von der PwM für die Motoren. Die anderen Timer sind/werden genutzt, wie es die untenstehenden Übersicht zeigt. Ich nehme die gleiche Aufteilung beim MiniD0 wie beim R2D03.

    ............Bild hier  

    Die ursprünglich höhere Frequenz für die Motor-PwM, 4,88 kHz, musste ich nach unten korrigieren, damit mir die davon abgeleiteten ISR für die irDME´s - Deine CIRperei - nicht zu viel CPU-Auslastung in den Interrupts bringt. Außerdem passte die niedrigere Frequenz dann auch noch fürs Auslesen des ADC-Sharp (alle 10 ms ist etwas schnell, aber dadurch bekomme ich die neuesten Ergebnisse des Sharp eben recht flott) und für die Regelung. Der Ablauf sieht in einem simplen Diagramm damit so aus:

    Code:
    ---C---1---2---3---4---5---6---7---8---9---A---B---C---1---2---3---4--> >
       |               |               v               |               |
       |               v               AR *) Mot34     |               v
       v               AR Mot 12                       v               AR Mot 12
       Auslesen des ADC/Sharp                          Auslesen des ADC/Sharp
       
     *) AR: Aufruf der Regelungsroutine
    Die externen Interrupts der Encoder/Gabellichtschranken werden so initialisiert und ausgelesen (Ausleseroutine sinngemäß für beide) :

    Code:
    /* ============================================================================== */
    /* ===  Initialisierung fuer EXT_INT0/1 auf Pin 4+5/PD2,3 bei m168  ================
    $002 jmp SIG_INTERRUPT0 ; IRQ0 Handler   _VECTOR(1)
    $004 jmp SIG_INTERRUPT1 ; IRQ1 Handler   _VECTOR(2)              ================ */
    void XTI_0_1_init( void )    
    {                //Initialisiere beide Interrupts auf rising edge
                    //  d.h. EICRA ISC00,01,10+11 auf 1 (doc,S68)
        EICRA |= (1<<ISC11)|(1<<ISC10)|(1<<ISC01)|(1<<ISC00);
        EIMSK  |= (1<<INT1)|(1<<INT0);    //  und erlaube diese I´s in EIMSK
    // Initialisierung der Zeiten:
      Iencdr0      = 0;
      Iz_diff0     = 0;
      Iz_yseci0    = 0;
      Iz_ysecv0    = 0;
    }
    /* ============================================================================== */
    
    
    // =================================================================================
    // ===  Nicht unterbrechbare ISR für EXT_INT0 auf Pin 4/PD2/mega168  ===============
    /* Routine setzt einen Zähler hoch. Der Zähler wird im main ausgelesen
         ##>> cli/sei setzen ?? <<## und nach 2 (od. 5) hunderstel Sekunden
         auf den Speicher WEG_L/_R vorzeichenrichtig aufaddiert und dann zurückgesetzt.
         ##>> Beim Richtungswechsel (cli/sei) wird der Zähler ausgelesen und genullt,
         damit ist eine saubere Wegmessung möglich.
         Der zugehörige Motor auf PD7/PB0 = re,li und PB1 Geschwind./PWM           */
      ISR(INT0_vect)                        // hiess mal: ISR(SIG_INTERRUPT0)
      {                                     //
        if (nenc0     <  4)                      
          nenc0       =  nenc0 + 1;             
        else                                    
        {                                   // Zähle NUR jeden vierten Interrupt
          nenc0       =  1;                     
          Iencdr0 ++;                       //zähle Counter/encoder0 hoch
          Ienc0alt  = Iencdr0;                   
          Iz_yseci0 = Izeit_1;              //Weise Iz_ysec-ist-0 dem akt. Timerwert zu
          Iz_diff0 = Iz_yseci0-Iz_ysecv0;    //Neue Zeit-Differenz1 ausrechnen
          Iz_ysecv0 = Iz_yseci0;            //der aktuelle Zeitwert wird "Alter"
        }                                     
      }                                       
    /* ============================================================================== */
    Die Größe Iencdr0 dient für allfällige Odometrieaufgaben, also z.B. um eine Drehung um genau 60° oder so zu erzeugen. Sie wird entweder sinnlos rundum gezählt, oder bei Bedarf auf Null gesetzt und in der entsprechenden Routine abgefragt.

    Damit sollte Deine Frage nach dem Gewinnen der Encoderdaten doch beantwortet sein!? Also für mich sieht das nicht aus wie Pollen. Sowas brächte ja blos Heuschnupfen! Jede extINT-ISR holt sich (ja ja, das wär aber doch pollen) den aktuellen Zeitwert Izeit_1 aus dem 50µs-Timer und weist ihm dem Wert Iz_yseci0 --- i wie "ISTzeit" --- zu, errechnet daraus die Zeitdifferenz zum vorherigen Interrupt und merkt sich die aktuelle ISTzeit als Iz_ysecv0=VORheriger Wert. Ok?

    Die Initialisierung der PWMs etc hatte ich in diesem Thread bereits vorgestellt und die Regelung zum Dottie hatten wir bereits diskutiert (da gings um die Asymmetrie von iesum12 - ich kann den Link gerade nicht finden). Den Code für MiniDO stelle ich vor (wenns Dir recht ist), sobald die aktuelle Version auch weitgehend stimmt - derzeit sind die Parameter keinesfalls optimal.

    Code:
    /* ============================================================================== */
    /* ===  Regelungsroutine für Motor 12  ========================================== */
    /* Die gemessene Zeitdifferenz Iz_diff0 wird zur Regelung verwendet   
                                                                                      */
      void rgl_mo_12(void)          // (Wird) Regelung für Motor 12
    {                                 
      if (stupsi12 <= 5)            // Soll überhaupt gefahren werden?
      {                              
        OCR0A = 0;
        return;
      }                            
      tupsi12      = Iz_diff0;                      // Übernahme Iz-Wert in Regelung
      ndrz12       = stupsi12;
      if ( tupsi12 > 100 )  { tupsi12  = 100; }     // Eingrenzen
      idrz12      = 1000 / tupsi12;
      ie_mot12     = ndrz12 - idrz12;               // Vergleich => Regelabweichung
      iesum12      = iesum12 + ie_mot12;
      if  (iesum12 < -10) { iesum12  = -10;}
      if  (iesum12 >  500) { iesum12  =  500;}
      iy12         = iesum12/2;
      iy12         = iy12 + ie_mot12 + ie_mot12 + ie_mot12 + ie_mot12 + ie_mot12;
                    // Diese Rechenoperation benötigt in float 0,20 bis 0,25 ms!
                            
      if ( iy12    <   0 )   { iy12   =    0;}
      if ( iy12    > 255 )   { iy12   =  255;}
                    
      OCR0A = iy12;                 // Ansteuerung der PWM direkt statt "setPWMlinks"
                                        
      return;                          
    }               
    /* ============================================================================== */
    So, damit habe ich hoffentlich für Deine Feiertagsruhe gesorgt - wenigstens soweit, dass Du nicht nach meinem Cäh-Code grübeln musst. Wenn Du mehr Softfutter möchstest - kein Problem.

    Übrigens hatte ich die Sprungantwort fürs MiniD0 etwas oberflächlich gemessen (auch nur ein Mal *brrrr*) und eine entdeckte Macke im Kurvenverlauf lasch als Aussreisser interpretiert und unbeachtet gelassen. Tatsächlich war die Messung für die Tonne, an neueren Messungen habe ich schon gearbeitet, aber heute standen auch (wieder) ein paar geradelte Straßenkilometer, gepaart mit Höhenmetern, auf dem Plan.
    Geändert von oberallgeier (17.10.2016 um 17:13 Uhr) Grund: neuer Bildserver
    Ciao sagt der JoeamBerg

  3. #163
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Hallo oberallgeier,

    danke für die Teil-Infos. Hilft schon mal etwas weiter.

    Das habe ich hier gefunden:

    Wenn die Variable Iz_diff0 nicht eine char-Variable, sondern ein längerer Datentyp wie z.B. int ist, dann kann es vorkommen, dass in rgl_mo_xx() der Zugriff auf diese Variable durch einen Interrupt unterbrochen wird.
    Es kann dann sporadisch passieren, dass du beim Zugriff einen Teil der Bytes aus dem Speicher VOR der Int-Änderung holst, und das andere Byte NACH der INT-Änderung.

    Sicherer ist folgendes in rgl_mo_xx():
    Code:
      int   Iz_diff0_lokal;
    
       interrupt_sperren();    -- dieses sei() und oder das andere Dingsda.
       Iz_diff0_lokal = Iz_diff0;
       -- und alle weiteren Variablen, die in Interrupts 'angefasst' werden.
       interrupt_wieder_zulassen();  -- das andere Dingsda oder halt sei().
    
      weiter mit deiner Funktion
    Das gilt grundsätzlich für alle Variablen die in Interruptfunktionen geändert werden können.
    Bei char-Variablen sollte man mal genauer auf den Output vom Compiler schauen, ob ein Zugriff komplett in einem Assembler-Befehl abgearbeitet wird. Dann, und nur dann, kann das sei() oder nicht sei() weg gelassen werden.

    Gruß Sternthaler
    P.S.: Ja, ich fahre jetzt nach meinem ersten Nach-Urlaubs-Arbeitstag auch wieder nach Hause.
    Lieber Asuro programieren als arbeiten gehen.

  4. #164
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.653
    Hallo Sternthaler,

    diese Geschichte mit den Mehr-als-ein-Byte-Werten liegt mir immer am Herzen (eigentlich nicht im Magen *gggg*). ABER, soweit ich weiß, wird der Interrupt bei den ATMELControllern verboten, sobald eine ISR angeworfen wird - und erst wieder nach deren RETI erlaubt. Präziser: ich habe softwaremässig keine nested Interrupts installiert (hoffe ich - wenn meine C-Kenntnisse in diesem Punkt stimmen). Bei mir läuft die Regelroutine nach Aufruf aus einer ISR. Bitte deswegen nicht schlagen - ich habe mich ausgiebig um die schnelle Abarbeitung gekümmert, damit ich in den Pausen meiner schnellsten Interrupt-Frequenz mit der ganzen Arbeit sehr locker zurande komme - dass also auch noch andere Aufrufe erfolgen können und kein Interrupt-Stau auftritt.

    Code:
    /* ============================================================================== */
    /* ===  Nicht unterbrechbare ISR für ADC3 auf Pin 26/PC3/mega168  =============== */
    ISR(ADC_vect)                   // _VECTOR(21)   
    {                                 
      - - - -
                
      if (adc3_cnt == 4)               
        rgl_mo_12();                // Aufruf Regeln für mo_12
                                     
      if (adc3_cnt == 8)               
        rgl_mo_34();                // Aufruf Regeln für mo_34
                                     
      - - - -
                                      
    }           
    /* ============================================================================== */
    Also sollte eine neue ISR doch erst gestartet werden, wenn sowohl die rgl_mo_ij als auch die ISR ADC_vect fertig sind. Damit sollten meine je 2-bytigen Zeitvariablen ungestört leben können. Oder habe ich da etwas falsch verstanden? Hoffentlich nicht, sonst - hmmmm, dann müsste ich den ganzen Codeaufbau umwerfen.

    PS: Hoffentlich hat Dir der Osterhase "auf Arbeit" kein allzu schweres (Arbeits-) Ei gelegt.
    Ciao sagt der JoeamBerg

  5. #165
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.653
    Hallo Dosenfans,

    die Regelungsfragen sind recht ordentlich geklärt worden. Die ersten Sprungantworten hatte ich ereignisgesteuert aufgenommen – es wurden hundert Interrupts an einem Motor erfasst, das waren anfangs 25 und sind jetzt 50 Umdrehungen. In den letzten Tagen (sprich nach etlichen unbefriedigenden Auslegungsversuchen) habe ich stattdessen isochrone Messungen durchgeführt: alle 1,0 ms (sprich: 20*50 µs) wurde der jeweils aktuelle Messwert für eine halbe Umdrehung der Motorwelle gespeichert. Diese Messungen scheinen mir aussagekräftiger zu sein. Im ersten Fall bekomme ich den ersten Messwert (vermutlich) dann, wenn der erste Interrupt erfasst wird. Im zweiten Fall werden Messwerte im Stillstand erfasst, danach wird die vollständige Anlaufphase des Motors dargestellt.

    ................Bild hier  

    In diesem Diagramm wurde die Kurvensteigung mit der Wendetangente (schwarze Linie) bestimmt und daraus die Verzugszeit Tu und die Ausgleichszeit Tg. Die blaue Linie stellt eine weniger glaubhafte Wendetangente dar aufgrund einer sehr toleranten Auswertung. Danach wurde genau nach „Kochbuch“ im RNWiki: Dimensionierung nach Einstellregeln gearbeitet. Aus dem früher vorgestellten Speedtest (hier, weiter oben) wurde Kp mit 0,2 = 1/5 bestimmt. Aus den Zeiten Tu und Tg bzw. Tn und Tv wurde mit den Formeln im Wiki „Einstellregeln nach Ziegler/Nichols“ die Parameter für den PID-Regler bestimmt: Ki = 1/30 und Kd = 1/3.

    Beim Aufbau meines Codes bin ich nach dem Motto vorgegangen: klau schau wem – und habe als Vorlage wieder das RNWiki genommen sowie ein Codebeispiel von waste für einen PD-Regler für Linienfolger. Mein Code sieht danach so aus:

    Code:
    // =================================================================================
    // ===  Regelungsroutine für Motor 12  =============================================
    // Die gemessene Zeitdifferenz Iz_diff0 zwischen zwei Encoderinterrupts wird zur
    //   Regelung verwendet. Es gibt pro halbe Umdrehung einen Interrupt/Zeitwert.
                                      
      void rgl_mo_12(void)          // Regelung für Motor 12 mit 2 Interr pro Umdr.
    {                                 
                                      
      if (sspeed12 <= 10)           // Soll überhaupt gefahren werden?
      {                               
        OCR0B = 0;                  // Unter 10 mm/s soll nicht gefahren werden
        return;                       
      }                              
      tupsi12      = Iz_diff0;              // Übernahme Interruptabstand in Regelung
      ndrz12       = sspeed12;              // Nenn = Solldrehzahl = Soll-speed
                                      
      sei();                        // Erlaube Interrupts ##### nested Interrupts
                                      
      ix12         = 8300 / tupsi12;        // => Ist-Geschwindigkeit in mm/s
      ie_mot12     = ndrz12 - ix12;         // Vergleich => Regelabweichung
                                              
      if (tupsi12 > 500) {tupsi12 = 500;}   // Begrenze auf 500
                                              
      isum12      += ie_mot12;                    
      if  (isum12  < -1000) { isum12  = -1000;}
      if  (isum12  >  1000) { isum12  =  1000;}
                                      
      iyp12        = ie_mot12 / Kp12;       // P-Anteil berechnen, Kptheor = 0,25 !!
      iyi12        = isum12   / Ki12;       // I-Anteil berechnen
      iyd12        = (ie_mot12 - ie_alt12) / Kd12;         // D-Anteil berechnen
                                       
      iy12         = iyp12 + iyi12 + iyd12;    // Gesamtkorrektur PID berechnet
                                                                      
      if ( iy12 <   0 ) { iy12   =    0;}   // Stellwert (PWM) begrenzen
      if ( iy12 > 255 ) { iy12   =  255;}
                    
      OCR0B = iy12;                 // Ansteuerung der PWM direkt 
                                        
      return;                          
    }               
    // =================================================================================
    und das MiniD0 läuft damit sehr schön (Danke Sternthaler, danke waste). Ach so: die Begrenzung der tupsi auf +- 500 und die von iesum auf +- 1000 ist aufgrund von Tests erfolgt. Hohe Werte von iesum führten zu deutlichen Störungen bei positiven und sehr auffallend bei negativen Beschleunigungen. Mit den genannten Eingrenzungen sieht der Lauf glatt und gut aus.

    Leider fehlt immer noch einiges: Abweichungen an einem Motor führen zu bleibenden Winkelfehlern der zurückgelegten Spur und zu große PWM-Werte für einen Motor werden nicht gleich zum Abbremsen bzw. verringerter Sollwertvorgabe des anderen Motors benutzt. Beide Dinge sind für eine saubere Odometrie notwendig. Da muss ich wieder ne Weile auf Tauchstation.

    Ein bisschen Legende:
    vgmm ... Vorgabegeschwindigkeit in mm/s, vgmm12 ... für Motor12
    sspeed ... Sollspeed, die eigentliche Führungsgröße/Sollwert W der Reglerschleife
    Iz_diff0 ... Zeitdifferenz zwischen zwei Interrupts durch den Encoder am Motor 12 (ist gleich "Motor 0")
    ix12 ... Der "eigentliche" Istwert X der Reglerschleife = Wert von Motor12.
    Geändert von oberallgeier (17.10.2016 um 17:15 Uhr)
    Ciao sagt der JoeamBerg

  6. #166
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Hallo oberallgeier,

    schön, dass du die Zusammenfassung geschrieben hast, die wir am Form vorbei angesprochen hatten.

    Zwei Dinge scheinen mir also noch nicht so richtig zu gehen:
    1) Die Zeit die du für den Regelvorgang benötigst ist zu lang.
    2) Abweichungen auf einer Seite führen zu einem Winkelfehler.


    ---- Ding 1
    Ich denke, dass die Rechenzeit für Problem 1) an der falschen Stelle verbraucht wird.
    Nun wird mir auch klar, warum du in diesem Thread nicht auf meinen Hinweis mit den char- bzw. int-Variablen und dem cli(); bzw. sei(); eingehen wolltest. (Jubel, jetzt habe ich deinen Ablauf möglicherweise auch verstanden.)

    In deiner oben gemachten Angabe mit
    Code:
    ---C---1---2---3---4---5---6---7---8---9---A---B---C---1---2---3---4--> >
       |               |               v               |               |
       |               v               AR *) Mot34     |               v
       v               AR Mot 12                       v               AR Mot 12
       Auslesen des ADC/Sharp                          Auslesen des ADC/Sharp
       
     *) AR: Aufruf der Regelungsroutine
    und der ISR(ADC_vect)
    Code:
    /* 
    
    ============================================================================== */
    /* ===  Nicht unterbrechbare ISR für ADC3 auf Pin 26/PC3/mega168  =============== */
    ISR(ADC_vect)                   // _VECTOR(21)   
    {                                 
      - - - -
               
      if (adc3_cnt == 4)               
        rgl_mo_12();                // Aufruf Regeln für mo_12
                                     
      if (adc3_cnt == 8)               
        rgl_mo_34();                // Aufruf Regeln für mo_34
                                     
      - - - -
                                     
    }           
    /* ============================================================================== */
    liegt das Problem darin, dass du die Rechenzeit in der Interruptfunktion benötigst.
    Wie vor langer Zeit mal bei dem "ASURO als Wecker" angesprochen, und von dir ja auch gelesen, solltest du im Interrupt nicht die Reglung durchrechnen, sondern nur eine "Aufforderung" für das Hauptprogramm setzen.
    Und diese "Aufforderung" dann im Hauptprogramm bearbeiten.

    Aktuell hast du 2 Regler, die gerechnet werden wollen, also benötigst du natürlich auch 2 Variablen für die Aufforderungen.
    ISR:
    Code:
    /* ============================================================================== */
    /* ===  Nicht unterbrechbare ISR für ADC3 auf Pin 26/PC3/mega168  =============== */
    ISR(ADC_vect)                   // _VECTOR(21)   
    {                                 
      - - - -
               
      if (adc3_cnt == 4)               
        v_rgl_mo_12_knz = 1;       // AUFFORDERUNG fuer Regeln für mo_12
                                     
      if (adc3_cnt == 8)               
        v_rgl_mo_34_knz = 1;       // AUFFORDERUNG fuer Regeln für mo_34
                                     
      - - - -
                                     
    }           
    /* ============================================================================== */
    Und im Hauptprogramm:
    Code:
       main ()
    {
       Variablen ...
       Init ();
    
       while (1)
       {
          /*
             Der AUFFORDERUNG folge leisten ;-)
          */
          if (v_rgl_mo_12_knz == 1)
          {
             v_rgl_mo_12_knz = 0;
             rgl_mo_12();                // Aufruf Regeln für mo_12
          }
          if (v_rgl_mo_34_knz == 1)
          {
             v_rgl_mo_34_knz = 0;
             rgl_mo_34();                // Aufruf Regeln für mo_34
          }
       }
       ...
    }
    Und nun unbedingt in den Funktionen rgl_mo_xx() diese cli(); und sei(); um das "Abholen" der im Interrupt veränderbaren Variablen legen.

    Was gewinnst du hierbei?
    Du koppelst die Rechenzeit komplett aus den Interruptfunktionen aus. Dein Timer wird nun ohne Probleme seinen Interrupt in kürzester Zeit, ohne Verlust von weiteren anstehenden Interrupts, abarbeiten können.
    ==> Auch die im Timer-ISR hängende Funktion "Auslesen des ADC/Sharp" solltest du so auslagern.


    ---- Ding 2
    Da wird es bei deiner Geschwindigkeitsreglung schon schwieriger.
    Im Asuro werden die Rad-Tiks bzw. die Differenz zwischen ihnen mit nur einem Regler bearbeitet.
    Du müsstest 'im Prinzip' eine mittlere Geschwindigkeit regeln und das Ergebnis entsprechend deinen Vorgaben für die rechte bzw. linke Seite verteilen.
    Ein anderer Ansatz wäre z.B., dass du doch anfängst zu lügen, wie schon mal in diesem Beitrag angedeutet wurde.


    Ich hoffe, nicht allzu viel Verwirrung gestiftet zu haben
    Gruß
    Sternthaler

    P.S: Deine 'klau schau wem'-Aktion hast du gut umgesetzt. Ein bisschen verwirrend ist, dass du die Kp- und Ki-Parameter mit einer Division verrechnest. Ist zwar hier mathematisch i.O., aber eigendlich sollte da das '*'-en hin. Ansonsten musst du jedesmal in 1/K[parameter] denken.
    Lieber Asuro programieren als arbeiten gehen.

  7. #167
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.653
    Hallo Sternthaler, hallo Mitleser,

    Zitat Zitat von Sternthaler
    ... Ich denke, dass die Rechenzeit für Problem 1) an der falschen Stelle verbraucht wird ...
    Danke Sternthaler für Deine Analyse. Ich werde Deine Ratschläge zu Ding1 einarbeiten, aber bitte nicht gleich - ich freu mich momentan, dass es momentan recht gut läuft. Im Übrigen ist mir klar: es sind nicht nur zwei Dinge die nicht richtig gehen. Dabei bin ich relativ stolz darauf - gewesen - , dass ich auch mal nested Interrupts habe. Oder auch nicht. Es stimmt ja schon, ich hatte garnicht daran gedacht, dass die 100 RegelungsHertzen im main locker in einer Schleife geschafft werden können. Aber ich werde wohl beim Regelungsaufruf erstmal ein Flag setzen, dann die aktuelle Abstandsdauer zwischen zwei Interrupts auslesen und in eine geeignete Variable kopieren. Den Hinweis auf die char-u.ä.-Variablen konnte ich nicht befolgen, weil ich dann auf Interruptabstände unter 0,12 s begrenzt wäre - 255*50µs. Hängt also schon mit den ursprünglichen Auslegungswerten bei Adam und Eva zusammen. Die zu ändern führt aber zu dem bekannten Rattenschwanz.

    Zitat Zitat von Sternthaler
    ... Du koppelst die Rechenzeit komplett aus den Interruptfunktionen aus ...
    Kurz und bündig: wird gemacht.

    Zitat Zitat von Sternthaler
    ... Ding 2 ... wird ... bei deiner Geschwindigkeitsreglung schon schwieriger ...
    Ich fürchte eben, dass eine Aufteilung wie beim asuro bei meinen relativ kleinen und schwachen Motoren Schwierigkeiten macht. Aber ich kann in dieser Richtung mal ein bisschen Gehirn anstrengen. Ich überlege sowieso seit einiger Zeit die Geschwindigkeitsvorgabe nur für einen Motor herzunehmen und den anderen über eine entsprechend korrigierte Vorgabe mitzuschleppen (auf diese Vorgabe wird er dann geregelt), die den jeweiligen Krümmungsradius berücksichtigt. Leider ist sowohl der Krümmungsradius als auch die Krümmung einer Geraden oder Beinahe-Geraden ein etwas unhandlicher Wert . . . . . Aber ich werde dazu schon noch ne Lösung finden.

    Zitat Zitat von Sternthaler
    ... Ich hoffe, nicht allzu viel Verwirrung gestiftet zu haben ...
    Nein, keine Bange. Noch bin ich nicht in einem Alter, in dem ich allzu leicht verwirrt werde. Und wenn ich das mal bin, dann werde ich es vermutlich garnicht merken *gggg*.

    Zitat Zitat von Sternthaler
    ... Deine 'klau schau wem'-Aktion hast du gut umgesetzt. Ein bisschen verwirrend ist ... Parameter mit einer Division verrechnest ...
    Danke für das Lob. Zur Division: es ist halt so, dass die Integer-Division durch 30 mit Sicherheit schneller ist, als eine Real-Multiplikation mit 0,03333, und die recht gute Regelungsfunktion zeigt ja, dass der Regler mit ganzen Zahlen gut zurecht kommt.

    Im Übrigen habe ich einen erheblichen Anteil an dem ursprünglich festgestellten Versatz des Fahrzeugs bei Kreis-Verkehr-Tests auf die Vorzugsrichtung der Fasern des Florteppichs zurückführen können.
    Ciao sagt der JoeamBerg

  8. #168
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Hallo Dosenfans,

    hier einiges zum letzten Beitrag von oberallgeier.


    Zitat Zitat von oberallgeier
    ... Den Hinweis auf die char-u.ä.-Variablen konnte ich nicht befolgen, weil ich dann auf Interruptabstände unter 0,12 s begrenzt wäre - 255*50µs.
    Das war auch nicht so gemeint das du auf Bytes runter gehen sollst.
    Code:
    /* Irgendwo an der richtigen Stelle */
    volatile int interrupt_var;
    
    /* Im Interrupt */
    {
       ...
       interrupt_var = sin (interrupt_var) mod sternthalerzeit;
       /* oder was einfacheres ;-) */
       interrupt_var++;
       ...
    }
    
    /* In der Funktion ausserhalb vom Interrupt */
    {
       ...
       int lokale_var;
    
       /*
          Verhindern, dass ein eventuell auftretender Interrupt
          die Variable aendern kann beim folgenden Auslesen von
          interrupt_var
       */
       cli ();
    
       lokale_var = interrupt_var;
       interrupt_var = 0;  /* natuerlich nur bei Bedarf */
    
       /*
          Und die Interrupts wieder zulassen.
          Die Zeit, in der die Interrupts nicht aufgerufen werden,
          beschraenkt sich auf einige Taktzyklen. Es geht aber keine
          Interruptanforderung verloren. Nach dem sei() wird ein
          anstehender INT sofort bedient.
       */
       sei ();
       ...
    }
    Zitat Zitat von oberallgeier
    ... ursprünglichen Auslegungswerten bei Adam und Eva ...
    Ist deshalb eben nicht notwendig.


    Zitat Zitat von oberallgeier
    Ich überlege sowieso seit einiger Zeit die Geschwindigkeitsvorgabe nur für einen Motor herzunehmen und den anderen über eine entsprechend korrigierte Vorgabe mitzuschleppen (auf diese Vorgabe wird er dann geregelt), ...
    Upps. Und genau hier wird dann wieder ein zweiter Regler ins Spiel kommen.
    Einer hält die Geschwindigkeitsvorgabe, und der zweite Regler muss sich um die Anpassung der anderen Radseite kümmern, wenn Differenzen auszugleichen sind.


    Zitat Zitat von oberallgeier
    ... Krümmungsradius berücksichtigt.
    Da schaust du hier beim EXCEL, wenn du Radiusvorgaben in Tiks umrechnen möchtest. OK, sind keine Geschwindigkeiten enthalten, aber das geht komplett über Geometrie und reduziert sich auf einfache Mathematik.
    Bestimmt lässt sich auf diesem Weg auch ein Bogen mit Radius- und Winkelvorgaben in Geschwindigkeiten der beiden Räder umrechnen.


    Zitat Zitat von oberallgeier
    Danke für das Lob.
    Ehre, wem Ehre gebührt.


    Zitat Zitat von oberallgeier
    Im Übrigen habe ich einen erheblichen Anteil an dem ursprünglich festgestellten Versatz des Fahrzeugs bei Kreis-Verkehr-Tests auf die Vorzugsrichtung der Fasern des Florteppichs zurückführen können.
    Und warum sind dann die Startprobleme auch auf der Hartfaserplatte zu sehen? (Keine Killerfragen bitte )


    Und schon ist es wieder über meinem selbst gesetzten 1:00 Uhr Limit ;-(
    Gruß Sternthaler
    Lieber Asuro programieren als arbeiten gehen.

  9. #169
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.653
    Hallo,

    oder eher Hilfe. Manchmal (ver)zweifle ich einfach an ... allem.

    Der Verdacht: offensichtlich hat eine Art Pest an meinen 3 mega168 auf drei verschiedenen Platinen die ADCs vernichtet.

    Das Problem: ein Sharp GP2D120 soll mit dem ADC3 des mega168 eingelesen werden. Mittlerweile geht es nur um den 10bittigen ADC-Wert. Aber es läuft einfach nicht, weder auf der einen, noch auf anderen Platinen. Allerdings kann ich auf einer kleinen Tiny13-Experimentierplatine vom Sharp mit dem ADC sinnvolle Spannungswerte einlesen. Ausserdem ist das Vo-Signal des Sharp, gemessen mit dem Multimeter, sinnvoll mit dem Abstand korreliert. Auch Messungen direkt am Portpin PC3/ADC3 des Mega168 mit dem Multimeter zeigen, dass die entsprechende Spannung ankommt (als Test auf Falschverdrahtung). Controller wie immer mit 20 MHz getaktet.

    Mit dieser Initialisierung werden die Portpins definiert:
    Code:
      DDRC  = 0b01110000;   // PC3 ist ADC3, PC0 .. 6 , kein PC7-Pin bei m168
      PORTC = 0b00000111;   // Beachte für ADC: PC3 ist ADC-Eingang ##>> OHNE Pullup !!
                            // 
    /* Dadurch Initialisierung der Anschlüsse für miniD0 : - - - - - - - - - - - - - -
               /RESET,PC6   1 A   A 28   PC5,(SCL), gLED
                  RxD,PD0   2 EU  A 27   PC4,(SDA), rLED
                  TxD,PD1___3 EU  E 26___PC3, ADC3=GP2D120
    Und so wird der ADC initialisiert, anschliessend der Auszug der Testversion (main) mit dem der ADC etwa im Sekundentakt gelesen wird:
    Code:
    // =================================================================================
    /* ===  Initialisierung fuer ADC    mega168    OHNE Interrupt  =====================
       ADC3/PC3 mit 10 Bit, Wandlung "auf Abruf",  es wird kein Interrupt ausgelöst   */
    void ADC3_10_init(void)         //
    {	                        // Referenz Selection Bit1..0 = 00 =>
                                    //   AREF, Internal Vref turned off       doc S 254                                  
      ADMUX   |=   (1<<MUX1)|(1<<MUX0);       // Wandlung mit ADC3 
      ADCSRA  |=   (1<<ADEN);       // AD Enable
      ADCSRA  |=   (1<<ADSC);       // starte erste Wandlung                                  
    }                                         
    // =================================================================================
    
    
    // =================================================================================
    // ===  HAUPTProgramm ==============================================================
    
    //   Hier irgendwo die oben zitierten Portinitialisierungen
    //     und der Aufruf der ADC-Initialisierung
    ....
    
    ....
    
      uint16_t igpd = 324;              
    
    .....
    
      igpd        = ADC;            
      ADCSRA     |= (1<<ADSC);    // starte nächste Wandlung
      utoa(igpd, wortc, 10);      //aktuellen Sharp-/ADC-Messwert ...
      waitms ( 1000);               
    
    ....
    Als Ergebnis wird (auf drei verschiedenen Controllern) immer 1023 ausgegeben. Testweise wurde auch die Variable igpd mit 324 belegt. Wird nun der ADC ausgelesen, bevor igpd gesandt wird, steht 1023 da. Wird der ADC nicht ausgelesen, steht 324. Ein anderer Test bestand darin, den Portpin PC3 direkt mit Vcc und alternativ mit GND zu verbinden. Ergebnis ist immer 1023. Diese Stöpselei wurde notwendig, da die Messwerte der Ausleseroutine mit Interrupt ebenso 1023 waren. In früheren Protokollen gefundenen Ergebnisse zeigen aber, dass es mal funktionierte . . . .

    Mittlerweile weiss ich nicht mehr weiter und bitte um Hilfe.

    Nachtrag: AREF ist mit Vcc verbunden, AVCC liegt mit 10 µH an VCC und mit 100 nF an GND.
    Ciao sagt der JoeamBerg

  10. #170
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Hallo oberallgeier,

    wahrscheinlich wird es nicht helfen was jetzt kommt, aber man kann ja nie wissen.

    Das im Register ADCSRA steckende Bit ADIF ist ein 'Schweinebit'. Laut Doku zum ATmega8, Kapitel "ADC Control and Status Register A – ADCSRA" muss man das Bit setzen um es zu löschen.
    ...
    ADIF is cleared by writing a logical one to the flag. Beware that if doing a Read-Modify-Write on ADCSRA, a pending interrupt can be disabled. This also applies if the SBI and CBI instructions are used.
    ...
    Dieses "Read-Modify-Write" macht man automatisch mit einem |= Befehl.

    Da dein HAUPTProgramm-Ablauf ja wohl eine Schleife ist, solltest du darin mal nach weiteren |= suchen. Eventuell ist ein Register dabei, welches auch den ADC beeinflusst.
    Ein Kandidat wäre noch ein löschen vom ADEN-Bit, da es die Wandlung sofort abbricht und möglicherweise dann mit deinen 1023 zurückkommt.

    Ansonsten kann ich so nichts Falsches feststellen.
    Ob nun die Schweinepest auf die AVR's überspringen kann, möchte ich hier aber mangels biologischer Vorbildung nicht sagen.

    Gruß Sternthaler
    P.S.: Zum Thema „setzen zum löschen“ von Registerbits gibt es in einem Thread im ASURO-Teil eine recht ausführliche Diskussion. Den Beitrag kann ich aber leider auch nach zig Stunden Suche nicht mehr finden.
    Lieber Asuro programieren als arbeiten gehen.

Seite 17 von 25 ErsteErste ... 71516171819 ... LetzteLetzte

Berechtigungen

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

LiFePO4 Speicher Test