-         
RSS-Feed anzeigen

Searcher

Die ersten Beschleunigungsmessungen. ..

Bewerten
Das Schreiben des Meßprogramms hat mich doch ganz schön mitgenommen und belasse es nun bei einer Version. Eigentlich hatte es schon recht schnell in den ersten Versionen funktioniert. Es waren jedoch in der Umsetzung der Meßergebnisse in einen Chart seltsame Zacken in der Kurve zu sehen, die von einem Strich zum anderen größere Geschwindigkeitsunterschiede darstellten. Da die Zacken immer an der gleichen Stelle waren, dachte ich weniger an Meßungenauigkeiten als an einen Fehler bei Timings im Programm und versuchte diese durch verschiedene Strukturierungen auszumerzen.

Gelang nicht und weitere Versuche zeigten dann, daß es an winzigen, mit bloßem Auge kaum zu sehenden Unterschieden der Striche im ausgedruckten Zebrastreifen liegt. Ist einfach zu testen, wenn man das Ergebnis kennt, indem man die Meßfahrt einfach nochmal in entgegengesetzter Richtung auf dem Streifen wiederholt. Das Streifenmuster wurde auf zwei verschiedenen DIN A4 Blättern ausgedruckt und zusammengeklebt. Sieht so aus, als wenn der Tintenstrahldruckervorschub beim zweiten Blatt ungleichmäßiger als beim ersten war. Vielleicht setzt auch nur der CNY70 ab der Klebestelle rythmisch auf - Muß ich sowieso nochmal umbauen.

Als Herausforderung beim Meßprogramm empfand ich folgende, mir selbst abgenötigte Voraussetzungen:

1. Die Meßmethode: TT fährt als Linienfolger über eine Linie und tastet zum Messen Streckenmarken auf der Linie ab.

2. Durch schon vorhandenen Aufbau gab es nur noch einen freien PIN am ATtiny45, nämlich den PB0 zum Anschluß des Streckenmarkensensors, bestehend aus CNY70 mit nachgeschaltetem Schmitttrigger. Wenn ich das Datenblatt richtig intepretiert habe, läßt sich auf PB0 weder ADC noch Analog Comparator noch flankengetriggerter Interrupt wie INT0 so einfach für diese Aufgabe im TT nutzen. Also Pollen oder Pin Change Interrupt.

3. Die Meßdaten sollten im EEPROM gespeichert werden. Ein Schreibzugriff dauert lt. Datenblatt 1,8ms und könnte Messungen stärker verfälschen. (Hier bin ich mir unsicher und hab sicherheitshalber das Schreiben in den eeprom während der Messfahrt in den letzten Programmversionen vermieden).

4. Der Tiny45 besitzt nur zwei 8bit Timer. Davon wird Timer0 in BASCOM von GetRC5, also IR Fernbedienungsempfang, der unbedingt beibehalten werden sollte, benutzt. Durch die BASCOM Funktion ist der Timer0 für mich unkalkulierbar und wird nicht weiter verwendet. Die Meßfahrt wird mit der FB gestartet und während der Fahrt der FB Empfang nicht verwendet. Gestoppt wird nach Erfassung aller Streckenmarken; 100 Stck, jeweils im Abstand von 0,5cm.

5. Ungelöst: Dis erste Messung bei Start aus dem Stand bis erste Streckenmarke ist zur Beschleunigungsmessung aus dem Stand unbrauchbar weil ich den TT nie gleichmäßig genau auf einen Startpunkt von Meßfahrt zu Meßfahrt ausgerichtet bekomme. Da sollte ich mir noch eine Startbox basteln.


Der grobe Ablauf des Programms ist in etwa:

1. Initialisierungen wie Timer- und ADC-Einstellungen.

2. Schleife zur Abfrage für Fernbedienungsstartbefehl.

3. ISR Zeiteinheiten hochzählen: Ist Startbefehl gekommen, der die Fahrtgeschwindigkeit beinhaltet, wird Timer1 Overflow Interrupt eingeschaltet.Timer1 wurde bei Initialisierung für PWM Freq. von 8kHz konfiguriert und erzeugt somit alle 125µs einen OVF Interrupt.Die ISR zu diesem Interrupt zählt eine Word Variable (0..65535) als Time_Tick hoch(hab leider keinen 16bit Timer auf'm Tiny45 gefunden).

4. ISR Linienfolgen: Außerdem wird in der Time_tick ISR die ADC Messung der Liniensensoren gestartet. Ist die ADC Messung beendet, erzeugt der ADC einen Interrupt und in der ADC ISR werden dann die Motore mit der PWM eingestellt. Der ADC braucht 13 ADC-Takt Takte für eine Messung. Durch den Prescaler ist der ADC-Takt auf 62500Hz eingestellt. Somit ist eine Messung nach 208µs beendet, also länger als bis zum nächsten Messung startenden Timer1 Overflow Interrupt. Dadurch wird eine ADC Messung nur bei jedem zweiten Timer1 Overflow gestartet, also mit 4kHz. Das ist ausreichend schnell um auf der Meßstrecke zu bleiben und ist auch mit der Time_Tick-ISR synchronisiert, um dort möglichst wenig Verfälschung wg. "gleichzeitig" auftretenden Interrupts zu bekommen. Die ADC Messung ist also nach 208µs beendet und bis zum Start einer neuen Messung bei 250µs (Periodendauer bei 4kHz) verbleiben rund 42µs für Rücksprung und die PWM ISR. Bei 8MHz Systemtakt und den paar Instruktionen sollte das kein Problem sein? Den Haupteil dieser ISR könnte man auch in der Hauptschleife laufen lassen, da er nicht so zeitkritisch ist - denke ich. Werd das vielleicht nochmal im Simulator überprüfen.

5. ISR Meßwertaufnahme: Kriegen die Motore PWM können dann Impulse vom Streckenmeßsensor eintreffen. Die ISR vom PCINT des Streckensensors schreibt den ersten und jeden weiteren zweiten Time_Tick als Meßwert in ein array. Nur jedes zweite Mal, da bei Überfahren einer Linie beide Helligkeitsübergänge/Flanken einen Interrupt auslösen (der schwarze Strich ist schmaler als der weiße Zwischenraum).

6. Meßwerte sichern: Wenn 100 Meßwerte aufgenommen wurden, werden die Motore gestoppt und die Meßwerte noch ins eeprom übertragen.

Code im 1. Kommentar, da der Blogeintragplatz mal wieder zu klein geworden ist

Zur Nachbereitung der Messungen lese ich den eeprom mit der BASCOM IDE aus, speichere sie in eine .eep Datei. Setze die Werte mit einem kleinen Hilfsprogramm für EXCEL lesbar in eine .csv Datei um und brüte dann über den dargestellbaren Charts.

Wofür das gut ist? Weis noch nicht. Vielleicht als Druckerblattvorschubtester

Einige Meßergebnisse mit Chart als EXCEL sheet im ZIP Anhang.

Bitte Fehlschlüsse, Verirrungen kommentieren oder einfach nur Anmerkungen dalassen. Vielen Dank.
Miniaturansichten angehängter Grafiken Angehängte Dateien

"Die ersten Beschleunigungsmessungen. .." bei Twitter speichern "Die ersten Beschleunigungsmessungen. .." bei Facebook speichern "Die ersten Beschleunigungsmessungen. .." bei Mister Wong speichern "Die ersten Beschleunigungsmessungen. .." bei YiGG.de speichern "Die ersten Beschleunigungsmessungen. .." bei Google speichern "Die ersten Beschleunigungsmessungen. .." bei del.icio.us speichern "Die ersten Beschleunigungsmessungen. .." bei Webnews speichern "Die ersten Beschleunigungsmessungen. .." bei My Yahoo speichern

Stichworte: - Stichworte bearbeiten
Kategorien
Projekte , ATtiny45 , Root , Linienfolger

Kommentare

  1. Avatar von Searcher
    Hier noch der hingefrickelte Code

    Code:
    '###############################################################################
    'File: Messprogramm_08.bas
    '
    'Funktionen:
    'Meßprogramm zum Abfahren einer geraden weißen Meßstrecke mit 100 schwarzen Strichen
    'Die Striche sind im Abstand von 0,5cm aufgetragen und werden von einem CNY70 abgetastet
    'Die verstrichenen Zeiteinheiten seit Start werden für jeden Strich im eeprom gesichert
    'Nachbereitung der Meßwerte in externen Programmen auf PC
    'Linienfolgefunktion sorgt für das Nichtabweichen von der Meßstrecke
    'Meßfahrt wird mit RC5 Infrarotfernbedienung gestartet und nach Zählen von 100 Strichen gestoppt
    '
    'IDE: BASCOM-AVR Demoversion 1.11.9.8
    '
    'HW circuit: Linienfolger_mit_FB.aac plus angeflanschtem CNY70 mit Schmittrigger an PB0
    'Timer1 für PWM Erzeugung, Timeticks und Start der ADC Messungen für Linienfolgung
    'TSOP für FB an PB3. BASCOM Kommando Getrc5 nutzt Timer0 !!!
    '###############################################################################
    
    $regfile = "attiny45.dat"
    $eepleave
    $framesize = 4
    $swstack = 4
    $hwstack = 34
    $crystal = 8000000
    $lib "mcsbyteint.lbx"                   'only byte and word operations
    
    Dim Address As Byte , Command As Byte   'variables for getrc5
    
    Dim Sr_tick(101) As Word                'Zwischenspeicher für Meßwerte
    Dim Ee_tick(101) As Eram Word At &H02   'eeprom Speicher wird am Ende der Meßfahrt gefüllt
    
    Dim Time_tick As Word
    Dim Toggle_bit As Bit
    
    Dim Index As Byte
    
    Dim Average_speed As Byte
    Average_speed = 0                       'Durchschittsgeschwindigkeit mit 0 initialisieren
    
    Dim Adc_low As Byte                     'variable for adc result
    
    Config Portb = Input                    'ports initialisieren
    Portb = Portb Or &H1F                   'ports mit pullups auf definierten Pegel
    
    Config Rc5 = Pinb.3                     'TSOP at PB3
    Config Portb.4 = Output                 'PB4 as output, OC1B, MotorX
    Config Portb.1 = Output                 'PB1 as output, OC1A, MotorY
    
    Tccr1 = Tccr1 Or &B01100000             'set PWM1A & OC1A (PB1)
    Gtccr = Gtccr Or &B01100000             'set PWM1B & OC1B (PB4) clear TCNT1 on OCR1C match
    Ocr1a = 0                               'initialise OCR1A -> low, no pulses at OC1A
    Ocr1b = 0                               'initialise OCR1B -> low, no pulses at OC1B
    Ocr1c = 249                             'set pwm frq. 8Mhz / 4 / (249 + 1)= 8kHz
    Tccr1 = Tccr1 Or &B00000011             'Einschalten TIMER1 - prescaler = 4
    
    Didr0 = &B00110100                      'ADC power save PB2,4,5. PB3 (TSOP) nicht abschalten
    Admux = &B10101011                      '1,1V internal reference, ADLAR=1 (left adjusted), PB5 PB2 gain 20
    Adcsrb.7 = 1                            'bipolar mode
    
    Adcsra = Adcsra Or &B00001111           'ADC Int. enable, ADC prescaler auf 128 (62500Hz at 8MHz systemclock)
                                            'Messung braucht 13 Takte -> 13 * 16µs = 208µs
    Adcsra.7 = 1                            'turn on ADC
    
    Pcmsk.pcint3 = 1                        'Pin Change Interrupt PCINT3 auf Pin PB3 für FB TSOP erlauben
    Enable Pcint0                           'Pin Change Interrupts erlauben
    
    On Adc Adcmessung_to_pwm                'Wenn ADC Messung fertig -> Interrupt zum PWM Tastverh. setzen
    On Pcint0 Get_time_tick                 'Zeitnahme wenn Pin Change Interrupt vom CNY70
    On Ovf1 Set_time_tick                   'Timer1 Overflow INT -> ISR zum Timeticks hochzählen
    
    Enable Interrupts                       'Interrupts generell erlauben
    
    
    Do                                      'Hauptschleife
       While Pcmsk.pcint0 <> 1              'Schleife für Startbefehl von Fernbedienung,
                                            'nur wenn PCINT auf PB0 für CNY70 NICHT zugelassen
          Getrc5(address , Command)         'procedure returns FF FF if no RC5 message
          If Address <> &HFF Then           'RC5 Nachricht empfangen then...
             Command = Command And &B01111111       'toggle bit auf Null
             Select Case Command
                Case &H1D : Average_speed = 0       'stop bei home taste
                            Tccr1 = Tccr1 And &B11011111       'OC1A (PB1) output abschalten
                            Gtccr = Gtccr And &B11011111       'OC1B (PB4) output abschalten
                            Portb.1 = 0     'OC1A auf low (Motor abschalten)
                            Portb.4 = 0     'OC1B auf low (Motor abschalten)
                            Ocr1a = 0
                            Ocr1b = 0
                Case &H01 : Average_speed = 60       'verschiedene Fahrstufen
                Case &H02 : Average_speed = 70
                Case &H03 : Average_speed = 80
                Case &H04 : Average_speed = 100
                Case &H05 : Average_speed = 120
                Case &H06 : Average_speed = 140
                Case &H07 : Average_speed = 160
                Case &H08 : Average_speed = 180
                Case &H09 : Average_speed = 200
             End Select
             If Average_speed <> 0 Then     'FB Befehl zum Losfahren/Messen erkannt
                Incr Index
                Time_tick = &HFF00 + Average_speed       'Fahrstufe mit highbyte HFF versehen
                Sr_tick(index) = Time_tick  'Fahrstufe speichern
                Time_tick = 0
                Pcmsk.pcint3 = 0            'Disable weitere interrupts von FB TSOP an PB3
                Pcmsk.pcint0 = 1            'Enable Interrupts vom CNY70 an PB0
                Tccr1 = Tccr1 Or &B01100000 'set PWM1A & OC1A (PB1) -Motor an PWM Generator anschalten
                Gtccr = Gtccr Or &B01100000 'set PWM1B & OC1B (PB4) clear TCNT1 on OCR1C match, Motor an PWM-Gen.
                Enable Ovf1                 'Timer1 Overflow Int enable (8kHz für Timetick hochz.)
             End If
          End If
       Wend
    
       If Index = 101 Then                  'Teststrecke bewältigt - 100 Striche gezählt plus Fahrstufe gespeichert
          Disable Ovf1
          Average_speed = 0
          Tccr1 = Tccr1 And &B11011111      'OC1A (PB1) output abschalten
          Gtccr = Gtccr And &B11011111      'OC1B (PB4) output abschalten
          Portb.1 = 0                       'OC1A auf low (Motor abschalten)
          Portb.4 = 0                       'OC1B auf low (Motor abschalten)
          Ocr1a = 0
          Ocr1b = 0
          Pcmsk.pcint0 = 0
          Pcmsk.pcint3 = 1
          Time_tick = 0
          Toggle_bit = 0
          For Index = 1 To 101
             Ee_tick(index) = Sr_tick(index)       'sram array zum eeprom array übertragen
          Next Index
          Index = 0
       End If
    Loop
    
    Set_time_tick:                          'wird alle 125µs aufgerufen (8kHz PWM freq.)
       Incr Time_tick                       'Zeiteinheiten hochzählen
       Adcsra.6 = 1                         'ADC Messung für Liniensensoren starten, benötigt ca 208µs
                                            'damit wird eine Messung jeden zweiten ISR Aufruf gestartet
                                            'und somit die PWM zum Lenken mit 4kHz aktualisiert
    Return
    
    
    Adcmessung_to_pwm:                      'ISR f. ADC Auslesen und Setzen der PWM (Aufruf alle 250µs)
       Adc_low = Adch                       'nur 8 bit der Messung nutzen
       If Adc_low.7 = 1 Then                'negativer Wert vom ADC
             Adc_low = Not Adc_low          'umsetzen des 2er Komplements
             Adc_low = Adc_low + 1          'umsetzen des 2er Komplements
             Shift Adc_low , Right , 1      'Trimmen des Meßwertes/Abschneiden Meßschwankungen
             Ocr1a = Average_speed - Adc_low       'PWM Pulsweite setzen
             Ocr1b = Average_speed + Adc_low       'PWM Pulsweite setzen
          Else                              'Meßwert positiv - keine Umwandlung
             Shift Adc_low , Right , 1      'Trimmen
             Ocr1a = Average_speed + Adc_low       'PWM Pulsweite setzen
             Ocr1b = Average_speed - Adc_low       'PWM Pulsweite setzen
       End If
    Return
    
    Get_time_tick:                          'ISR Aufruf durch PCINT
       If Pcmsk.pcint0 = 1 Then             'Gilt nur, wenn CNY70 Interrupt verursacht
          If Toggle_bit = 0 Then            'Nur jeder zweite Interrupt zählt, da PCINT nicht nur bei
                                            'schwarzen Strichen sondern auch bei weißen auftritt
             Incr Index
             If Index = 102 Then Index = 101       'Arrayindexüberlauf verhindern
             Sr_tick(index) = Time_tick     'Zeiteinheit in den Zwischenspeicher
             If Index = 50 Then Average_speed = Average_speed + 40       'Während Fahrt speed erhöhen
          End If
          Toggle Toggle_bit
       End If
    Return
    Gruß
    Searcher