Hi, Zurzeit bin ich an einem Projekt beteiligt, wo es darum geht eine Roboter Spinne zu programmieren. Im letzen Jahr wurden die Befehle für die Servos vom PC über ein Servocontroller Board geschickt, in diesem Jahr haben wir uns vorgenommen der Spinne eine "Inteligenz" zu verschaffen, und sie mit einem Microcontroller auszustatten, gesagt getan, die Hardware wurde auf einen neu entwickelten Print gemacht. Wir haben auf diesem Print einen PIC18F2620(nicht ganz sicher werde noch nachschauen), und 14 Servos die angesteuert werden müssen. Dazu gibt es ja bekanntlich nicht genug PWM Ausgänge. Nun müssten wir die Servos ja über "normale" I/O's ansteuern. Die Digital Servos reagieren auf Impulse zwischen 0.5 ms und 2.0 ms, jetzt habe ich ghört sobald so ein Signal geschickt wurde muss eine Pause von 20ms eingelegt werden, wieso das? Kann mir jemand erklären wie man genau so ein Signal bzw. Frequenz erzeugt? Super wäre es natürlich gleich in C :D Braucht man dazu einen Timer? Wenn ja wie wird dieser "eingeschaltet" etc. ? Um eine Antwort wäre ich euch sehr dankbar! Grüsse linuxjohnny
Die Impulslänge von Standard-Servos ist 0,9-2,1ms. Die Pause liegt bei
Normal-Servos zwischen 15 und 25ms. Moderne Servos verkraften auch
>=6ms.
Die 14 Servos teilst du am besten in zwei Gruppen a 7 Stück. Jede Gruppe
bekommt einen Timer.
Die jeweils 7 Servos bekommen nacheinander ihren Impuls. Jeder Timer
erzeugt also nacheinander die Impulse für 7 Servos. Dann legt er eine
Pause ein um auf mehr als 15ms Zykluszeit zu kommen.
Hmm vielleicht muss ich noch genauer erklären für was die einzelnen Servos gebraucht werden. Und zwar sind 6 Servos also je 3 auf einer Seite für die Horizontale bewegung der Beine zuständig und die anderen 6 wieder aufgeteilt auf je 3 auf jeder Seite für die Vertikale bewegung, die anderen beiden sind für den Kopf und die Zange die am Kopf befestigt ist. Dann müssten die Servos wohl anders gruppiert werden, was aber eigentlich meine Frage ist, wie sieht den der genaue Ablauf aus wenn man einen Servo ansteuern will. Ich stelle mir das so vor: Impuls auf Rxx von 1.5 ms --> Pause von 20 ms --> Impuls auf Rxx von 1.9 ms So sollte sich doch der Servo von 1.5ms auf 1.9ms verstellen bzw. einfach die Positions ändern das er nicht auf 1.9 ms fährt ist mir klar :P Theoretisch wäre dies doch so, aber wie kann ich dies in C realisieren? Gibt es da Lösungsansätze? Ich habe jetzt mal versucht einen Programmcode zu compilieren leider ist mir dies nicht gelungen und mit folgender Fehlermeldung abgebrochen:
1 | ---------------------------------------------------------------------- |
2 | Debug build of project `C:\Dokumente und Einstellungen\khaag\Eigene Dateien\PIC\Source\Projekt Spinne 2009\Projekt Spinne 2009.mcp' started. |
3 | Language tool versions: mplink.exe v4.30.01, mcc18.exe v3.30 |
4 | Preprocessor symbol `__DEBUG' is defined. |
5 | Sat Oct 24 14:50:12 2009 |
6 | ---------------------------------------------------------------------- |
7 | Make: The target "C:\Dokumente und Einstellungen\khaag\Eigene Dateien\PIC\Source\Projekt Spinne 2009\main.o" is out of date. |
8 | Executing: "C:\MCC18\bin\mcc18.exe" -p=18F452 "main.c" -fo="main.o" -D__DEBUG -w3 -Ou- -Ot- -Ob- -Op- -Or- -Od- -Opa- |
9 | C:\Dokumente und Einstellungen\khaag\Eigene Dateien\PIC\Source\Projekt Spinne 2009\main.c:7:Error: syntax error |
10 | Halting build on first failure as requested. |
11 | ---------------------------------------------------------------------- |
12 | Debug build of project `C:\Dokumente und Einstellungen\khaag\Eigene Dateien\PIC\Source\Projekt Spinne 2009\Projekt Spinne 2009.mcp' failed. |
13 | Language tool versions: mplink.exe v4.30.01, mcc18.exe v3.30 |
14 | Preprocessor symbol `__DEBUG' is defined. |
15 | Sat Oct 24 14:50:12 2009 |
16 | ---------------------------------------------------------------------- |
17 | BUILD FAILED |
Source Code
1 | /////////////////////////////////////////////////////// |
2 | //Datum: 24.10.2009 // |
3 | //Funktion: Hauptprogramm zur Steuerung von Phoenix 2// |
4 | /////////////////////////////////////////////////////// |
5 | |
6 | //Deklarationen |
7 | bit servo01 @PORTB.4; |
8 | bit servo02 @PORTB.3; |
9 | bit servo03 @PORTB.2; |
10 | bit servo04 @PORTB.1; |
11 | bit servo05 @PORTB.1; |
12 | bit servo06 @PORTB.1; |
13 | bit servo07 @PORTB.1; |
14 | bit servo08 @PORTB.1; |
15 | bit servo09 @PORTB.1; |
16 | bit servo10 @PORTB.1; |
17 | bit servo11 @PORTB.1; |
18 | bit servo12 @PORTB.1; |
19 | bit servo13 @PORTB.1; |
20 | bit servo14 @PORTB.1; |
21 | |
22 | |
23 | void init(void){ |
24 | //TRISA = 0b.1111.1111; //1 entspricht Eingang |
25 | TRISB = 0b.0000.0000; //0 entspricht Ausgang |
26 | } |
27 | |
28 | void delay(void){ |
29 | uns16 i; |
30 | uns16 k; |
31 | for(i = 0; i <= 400; i++) |
32 | { |
33 | k=k+1; |
34 | } |
35 | } |
36 | |
37 | void main(void){ |
38 | init(); |
39 | while(1){ |
40 | } |
41 | } |
Denn Code habe ich früher für einen PIC aus der 16Fxxx Reihe gebraucht. Könnte es sein das es für den 18Fxxxx eine andere Syntax gibt oder so? P.S. Der PIC ist ein 18F2525 Grüsse linuxjohnny
Guck mal bitte bei voidpointer.de vorbei. Die Sachen sind zwar für den AVR, sollten sich aber auch für den PIC adaptieren lassen. >Impuls auf Rxx von 1.5 ms --> Pause von 20 ms --> Impuls auf Rxx von 1.9 >ms Hä? Mach es wie Modellfernsteuerungen: Erzeuge einen Puls mit der für das Servo gewünschten Impulslänge und schaltet während dieser Zeit den zugehörigen Steuerausgang ein. Wenn der Impuls zuende ist, wird die Impulsdauer für das nächste Servo eingestellt und der dazugehörige Steuerausgang eingeschaltet. Das macht man der Reihe nach und dann wieder von vorne... Ich bin in PIC-Sachen nicht bewandert, weswegen ich nur allgemeine Aussagen treffen kann. Aber wenn dein PIC einen oder zwei Timer hat, dann ist die Aufgabe sehr leicht zu lösen. Wie die Servos gruppiert werden, dürfte völlig egal sein.
Also, die Pause von 20ms kommt vermutlich einfach daher, das eine klassische Modellbau Fernsteuerung alle Kanäle in ein Telegramm packt, wo auf die (kurzen) Impulse der einzelnen Kanäle eine Pause (bzw. ein ganz langer Impuls) von ca. 10ms folgt. Diser dient als Startmarkierung für das nachfolgende Telegramm. Daraus resultiert für die Zykluszeit jedes einzelnen Impulses eine Zeit von ca.20ms. Könnte aber gut sein, das ein Servo auch mit kürzerer Wiederholzeit funktioniert.
Deine Lösung heißt Soft-PWM! Such mal nach dem Stichwort. Der bereich für Servos ist per Definition 1-2ms, nicht 1,9 bis 2,1. Die HErsteller gehen damit aber unterschiedlich um. Graupner-Anlagen senden von 0,9-2,1, Multiplex glaube ich sogar noch weiter. Außerdem kann man an den meisten Sendern die Servowege bis auf +-150% verlängern. Da probierst du am besten aus, was am besten zu den verbauten Servos passt bzw. wie weit sich die Servos i9n deinem Roboter überhaupt bewegen müssen. Siehe auch: www.sprut.de LG, Björn
Danke für eure Tipps, Wenn ich das jetzt richtig verstehe, sende ich z.B. auf PORTA.0 einen Impuls, bzw. schalte den Port für 1.5ms ein. Und schalte ihn danach wieder auf 0, während dem der Port auf 1 ist sollte sich der Servo bewegen, stimmts? Und danach muss eine Pause eingelegt werden um einen neuen Impuls für den gleichen Servo zu schicken? Gilt dies auch wenn ich einen anderen Servo ansprechen will? Ich habe herausgefunden das man die Ports nicht so definieren kann, weil der Compiler das nicht mitmacht, wisst Ihr wie ich einem Port z.B. PORTA.0 den Namen servo01 geben kann? Mit dem C5xx, oder so, Compiler hat dies eben so funktioniert. xD Grüsse linuxjohnny
versuch doch einfach in asm deine servos zu deklarieren... MPLAB: __asm #define PORTA, 0 Servo0 #define PORTA, 1 Servo1 #define PORTA, 2 Servo2 #define PORTA, 3 Servo3 usw... #global Servo1; Servo2; Servo3; usw... __endasm da sie jetzt Globalisiert sind kannste die einfach in C ansprechen....
Wenn Du so viele PWM-Kanäle brauchst, kannst Du ja einen PIC suchen, der viele Timer hatr, bei den PIC18Fxxxx kannst Du bis zu 6x 8-bit-Timer und bis zu 5x 16-bit-Timer haben. Anbei der Link zum parametric search, die Timer sind ganz unten http://www.microchip.com/ParamChartSearch/params.aspx?mid=10&lang=en&branchID=1004
mach's doch einfach mit 1 bis 2 timer so wie's "STK500-Besitzer" gesagt hat oder so wie "Gast" es vorgeschlagen hat. wenn der PIC nichts anderes tun muss, so kannst du auch quick-and-dirty programmieren wie so: timer1_interrupt() { // timer1 interrupt alle 100us CountPause++; // global und ist typ "unsigned int" if (CountPause > 200) { // 200*100us = 20ms pause sind verstrichen CountServo++; // global und ist typ "unsigned char" if (CountServo < value0) Servo0 = 1; else Servo0 = 0; if (CountServo < value1) Servo1 = 1; else Servo1 = 0; ...usw... } if (CountServo > 200) { // ein neuer zyklus beginnt CountPause = 0; CountServo = 0; } } leider bin ich jetzt aus den zeiten, die deine servos haben müssen, nach all den vielen korrekturen immer noch nicht schlau geworden, was richtig ist, aber diese quick-and-dirty-idee lässt sich ja einfach anpassen ;-)
mit meinem code und den interruptzeiten hast du für die servos eine auflösung von 0..100. wenn eine feinere auflösung brauchst, müssen wir den code optimieren: interrupt häufiger aufrufen, if-anweisungen besser schreiben etc. aber das macht keinen sinn solange die zeiten für deine digitalen servos noch nicht geklärt sind.
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.