Forum: Mikrocontroller und Digitale Elektronik Arduino Servo.Detach() Problem


von Philipp G. (geiserp01)


Lesenswert?

Hallo zusammen

Ausgangslage

- Arduino Nano
- Zwei digitale Servos
- Zwei Schaltregler

Der eine Schaltregler stellt die +5V für den Nano bereit, der andere 
dient als Versorgungsspannung für die Servos.

Wenn Pin2 auf HIGH gelegt wird, bewegen sich beide Servos simultan auf 
Position (a). Bei LOW gehen diese wieder in die Ausgangsstellung, die 
Position (b).

In beiden Positionen, sowohl (a) als auch (b), soll die Position nicht 
von den Servos gehalten werden. Um das zu erreichen, arbeite ich mich 
den Befehlen Servo.attach und Servo.deatach.

Das funktioniert.

Versuchsaufbau

Um die Anwendung zu testen, habe ich einen Versuchsaufbau mit einem 
Labornetzgerät und einer elektronischen Last aufgebaut. Die 
elektronische Last lässt sich programmieren. In meinem Aufbau tut diese 
nichts anderes, als alle 10 Sekunden Pin2 zu invertieren.

Problembeschreibung

Von 20-30 Bewegungen fällt eine aus. Die nächste erfolgt dann natürlich 
wieder 10 Sekunden später. Hierbei ist kein Muster erkennbar, es kann 
fünf Mal funktionieren, dann eine Bewegung ausfallen, oder 30 Mal 
hintereinander funktionieren. Im Schnitt komme ich auf die erwähnten 
20-30 Bewegungen. Das betrifft immer beide Servos, also beide 
Ausgänge.

Vorgehensweise zur Lösung

@ Die Servos ziehen unter Last zusammen max. 800mA. Das Labornetzgerät 
liefert 3A. Mit DSO kein Spannungsabfall zu beobachten. Auch Versuche 
mit C's am Ein- und Ausgang der Schaltregler haben keine Besserung 
gebracht.

@ Das PWM Signal sieht auf dem DSO so aus, wie es sein soll. Keine 
Auffälligkeiten zu erkennen.

->

Ich denke hier liegt eher ein Problem im Coding vor. Wenn der Befehl 
Servo.detach ausgeführt wird, wird der Pin der PWM geführt hat 
freigegeben. Meine Vermutung, bei Servo.attach ein paar Millisekunden 
warten, bis sich der PWM Timer reinitialisiert hat, oder den Timer 
direkt initialisieren.

Hat jemand eine Idee?

Ich freue mich auf sachliche Antworten.

Gruss, Philipp

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Seufz...
Wie wäre es mit dem Programm?

von Philipp G. (geiserp01)


Lesenswert?

Auf das Programm an sich habe ich hier leider grad keinen Zugriff. Es 
lässt sich leicht auf das folgende reduzieren:


Loop
{
if (Pin2 == high)
{
  Servo.attach;
  Servo.write(90);
  Servo.detach;
}
else
{
  Servo.attach;
  Servo.write(0);
  Servo.detach;
}
}

von Stefan F. (Gast)


Lesenswert?

Du musst vor dem detach ausreichend lange warten, damit die Servos sich 
zur Zielposition hin bewegen können.

von Vka (Gast)


Lesenswert?

Philipp G. schrieb:
> Hat jemand eine Idee?

Ich würde da einfach die PWM weiter laufen lassen und den Pin über DDRx 
abschalten. Ggf. dazu noch einen Pulldown.

von Philipp G. (geiserp01)


Lesenswert?

Stefan U. schrieb:
> Du musst vor dem detach ausreichend lange warten, damit die Servos
> sich zur Zielposition hin bewegen können.

Das Programm wartet, bis Servo.read >= iEndPos.

@vka: Was meinst du mit DDRx?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Philipp G. schrieb:
> @vka: Was meinst du mit DDRx?

Das Richtungsregister des PWM Ports. Ohne in die Konfiguration der PWM 
einzugreifen, kann man durch Umschalten des Signalpins auf Eingang die 
PWM abschalten.

von Stefan F. (Gast)


Lesenswert?

> Das Programm wartet, bis Servo.read >= iEndPos.

Wo denn? Ich sehe dazu keinen Hinweis im Quelltext.

Es geht doch um RC Modellbau Servos und die dazugehörige Arduino Klasse, 
oder etwa nicht?

Diese RC Modellbau Servos haben keinen Rückkanal, deren aktuelle 
Positionen kann man nicht auslesen. Dir bleibt daher nur die 
Möglichkeit, zu schätzen, wie lange die Servos bis zum Erreichen der 
Soll-Position brauchen, bevor du das Signal abschaltest.

Wenn du meinst, dass ich hier auf einem Irrweg bin, dann zeige deinen 
Schaltplan, das Programm, einen Link auf die verwendete Library und 
einen Link auf die Produktbeschreibung der Servos.

von Philipp G. (geiserp01)


Lesenswert?

Stefan U. schrieb:
> Wo denn? Ich sehe dazu keinen Hinweis im Quelltext.
>
> Es geht doch um RC Modellbau Servos und die dazugehörige Arduino Klasse,
> oder etwa nicht?

Das ist korrekt.

Stefan U. schrieb:
> Diese RC Modellbau Servos haben keinen Rückkanal, deren aktuelle
> Positionen kann man nicht auslesen. Dir bleibt daher nur die
> Möglichkeit, zu schätzen, wie lange die Servos bis zum Erreichen der
> Soll-Position brauchen, bevor du das Signal abschaltest.

Nun ja, Ich gehe davon aus, die Servo.read Funktion wertet das PWM 
Signal aus, nicht die tatsächliche Position der Servos. Aber mechanisch 
ist ja alles in Ordnung. Das Problem ist nach wie vor, dass manchmal 
nach dem Detach Befehl es zu Ausfällen kommt.

Stefan U. schrieb:
> Wenn du meinst, dass ich hier auf einem Irrweg bin, dann zeige deinen
> Schaltplan, das Programm, einen Link auf die verwendete Library und
> einen Link auf die Produktbeschreibung der Servos.

Ich verwende die folgenden Libs:

#include <Servo.h>
#include "ServoEaser.h"
https://github.com/todbot/ServoEaser/blob/master/ServoEaser.h

Ich habe nun die Funktion reinit() eingefügt, leider hat dies nicht den 
gewünschten Erfolg gebracht:

head
1
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
2
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
3
#include <Servo.h>
4
#include "ServoEaser.h"

Loop
1
void loop()
2
{
3
  if (digitalRead(iIGNPlusPin) == HIGH)
4
  {
5
     if (bIsOpen == false)
6
           {
7
           unsigned long currentMillis = millis();
8
           if (bAttached == false)
9
           {
10
              reinit;
11
              SrvRight.attach(10);
12
              SrvLeft.attach(9);
13
              bAttached = true;
14
              previousMillis = millis();
15
           }
16
           if( servoEaserL.hasArrived()) 
17
           {
18
            lastMillis = millis();
19
            servoEaserL.easeTo(180 - iEndPos, 1700);
20
            servoEaserR.easeTo(iEndPos, 1700);
21
           }
22
           //Serial.println(SrvRight.read());
23
           //if ((unsigned long)(currentMillis  - previousMillis) >= interval)
24
           if (SrvRight.read() >= iEndPos)
25
           {
26
                SrvRight.detach(); 
27
                SrvLeft.detach();
28
                previousMillis = millis();
29
                bIsOpen = true;
30
                bAttached = false;
31
           }
32
     }
33
  }
34
else

reinit:
1
void reinit()
2
{
3
  TCCR1B = 0;
4
  // set timer 1 prescale factor to 64
5
  sbi(TCCR1B, CS11);
6
  sbi(TCCR1B, CS10);
7
  // put timer 1 in 8-bit phase correct pwm mode
8
  sbi(TCCR1A, WGM10);
9
}

Matthias S. schrieb:
> Das Richtungsregister des PWM Ports. Ohne in die Konfiguration der PWM
> einzugreifen, kann man durch Umschalten des Signalpins auf Eingang die
> PWM abschalten.

Steh immer noch auf dem Schlauch. Kannst Du mir bitte ein Beispiel 
machen?

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Philipp G. schrieb:
> Steh immer noch auf dem Schlauch. Kannst Du mir bitte ein Beispiel
> machen?

Gibts in meinem Frequenzumrichter:
https://www.mikrocontroller.net/articles/3-Phasen_Frequenzumrichter_mit_AVR

Ich zitiere:
1
// from vfd.h
2
//! Bit pattern of PWM pins placed on PORTB.
3
#define PWM_PATTERN_PORTB   ((1 << PB1) | (1 << PB2) | (1 << PB3))
4
5
//! Bit pattern of PWM pins placed on PORTD.
6
#define PWM_PATTERN_PORTD   ((1 << PD3) | (1 << PD5) | (1 << PD6))
7
// in main.c
8
/*! \brief Enables PWM output pins
9
 *
10
 *  This function enables PWM outputs by setting the port direction for
11
 *  all PWM pins as output. The PWM configuration itself is not altered
12
 *  in any way by running this function.
13
 */
14
static void EnablePWMOutputs(void)
15
{
16
  DDRB |= PWM_PATTERN_PORTB;
17
  DDRD |= PWM_PATTERN_PORTD;
18
}
19
/*! \brief Disables PWM output pins
20
 *
21
 *  This function disables PWM outputs by setting the port direction for
22
 *  all PWM pins as inputs, thus overriding the PWM. The PWM configuration
23
 *  itself is not altered in any way by running this function.
24
 */
25
static void DisablePWMOutputs(void)
26
{
27
  DDRB &= ~PWM_PATTERN_PORTB;
28
  DDRD &= ~PWM_PATTERN_PORTD;
29
}
Hier werden alle 6 PWM Ausgänge ein- bzw. ausgeschaltet, die im Projekt 
benutzt werden. Bei dir ist das nur ein Bit pro Servo.

von Philipp G. (geiserp01)


Lesenswert?

Super, danke Dir.

Also, anstatt Servo.attach oder Servo.deattach zu benutzen, wechsle ich 
diese einfach durch Deine Funktionen aus und teste.

Muss ich nach dem enablen warten, oder wartet der uC bis das PWM 
enabled ist, also synchrone Abfolge?

Nochmal danke @Matthias.

: Bearbeitet durch User
von soundso (Gast)


Lesenswert?

Philipp G. schrieb:
> Ausgangslage
>
> - Arduino Nano
> - Zwei digitale Servos
> - Zwei Schaltregler

Was für eine Schnittstelle haben denn die Servos? Ist es wirklich 
RC-Like mit der PWM oder ist es was mit Rückkanal. Das würde die 
Confusion mit Servo.read erklären...

Das Verhalten von Servos ist IMHO nicht definiert wenn die PWM nicht 
mehr anliegt. Vor allem wenn der Schaltkreis im Servo digital ist wie du 
beschreiben hast. Servotyp wäre hier hilfreich ...

von Philipp G. (geiserp01)


Lesenswert?

soundso schrieb:
> Was für eine Schnittstelle haben denn die Servos? Ist es wirklich
> RC-Like mit der PWM. Das würde die

Nö, wirklich RC Servos ganz normal.

> Confusion mit Servo.read erklären...

Ich hatte Servo.read als Ausgabe mit Serial.read drin, das funktioniert 
wirklich. Das ist aber wirklich nur die Positionsvorgabe vom uC nicht 
den Rückwert vom Servo. Das Servo hat ja gar keinen, das macht nur was 
das PWM Signal ihm sagt.

soundso schrieb:
> Das Verhalten von Servos ist IMHO nicht definiert wenn die PWM nicht
> mehr anliegt. Vor allem wenn der Schaltkreis im Servo digital ist wie du
> beschreiben hast. Servotyp wäre hier hilfreich ...

Ich weiss, deswegen sind es digitale Servos. Die haben die wunderschöne 
Eigenschaft, dass wenn kein verwertbares PWM Signal am Eingang anliegt 
deren Controller den Brushless Motor einfach abschalten. Das mache ich 
mir zunutze.

Das sind diese hier:

http://www.savoxusa.com/Savox_SA1283SG_Digital_Servo_p/savsa1283sg.htm

Natürlich ist das Verhalten nicht standardisiert, ein anderes könnte die 
letzte Position halten, ein analoges könnte wild ausschlagen. Könnte 
auch eine Herstellerüberlegung sein, wenn das Signal fehlt geben wir das 
Servo frei, um Beschädigungen beim Flugzeug Absturz auf ein Minimum zu 
reduzieren. Sowohl hitec, Futaba als auch Savöx machen das so. Aber wir 
weichen vom Thema ab.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Ich hatte bisher mit 6 unterschiedlichen analogen Servos von 5 
unterschiedlichen marken zu tun. Alle lassen den Motor frei (stromlos) 
drehen, wenn sie kein Signal bekommen.

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.