Platform mit MPU6050 Ausrichten

Hallo zusammen,
Ich hab zwar schon mehrere Projekte mit ESP und IDE umgesetzt doch hier stoße ich an meine grenzen.
Im genaueren geht es um eine Plattform die sich mit 2 Servos und einem MPU6050 ausrichten wollte.
Leichte erfolge hatte ich schon doch nun ist ende des Piers erreicht.
Wenn ich die Steuerung einschalte macht die Plattform Bewegungen die ich nicht definieren kann.
nun meine ich gelesen zu haben das der MPU6050 nur ein Inkrementalgeber zu sein scheint.
gibt es da eine Funktion dies irgendwie
zu umgehen oder hilft nur ein anderer Sensor bzw. gibt es einen Sensor der wirklich einen Absolutwert sendet und die Plattform sich ausrichtet also im Bereich seines maximalen Bewegungs Winkels der ja durch die Mechanik und servos begrenz ist.

beim starten zählt der mpu jeweils von 180 runter bis er sich irgendwo normalisiert

danke fürs lesen eventuell für einen einen anderen Denkanstoß
schöne Feiertage

Willkommen im Forum,
wie soll geholfen werden wenn du nichts zeigest was du hast.

bei Servos normal da Du nicht weißt wo die Servos stehen und Du darum nicht einen Istwert sondern immer nur den Sollwert kennst.

Wo hast Du das gelesen? Einzig zuverlässoge Quelle ist das Datenblatt des Bauteils:

Der MPU6050 ist ein 3 Achsen Beschleunigungsmesser, ein 3 Achsen Gyroskop, Thermometer mit integriertem Digital Motion Processor. Damit kannst Du die Lage im Raum und die Drehgeschwindigkeit bzw Temperatur messen.

Das ist er ja ein 3 Achsen Beschleunigungsmesser. Du mißt wenn das Teil still steht in 3 Achsen die Erdbeschleunigung. Du mußt die Werte der 3 Achsen benutzen um die Servos anzusteuern.

Wenn Du das so programmiert hast, wird es wohl so sein.
Wie sollen wir Deinen Sketch kennen?

Grüße Uwe

Hallo,
damit Du die Funktionsweise des Sensors besser verstehst solltest Du das zunächst mal ohne Servos betreiben und den Sensor auf eine Platte legen die Du manuell mit der Hand ausrichten kannst.

Dann überlegst Du dir welche Messwerte sinnvoll auf welchen Servo gehen und wie schnell der Servo fahren darf ohne das das System wild in Schwingung gerät. Es gibt Libs für die Servos die nach dem Einschalten immer auf eine bestimmte Position fahren. Eventuell macht in Deinem Fall ja die Mittelstellung Sinn. Als Lib zum Ansteuern der Servos könntest Du die Moba Tools verwenden, die hat gegenüber der Standard Lib einige Vorteile.

Also ich denke es ist ein wenig Grundlagenstudium angebracht.

Gruß Heinz

Servus Grüazi und hallo

ja ich hab den code vergessen sorry. Ich hab auch nachgebrütet und bin drauf gekommen die falsche bibliothekt verwendet.

mit der MPU6550_light ging es nicht aber mit der MPU6050 und diesem code

// v3.4.0 – MPU6050 FINAL
// Korrekte Achsen, stabiler Stillstand, Chip kann nach unten liegen

#include <Wire.h>
#include <MPU6050.h>
#include <math.h>

MPU6050 mpu;

// Winkel
float pitch = 0.0;
float roll  = 0.0;

// Gyro-Offsets
float gyroOffsetX = 0.0;
float gyroOffsetY = 0.0;

// Zeit
unsigned long lastTime = 0;

// Filter & Loop
const float ALPHA = 0.90;     // Debug-tauglich bei 5 Hz
const int LOOP_DELAY = 200;   // ms

// --------------------------------------------------

float normalizeAngle(float angle) {
  while (angle > 180.0) angle -= 360.0;
  while (angle < -180.0) angle += 360.0;
  return angle;
}

// --------------------------------------------------

void calibrateGyro() {
  const int samples = 1000;
  long sumX = 0, sumY = 0;

  Serial.println("Gyro-Kalibrierung... ruhig liegen lassen");

  for (int i = 0; i < samples; i++) {
    int16_t gx, gy, gz;
    mpu.getRotation(&gx, &gy, &gz);
    sumX += gx;
    sumY += gy;
    delay(2);
  }

  gyroOffsetX = sumX / (float)samples;
  gyroOffsetY = sumY / (float)samples;

  Serial.print("Offset GX: "); Serial.println(gyroOffsetX);
  Serial.print("Offset GY: "); Serial.println(gyroOffsetY);
}

// --------------------------------------------------

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);

  mpu.initialize();
  if (!mpu.testConnection()) {
    Serial.println("MPU6050 Fehler");
    while (1);
  }

  Serial.println("MPU6050 bereit (v3.4)");

  calibrateGyro();

  // Startwinkel aus Accelerometer setzen
  int16_t ax, ay, az;
  mpu.getAcceleration(&ax, &ay, &az);

  float Ax = ax / 16384.0;
  float Ay = ay / 16384.0;
  float Az = az / 16384.0;

  pitch = atan2(-Ax, sqrt(Ay * Ay + Az * Az)) * 180.0 / PI;
  roll  = atan2(Ay,  sqrt(Ax * Ax + Az * Az)) * 180.0 / PI;

  lastTime = micros();
}

// --------------------------------------------------

void loop() {
  int16_t ax, ay, az;
  int16_t gx, gy, gz;

  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

  unsigned long now = micros();
  float dt = (now - lastTime) / 1000000.0;
  lastTime = now;

  float Ax = ax / 16384.0;
  float Ay = ay / 16384.0;
  float Az = az / 16384.0;

  // KORREKTE Gyro-Zuordnung
  float gyroPitch = (gy - gyroOffsetY) / 131.0;
  float gyroRoll  = (gx - gyroOffsetX) / 131.0;

  float accPitch = atan2(-Ax, sqrt(Ay * Ay + Az * Az)) * 180.0 / PI;
  float accRoll  = atan2(Ay,  sqrt(Ax * Ax + Az * Az)) * 180.0 / PI;

  pitch = ALPHA * (pitch + gyroPitch * dt) + (1.0 - ALPHA) * accPitch;
  roll  = ALPHA * (roll  + gyroRoll  * dt) + (1.0 - ALPHA) * accRoll;

  pitch = normalizeAngle(pitch);
  roll  = normalizeAngle(roll);

  Serial.print("Pitch: ");
  Serial.print(pitch, 2);
  Serial.print("  Roll: ");
  Serial.println(roll, 2);

  delay(LOOP_DELAY);
}

kommen verwertbare werte raus
Das kippen und ausgleichen kommt mit dem code

#include <Wire.h>
#include <MPU6050.h>
#include <ESP32Servo.h>
#include <math.h>

MPU6050 mpu;

// -------- SERVO SETUP --------
Servo servoA;
Servo servoB;

const int SERVO_A_PIN = 16;
const int SERVO_B_PIN = 17;

const float SERVO_CENTER = 90.0;
const float SERVO_MIN = 45.0;
const float SERVO_MAX = 135.0;

const float MAX_HUB = 45.0;

// -------- Bewegung --------
float currentHub = 0.0;
const float MAX_HUB_SPEED = 60.0;   // °/s

// -------- PID --------
float Kp = 2.2;   // <<< NUR P-AKTIV
float Ki = 0.0;
float Kd = 0.0;

float pidIntegral = 0.0;
float lastError = 0.0;
float targetPitch = 0.0;

// -------- FILTER --------
const float ALPHA = 0.90;
float pitch = 0.0;
float gyroOffsetY = 0.0;

unsigned long lastTime = 0;

// ------------------------------------------------

float constrainFloat(float v, float mn, float mx) {
  if (v < mn) return mn;
  if (v > mx) return mx;
  return v;
}

float normalizeAngle(float a) {
  while (a > 180.0) a -= 360.0;
  while (a < -180.0) a += 360.0;
  return a;
}

// ------------------------------------------------

void calibrateGyro() {
  long sum = 0;
  const int samples = 800;

  Serial.println("Gyro-Kalibrierung... ruhig liegen lassen");

  for (int i = 0; i < samples; i++) {
    int16_t gx, gy, gz;
    mpu.getRotation(&gx, &gy, &gz);
    sum += gy;
    delay(2);
  }

  gyroOffsetY = sum / (float)samples;
  Serial.println("Kalibrierung fertig");
}

// ------------------------------------------------

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);

  mpu.initialize();
  if (!mpu.testConnection()) {
    Serial.println("MPU6050 Fehler!");
    while (1);
  }

  calibrateGyro();

  // Startwinkel
  int16_t ax, ay, az;
  mpu.getAcceleration(&ax, &ay, &az);

  float Ax = ax / 16384.0;
  float Ay = ay / 16384.0;
  float Az = az / 16384.0;

  pitch = atan2(-Ax, sqrt(Ay * Ay + Az * Az)) * 180.0 / PI;

  servoA.attach(SERVO_A_PIN);
  servoB.attach(SERVO_B_PIN);

  servoA.write(SERVO_CENTER);
  servoB.write(SERVO_CENTER);

  lastTime = micros();

  Serial.println("v4.4 gestartet – Kp = 1.0");
}

// ------------------------------------------------

void loop() {
  int16_t ax, ay, az, gx, gy, gz;
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

  unsigned long now = micros();
  float dt = (now - lastTime) / 1e6;
  lastTime = now;

  // -------- SENSOR --------
  float Ax = ax / 16384.0;
  float Ay = ay / 16384.0;
  float Az = az / 16384.0;

  float accPitch = atan2(-Ax, sqrt(Ay * Ay + Az * Az)) * 180.0 / PI;
  float gyroPitch = (gy - gyroOffsetY) / 131.0;

  pitch = ALPHA * (pitch + gyroPitch * dt) + (1.0 - ALPHA) * accPitch;
  pitch = normalizeAngle(pitch);

  // -------- PID --------
  float error = pitch - targetPitch;
  float pidOut = Kp * error;

  // -------- HUB --------
  float targetHub = constrainFloat(pidOut, -MAX_HUB, MAX_HUB);

  // -------- WEICHE BEWEGUNG --------
  float maxStep = MAX_HUB_SPEED * dt;
  float diff = targetHub - currentHub;

  if (fabs(diff) > maxStep) {
    currentHub += (diff > 0 ? maxStep : -maxStep);
  } else {
    currentHub = targetHub;
  }

  // -------- SERVO OUTPUT --------
  float servoPosA = SERVO_CENTER + currentHub;
  float servoPosB = SERVO_CENTER - currentHub;

  servoPosA = constrainFloat(servoPosA, SERVO_MIN, SERVO_MAX);
  servoPosB = constrainFloat(servoPosB, SERVO_MIN, SERVO_MAX);

  servoA.write(servoPosA);
  servoB.write(servoPosB);

  // -------- DEBUG --------
  Serial.print("Pitch: ");
  Serial.print(pitch, 2);
  Serial.print("  Hub: ");
  Serial.println(currentHub, 2);

  delay(5);
}

schon ganz gut an
das mixen der Achsen damit die oben abgebildete Mechanik funktioniert ist echt fordernd

ich hab mir die Codes aus dem netz zusammengestoppelt sicher ist das eine oder andere überflüssig aber gelernter Programmierer bin ich keiner.

ich werd mal weiter basteln vielleicht komm ich ja ans ziel :)

Ja, so habe ich mit dem Sensor auch meine ersten Tests gemacht. Hab das Ding mit der CPU auf eine kleine Holzplatte geschraubt und getest was die Werte machen, wenn ich sie Kippe und drehe. Ich war aber nicht soooo erbaut vom Ergebnis. Das Thema hier erinnert mich, dass ich mit dem MPU6050 - 3 Achsen Beschleunigungssensor, nochmal nacharbeiten muss.

Franz

Hi Karl, wenn du einen MPU6050 nutzzt kann ich dir noch einen Kalmanfilter empfehlern der oft zusammen mit den MOU6050 sehr gute ergebnisse erzielt.
Wikrungsweise des Filters.:

Ja, absolut! Das ist genau die Stärke des Kalman-Filters. Er verlässt sich nicht nur auf das, was er jetzt misst, sondern auf das, was er aufgrund der Physik erwartet hat.wikipedia+1

Das Prinzip funktioniert so:

  1. Er weiß, wie sich das System verhält: Wenn ein Objekt mit 50 km/h nach Osten fliegt, erwartet der Filter, dass es eine Sekunde später ca. 14 Meter weiter östlich ist.

  2. Er bewertet den Fehler: Wenn die nächste Messung plötzlich sagt, das Objekt sei 200 Meter weiter westlich, erkennt der Filter durch seine Unsicherheits-Berechnung ("Kovarianz"), dass das physikalisch extrem unwahrscheinlich ist. Er wird dieser "wilden" Messung weniger vertrauen und stärker an seiner Vorhersage festhalten.

  3. Er korrigiert intelligent: Umgekehrt: Wenn dein Modell sagt "Temperatur bleibt gleich", aber der präzise Sensor konstant "es wird wärmer" meldet, lernt der Filter schnell mit und korrigiert seine Vorhersage nach oben.

    Das gleiche gilt dann auch für Winkel. Das hat in meinem DIY Segway perfekt funktioniert, da aussreisser beim Messen keinen bzw kaum einfluss auf das System gehabt.
    Gruß
    DerDani

Hallo,
@volvodani , das ist ja alles sehr interessant was Du da so über den Filter und das fliegende "Objekt" schreibst. Aber der T0 wollte eine Plattform mit zwei Servos ausrichten und keinen fliegende Teppich bauen. Vermutlich hilft Ihm das nicht weiter.

Gruß Heinz

grüß euch
die letzten tage waren arbeitsreich
hab einiges probiert auch mit der Filterung

aber das System schaukelt sich auf und kommt nicht zur ruhe ich werd das einen EX Arbeitskollegen zeigen der hauptberuflich Microcontroller Regelungen konstruiert und programmiert vielleicht sieht er ja den fehler

Die Plattform kreist immer um 0 herum obwohl ich die Fehler meiner Meinung schon großzügig definiert habe.

Vielleicht kann ja der eine oder andere was mit dem code was anfangen für später

Schöne grüße

// =====================================================
// VERSION: 4.2
// Selbstnivellierende Plattform - WEBSERVER EDITION
// NEU: Kalmanfilter für MPU6050
// =====================================================

#include <Wire.h>
#include <MPU6050.h>
#include <ESP32Servo.h>
#include <WiFi.h>
#include <WebServer.h>
#include <math.h>

// ========== WLAN ACCESS POINT ==========
const char* ap_ssid = "Plattform-Control";
const char* ap_password = "12345678";

WebServer server(80);

// ========== MPU6050 ==========
MPU6050 mpu;

const float PITCH_OFFSET = -4.9;
const float ROLL_OFFSET  = 181.4;

// Kalmanfilter Variablen
float pitch = 0;
float roll  = 0;
float kalmanPitch = 0;
float kalmanRoll  = 0;
float P_pitch = 1, P_roll = 1;
const float Q_angle = 0.001;
const float Q_gyro  = 0.003;
const float R_angle = 0.03;

// ========== SERVOS ==========
Servo servoRight;
Servo servoLeft;

const int SERVO_RIGHT_PIN = 16;
const int SERVO_LEFT_PIN  = 17;

const float SERVO_RIGHT_MIN = 47.0;
const float SERVO_RIGHT_MAX = 138.0;
const float SERVO_LEFT_MIN  = 41.0;
const float SERVO_LEFT_MAX  = 130.0;

const float SERVO_RIGHT_NEUTRAL = 99.5;
const float SERVO_LEFT_NEUTRAL  = 89.5;

float currentRight = SERVO_RIGHT_NEUTRAL;
float currentLeft  = SERVO_LEFT_NEUTRAL;

// ========== REGELUNG ==========
const float MAX_SPEED = 50.0;
const float SLOW_DOWN_THRESHOLD = 2.0;
const float MIN_SPEED = 0.2;
const float TARGET_ACCURACY = 0.5;
const float DEADZONE = 0.80;

float pitchGain = 65.5;
float rollGain  = 60.5;

float pitchDirection = 1.0;
float rollDirection  = 1.0;

unsigned long lastUpdate = 0;
const int UPDATE_INTERVAL = 40;

// Status
float totalError = 0;
bool inDeadzone = false;
unsigned long uptimeSeconds = 0;

// ========== HILFSFUNKTIONEN ==========
float normalize(float a) {
  while (a > 180) a -= 360;
  while (a < -180) a += 360;
  return a;
}

float calculateSpeed(float error) {
  if (abs(error) < TARGET_ACCURACY) return 0;
  if (abs(error) < SLOW_DOWN_THRESHOLD) {
    return MIN_SPEED + (MAX_SPEED - MIN_SPEED) * (abs(error)/SLOW_DOWN_THRESHOLD);
  }
  return MAX_SPEED;
}

float moveServoSmooth(float current, float target, float dt) {
  float error = target - current;
  if (abs(error) < 0.1) return target;
  float speed = calculateSpeed(error);
  float maxChange = speed * dt;
  if (abs(error) <= maxChange) return target;
  return current + (error > 0 ? maxChange : -maxChange);
}

// ========== KALMANFILTER ==========
float kalmanUpdate(float accelAngle, float gyroRate, float dt, float &P) {
    // Vorhersage
    float angle = accelAngle; // initial
    angle += gyroRate * dt;
    P += Q_angle + dt*dt*Q_gyro;

    // Messung
    float K = P / (P + R_angle);
    angle += K * (accelAngle - angle);
    P = (1 - K) * P;
    return angle;
}

void readMPU(float dt) {
  int16_t ax, ay, az, gx, gy, gz;
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

  float Ax = ax / 16384.0;
  float Ay = ay / 16384.0;
  float Az = az / 16384.0;

  float accelPitch = atan2(-Ax, sqrt(Ay*Ay + Az*Az)) * 180.0 / PI;
  float accelRoll  = atan2(Ay, Az) * 180.0 / PI;

  accelPitch = normalize(accelPitch - PITCH_OFFSET);
  accelRoll  = normalize(accelRoll  - ROLL_OFFSET);

  float gyroPitchRate = gx / 131.0;
  float gyroRollRate  = gy / 131.0;

  kalmanPitch = kalmanUpdate(accelPitch, gyroPitchRate, dt, P_pitch);
  kalmanRoll  = kalmanUpdate(accelRoll,  gyroRollRate,  dt, P_roll);

  pitch = kalmanPitch;
  roll  = kalmanRoll;
}

// ========== WEBSERVER ==========
void handleRoot() {
  String html = R"(
<!DOCTYPE html>
<html><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1'><title>Plattform Control v4.2</title></head>
<body><h1>Plattform Stabilisierung v4.2</h1></body></html>
  )";
  server.send(200, "text/html", html);
}

void handleData() {
  String json = "{";
  json += "\"pitch\":" + String(pitch, 1) + ",";
  json += "\"roll\":" + String(roll, 1) + ",";
  json += "\"error\":" + String(totalError, 1) + ",";
  json += "\"servoR\":" + String((int)currentRight) + ",";
  json += "\"servoL\":" + String((int)currentLeft) + ",";
  json += "\"status\":\"" + String(inDeadzone ? "DEADZONE" : "AKTIV") + "\"";
  json += "}";
  server.send(200, "application/json", json);
}

// ========== SETUP ==========
void setup() {
  Serial.begin(115200);
  delay(1000);

  WiFi.softAP(ap_ssid, ap_password);
  server.on("/", handleRoot);
  server.on("/data", handleData);
  server.begin();

  Wire.begin(21, 22);
  mpu.initialize();

  servoRight.attach(SERVO_RIGHT_PIN);
  servoLeft.attach(SERVO_LEFT_PIN);

  lastUpdate = millis();
}

// ========== LOOP ==========
void loop() {
  server.handleClient();

  static unsigned long lastUptime = 0;
  if (millis() - lastUptime >= 1000) {
    uptimeSeconds++;
    lastUptime = millis();
  }

  unsigned long now = millis();
  if (now - lastUpdate < UPDATE_INTERVAL) return;

  float dt = (now - lastUpdate) / 1000.0;
  lastUpdate = now;

  readMPU(dt);

  totalError = sqrt(pitch * pitch + roll * roll);

  if (abs(pitch) < DEADZONE && abs(roll) < DEADZONE) {
    inDeadzone = true;
    return;
  }
  inDeadzone = false;

  float activePitchGain = pitchGain;
  float activeRollGain  = rollGain;

  if (totalError < 2.0) {
    float f = totalError / 2.0;
    activePitchGain *= f;
    activeRollGain  *= f;
  }

  float pitchCorrection = -roll  * activePitchGain * pitchDirection;
  float rollCorrection  = -pitch * activeRollGain * rollDirection;

  float targetRight = SERVO_RIGHT_NEUTRAL + pitchCorrection + rollCorrection;
  float targetLeft  = SERVO_LEFT_NEUTRAL  + pitchCorrection - rollCorrection;

  targetRight = constrain(targetRight, SERVO_RIGHT_MIN, SERVO_RIGHT_MAX);
  targetLeft  = constrain(targetLeft,  SERVO_LEFT_MIN,  SERVO_LEFT_MAX);

  currentRight = moveServoSmooth(currentRight, targetRight, dt);
  currentLeft  = moveServoSmooth(currentLeft, targetLeft, dt);

  servoRight.write((int)currentRight);
  servoLeft.write((int)currentLeft);
}

Hallo,

ich denke die Servos sind zu schnell.
ich habe mir Deinen Sketch mal angesehen, habe aber nicht verstanden wie das mit der Geschwindigkeit an die Servos funzen soll, ja es geht irgendwie mittels der Bearbeitungszeit . Das wird eine Geschwindigkeit berechent , ok das kann man abhängig von der Differenz Sollwert/Istwert sicher machen. Mir erscheint das aber zunächst erst mal unnötig.Ich würde die erst mal konstant lassen um einen vernünftigen Wert zu ermitteln bei dem das System stabil ist. Ich habe dir schon mal die MobaTools empfohlen. Da lässt sich die Geschwindigkeit ganz einfach als Parameter zusammen mit der Position an den Servo übergeben.
Beispiel
servo.write(pos, speed)

Heinz

Das mit dem Schwingen um den Nullpunkt wäre die perfekte Aufgabe für einen PID Regler. Denn wenn die “Abweichung” zu groß ist gibt es immer den gleichen schnellen Impuls zurück.
Dafür helfen die Anteile der P I D Regler genau das hin zu bekommen.

Gruß

DerDani.

@Rentner
hier geht es in erster Linie darum das die Werte durch den Kalman extrem präzise werden und noch stabiler. Je sauberer die Werte desto einfacher auch darauf zu reagieren. Und da man mehr als genug Ressourcen hat auf dem µC verliert man ja nichts mit dem rein bringen des Filters.

Hallo,
das bezweifele ich.
ich hab mir mal ein paar Gedanken zu dem Projekt gemacht, aber es fehlen noch so ein paar Randbedingungen. Steht das Ding auf einer festen Unterlage, oder bewegt sich die Unterlage. Gibt es Ansprüche an hoch dynamische Vorgänge , oder kann es auch langsam gehen.

Es handelt sich letztlich um eine Positionsregelung. Sollwert für x und y Position sind beide "0" bzw. Werte die dem Zustand in der Waage entsprechen.
Die Positionsregelung für die x und y Achse wird mittels zweier Antriebe realisiert. Normalerweise ist bei einem Regelkreis mit PID Regler die Geschwindigkeit des Stellgliedes die eigentliche Stellgrösse y des Reglers. Das ergibt sich letztlich auch aus der Analyse der Regelstrecke.
Vereinfacht kommt dabei dann heraus:

  • Stellgrösse für die Position ist die Geschwindigkeit der Servos.
  • Stellgrösse hoch -> Antrieb läuft schnell -> Position ändert sich schnell
  • Stellgrösse klein -> Antrieb läuft langsam -> Position andert sich langsam
  • das gilt für beide Richtungen
  • Stellgrösse =0 -> Antrieb steht -> Sollposition erreicht

Damit handelt es sich um eine Regelstrecke mit klassischem Integral-Verhalten.

Die steige Veränderung der Geschwindigkeit ist bei so einem Regelkonzept also zwingend erforderlich. Erschwerend kommt hinzu das bei kleinen Sollwerten für die Geschwindigkeiten der Antrieb stehen bleibt oder nicht anläuft. Damit ergibt sich ein "Todband" in der Nähe des Sollwertes. Der I-Anteil des PID Reglers würde darauf hin weiter hoch laufen, bis der Antrieb irgendwann wieder startet, was vermutlich dazu führt das die Position dabei über schwingt.

Nun Könnte man die Sache auch anders aufziehen, was letztlich ein wenig davon abhängig ist worauf die Anordnung des T0 steht. Steht sie auf einem festen Untergrund, oder der Untergrund bewegt sich nur langsam, so ist für die Positionierung keine hohe Dynamik , bzw stetige Regelung erforderlich. Ich kann mir auch eine zyklische Messung ( z.B 500ms ) vorstellen und ein Verfahren der Antriebe um jeweils eine bestimmten Betrag bis in ein Fenster. Die Verfahrschritte konnten z.B zwei Werte haben.

  • grosse Abweichung vom Sollwert( z.B>10 Grad) -> grosser Schritt (z.B 10 grad)
  • kleine Abweichung vom Sollwert -> kleiner Schritt (z.B 1Grad)

Das konnte man eventuell mit max Geschwindigkeit der Servos machen, oder aber auch mit einer reduzierten. Jedenfalls halte ich diesen Lösungsansatz für wesentlich einfacher.

Gruß Heinz

1 Like