Forum: Mikrocontroller und Digitale Elektronik Roboterarm mit Pic18F4580


von daniel o. (ineedhelp)


Lesenswert?

Hallo alle zusammen,

ich habe gerade ein kleines Projekt am laufen, und zwar baue ich einen
Roboterarm mit Servomotoren. Die Ansteuerung erfolgt über einen Pic
18F4580. Ich bin was Microcontroller betrifft noch ein Anfänger. Die
Ansteuerung in prog #1 funktioniert eigentlich, ich bin aber auf ein
Problem gestoßen. Das liegt darin, dass der Servo die vorgegebenen
Positionen zwar anfährt, aber jedoch keinerlei  Halt- und Stellkraft
hat.

Zu testzwecken habe ich ein programm  #2 geschrieben, indem die servos
über das Auslesen eines potiwertes angesteuert werden (wie bei der
fernbedienung). Bei dieser variante hat der servo eine enorme kraft so
wie es sein sollte. Warum hat er diese nicht auch in programm #1 ? und
kann ich die stellgeschwindigkeit beeinflussen, und wenn ja wie? ich
zeige euch hier mal die 2 programme.


Prog #1: Ansteuerung über ziffernblock (jede ziffer hat eine vorgegebene
servostellung)

void servo_1_links (void)
{   Output_high (pin_C5);
  delay_us(2000);
  Output_low  (pin_C5);
  delay_us(18000);
}

void servo_1_mitte (void)
{  Output_high (pin_C5);
  delay_us(1750);
  Output_low  (pin_C5);
  delay_us(18000);
}

void servo_1_rechts (void)
{  Output_high (pin_C5);
  delay_us(1500);
  Output_low  (pin_C5);
  delay_us(18000);
}
void main(void)

{  while (true)
  {
    taste = keypad(taste);
    switch(taste)
    {
    case 1:    servo_1_links();      break;
    case 2:    servo_1_mitte();      break;
    case 3:    servo_1_rechts();      break;
    }
    //  delay_ms(100);   (funktioniert auch mit verweilzeit nicht)
  }

}
___________________________________________


Prog #2: Ansteuern über ausgelesenen potiwert (ad wandlung eines poties
welcher auf der platine sitzt )

void ADC (void)
{
        setup_adc_ports(PIN_a0);        //ADC-Pin analog input
  set_adc_channel(0);    //Kanalauswahl
  delay_us(10);      //Hier Zeitverzögerung!
  AD_Wert=read_adc();    //Wandlungsergebnis holen...
  setup_adc_ports(NO_ANALOGS);  //Alle Eingänge digital
}

void main(void)
{
  lcd_init();
  setup_adc(ADC_CLOCK_INTERNAL);
  while (true)
{
    ADc();        // fkt aufruf adc
    x=_mul(ad_wert, 6);       // eigentliche multifakt. 5,4078
    y=x+800;      //  add 800
                Output_high (pin_c5);
    delay_us(y);    // var positionierung
    Output_low  (pin_C5);
    delay_us(18000);

}

}


Ich hoffe die schilderung meines problems ist verständlich… wäre sehr
dankbar wenn mir hierbei  jemand weiterhelfen könnte, vielen dank
schonmal im voraus

von Jonas B. (jibi)


Lesenswert?

Bei Version2 wird immer pin_C5 getoggelt, bei der ersten Version halt 
nur wenn du ne Taste drückst. Wenn du da noch einen ansonsten Fall, 
nämlich falls kein Button gedrückt = tue dass..., dann sollte es funzen. 
Ob man das generell so machen sollte, wage ich mal zu bezweifeln...

Gruß Jonas

von holger (Gast)


Lesenswert?

taste = keypad(taste);
    switch(taste)
    {
    case 1:    servo_1_links();      break;
    case 2:    servo_1_mitte();      break;
    case 3:    servo_1_rechts();      break;
    }

Wenn taste keinem deiner case entspricht wird auch
keine deiner Funktionen aufgerufen. Sprich: Der Servo
bekommt kein Signal.

von daniel o. (ineedhelp)


Lesenswert?

@ Jonas

erstmal danke für deine antwort,

aber wenn wie in prog 2 eine taste gedrückt wird hängt er die ganze zeit 
in der schleife für die jeweilige position bis etwas anderes gedrückt 
wird, oder liege ich da falsch ?

wie würdest du das generell machen ?

von daniel o. (ineedhelp)


Lesenswert?

@ holger

"Wenn taste keinem deiner case entspricht wird auch
keine deiner Funktionen aufgerufen. Sprich: Der Servo
bekommt kein Signal."


--> der case trift ein wenn ich die entsprechende taste drücke

von Jonas B. (jibi)


Lesenswert?

Holger hat das gleiche gemeint wie ich. Um dir wirklich helfen zu 
können, müsstest du mal mal näher beschreiben, was du genau vorhast. 
Meine Glaskugel ist kaputt. Also in etwa so, ich hab ein Tastaturfeld, 
ich hab x Servos die ich über m/eine Software-delay-Geraffel PWM 
ansteuern will...

Gruß Jonas

von holger (Gast)


Lesenswert?

>--> der case trift ein wenn ich die entsprechende taste drücke

Sicher, aber hältst du sie dann auch fest?
Bist du sicher das taste beim festhalten auch weiter
einen Wert liefert der für deine case zutrifft?

Was passiert wenn du das machst:

Am Anfang von main diese Variable definieren:
    unsigned int position = 1750;
1
    taste = keypad(taste);
2
    switch(taste)
3
    {
4
    case 1:    position = 2000;      break;
5
    case 2:    position = 1750;      break;
6
    case 3:    position = 1500;      break;
7
    }
8
9
  Output_high (pin_C5);
10
  delay_us(position);
11
  Output_low  (pin_C5);
12
  delay_us(18000);

von daniel o. (ineedhelp)


Lesenswert?

also ich baue einen 5-achsigen roboterarm der vorgegebene positionen 
anfahren soll. das heißt ich muss 5 sevos gleichzeitigt ansteuern.
die positionen werden zwar angefahren ,aber die motoren haben keine 
kraft.
wenn ich die jeweilige taste gedrückt halte ändert das nicht..

@ holger ich werde deine variante gleich mal testen
 für die anderen motoren benutze ich dann einfach weitere vaiablen- wie 
position 2, 3 , 4...wenn ich das richtig verstanden habe

von Jonas B. (jibi)


Lesenswert?

> das heißt ich muss 5 sevos gleichzeitigt ansteuern.

Das gibt ein Problem mit deinen delay_us Aufrufen zur PWM Erzeugung. 
Wenn du die gleichzeitig generieren willst, klappt das mit deiner 
Programmierung nicht. Such mal in deinem Mikrocontroller Handbuch nach 
Timer und PWM. Meist kann man mit dem Timer auch eine PWM erzeugen und 
das auf mehreren Pins gleichzeitig. Dann musst du die Timertopwerte 
(erklärt sich, wenn du das Handbuch liest) nur noch pro Taster mit 
passenden Werten neu laden und voila ;)

Gruß Jonas

von Jonas B. (jibi)


Lesenswert?

• One Capture/Compare/PWM (CCP) module
• Enhanced Capture/Compare/PWM (ECCP) module (40/44-pin devices only):
- One, two or four PWM outputs
- Selectable polarity
- Programmable dead time
- Auto
-shutdownandauto-restart

Auszug aus dem Datenblatt deines Controllers, da gibt es also definitiv 
PWM-Hardware. Nun also damit beschäftigen, hoffentlich habt ihr die 
richtigen Pins geroutet (wahrscheinlich nicht ?! ;) )...

Gruß Jonas

von holger (Gast)


Lesenswert?

>@ holger ich werde deine variante gleich mal testen
> für die anderen motoren benutze ich dann einfach weitere vaiablen- wie
>position 2, 3 , 4...wenn ich das richtig verstanden habe

Die wird nur mit einem Servo funktionieren.
Also nimm auch erstmal nur einen Servo.
Ansonsten siehe die Antworten von Jonas.
Mit den Delays wird das nix bei fünf Servos.

von daniel o. (ineedhelp)


Lesenswert?

@ holger

ich habe deine variante mit einem servo getestet. das verhalten des 
motors ist leider das selbe wie in meinem programm.
ich denke es liegt wohl wirklich daran dass die tasten nicht weiterhin 
werte liefern nach ein oder mehrmaligem drücken..

@jonas

also mit pwm habe ich noch nie etwas gemacht, aber werde mich da 
reinarbeiten
und das mal testen
_____

leute ich danke euch dass ihr euch die zeit genommen habt mir zu helfen. 
ich werde euch auf dem laufenden halten :)

von D. S. (datasheet)


Lesenswert?

Schonmal in die Codesammlung geschaut?
Beitrag "Servo Ansteuerung in C mit Timer0"
Sieht ganz vielversprechend aus.
Nochne Möglichkeit ist ein Baustein wie der Tlc5940 der kann PWM auf 16 
Kanälen und wird ganz einfach über SPI gefüttert.

von Martin H. (martinhaag)


Lesenswert?

Hallo Daniel,

ich habe eine Spinne mit 12 Servos gebaut. Diese wurden von 2 Pics (je 6 
pro pic) auch mit "Delay-Anweisungen" gesteuert und hat gut geklappt, 
allerdings musst Du das Programm etwas anders aufbauen. meine Lösung:

(Sinnfreies Beispiel für 3 servos)

position_servo1=150; // diesen positonswert änderst du mit den tasten
position_servo2=160;
position_servo3=170;

start

Output_high (pin_C1); //servo1
Output_high (pin_C2); //servo2
Output_high (pin_C3); //servo3

for schleife = 1 to 200
  if schleife == position_servo1
    Output_low (pin_C1); //servo1
  if schleife == position_servo2
    Output_low (pin_C1); //servo2
  if schleife == position_servo3
    Output_low (pin_C1); //servo3
next

delay_us(18000); // hier kannst du zB die Tastenabfrage reinpacken

goto start;

ACHTUNG, die Positonswerte entsprechen nicht mehr einer fixen Zeit 
sondern sind von der dauer der schleife abhängig. Das heisst entweder 
berechnen oder try und error, letzteres geht ziemlich gut. Ausserden 
verlierts du etwas an Auflösung, das war in meinem Fall irrelevant. Ich 
hoffe das war einigemassen verständlich, sonst bei interesse nachhaken.

Viel Erfolg

von Kein Name (Gast)


Lesenswert?

Das ist mit 5 Servos nicht so einfach.

Du brauchst die ganze Zeit über Impulse ohne Jitter.
- Ohne Impulse bekommst du dein Problem.
- Ungleichmäßige Impulse -> Die Servos summen und die Batterie ist 
sofort leer.

Für 2 Servos gibt es eine trickreiche Routine mit dem Timer im 
Compere-Mode (PWM Mode hat zu wenig Auflösung). Bei 5 musst du aber die 
Pins in der ISR setzen. Im Prinzip kannst du die Strategie von Martin 
Haag mit einem Timer im Compare-Modus umsetzen. Im High-Priority 
Interrupt. Damit der Jitter klein bleibt, muss aber alles andere 
Low-Priority laufen.

von Jonas B. (jibi)


Lesenswert?

>also mit pwm habe ich noch nie etwas gemacht, aber werde mich da
>reinarbeiten
>und das mal testen

Das sehe ich anders, immerhin haste du ja schon eine implementiert, dass 
war dir nur nicht klar :) :

  >Output_high (pin_C5);
  >delay_us(2000);
  >Output_low  (pin_C5);
  >delay_us(18000);

Nur das ganze kann auch die Hardware für dich machen, aber da liest du 
dich ja bestimmt gerade ein...

Gruß Jonas

von Lehrmann M. (ubimbo)


Lesenswert?

Ich halte eine Ansteuerung von mehr als 2 Servos ohne Timer 
grundsätzlich für problematisch bzw. einfach inkorrekt. Die Delays sind 
so und so eine fragwürdige Sache und können sinnvoll eigentlich nur in 
Initialisierungsroutinen verwendet werden, während weder Benutzer noch 
Sensorik / Regelungstechnik einen Einfluss auf den Programmablauf hat. 
Beispiel: Initialisierung eines Displays beim Einschalten eines Gerätes. 
Ansonsten blockieren die Delays ja entweder Alles oder sie sind (weil 
Interrupts zugelassen werden) nicht zeitlich konstant. Darum gibt es 
eine geniale Erfindung und die nennt sich Timer + Interrupt. Auch wenn 
es einem als Anfänger schwer fällt sich in dem Gewirr zu Recht zu 
finden, sollte man DRINGENDST diese Thematik beherrschen. Dazu 
empfehle ich als Einstieg: 
http://www.sprut.de/electronic/pic/grund/timer/timer.htm
Danach kann man einen Blick ins Datenblatt werfen und damit dann auch 
die Blockschaltbilder der Timer-Module verstehen. Zur Servospezifischen 
Ansteuerung empfehle ich diesen Artikel (gesamt für Grundlagen), ganz 
besonders aber diesen Abschnitt: 
http://www.mikrocontroller.net/articles/Modellbauservo_Ansteuerung#Signalerzeugung_f.C3.BCr_mehrere_Servos_mittels_Timer_.28C.29
Die Register heißen ein wenig anderst aber von der Methodik alles gleich 
...

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.