Regelkreis mit Arduino Uno

Hallo Liebe Community,

ich bastel nun schon seit Tagen an einer Realisierung meines Problems.
Erstmal alle Konkreten Daten zur Peripherie:
Aufgebaut ist ein so genannter Schwerkraftabsorber.
Um Euch einen kleinen Einblick in meine bisherig Aufgebaute Analoge Schaltung zu geben, bzw. deren Funktion, existiert ein kleines Video.

KLICK MICH

Kurzabriss, die Interne Beschaltung des Systems arbeitet mit zwei OP07 die als Invertierende Verstärker agieren.
Das Grundprinzip ist eine PID-Regelung mittels der beiden OP´s.
Sobald das Objekt (in dem Fall der Ball) die Lichtschranke passiert, bekommt der Elektromagnet das Signal zum einschalten, allerdings ist das Schaltsignal alles andere als Homogen und auch nicht wirklich TTL fähig.

Das Programm was ich zu Testzwecken geschrieben habe, hat folgende Probleme:

  1. Wie kann ich einen Ausgang beschalten, der Analoge werte abgibt?
    z.B.: 0-1,5 V in 10mV Schritten

  2. Mein Eingangssignal zum Arduino liegt zwischen 3 und 4,8 Volt, eine sich ändernde Messung konnte ich auslesen, je nachdem wie sehr die Dioden Verstärkerschaltung unterbrochen und das Signal eingelesen wird.

Im nachfolgenden Video, könnt Ihr erkennen das der Magnet wirklich nur Digital schaltet, was ich benötige ist eine annähernd Stufenlose Regelung des Eingangsignals.

KLICK MICH

const int voltagePin = 0;
int Magnet = 13;

void setup()
{
 pinMode(Magnet, OUTPUT);
}


void loop()
{
  
  float voltage;

  
  voltage = getVoltage(voltagePin);
  
  if(voltage>=3.46)
    digitalWrite(Magnet, HIGH);
  else
    digitalWrite(Magnet, LOW);
   
  delay(0); 
}


float getVoltage(int pin)

{
  return (analogRead(pin) * 0.004882814);
  
}

Wie ihr erkennen könnt habe ich in vorrangegangenen Prototypen einen Rückgabewert Definiert, damit ich über USB mir einen Wert anzeigen lassen kann ...

Ich hoffe ich habe mich gut genug ausgedrückt :smiley:

Vielen Dank schonmal, wenn Ihr noch mehr Informationen benötigt, ich versuche alles zu Erläutern.

Danke, Gruß, Ben

Aus der Hüfte geschossen: probier doch mal PWM zur Magnetsteuerung

Klaus_ww:
Aus der Hüfte geschossen: probier doch mal PWM zur Magnetsteuerung

Hi,
Danke … nur stellen sich mir da gerade die nächsten Fragen …

PWM (=Pulsweitenmodulation) <<— ??? Richtig?

Muss ich dann nicht im Idealfall ein RC-Glied dahinterpacken?
Also, so gesehen nen Tiefpass, damit da annähernd etwas Gleichspg. mäßiges bei rumkommt?

Oder, kann ich den PWM Ausgang einfach als solches Deklarieren, oder muss ich dann eine gewisse Datenverarbeitung durchführen, so das mir der Ausgang etwas brauchbares liefert?

Habe zwar “relativ” mit Programmieren zu tun gehabt, allerdings nur so Bausteinmäßig, mit “Wie lasse ich eine LED blinken” oder wie bastel ich ein Lauflicht, das ganze unter C und auf einem ATMega 8 von Atmel …

Ich bin auch auf vieles Brauchbares hier im Forum schon gestoßen, nur wenn die eine Frage beantwortet ist, stellt sich die nächste …


Um noch ein paar Informationen raus zu schießen:

“Sende-/Empfangsweg”
Das wird durch eine Infrarot Lichtschranke realisiert, das IR-Fotoelement sitzt in einem Basisspannungsteiler und schaltet damit meinen Transistor, der wahlweise mit 12V oder 4,8V arbeiten kann.
Stufenlos messbar sind Spannungen von den oben genannten werten.

“Schalter”
Der Magnet wird mittels eines 2N3055 geschaltet, also da geht Ordentlich Bumms über die Schaltung (ca. 16,8 Volt und 2 Ampere)

Die Anpassung und Impedanzen sind absolut kein Problem …

Glättung des PWM Signals sollte nicht nötig sein. Schau dir mal analogWrite(x, y) an. Wie wird der Magnet angesteuert?

sschultewolter:
Glättung des PWM Signals sollte nicht nötig sein. Schau dir mal analogWrite(x, y) an. Wie wird der Magnet angesteuert?

Mit dem analogWrite (Magnet, HIGH) und …(Magnet, LOW) habe ich schon Experementiert, allerdings passiert dann überhaupt nichts mehr :frowning:

Im Bild kann man erkennen wie der Magnet angesteuert wird…

Die Dioden sind zum Stromrückschlagschutz eingebaut …

Ich sollte vielleicht nocht dazu sagen, die Interne Schaltung mit den OP´s arbeitet mit ca. 53kHz
Dazu hätte ich noch ein Foto vom Oszilloskop, da sieht man schön, das der Transistor zwar übersteuert, aber das ist nicht so schlimm.
Was mir mehr sorgen macht, ist die Tatsache das man auch schemenhaft erkennen kann, das es gewisse Frequenzbänder mitschwingen … :frowning:

Leistungstransistor.JPG

Hoppla ... :smiley:
Bild vergessen

Dropbox Link ^^

BenZin:
Mit dem analogWrite (Magnet, HIGH) und …(Magnet, LOW) habe ich schon Experementiert, allerdings passiert dann überhaupt nichts mehr :frowning:

Lies dir halt mal die Dokumentation oder Tutorials durch:
http://arduino.cc/en/Reference/AnalogWrite

analogWrite() erwartet einen Wert zwischen 0 und 255 als Parameter. Es ist 8 Bit PWM und darüber stellst du den Tastgrad ein

D2 ist überflüssig. Basiswiderstand fehlt.

BenZin:
Mit dem analogWrite (Magnet, HIGH) und ....(Magnet, LOW) habe ich schon Experementiert, allerdings passiert dann überhaupt nichts mehr :frowning:

:grin:

Mach doch mal analogWrite(Magnet, 255)

Serenifly:
Lies dir halt mal die Dokumentation oder Tutorials durch:
http://arduino.cc/en/Reference/AnalogWrite

analogWrite() erwartet einen Wert zwischen 0 und 255 als Parameter. Es ist 8 Bit PWM und darüber stellst du den Tastgrad ein

D2 ist überflüssig. Basiswiderstand fehlt.

D2 ist umstritten … die einen sagen ja, die anderen nein … Ändert nichts an der Funktion …

Basiswiderstand ist vorhanden, nur nicht auf diesem Schematischen Aufbau zu erkennen ^^
:wink:

Jetzt habe ich erst gerafft was Ihr von mir wollt …

Die Dokumentation habe ich mehrfach durchgelesen und bin auf keinen Grünen Zweig gekommen …

-.-"

if(voltage>=3.8)
    analogWrite(Magnet, 254);
  else
    analogWrite(Magnet, 20);
   
  delay(0);

Dann schwingt es immernoch … jetzt frage ich mich, kann ich nicht meinen “Volt” Wert zurückgeben?

Sprich…

if(voltage>=3.8)
    analogWrite(Magnet, voltage);
  else
    analogWrite(Magnet, 20);
   
  delay(0);

Eine gewisse Grundspannung sollte im Idealfall immer vorhanden sein

Okay … das ist Quatsch mit den Volt … denn dann übersteige ich immer meinen Grundspannungswert und der Transistor ist immer voll Leitend …

Außer, ich teile meine 10 Bit Eingang runter auf 8 Bit und gebe den Wert zurück an meinen Ausgang … oder sehe ich das Falsch !?

Ich hoffe dat nervt nicht unnötig, versuche mich da irgendwie rein zu arbeiten in das geschehen … vieles ist Learning by doing … nur möchte ich das ganze auch richtig verstehen … -.-"

if(voltage>=3.8)
    analogWrite(Magnet, voltage));
  else
    analogWrite(Magnet, 20);
   
  delay(0); 
}


float getVoltage(int pin)

{
  return (analogRead(pin)/4 ); //* 0.004882814(ausgeklammert, für Spannungswert)
}

Ich verstehe deinen Eingangspost so, dass du bereits einen PID Regler (auf opamp - Basis) hast.

Im ersten Video funktioniert der Regler wunderbar, im zweiten nicht.
Ein PID - Regler hat nun mindestens 3 Parameter: P I und D, die man halbwegs richtig einstellen muss.
Ausserdem hängt alles erstmal an der Erfassung des Ist-Werts (Abstand Objekt/Magnet). Wenn da nur eine Lichtschranke ist, die nur 2 Zustände hat, wird es schwierig, mehr als Magnet an/aus zu steuern, aber nicht ganz unmöglich. ( Man könnte noch die Zeit messen, bis die Lichtschranke wieder anspricht ... )

Da bietet sich an, dass du von analog PID (?) mit deinen opamps (wenn die nicht nur im Endeffekt einen 2Punkt-Regler darstellen, so wie es auch dein Arduino sketch im Prinzip ist ?) auf einen digitalen PID Regler im Arduino umsteigst.

Da hast du viel zu suchen, finden, lernen.

Viel Spass :wink:

Schönes Projekt.
Ich denke das du dazu die Arduino PID Lib brauchst. >Klick<
An dieser Lib kannst du deinen Sollwert (z.B. den gewünschten Spannungswert der LS) übergeben.
Als Ausgang kannst du dann z.B. 0-255 angeben mit denen du direkt auf PWM Ausgang gehst.
Drei Poti ran um die PID Parameter einzustellen ohne das du jedes mal den Sketch übertragen musst.
Die PID Lib funktioniert hervoragen da es auch in meinem Segway genutzt wird als Lageregelung.

Wie schon geschrieben. Perfekt zum lernen
Gruß
DerDani

michael_x:
Ich verstehe deinen Eingangspost so, dass du bereits einen PID Regler (auf opamp - Basis) hast.

Das ist vollkommen Korrekt … :slight_smile:

michael_x:
Im ersten Video funktioniert der Regler wunderbar, im zweiten nicht.
Ein PID - Regler hat nun mindestens 3 Parameter: P I und D, die man halbwegs richtig einstellen muss.
Ausserdem hängt alles erstmal an der Erfassung des Ist-Werts (Abstand Objekt/Magnet). Wenn da nur eine Lichtschranke ist, die nur 2 Zustände hat, wird es schwierig, mehr als Magnet an/aus zu steuern, aber nicht ganz unmöglich. ( Man könnte noch die Zeit messen, bis die Lichtschranke wieder anspricht … )

Das ist auch Richtig, allerdings gibt es da die Tatsache, das ich an meinem Leistungstransistor keinen Zusätzlichen Widerstand habe, um eine Arbeitspunktstabilisierung zu Realisieren, deswegen neigt der Magnet (Transistor) zum eigenschwingen. Zusätzlich kommt noch dazu, das die Emitterschaltung des Leistungstransistor 180° Phasenverschiebung erzeugt…
Der benötigte Effekt dadurch ist, das nach der erreichten Schwellspannung (je nach Temp. zwischen 0,55 und 0,63 Volt) eine gewisse Verstärkung kommt, die sich Dynamisch in einem geschlossenen Regelkreis mit der Lichtschranke bewegt.

Es Existiert eine Oszilloskop Aufnahme von dem OP-Amp Regelkreis, da ist gut zu erkennen, das ein “relativ” sauberer Sinus bei rum kommt und etwa mit 53kHz schwingt … Natürlich kein Klassischer Sinus, sondern ein der DC Spannung unterlegter Sinus (wir erreichen nie “null”)

michael_x:
Da bietet sich an, dass du von analog PID (?) mit deinen opamps (wenn die nicht nur im Endeffekt einen 2Punkt-Regler darstellen, so wie es auch dein Arduino sketch im Prinzip ist ?) auf einen digitalen PID Regler im Arduino umsteigst.

Ähm … ja … also, gewissermaßen vom Grundprinzip ist es ein 2-Punkt-Regler …
Rein Praktisch gesehen, haben wir zu speziellen Spannungswerten einen bestimmten Ausgangswert.
Der P-Anteil “passiert” direkt in dem der Transistor freigeschaltet wird … der D-Anteil kann in der hinsicht vernachlässigt werden. Nun kommt das Interessante daran, der Transistor funktioniert in diesem Fall wie ein I-Regler, denn die Spule benötigt eine gewisse Zeit bis sie den Strom verarbeitet hat, dadurch wird der Transistor im gegenzug immer weiter leitend … Womit ich den Effekt erreiche, das mein Spannungs und Zeitverlauf wie der I-Regler arbeitet.

Nun meine Große Frage … wie benutze ich die PID.Lib?
Habe nun schon viele Möglichkeiten mit For-Schleifen, Do-While und und und und durchgespielt.
Ich war auch schon fast an dem Punkt das ich versuche irgendwas mit dem Switch-Befehl zu realisieren.
zB. bei Wert 3 Volt → gebe volle Leistung // bei Wert 3,5 → x und so weiter …

Meine Programmierkenntnisse sind leider nicht auf einem Level, das ich mir spontan was aus den Synapsen ziehen kann … Bei mir ist das Problem, ich brauche zu vielem einen Praktischen bezug (weshalb ich mit den “normalen” C-Sprachen mit Hallo Welt ausgabe und sowas leider nix anfangen kann)

Hätte jemand für mich zufällig einen Lösungsvorschlag … Denn wenn ich nach PID-“Programmen” suche, eröffnen sich mir noch unbekannte Welten und ich verstehe Leider nur die hälfte von dem, was da steht …

Da ich ja das PI-Prinzip “bauen” möchte.

P = Lichtschranke
Ich überschreite einen Wert, also soll er “vollgas” geben bis Wert X

I = wäre in dem Fall die Collector-Emitter-Strecke

Ich hoffe meinen Gedanken Wirr-Warr kann jemand folgen … :wink:

volvodani:
Schönes Projekt.
An dieser Lib kannst du deinen Sollwert (z.B. den gewünschten Spannungswert der LS) übergeben.
Als Ausgang kannst du dann z.B. 0-255 angeben mit denen du direkt auf PWM Ausgang gehst.
Drei Poti ran um die PID Parameter einzustellen ohne das du jedes mal den Sketch übertragen musst.
Die PID Lib funktioniert hervoragen da es auch in meinem Segway genutzt wird als Lageregelung.

Gibt es dafür einen Schaltplan? Also, wie und wo ich die Poti´s anschließen muss, und oder sowas Ähnliches? -.-"

Danke für die Antworten … :slight_smile:

Ich werde heute Abend mal in meinen Sketch reinschauen und dir die für dich wichtigen Sachen zusammen kopieren. Mit ein bisschen erklärung.
Bekommst du einen Analogwert von der Lichtschranke?
Vom Prinzip her

-Analogwert eingelesen
-Sollwert X für die Position vorgeben den du haben willst (Setpoint für PID)
-Istwert auswerten (Istwert für PID)
-Dann kannst du einen Ausgangsbandbreite definieren (Hier 0-255 für Analog.write)

Und dann die
P-Wert
I-Wert
D-Wert
Werte definieren.

Gruß
DerDani
Gruß

volvodani:
Ich werde heute Abend mal in meinen Sketch reinschauen und dir die für dich wichtigen Sachen zusammen kopieren. Mit ein bisschen erklärung.
Bekommst du einen Analogwert von der Lichtschranke?
Vom Prinzip her

Ja, bekomme Analogwerte zwischen 3.0 V und 4.8 V ...
Dabei wäre es Sinngemäß so, das bei den 4.8V die volle Ansteuerung an den Magneten weitergegeben werden müsste.
Bei 3.0 V wäre dann Magnet aus ... alles dazwischen müsste via dem Integral geregelt werden ...

Also wäre ja mein Setpoint den ich erreichen möchte, ein Zwischenwert, den ich dann leider durch ausprobieren, ermitteln müsste ...

Mein Istwert ist ja der, der Lichtschranke, also auch meinem Analogwert ...

Mit der Bandbreite der Ausgabe ist es ja dann auch eine Spielerei .... oder Regelt der sich dann Automatisch ein?!

Was mir noch einfällt, da ich ja NIE Logisch "0" erreiche, kann ich dem Programm einen Logisch "0" Wert zuweisen? Also, eine Umformatierung, an meinem Eingang Lese ich ja mit 1024 Werten ein und gebe nur 256 am PWM Ausgang aus ... mit meinem künstlichen Prototypen zur Umrechnung erreiche ich ja nur meine Angabe der "Spannung"
Da ich ja Ausgangsseitig dann nie unter den "Schritt" 154 Komme ...
Oder kann ich das Eingangssignal auch so auswerten, das mir die Gesamte Auflösung zur Verfügung steht !?
Denn rein von der Leistung des Transistors habe ich ja "runter" bis "Schritt" 80 eine Auswirkung an meinem Magneten ....
(Habe ich einfach mal ausprobiert, bei welchem Ausgangswert keine Ausreichende Leistung mehr entsteht um meinen "Ball" anzuziehen)

#include <PID_v1.h>

double Setpoint, Input, Output;


PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

void setup()
{
  
  Input = analogRead(A0);
  Setpoint = 100;

  myPID.SetMode(AUTOMATIC);
}

void loop()
{
  Input = analogRead(0);
  myPID.Compute();
  analogWrite(6,Output);
}

In wie weit kann ich denn Einfluss auf diese “Tuning” Werte nehmen, bzw. was sagen die aus !?

kP, kI und kD haben die gleiche Bedeutung wie üblich bei einem PID Regler.

Input ist die Eingangsgröße. Setpoint ist der Sollwert. Und Output ist die Ausgangsgröße.

Ja, bekomme Analogwerte zwischen 3.0 V und 4.8 V ...
Dabei wäre es Sinngemäß so, das bei den 4.8V die volle Ansteuerung an den Magneten weitergegeben werden müsste.
Bei 3.0 V wäre dann Magnet aus.

Wenn du zwischen Eingang ( Lichtschranke sagt wie hoch das Ding ist )
und Ausgang (Strom durch den Magneten) unterscheidest, wird für uns die Verständigung leichter.

Wenn du z.B. das Teil so ansteuern willst, dass eine Bandbreite von 3.8 einen Ausgangsbereich von 0 .. 255 ergeben soll, wäre der erste grobe Wert für Kp ca. 60

Gibst du einen Sollwert von z.B 3.9 vor, hast du Regelabweichungen +- 1.9 , der Regler-Ausgangswert wird dann ca. +- 120. Addiere 120 drauf und du bekommst ca. 0 .. 240 Das ganze auf 0 - 255 begrenzen, fertig ist der P -Anteil ( 1. Versuch )
Sollte das stabil sein, kannst du ausprobieren, was bei Kp 30 ... 100 passiert. (Bei hohen Werten wird er sich aufschwingen, bei zu kleinen fängt er kleinste Störungen nicht mehr ab)

Kann auch sein, dass deine Vorgaben nicht optimal waren ...

Hallo Ben,
hier mal die auszüge aus meinem Segway Sketch bezüglich dem PID Regler.

Hier sind nur die Teile drin die das PID enthalten.

#include <PID_v1.h>   // Die Library einfügen

#define P_PART A1    // Hier hängen die Potis dran für die einzelenen Regleranteile
#define I_PART A0
#define D_PART A2



double Setpoint, Input, Output;  // die benötigeten variabeln Setpoint = Sollwert LS Input= Istwert LS Output = PWM-Wert für den Magneten 

double Kp=0.0, Ki=0.0, Kd=0.0;      tuning parameter


//Aufrugfen bzw erstellen einer PID Instanz

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



void setup(){
  Kp=(analogRead(P_PART)>>2)/20.0;  // Hier werden die 0-1024 auf die Größen "runtergebrochen"
  Ki=(analogRead(I_PART)>>2)/10.0;   // die ich für meinen Segway brauche
  Kd=(analogRead(D_PART)>>2)/20.0; // damit zum Start auch schon Werte stehen
  myPID.SetTunings(Kp, Ki, Kd);         // die erstelleten Werte in die instanz übernehmen
  myPID.SetSampleTime(30);            // Sample Zeit für den Regler (alle 30ms neu berechnung)
  myPID.SetOutputLimits(30,255);     // Die Limits des Reglers da aus der Lib auch größer 255 rauskomemn könne kann man diese hier begrentzen um einem Überlauf entgen zu wirken (30 wäre deine "grundspannung"
}


void loop(){
// Hier musst du noch dein Istwert einlesen als Input
  AnalogKP=(analogRead(P_PART)>>2)/20.0; //einlesen der  in der Loop
  AnalogKI=(analogRead(I_PART)>>2)/10.0;
  AnalogKD=(analogRead(D_PART)>>2)/20.0;
  if (HMset==false){                                 // ich habe einen Set Button an meiner Steuerung um neue
    Kp=AnalogKP;                                     // werte innerhalb der Loop zu setzen
    Ki=AnalogKI;
    Kd=AnalogKD;
    myPID.SetTunings(Kp, Ki, Kd);
  }

  myPID.Compute();  // muss jeden zyklus gsetzte werden damit der PID Wert brechenet intern                     // wird geschaut ob die sample Zeit schon vorüber ist dafür muss aber jeden                      //Zyklus Compute gecalled werden

//Hier dein PWM Ausgang mit der Vaiabele Output
}

Hoffe dir mal ein bisschen geholfen zu haben.
Die Potis sind 10-gang Spindeltrimmer zwiscen +5V und GND Schleifer auf die entsprechenden Analog Eingange.

gruß
DerDani

Also .... um ehrlich zu sein .... irgendwie komme ich mit der PID-Library nicht zurecht .... oder es sind zu viele unbekannte Parameter, die ich nicht richtig parametrieren kann ...

Dazu kommt noch das Problem, das mir aktuell die Mittel dazu fehlen, zusätzliche Bausteine einzubinden ....

Eine Idee hatte ich noch, allerdings ist die entweder zu langsam, oder ich bin mal wieder zu Untalentiert, die richtig an zu wenden .... -.-"
Ich hätte mir vielleicht nicht unbedingt so ein Mammut Projekt ans Bein schnallen dürfen, ohne mich vorher richtig mit gewissen Rahmenbedingungen zu beschäftigen ....

Ich bin unendlich dankbar für die Hilfestellungen, habe auch grundlegendes gelernt ...
Nur hapert es bei mir mit der Denkweise .... :-/

const int voltagePin = 0;
int Magnet = 6;
void setup()
{
 pinMode(Magnet, OUTPUT);
 pinMode(voltagePin, INPUT);
}


void loop()
{
  
  float voltage;
  int hilfe=0;

  
  voltage = getVoltage(voltagePin);
  hilfe=voltage*10;
  switch(hilfe)
  {
    case 30: analogWrite(Magnet, 0);
    case 31: analogWrite(Magnet, 10);
    case 32: analogWrite(Magnet, 20);
    case 33: analogWrite(Magnet, 30);
    case 34: analogWrite(Magnet, 40);
    case 35: analogWrite(Magnet, 50);
    case 36: analogWrite(Magnet, 60);
    case 37: analogWrite(Magnet, 70);
    case 38: analogWrite(Magnet, 80);
    case 39: analogWrite(Magnet, 90);
    case 40: analogWrite(Magnet, 100);
    case 41: analogWrite(Magnet, 130);
    case 42: analogWrite(Magnet, 150);
    case 43: analogWrite(Magnet, 170);
    case 44: analogWrite(Magnet, 180);
    case 45: analogWrite(Magnet, 200);
    case 46: analogWrite(Magnet, 220);
    case 47: analogWrite(Magnet, 240);
    case 48: analogWrite(Magnet, 255);
  }
  delay(0.025); 
}


float getVoltage(int pin)

{
  return (analogRead(pin) * 0.004882814);
}