Salut, momentan entwickle ich einen Servocontroller, der auf einem Hexapod zum Einsatz kommen soll. Leider zeigt dieser seltsame Fehler, bei denen mir auch im Roboternetz niemand helfen konnte, deshalb frage ich hier einmal nach. Problem ist, dass sich die Servos nicht separat regeln lassen; stattdessen wird der (gemeinsame) Puls einfach fuer alle Werte, die im SRAM hintereinander liegend == 255 sind, etwas laenger, in einer Art exponentiellen Kurve. Der Code an sich ist simpel, weshalb ich mir den Fehler nicht erklaeren kann; hier der ASM-Code zur Erzeugung der variablen Komponente des Signals: clr lowmask clr highmask clr ptr ldi counter,127 ; count down from 127 to -128 sec ; c is to be rotated into ptr ldi ZH,4 ; RAM pointer is at 1024, address of first servo value ; repeat this once every ( 1.35 / 255 ) ms cycle: clr ZL ; point Z to first servo compare_next_motor: rol ptr ; rotate servo ptr to next value brcs write ; if all values compared: break ldd servo,z+8 ; load servo in higher byte cp servo,counter ; and compare w/ counter brne second ; if not equal: leave high mask blank at position or highmask,ptr ; else start pulse at end of cycle second: ld servo,z+ ; compare lower servo respectively cp servo,counter brne compare_next_motor or lowmask,ptr rjmp compare_next_motor ; and loop write: out _SFR_IO_ADDR(PORTA),lowmask out _SFR_IO_ADDR(PORTD),highmask dec counter ; count comparision value for servos down brvc cycle ; if not transition -128 -> 127: repeat Der Code liegt in einem .S-File, umgeben von den noetigen Pushs und Pops, und wird als Funktion aus C in einer ISR alle 20ms aufgerufen. Grundidee, falls nicht ersichtlich, ist ein von 127 abwaerts zaehlender int8_t-Wert, der laufend mit saemtlichen Servowerten, die sequentiell ab 1024 im SRAM liegen, abgeglichen wird; bei gleichem Wert wird der Servo aktiviert, je hoeher der Wert, je frueher findet das statt. Soweit ganz einfach - gerade deshalb komme ich nicht weiter... Kann vielleicht jemand helfen? Gruss, David PS: Fuer Optimierungsvorschlaege, was die Geschwindigkeit angeht, waere ich ebenfalls sehr dankbar; bin zwar momentan auf 0-1.34 ms Variationsbreite runter, das reicht aber nur fuer die mir vorliegenden Conrad-Servos und entspricht nicht der Norm (zu lang - die liegt bei 1-2 ms AFAIK?).
Also so richtig verstehe ich nicht, was du da vor hast. Unter Servocontroller stelle ich mir das Teil vor, was die Nachlaufsteuerung im Servo realisiert, also die Servo-Elektronik. Solltest du aber einen Controller meinen, der Servoimpulse generiert, dann schau mal hier: http://www.hanneslux.de/avr/mobau/7ksend/7ksend02.html Du kannst ja die ADC-Abfrage rauswerfen und dafür eine alternative Bereitstellung der Servosollwerte einbauen. ...
Hallo, an dieser Begriffsverwirrung mag auch teilweise die geringe Resonanz bei einem so einfachen Problem liegen ;) Jedenfalls plane ich zweiteres, naemlich eine Ansteuerung von 16 Servos aus einem uC. Bei obigem Code beeinflussen sich die Werte jedoch gegenseitig, und ich weiss nicht, warum... Nun brauche ich den uC allerdings noch fuer andere Aufgaben als die Servoansteuerung, sonst waere die Sache kein Problem - haette es dann genauso implementiert wie Du bei der RC-Sache, naemlich mit (wenn ich es ohne RC-Wissen richtig verstanden habe) sequentieller Abfrage der Werte und Erzeugung der Impulse fuer jeden Kanal. Dabei ist der Controller leider voll ausgelastet, das faellt also weg; gibt auch Probleme mit der Kommunikation ueber z. B. UART, wenn wg. Interrupt ploetzlich der Puls ausbleibt... Darum ist mein Ansatz eben, alle 16 Servos zur gleichen Zeit anzusteuern - dazu muss ich allerdings in der variablem ms des Pulses alle 255 moeglichen Positionen fuer alle Motoren abfragen und regeln, was zwar auf nur etwa 5% Auslastung insgesamt hinauslaeuft, aber nicht leicht zu implementieren ist. Graphisch: statt: will ich: |"|______ ___|"|___ Servo1 __|"|____ ___|"|___ Servo2 ____|"|__ ___|"|___ Servo3 ... Zwischen den Pulsen ist also voellig ungenutzte Zeit, sollte also das Restprogramm nicht stoeren. Ich hoffe, die Sache ist jetzt etwas verstaendlicher - waere nicht schlecht, ich steig naemlich echt nicht dahinter, was das Problem sein sollte. Leider hab ich kaum ASM-Erfahrung, bin GCC-Fan und versuche mich das erste mal an geschwindigkeitsoptimiertem Code. Gruss und Danke, David
> Dabei ist der > Controller leider voll ausgelastet, Das ist aber nicht der Fall. Der Controller verbringt die meiste Zeit im Sleep-Mode Idle. Es sind also noch enorme Reserven an Rechenzeit vorhanden, die Mainloop darf also noch drastisch wachsen. Zeitkritische Sachen synchronisiert man vorteilhaft mittels Timer-Interrupt. Das vermeidet rechenzeitfressende Warteschleifen. Mein Vorschlag: Nimm den Interrupt von Timer0, um alle 20ms eine Sequenz anzustoßen und eventuelle mechanische Kontakte (z.B. Taster zu entprellen). Dann hast du beide Compare-Interrupts von Timer1 frei. Nun teilst du deine 16 Impulse in zwei Gruppen auf, von denen die eine von Compare1A und die andere von Compare1B sequentiell abgearbeitet wird. Die Sollwerte für die Impulsbreite entnimmst du dabei dem SRAM. Somit läuft die gesamte Impulserzeugung im Interrupt und dein Hauptprogramm kann sich um die Generierung der Sollwerte kümmern. Ich denke mal, dass der Mega16 das mit 1MHz Takt locker schafft und mehr als die Hälfte seiner Zeit im Sleepmode vertrödelt. Wenn du C wirklich beherrscht (ich kann es nicht), dann kannst du das in C genauso effizient programmieren wie ich in ASM. ...
// Timer 1 output compare interrupt service routine interrupt [TIM1_COMP] void timer1_comp_isr(void) {static unsigned char servo_nr; PORTB=output_mask[servo_nr]; //alten Impulsausgang löschen, neuen setzen OCR1=servo_zeit[servo_nr]; //neue Impulszeit if (servo_nr<9) servo_nr++; else servo_nr=0; } Das ist im Prinzip schon alles und läuft im Hintergrund, du merkst kaum was davon. Ist für 8 Servos am PortB. Die Zeiten stehen in servo_zeit[0..7], die Restzeit zu 20ms in servo_zeit[8]. Und noch Timer1_init: // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 1000,000 kHz // Mode: Output Compare // OC1 output: Discon. // Timer 1 is cleared on compare match // Noise Canceler: Off // Input Capture on Falling Edge TCCR1A=0x00; TCCR1B=0x0A; TCNT1H=0x00; TCNT1L=0x00; OCR1H=0xf0; OCR1L=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0xC0;
Ham' wir wieder was gelernt, diesen Betriebsmodus kannte ich noch gar nicht :) Kenne leider niemanden, der Ahnung von uCs hat, und bin noch nicht selbst drueber gestolpert (sollte mich wohl mehr hier aufhalten statt im RN). Dann hat das Projekt schonmal seinen Zweck erfuellt. Danke, David
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.