Forum: Mikrocontroller und Digitale Elektronik Servo per PIC ansteuern ohne PWM


von Kevin H. (linuxjohnny)


Lesenswert?

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

von Gast (Gast)


Lesenswert?

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.

von Kevin H. (linuxjohnny)


Lesenswert?

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

von STK500-Besitzer (Gast)


Lesenswert?

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.

von Jochen.L. (Gast)


Lesenswert?

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.

von Björn R. (sushi)


Lesenswert?

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

von Kevin H. (linuxjohnny)


Lesenswert?

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

von Saimen (Gast)


Lesenswert?

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

von usuru (Gast)


Lesenswert?

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

von Master S. (snowman)


Lesenswert?

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

von Master S. (snowman)


Lesenswert?

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