Forum: Mikrocontroller und Digitale Elektronik PI-Regler | PWM | Motoransteuerung


von Sven W. (sickone4)


Lesenswert?

Hallo Leute,

ich habe von meinem Lehrer eine Aufgabenstellung bekommen:

ein 12V DC-Motor läuft viel zu schnell UND über einen vorgegebenen ADC 
Wert hinaus (Überschiesst sein Ziel)

Ich soll also einen PI Regler nutzen um den Punkt genau anzufahren.

Den Motor steuere ich über einen L298 Motortreiber an mit zwei Ausgängen 
vom µC.

PortB,1
PortB,2

Die Freigabe habe ich über PortB,0 gegeben.


mit der Formel :
esum = esum + e
y = Kp * e + Ki  Ta  esum

aus dem RN-Wissen soll ich den PI Regler Softwaremäßig umsetzen.

Ich habe gerade allerdings noch keinen wirklichen Plan, wie ich mein 
Script:
1
void Motor( uint8_t EingangA )
2
{  
3
   uint8_t EingangB;
4
   EingangB = 1 - EingangA;
5
  
6
   PORTB &= ~(1 << EingangA);  // Eingang A am Motortreiber
7
   PORTB |=  (1 << EingangB);  // Eingang B
8
   return;
9
}

anpassen muss, um eine PWM mit dem PI Regler einzufügen.
1
int32_t adwert;
2
3
// ----------------------------------------------------------------------------------------------
4
// Unterprogramm "ADC"--------------------------------------------------------------------------
5
// ---------------------------------------------------------------------------------------------- 
6
7
int ADC()       
8
{   
9
    int ergebnis = 0;        // Variable Ergebnis deklarieren 
10
                                  
11
    ADMUX = (0<<REFS1) | (1<<REFS0);            // interne Referenzspannung nutzen (5V)
12
    ADCSR = 0b11000110;        // Frequenzvorteiler auf 64 setzen und ADC 
13
            // aktivieren 
14
15
    while (bit_is_set(ADCSR,6));    // Warten, bis Umwandlung erfolgt ist   
16
17
    ergebnis = ADCW;        // Wert vom AD-Wandler wird Ergebnis zugeordnet               
18
    return ergebnis;        // Wert von ergebnis wird der aufrufenden Funktion (hier main)
19
            // übergeben 
20
}
21
22
// ----------------------------------------------------------------------------------------------
23
// Hauptprogramm "MAIN"--------------------------------------------------------------------------
24
// ----------------------------------------------------------------------------------------------
25
26
int main(void)
27
{
28
    DDRB   = 0b00001000;            // Ausgang PB3 für PWM-Signal (vgl. Datenblatt --> OC2)
29
    DDRC   = 0b00000000;            // Port C als Eingang   
30
31
    TCCR2  = 0b01100101;      // 8Bit-PWM-Modus WGM21, WGM20 = 0bx1xx0xxx: Phase Correct PWM
32
            // CS22, CS21, CS20 = 101: Prescaler 128 = 0bxxxxx101
33
            // COM21, COM20 = 0bxx10xxxx: Löschen von OC2 bei Compare Match
34
35
    while(1)
36
    {
37
        adwert = ADC();        // Wert des AD-Wandlers aus Unterprogramm "lese" holen 
38
        OCR2   = adwert;      // gelesener Wert wird dem PWM-Vergleichswert übergeben.  
39
          
40
        int wert;        // Dekleration variable wert  
41
        wert   = adwert;      // Übergabe des Wertes adwert an wert 
42
    }
43
}


Also das Problem ist, dass ich nicht weiß wie ich den PI Regler mit der 
PWM verknüpfe. Mein Lehrer gab mir die Aufgabe im Zuge eines Projektes 
und hat davon leider wenig Ahnung, er meinte nur es geht.
Er sagte, dass Y aus der Formel der Prozentuale Wert ist den die PWM 
bekäme.

Kent jemand so eine Funktion?

Gruß Sven


Edit: Sry für die Formatierung der Kommentare, irgendwie ist sieht das 
im Editor anders aus!

von xfr (Gast)


Lesenswert?

Ich habe keine Ahnung, wie Dein Motor angesteuert wird. Das geht aus 
Deinem Code nicht hervor. Deshalb: Wähle sinnvolle Bezeichner für 
Funktionen, Parameter, Variablen und kommentiere, was die Pins bewirken.

Mit diesem Code kann man als Außenstehender absolut nichts anfangen:
1
void Motor( uint8_t EingangA )
2
{
3
   uint8_t EingangB;
4
   EingangB = 1 - EingangA;
5
  
6
   PORTB &= ~(1 << EingangA);  // Eingang A am Motortreiber
7
   PORTB |=  (1 << EingangB);  // Eingang B
8
   return;
9
}

Meine Glaskugel sagt mir allerdings, dass zukünftig mindestens einer der 
Pins per PWM angesteuert werden muss. Am besten schließt Du den dann an 
den Ausgangs-Pin des Timers an. Ansonsten musst Du den Pin in der 
Timer-ISR umschalten.

Der PI-Regler ist dafür da, dem Timer den PWM-Wert vorzugeben, den er 
erzeugt. Also statt
1
while(1)
2
{
3
  adwert = ADC();
4
  OCR2   = adwert;
5
}

wirst Du dann haben:
1
while(1)
2
{
3
  sollwert = ADC();
4
  ausgabe  = PI_Regler(sollwert);
5
  OCR2     = ausgabe;
6
}

von Sven W. (sickone4)


Lesenswert?

sorry für mein unvollständiges script!

also ich habe zwei define angaben mit drin:

einmal für links 0 und rechts 1

wenn ich also dann Motor(links) aufrufe wird im unterprogramm
eine 0 übergeben, womit eingang B automatisch zur 1 wird!
1
void Motor( uint8_t EingangA )
2
{
3
   uint8_t EingangB;
4
   EingangB = 1 - EingangA;
5
  
6
   PORTB &= ~(1 << EingangA);  // Eingang A am Motortreiber
7
   PORTB |=  (1 << EingangB);  // Eingang B
8
   return;
9
}

von Bronco (Gast)


Lesenswert?

Guckst Du:
http://www.atmel.com/Images/doc2558.pdf

PS: nicht nur abschreiben, auch verstehen!

von Sven W. (sickone4)


Lesenswert?

was hab ich denn abgeschrieben?
der oben aufgelistete QC ist von mir.

von Sven W. (sickone4)


Lesenswert?

eine kleine Frage:

wie bekomme ich denn die Parameter für Ki, Kp usw ?
Ich habe ja keinen Sensor o.Ä. den ich nutze. Lediglich einen IST_wert 
von der ADC...

irgendwie steh ich da aufm schlauch

wenn ich beispielsweise werte aus einem thread nutze, in dem es um PID 
regler ging:

  Regler1.Ta=10;
  Regler1.I=100;
  Regler1.D=0;
  Regler1.Kp=1;
  Regler1.esum=0;
  Regler1.e=0;
  Regler1.ealt=0;

erhalte ich bei :

Y = (Kp*e)+(Ki*Ta*esum);

Aktueller ADC_Wert = 524
Fürhungsgröße = 500

folgenden wert: Y = (1*-24) + (100*10*6)
== 5976

was ist denn das für ein Wert? Der macht für mich gar keinen sinn, kann 
mir das wer erläutern?
1
          
2
    r = ADC_Read(0);
3
    w = 500;
4
        
5
    e = w - r;    // aktuelle Abweichung         
6
    
7
    if ((Y < 1023) && (Y > 0))        
8
    { esum = esum + e; }
9
    
10
    
11
    Y = (Kp*e)+(Ki*Ta*esum);  // Reglergleichung
12
13
    OCR1A    = Y;

von xfr (Gast)


Lesenswert?

Sven Weinmann schrieb:
> wie bekomme ich denn die Parameter für Ki, Kp usw ?

Tja, das ist eine Wissenschaft für sich. Am einfachsten durch 
Ausprobieren/Herantasten.

Für einen Regler brauchst Du einen Sollwert (der wird von außen/vom 
Benutzer vorgegeben) und einen Istwert (der wird gemessen). Daraus 
berechnest Du mit Hilfe von Ki und Kp (und dem gespeicherten 
integrierten Wert) den Ausgabewert.

Woher in der Aufgabe Soll- und Istwert kommen weißt aber nur Du bzw. 
Dein Lehrer ...

von Karl H. (kbuchegg)


Lesenswert?

Meiner Meinung nach solltest du fürs erste den Regler erst mal Regler 
sein lassen und dich einer ganz anderen Problematik widmen.

Das hier
1
void Motor( uint8_t EingangA )
2
{
3
   uint8_t EingangB;
4
   EingangB = 1 - EingangA;
5
  
6
   PORTB &= ~(1 << EingangA);  // Eingang A am Motortreiber
7
   PORTB |=  (1 << EingangB);  // Eingang B
8
   return;
9
}

kann nicht so bleiben.
Denn mit dieser Funktionn fährt der Motor entweder volle Kanne nach 
links oder er fährt volle Kanne nach rechts.

Und genau das kannst du nicht gebrauchen.
Du brauchst erst mal eine PWM Ansteuerung des Motors, mit der du den 
Motor mit einer vorgegebenen Geschwindigkeit fahren lassen kannst, nicht 
nur volle Kanne.

Dein erstes Ziel sollte IMHO sein:
Da muss eine Steuerung her, die mittels PWM den Motor in (in Grenzen) 
jeder beliebigen Geschwindigkeit nach links/rechts fahren lassen kann. 
Solange du nur Full-Speed hast, kommst du nicht weiter.

Und dieser Teilaspekt des Problems ist erst mal völlig unabhängig von 
irgendwelchen PI Reglern. Er kann also völlig für sich alleine 
betrachtet und gelöst werden.

Was du brauchst ist erst mal eine Funktion
1
void Motor( int8_t Speed )
2
{
3
   ....
4
}
mit der du dem Motor nicht nur eine Richtung, sondern auch eine 
Geschwindigkeit gibst. Daher auch der int8_t Wert ... also einer mit 
Vorzeichen.

  0                   ....    Motor steht

  positive Werte      ....    Motor dreht rechts rum
                              wobei der Motor umso schneller dreht
                              je größer der Wert ist
                              (bei +90 dreht der Motor schneller als
                               bei +10)

  negative Werte      ....    Motor dreht links rum
                              wobei der Motor umso schneller dreht
                              je kleiner der Wert ist
                              (bei -90 dreht der Motor schneller als
                               bei -10)

Überleg dir dazu mal was.

Testen kannst du das wieder mit deinem ADC bzw. dem Poti. Ist das Poti 
in Mittelstellung muss der Motor stehen. Verdrehst du das Poti aus der 
Mittelstellung heraus muss der Motor anfangen zu laufen (Je nachdem in 
welcher Richtung du am Poti drehst, dreht dann auch der Motor in eine 
richtung). Je mehr du ihn aus der Mittelstellung heraus verdrehst, desto 
schneller muss der Motor laufen.

von Sven W. (sickone4)


Lesenswert?

hallo Karl Heinz,

ich hab damit ein kleines problem.

1) ich habe in meiner anlage zwar ein poti welches ich nutzen kann, dies 
sollte aber späte rnichtmehr benutzt werden, da das dann durch den PI 
regler geschehen soll, beim punktgenauen anfahren.

2) ich hab einen L 298 mit der schaltung vom strippenstrolch ->
http://www.strippenstrolch.de/1-2-9-motortreiber-298.html

auf meinem breadboard gebaut. ich gebe dem treiber also nur ein 1 und 
ein 0 signal. + freigabe.


und das zweite zu deiner Funktion:
1
void Motor( int8_t Speed )
2
{
3
   ....
4
}

das bedeutet doch, dass ich den Aufruf über  "Motor( zahl +/- 100);" 
schreiben muss. vorher hatte ich dort einfach nur "links" und "rechts" 
stehen, d.h. ich müsste nun einfach wissen -> + ^rechts und - ^links.

von Sven W. (sickone4)


Lesenswert?

ok UPDATE:

zum Thema PWM:

ich hab also ein Problem:

das erfassen und das anpassen vom Speed funktioniert.

was nicht funktioniert ist die Richtungsumkehr. Grund ->

Das Schema der zwei Pins ist wie folgt (am Treiber)

Eingang 3 ... 1 Vorwärts
Eingang 4 ... 0

Eingang 3 ... 0 Rückwärts
Eingang 4 ... 1

Eingang 3 ... 0 Vollbremsung
Eingang 4 ... 0

Eingang 3 ... 1 Vollbremsung
Eingang 4 ... 1

das problem ist, dass ich nun B1 als PWM Pin (Eingang3) nutze und B2 als 
Eingang 4.

Diesen möchte ich in abhängigkeit von B1 invertieren, ist der PWM Wert = 
0 dann soll B1 und B2 gleich sein.

Das gilt es nun zu realisieren für die Drehrichtung.

von Informer (Gast)


Lesenswert?

Hallo,

deine "Strippenstrolch-Schaltung" ala L298 hat nicht 2, sondern 3 Pins: 
die Freigabe und die beiden Richtungs-Pins. Und die brauchst du auch 
alle für die PWM-Steuerung.
Über die 2 Eingänge (3 und 4) stellst du die Drehrichtung ein, und an 
den Freigabe-Pin kommt die PWM. Wobei man die Richtung möglichst nur 
umschalten sollte, wenn der Freigabe-Pin inaktiv ist; das vermeidet die 
Bremseffekte.
Also werden auch 3 Controller-Pins benötigt; einer davon sollte der 
PWM-Ausgang von einem Timer sein.

von Sven W. (sickone4)


Lesenswert?

ohje... das ist endlich der tipp gewesen, welchen ich gesucht habe!

der enable -.-

wenn ich den PWM wert eben an diesen setzt und die drehrichtung bestimme 
klappt das auch!

nun aber die frage, kann ich denn die PWM auch irgendwie nutzen, die 
drehrichtung zu ändern, oder geht das nicht?=

die PWM geht ja vn 0-1023, gibt es sowas wie einen mittelpunkt -> 512 
als umschaltpunkt?

oder benötige ich wie in meiner originalfunktion eine drehrichtung und 
eben eine geschwindigkeit?

von TestX .. (xaos)


Lesenswert?

Sven Weinmann schrieb:
> die PWM geht ja vn 0-1023, gibt es sowas wie einen mittelpunkt -> 512
> als umschaltpunkt?
>
> oder benötige ich wie in meiner originalfunktion eine drehrichtung und
> eben eine geschwindigkeit?

wenn musst du dir eine funktion selber bauen...die PWM stellt nur die 
geschwindigkeit des motors ein..die drehrichtung kommt von den pins..

von Karl H. (kbuchegg)


Lesenswert?

> 1) ich habe in meiner anlage zwar ein poti welches ich nutzen kann,
> dies sollte aber späte rnichtmehr benutzt werden

Später ist später. Jetzt ist jetzt.

Und jetzt brauchst du erst mal eine ordentliche Ansteuerfunktion für den 
Motor. Und eine Möglichkeit die zu testen.
Später, wenn deine Tests abgeschlossen sind, kannst du ja das Poti 
wieder anderweitig benutzen.


> nun aber die frage, kann ich denn die PWM auch
> irgendwie nutzen, die drehrichtung zu ändern, oder geht das nicht?=

Genau darum geht es:
Das du eine Funktion brauchst, die BEIDES macht.
Sowohl die Geschwindigkeit ALS AUCH die Richtung einzustellen. Und das 
möglichst, indem man ihr EINEN Wert gibt, in dem beides in irgendeiner 
Form enthaten ist (denn den Wert wirst du später aus dem PI Regler 
bekommen).

> die PWM geht ja vn 0-1023, gibt es sowas wie einen
> mittelpunkt -> 512 als umschaltpunkt?

Nein. Denn 'Geschwindigkeit' ist ein in diesem Zusammenhang ein skalarer 
Begriff. Deine Motorgeschwindigkeit ist hier etwas absolutes. Die geht 
von Stillstand bis Vollgas. 0 bis 100%
Aber: dein µC kann ja rechnen. Es spricht ja nichts dagegen, dass du mit 
dem Wert, den die Funktion bekommt, erst mal ein bischen rumrechnest, 
ehe du dann die Werte hast mit denen du die Richtungspins einstellst 
bzw., den OCR Wert für den PWM-Timer hast. Nicht immer sind die Dinge so 
einfach, dass man aus einer Hardware Komponente einen Wert bekommt, den 
man unverändert in ein andere Komponente reinsteckt und dann passt das 
schon.
Leg deine Abneigung gegen Mathe beiseite und gewöhn dich daran, dass du 
auch mal ein paar Formeln 'erfinden' musst. Du wirst sehen: Es geht 
selten über die Grundrechenarten hinaus, die meisten Umrechnungen lassen 
sich mit ein wenig Phantasie leicht finden und der berühmt/berüchtigte 
Dreisatz ist dein Freund.



Du klebst noch viel zu sehr an vorhandenem Code. Es ist nicht verboten, 
das man Code, den man schon geschrieben hat, auch mal ändert, wenn es 
notwendig ist und sich die Anforderungen geändert haben. Und es ist auch 
nicht verboten, sich Zwischenziele zu setzen, in denen man Komponenten 
kurzfristig zweckentfremdet, wenn es der Sache das Zwischenziel zu 
erreichen dienlich ist. Die Vorstellung: Ich fang heute zu coden an und 
dann schreibe ich nur Code, der dann in Zement gemauert auch im fertigen 
Programm enthalten sein wird ist eine falsche. Tatsächlich funktioniet 
Software-Entwicklung eher wie 'anschleichen an das Ziel'. Die grobe 
Richtung kennt man, aber dann hangelt man sich von Busch zu Busch - von 
einer sicheren Position zur nächsten.

von xfr (Gast)


Lesenswert?

Bevor man anfängt irgendwas zu programmieren sollte man aber zumindest 
mal eine Vorstellung davon haben, wie das Projekt am Ende aussehen soll. 
Das scheint bisher nicht der Fall zu sein.

Wir haben also einen Motor, der vorwärts und rückwärts drehen kann. 
Bisher aber nur binär, d.h. Vollgas vorwärts oder rückwärts. Außerdem 
ein Poti am ADC, das bisher nicht benutzt wird und am Ende auch nicht 
benutzt werden soll?

Woher kommen Soll- und Istwert für die Regelung? Was soll geregelt 
werden? Die Geschwindigkeit oder vielleicht die Position von etwas, das 
der Motor bewegt? Ist vielleicht gar keine Regelung sondern nur eine 
Steuerung gefragt?

Vielleicht weiß der TO das alles, dann will ich nichts gesagt haben. Ich 
habe aber nicht den Eindruck ...

von Bronco (Gast)


Lesenswert?

xfr schrieb:
> Vielleicht weiß der TO das alles, dann will ich nichts gesagt haben. Ich
> habe aber nicht den Eindruck ...

Sven Weinmann schrieb:
> Mein Lehrer gab mir die Aufgabe im Zuge eines Projektes
> und hat davon leider wenig Ahnung, er meinte nur es geht.

Wer soll es ihm denn auch beibringen?

von Karl H. (kbuchegg)


Lesenswert?

xfr schrieb:

> Woher kommen Soll- und Istwert für die Regelung? Was soll geregelt
> werden? Die Geschwindigkeit oder vielleicht die Position von etwas, das
> der Motor bewegt? Ist vielleicht gar keine Regelung sondern nur eine
> Steuerung gefragt?

Ich hab eine gewisse Vorstellung entwickelt, was eigentlich das Ziel 
sein soll. Ob sie stimmt oder nicht, weiß ich nicht.
Aber vor meinem geistigen Auge gibt es da einen 'Schlitten', der über 
einen Riemen gezogen auf einer Bahn läuft. Und es gibt einen Motor samt 
Poti, die ebenfalls vom Riemen 'umschlungen' sind.
Das ganz ist nicht ganz unähnlich einer Druckkopfmechanik, mit Poti zur 
Positionsrückmeldung.

Ziel ist es den Schlitten an eine bestimmte Position zu fahren, wobei 
die Position durch die Potistellung (und damit durch eine Spannung) 
definiert wird.


Das ist mein mentales Arbeitsmodell.
Vielleicht liege ich völlig falsch, vielleicht auch nicht. Wer weiß das 
schon.

Vielleicht gehts auch einfach nur um eine Drehzahlregelung.

von Sven W. (sickone4)


Lesenswert?

hallo leute,

danke für die kommentare, ihr habt natürlich recht.

folgedes zu den werten:

ich habe einen 12v motor mit sehr hoher drehzahl.
dieser ist über zahnräder mit einer "seilsteuerung" verbunden, welche 
einen schlitten über eine aluschiene bewegt.

an dem zahnradkonstrukt(, welches ich nicht als getriebe deute!), ist 
auch ein poti zur positionierung des schlittens dran.

nun soll später durch ein programm die fahrt von endpunkt zu endpunkt 
realisiert werden.

im moment geht das durch vollgas vorwärts/vollgas rückwärts, wie karl 
heinz das wunderbar aus meinem code gelesen hat.

stattdessen soll aber keine vollgasfahrt sondern eine PI geregelte fahrt 
gemacht werden (aufgabenstellung), welche auch von anfang zum ende 
fährt, aber eben auch mal an einem genauen punkt angehalten werden kann.

REAL:
if (position == wunschwert)
{
  mnotorstop;
}

vereinfacht dargestellt.

was aber passiert ist folgendes:
er bleibt tatsächlich stehen, aber eben nicht am wunschwert sondern an 
einem x-beliebigen wert dahinter. auch die endpositionsanfahrt ist jedes 
mal ein anderer wert.

daher die PI regelung -> durch den P anteil wird ja der proportionale 
anteil gefahren, ich nenne es mal "den gröbsten teil der strecke" und 
mit dem I anteil die "anfahrt an den wunschwert"
dass der PI regler den wunschwert nicht 100% erreicht ist klar, sonst 
wärs keine regelung. (regeldifferenz 0 = unsinn!)


was ich also tun muss, ist mir einen schlachtplan zu entwickeln, wie ich 
mich dahin programmiere sozusagen.

karl heinz sagte so schön, man muss über umwege gehen. das problem ist 
jedoch, dass ich den umweg nicht kenne, oder erst kennen lernen muss, 
weil ich nicht weiß wie dieser aussehen könnte.

mitlerweile sind wir soweit, dass ich meinen quellcode so anpassen 
möchte,
dass der PWM wert 0-1023 in der mitte (511/512) = 0 ist und bei 0-510 
-100%-1% hat und bei 513-1023 1%-100%

diesen dann enthaltenen wert gebe ich auf den enable eingang am L298. 
und in abhängigkeit ob der wert positiv oder negativ ist drehrichtung A 
oder B.

wie ich damit dann allerdings in richtung PI regler komme weiß ich noch 
nicht. vermutlich ist der momentan genutzte PWM wert später mein Y, aber 
das ist nur eine vermutung.


später soll an diesem schlitten ein sensor o.Ä. angebracht werden, der 
an genauen punkten messwerte ausgibt. aber das ist nicht mein projekt.

ich hoffe mich etwas verständlicher ausgedrückt zu haben.

gruß
sven

von Karl H. (kbuchegg)


Lesenswert?

Sven Weinmann schrieb:

> REAL:
> if (position == wunschwert)
> {
>   mnotorstop;
> }
>
> vereinfacht dargestellt.
>
> was aber passiert ist folgendes:
> er bleibt tatsächlich stehen, aber eben nicht am wunschwert sondern an
> einem x-beliebigen wert dahinter. auch die endpositionsanfahrt ist jedes
> mal ein anderer wert.

Logisch.
Das übliche Problem:
Wenn man nicht rechtzeitig genug bremst (die Geschwindigkeit reduziert), 
dann knallt man mit dem Auto unweigerlich in die Rückwand der Garage.

> daher die PI regelung -> durch den P anteil wird ja der proportionale
> anteil gefahren, ich nenne es mal "den gröbsten teil der strecke" und
> mit dem I anteil die "anfahrt an den wunschwert"
> dass der PI regler den wunschwert nicht 100% erreicht ist klar, sonst
> wärs keine regelung. (regeldifferenz 0 = unsinn!)

Doch, wenn der gut eingestellt ist, dann macht der das.
Kurz vor dem Ziel wird die Geschwindigkeit zurückgenommen. Der Schlitten 
beginnt zu 'bremsen' und kommt im Idealfall mit dem Ende der 
Bremsperiode genau an der Wunschposition zum stehen.

> karl heinz sagte so schön, man muss über umwege gehen. das problem ist
> jedoch, dass ich den umweg nicht kenne, oder erst kennen lernen muss,
> weil ich nicht weiß wie dieser aussehen könnte.

Wie machst du es denn im realen Leben?
Läufst du volle Kanne auf eine Wand zu oder richtest du deine 
Geschwindigkeit danach aus, wie weit du noch von der Wand entfernt bist?

Entfernung von der Wand:   -> Regelabweichung

Je kleiner die Abweichung, desto kleiner wird die Geschwindigkeit.
Bist du mit dem Fahrrad 300 Meter von der Wand entfernt, dann fährst du 
volle Kanne auf die Wand zu. Ab vielleicht 50 Meter ENtfernung beginnst 
du zu bremsen und die letzten Zentimeter lässt du es ganz langsam 
rollen, bis die Reifen an der Wand anstehen.
Ein 'schärfer eingestellter' Regler (Brain 2.0) hat den Dreh raus, wie 
man aus voller Kanne mit quietschenden Bremsen den Reifen exakt an die 
Wand einparkt.


>
> wie ich damit dann allerdings in richtung PI regler komme weiß ich noch
> nicht.

Gar nicht.
Der hat damit ja nichts zu tun.

Der PI-Regler benutzt dann dieses Funktion um die von ihm errechneten 
Geschwindigkeitswerte (die sich nach der 'Regeldifferenz', also dem 
Abstand zur Zielposition richten) in eine Motorgeschwindigkeit 
umzusetzen. Nämlich jene Geschwindikeit mit der er ans Ziel kommt ohne 
darüber hinauszuschiessen. Und wenn er mal darüber hinausschiesst, dann 
muss er eben zurückfahren - dazu braucht er einen Rückwärtsgang. Für den 
Regler ist es am einfachsten, wenn er sich um solche 'Details' nicht 
kümmern muss. Er hat einfach eine positive und eine negative 
Geschwindigkeit.


Du verwechselst jetzt gerade das Gaspedal (+ Gang-Schaltung) mit dem 
Menschen, der aufs Pedal drückt. Jetzt hast du erst mal das Gaspedal 
implementiert.

> vermutlich ist der momentan genutzte PWM wert später mein Y, aber
> das ist nur eine vermutung.

Das eigentlich traurige ist, dass du so gar keine Ahnung oder 
Vorstellung davon hast, wie die Dinge zusammenspielen. Du hast seit den 
Tagen als du als Kind Fahrradfahren gelernt hast, genau dasselbe 
tausende male gemacht. Hier heißen die Dinge ein wenig anders und sind 
technischer beschrieben bzw. in einen Formalismus eingebunden. Aber das 
Prinzip und die Einzelkomponenten sind da wie dort genau die gleichen.

Man kann viel davon lernen, wie und aus welchen Komponenten ein Programm 
aufgebaut sein könnte, wenn man sich eine ähnliche Aufgabenstellung aus 
dem täglichen Leben sucht und sich mal überlegt, wie man da eigentlich 
vorgeht. Ich würde mal schätzen, dass mindestens 80% der weniger 
ausgeklügelten Algorithmen genau darauf beruhen, dass man sich ansieht, 
wie eigentlich das Gehirn aus Erfahrung heraus ein gleichwertiges 
Problem löst.
Wir Menschen können viel - nur wissen wir oft gar nicht bewusst, wie wir 
das machen. Als Informatiker ist man immer gut beraten, sich selbst mal 
bei einer gleichwertigen Problemlösung zu beobachten.

von xfr (Gast)


Lesenswert?

Sven Weinmann schrieb:
> ich hoffe mich etwas verständlicher ausgedrückt zu haben.
Ja, damit kann man was anfangen. Du hast allerdings ein ganz 
grundlegendes konzeptionelles Problem: Mit dem Aufbau ist keine Regelung 
möglich. Für eine Regelung brauchst Du genau das hier:

> später soll an diesem schlitten ein sensor o.Ä. angebracht werden, der
> an genauen punkten messwerte ausgibt. aber das ist nicht mein projekt.

Alles was mit Du mit Deinem jetzigen Aufbau machen kannst, ist dem Motor 
eine Geschwindigkeit vorgeben, mehr nicht. Du weißt nicht, an welcher 
Position er sich befindet. Dieser Code hier

> if (position == wunschwert)
> {
>   mnotorstop;
> }

wird also nicht möglich sein. Denn woher soll der Wert "position" 
kommen, wenn nicht von einem Sensor?

Das einzige, was Du derzeit machen kannst, ist folgendes:

Du gehst davon aus, dass sich der Aufbau beim Einschalten in einem 
definierten Zustand befindet, das heißt der Schlitten ist z.B. ganz 
links. Wenn Du an Position x fahren willst, lässt Du den Motor eine 
bestimmte Zeit lang mit einer bestimmten Geschwindigkeit nach 
rechts/links drehen. Gemäß v = s / t kannst Du das grob ausrechnen.

Das Problem ist: Du weißt nicht, ob der Schlitten danach tatsächlich an 
der Stelle ist. Es kommen ja noch Effekte wie Beschleunigung, Abbremsen 
und andere Ungenauigkeiten ins Spiel. Mit der Zeit wird also die 
geschätzte Position und die tatsächliche Position sich immer weiter 
voneinander entfernen.

Um das zu verhindern, macht man eine Regelung. Das heißt, man misst, wo 
sich der Schlitten befindet (Ist-Wert) und vergleicht das mit der 
Position, an der er sein sollte (Soll-Wert). Wenn die Differenz ungleich 
Null ist, lässt man den Motor in die entsprechende Richtung fahren. Wenn 
man die Regelung richtig auslegt, erreicht der Schlitten diesen Punkt 
dann auch (innerhalb der Messgenauigkeit und Feinheit der 
Motoransteuerung). Das geht aber wie gesagt erst, wenn man auch einen 
gemessenen Ist-Wert hat.

von Karl H. (kbuchegg)


Lesenswert?

xfr schrieb:

> grundlegendes konzeptionelles Problem: Mit dem Aufbau ist keine Regelung
> möglich. Für eine Regelung brauchst Du genau das hier:
>
>> später soll an diesem schlitten ein sensor o.Ä. angebracht werden, der
>> an genauen punkten messwerte ausgibt. aber das ist nicht mein projekt.
>
> Alles was mit Du mit Deinem jetzigen Aufbau machen kannst, ist dem Motor
> eine Geschwindigkeit vorgeben, mehr nicht. Du weißt nicht, an welcher
> Position er sich befindet.

Langsam.
Er hat von den Dingen gesprochen, die am Schlitten montiert sind (und 
die für uns uninteressant sind). Interessant ist nur, dass sich am 
Antrieb ein Poti befindet, welches eine Aussage über die momentane 
Schlittenposition erlaubt. Er hat das in einem Nebensatz irgendwo 
erwähnt und dafür lieber über Dinge erzählt, die für die Aufgabe 
irrelevant sind :-)

Das übliche halt: Vor lauter 'komplexer Aufgabenstellung' verliert man 
aus lauter Ehrfurcht vor dem Schwierigkeitsgrad die tatsächlich 
wichtigen Dinge aus den Augen. Das Kaninchen sieht aus lauter Angst vor 
der Schlange nicht den Adler, der sich gerade auf die Schlange stürzt.

von xfr (Gast)


Lesenswert?

Sven Weinmann schrieb:
> an dem zahnradkonstrukt(, welches ich nicht als getriebe deute!), ist
> auch ein poti zur positionierung des schlittens dran.

Vielleicht habe ich das aber auch falsch gedeutet. Wenn dieses Poti die 
Position des Schlittens erfasst, dann ist das Dein Ist-Wert. Damit ist 
dann natürlich eine Regelung der Position möglich.

Die Aufgabe der Regelung ist also grob gesagt: Je größer der Abstand 
zwischen Soll- und Ist-Position, desto schneller den Motor in die 
Richtung fahren lassen.

von xfr (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Er hat von den Dingen gesprochen, die am Schlitten montiert sind (und
> die für uns uninteressant sind). Interessant ist nur, dass sich am
> Antrieb ein Poti befindet, welches eine Aussage über die momentane
> Schlittenposition erlaubt. Er hat das in einem Nebensatz irgendwo
> erwähnt und dafür lieber über Dinge erzählt, die für die Aufgabe
> irrelevant sind :-)

Jep, habe es jetzt auch gelesen. Ich war gedanklich die ganze Zeit bei 
einem Poti mit Drehknopf, mit dem ein Mensch den Sollwert einstellt ...

von Bronco (Gast)


Lesenswert?

1. Potiwert per ADC messen
2. ADC-Wert in absolute IstPosition umrechnen
3. Differenz zwischen IstPosition und SollPosition ausrechnen (mit 
Vorzeichen!) -> Regeldifferenz
4. Regelgleichung mit der Differenz berechnen (mit Vorzeichen und gegen 
Überläufe abgesichert), ergibt die Stellgröße
5. Stellgröße in PWM umrechnen
6. PWM auf Motor geben

P-Regler:
Die Differenzstrecke zwischen Soll und Ist multipliziert mit einem 
festen Faktor ergibt die Motorleistung. Der Schlitten bleibt dann 
stehen, wenn er entweder genau am Ziel ist oder die Motorleistung nicht 
mehr reicht, um ihn zu bewegen (Reibung).

PI-Regler:
Der I-Anteil gibt sich nicht damit zufrieden, wenn der Schlitten nicht 
genau am Ziel ist. Er erhöht die Motorleistung, wenn der Schlitten neben 
dem Ziel steht, aber der P-Anteil schon zu gering ist, um die Reibung zu 
überwinden.

Sven Weinmann schrieb:
> dass der PI regler den wunschwert nicht 100% erreicht ist klar, sonst
> wärs keine regelung. (regeldifferenz 0 = unsinn!)
Doch! Der Sinn des I-Anteil ist es, die Regelabweichung zu minimieren!

Zu beachten:
Der Regler kann überschwingen, d.h. der Schlitten fährt über's Ziel 
hinaus. Hier ist die Frage, ob bzw. wie weit Deine Maschine das erlaubt.
Als Faustregel gilt: Je schneller der Regler, umso mehr schwingt er 
über.
Ist auch logisch: Mit hohem P-Anteil fährt der Schlitten mit voller 
Motorleistung nahe ans Ziel und fährt dann wegen seiner Trägheit über's 
Ziel hinaus. Mit kleinem P-Anteil schleicht sich der Schlitten an, aber 
er braucht auch länger, weil er langsamer fährt.

von Sven W. (sickone4)


Lesenswert?

Hey Leute, danke für die vielen Antworten!

hab mir das nun mal durchgelesen.

den Ansatz den Bronco gegeben hat ist sehr interessant, wobei mir der 2 
punkt nicht einleuichtet.

ich lese per ADC den Potiwert, dieser ist zw. 0..1023, also 1024 
Schritte.

wenn ich zu Position 500 fahren möchte, wieso muss ich ihn dann noch 
vorher umrechnen?

beispiel Istwert = 230 Sollwert = 500 dann ist die Regeldifferenz (e = 
w-r => e = 500 - 230 = +270

ich denke der Ansatz ist prima, wobei ich damit natürlich noch nicht mit 
der oben genannten Formel arbeiten kann.

Karl Heinz wird wahrscheinlich sagen, "wieso wieder mit der Tür ins Haus 
fallen, der junge braucht Grundlagen" und genau da stimme ich ihm an 
dieser Stelle zu.

wir waren bei der geschriebenen PWM:

da stand die frage im Raum, durch den pwm wert die geschwindigkeit zu 
regeln.
0..1023 umzurechnen in -100 .. 0 .. +100 SPEED

der jetzt genutzte Poti hat allerdings nichts mit der Position zutun, 
vom Schlitten!

Dieser ist später erst zu benutzen!

von xfr (Gast)


Lesenswert?

Sven Weinmann schrieb:
> ich lese per ADC den Potiwert, dieser ist zw. 0..1023, also 1024
> Schritte.
>
> wenn ich zu Position 500 fahren möchte, wieso muss ich ihn dann noch
> vorher umrechnen?

Du musst Dich für eine Einheit für die Position entscheiden. Du kannst 
dafür direkt den ADC-Wert nehmen, dann musst Du nichts umrechnen. Du 
hast aber ja neben dem Ist-Wert auch noch den Soll-Wert, den der 
Benutzer vorgibt. Vielleicht möchte der ja lieber die Position in 
Zentimetern angeben statt in "ADC-Spannung". Dann würde es sich 
anbieten, den gemessenen ADC-Wert in Zentimeter umzurechnen und dann 
erst zu vergleichen.

Sven Weinmann schrieb:
> ich denke der Ansatz ist prima, wobei ich damit natürlich noch nicht mit
> der oben genannten Formel arbeiten kann.

Mit "oben genannter Formel" meinst Du die im Ausgangspost, für den 
PI-Regler? Das ist Schritt 4.

Sven Weinmann schrieb:
> wir waren bei der geschriebenen PWM:
>
> da stand die frage im Raum, durch den pwm wert die geschwindigkeit zu
> regeln.
> 0..1023 umzurechnen in -100 .. 0 .. +100 SPEED

Die Geschwindigkeit soll nicht geregelt werden, sondern später die 
Position. Deine erste Aufgabe (sofern das noch nicht funktioniert) ist, 
den Motor mit unterschiedlichen Geschwindigkeiten vor- und rückwärts 
fahren zu lassen. Also statt nur Ein und Aus ein PWM-Signal zu erzeugen.

Das ist aber erstmal nur eine reine Steuerung, ohne Messen der 
tatsächlichen Geschwindigkeit. Die Regelung kommt später, aber dann 
als Positionsregelung, nicht als Geschwindigkeitsregelung.

von xfr (Gast)


Lesenswert?

xfr schrieb:
> Vielleicht möchte der ja lieber die Position in
> Zentimetern angeben statt in "ADC-Spannung". Dann würde es sich
> anbieten, den gemessenen ADC-Wert in Zentimeter umzurechnen und dann
> erst zu vergleichen.

Vielleicht noch als Ergänzung:

Hinsichtlich Genauigkeit wäre es hier allerdings sinnvoller, Zentimeter 
in "ADC 0-1023" umzurechnen. Die Erklärung war grundsätzlicher gemeint, 
also warum man im Allgemeinen den ADC-Wert eventuell nicht 1:1 
weiterverwenden kann, sondern in die richtige Einheit umrechnen muss.

von Bronco (Gast)


Lesenswert?

Sven Weinmann schrieb:
> wenn ich zu Position 500 fahren möchte, wieso muss ich ihn dann noch
> vorher umrechnen?

Hat zwei Gründe:
1. Der Mensch versteht physikalische Einheiten besser als Hexwerte, 
wodurch das Debuggen einfacher wird. Wenn Du irgendwo in Deiner Rechnung 
einen Wert von 0x3354 vorfindest, wird gerade ein ambitionierter 
Einsteiger nicht sofort wissen, ob das sinnvoll ist oder total daneben 
liegt.
2. Ein Istwert-Sensor (in Deinem Fall der Poti) hat oft keinen linearen 
(proportionalen) Zusammenhang von Spannung und physikalischem Meßwert, 
sondern irgendeine Kurve. In dem Fall wäre der ADC-Wert dann nicht 
proportional zur Position. Um es mit Monthy Python zu sagen: Hast Tu Tas 
üperprüft?

Eines noch:
Du mußt wirklich sehr genau darauf achten, die Werte und 
Zwischenergebnisse auf ihre erlaubten Werteräume zu begrenzen und 
Überläufe zu vermeiden.
Aber das steht auch in der Atmel Appnote drinn.

von Karl H. (kbuchegg)


Lesenswert?

Das Argument mit der Nichtlinearität ist ok.
Aber das andere ist eine reine Frage der Anzeige.

Ob der Regler jetzt von Position 258 zur Position 876 fahren soll und 
beide Zahlen ADC Einheiten sind, oder ob er von Position 12.8 zur 
Position 34.2 fahren soll und beides Zentimeter sind, ist ziemlich egal. 
Beides sind einfach nur Zahlen. Und mit dem Kp, Ki Werten ist sowieso 
keine physikalische Vorstellung verknüpft ausser einer gewissen 'Stärke' 
mit der der Regler reagiert.

D.h. Eine Sollvorgabe vom Benutzer gleich mal in ADC Einheiten 
umzurechnen und dann innerhalb des Reglers nur mit ADC Einheiten zu 
arbeiten ist  genauso gut/schlecht wie anders rum. Nur der Rechenaufwand 
im Regler ist geringer, weil man sich eine sinnlose 
Bereichskonvertierung spart. (und sich hoffentlich dann auch bewusst 
ist, dass man auf die Art den überhaupt möglichen Verfahrweg in 
lediglich 1024 Teile aufgeteilt hat. D.h. das ist bei 1 Meter ca. 1 
Millimeter und selbst die werden nicht wirklich stimmen)

von Wolfgang-G (Gast)


Lesenswert?

>Den Motor steuere ich über einen L298 Motortreiber
Es handelt sich also um eine Schrittmotorsteuerung. Wozu braucht man 
dabei einen PI-regler?
Wenn ich z. B. sage, der Motor soll 200 Schritte nach links machen, dann 
bleibt er nach 200 Schritten stehen.
Sollte der Motor durch Trägheit über das Ziel, wie hier angegeben, 
hinaus schießen, dann kann man evtl. bei den letzten 10-15 Schritten die 
Geschwindigkeit reduzieren. Dann bleibt der Motor genau am gewünschten 
Ziel stehen.
Oder habe ich da etwas falsch verstanden?
MfG

von Sven (Gast)


Lesenswert?

Der 298 ist ein motortreiber. Man kann damit in Kombination mit einem 
297 auch einen schrittmotor ansteuern. Was ich auch in einen anderen 
Projekt schon getan habe. Aber hier geht's nur um einen 12v dc Motor.

von Sven W. (sickone4)


Lesenswert?

ich hätte kurz eine frage:

wie übergebe ich z.b. dem PIN B4 den wert von Y?

PORTB |= (1<<4);

wie übergebe ich den PWM wert an diesen?

oder muss der pin dann der vom OCR1A sein?

von xfr (Gast)


Lesenswert?

Mit PORTB kann man den Pin nur ein- und ausschalten, also auf 0 oder 1 
setzen. Du musst einen Timer so einrichten, dass er ein PWM-Signal an 
dem Pin erzeugt. Wie das geht steht im Tutorial.

von Sven W. (sickone4)


Lesenswert?

hey leute,

ich hab dann mal eine kurze lösung:
1
    Ist_Wert   = ADC_Read(0);    // Istwert
2
    Soll_Wert  = ADC_Read(1);    // Sollwert
3
4
    r = Ist_Wert;
5
    w = Soll_Wert;
6
    
7
    e = w - r;            // Bildung der Regeldifferenz
8
    
9
    // PI-Regler
10
    
11
    if ((y < 1023) && (y > 0))    // bei Übersteuertem stellglied Integration einfrieren
12
    {                // (Anti-Windup)
13
      esum = esum + e;      // Summe der Regelabweichung aktualisieren
14
    }    
15
    
16
    y = (Kp * e) + (Ki * Ta *esum);  // Formel des PI Reglers -> Kp = Proportionalbeiwert, Ki = Integrierbeiwert, Ta = Abtastzeit
17
    
18
    if ( y < -5 )          { Motor_X(Links, abs(y)); }  // Drehrichtung Links  und PWM Wert  
19
    if ( y >  5 )          { Motor_X(Rechts,abs(y)); }  // Drehrichtung Rechts und PWM Wert
20
    if ((y >= -5 ) && ( y <= 5 )) { Motor_X(Stop,  0     ); }  // Drehrichtung "Stop" und PWM = 0
21
                    
22
    if ( y > 1023) { y = 1023; }  // Ist y größer  als 1023 dann soll y = 1023 sein
23
    if ( y < 0   ) { y = 0;    }  // Ist y kleiner als 0    dann soll y = 0    sein
24
                    // 0..1023 = 10bit PWM
// Die Richtungen Links und Rechts sind via define mit 1 und 0 belegt.

folgendes:

ich gebe mit einem poti, wessen wert ich via ADC einlese einen wert vor, 
an den der motor fährt. anhand des control centers sehe ich den ist/soll 
wert und die sprünge.

ich arbeite mit den werten:
Ta = 2;
esum = 0;
Kp = 10;
Ki = 2;

und das ist mein unterprogram, mit welchem ich den motor ansteuer:
1
void Motor_X( uint8_t EingangA, int8_t Speed)
2
{
3
  uint8_t EingangB;
4
  
5
  OCR1A = Speed;
6
7
  PORTB |= (1<<1);
8
  
9
  if (EingangA == 2)        // Vollbremsung
10
  {
11
    PORTB |=  (1 << 2);      // Eingang A = 1
12
    PORTB |=  (1 << 3);      // Eingang B = 1
13
  }
14
  
15
  if (EingangA == 0)        // Rechts
16
  {
17
    PORTB &= ~(1 << 2);      // Eingang A = 0
18
    PORTB |=  (1 << 3);      // Eingang B = 1
19
  }
20
    
21
  if (EingangA == 1)        // Links
22
  {
23
    PORTB |=  (1 << 2);      // Eingang A = 1
24
    PORTB &= ~(1 << 3);      // Eingang B = 0
25
  }
26
   return;
27
}


ich bin mir sicher, dass der P-Regler funktioniert, da ich den Ki Anteil 
zunächst auf 0 gesetzt habe, und die Sprünge des Reglers im Control 
Center ausgewertet habe.
jedoch der I Anteil fehlt mir.
Im Controlcenter sehe ich lediglich 10er Werte, keine "krummen" Werte, 
welche aus der rechnung mit dem Ki-Teil resultieren sollten.

habe ich da noch einen fehler drin, dass der I-Regler nicht 
funktionieren könnte?

achja UND :) die bereichseingrenzung > 1023 und <0 ist nicht in der 
übergabe an den motor enthalten! d.h. die müsste ich irgendwie noch hier 
rein bringen ->
1
if ( y < -5 )          { Motor_X(Links, abs(y)); }  // Drehrichtung Links  und PWM Wert  
2
    if ( y >  5 )          { Motor_X(Rechts,abs(y)); }  // Drehrichtung Rechts und PWM Wert
3
    if ((y >= -5 ) && ( y <= 5 )) { Motor_X(Stop,  0     ); }  // Drehrichtung "Stop" und PWM = 0

dafür hab ich noch keine lösung gefunden!

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.