Bei Sketchübertragung bewegt sich der Servomotor

Hallo zusammen,

ich habe das folgende Projekte Mechatronics Tutorials: Balancing of a Ball on Beam using Arduino as a PID controller versucht umzusetzen (ich besitze einen Arduino UNO rev3).

Es klappt auch alles wunderbar, allerdings wenn ich den Sketch neu übertrage macht der Servo-Motor (https://www.amazon.de/Packung-GSS-Servos-Hubschrauber-Flugzeug/dp/B01EH4JEYW/ref=sr_1_1?ie=UTF8&qid=1509186375&sr=8-1&keywords=servomotor) einen kurzen, ruckartigen Ausschlag und fährt dann wieder zurück.

Ich habe hier (Servos – RN-Wissen.de) gelesen, dass man den uC sowie den Motor mit getrennten Spannungsversorgungen betreiben soll. Dies habe ich gemacht, da mein uC über den USB-Port versorgt wird und der Servor über ein Netzteil. Aber auch das hat nicht geholfen.

Dann dachte ich, dass es evtl. an einem undefinierten Signal bei der Sketchübermittlung an den Ausgangs-Pins liegt und habe versucht einen Pull-Down-Widerstand einzusetzen:

Allerdings bewegt sich der Servo immernoch, wenn ich irgendwas übertrage.

Kann mir jemand helfen?

Vielen Dank!

Code:

#include <Servo.h>
#include <PID_v1.h>

double Setpoint, Input, Output, ServoOutput;


int last_reading = 0;

int ServoPin = 7;
int trigger = 10;
int echo = 11;

float Kp = 5;
float Ki = 5;
float Kd = 1;

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
Servo myServo;

void setup()
{
  Serial.begin (9600);
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);
  myServo.attach(ServoPin);
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(-5, 5);
  Input = readPosition();
}


void loop()
{
  Setpoint = 4;
  Input = readPosition();
  myPID.Compute();
  last_reading = Input;
  ServoOutput = 25 + Output;
  myServo.write(ServoOutput);
}

float readPosition() {
  long dauer = 0;
  long entfernung = 0;
  unsigned long now = millis();
  delay(40);
  digitalWrite(trigger, LOW);
  delay(5);
  digitalWrite(trigger, HIGH);
  delay(10);
  digitalWrite(trigger, LOW);
  dauer = pulseIn(echo, HIGH);
  entfernung = (dauer / 2) * 0.03432;
  if (entfernung > 30)
  {
    entfernung = 30;
  }
  Serial.print(entfernung);
  Serial.println();
  return entfernung;

}

Versuch mal so (ungetestet):

#include <Servo.h>
#include <PID_v1.h>

double Setpoint, Input, Output, ServoOutput;

bool oneshot = true;
int last_reading = 0;

const int ServoPin = 7;
const int trigger = 10;
const int echo = 11;

float Kp = 5;
float Ki = 5;
float Kd = 1;

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
Servo myServo;

void setup()
{
  Serial.begin (9600);
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);
  myServo.attach(ServoPin);
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(-5, 5);
  Input = readPosition();
}


void loop()
{
  Setpoint = 4;
  Input = readPosition();
  myPID.Compute();
  last_reading = Input;
  ServoOutput = 25 + Output;
  if (!oneshot) {
    myServo.write(ServoOutput);
  } else {
    oneshot = false;
  }
}

float readPosition() {
  long dauer = 0;
  long entfernung = 0;
  unsigned long now = millis();
  delay(40);
  digitalWrite(trigger, LOW);
  delay(5);
  digitalWrite(trigger, HIGH);
  delay(10);
  digitalWrite(trigger, LOW);
  dauer = pulseIn(echo, HIGH);
  entfernung = (dauer / 2) * 0.03432;
  if (entfernung > 30)
  {
    entfernung = 30;
  }
  Serial.print(entfernung);
  Serial.println();
  return entfernung;

}

EDIT: oneshot = false; ergänzt.

Zum Upload wird der Controller zurückgesetzt, und damit alle Pins auf Eingang geschaltet - der Servo hängt dann in der Luft und kann beliebig herumzappeln.

Je nach Servo kann es helfen, einen 4,7kOhm Widerstand vom Servoeingang nach 5V zu schalten.

Hallo,

@agmue:
Der Code hat leider nicht funktioniert. Mein Servo fährt dann in eine Position und bewegt sich gar nicht mehr. Ich habe noch versucht ein oneshot=false in die Abfrage einzubauen, weil ich dachte, dass die Variable immer true bleibt und sich darum nichts ändert. Das hat auch nichts geholfen.

@DrDiettrich:
Ich habe extra ein Pull-Down-Widerstand eingebaut, ich dachte das würde diesen Effekt unterbinden.

@MicroBahner:
Also meine Version mit dem Widerstand nicht gegen GND, sondern gegen die 5V? Sodass an dem Widerstand die Spannung von Vcc abfällt und ich so immer 0 an dem Servo anliegen habe? -> Habe ich gerade probiert, bringt leider auch nichts. Er fährt immernoch einmal ~90 ° an und dann wieder in seine alte Stellung.

theev:
Also meine Version mit dem Widerstand nicht gegen GND, sondern gegen die 5V? Sodass an dem Widerstand die Spannung von Vcc abfällt und ich so immer 0 an dem Servo anliegen habe?

Ja, gegen 5V, als PullUp - aber dann sollte am Servoeingang 5V anliegen, und nicht 0.
Hilft aber wie gesagt nicht bei allen Servos. Manchen ist das Zucken auch nur sehr schwer abzugewöhnen.
Gegebenenfalls könntest Du es mit digital-Servos versuchen. Die sind in dieser Beziehung unkritischer.

theev:
Ich habe noch versucht ein oneshot=false in die Abfrage einzubauen, weil ich dachte, dass die Variable immer true bleibt und sich darum nichts ändert. Das hat auch nichts geholfen.

Richtig gedacht, sorry für die Unachtsamkeit.

Laß Dir doch ServoOutput ausgeben, ob der Anfangswert daneben liegt. Sonst müßte man an einer anderen Stelle suchen, nicht im Sketch, also so wie in #2 und #3 (die beiden kennen sich besser mit Servos aus :slight_smile: ).

MicroBahner:
Ja, gegen 5V, als PullUp - aber dann sollte am Servoeingang 5V anliegen, und nicht 0.

Wobei der Widerstand vor allem gegen das Zucken beim Einschalten der Versorgungsspannung helfen soll. Wahrscheinlich ist das aber bei dir nicht das Problem, da die Spannung am Servo ja während des Programmübertragens stabil bleibt? Hast Du die Möglichkeit mit einem Oszi zu schauen, was da am EIngang während des Übertragens passiert?
Wann zuckt den das Servo - beim Programmstart oder beim Beginn der Programmübertagung ( ok, bei dem kurzen Programm dürfte das Übertragen recht schnell gehen) ?
Was passiert denn, wenn Du Reset drückst? Da kannst du den Reset-Zustand ja etwas länger aufrechthalten.

Hallo,

ich habe mir mal ServoOutput ausgeben lassen und die ersten beiden Werte sind tatsächlich:

0.00
0.00
20.00
20.00
20.00
...

Ein Oszi besitze ich leider nicht, die sind so teuer und lohnen sich für mich (noch?!) nicht.

Der Servo zuckt bei folgenden Punkten:

  • Sketch hochladen, mit der normalen Maker-Umgebung
  • Nachdem man die Spannung des Arduino getrennt hat und sie dann wieder anlegt
  • Beim drücken des Reset-Knopfs

Ist es also relativ normal, dass Servos zucken? Sind die so empfindlich?

Danke Euch!

Gruß!

theev:
ich habe mir mal ServoOutput ausgeben lassen und die ersten beiden Werte sind tatsächlich:

0.00
0.00
20.00
20.00
20.00
...

Dann würde ich mal sagen, das Servo macht, was ihm gesagt wird. Wenn die ersten beiden Werte nach Programmstart 0 sind, dann zuckt es natürlich bei jeder Aktion die einen Neustart des Programms verursacht.

Das Servos beim Anlegen der Versorgungsspannung zucken, ist 'relativ normal' - manchen Servos ist das kaum abzugewöhnen. Es gibt aber auch Servos, die da wesentlich besser sind, und keinen Mucks machen. Nach meiner Erfahrung sind diesbezüglich digitale Servos deutlich besser als analoge.

P.S. zum Oszi: beim Test von Arduino-Programmen braucht man oftmals gar kein Oszi, da reicht vielfach ein einfacher USB-Logikanalysator aus. Bei ebay gibt's sowas für wenig Geld, bei direktem Bezug aus China auch noch günstiger.
Obwohl ich auch was Größeres habe, benutze ich den gern weil er so klein und einfach zu handhaben ist und meistens ausreicht.

Hallo,

danke für den Hinweis.
Das werde ich mir mal bestellen!

theev:
ich habe mir mal ServoOutput ausgeben lassen und die ersten beiden Werte sind tatsächlich:

0.00
0.00
20.00
20.00
20.00
...

Dann sollte man die ersten beiden Stellwerte ignorieren, ein Versuch (ungetestet):

#include <Servo.h>
#include <PID_v1.h>

double Setpoint, Input, Output, ServoOutput;

byte doubleshot = 2;
int last_reading = 0;

const int ServoPin = 7;
const int trigger = 10;
const int echo = 11;

float Kp = 5;
float Ki = 5;
float Kd = 1;

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
Servo myServo;

void setup()
{
  Serial.begin (9600);
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);
  myServo.attach(ServoPin);
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(-5, 5);
  Input = readPosition();
}


void loop()
{
  Setpoint = 4;
  Input = readPosition();
  myPID.Compute();
  last_reading = Input;
  ServoOutput = 25 + Output;
  if (doubleshot) {
    doubleshot--;
  } else {
    myServo.write(ServoOutput);
  }
}

float readPosition() {
  long dauer = 0;
  long entfernung = 0;
  unsigned long now = millis();
  delay(40);
  digitalWrite(trigger, LOW);
  delay(5);
  digitalWrite(trigger, HIGH);
  delay(10);
  digitalWrite(trigger, LOW);
  dauer = pulseIn(echo, HIGH);
  entfernung = (dauer / 2) * 0.03432;
  if (entfernung > 30)
  {
    entfernung = 30;
  }
  Serial.print(entfernung);
  Serial.println();
  return entfernung;

}

Hallo,

Ich habe zwar in der Ausgabe nun keine 0-Werte mehr, allerdings macht er immernoch diesen "Zuck".

Ich werde mir mal den Analyzer kaufen und schauen, was für ein Signal auf der Leitung die ganze Zeit rumfliegt.

Total merkwürdig.

Dankeschön soweit für Eure Hilfe!

theev:
Ich habe zwar in der Ausgabe nun keine 0-Werte mehr, allerdings macht er immernoch diesen "Zuck".

Dafür gibt es mehrere Möglichkeiten. Eine davon ist die dem Arduino nicht bekannte Ist-Position des Servos beim Einschalten.

Beispiel: Der Servo steht bei 15°, der Arduino wird ausgeschaltet. Beim nächsten Einschalten hat der Arduino keine Möglichkeit, die Ist-Position des Servos festzustellen. Daher gibt er eine Soll-Position aus, zu der der Servo mit maximaler Geschwindigkeit "zuckt".

Wenn es das "Zucken" ist, das Dich stört, dann kann man die Potispannung des Servos als Ist-Position auf den Arduino zurückführen. RC-Servo mit Istpositionsmeldung.

Hallo,

danke für die Antwort!
Interessant zu lesen, aber ich glaube für diesen Fall ist es zu unnötig - ich dachte ich hätte einen Fehler in der Verkablung etc. gemacht.

Danke für die Hilfe!

Gruß!