Forum: Mikrocontroller und Digitale Elektronik Newbie braucht Hilfe: 9 Servos mit 1µs Auflösung ansteuern? (AVR)


von PuraVida (Gast)


Lesenswert?

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

von H.Joachim S. (crazyhorse)


Lesenswert?

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

von Uwe (Gast)


Lesenswert?

Die Servos können eh keine auflösung von 1µs also warum sich darüber den 
Kopf zerbrechen.

von PuraVida (Gast)


Lesenswert?

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

von Harald W. (wilhelms)


Lesenswert?

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

von H.Joachim S. (crazyhorse)


Lesenswert?

Ok, das mit den Digitalservos hatte ich überlesen...

von Peter D. (peda)


Lesenswert?

Der ATmega2560 hat 12 PWMs mit 16Bit, damit gehts.


Peter

von H.Joachim S. (crazyhorse)


Lesenswert?

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.

von PuraVida (Gast)


Lesenswert?

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

von PuraVida (Gast)


Lesenswert?

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

von Michael K. (mmike)


Lesenswert?

Mit nem XMega ist das ein Kinderspiel ;-)

Grüße,
Michael

von Peter D. (peda)


Lesenswert?

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

von PuraVida (Gast)


Lesenswert?

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

von UR Schmitt (Gast)


Lesenswert?

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.

von MaWin (Gast)


Lesenswert?

> 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
}

von PuraVida (Gast)


Lesenswert?

@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

von Thomas (Gast)


Lesenswert?

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.

von PuraVida (Gast)


Lesenswert?

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

von Harald W. (wilhelms)


Lesenswert?

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

von Ernst B. (puravida)


Lesenswert?

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

von Ernst B. (puravida)


Lesenswert?

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

von MaWin (Gast)


Lesenswert?

> 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
}

von Matthias L. (Gast)


Lesenswert?

>virtuos programmieren können.

Was ist das?

von Harald W. (wilhelms)


Lesenswert?

Matthias Lipinsky schrieb:
>>virtuos programmieren können.
>
> Was ist das?

Siehe hier:
http://de.wikipedia.org/wiki/Der_Virtuos
Gruss
Harald

von UR Schmitt (Gast)


Lesenswert?

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)!

von Oliver (Gast)


Lesenswert?

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

von Ernst B. (puravida)


Lesenswert?

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

von MaWin (Gast)


Lesenswert?

>  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)
}

von Josef (Gast)


Lesenswert?

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

von Ernst B. (puravida)


Lesenswert?

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

von Ernst B. (puravida)


Lesenswert?

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

von Josef (Gast)


Lesenswert?

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

von Ernst B. (puravida)


Lesenswert?

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... :-))

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

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.

von Ernst B. (puravida)


Lesenswert?

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

von Matthias L. (Gast)


Lesenswert?

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.

von Ernst B. (puravida)


Lesenswert?

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?

von Ernst B. (puravida)


Lesenswert?

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...

von Michael A. (Gast)


Lesenswert?

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.

von Ernst B. (puravida)


Lesenswert?

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...

von Ernst B. (puravida)


Lesenswert?

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

von Matthias L. (Gast)


Lesenswert?

struct serv_o
{
  int when;
  int port;
} ...

und

struct serv_c
{
  int when;
  int port;
} ...


Was ist der Unterschied?

von Udo S. (urschmitt)


Lesenswert?

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.

von Heinz L. (ducttape)


Lesenswert?

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!

von Ernst B. (puravida)


Lesenswert?

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

von Ernst B. (puravida)


Lesenswert?

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

von Ernst B. (puravida)


Lesenswert?

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

von Harald W. (wilhelms)


Lesenswert?

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

von Ernst B. (puravida)


Lesenswert?

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

von Heinz L. (ducttape)


Lesenswert?

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.

von Matthias L. (Gast)


Lesenswert?

>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

von W.S. (Gast)


Lesenswert?

Matthias Lipinsky schrieb:
> Und einen Namen: Tacoma Narrows Brigde

Klarer Konstruktionsfehler: Nicht ausreichend bedämpfte Resonanzen der 
Konstruktion.

von Ernst B. (puravida)


Lesenswert?

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

von Harald W. (wilhelms)


Lesenswert?

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

von Heinz L. (ducttape)


Lesenswert?

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. ;)

von Heinz L. (ducttape)


Lesenswert?

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.

von Ernst B. (puravida)


Lesenswert?

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

von Heinz L. (ducttape)


Lesenswert?

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. 
:)

von Ernst B. (puravida)


Lesenswert?

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

von Ulli B. (ulli-b)


Lesenswert?

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

von Ernst B. (puravida)


Lesenswert?

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

von Horst H. (horha)


Lesenswert?

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.

von Ulli B. (ulli-b)


Lesenswert?

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

von Horst H. (horha)


Lesenswert?

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.

von Ernst B. (puravida)


Lesenswert?

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

von Ernst B. (puravida)


Lesenswert?

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

von Test (Gast)


Lesenswert?

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.

von Ernst B. (puravida)


Lesenswert?

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
Noch kein Account? Hier anmelden.