Hi! Bin ein Anfänger der sich vor kurzem entschlossen hat in die µC Programmierung einzusteigen. Habe jede Menge gelesen, noch mehr gelesen und bin gerade dabei auf meinem Breadboard verschiedene "Hallo Welt" Dinge zu probieren wie Led schalten, blinken und so weiter. Für mein Projekt würde ich gerne folgendes tun: 9 Servos sollen mit einer Auflösung von 1µs (750µs - 2250µs) angesteuert werden mit einer Frequenz von mind. 50Hz, also alle 20ms für Analogservos und max. 330Hz für Digitalservos. Auf "Befehl" sollen alle Servos gleichzeitig angesteuert werden und ihre entsprechende Position anfahren bzw. halten. Es gibt eigentlich nur zwei Positionen die die Servos anfahren sollen die zuvor vom Benutzer festgelegt wurden. Im Endausbau soll das folgendes können: Der Benutzer legt für jedes Servo fest welche Start und welche Endposition es hat, immer drei Servos bilden eine Gruppe. Er gibt ein mit welcher Geschwindigkeit sich die Servos in die Endposition bewegen und Wartezeiten zwischen den verschiedenen Gruppen. Die Servos starten alle von der festgelegten Startposition. Auf "Befehl" fahren die ersten drei Servos ihre Endposition an in der festgelegten Geschwindigkeit, festgelegte Pause, die nächsten drei Servos fahren in die eingestellte Endposition. Im Moment scheitere ich daran die Auflösung von 1µs zu realisieren. Bei 16Mhz Takt vergehen in 1µs gerade mal 16Takte. Was ich schon geschafft habe ist eine Fast-PWM mit einer Frequenz von 2,250ms wo ich die Servos hintereinander ansteuere und somit bei 9 Servos ca. 50Hz für jedes Servo hinbekomme bei einer Auflösung von 1µs. Aber so schaffe ich keine 330Hz und die Servos starten nicht gleichzeitig. Wie könnte ich das was ich vorhabe realisieren? Die PWM-Threads und Artikel hier habe ich schon gelesen aber die schaffen nur eine Auflösung von 255 Schritten. (Wenn ich keines übersehen habe). Irgendwelche Tipps oder Ideen dazu? Achja, im Moment programmiere ich das ganze mit einem ATmega8. LG PuraVida
Mann macht es ja auch nicht mit PWM (auch wenn das immer wieder mal empfohlen wird.... Nimm den Timer1, getaktet mit 1MHz=1µs. CTC, Top on OCR1A, OCR1A laden mit 20000=20ms; Kommt der OCR1A-Interrupt, PIN für Servo1 einschalten. OCR1B mit dem Servowert für Servo1 laden. OCR1B-Interrupt: PIN1 auschalten, PIN2 einschalten, OCR1B mit dem Wert von Servo1+Servo2 laden usw
Die Servos können eh keine auflösung von 1µs also warum sich darüber den Kopf zerbrechen.
H.joachim Seifert schrieb: > Mann macht es ja auch nicht mit PWM (auch wenn das immer wieder mal > empfohlen wird.... > Nimm den Timer1, getaktet mit 1MHz=1µs. > CTC, Top on OCR1A, OCR1A laden mit 20000=20ms; > Kommt der OCR1A-Interrupt, PIN für Servo1 einschalten. > OCR1B mit dem Servowert für Servo1 laden. > > OCR1B-Interrupt: > PIN1 auschalten, PIN2 einschalten, OCR1B mit dem Wert von Servo1+Servo2 > laden > usw Hi Joachim! Danke für Deine Antwort! Ich mache meine derzeitige Lösung eh mit Timer. Und sie funktioniert so ähnlich wie Deine Idee/Lösung. Das Ergebnis an den Pins ist halt eine PWM. Aber ich nutze nicht die PWM-Funktionalität des AVR. Die von Dir geschilderte Variante läßt leider nur 50Hz Ansteuerung zu . Ich möchte aber mit 330Hz die Servos ansteuern können, also eine Pulswiederholung von alle ca. 3ms erreichen. Dazu müssen die Servopins alle gleichzeitig auf High gehen. Und der letzte spätestens nach 2,25ms auf Low. Und nach 3ms beginnt der nächste Zyklus. LG PuraVida
Uwe schrieb: > Die Servos können eh keine auflösung von 1µs also warum sich darüber den > Kopf zerbrechen. Hauptsache die Auflösung stimmt. Die Genauigkeit ist unwichtig. :-) Gruss Harald
Ok, das mit den Digitalservos hatte ich überlesen...
Der ATmega2560 hat 12 PWMs mit 16Bit, damit gehts. Peter
Und da sind wir wiedermal beim STM32... STM32F101 für ca. 3€, 5 Timer mit je 4 OC-Einheiten. Da kann der Mega2560 nicht anstinken.
Peter Dannegger schrieb: > Der ATmega2560 hat 12 PWMs mit 16Bit, damit gehts. > > > Peter Hi Peter! Danke für den Tipp! Wobei der mit seinen 86 I/O Leitungen und 100Pins ein bisl oversized ist. gg
Dann anders gefragt. Auf wie viel Auflösung müßte ich wohl verzichten wenn ich mittels Timer eine 3ms Frequenz einrichte, bei BOTTOM alle Servopins auf High setze und dann durch auslesen des Timers die Pins schön langsam auf Low setze sobald der Zählerwert dem µs Wert des Servos entspricht? Bzw. der Vorschlag von Joachim den OCR1B Wert innerhalb der 3 ms immer weiter nach oben verschiebe. Oder wäre es besser einen Timer mit z. Bsp. 3µs einzurichten und in der ISR Zähler mitlaufen zu lassen die einerseits mal alle Servopins auf High setzen und dann bei Match Zählerwert - Servowert den entsprechenden Servopin auf Low zu setzen? LG
Mit nem XMega ist das ein Kinderspiel ;-) Grüße, Michael
H.joachim Seifert schrieb: > STM32F101 für ca. 3€, 5 Timer mit je 4 OC-Einheiten. Da kann der > Mega2560 nicht anstinken. Muß er ja nicht, alles >= 9 PWM-Ausgänge erfüllt die Aufgabe. Und auf den Preis des MC achte ich auch nicht, der verschwindet völlig in den andere Kosten, schon eine Platine ist ja deutlich teurer. Ich bin mir auch nicht sicher, ob für den STM32 2 Lagen reichen oder es schon 4 Lagen sein müssen. Bei hohen Frequenzen wird das ja kritischer. Und auch die Spannungsversorgung muß stabiler sein, 1,8..5,5V Weitbereich, wie beim AVR, mag der bestimmt nicht. Peter
Michael K. schrieb: > Mit nem XMega ist das ein Kinderspiel ;-) Hi Michael, das kann ich mir gut vorstellen. g Es ist halt so, daß ich ein Neueinsteiger in die Materie bin und nicht nur, daß ich noch nie Mikrocontroller programmiert habe muß ich auch noch C lernen parallel dazu. Ich habe zwar ein wenig Erfahrung in VB und auch ein Elektronik-Grundwissen aber trotzdem ist alles sehr neu für mich. Also wollte ich mal mit einfachen Dingen anfangen die ich auf einem Breadboard zusammenstoppeln kann. Und da so Dinge machen wie Servos ansteuern, Sensoren auslesen, Motore ansteuern... Für AVR habe ich mich deshalb entschieden weil es viele Infos dazu gibt, viele damit arbeiten und so der Einstieg hoffentlich leichter fällt. (Google glüht :-) ) Nachdem es die XMega nicht im DIL Gehäuse gibt und ich mich noch nicht darum gekümmert habe ob man die in irgend eine Adapterplatine stecken kann die man dann am Breadboard verwenden kann habe ich die XMega im Moment noch gar nicht angedacht. LG
Die Frage ist doch eher, braucht der TO zum einen eine Widerholrate von 3ms? Nur weil der Servo das theoretisch verarbeiten kann heisst das noch lange nicht daß das sinnvoll ist. Vor allem notwendig für das Problem, das gelöst werden soll. Die 2. Frage: Was will der TO mit einer Auflösung von 3000 Werten (1µs bei ca. 3 ms Widerholrate) Welcher Servo kann auch nur 1000 Punkte auflösen? Wahrscheinlich ist die Positioniergenauigkeit weniger als 1% also würden 100 Punkte schon reichen. Ist aber wie so oft: Man braucht gleich die eierlegende Wollmilchsau mit einer Auflösung von weniger als 0,03% und das dann am besten mit Bauteilen die 5% Fehler haben können.
> Die Frage ist doch eher, braucht der TO zum einen eine Widerholrate von > 3ms? Nur weil der Servo das theoretisch verarbeiten kann heisst das noch > lange nicht daß das sinnvoll ist. Vor allem notwendig für das Problem, > das gelöst werden soll. > Die 2. Frage: Was will der TO mit einer Auflösung von 3000 Werten (1µs > bei ca. 3 ms Widerholrate) Welcher Servo kann auch nur 1000 Punkte > auflösen? Wahrscheinlich ist die Positioniergenauigkeit weniger als 1% > also würden 100 Punkte schon reichen. > Ist aber wie so oft: Man braucht gleich die eierlegende Wollmilchsau mit > einer Auflösung von weniger als 0,03% und das dann am besten mit > Bauteilen die 5% Fehler haben können. Eben. Zwar will er nur 1501 Positionen (2250-750), aber auch das liegt weit über der möglichen Präzision von üblichen Servos, mit 10us käme er locker immer noch auf 150 und damit besser als 1% und damt besser als jeder Modellbauservo hin. Normalerweise ist es auch bei einem uC ohne TPU mit nur einem Timer ganz einfach: Man baut eine Tabelle mit den verschiedenen Zeitpunkten und den dann gültigen neuen Portzuständen struct { int when; int ports; } events[20]; int next=0; und sorgt in einer vom Timer aufgerufenen Interruptroutine void timer(void) { TMR+=events[next].when; PORT=events[next].ports; next++; if(timer[events[next].when=0) next=0; } aber das benötigt auch in Assembler ein paar Takte und damit sind die kürzest möglichen Zeitabstände länger als 1us (aber nicht länger als 10us). Durch die künstlichen sinnlos hochgeschraubten Vorgaben des OP ruiniert er sich so einfache Möglichkeiten, und sucht sich nun den Wolf. Lösen könnte man es ohne Interrupts, aber dazu müsste er virtuos programmieren können. while(1) { PORT=-1; // 750 us was sinnvolles tun for(i=750;i<=2250;i++) // Schleife in Assembler genau auf 1us { PORT=events[next].ports; next+=events[next].when==i; } // bis 3ms was nützliches tun }
@UR Schmitt: Es kommt darauf an was man als "Aufgabe" sieht. Es haben ja schon mehrere auf die Stellgenauigkeit der Servos hingewiesen und ob die denn so genau auflösen. Hier wäre zum Beispiel ein Servo der mit 4096 Schritten auflöst. http://www.heliflightcenter.com/HSD65001_Align_DS650_Digital_Servo_p/hsd65001.htm Dann gibt es eine Reihe von Servos die mit 560Hz (1,8ms) angesteuert werden die ich sowieso ausklammere bei meinem Problem. Mir ist schon klar, daß ich mir bei Analogservos keine Gedanken machen muß um eine Auflösung von 1µs. Die haben wahrscheinlich schon eine Hysterese von 5µs. Im Moment kann ich 9 Servos ansteuern mit einer Auflösung von 1µs und ca. 50Hz. Für das was ich bauen möchte reicht das ansolut. So gesehen wäre die "Aufgabe" erfüllt. Die eigentliche "Aufgabe" wäre aber nicht erfüllt. Nämlich programmieren zu lernen und µC sehr gut kennen zu lernen. Was bekommt man hin mit einem ATmega8? Gibt es Tricks doch das geforderte rauszukitzeln? Auf welche Auflösung müßte man zurück gehen wenn 330Hz erfüllt sein sollen? Mit welchen µC würde man die Aufgabenstellung umsetzen können? Wie muß programmiert werden das möglichst wenige Zyklen verbraten werden? Etc. etc. Wenn ich dazu Tipps bekommen könnte (z. Bsp, wie sehr müßte ich die Auflösung reduzieren um doch mit 330Hz anzusteuern), dann wäre mir sehr geholfen. LG
PuraVida schrieb: > Wobei der mit seinen 86 I/O Leitungen und 100Pins ein bisl oversized > ist. gg Das selbe trifft allerdings vermutlich auch auf die 330 Hz Refresh-Rate zu. Oder wie schnell sind deine Motoren in den Servos.
Danke MaWin! Das hilft mir unheimlich weiter auch wenn ich das
1 | struct { int when; int ports; } events[20]; int next=0; |
2 | |
3 | und sorgt in einer vom Timer aufgerufenen Interruptroutine |
4 | |
5 | void timer(void) |
6 | { |
7 | TMR+=events[next].when; |
8 | PORT=events[next].ports; |
9 | next++; |
10 | if(timer[events[next].when=0) next=0; |
11 | } |
noch überhaupt nicht durchschaue. :-)) Und Du hast recht, ich suche mir schon einen Wolf die letzten Tage. Nur ist das für mich (im Moment) keine verlorene Zeit sondern ich habe unheimlich viel dazugelernt in diesen Tagen. Ich habe schon vermutet, daß meine Anforderung mit dem mega8 so wahrscheinlich nicht umzusetzen ist. Und deshalb auch gefragt ob es nicht doch geht. (und es könnte gehen wenn ich virtuos programmieren könnte g) bzw. gibt es einen Ansatz der nahezu meine Anforderungen erfüllt. Bzw. die Lösung mit einem anderen Prozessor. Hätte ich mich mit meiner/einer einfachen Lösung zufrieden gegeben hätte ich bei weitem nicht so viel profitiert. Nochmals vielen Dank für Deine Vorschläge! LG
PuraVida schrieb: > Hier wäre zum Beispiel ein Servo der mit 4096 Schritten auflöst. Aha; dann nimm doch ein analoges Servo. Das hat die Auflösung unendlich. :-) [ ] Du kennst den Unterschied zwischen Auflösung und Genauigkeit? Es gibt zwar Antriebe, die mit einer Genauigkeit von einigen Winkelsekunden positionieren können. Die liegen preislich aber sicherlich über 1000€. Ein Modellbauservo gehört aber eindeutig nicht in diese Klasse. Gruss Harald
Harald Wilhelms schrieb: > PuraVida schrieb: > >> Hier wäre zum Beispiel ein Servo der mit 4096 Schritten auflöst. > > Aha; dann nimm doch ein analoges Servo. Das hat die Auflösung unendlich. > :-) gg > > [ ] Du kennst den Unterschied zwischen Auflösung und Genauigkeit? > > Es gibt zwar Antriebe, die mit einer Genauigkeit von einigen > Winkelsekunden positionieren können. Die liegen preislich aber > sicherlich über 1000€. Ein Modellbauservo gehört aber eindeutig > nicht in diese Klasse. Hi Harald, ich glaube, ich weiß worauf Du hinaus willst. Es gibt hier: http://members.aon.at/flug.fiala/servo.html einen schon älteren Test von Servos. Und er kommt bei diesem Test auf 2250 Schritte für ca. 135°. Es sollte also mit einem guten Servo eine Genauigkeit von 0,1° real zu schaffen sein wenn ich mit 1µs auflöse. Oder habe ich da wo einen Gedankenfehler? LG Ernst
MaWin schrieb: > Normalerweise ist es auch bei einem uC ohne TPU mit nur einem Timer ganz > einfach: Man baut eine Tabelle mit den verschiedenen Zeitpunkten und den > dann gültigen neuen Portzuständen > > struct { int when; int ports; } events[20]; int next=0; > > und sorgt in einer vom Timer aufgerufenen Interruptroutine > > void timer(void) > { > TMR+=events[next].when; > PORT=events[next].ports; > next++; > if(timer[events[next].when=0) next=0; > } > Mawin, kannst Du, oder wer anderer mit diesen Code ein bisl näher erläutern? Ich versuche mal zu erläutern wie ich es verstehe (und was ich noch nicht verstehe): Ich baue ein struct mit der Strukturvariablen, bzw. ist es ja ein Array events. Darin sind die int Variablen when (wann der Port ein bzw. ausgeschaltet werden soll - oder ist das nur wann er ausgeschaltet werden soll weil ich bei Timer==0 sowieso alle nötigen Ports gleichzeitig einschalte? Aber wo bzw. wann würde ich das? Also nehme ich mal an, daß da der Einschaltwert und Ausschaltwert des Ports rein kommt.) und der Zustand des Ports zu dem Zeitpunkt. struct { int when; int port; } events[20]; dann eine Zählervariable next int next=0; Dann füllen wir die Tabelle events[0].when=0; events[0].port= PORTA |= (1<<PA0); //geht das so? :-/ events[1].when=0; events[1].port=PORTA |= (1<<PA1); events[2].when=1500; events[2].port=PORTA &= ~(1<<PA0); //Pin0 von Port A wieder auf Low events[3].when=1550; events[3].port=PORTA &= ~(1<<PA1); //mal nur mit zwei Servos zwecks Prinzip Aber jetzt beginnen meine Probleme. Wann wird der Timerinterrupt aufgerufen? Von wo bis wohin soll der Zählen? Ich nehme mal an, ein 3ms Timer und der Interrupt wird bei BOTTOM aufgerufen? Dann: TMR += events[next].when; uff??... ich nehme mal an, TMR ist das Timerregister mit dem aktuellen Zählerstand. Warum wird da der when-Wert dazuaddiert? Wird dadurch ein neuer Timerwert geschrieben? Was ist der Sinn dieser Zeile? Gut, dann ist es wieder einfacher, der Portpin wird auf High gesetzt. PORTA = events[next].port; Sollte ich aber mehr als einen Port brauchen muß ich in die Tabelle auch noch die Ports aufnehmen, oder? Weil Port = events[next].port; wird ja nicht funktionieren? Dann wird die Zählervariable um 1 erhöht next++; Und die if Zeile verstehe ich schon wieder nicht. Bzw. die Bedingung. Aber das hängt wohl mit obigen zusammen weil ich das wesentliche wohl noch nicht durchschaue. if(timer[events[next].when=0) next=0; Was macht oder wofür steht das Wort timer da drinnen? Wäre wirklich super wenn mir da jemand von Euch helfen kann Licht in mein Dunkel zu bringen. Und bitte nicht lachen, für Euch ist das sicher super easy. LG Ernst
> events[0].when=0; > events[0].port= PORTA |= (1<<PA0); //geht das so? :-/ > events[1].when=0; > events[1].port=PORTA |= (1<<PA1); Nein. Es sind alle 9 Portausgänge gleichzeitig in ports. Da der AVR ein 8 bit Prozessor ist, müsste man maximal 2 Ports versorgen: PORTA=LOBYTE(events[1].ports) PORTB=HIBYTE(events[1].ports) Beispiel für den Inhalt des Strukturarrays event, wenn ein Servo 1m, der zweite 1.5ms und der dritte 2ms haben soll: struct { int when; int ports; } events[]= { {1000, (1<<PA2)|(1<<PA1)|(1<<PA0)}, // alle auf 1, dann 1ms warten { 500, (1<<PA2)|(1<<PA1)|(0<<PA0)}, { 500, (1<<PA2)|(0<<PA1)|(0<<PA0)}, {1000, (0<<PA2)|(0<<PA1)|(0<<PA0)}, // alle auf 0, dann bis insgesamt 3ms warten { 0, 0} // von vorne }
>virtuos programmieren können.
Was ist das?
Matthias Lipinsky schrieb: >>virtuos programmieren können. > > Was ist das? Siehe hier: http://de.wikipedia.org/wiki/Der_Virtuos Gruss Harald
PuraVida schrieb: > Hier wäre zum Beispiel ein Servo der mit 4096 Schritten auflöst. > > http://www.heliflightcenter.com/HSD65001_Align_DS6... [ ] Du kennst den Unterschied zwischen Marketing Aussagen und der Realität? Ich wette mit dir daß 6 von 8 Weltmeister im Modellhelifliegen ohne diesen Servo Weltmeister geworden sind. Und daß du in den nächsten 10Jahren so gut fliegst daß der Servo zu einem normalen analogen guten Servo irgendeinen Unterschied macht. Alleine die Mechanik nach dem Servo hat wahrscheinlich schon 1% Linearitäts und Lose-Fehler. PuraVida schrieb: > Die eigentliche "Aufgabe" wäre aber nicht erfüllt. Nämlich programmieren > zu lernen und µC sehr gut kennen zu lernen. Was bekommt man hin mit > einem ATmega8? Gibt es Tricks doch das geforderte rauszukitzeln? Auf > welche Auflösung müßte man zurück gehen wenn 330Hz erfüllt sein sollen? > Mit welchen µC würde man die Aufgabenstellung umsetzen können? Wie muß > programmiert werden das möglichst wenige Zyklen verbraten werden? Etc. > etc. Und PuraVida schrieb: > Danke MaWin! Das hilft mir unheimlich weiter auch wenn ich das > noch überhaupt nicht durchschaue. :-)) Du willst den 4. Schritt vor dem ersten machen! Krieg erst mal hin einen Servo sauber anzusteuern (mit 50Hz Widerholrate), dann 2, dann 4. Dann kriege hin Ablaufsteuerungen einzubauen, mit parametriesierbaren Rampen usw. Dann versuche es mit schnelleren Widerholraten und größerer Auflösung. Wer alles auf einmal will scheitert grandios. Richtig gut programmieren zu lernen ist ein Prozess, der Jahre in Anspruch nimmt (bei 40h Beschäftigung pro Woche mit dem Thema)!
UR Schmitt schrieb: > Ich wette mit dir daß 6 von 8 Weltmeister im Modellhelifliegen ohne > diesen Servo Weltmeister geworden sind. Und die andere zwei haben das Servo nur benutzzt, weil der Sponsor das so wollte. Die hätten auch mit jedem anderen Servo gewonnen. Ansonsten gibt es zum Thema Servoansteuerung (auch per AVR) eigentlich nichts, was nicht schon mal geschrieben wurde. google liefert da problemlos nächteweise Lesestoff, Source codes, und Anwendungsbeispiele. Oliver
Hi MaWin, vielen Dank für Deine Mühe mir zu helfen! MaWin schrieb: > Nein. Es sind alle 9 Portausgänge gleichzeitig in ports. > > Da der AVR ein 8 bit Prozessor ist, müsste man maximal 2 Ports > versorgen: > > PORTA=LOBYTE(events[1].ports) > PORTB=HIBYTE(events[1].ports) Hey, lässig... wenn ich so zuweise dann ist PB0 mein HIBYTE, oder? {1000, (1<<PB0)|(1<<PA7)|(1<<PA6)(1<<PA5)|(1<<PA4)|(1<<PA3)(1<<PA2)|(1<<PA1)|(1 <<PA0)}, > > Beispiel für den Inhalt des Strukturarrays event, wenn ein Servo 1m, der > zweite 1.5ms und der dritte 2ms haben soll: > > struct { int when; int ports; } events[]= > { > {1000, (1<<PA2)|(1<<PA1)|(1<<PA0)}, // alle auf 1, dann 1ms warten > { 500, (1<<PA2)|(1<<PA1)|(0<<PA0)}, > { 500, (1<<PA2)|(0<<PA1)|(0<<PA0)}, > {1000, (0<<PA2)|(0<<PA1)|(0<<PA0)}, // alle auf 0, dann bis insgesamt > 3ms warten > { 0, 0} // von vorne > } Ah, ich glaube, jetzt habe ich es endlich verstanden. D. h. ich muß die Servowerte (die ich ja nicht kenne sondern vom User eingegeben werden) mal sortieren und dann jeweils die Differenzen bilden und in der Strukturvariablen ablegen. Na, dann mache ich mich mal auf die Suche wie man sortiert und das am besten löst... Vielen Dank nochmals für die Hilfe. Werde später mal meinen Code reinstellen wenn er soweit fertig ist. LG Ernst
> PB0 mein HIBYTE, oder? > {1000, > (1<<PB0)|(1<<PA7)|( Nein, eher > (0x100<<PB0)|(1<<PA7)|( oder die Struct anpassen struct { int when; int portabits,portbbits; } events[]= {1000, (1<<PA7)|(1<<PA6)|(1<<PA5)|(1<<PA4)|(1<<PA3)|(1<<PA2)|(1<<PA1)|(1<<PA0), (1<<PB7)|(1<<PB6)|(1<<PB5)|(1<<PB4)|(1<<PB3)|(1<<PB2)|(1<<PB1)|(1<<PB0) }
Hallo, hier hast du die fertige Lösung: http://code.google.com/p/oradiocontrol/source/browse/trunk/ORadioControl/rx/src/ORC_rx.c Das Programm lässt sich leicht auf 9 Kanäle erweitern, da es eh schon 2 Ports benutzt. Erst wird sortiert und dann der Timer programmiert. Bei kleinen Abständen werden nop's verwendet, bei großen wird der Timer verwendet. Auflösung bei 8MHz mit atmega88 ist 1µs. Gruß Josef
Servus Josef! Vielen Dank den Link mit mir zu teilen, werde ich mir gleich anschauen. Wäre ja cool wenn dort alles gelöst ist. Ich zermartere mir ja schon seit Tagen meinen Kopf wie man das am besten löst. :-)) 1µs bei 8Mhz finde ich ja sehr beachtlich. Ich habe inzwischen auch weiterüberlegt und geschaut und bin auch über eine Funktion gestoßen die bei 16Mhz genau 0,625µs braucht und beliebig skalierbar ist. Da wird auch mit nop gearbeitet. LG Ernst
Also Josef... ich bin schwer beeindruckt! Und wie ich sehe/denke ist der Code wohl von Dir. Bist also auch ein Modellbauer. Mein Projekt ist ja viel einfacher und wie weiter vorne schon beschrieben, wären eigentlich 3ms und 1µs nicht unbedingt notwendig um das eigentliche zu lösen. Denn ich möchte mal einen Door-Sequencer bauen der meine Ansprüche erfüllt. Und der würde es natürlich mit Analogservos die alle 20ms angesprochen werden mehr als ausreichend tun. Aber meine Gedanken gehen auch jetzt schon in die Richtung mal sowas zu machen wie Dein Code scheinbar macht und da wollte ich eben gleich entsprechende Werte realisieren. Auch wenn das bei einem Door-Sequencer echt nicht notwendig ist. Ich fürchte allerdings, daß ich mir selbst was einfallen lassen muß, ich denke, Deinen Code zu durchschauen übersteigt meine momentanen Fähigkeiten sowas zu lesen. :-(( Um den Code anzupassen müsstest Du mich schon an der Hand nehmen wie ein kleines Kind und mich da durch führen. Und das möchte ich Dir auch nicht antun. :-)) Auf jeden Fall ist die Seite schon gebookmarkt! Danke nochmals! LG Ernst
Hallo Ernst, es stimmt, die Software ist von mir. So richtig anfängertauglich ist es nicht, das ist klar. Dein Problem ist es aber auch nicht -) Das ganze funktioniert über 2 Ausgaben (highGroup, lowGroup) hintereinander a 4 Kanäle. Die Funktion die, die Daten aufbereitet und alle Ausgänge setzt heißt: setupPulses. Das Abschalten der Kanäle wird in der Interruptroutine (TIMER1_COMPA_vect) abhängig von der Pulsdauer erledigt. Wenn du nur 3ms Zeit hast, müssen alle 9 Känale auf einmal ausgegeben werden. Dazu setupPulses und den Timerinterrupt auf 9 Kanäle erweitern. In der Interruptroutine könnte es knifflig werden, weil c1,d1,c2,d2,c3,d3,c4,d4 Registervariable sein müssen. Du brauchst statt 8 18 Variable. Da deine CPU aber doppelt so schnell ist, könnte man auch die Struktur direkt lesen. Das ganze habe ich mit dem Simulator auf den Takt genau ausgemessen. Wenn du änderst, bleibt dir das auch nicht erspart. Gruß Josef
Ich habe beschlossen das Projekt zweizuteilen. Hätte nicht erwartet, daß sich die µs als so Trickreich herausstellt. Einerseits werde ich den Door-Sequencer verfolgen. Da reicht es wenn Analogservos dran kommen und dann ist das ganze nimmer so tricky weil ja Zeit genug da das auch sequentiell abzuarbeiten. Und parallel dazu verfolge ich die Lösung für Digitalservos. Da habe ich mir gedacht, ich könnte was programmtechnisch nicht so elegantes machen was aber relativ einfach scheint - in der Theorie zumindest: Ich schalte alle Servoausgänge gleichzeitig auf high, habe dann mind. 750µs Zeit für irgendwas und drehe dann die einzelnen Servosausgänge auf LOW mit nop's dazwischen. Das bedeutet max. Blockierung vom IC für 1,5ms. Wobei ich mir bei Dir - Josef - anschauen muß wie Du differenziert hast zwischen nop oder differenz so groß, daß Timer auch reicht. Und dann sind wieder 750µs Zeit für irgendwas. Aber programmtechnisch elegant ist wohl anders... :-))
Ein STM32 ist jetzt zwar nicht Anfängertauglich, daher will ich den jetzt nicht empfehlen, da ich den gut kenne rechne ich einfach mal das Beispiel vor (geht sicher auch mit einem XMega ähnlich). Timer Clock mit 36MHz geht an den Prescaler mit Wert 4 auf den PWM Timer. Somit läuft der PWM Timer mit 8MHz = 0,125µS Der Timer hat eine Auflösung von 16 Bit, dort wird die Grenze auf 24000 eingestellt = 3ms / 330Hz. Als PWM Schwelle kann nun ein Wert zwischen 6000 ... 18000 (750..2250µS) eingestellt werden. Somit hat man einen exakten PWM, 0,125µS Auflösung. Und noch was: Die Summe aller Fehler addiert sich aus den einzelnen Fehlern, daher sollte jedes einzelne Bauteil so geringe wie mögliche Fehler haben, nur so lässt sich die Summe aller Fehler reduzieren. Wenn man jetzt eine µC Schaltung mit 0,5% + ein Servo mit 0,5% Fehlerrate hat, dann sind das schon bis zu 1%. Daher ist es hilfreich eine Schaltung zu haben, die die Fehlerrate nicht extra erhöht. Falls doch der STM32 (kein DIL Gehäuse!) interessant ist, hier der Artikel STM32 und es gibt Borad-Hersteller die für kleines Geld eine Steckbrettaugliche Platine liefern.
Hi zusammen! So, ich bin also dabei mein Programm zusammen zu stöpseln. Jetzt bin ich beim debuggen auf ein - für mich - komisches verhalten gestossen. Folgenden Code habe ich:
1 | #ifndef F_CPU //setzen der CPU-Geschwindigkeit falls nicht gesetzt
|
2 | #define F_CPU 16000000UL
|
3 | #endif
|
4 | |
5 | |
6 | #include <avr/io.h> |
7 | #include <avr/interrupt.h> |
8 | #include <stdlib.h> |
9 | #include <stdio.h> |
10 | |
11 | #define SERVOANZAHL 9
|
12 | |
13 | volatile struct serv_o{ |
14 | int when; |
15 | int port; |
16 | } servos_open[SERVOANZAHL]; |
17 | |
18 | volatile struct serv_c{ |
19 | int when; |
20 | int port; |
21 | } servos_closed[SERVOANZAHL]; |
22 | |
23 | volatile uint8_t i; // i als 8 Bit Variable deklarieren |
24 | volatile uint8_t j; |
25 | volatile uint8_t oeffnen; //oeffen = 1 bei Fahrwerk ausfahren, oeffnen = 0 bei Fahrwerk einfahren |
26 | |
27 | int main(void) |
28 | {
|
29 | servos_open[0].when = 1500; |
30 | servos_open[0].port = PC0; |
31 | servos_open[1].when = 1550; |
32 | servos_open[1].port = PC0; |
33 | servos_open[2].when = 2000; |
34 | servos_open[2].port = PC0; |
35 | servos_open[3].when = 2100; |
36 | servos_open[3].port = PC0; |
37 | servos_open[4].when = 1666; |
38 | servos_open[4].port = PC0; |
39 | servos_open[5].when = 1167; |
40 | servos_open[5].port = PC0; |
41 | servos_open[6].when = 1400; |
42 | servos_open[6].port = PC0; |
43 | servos_open[7].when = 1900; |
44 | servos_open[7].port = PC0; |
45 | servos_open[8].when = 1950; |
46 | servos_open[8].port = PC0; |
47 | |
48 | servos_closed[0].when = 1000; |
49 | servos_closed[0].port = PC0; |
50 | servos_closed[1].when = 1400; |
51 | servos_closed[1].port = PC0; |
52 | servos_closed[2].when = 1320; |
53 | servos_closed[2].port = PC0; |
54 | servos_closed[3].when = 999; |
55 | servos_closed[3].port = PC0; |
56 | servos_closed[4].when = 1255; |
57 | servos_closed[4].port = PC0; |
58 | servos_closed[5].when = 1345; |
59 | servos_closed[5].port = PC0; |
60 | servos_closed[6].when = 1350; |
61 | servos_closed[6].port = PC0; |
62 | servos_closed[7].when = 1299; |
63 | servos_closed[7].port = PC0; |
64 | servos_closed[8].when = 1199; |
65 | servos_closed[8].port = PC0; |
66 | |
67 | |
68 | Bubble(servos_open, SERVOANZAHL); |
69 | Bubble(servos_closed, SERVOANZAHL); |
70 | |
71 | |
72 | DDRC |= (1<<PC3 | 1<<PC4 | 1<<PC5 | 1<<PC0); // Port C, Pin 3, 4 & 5 auf Ausgang schalten |
73 | TCCR1A |= (1<<WGM10 | 1<<WGM11); // WGM10 bis WGM13 auf 1 für Fast PWM mit Top OCR1A |
74 | TCCR1B |= (1<<WGM12 | 1<<WGM13); // |
75 | TCCR1B |= (1<<CS11); // Prescaler auf 8 setzen |
76 | TIMSK |= (1<<TOIE1 | 1<<OCIE1A | 1<< OCIE1B); // Interrupt Flags maskieren für Overflow, Output Compare A, Output Compare B |
77 | OCR1A = 40000; // TOP-Wert auf 20ms |
78 | j=0; |
79 | i=1; |
80 | if (oeffnen==1) //ersten OCR1B Wert setzen je nachdem ob Fahrwerk offen oder zu |
81 | {
|
82 | OCR1B = servos_open[j].when; |
83 | }
|
84 | else
|
85 | {
|
86 | OCR1B = servos_closed[j].when; |
87 | }
|
88 | |
89 | |
90 | sei(); |
91 | |
92 | |
93 | while(1) |
94 | {
|
95 | //TODO:: Please write your application code
|
96 | //PORTC |= (1<<PC5);
|
97 | }
|
98 | }
|
99 | |
100 | void Bubble(struct serv_o *sort, int elemente){ |
101 | int k; |
102 | struct serv_o *temp; |
103 | //temp = malloc(sizeof(struct serv_o *));
|
104 | |
105 | while(elemente--) |
106 | for(k=1; k<=elemente; k++) |
107 | if (sort[k-1].when > sort[k].when) |
108 | {
|
109 | *temp = sort[k]; |
110 | sort[k] = sort[k-1]; |
111 | sort[k-1] = *temp; |
112 | |
113 | }
|
114 | |
115 | }
|
Die Zeile die mich vor rätseln stellt ist folgende: "j=0;" in Main. Wenn ich die Variable überwache beim debuggen, dann ist ihr Wert nach der Zeile mit der Wertzuweisung nicht 0 sondern 4. Woher kommt das? Soweit ich mir das bisher angelesen habe werden Variablen bei der Deklaration nicht initialisiert. Mit Ausnahme von volatile-Variablen die - soweit nichts anderes angegeben - mit 0 initialisiert werden bei der Deklaration. Wieso sollte es aber stören trotzdem nochmals j=0; zuzuweisen? Es geht auch noch weiter, wenn ich j bei der Definition volatile uint8_t j=10; definiere dann sehe ich im Überwachungsfenster auch den Wert 10 für j. Nach der Zeile j=0; erhält die Variable aber den Wert 4. Wieso ist das so? uint8_t geht doch von 0 bis 255, oder? LG Ernst
Ich vermute, die Variable fällt der Optimierung zum Opfer. Denn du nutzt sie ja nicht. Ja. Im Array-Index. Aber sonst nirgends. Also kann als Array-Index auf direkt ne Null stehen, was der Compiler vermutlich tut.
Matthias Lipinsky schrieb: > Ich vermute, die Variable fällt der Optimierung zum Opfer. Denn du nutzt > sie ja nicht. > > Ja. Im Array-Index. Aber sonst nirgends. Also kann als Array-Index auf > direkt ne Null stehen, was der Compiler vermutlich tut. Auch ohne Optimierung ändert sich da leider nix. Die Variable wird ja leider nicht unter den Tisch gefallen gelassen sondern sie bekommt den Wert 4. Was dann im struct-Index ganz falsch ist. Wenn ich den Aufruf meiner Bubble-Sort Funktion auskommentiere dann funktioniert auch die j und i Variable und sie läßt sich auf 0 setzen. Das muß also irgendwie zusammenhängen. Aber ich habe keine Idee wo ich da ansetzen soll... :-(( Oder ist das ein Debug-Problem vom AVR-Studio 5? Ich denke aber eher nicht... LG Ernst EDITH sagt: Ich glaube, ich habe jetzt den Fehler gefunden. Wenn ich Speicherbereich mit malloc für den Pointer reserviere und dann wieder freigebe dann funktionieren auch die i und j Variablen. Dabei dachte ich hier irgendwo gelesen zu haben, daß man sich das malloc sparen kann?
Nur bekomme ich jetzt zwei Warnungen und einen Error: Warning 1 implicit declaration of function 'Bubble' Warning 2 conflicting types for 'Bubble' Error 3 previous implicit declaration of 'Bubble' was here Uff... muß mal schauen was das wieder heißen soll...
Ernst B. schrieb: > Dabei dachte ich hier irgendwo gelesen zu haben, daß man sich das malloc > sparen kann? Wieso sollte? Was bringt es überhaupt, dynamischen Speicher zu verwenden? Entweder der µC hat ihn, oder nicht. Dann kann man den auch gleich statisch deklarieren.
Ernst B. schrieb: > Nur bekomme ich jetzt zwei Warnungen und einen Error: > > Warning 1 implicit declaration of function 'Bubble' > Warning 2 conflicting types for 'Bubble' > Error 3 previous implicit declaration of 'Bubble' was here > > Uff... muß mal schauen was das wieder heißen soll... So, das waren also die fehlenden Funktionsdeklarationen. Soweit so gut. Jetzt habe ich ja in meinem Programm zwei structs drinnen.
1 | struct serv_o{ |
2 | int when; |
3 | int port; |
4 | } servos_open[SERVOANZAHL]; |
5 | |
6 | struct serv_c{ |
7 | int when; |
8 | int port; |
9 | } servos_closed[SERVOANZAHL]; |
Wenn ich jetzt eine Funktionsdeklaration schreibe die wie folgt ausschaut void Bubble(struct serv_o *sort, int elemente) beschwert sich der Compiler wenn ich meine Funktionsaufrufe mache: Bubble(servos_open, SERVOANZAHL); Bubble(servos_closed, SERVOANZAHL); weil er meint, er erwartet serv_o aber bekommt serv_c geliefert. Wenn ich zwei Bubble Funktionen schreibe für je ein Struct funktioniert das ohne Warnungen oder Fehler. Aber das ist ja blöd denn ich verschenke ja Platz mit der zweiten Funktion die genau so sortiert wie die erste und die Structs sind auch gleich groß. Das kann man sicher besser lösen, oder? @Michael: Ich dachte, da man den Platz ja nur braucht während sortiert wird wäre es nicht sinnvoll den dauerhaft zu reservieren? Aber ich muß eh gestehen, mir ist nicht klar warum es ohne malloc nicht funktioniert hat und jetzt schon. Trotz C-Bücher stochere ich oft im dunkeln herum...
Okay, das mit der Funktiondeklaration habe ich auch hinbekommen. Ich sehe schon, ich zermartere mir den Kopf, schreibe dann nach langem Zögern hier rein und dann plötzlich die Idee! :-)) Aber ich schreibe sicher lieber nix mehr, ich langweile sicher mit meinen Kinderfragen... LG Ernst
struct serv_o { int when; int port; } ... und struct serv_c { int when; int port; } ... Was ist der Unterschied?
Ernst, du brauchst ein C Buch. Man lernt eine komplexe Sprache wie C nicht indem man nur trial and error macht und kopiert. Man muss die Grundlagen LERNEN! Das ist nicht so wie eine Doktorarbeit in Jura schreiben.
Du langweilst nicht, keine Angst, ich sitzt seit 'ner guten Stunde hier und grübel... Ich hab eine Servosteuerung mit einer nahezu beliebigen (für alle praktischen Anwendungen...) Auflösung geschrieben, allerdings scheitert die an Deiner Aufgabenstellung insofern, als sie erstens ins ASM ist und zweitens die Servos sequentiell und nicht parallel schaltet (und damit eben die bereits beanstandeten 50Hz liefert). 330Hz bedeutet, dass ein Schaltcycle 3ms dauert, was angesichts der üblichen Ansteuerfrequenz von Servos schon recht sportlich ist. Lass mich das Problem mal zerlegen. So wie Du schreibst ist von Anfang an klar, welche Start- und Endposition die Servos haben werden. Ist das korrekt? Weil dann könnte man die Sortiererei vor dem Einschalten der Servos bereits abhandeln und es würde nicht in den zeitkritischen Teil fallen. Die Auflösung auf eine Mikrosekunde sollte auch mit einem Atmega8 möglich sein, 8-16 Instruktionen sollten reichen. Wir müssen ja darin nicht die Welt bewegen, sondern nur 1-3 Servos ein- oder ausschalten. Wird eng, aber sollt sich realisieren lassen. Wär eine Auflösung von 2microsecs denkbar? 16-32 Instruktionen sollten hinreichend sein. Oder fragen wir anders: Was wär die niedrigste, akzeptable Auflösung? Und was muss da sonst noch rein, viel sollt's definitiv nicht sein!
Matthias Lipinsky schrieb: > struct serv_o > { > int when; > int port; > } ... > > und > > struct serv_c > { > int when; > int port; > } ... > > > Was ist der Unterschied? Ursprünglich waren sie für folgendes vorgesehen: Die Servos haben einen Start und einen Endwert - und wieder retour. serv_o war für open gedacht, serv_c für closed. Beide Positionswerte in ein struct wollte ich nicht schreiben da ich die Werte ja sortieren muß und sich die Ansteuerung auch überschneidet. Werden soll das ja ein Door-Sequencer für Modellflugzeuge. Da gibt es Modelle, da ist das Fahrwerk hinter Klappen versteckt, manchmal sogar zwei Klappen für ein Fahrwerk. Es muß also zuerst die Klappe aufgehen - kurze Pause - und dann erst die Räder ausfahren. (Je nach Modell kann man dann die Klappen sogar wieder zu machen obwohl die Räder heraussen sind - ist aber noch kein Ziel von mir). Und umgekehrt muß natürlich das Rad zuerst einklappen - Pause - Klappe zu. Die Pause und die Geschwindigkeit in der die Klappen/Räder ausklappen/einklappen soll einstellbar sein. So, das wäre also der Unterschied gewesen. Aber ich habe es dann doch anders gemacht weil es zwei mal zu definieren ja ein Holler ist. Schaut jetzt so aus: struct serv { int when; int port; } servos_open, servos_closed; und ich denke, so paßt das. LG Ernst
Udo Schmitt schrieb: > Ernst, du brauchst ein C Buch. > Man lernt eine komplexe Sprache wie C nicht indem man nur trial and > error macht und kopiert. Man muss die Grundlagen LERNEN! > > Das ist nicht so wie eine Doktorarbeit in Jura schreiben. Hi Udo! Ich habe inzwischen eh ein bisl was dazu. "C von A-Z" und "Programmieren in C". Und da bin ich auch fleissig am lesen. Allerdings kann ich nicht 1000 Seiten durcharbeiten und mein Projekt links liegen lassen. Das bringe ich nicht fertig und so probiere ich halt einiges aus. Die Beispiele in den Büchern beziehen sich auch auf PC-Programmierung in ihren Beispielen. Und eine Datenbank mit Adressen die am Bildschirm ausgegeben wird ist halt nicht so das wahre Beispiel dann. Ja, in Jura kann man mehr labern, da gebe ich Dir recht. Wußtest Du, daß es Menschengruppen insbesondere Soldaten verboten ist in Gleichschritt über Brücken zu gehen? §22 oder §25 dt. Straßenverkehrsordnung, §77 österr. Straßenverkehrsordnung. :-) Also, wie gesagt ich bin auch am lernen. :-D LG Ernst
Heinz L. schrieb: > Du langweilst nicht, keine Angst, ich sitzt seit 'ner guten Stunde hier > und grübel... Oh, da bin ich froh. Ich bin mir schon bewußt, daß da von den Anfängern seit Jahr und Tag die gleichen Fragen kommen. Und man ist dann als alter Hase schon genervt davon. > > Ich hab eine Servosteuerung mit einer nahezu beliebigen (für alle > praktischen Anwendungen...) Auflösung geschrieben, allerdings scheitert > die an Deiner Aufgabenstellung insofern, als sie erstens ins ASM ist und > zweitens die Servos sequentiell und nicht parallel schaltet (und damit > eben die bereits beanstandeten 50Hz liefert). 330Hz bedeutet, dass ein > Schaltcycle 3ms dauert, was angesichts der üblichen Ansteuerfrequenz von > Servos schon recht sportlich ist. Ja, mit ca. 50 Hz habe ich auch recht schnell heraußen gehabt. Wenn man da sequentiell ansteuert hat man eigentlich alle Zeit der Welt. Ich habe es weiter vorne schon mal geschrieben, für den Door-Sequencer brauche ich eigentlich keine 330 Hz. Aber ich würde das gerne gleich so lösen weil ich später noch andere Dinge mit Servos umsetzen möchte. Digitale Servos schaffen eigentlich alle 270Hz und die meisten 330Hz. Es gäbe sogar noch schnellere mit 560Hz aber die habe ich jetzt mal außen vor gelassen. Aber auch das sollte gehen wenn meine Umsetzung so hinhaut wie ich mir das vorstelle. > > Lass mich das Problem mal zerlegen. So wie Du schreibst ist von Anfang > an klar, welche Start- und Endposition die Servos haben werden. Ist das > korrekt? Weil dann könnte man die Sortiererei vor dem Einschalten der > Servos bereits abhandeln und es würde nicht in den zeitkritischen Teil > fallen. Ich habe mir das so vorgestellt. Es gibt wohl eine Anfangs und eine Endposition allerdings kenne ich die nicht. Was in meinem Code-Beispiel drinnen steht sind nur Beispielswerte damit ich mit irgendwas arbeiten kann. Also folgender Plan: µC wird eingeschaltet und als erstes liest er mal die Werte aus dem EEProm. Fürs erste müssen da irgendwelche Werte rein die alle so um die Mittenposition liegen. Dann stellt der User (also eigentlich ich) über Tasten für jedes Servo die wirkliche Start und Endposition ein. Das kann man aber erst machen wenn der µC im Flugmodell zum Einsatz kommt. Dann werden die Werte wieder ins EEProm zurück geschrieben. Die Werte werden sortiert, der Timer gestartet und es geht los. > > Die Auflösung auf eine Mikrosekunde sollte auch mit einem Atmega8 > möglich sein, 8-16 Instruktionen sollten reichen. Wir müssen ja darin > nicht die Welt bewegen, sondern nur 1-3 Servos ein- oder ausschalten. > Wird eng, aber sollt sich realisieren lassen. Wär eine Auflösung von > 2microsecs denkbar? 16-32 Instruktionen sollten hinreichend sein. Oder > fragen wir anders: Was wär die niedrigste, akzeptable Auflösung? Und was > muss da sonst noch rein, viel sollt's definitiv nicht sein! Alle Servos bekommen mal gleichzeitig ein High und nach frühestens 750µs wird der erste ausgeschaltet. Sobald in der sortierten Reihenfolge ca. 5-10µs dazwischen liegen kann man eigentlich den OCR1B Wert leicht auf die neue Position verschieben. Also angenommen 1. Servo 750µs, zweiter Servo 765µs: da wird zuerst OCR1B auf 750 gesetzt, der Interrupt aufgerufen und der 1. Servo wieder ausgeschaltet. Die 10µs lassen dann genug Zeit den OCR1B Wert zu setzen. Aber wie Du schon ansprichst, was, wenn zwei Servos den gleichen Wert hinterlegt haben oder nur wenige µs differenz. Diese Spezialfälle möchte ich dann gerne mit NOP's oder ähnlichem lösen. Dadurch kann ich die Frequenz fast beliebig wählen, nicht nur 330Hz sollten dann möglich sein sondern auch 560Hz. (bei anderen Mittenwerten der Servos) Im Moment ist es nicht so heikel da man für das Fahrwerk sowieso keine super tollen Servos nimmt und deshalb sind es jetzt mal 50Hz. Was Deine Frage betrifft: 2µs sind für diese Spezialfälle sicher auch ok. Ich habe vor kurzem einen Durchschnittsdigitalservo an den µC gehängt und mal getestet welche Schrittweiten ich noch mit dem freien Auge wahrnehmen kann. 3µs sind gut zu sehen. Für mich gibt es noch einiges zu tun: 1. Ich habe mir schon angeschaut wie ich Initialwerte ins EEProm schreibe. Das sollte über die .eep relativ leicht gehen. Was ich aber noch nicht weiß, an welcher Adresse die dann eigentlich liegen. Oder ob ich das Struct einfach mit dem Namen ansprechen kann und mich interessieren Adressen überhaupt nicht. 2. Ich brauche eine Routine mit der der Benutzer die echten Start und Endpositionen einträgt. Dazu brauche ich auch ein Display in irgendeiner Form. Dazu habe ich noch keinen Plan. 3. Ich muß sicherstellen, sollte der Benutzer irgendwann drauf kommen doch wieder einen Wert zu ändern, daß er das nicht in der heißen Phase zwischen 750-2250µs tut. Vorher oder nachher ist egal, da kann man auch den Timer kurz abschalten. Denn wenn verstellt wird ist der Flieger sicher am Boden und nicht in der Luft. 4. Ich muß mir irgendwie merken was der letzte Zustand des Fahrwerkes war. Angenommen, das Fahrwerk war heraußen dann darf beim wiederanstecken des Akkus das Fahrwerk nicht plötzlich einklappen. 5. Die Servos sollen schön langsam in ihre Positionen fahren. Das Fahrwerk soll also schön langsam ausfahren damit das scale-mäßig aussieht. Wie schnell, soll der Benutzer einstellen können. 6. Ich muß einen Port vom Fernsteuerungsempfänger abgreifen damit ich das Fahrwerk dann fernsteuern kann. 7. Folgender Ablauf gehört noch umgesetzt: Schalter an der Fernsteuerung wird umgelegt, 3(6) Servos machen die Fahrwerksklappen auf - Pause (soll der Benutzer festlegen können) - Fahrwerk fährt aus. Und das alles mit der Geschwindigkeit die man gewählt hat. (8. - keine Grundanfoderung im Moment) Es soll irgendwann auch möglich sein: Klappe auf, Fahrwerk raus, Klappe zu. Oder zwei Klappen (pro Fahrwerk) auf - Fahrwerk raus - beide oder eine Klappe wieder zu. Wie man sieht, noch ganz schöne Brocken. Aber ich habe super Spaß daran mich damit zu beschäftigen. Und ich mache auch zwischendurch immer auch mal was anderes - einfacheres - mit dem µC um zu lernen. Wie eben nur ein Servo mal hin und her wandern lassen. Als nächstes ist dann mal LCD ansteuern geplant damit ich mal ein paar Variablen auswerfen kann. Warum ich mir das eigentlich antue hat auch folgenden Grund: Ich habe so einen Door-Sequencer gekauft und der funktioniert so unzufriedenstellend das ich mir gedacht habe, das kann ich besser. Bei dem kann es durchaus sein, daß das Flugzeug auf den Rädern steht, man steckt den Akku an und plötzlich klappt das Fahrwerk ein. Tut weder dem Flugzeug gut noch dem Fahrwerk noch den Servos. Tja, noch genug zu tun wie mir scheint! :-)) Aber die Zeit drängt mich nicht. LG Ernst
Ernst B. schrieb: > Ja, in Jura kann man mehr labern, da gebe ich Dir recht. Wußtest Du, daß > es Menschengruppen insbesondere Soldaten verboten ist in Gleichschritt > über Brücken zu gehen? §22 oder §25 dt. Straßenverkehrsordnung, §77 > österr. Straßenverkehrsordnung. :-) Dafür gibt es ja auch einen sehr sinnvollen praktischen Grund, der in den entsprechenden Gesetzen vermutlich nicht erwähnt wird. :-) Gruss Harald
Harald Wilhelms schrieb: > Ernst B. schrieb: > >> Ja, in Jura kann man mehr labern, da gebe ich Dir recht. Wußtest Du, daß >> es Menschengruppen insbesondere Soldaten verboten ist in Gleichschritt >> über Brücken zu gehen? §22 oder §25 dt. Straßenverkehrsordnung, §77 >> österr. Straßenverkehrsordnung. :-) > > Dafür gibt es ja auch einen sehr sinnvollen praktischen Grund, > der in den entsprechenden Gesetzen vermutlich nicht erwähnt wird. > :-) > Gruss > Harald OT: Ja, den Grund kenne ich natürlich auch. Spannend fand ich, daß das sogar gesetzlich geregelt ist. LG Ernst
Ok, lass mich mal mit den Fragen anfangen. 1. Ömm... eigentlich ja, so ähnlich wie Du auch den SRam ansprichst. Andere Befehle, sonst afaik ident. Der Unterschied ist eigenltich hauptsächlich dass es länger dauert, ich würde das tunlichst NICHT in der zeitkritischen Zeit tun. Die Details möge allerdings bitte jemand mit mehr Erfahrung mit AVR-C posten (Meine Sprache im MC Bereich ist halt ASM). 2. Wie gibt der User die Bereiche denn ein? Darf ich vorschlagen einen Drehimpulsgeber, optimalerweise mit Taster, dann hast genau ein Eingabeteil (drehen links-rechts für mehr-weniger, draufdrücken für "nächste Einstellung"). Das Ding abzugreifen ist nicht so kompliziert, im Endeffekt hast dann eine Routine für Taster und Impulsgeber die ein wenig anders dann nach der Eingabe bearbeitet werden. Für die Ausgabe halt irgendein I2C Display, dafür gibt's hier auch massig code. 3. Dreh's dem User einfach ab? Setz ein Flag wenn die Routine anfängt und lass keine Eingaben zu bis sie abgeschlossen ist, d.h. prüf das Flag vor der Input-Routine und überspring sie einfach wenn es gesetzt ist. Oder wär das nicht gewünscht? 4. DAS ist schon etwas komplizierter. Du müßtest den Zustand des Servos im EEProm speichern, wenn Dir allerdings der User den Saft abdreht bevor Du speicherst hast noch den vorhergehenden Zustand im EEProm. Und ständig in den EEProm schreiben nach jeder Minimaländerung killt Dir den wahrscheinlich innerhalb von wenigen Minuten. Mir fallen im Endeffekt zwei Möglichkeiten ein: a) Ein Sensor, der den Zustand des Fahrwerks prüft und den Servozustand entsprechend "überschreibt" beim Einschalten. b) Dem User klar machen, er darf nur zu sehr bestimmten Momenten (nämlich nachdem der Zustand gesichert ist) den Saft wegnehmen. Don't turn off your XBox while saving. :) Angesichts dessen was auf dem Spiel steht würd ich hier zu einem Sensor raten, damit ABSOLUT sicher ist dass da nix passiert. Einfacher Kontaktsensor sollte reichen. Klappe zu, also Kontakt zwischen Klappe und Rumpf geschlossen -> Fahrwerk drin. Falls nicht -> Fahrwerk draussen. 5. Meine erste Reaktion hier wäre ein (zeitsteuernder) Timer der einfach die Servoposition hochzählt, die Servos werden dann nicht in die eingestellte Position gebracht sondern in die, die der Timer grad vorgibt. Mit den Schuhlöffelvorgaben die hier an Zeit zur Verfügung stehen dürft das allerdings flach fallen. 6. Nachdem der genauso ein PWM Signal liefert wie Du sendest, einfach 'n Pin als Input und messen lassen wie lang der Puls ist. Wenn ich Dich richtig verstehe ist das nur der "Startbefehl", also nicht in der kritischen Zeit, sprich, das was hier im mikrosekundenbereich getimed werden soll läuft vollautomatisch ab, ohne dass der user das währenddessen verändert oder steuert? 7. Ok, jetzt hab ich Dich verstanden. :) Nachdem wir (also, mehr Du und mein Vater) das gleiche Hobby haben dürften, und ich daher zumindest ein klein wenig davon versteh... ist es WIRKLICH so absolut entscheidend wie oft der Servo sein Signal bekommt? Ich weiß nun nicht was Du für Servos verwendest, aber alles ausserhalb des Hochleistungsbereichs in der Pricerange von einigen 100 Euros stellt Dir das ohnehin nicht so genau dass ein Unterschied zwischen 100 und 300 Hz mehr als messbar (sprich, sichtbar) wäre. Sofern Du da nicht 'nen gewaltigen Hebel ansetzt ist das "Ticken" kaum oder gar nicht sichtbar. Im Endeffekt bestimmst Du damit nur, wie häufig der Sensor sein Stellsignal bekommen soll, und sofern das nicht grad ein besagter Servo mit einigen kN Stellkraft und der Stellgeschwindigkeit von nahezu null ist, braucht der ohnehin einiges länger um seine Position einzunehmen als Du stellen könntest. Wenn Du, sagen wir mal, den Servo im Lauf von 5 Sekunden von Anschlag auf Anschlag (sagen wir mal 180°) bringen willst, bewegst Du den Servo bei 50Hz pro Stellvorgang 43 Winkelminuten, 250 Mal, bei 330Hz 6,5 Winkelminuten, 1650 mal. Anders ausgedrückt, Du stellst in 43 Winkelminuten sechsmal statt einmal. Stell mal den Servo mit der Klappe dran 43 Winkelminuten weit und sag mir ob Du ernsthaft einen Unterschied sehen würdest wenn diese Bewegung nicht in einem sondern in sechs Schritten erfolgen würde. Ganz abgesehen von der Schuhlöffelprogrammiererei, bei der Du irgendwann gnadenlos bei ASM landest weil C die Kontrolle über die einzelnen Instruktionen und damit das taktgenaue Timing nicht erlaubt: Der Stromverbrauch ist nämlich bei solchen Stellfrequenzen auch nicht ohne. Selbst wenn der dabei nix stellt brätst Du hier einiges an Strom weg. Und grad beim Fahrwerk würde der dann tatsächlich 90% der Zeit nix stellen aber saugen wie 'n Kamel nach dem Wüstendurchritt, sprich, Du musst dann fast zwangsläufig das Ding in den Schlafmodus schicken, bzw. die Stellfrequenz erheblich runterschrauben während das Fahrwerk eingezogen ist, sonst ist der Akku leer bevor Du den Flug beendet hast. Ok, is' etwas übertrieben, aber es war auch für mich 'n Augenöffner, lass mal das Ampmeter mitlaufen wenn Du einen Servo so behandelst und er dabei nicht mal was stellt. Ich muss Dir allerdings jetzt auch ehrlich gestehen, ich sehe das ultimative Problem der Gleichzeitigkeit nicht mehr. Wir reden hier von einem Zeitunterschied im Bereich von 2ms wenn die Servos sequentiell angesteuert würden. Das ist nicht sichtbar! Ich stelle alle meine Servos sequentiell, und ich müßte ehrlich gestehen, entweder ich bin inzwischen blind oder einfach nur langsam in der Aufnahme, aber ich sehe den Unterschied nicht. Wäre es vielleicht möglich, wenn Du diesen Unterschied bei einem Deiner Versuche sehen konntest, dass ein Programmfehler vorgelegen hat? Wenn Du den Unterschied im Bereich von 0.2 Hunderstel Sekunden sehen kannst, rate ich Dir zu einer Karriere als Wettkampfrichter für Sportarten wo diese Zeiten entscheidend sind. Versteh mich bitte nicht falsch, ich will Dir nicht in Deine Projekt hineinreden, allerdings glaube ich, Du willst hier Genauigkeit die Dir nichts bringt und nur sehr viel Kopfschmerz verursacht.
>Dafür gibt es ja auch einen sehr sinnvollen praktischen Grund, >der in den entsprechenden Gesetzen vermutlich nicht erwähnt wird. >:-) Und einen Namen: Tacoma Narrows Brigde
Matthias Lipinsky schrieb: > Und einen Namen: Tacoma Narrows Brigde Klarer Konstruktionsfehler: Nicht ausreichend bedämpfte Resonanzen der Konstruktion.
Hi Heinz! Sorry, daß ich erst jetzt antworte, ich bin über meinen Programmfehlern gehockt und habe lange die Lösung gesucht. :-/ Heinz L. schrieb: > Ok, lass mich mal mit den Fragen anfangen. > > 1. Ömm... eigentlich ja, so ähnlich wie Du auch den SRam ansprichst. > Andere Befehle, sonst afaik ident. Der Unterschied ist eigenltich > hauptsächlich dass es länger dauert, ich würde das tunlichst NICHT in > der zeitkritischen Zeit tun. Die Details möge allerdings bitte jemand > mit mehr Erfahrung mit AVR-C posten (Meine Sprache im MC Bereich ist > halt ASM). Ja, das ist das was ich unter 3. als "heiße Phase" bezeichnet habe. Da darf der Zugriff auf keinen Fall erfolgen sonst ist alles im Eimer. :-) Na, ich bin gespannt, werde ich demnächst mal probieren. 1. Mal Standardwerte ins EEProm brennen. 2. Auslesen versuchen. > > 2. Wie gibt der User die Bereiche denn ein? Darf ich vorschlagen einen > Drehimpulsgeber, optimalerweise mit Taster, dann hast genau ein > Eingabeteil (drehen links-rechts für mehr-weniger, draufdrücken für > "nächste Einstellung"). Das Ding abzugreifen ist nicht so kompliziert, > im Endeffekt hast dann eine Routine für Taster und Impulsgeber die ein > wenig anders dann nach der Eingabe bearbeitet werden. > Für die Ausgabe halt irgendein I2C Display, dafür gibt's hier auch > massig code. Das ist eine coole Idee. Ursprünglich dachte ich an vier Taster. Zwei um durch die Funktionen zu blättern und zwei um die Werte zu erhöhen oder zu erniedrigen. Die Taster hätte ich gleich auf die Platine zum µC gelötet. Kennst Du die ESC's die man an die Elektromotoren hängt im Modellbau? Die eigentlichen Drehzahlregler für die Motoren. Da sind viele Programmierbar über so kleine extra Programmierkarten. Sowas wäre natürlich auch toll. Wobei ich keine Ahnung habe wie das Funktioniert. Denn die Daten werden nur über einen Pin übertragen. Und noch dazu ist das der Pin der sonst den Gaskanal überträgt vom Empfänger. Das wäre auch noch geil das so zu lösen. Nach Drehimpulsgebern muß ich mal googeln. > > 3. Dreh's dem User einfach ab? Setz ein Flag wenn die Routine anfängt > und lass keine Eingaben zu bis sie abgeschlossen ist, d.h. prüf das Flag > vor der Input-Routine und überspring sie einfach wenn es gesetzt ist. > Oder wär das nicht gewünscht? Das könnte ich machen. Allerdings habe ich ja in dem Fall recht viel Zeit. Der letzte Servo geht nach maximal 2,25ms auf Low. das heißt mir bleiben 17,72ms Zeit irgendwas zu tun. In diesem Fenster könnte man auf Usereingaben reagieren. Und ich denke daran, wenn eine Usereingabe festgestellt wird einfach den Timer abzudrehen und die Servos inzwischen "still" zu legen. > > 4. DAS ist schon etwas komplizierter. Du müßtest den Zustand des Servos > im EEProm speichern, wenn Dir allerdings der User den Saft abdreht bevor > Du speicherst hast noch den vorhergehenden Zustand im EEProm. Und > ständig in den EEProm schreiben nach jeder Minimaländerung killt Dir den > wahrscheinlich innerhalb von wenigen Minuten. Mir fallen im Endeffekt > zwei Möglichkeiten ein: > a) Ein Sensor, der den Zustand des Fahrwerks prüft und den Servozustand > entsprechend "überschreibt" beim Einschalten. > b) Dem User klar machen, er darf nur zu sehr bestimmten Momenten > (nämlich nachdem der Zustand gesichert ist) den Saft wegnehmen. Don't > turn off your XBox while saving. :) > Angesichts dessen was auf dem Spiel steht würd ich hier zu einem Sensor > raten, damit ABSOLUT sicher ist dass da nix passiert. Einfacher > Kontaktsensor sollte reichen. Klappe zu, also Kontakt zwischen Klappe > und Rumpf geschlossen -> Fahrwerk drin. Falls nicht -> Fahrwerk > draussen. Ja, da weiß ich auch noch nicht recht was machen... > > 5. Meine erste Reaktion hier wäre ein (zeitsteuernder) Timer der einfach > die Servoposition hochzählt, die Servos werden dann nicht in die > eingestellte Position gebracht sondern in die, die der Timer grad > vorgibt. Mit den Schuhlöffelvorgaben die hier an Zeit zur Verfügung > stehen dürft das allerdings flach fallen. Zeitlich stelle ich mir das eigentlich nicht so schwierig vor. Ich habe ja das Fenster von 17ms um irgendwas zu machen. Da dachte ich an eine Funktion die ich aufrufe und schön langsam sich dem Zielwert annähert. > > 6. Nachdem der genauso ein PWM Signal liefert wie Du sendest, einfach 'n > Pin als Input und messen lassen wie lang der Puls ist. Wenn ich Dich > richtig verstehe ist das nur der "Startbefehl", also nicht in der > kritischen Zeit, sprich, das was hier im mikrosekundenbereich getimed > werden soll läuft vollautomatisch ab, ohne dass der user das > währenddessen verändert oder steuert? Genau so ist es wie Du sagst. Der User muß da nix im ms Bereich oder so steuern sondern der Fliegt mit seinem Flieger, will landen, und legt einen Schalter um damit das Fahrwerk ausfährt. (Oder umgekehrt nach dem Start, Schalter wird umgelegt und das Fahrwerk fährt ein) > > 7. Ok, jetzt hab ich Dich verstanden. :) > > > Nachdem wir (also, mehr Du und mein Vater) das gleiche Hobby haben > dürften, und ich daher zumindest ein klein wenig davon versteh... ist es > WIRKLICH so absolut entscheidend wie oft der Servo sein Signal bekommt? > Ich weiß nun nicht was Du für Servos verwendest, aber alles ausserhalb > des Hochleistungsbereichs in der Pricerange von einigen 100 Euros stellt > Dir das ohnehin nicht so genau dass ein Unterschied zwischen 100 und 300 > Hz mehr als messbar (sprich, sichtbar) wäre. Sofern Du da nicht 'nen > gewaltigen Hebel ansetzt ist das "Ticken" kaum oder gar nicht sichtbar. > Im Endeffekt bestimmst Du damit nur, wie häufig der Sensor sein > Stellsignal bekommen soll, und sofern das nicht grad ein besagter Servo > mit einigen kN Stellkraft und der Stellgeschwindigkeit von nahezu null > ist, braucht der ohnehin einiges länger um seine Position einzunehmen > als Du stellen könntest. Wenn Du, sagen wir mal, den Servo im Lauf von 5 > Sekunden von Anschlag auf Anschlag (sagen wir mal 180°) bringen willst, > bewegst Du den Servo bei 50Hz pro Stellvorgang 43 Winkelminuten, 250 > Mal, bei 330Hz 6,5 Winkelminuten, 1650 mal. Anders ausgedrückt, Du > stellst in 43 Winkelminuten sechsmal statt einmal. Stell mal den Servo > mit der Klappe dran 43 Winkelminuten weit und sag mir ob Du ernsthaft > einen Unterschied sehen würdest wenn diese Bewegung nicht in einem > sondern in sechs Schritten erfolgen würde. Es ist ganz richtig, daß es viele Anwendungen gibt wo das unwichtig oder nur unwesentlich wichtig ist wie schnell und wie genau man den Servo ansteuert. Aber ein Beispiel wo es zum Beispiel schon wichtig ist ist der Heckservo eines Hubschraubers. Der wird ja, wenn der Pilot nicht gerade sagt: "Heck dreh dich" vom Gyro gesteuert und das Heck so still gehalten. Da merkt man - auch wenn weiter vorne im Thread manche behaupten das würden nur Weltmeister merken - wie schnell der Servo ist und ob er mit 50Hz oder mit 330Hz angesteuert wird. Da geht es (auch) um kleine Ausschläge die der Gyro steuert. Und wenn der Gyro nach 10ms eigentlich schon wieder in die andere Richtung steuern will aber der Servo erst nach weiteren 10ms das überhaupt mitbekommt dann ist das ein Unterschied. Den man sogar dann merkt wenn man nur schweben kann. > > Ganz abgesehen von der Schuhlöffelprogrammiererei, bei der Du irgendwann > gnadenlos bei ASM landest weil C die Kontrolle über die einzelnen > Instruktionen und damit das taktgenaue Timing nicht erlaubt: Der > Stromverbrauch ist nämlich bei solchen Stellfrequenzen auch nicht ohne. > Selbst wenn der dabei nix stellt brätst Du hier einiges an Strom weg. > Und grad beim Fahrwerk würde der dann tatsächlich 90% der Zeit nix > stellen aber saugen wie 'n Kamel nach dem Wüstendurchritt, sprich, Du > musst dann fast zwangsläufig das Ding in den Schlafmodus schicken, bzw. > die Stellfrequenz erheblich runterschrauben während das Fahrwerk > eingezogen ist, sonst ist der Akku leer bevor Du den Flug beendet hast. > Ok, is' etwas übertrieben, aber es war auch für mich 'n Augenöffner, > lass mal das Ampmeter mitlaufen wenn Du einen Servo so behandelst und er > dabei nicht mal was stellt. Das Projekt jetzt wird eh mit 20ms angesteuert. Weil beim Fahrwerk nicht mehr nötig ist. Aber das Programm dahinter soll es schon schaffen auch mit 3ms auf 1µs genau zu arbeiten. Im Kopf geistern mir nämlich noch andere Dinge herum die eine wirklich schnelle Reaktion der Servos (wahrscheinlich) brauchen können. > > Ich muss Dir allerdings jetzt auch ehrlich gestehen, ich sehe das > ultimative Problem der Gleichzeitigkeit nicht mehr. Wir reden hier von > einem Zeitunterschied im Bereich von 2ms wenn die Servos sequentiell > angesteuert würden. Das ist nicht sichtbar! Ich stelle alle meine Servos > sequentiell, und ich müßte ehrlich gestehen, entweder ich bin inzwischen > blind oder einfach nur langsam in der Aufnahme, aber ich sehe den > Unterschied nicht. Wäre es vielleicht möglich, wenn Du diesen > Unterschied bei einem Deiner Versuche sehen konntest, dass ein > Programmfehler vorgelegen hat? Wenn Du den Unterschied im Bereich von > 0.2 Hunderstel Sekunden sehen kannst, rate ich Dir zu einer Karriere als > Wettkampfrichter für Sportarten wo diese Zeiten entscheidend sind. > > Versteh mich bitte nicht falsch, ich will Dir nicht in Deine Projekt > hineinreden, allerdings glaube ich, Du willst hier Genauigkeit die Dir > nichts bringt und nur sehr viel Kopfschmerz verursacht. Nein, 2ms sieht man natürlich nicht. Aber zwischen ersten und letzen Servo bei 10 Servos liegen schon 20ms. Weil Du meine Versuch ansprichst. Der war nur mit einem einzigen Servo wo ich sehen wollte ab wann man merkt bzw. ab wann der Servo den Servohebel verstellt. Ich habe das Signal periodisch gewechselt 1500µs (Mittenposition) und 1501µs und habe geschaut ob sich der Hebel bewegt. 1500 zu 1503µs sieht man deutlich eine Bewegung. (Wenn es interessiert hätte ich ein Video dazu.) Ob da am Ausgang dann später jetzt wirklich 1500 und 1503µs rauskommen oder ob es durch die ISR in Wirklichkeit 1502 und 1505µs sind ist egal. Wichtig ist, daß es 3µs Differenz sind. Denn den praktisch wichtigen Wert stelle ich dann ja am Modell/Roboter oder was auch immer ein. Ich hoffe, Du weißt was ich meine damit. Ich bin heute, nach großen Problemen beim Programmieren, einen entscheidenden Schritt weiter gekommen. Und so wie es aussieht wird das funktionieren die Servos bei Bedarf alle 3ms anzusteuern mit einer Genauigkeit von meistens 1µs. Meistens weil es ganz stark darauf ankommt wie nahe die einzelnen Werte zueinander liegen. Wenn sie Liste so aussieht: Servo1 1500µs Servo2 1510µs dann ist 1µs kein Problem. Wenn es allerdings Servo1 1500µs Servo2 1501µs sind dann muß ich da Genauigkeit hergeben. Ich möchte noch schauen, daß ich die Sortierung noch hinbekomme und dann stelle ich den Code mal rein. Bei bereits sortierten Werten funktioniert es schon soweit ich das sehe. Auch am Steckbrett. Heinz, es ist sehr bereichernd mit Dir zu diskutieren, freut mich sehr! LG Ernst
W.S. schrieb: > Matthias Lipinsky schrieb: >> Und einen Namen: Tacoma Narrows Brigde > > Klarer Konstruktionsfehler: Nicht ausreichend bedämpfte Resonanzen der > Konstruktion. Ja, und man hat da wohl in vielen Jahrzehnten nichts dazugelernt: http://en.wikipedia.org/wiki/Millennium_Bridge_(London) Gruss Harald
Freut mich, dass ich Dir helfen kann. Hoff ich zumindest, dass ich's kann. Um mit dem Thema der Frequenz anzufangen, ich gebe zu, ich bin noch nicht ganz überzeugt. Ich hab selbst 'ne Weile Hubschrauber geflogen, damals noch ganz ohne Gyro und co (ist ja auch bald 20 Jahre her...), und ehrlich gesagt sind 20ms nicht die Welt. 50 Stellbewegungen pro Sekunde sind jenseits dessen was jemand merken könnte. Sollte es Dir allerdings wirklich ein unbedingtes Anliegen sein, würd ich für den Spezialfall einfach hergehen und dem Heckrotor seinen eigenen ATTiny spendieren, mit einem Kanal der NUR und AUSSCHLIESSLICH den Heckrotor austariert. Den dann mit 2ms Dauerstellungsfeuer anzusprechen, und damit dann 500Hz Frequenz rauszuholen ist auch kein Thema mehr. Der MC den Du für sowas bräuchtest ist für weniger als 'n Euro zu bekommen. Ich würd hier ehrlich dann überlegen für kritische Steuerbereiche eigene MCs einzusetzen statt jetzt hier auf Krampf zu versuchen eine "all in one" Lösung zurechtzufummeln. Sonst wird's eines der Projekte, die zwar absolute Granate wären, wenn sie jemals fertig würden. Und davon gibt's schon genug. Auch in meiner Coderamschkiste genannt Versionsverwaltung. Auch kann ich Dir aus Erfahrung sagen, vor allem am Anfang der Codekarriere, Du WILLST für Dein 2. Projekt nix aus dem ersten übernehmen. Du lernst so viel, dass Dir der Code einfach nur zum Wegschmeissen geeignet vorkommen wird. Bitte versteh das nicht als Kritik an Deinem Code, so geht es JEDEM. Sieh dieses Projekt als Gelegenheit zum Lernen. Erwarte aber nicht dass Du von dem Code irgendwas für Dein nächstes Projekt noch verwenden willst. Ich würde Dir also raten, nimm dieses Projekt als das was es ist und setze DIESES Projekt um. Ohne Aussicht auf ein nächstes oder Planung wie Du den Code wiederverwenden könntest. Du wirst ihn nicht wiederverwenden. Aber zum eigentlichen Thema. Programmierung: Du kannst es auch so lösen, dass Du die "Programmiereinheit" abnehmbar machst und nur den "Steuerungsteil" in das Modell einbaust. Was so nebenbei den netten Effekt hätte, dass du nur eine "Programmiereinheit" für diverse Modelle bräuchtest, wenn Du das Feature bei mehreren Modellen nutzen willst. Drehimpulsgeber kosten zwar nur 2 Euro, aber das Display ist üblicherweise 'ne recht teure Angelegenheit, die Trennung lohnt also. Auch weil sich so sehr einfach feststellen läßt, ob programmiert wird. Einfach einen Pin zum Programmiergerät führen und dort gegen Masse legen, Pullup für den Pin aktivieren und prüfen ob auf dem Pin 1 oder 0 anliegt. Ist's 0, ist er angesteckt. Ich würde allerdings raten nicht zu versuchen das auf Krampf über eine Leitung zu übertragen, sonst wird Dir nix übrig bleiben außer auch dem Programmierteil 'nen MC zu spendieren der die Signale mit dem anderen synchronisiert. Einfacher ist es, das Programmierteil "dumm" zu halten und einfach hinreichend viele Leitungen vom MC rauszuleiten und den das alles steuern zu lassen. Braucht zwar 8 Leitungen (2 für Drehimpulsgeber, 1 für taster, 1 für "bin ich angesteckt" Leitung, 2 für Display und 2 für vcc/gnd), aber simpler wird's kaum. Und für's erste Projekt würde ich das KISS Prinzip dringend empfehlen. Auch komm ich nicht ganz dahinter wo Du jetzt die 17ms freie Zeit her hast. Entweder Du willst alle 3ms steuern oder alle 20ms. Ich bitte um Erklärung hier. Wenn Du eine 20ms Steuerung brauchst, ist es problemlos möglich, auch kannst Du dann die Servos bequem in Sequenz ansteuern mit einer Auflösung von (nahezu) beliebig (bei einem 16MHz Quarz hab ich eine de facto Auflösung von 0,3 Mikrosekunden, wenn ich mich jetzt nicht verrechnet hab, was im Prinzip 3333 Schritte zwischen Anschlag und Anschlag bedeutet). Ist allerdings glaub ich nur mit ASM genau hinzubiegen, ich weiß nicht ob man auch in C instruktionsgenau arbeiten kann (weil jede Instruktion mehr oder weniger bereits eine Abweichung bedeutet). Ich glaube ehrlich gesagt nicht, dass die Schrittweite ein Problem darstellen wird, ausser Du bestehst darauf, dass alles "gleichzeitig" gestellt werden muss und Du wirklich 330Hz Frequenz benötigst. Bei dem Ganzen ist bei mir hinreichend Zeit um mit dem ADC 6 verschiedene Signale zu samplen, und wer weiss wie viel Zeit ADC sampling frisst, der weiss wie viel spare time ich da hab. ;)
Kleinigkeit noch zur Lösung des Speicherproblems. Ich hab mir überlegt, man müßte doch Kondensatoren dafür nutzen können. Ja, die liefern nicht viel und nicht lang, aber wir müssen ja auch nur ein Byte schreiben, das sind wenn ich nicht ganz falsch liege 6 Cycles. Mit overhead sollen's 20 sein, wir müssen also grad mal ein wenig über eine Mikrosekunde das Ding noch "am Leben" erhalten. Bischen hier graben produzierte das da: http://www.mikrocontroller.net/articles/Speicher#EEPROM_Schreibzugriffe_minimieren Das sollte das Problem erledigen wie man feststellt wo das Fahrwerk war als das Ding ausgeschaltet wurde.
Hallo Heinz! Sorry, daß ich erst jetzt antworte, die letzten Tage sind die ersten LCD's bei mir eingetrudelt so daß ich mal total neugierig war die anzusteuern und das erste Hallo Welt zu schreiben. Ging aber dank Tutorial sehr leicht von der Hand. Trotzdem war es eine super Sache das erste mal selbst was auf ein Display zu schreiben und den Text dann in leuchtenden Buchstaben zu sehen. Doch zurück zu den Servos... Die 17ms habe ich deshalb frei weil ich zwar alle Servos gleichzeitig starte mir aber trotzdem 20ms für einen Zyklus Zeit lasse. Mehr brauche ich beim Fahrwerk ja nicht. Aber es ließe sich auf 3ms stellen wenn man denn wollte. Da sind dann natürlich keine 17ms mehr Zeit und es könnte tatsächlich eine Herausforderung sein die Tasten abzufragen. Wobei die ersten 750µs ist ja auch Zeit was anderes zu tun als Servos zu stellen. Und nach 2250µs nochmals 750µs. Die Genauigkeit betreffend kann ich mit meinem Code auf 1µs genau die Servos ansteuern unter der Voraussetzung, daß zwei Servos nicht genau den gleichen Wert haben bzw. die Werte nicht zu knapp nebeneinander liegen. Haben sie den gleichen Wert dann bekomme ich bei dem Servo eine kleine Abweichung von 1-3µs in der Genauigkeit. Wobei das muß noch optimiert werden, da läßt sich sicher einiges noch rausholen. Was den Code betrifft, da hast Du sicher ganz recht, im nächsten Projekt werde ich den nicht mehr verwenden wollen. Gutes Argument. Den extra Programmer werde ich weiter verfolgen. Im Moment habe ich alles am Steckbrett aufgebaut und habe so meine "Entwicklungsumgebung". Von dem Elko als Stromversorgung um noch schnell was ins EEProm zu schreiben habe ich hier schon irgendwo mal gelesen, das wäre eine Option den letzten Zustand reinzuschreiben. Aber vielleicht muß man sich darüber auch gar keine Gedanken machen. Der EEProm hält 100000 mal schreiben aus. Selbst wenn man nach jedem mal Fahrwerk rein oder raus schreibt hält der EEProm sicher trotzdem jahrelang. Angenommen, man geht jedes Wochenende Sa und Sonntag fliegen und verfliegt da 6 Akkus. Das sind 6 Starts und 6 Landungen also 12mal Fahrwerk raus oder rein. 24 mal an einem Wochenende. Das Jahr hat 52 Wochen, sind 1248 Schreibzugriffe im Jahr. Damit könnte man 80 Jahre lang jedes Wochenende fliegen gehen. Das ist mehr als genug. :-)) Bei mir steht Programm-mäßig als nächstes die EEProm Progrogrammierung an. Also Daten auslesen und wieder rein schreiben. Und wenn das funktioniert dann werde ich mich um die Tasten kümmern um dem User die Möglichkeit der Einstellung zu geben. Magst den bisherigen Code mal sehen? (Aber teilweise schrecklich, ich sags gleich!) LG Ernst
Kann ich verstehen, meine ersten LEDs hatten bei mir auch einen "ohhhh, shiny!" Effekt. :) Zum timing: Wie gesagt, wenn Du hier ohnehin mit 20ms (50Hz) Cycles arbeitest würd ich's einfach sequentiell ansteuern und mir den ganzen Aufwand zum Sortieren usw. ersparen. Du gewinnst nichts dabei für zukünftige Projekte, da Du wahrscheinlich irgendwann nicht nur "statische", voreingestellte Bewegungen machen willst sondern Interaktivität willst, und spätestens dann hast Du keine Zeit mehr die Servos durchzusortieren vor jeder Steuerung. Überleg's Dir. Es würde Dir SEHR viele Kopfschmerzen nehmen. Damit würden einige Probleme auf einmal verschwinden, ob 2 Servos gleiche oder ähnliche Werte haben wird egal, Du hast einen wesentlich einfacheren Code (weniger "bewegliche Teile")... Die "externe Programmiereinheit" wird erst zum Thema wennst mal das Ding auf die Platine überträgst, da hast recht. Lassen wir vielleicht mal weg bis der Code steht. Beim Speichern hast auch recht... später mal wär's vielleihct interessant einen Weg zu finden die genaue Position aller Servos bei Power-off zu sichern, vorläufig stimm ich Dir zu, das sollte reichen. Der Code würd mich durchaus interessieren, kannst ihn mir gern per Nachricht zukommen lassen. Und da ausser uns zwei beiden scheinbar kein Schwein der Thread mehr interessiert sollten wir vielleicht auch zur Kommunikation einfach wirklich auf persönliche Nachrichten umschwenken. :)
Servus Heinz! Sortiert werden die Servos eh nur einmal. Und zwar beim Start des µCs. Das ist Gott sei Dank kein Problem. Mit dem Code, das wird noch ein bisl dauern bis ich Dir den schicken kann, ich habe heute begonnen den Code in wesentlichen Teilen umzustellen. Damit wird die ISR kürzer, nicht viel aber doch. Nötig wurde das weil ich doch - wenn Du Dich erinnerst - möchte, daß die Servos langsam - je nach Userwunsch - in die jeweils andere Position fahren. Also habe ich noch ein drittes struct eingeführt. Die Pause zwischen Fahrwerksklappe und Fahrwerk habe ich auch noch nicht umgesetzt, ich hoffe, ich baue ihn dann nicht noch ein drittes mal um. :-)) Soweit ich das sehe läuft der Code eigentlich sehr gut. Nur beim allerersten Timerdurchlauf paßt was nicht. Wobei ich nicht weiß, warum. Die Sub-Routine die mir die Zwischenpositionen errechnet (für das langsame Anfahren der Gegenposition) dauert 30µs. Womit ich mich auseinandersetzen muß ist wie man ein Byte als Flag-Register nutzt. Weißt was ich meine? Ich habe verschiedene Dinge in meinem Code die 0 oder 1 sein können. Im Moment verbrate ich dafür jedesmal ein Byte. Aber das müßte sich auch anders lösen lassen. Wie ein Register sozusagen. Muß ich nochmals das Tutorial lesen, ich glaube, da drinnen steht was. Dürftest recht haben, außer uns beiden interessiert sich niemand mehr für den Thread. Werden wir unsere Unterhaltung also auf PNs verlegen. (Wobei ich gar nicht weiß wie das hier geht...) LG Ernst
Hallo Ernst + Heinz, einen (stillen) Mitleser habt ihr noch :-) Da ich mich für Servoansteuerungen interessiere und auch so etwas ähnliches machen möchte, lese ich hier mit. Muss gleich sagen: Bin bisher noch bei der Theorie und habe noch keine Zeile Code geschrieben. Mein Ansatz für ein solches Problem ist jedoch ein ganz anderer. Und zwar ist es bei den sogenannten Digitalservos ja so, dass sie nicht ständig einen Impuls benötigen. Denen reicht ein Impuls um eine bestimmte Position an zu fahren. Sie versuchen dann dort hin zu fahren und die Position so lange zu halten, bis ein Impuls mit einer anderen Vorabe kommt. Und wenn dieser Impuls auch erst eine Woche später kommt, so bleiben sie eben eine Woche stehen. Ich schreibe "sie versuchen", denn wenn es irgendwo klemmt, dann versucht der Servo es trotzdem weiter so lange bis er sich selbst aufgrund hoher Stromaufnahme zerstört hat. Deshalb mein Ansatz für das Problem: Nur dann Steuerimpulse senden wenn sich eine Position geändert hat oder auch dann, wenn es dem µC eh grade langweilig ist (obwohl dies nicht nötig wäre). Muss noch dazu sagen, bei meinem Projekt sollen sich die Endpositionen dynamisch ändern können. Es gibt also keine fest definierten Anfangs- und Endpositionen. Nur die Verfahrgeschwindigkeiten werden einmal fest definiert. Zwei Nachteile: 1. Es könenn nur Digitalservos verwendet werden. Ist aber nicht sooo schlimm, da diese preislich immer interessanter werden. Ausserdem kann man auch mal ein bisschen in die Zukunft denken ;-) 2. Wenn sich viele Positionen gleichzeitig ändern, dann müssen Prioritäten an die Servos vergeben werden. Je nach Projekt ist das ein Problem oder auch nicht. @Ernst: Wenn Dein Konzept allerdings so auf geht wie Du es Dir vorstellst, dann wäre das für Deinen Anwendungsfall ja noch besser, da dann auch auf 330Hz parametriert werden kann und trotzdem alles ohne Einschränkungen funktioniert. Ich kann mir zwar im Moment kein Projekt vorstellen, bei welchem diese exakte Gleichzeitigkeit von Nöten ist. Ist aber egal, denn weshalb soll ein System nicht trotzdem exakt sein, auch wenn es 99% der Anwender nicht für nötig halten!? Eines ist mir noch nicht klar: Ernst B. schrieb: > Sortiert werden die Servos eh nur einmal. Und zwar beim Start des µCs. > Das ist Gott sei Dank kein Problem. Wenn das Ganze justiert wird, dann stimmt doch die Sotierung nicht mehr. Muss dann nicht bei jeder Änderung alles neu sortiert werden? Okay, ist auch kein Problem, der Flieger ist am Boden und die Sortierroutine kann zwischen drin mal durchlaufen werden. Gruss Ulli-B
Ulli B. schrieb: > Hallo Ernst + Heinz, > > einen (stillen) Mitleser habt ihr noch :-) Hi Ulli! Das freut mich aber, daß es noch einen stillen Mitleser gibt. > Deshalb mein Ansatz für das Problem: Nur dann Steuerimpulse senden wenn > sich eine Position geändert hat oder auch dann, wenn es dem µC eh grade > langweilig ist (obwohl dies nicht nötig wäre). > Muss noch dazu sagen, bei meinem Projekt sollen sich die Endpositionen > dynamisch ändern können. Es gibt also keine fest definierten Anfangs- > und Endpositionen. Nur die Verfahrgeschwindigkeiten werden einmal fest > definiert. Das ist auch ein interessanter Ansatz. Und ich denke, der wird auch gut funktionieren. In meinem Fall habe ich die Servos fürs Fahrwerk schon und es sind Analogservos. Preislich sind die halt nochmal um vieles billiger als die Digitalservos. 4 Stück MG90 kosten auf Ebay gerade mal 16 Euro. Und das sind eigentlich sehr gute Analogservos. Was mir schon die ganze Zeit durch den Hinterkopf schwebt und Du hast es ja auch angesprochen: Ob man wohl recht einfach "messen" kann ob ein Servo irgendwo blockiert? Müßte eigentlich möglich sein aufgrund des höheren Stromes den das Servo dann zieht. Die Verfahrgeschwindigkeiten kann ich seit gestern Nacht parametrisieren. Wie wirst Du die Verfahrgeschwindigkeiten reallisieren? Hast schon eine Idee dazu? > > Zwei Nachteile: > 1. Es könenn nur Digitalservos verwendet werden. > Ist aber nicht sooo schlimm, da diese preislich immer interessanter > werden. > Ausserdem kann man auch mal ein bisschen in die Zukunft denken ;-) > > 2. Wenn sich viele Positionen gleichzeitig ändern, dann müssen > Prioritäten an die Servos vergeben werden. > Je nach Projekt ist das ein Problem oder auch nicht. ad 2. Oder Du startest auch alle Servos gleichzeitig los so wie ich das mache. Kommt halt drauf an ob Du "rechtzeitig" alle Positionen vorliegen hast um das auch umzusetzen. > > > @Ernst: > Wenn Dein Konzept allerdings so auf geht wie Du es Dir vorstellst, dann > wäre das für Deinen Anwendungsfall ja noch besser, da dann auch auf > 330Hz parametriert werden kann und trotzdem alles ohne Einschränkungen > funktioniert. > Ich kann mir zwar im Moment kein Projekt vorstellen, bei welchem diese > exakte Gleichzeitigkeit von Nöten ist. Ist aber egal, denn weshalb soll > ein System nicht trotzdem exakt sein, auch wenn es 99% der Anwender > nicht für nötig halten!? Ich hoffe, daß es so aufgeht wie ich mir das vorstelle. Und im Moment sieht es ganz danach aus. Wie gesagt, von meiner mir selbst gestellten Vorgabe, 330Hz auf µs genau muß ich im Moment nur dann ein wenig abweichen wenn zwei Servos zufällig eine Position anfahren die nur wenige µs auseinander liegt. > > > Eines ist mir noch nicht klar: > Ernst B. schrieb: >> Sortiert werden die Servos eh nur einmal. Und zwar beim Start des µCs. >> Das ist Gott sei Dank kein Problem. > > Wenn das Ganze justiert wird, dann stimmt doch die Sotierung nicht mehr. > Muss dann nicht bei jeder Änderung alles neu sortiert werden? > Okay, ist auch kein Problem, der Flieger ist am Boden und die > Sortierroutine kann zwischen drin mal durchlaufen werden. > Ulli, da hast natürlich recht. Wenn der User einstellt und justiert dann stimmt die Reihenfolge nimmer. Das ist sowieso programmtechnisch ein heikler Vorgang. Denn ich muß sicherstellen, daß der User nicht zufällig anfängt zu justieren während alle Servoausgänge auf High sind und die dann nicht rechtzeitig wieder auf Low gehen. Da würden mir ja alle Servos auf Maximalausschlag fahren und in die Begrenzung krachen und ev. kaputt gehen. Umgesetzt habe ich das ja noch nicht aber ich stelle es mir mal so vor: Ich frage ab ob alle Servoausgänge auf Low sind und ob der User gerade versucht einzustellen. Falls ja dann stoppe ich das stellen der Servos bis der User fertig ist und starte danach wieder. Die Sortierung wäre wahrscheinlich gar nicht so das zeitkritische aber ich muß die Werte ja auch ins EEProm schreiben und das soll ja doch ziemlich dauern. Gestern Nacht hatte ich noch ein geiles Erfolgserlebnis, habe ja den Code umgestellt um die Verfahrgeschwindigkeit zu regeln und es hat tatsächlich funktioniert. Meine zwei Testservos fahren schön langsam hin und her. Ich muß das natürlich noch austesten mit verschiedenen Werten sowohl für die Servopositionen als auch für die Verfahrgeschwindigkeit aber es schaut im Moment sehr vielversprechend aus. freufreu LG Ernst
Hallo, du musst doch Deine Werte für die Servos umsortieren, wenn sich eins von links nach rechts und das andere in Gegenrichtung bewegt und wieder andere statisch ihre Position halten. Aber das ist auch nicht schwer, wenn Du weißt an welcher Position in der sortierten Liste/Feld das entsprechende Servo einsortiert ist. Dazu muss man parallel zu der zu sortierenden Liste die liste mit den Positionen mittauschen. Zu Beginn hat Posliste die Werte [0,1,2,3,4,5,6,7,8] und nach der Sortierung zum Beispiel: Posliste[0,8,4,5,7,6,3,2,1] Dann kannst Du dieses mit der inneren Schleife von Bubblesort einsortieren, wobei Du Start und Endposition ( rauf oder runter ) kennst. Meist wird sich die Sortierung dabei nicht ändern, da Du ja langsame Bewegung an der Klappe und Fahrwerk haben willst. Du übergibt Servo Nr und Richtung, Du weißt ja, ob die Änderung positiv oder negativ war. Und dann einfach wie InsertionSort ab der Position des Servo Wiederhole mit Nachbarn vergleichen, bei nötigem Austausch dies tuen und die Positionsnummern auch tauschen, T falls kein Austausch nötig dann Abbruch der Schleife, da fertig sortiert. Vielleicht kann man die TimerListe entsprechend parallel aktualisieren, aber die müsste dann eine Kopie sein ( double buffer), damit diese nicht gerade in Verwendung ist. Da meist eine gleichmässige Bewegung angestrebt ist, ändern sich die Positionen in der sortierten Liste nur minimal. Es geht also sehr schnell.
hallo Ernst, Ernst B. schrieb: > Wie wirst Du die Verfahrgeschwindigkeiten reallisieren? Hast schon eine > Idee dazu? nun, einfach durch einen Vorgabewert und einen Ausgabewert. Der Vorgabewert entspricht der Soll-Endposition. Der Ausgabewert folgt dem Vorgabewert indem er sich schrittweise durch addieren bzw. subtrahieren eines Schrittwertes dem Vorgabewert annähert. Der Schrittwert zusammen mit der Zeit zwischen zwei Additionen/Subtraktionen entspricht der Verfahrgeschwindigkeit. Hört sich komplizierter an als es sein sollte. Wie gesagt, habe bisher aus Zeitgründen noch nichts programmieren können. Bin selbst gespannt, ob man die schrittweise Verstellung dann am Servo sieht. Denn je nach Verhältnis zwischen Servogeschwindigkeit und Schrittweite ist dann entweder der Servo schneller oder der Vorgabewert. Jetzt wo ich dies hier schreibe, könnte ich mir vorstellen, dass analoge Servos hier wesentlich weicher fahren werden als digitale. Denn die analogen Servos fahren ja nur dann auch in die ihnen bestimmte Position, wenn ständig ein Impuls kommt. Kommt hier während dem Verfahren kein Impuls mehr, dann "trudelt" ein analoger Servo aus. Was ich sagen will: Analoge Servos fahren schin immer etwas weicher als digitale. Aber Du kannst ja sicher schon von Erfahrungen profitieren: Ernst B. schrieb: > Gestern Nacht hatte ich noch ein geiles Erfolgserlebnis, habe ja den > Code umgestellt um die Verfahrgeschwindigkeit zu regeln und es hat > tatsächlich funktioniert. Meine zwei Testservos fahren schön langsam hin > und her. Ich muß das natürlich noch austesten mit verschiedenen Werten > sowohl für die Servopositionen als auch für die Verfahrgeschwindigkeit > aber es schaut im Moment sehr vielversprechend aus. Kann man hier bei ungünstigen Verhältnissen ein "takten" des Servos sehen? Gruss Ulli-B
Hallo Hier erkennt man, was ich meine, beispielhaft fuer zwei Servos. Servo 1 von links nach rechts und Servo 2 entgegengesetzt. Impulsdauer bei gemeinsamen Start
1 | Servo1 Servo2 |
2 | 0 1000 |
3 | 50 920 |
4 | 100 840 |
5 | 150 760 |
6 | 200 680 |
7 | 250 600 |
8 | 300 520 |
9 | 350 440 |
10 | 400 360 <= Wechsel in Timerliste |
11 | 450 280 |
12 | 500 200 |
13 | 550 120 |
14 | 600 40 |
15 | 650 0 |
16 | 700
|
17 | 750
|
18 | 800
|
19 | 850
|
20 | 900
|
21 | 950
|
22 | 1000
|
Das ist etwas schnell mit 80 Zeiteinheiten zwischen zwei Impulsen, das sind bei 20 ms == 50 Hz 0.26 Sekunden von einem zum anderen Anschlag, so schnell sind nicht alle Servos, dafuer ist das Beispiel kuerzer. Bei 300 Hz kannst Du nur maximal die Stufen 1 bis 12 nutzen, nicht berauschend. Eine Aenderung um 1000 Pulse bei einer Schrittweite x von Puls zu Puls
1 | Schritt ms fuer Aenderung von 1000 auf 2000 |
2 | 1 3300 |
3 | 2 1650 |
4 | 3 1100 |
5 | 4 825 |
6 | 5 660 |
7 | 6 550 |
8 | 7 471 |
9 | 8 412 |
10 | 9 367 |
11 | 10 330 |
12 | 11 300 |
13 | 12 275 |
1 durch x, war wohl nix. Es sind enorme Spruenge in den moeglichen Laufzeiten von Anschlag zu Anschlag. Das kann man aendern kostet aber auch Rechenzeit.
Ich wollte Euch mal auf dem laufenden halten wie es in meinem Projekt voran geht. Inzwischen habe ich folgenden funktionsfähigen Stand der Dinge: Ich kann 9 Servos anschließen, alle starten gleichzeitig und ich habe die Möglichkeit auf 1µs genau anzusteuern. Über drei Taster kann man die jeweilige Start- und Endposition jedes Servos eingeben, Ausgabe auf einem LCD-Display. Die einzelnen Werte werden beim Start des µC aus dem EEProm gelesen. Mit dem ersten Taster schaltet man der Reihe nach die Servos, mit den beiden anderen Tastern kann man den Wert rauf oder runterzählen. Die Verfahrgeschwindigkeit der Servos kann ebenfalls eingegeben werden.(für alle gemeinsam, einzeln ginge zwar auch macht aber keinen Sinn bei einem Door-Sequenzer. Eventuell könnte man unterschiedliche Verfahrgeschwindigkeiten für Fahrwerk und Fahrwerkstüren andenken) ToDo: Abspeichern der (geänderten) Werte im EEProm. Hier überlege ich noch ob der User die Werte dezidiert über einen "Speicherbefehl" abspeichern muß oder ob ich einfach nach jeder Änderung die Daten im EEProm speichere. Eine variable, vom User konfigurierbare Zeit zwischen Klappen auf und Fahrwerk raus. (und umgekehrt) Der Eingang vom Empfänger des Modells hin zum µC für die Zustandsumschaltung. (Fahrwerk rein-raus) Viel ist also nicht mehr zu tun und schön langsam neigt sich das Projekt einem Ende entgegen. Vielen Dank an alle die mir weiter geholfen haben! LG Ernst
Ulli B. schrieb: > Ernst B. schrieb: >> Gestern Nacht hatte ich noch ein geiles Erfolgserlebnis, habe ja den >> Code umgestellt um die Verfahrgeschwindigkeit zu regeln und es hat >> tatsächlich funktioniert. Meine zwei Testservos fahren schön langsam hin >> und her. Ich muß das natürlich noch austesten mit verschiedenen Werten >> sowohl für die Servopositionen als auch für die Verfahrgeschwindigkeit >> aber es schaut im Moment sehr vielversprechend aus. > > Kann man hier bei ungünstigen Verhältnissen ein "takten" des Servos > sehen? Hi Ulli, sorry, die Frage habe ich ganz übersehen. Die Servos fahren ganz weich. Das gilt für "Schrittweiten" von 10 bis 90µs pro Takt (also alle 20ms). Für diese Schrittweiten habe ich es getestet, bis zu 255µs Schrittweite sollen einstellbar sein, muß ich aber noch anschauen. Wo ich ein Problem habe ist folgende Testsituation. Die erste Servo von insgesamt neun Servos fährt von 1000 auf 2000µs und der zweite von 2000µs auf 1000µs. Alle anderen Servos haben als Start und Endposition 1500µs eingestellt. Das heißt bei 1500µs überschneiden sich die zwei Servos und alle anderen haben auch die gleiche Position. Da merkt man ein kurzes rucken im Servo weil ich in meiner ISR die Servos nicht alle gleichzeitig ausschalten kann und in so einem Extremfall die Ansteuerung nicht mehr auf µs genau ist. Gleiche oder ganz knapp beieinander liegende µs-Zahlenwerte sind im Moment noch die größte Schwäche in meinem Programm. Ich glaube aber, daß das im praktischen Einsatz nicht vorkommen wird, daß mehrere Servos gleiche oder ganz ähnliche Start- bzw. Endpositionen haben werden. LG Ernst
Hallo, r Ernst B. schrieb: > Die Servos fahren ganz weich. Das gilt für "Schrittweiten" von 10 bis > 90µs pro Takt (also alle 20ms) wie kann das ganz weich sein wenn bei Schrittweite von 90 µs alle 20 ms die 1000 µs ~ 11* 90 µs von links bis rechts nach 11x20 ms = 0,22 s durchschritten sind. Dann kannst Du auch direkt nach dem Startwert den Endwert nutzen, dass dürfte keinen Unterschied machen. Das MG90 legt bei 6 V in 0,1 s 60 Grad zurück, die maximalen, geratenen 180 Grad also in knapp unter 0,3 Sekunden, was auch noch Angeban ohne äußere Last sind. Bis schätzungsweise einer Schrittweite von 67 µs dürfte kein Unterschied zwischen schrittweise erhöhen und sofortiges setzen des Endwertes erkennbar sein. Das hängt natürlich davon ab, ob der innere Verstärker eine Abweichung von 6,67 % schon zu einer Spannung am Motor von 100% umsetzt.
Test schrieb: > Hallo, > r > Ernst B. schrieb: >> Die Servos fahren ganz weich. Das gilt für "Schrittweiten" von 10 bis >> 90µs pro Takt (also alle 20ms) > > wie kann das ganz weich sein wenn bei Schrittweite von 90 µs alle 20 ms > die 1000 µs ~ 11* 90 µs von links bis rechts nach 11x20 ms = 0,22 s > durchschritten sind. > Dann kannst Du auch direkt nach dem Startwert den Endwert nutzen, dass > dürfte keinen Unterschied machen. > Das MG90 legt bei 6 V in 0,1 s 60 Grad zurück, die maximalen, geratenen > 180 Grad also in knapp unter 0,3 Sekunden, was auch noch Angeban ohne > äußere Last sind. > Bis schätzungsweise einer Schrittweite von 67 µs dürfte kein Unterschied > zwischen schrittweise erhöhen und sofortiges setzen des Endwertes > erkennbar sein. > Das hängt natürlich davon ab, ob der innere Verstärker eine Abweichung > von 6,67 % schon zu einer Spannung am Motor von 100% umsetzt. Hi Test, Danke für Deinen Beitrag, ich habe mich um den Faktor 2 geiirt. 10-90 sind meine "Timerwerte" die ich jetzt irrtümlich als µs angegeben habe. In Wirklichkeit sind das 5-45µs Schrittweite. Genau genommen habe ich eine kleinste Schrittweite von 0,5µs. Aber ich werde das mal testen ob man bei 90µs Schrittweite noch einen Unterschied sieht zu gleich max-min Position. LG Ernst
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.