Servo mit MPU6050 ansteuern

Hallo,

ups klammer zu viel sorry

ziel = constrain((90 + along / 50 - across / 50 - vertical / 50), 45, 135); // 45 - 135° (front left)

Ich würde sagen, dass war schon richtig so. Habe nochmal geschaut. Im Original Code aus dem Link, steht es auch so. Vor Constrain ist eine Klammer und hinter 135 noch eine.:

void writeServos() {
    servoFL.write(constrain((90 + along / 20 - across / 20 - vertical / 20), 45, 135)); // 45 - 135° (front left)    servoFR.write(constrain((90 - along / 20 - across / 20 + vertical / 20), 45, 135));; // 45 - 135° (front right)    servoRL.write(constrain((90 - along / 20 - across / 20 - vertical / 20), 45, 135)); // 45 - 135° (rear left)    servoRR.write(constrain((90 + along / 20 - across / 20 + vertical / 20), 45, 135)); // 45 - 135° (rear right)    }

Habe es mit dem Code von dir ohne Klammer versucht. Leider bei keiner Version Bewegungen der Servos festzustellen.

Was ist nicht verstehe: Wo wird dem Servo ein Wert zugeordnet, damit er hier gelesen wird:

akt = servoFL.read();

Hallo,

akt = servoFL.read();
das ist nicht die reale ist Position des servos sondern die aus der lib, eigendlich ist das immer die letzte angefahrene Sollposition. Wenn man den Servo langsam fahren lassen würde, mittes eines Konstrukts aus millis() , also immer nur kleine Schrittchen, würde sich die der der Wert servo.read() auch langsam ändern.

die Klammer muss schon weg siehe Arduino referenz link

bekommst Du den unterschiedliche Werte für ziel angezeigt wenn der Senso bewegt wird ?

ich muss mal suchen irgedwo hab ich noch so einen Sensor rumfliegen dann muss ich das mal aufbauen morgen und mit dem original sketch und dann mit dem geänderten testen

Heinz

Hallo Heinz,

das ist ja interessant mit der Klammer. Im Original Sketch war die Klammer ich da und es hat funktioniert.

Den Serial Teil hatte ich noch nicht eingebaut. Das mache ich morgen ( heute ) mal. Falls du keinen Sensor hast, kann ich dir auch gerne einen schicken. Du hast mir schon so viel geholfen.

Viele Grüße
Sven

Hast Du denn einen Sensor gefunden. Bin heute leider noch nicht dazu gekommen, mal den Serial Teil einzubauen. Hoffe ich schaffe das noch.

Hallo,

ich habe mir heute mal den original Sketch zusammen mit einem Sensor aufgebaut. Grundsätzlich klappt der Sketche ja, allerdings misst der Sensor sehr schnell. Wenn man jetzt eine Peek hat, bekommt der Servo das eventuell gar nicht mit.
ich hab dann mal einen delay(10) eingebaut damit war das dann besser. Darauf hab ich dann meinen Sketch verwendet , den mit der Classe Feder, und das noch ein bischen angepasst. Ich denke mehr kann man da nicht rausholen.

Bei der Ausgabe für den Servo hab ich jetzt mal einen mit Feder und die 3 anderen sind ohne. Damit kann man den Unterschied besser sehen. Es gibt noch eine serielle Ausgabe dazu die auch im Plotter läuft , da kann man dann was mehr sehen.

Es besteht noch ein Grundsätzliches Problem. Der Vorgang an sich ist ja ein kontinuierlicher, wenn nun dazwischen die Feder mit den Schritten zum nachfedern ablaufen soll dann kann das zu einem verfahren des Servos in Stufen führen. Langsame Bewegungen des Sensors klappen , schnelle auch , dazwischen kanns Probleme geben. Bei starken Bremsvorgänge des Modells wid das Ding schon nachfedern, das muss man mal probieren am Modell. Eventuell ist eine Lösung mit zu spitzem PI Regler noch eine Variante die einen Versuch wert wäre.

// 4 Channel "Micro RC" Receiver with 4 standard RC Servo Outputs (used as active suspension)
// ATMEL Mega 328P TQFP 32 soldered directly to the board, 8MHz external resonator, (tested on a Pro Micro 8MHz)
// MPU-6050 gyro / accelerometer


/* This code is still very quick and dirty!
    MPU-6050 code based on the work of Joop Brokking, no library required!
    8MHz is a bit on the weak side, servo lag may occure
    This simulation shows an active truck cabin suspension, using 4 servos
*/

const float codeVersion = 0.1; // Software revision (see)

//
// =======================================================================================================
// BUILD OPTIONS (comment out unneeded options)
// =======================================================================================================
//

//#define DEBUG // if not commented out, Serial.print() is active! For debugging only!!

//
// =======================================================================================================
// INCLUDE LIRBARIES
// =======================================================================================================
//

// Libraries
#include <Wire.h> // I2C library (for the MPU-6050 gyro /accelerometer)
#include <Servo.h>

// Tabs (header files in sketch directory)
#include "MPU6050.h"
#include "helper.h"

// ========================================================
// Classe Federn
// ======================================================
class Federn {

  private:
    byte schritt;
    uint32_t altzeit;
    uint32_t intervall;
    float faktor;
    int neuepos, aktuelleps;

  public:
    // Konstruktor
    Federn( uint32_t intervall, float faktor): intervall{intervall}, faktor{faktor} {}

    int nachfedern(int zielpos, int aktuellepos) { //Methode

      if ( millis() - altzeit >= intervall || schritt==0) {
        altzeit = millis();
       
        if (schritt < 5) {
          // Position berechnen
          neuepos = aktuellepos + (zielpos - aktuellepos) * faktor;
        }
        else {
          neuepos = zielpos;
        }
        // Serial.print(schritt); Serial.print('\t');
        // Serial.print(neuepos); Serial.print('\t');
        // Serial.print(aktuellepos); Serial.println();


        if (neuepos !=zielpos)schritt++; // schritt hochzählen
        else schritt = 0;  // oder fertig
        
     }
      return (neuepos);
    }
};


//
// =======================================================================================================
// PIN ASSIGNMENTS & GLOBAL VARIABLES
// =======================================================================================================
//

// Create Servo objects
Servo servoFL;
Servo servoFR;
Servo servoRL;
Servo servoRR;

// Create feder Objeke

Federn federFL(300, 1.6);
Federn federFR(300, 1.6);
Federn federRL(200, 1.6);
Federn federRR(200, 1.6);


// Pin assignment
#define SERVO_FL_PIN 4 // Front left servo pin
#define SERVO_FR_PIN 5 // Front right servo pin
#define SERVO_RL_PIN 6 // Rear left servo pin
#define SERVO_RR_PIN 7 // Rear right servo pin

//
// =======================================================================================================
// MAIN ARDUINO SETUP (1x during startup)
// =======================================================================================================
//

void setup() {

 
//#ifdef DEBUG
  Serial.begin(115200);
 
//#endif


  // Servo pins
  servoFL.attach(SERVO_FL_PIN);
  servoFR.attach(SERVO_FR_PIN);
  servoRL.attach(SERVO_RL_PIN);
  servoRR.attach(SERVO_RR_PIN);

  // MPU 6050 accelerometer / gyro setup
  setupMpu6050();

}

//
// =======================================================================================================
// WRITE SERVO POSITIONS
// =======================================================================================================
//

void writeServos() {
  int ziel, akt, pos;

  delay(10);

  ziel = constrain((90 + along / 50 - across / 50 - vertical / 50), 45, 135); // 45 - 135° (front left)
  akt = servoFL.read();
  pos = federFL.nachfedern(ziel, akt);
  servoFL.write(constrain(pos,45,135));
  
  Serial.print(ziel); Serial.print('\t');
  Serial.print(akt); Serial.print('\t');
  Serial.print(pos); Serial.println();

  ziel = constrain((90 - along / 50 - across / 50 + vertical / 50), 45, 135); // 45 - 135° (front right
  akt = servoFR.read();
  pos = federFR.nachfedern(ziel, akt);
  servoFR.write(constrain(ziel,45,135));

  ziel = constrain((90 - along / 50 - across / 50 - vertical / 50), 45, 135); // 45 - 135° (rear left)
  akt = servoRL.read();
  pos = federRL.nachfedern(ziel, akt);
  servoRL.write(constrain(ziel,45,135));

  ziel = constrain((90 + along / 50 - across / 50 + vertical / 50), 45, 135); // 45 - 135° (rear right)
  akt = servoRR.read();
  pos = federRR.nachfedern(ziel, akt);
  servoRR.write(constrain(ziel,45,135));


}
// =======================================================================================================
// SUSPENSION CALCULATIONS
// =======================================================================================================
//

void calculateSuspension() {

  // Read sensor data
  readMpu6050Data();

}

//
// =======================================================================================================
// MAIN LOOP
// =======================================================================================================
//

void loop() {

  // Calculate suspension
  calculateSuspension();

  // Write the servo positions
  writeServos();

}

Das Servo darfst du max. 50x die Sekunde mit einer neuen Position füttern, sonst macht's komische Sachen.

Hallo,

ich hole den Post noch mal nach vorne. Wer mich ein bischen kennt der weis das wenn ich mich in was verbissen habe dann will ich das auch lösen.

Die Idee eine PI Regler zu verwenden und den zu spitz einzustellen um den Servo nachfedern zu lassen hat mir keine Ruhe gelassen. Nu hat ein Servo ja eine ziemlich straffen Regelkreis intern um die Postiton anzufahren. Ein zusätzlicher Regler ist damit also eigendlich völlig Banane. Um eine abklingende Schwingung zu erzeugen baucht man erst mal eine odere mehrere zeitliche Komponente, am besten und einfachsten als PT1 Glied . Ein gleitender Mittelwert macht genau das.

Ich habe mir also eine Classe erstellt mit eine PI Regler und einem Istwerfilter in Form eines gleitenden Mittelwertes. Istwertfilter werden ja auch in realen Regelkreisen oft benötigt, ist also naheliegend das als Methode in die PI Classe zu packen. Natürlich hätte ich auch den standard PID regler nehmen können, aber mal einen selber machen kann ja auch Spass machen. :wink:

Also hier das Ergebniss

/* Servo mit PI Regler (Nachbildung einer Federbewegung)
 *  als Sollwertprung werden zwei Positionen angefahren
 *  Mit den Parametern kann die Federnachbilung verändert werden
 *  Ziel ist eine Reglereistellung die stark überchwingt
 *  Dämpfung Zeitverhalten ( Masse)
 *  
 */

#include <Servo.h>
int pos1 = 80; // Sollwert positionen
int pos2 = 120;
bool posstate;
int ziel;
uint32_t altzeit, altdisp;    // letzte Sollwertumschaltng  und Anzeige Zeit

// Regler Parameter
#define PI_cycle 20   // ms
#define KP 0.3
#define KI 20.0
#define daempfung 20

class PiRegler {
  private:
    float soll, ist, y , yi, yp, dif, lastyi;
    float Kp, Ki;
    float buff, av;   // Mittelwert bilden
    uint32_t altzeit, cycletime, av_time;

  public:
    // Konstruktor
    PiRegler(uint32_t cycletime, float Kp, float Ki): cycletime{cycletime}, Kp{Kp}, Ki{Ki} {};

    float control(float soll, float ist) {
      if (millis() - altzeit >= cycletime) {
        altzeit = millis();
        dif = (soll - ist);   // Regeldifferenz
        yp = constrain (dif * Kp, -200, 200);   // P-Anteil
        yi = constrain (lastyi + dif * Ki * cycletime / 1000.0 , -200, 200); //I-Anteil
        lastyi = yi;
        y = yp + yi;  // Stellgrösse bilden
      }
      return (y);
    }

    float mittel(float in, int f) { // gleitender Mittelwert

      if (millis() - av_time > 10) {
        av_time = millis();
        buff = buff - buff / f;
        buff = buff + in;
        av = buff / f;
      }
      return (av);
    }
};

// Objekte erstellen
Servo servo1;
PiRegler regler1(PI_cycle, KP, KI); 
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  servo1.attach(4);
  servo1.write(pos1);
}

void loop() {
  int akt, pos;

  // Sollwert Umschaltung zum testen
  // letztlich kommen die Sollwerte ja vom Sensor.
  if (millis() - altzeit >= 3000) {
    altzeit = millis();
    posstate = !posstate;
    if ( posstate ) ziel = pos1;
    else ziel = pos2;
  }

  
  akt = servo1.read();                // Istwert lesen
  akt = regler1.mittel(akt, daempfung); // dämpfen Mittelwert
  pos = regler1.control(ziel, akt);   // PI Regler bearbeiten
  pos = constrain(pos, 0, 180);       // Auf servo begrenzen
  servo1.write(pos);                  // Wert an Servo geben

  
  if (millis() - altdisp >= 20) {     // Werte anzeigen
    altdisp = millis();
    Serial.print(ziel); Serial.print('\t');
    Serial.print(akt); Serial.print('\t');
    Serial.println();
  }

}// =====loop ende

graf.png

graf.png

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.