# Verschachtelte Schleife vorzeitig abbrechen.



## papapete (18. Mai 2012)

Hallo Leute... hab mal wieder ein Problem.

Habe folgende Regelaufgabe:
USB-Interface, über das ein Messwert eingelesen wird.
Einen Schieber, der einen Rohrquerschnitt verengt und damit auch den Messwert verändert.
Einen zu messenden Wert, der eben über den Schieber "angefahren" werden soll.
Wenn der Messwert den zu messenden Wert erreicht (+- 4%) soll 3sec gewartet werden und der Messwert gespeichert werden. 
Aber wenn in der Zeit (3sec) der Messwert wieder ausserhalb der +-4% ist, soll der Schieber wider nachregeln.
Habe das bisher so gelöst:

loop3 und 4 werden an anderer Stelle auf true gesetzt und SchieberRegelung aufgerufen.


```
public class SchieberRegelung extends Thread{
	@Override
	public void run() {
        while ( loop3) {
        	if (schieberPos<=255 & schieberPos>=0){
        		if(gemessenerWert<zuMessenderWert*1.04 && gemessenerWert>zuMessenderWert*0.96){
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						interrupt();
					}
					if(loop4){
						loop4=false;
						counter=zeile+1;
							
						for (int i = 0; i <= 3; i++) {
			            	try {
				                    meldArea.setText("Warte " + i+" sec.");
				                    Thread.sleep(1000);
				            	} catch (InterruptedException e) {
				            		interrupt();
				            	}
			             }
						if(counter==zeile+1){
							meldArea.setText("Messpunkt erfasst.");
							Schreiben();
						}
					}
					
				}
				else{
    					loop4=true;
    					counter=zeile;
    				if (gemessenerWert<zuMessenderWert){
            			schieberPos=schieberPos+1;
            			jv.OutputAnalogChannel(1, schieberPos);
            			SchieberProg.setValue((int)Math.round(schieberPos/2.55));
            			try {
							Thread.sleep(150);
						} catch (InterruptedException e) {
							interrupt();
							e.printStackTrace();
						}
            		}
            		else{
            			schieberPos=schieberPos-1;
            			jv.OutputAnalogChannel(1, schieberPos);
            			SchieberProg.setValue((int)Math.round(schieberPos/2.55));
            			try {
							Thread.sleep(150);
						} catch (InterruptedException e) {
							interrupt();
							e.printStackTrace();
						}
            		}
				}
        	}
        	else{
        		if (schieberPos>127){
        			schieberPos=255;
        		}
        		else{
        			schieberPos=0;
        		}
        	}
        }

    }
}
```


Funktioniert soweit eigentlich ganz gut.
Wenn sich das Programm aber in der For-Schleife befindet und der Messwert die +-4% verlässt und dann wieder drinn ist, scheint es so als ob 2 parallele For-Schleifen.
Wie kann ich ganz sicher die For-Schleife in der die 3sec gezählt werden abbrechen wenn der Messwert die +-4% verlässt?

Hoffe ich konnte es halbwegs verständlich erklären und Ihr mir helfen könnt.

Danke schon mal im Voraus


----------



## SlaterB (18. Mai 2012)

> scheint es so als ob 2 parallele For-Schleifen.
sollte dieser Satz noch weitergehen, abgesehen vielleicht von [laufen]?

was du meinst ist wahrlich unklar, 
direkt zu sagen ist, dass eine Schleife mit break; abgebrochen werden kann, wenn man nicht an den Bedingungen der Schleife a la loop4858 arbeitet,

> Wie kann ich ganz sicher die For-Schleife in der die 3sec gezählt werden abbrechen wenn der Messwert die +-4% verlässt?
läßt aber auch andere Fragen zu,
wie ändert sich der Messwert, unabhängig von der Schleife? 
ist noch jemand anders da der währenddessen misst, soll derjenige diese Schleife, diesen Thread informieren und deswegen für den Abbruch der Schleife sorgen?
wenn nicht dann gibt es zu Beginn der 3 sec-Schleifen keinen Grunden, je von einam anderen Messwert auszugehen/ die Schleife überhaupt abzubrechen,

die angesprochenden '2 parallele For-Schleifen' gehen auch in Richtung dieser Fragen..


----------



## papapete (18. Mai 2012)

Ja die parallelen Schleifen laufen.

Also ich habe einen anderen Thread, der in einer while-Schleife dauernd den Messwert misst.
Ist der Messwert über dem zuMessendenwert soll der Schieber aufgehen, ist er darunter soll der Schieber zugehen. Kommt der Messwert aber in den +-4% bereich, soll einfach eine Zeit lang (Beruhigungszeit) gewartet werden und der Messwert gespeichert werden. Wenn aber in der Beruhigungszeit der Messwert die +-4% Marke verlässt, soll der Schieber nochmal nachjustieren und wieder warten, bevor gespeichert wird.


----------



## SlaterB (18. Mai 2012)

vieles muss ich eher durch Vermutung dazuaddieren, 
durch meinen Text wird vielleicht klar, was ich mir gerade unter deinem Programm + Problem vorstelle:

drei Schritte

a)
kann der andere Thread diesen hier durch interrupt() aufwecken?
alternativ könnten die beiden mit wait/notify kommunizieren,
oder der andere Thread setzt irgenden boolean oder (sowieso schon) den neuen Messwert oder was auch immer,
notfalls passier hierzu gar nix

b)
dieser Thread hier, SchieberRegelung, kommt irgendwann ja wieder dran,
falls interruptet oder sonstwie direkt aufgeweckt so schnell wie möglich, 
ansonsten zumindest nach 1 sec bzw. nach 2 sec von den insgesamt 3 sec, 
das wären zwei Möglichkeiten schneller als vor Ablauf der gesamten Zeit zu reagieren,

wenn du das Thread.sleep() auf 100ms absenkst gibts noch viel mehr Möglichkeiten, auch ohne interrupt() bzw. wait/notify von außen,
mit richtigen Code kannst du dabei immer noch dafür sorgen, dass nur bei ganzen sec eine Ausgabe erfolgt

c)
nun irgendwann jedenfalls wurde der Thread extra aufgeweckt, was wahrscheinlich ein Zeichen dafür ist, dass etwas zu tun ist,
oder es liegt eine Routine-Überprüfung während des Wartens vor,
es kann nun
c1) falls nötig erst noch ein neuer/ der aktuelle Messwert geholt und die Grenze geprüft werden
c2) abgebrochen werden, das geht innerhalb der Schleife mit break;


----------



## Landei (18. Mai 2012)

Keine Ahnung, ob das hier das richtige ist (*), aber aus mehreren geschachtelten Schleifen kann man mit Labels ausbrechen:


```
einLustigerNameDenDuDirAusdenkenKannst:
for(foo : foos) {
   for(bar : bars) {
      if(bar.isFoobar()) {
         break einLustigerNameDenDuDirAusdenkenKannst; 
      }
   }
}
```

(*) Versuche mal deine Fragestellung aus Sicht eines Außenstehenden, der *nichts* über deine konkrete Aufgabenstellung weiß, zu lesen - und du bist so verwirrt wie wir.


----------



## Spacerat (18. Mai 2012)

BITTE KEIN BREAK-LABEL!!! Labels funktionieren nur rückwärts, wie Landei das schon demonstriert hat. Die Schleife wird bei Ihm allerdings erneut durchlaufen. Wenn man also einen Label hinter der Schleife setzt, ist dieser zum Zeitpunkt des Abbruchs noch gar nicht definiert und es kommt zum Compile-Fehler. 
Viel eleganter ist's, wenn man in der inneren Schleife eine Abbruchbedingung für die äussere Schleife setzt, z.B. einen Boolean hinzufügt oder den äusseren Schleifenzähler auf den Endwert setzt.


----------



## Tomate_Salat (18. Mai 2012)

Spacerat hat gesagt.:


> Die Schleife wird bei Ihm allerdings erneut durchlaufen.


Nein (dachte ich aber auch im ersten Moment [was gegen das Konstrukt spricht]):

```
String[] abc={"a","b","c"};

OUTER:
for(String a:abc) {
	for(String b:abc) {
		System.out.println(a);
		break OUTER;
	}
}
System.out.println("Ende");
```

ergibt:

```
a
Ende
```

Aber dennoch. Ich würde soetwas verwenden:

```
boolean run=true;
for(int i=0;i<abc.length && run;i++) {
	for(int j=0;j<abc.length && run;j++) {
		System.out.println(abc[j]);
		run=false;
	}
}
System.out.println("Ende");
```

Da weiß man gleich, wann die Schleife betreten wird und muss nicht erstnoch Labels im Code suchen. Außerdem ist das für viele leichter zu lesen als Labels.
... oder lager es gleich in Methoden aus.


----------



## Landei (18. Mai 2012)

Bevor man über Sinn und Unsinn streitet, sollte man schon wissen, wie es funktioniert 

(Wobei ich in diesem Fall die Abneigung gegen das Konstrukt einigermaßen nachvollziehen kann)

Aber Labels können auch sehr nützlich sein:

```
http: //dgronau.wordpress.com
...anderer Code...
```


----------



## Tomate_Salat (18. Mai 2012)

Landei hat gesagt.:


> Aber Labels können auch sehr nützlich sein:


Wer sie nicht kennt, den verwirrt das auch. Ich würde hier das http mit in den Kommentar setzen.


----------



## Spacerat (18. Mai 2012)

Tomate_Salat hat gesagt.:


> Ich würde hier das http mit in den Kommentar setzen.


Niemals!!! Sonst macht's ja keinen Sinn :lol:


----------



## Landei (18. Mai 2012)

Na wenigstens ein Ironiedetektor funktioniert noch


----------



## Tomate_Salat (18. Mai 2012)

Landei hat gesagt.:


> Ironiedetektor


Ist zusammen mit der Glaskugel in der Werkstatt ... :joke:


----------



## papapete (19. Mai 2012)

Hi nochmal. Sorry erstma für die Verwirrung, ist nicht ganz einfach zu erklären.
Hab das ganze Ding nochmal zerlegt und die Wartezeit in einen eigenen Thread gepackt. Zusätzlich habe ich einen KontrollThread der den Messwert überwacht.
Hoffe ich kann das jetzt einigermaßen verständlich machen. ... ALSO:

Von hier aus Starte ich 3 Threads:


```
public void StartMessung(){
	if (zeile <DatenTableModel.getRowCount()-2){
		messungLoop =true;
		schieberLoop=true;
		kontrollLoop=true;
		kontrolle=new Kontrolle();
		kontrolle.start();
		schieberRegelung=new SchieberRegelung();
		schieberRegelung.start();
		messung=new Messung();
		messung.start();
	}
	else{
                messungLoop=false;
		schieberLoop=false;
		kontrollLoop=false;
		}
}
```


```
public class Messung extends Thread{
    
	
        @Override
		public void run() {
            while(messungLoop) {																			
            	Hier wir der analoge Messwert erfasst und an die Variable messWert übergeben.
            }
        }
    }
```
 



```
public class SchieberRegelung extends Thread{
	@Override
	public void run() {
        while ( schieberLoop) {
        	Dieser Thread steuert nur den Schieber in Abhängigkeit vom Messwert
        }

    }
}
```

Der Kontroll-Thread soll nun den Messwert überwachen. Kommt er nun in den Bereich +-4% des gewünschten Wertes, soll der Thread messeMesspunkt gestartet werden, der dann 3sec wartet. Verlässt aber der Messwert in dieser Zeit den +-4% Bereich, soll der Thread messeMesspunkt abgebrochen werden.



```
public class Kontrolle extends Thread{
	public void run(){
		while(kontrollLoop){
		if(gemessenerWert<zuMessenderWert*1.04 && gemessenerWert>zuMessenderWert*0.96){
			
			messpunktLoop=true;
			messeMesspunkt=new MesseMesspunkt();
			messeMesspunkt.start();
		}
		else{
			messpunktLoop=false;
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		}
	}
}
```

Bleibt der Messwert über die 3 sec im +-4% Bereich, soll er mit Schreiben() in eine Tabelle geschrieben werden und der nächste Wert ist drann.


```
public class MesseMesspunkt extends Thread{
	public void run(){
			for (int i = 0; i <= 3 && messpunktLoop; i++) {
            	try {
	                    meldArea.setText("Warte " + i+" sec.");
	                    Thread.sleep(1000);
	            	} catch (InterruptedException e) {
	            		interrupt();
	            	}
             }
			meldArea.setText("Messpunkt erfasst.");
			Schreiben();
			
			
		}
	}
```

Hier sollen dann alle Thread fertiglaufen und beenden, damit mit StartMessung() der nächste Wert gemessen werden kann.


```
public void Schreiben(){
	kontrollLoop=false;
	schieberLoop=false;
	messpunktLoop=false;
	messungLoop=false;
	try {
		Thread.sleep(1000);
	} catch (InterruptedException e) {
	}
	DatenTableModel.setValueAt(DruckField.getText(), zeile, 2);
	DatenTableModel.setValueAt(VolStromField.getText(), zeile, 3);
	zeile++;
	StartMessung();
}
```


Ich hoffe ich konnte es verständlich machen. Das scheint bis auf wenige Ausnahmen zu funktionieren... ABER
Da es ein analoger Messwert ist, schwankt er sehr stark. Wenn man nun langsam an die "Grenze" des +-4% Breichs kommt, ist er sehr schnell "mal drinn dann wieder raus" und dann starten mir ganz ganz viele parallele Threads (im debug-Modus von eclipse getestet). Hat jemand ne Idee woran das liegen kann? oder wie ich das vllt. "eleganter" lösen könnte?


Gruß


----------



## Spacerat (19. Mai 2012)

Das ist jetzt keine Scherzfrage! Soll das eine programmtechnische Regelstrecke werden? Gewisse Paralellen lassen sich zumindest schon mal erkennen. Wenn dem so ist, solltest du deine Threads jedoch kontinuierlich (das bedeutet zyklisch) verwenden, statt immer neu zu starten. Ferner müsstest du jede Abweichung und nicht blos jene, die unter lowerBorder (96%) bzw. über upperBorder (104%) liegen, an ein Stellglied übermitteln weil der Regelwert sonst ausbricht. Letzteres könnte nämlich der Grund dafür sein, dass am Ende diese ganzen Threads zu häuf gestartet werden. Das Ganze geht soweit ich weis auch mit einem einzigen Thread bzw. einem Master-Thread, und evtl. einem wartenden Slave-Thread. Ist aber schon länger her, dass ich so etwas machen durfte und ich müsste mir noch mal ansehen, wie das genau ging.


----------



## papapete (20. Mai 2012)

Ja das ist eine Regelstrecke. Wobei ich nicht nur einen Wert habe. Deswegen habe ich gedacht es wäre sinnvoller nach jedem erfolgreich eingeregeltem und gemessenen Wert die Threads zu beenden und mit einem neuen Wert alles neu zu starten. 
Wie meinst du das mit dem Master/Slave Thread?


----------



## Spacerat (20. Mai 2012)

Da war doch irgend wie was mit Stellglied, Messglied und Sprungantwort.
Das Stellglied wäre der Slave-Thread, welcher vom Messglied nur "geweckt" wird, wenn es was zu Regeln gibt, also wenn sich im Messglied eine entsprechende Sprungantwort ergibt.
Das Messglied wäre also der Master-Thread.
Das ganze geht dann so, dass das Stellglied kontinuierlich Daten bekommt und diese solange an das Messglied durchschleift, bis dieses eine Unter- bzw. Überschreitung des Sollwertes per Sprungantwort sendet. Fortan schleift das Stellglied nicht blos mehr die Daten durch, sondern differenziert sie vorher anhand der Daten in der Sprungantwort. Das Stellglied als Slave, kann man sich sparen, wenn Eingang und Ausgang des gesammten Reglers bereits auf verschiedenen Threads laufen.
Ich such' das mal raus oder frickel es neu zusammen... wie gesagt, schon länger her.
[EDIT]BTW.: Das Stellglied wäre bei dir die Klasse "SchieberRegelung" und das Messglied die Klasse "Kontrolle", aber ich denke mal, das weisst du bereits...[/EDIT]


----------



## Spacerat (20. Mai 2012)

So, ich habe die Ein-Threadversion mal zusammengefrickelt.

```
public final class Regler
implements Regelglied
{
	private final double obergrenze, untergrenze;
	private final Stellglied sg;
	private final Messglied mg;

	private Regler(double sollwert, double abweichung)
	{
		obergrenze = sollwert * (1.0 + abweichung);
		untergrenze = sollwert * (1.0 - abweichung);
		sg = new Stellglied();
		mg = new Messglied();
	}

	@Override
	public double regle(double messwert)
	{
		return mg.regle(messwert);
	}

	private final class Stellglied
	{
		private double stellwert;

		public double getStellwert()
		{
			return stellwert;
		}

		public void addStellwert(double newStellwert)
		{
			System.out.print("Stellwert von " + stellwert + " auf ");
			stellwert += newStellwert;
			System.out.println(stellwert + " geändert");
			setSchieberHardware(newStellwert);
		}

		public void subStellwert(double newStellwert)
		{
			System.err.print("Stellwert von " + stellwert + " auf ");
			stellwert -= newStellwert;
			System.err.println(stellwert + " geändert");
			setSchieberHardware(-newStellwert);
		}
	}

	private final class Messglied
	implements Regelglied
	{
		@Override
		public double regle(double messwert)
		{
			if(messwert < untergrenze) {
				sg.addStellwert((untergrenze - messwert) / 2.0);
				// Eintrag in Datenbank
				return messwert + sg.getStellwert();
			}
			if(messwert > obergrenze) {
				sg.subStellwert((messwert - obergrenze) / 2.0);
				// Eintrag in Datenbank
				return messwert - sg.getStellwert();
			}
			return messwert;
		}
	}

	public static void main(String[] args) {
		final Regler r = new Regler(350.0, 0.04);
		Thread messung = new Thread("Messwerterfassung") {
			@Override
			public void run() {
				while(!isInterrupted()) {
					try {
						double messwert = getMesswertFromHardware();
						System.out.println("Messwert: " + r.regle(messwert));
						synchronized(this) {
							wait(1000);
						}
					} catch(InterruptedException e) {
						interrupt();
					}
					
				}
			}
		};
		messung.start();
	}
}

interface Regelglied
{
	double regle(double messwert);
}
```
Der 2. Thread wird im übrigen erst erforderlich, wenn die Hardware des Stellglieds für die Messpunktabstände zu träge korregiert. Das Messglied bekommt dann bereits vorkorregierte Messwerte, damit nicht ständig weiter (am Ende sogar in die falsche Richtung!) korregiert wird, während die Hardware immer noch dabei ist den vorherigen Wert einzustellen.


----------



## papapete (21. Mai 2012)

Vielen Dank erstmal für die Mühe. Werde das heute Abend mal einbauen und testen... aber wo baue ich die 3 sec Wartezeit ein?


----------



## Spacerat (21. Mai 2012)

In Zeile 78... in "wait(3000)" ändern.


----------



## papapete (21. Mai 2012)

Ok... verstehe ich soweit. Ist auf jeden Fall "eleganter" als mein Murks... aber ich bin ja noch am Lernen. 
Aber habe ich damit wirklich mein Grundproblem gelöst? Er regelt ja solange bis der Messwert im gewünschten Tolleranzbereich ist und macht dann garnix. Erst jetzt sollten die 3 sec abgewartet werden und falls der Messwert den Tolleranzbereich in dieser Zeit NICHT verlässt, soll der Messwert (und ein anderer) gespeichert werden.

Frage 2: In der Klasse Messglied steht //Eintrag in Datenbank... warum?

Vielleich nochmal was zur Erklärung der Gesamtaufgabe:

Ich möchte vorhandene Messpunkte (Druckaufbau,Volumenstrom) eines Gebläses nachfahren und überprüfen (Gebläseprüfstand).
Dazu wird in einer Kammer der Unterdruck gemessen. Am Zuluftkanal sitzt ein Schieber, der den Ansaugquerschnitt verändert und somit den Unterdruck "regelt". 
Ich muss also mittels Schieber einen Sollwert "anfahren" und diesen dann zusammen mit einem Volumestrom speichern. Danach hole ich mir den nächsten Wert... usw.

Da die Unterdrucksensoren schwanken, benötige ich eben diese Beruhigungszeit.


----------



## Spacerat (22. Mai 2012)

Das mit der Datenbank steht dort, weil du Werte speichern wolltest...

Das der Regler nach Erreichen des Sollwertes im Toleranzbereich gar nichts mehr tut, ist nicht ganz richtig. Er regelt nämlich solange er läuft jeden ausserhalb der Toleranz liegenden Wert aus, das macht er in den Abständen, die durch den Wert in Zeile 78 festgelegt wird.

Ok... ich denke, es wird Zeit für den 2. Thread. Hardware Luft ist unheimlich träge und ich glaub' jetzt versteh' ich auch die Problematik und vor allem den Grund, warum's "zappelt".
Der Regler sollte wenn es notwendig wird nur einmal zustellen, dann solange Messwerte lesen, bis sich diese nicht mehr bzw. geringfügig ändern, erst dann darf erneut zugestellt werden. Weil selbst wenn der Schieber adhoc bewegt werden kann, ändert sich dadurch ja nicht gleich der Unterdruck. Das kann unter Umständen auch länger als 3 Sekunden dauern. Willst du herausfinden, bei welcher Schieberposition welcher Unterdruck entsteht?


----------



## papapete (22. Mai 2012)

Die Werte will ich aber nicht nach jedem zustell-Vorgang speichern sondern erst wenn der Messwert eine Zeit lang nicht mehr aus dem Toleranzbereich herausspringt. (Eine zu große Schwankung könnte man hier über einen Mittelwert "abfangen")

Die Zeit in Zeile 78 dient doch nur zur Verzögerung zwischen den einzelne zustell-Vorgängen (Oder?!?). Damit könnte ich doch die Trägheit der Luft "regeln"?



> Willst du herausfinden, bei welcher Schieberposition welcher Unterdruck entsteht?



Nein die Schieberposition ist egal, er soll dur einen vorgegebenen Wert einregeln und dann den Unterdruck und von einem anderen Sensor den Volumenstrom speichern. Dann soll er den nächsten Wert anfahren usw.


----------



## Spacerat (25. Mai 2012)

Leider ist die Schieberposition alles andere als egal. Die Zustellwerte müssen nämlich zu den Druckdifferenzen passen, sonst wird's kompliziert. Du hast es nämlich mit einer Hardware zu tun, die extrem träge ist. Du kannst nämlich nur einmal zustellen, dann ändert sich erst der Druck. Die nächste Zustellung kannst du erst machen, wenn sich der Messwert innerhalb des Toleranzbereichs nicht mehr ändert. Das bedeutet, du muss schon wissen, um wieviel Einheiten du den Schieber bewegen musst, damit sich die benötigte Druckdifferenz einstellt. Das Verfahren ist aber ähnlich. Nur, dass du halt keine speziellen Druckwerte anfahren kannst, sondern dir prinzipiell zu jeder möglichen Schieberstellung erstmal die Druckwerte nebst Differenzen zu den benachbarten Stellungen in einer Tabelle speicherst. Wenn diese Werte erstmal eingemessen sind, sollte dieses

```
public final class Regler {
	private final Object syncObject = new Object();
	private final double abweichung;
	private double obergrenze, untergrenze;
	private final Stellglied sg;
	private final Messglied mg;

	private Regler(double abweichung) {
		this.abweichung = abweichung;
		sg = new Stellglied();
		mg = new Messglied();
	}

	/**
	 * Sollwert setzen und erneutes Setzen durch syncObject.wait()
	 * verhindern.
	 * @param sollwert
	 */
	public void setSollwert(double sollwert) {
		obergrenze = sollwert * (1.0 + abweichung);
		untergrenze = sollwert * (1.0 - abweichung);
		synchronized(mg) {
			mg.notify();
		}
		synchronized (syncObject) {
			try {
				syncObject.wait();
			} catch(InterruptedException e) {
				// ignore;
			}
		}
	}

	/**
	 * Unterdrucksensor auslesen und Wert zurückgeben.
	 * @return messwert
	 */
	private double getMesswertFromHardware() {
		// TODO Auto-generated method stub
		return 0;
	}

	/**
	 * Volumenstromsensor auslesen und Wert zurückgeben.
	 * @return messwert
	 */
	private double getVolumenstromFromHardware() {
		// TODO Auto-generated method stub
		return 0;
	}

	/**
	 * Schieberhardware einstellen. Negative Werte öffnen, positive
	 * schliessen. Die Zustellbereiche für die Druckdifferenzen
	 * müssen bereits eingemessen sein. Stellwert = x Zustelleinheiten.
	 * @param stellwert
	 */
	private void setHardwareStellwert(double stellwert)
	{
		// TODO Auto-generated method stub
		
	}

	/**
	 * gemessenen Werte speichern.
	 * @param unterdruck
	 * @param volumenstrom
	 */
	private void saveValues(double unterdruck, double volumenstrom) {
		// TODO Auto-generated method stub
		
	}

	private final class Stellglied extends Thread {
		private double stellwertLastUpper, stellwertLastLower, stellwert;
		private int counter;

		private Stellglied() {
			super("Stellglied");
			// es wurde noch nicht zugestellt, Schieber bewegt sich nicht
			double messwert = getMesswertFromHardware();
			stellwertLastUpper = messwert * (1 + abweichung);
			stellwertLastLower = messwert * (1 - abweichung);
			start();
		}

		public void addStellwert(double stellwert) {
			setHardwareStellwert(stellwert);
			this.stellwert += stellwert;
			stellwertLastUpper = this.stellwert * (1 + abweichung);
			stellwertLastUpper = this.stellwert * (1 - abweichung);
		}

		public void subStellwert(double stellwert) {
			setHardwareStellwert(-stellwert);
			this.stellwert -= stellwert;
			stellwertLastUpper = this.stellwert * (1 + abweichung);
			stellwertLastUpper = this.stellwert * (1 - abweichung);
		}

		@Override
		public void run() {
			while(!isInterrupted()) {
				try {
					synchronized (this) {
						wait();
					}
					counter = 0;
					do {
						double messwert = getMesswertFromHardware();
						if(messwert >= stellwertLastLower && messwert <= stellwertLastUpper) {
							counter++;
						}
						Thread.sleep(1000);
					} while(counter != 3);
					synchronized (mg) {
						mg.notify();
					}
				} catch(InterruptedException e) {
					interrupt();
				}
			}
		}
	}

	private final class Messglied extends Thread {
		private Messglied() {
			super("Messglied");
			start();
		}

		@Override
		public void run() {
			while (!isInterrupted()) {
				try {
					double unterdruck = getMesswertFromHardware();
					while(unterdruck < untergrenze && unterdruck > obergrenze) {
						if (unterdruck < untergrenze) {
							sg.addStellwert((untergrenze - unterdruck));
							synchronized (sg) {
								notify();
							}
							synchronized (this) {
								wait();
							}
						}
						if (unterdruck > obergrenze) {
							sg.subStellwert((unterdruck - obergrenze));
							synchronized (sg) {
								notify();
							}
							synchronized (this) {
								wait();
							}
						}
						unterdruck = getMesswertFromHardware();
					}
					double volumenstrom = getVolumenstromFromHardware();
					saveValues(unterdruck, volumenstrom);
					synchronized (syncObject) {
						syncObject.notify();
					}
				} catch (InterruptedException e) {
					interrupt();
				}
			}
		}
	}

	public static void main(String[] args) {
		Regler r = new Regler(0.04);
		// Punkte anfahren
		r.setSollwert(350.45);
		r.setSollwert(247.34);
		r.setSollwert(765.55);
		r.setSollwert(564.67);
		// ...
	}
}
```
dein Problem lösen. Dazu musst du bei den TODOs nur noch Code zum Übertragen der Werte von und zu der Hardware einfügen. 3 Sekunden Wartezeit ergeben sich aus 3 * 1000ms und zwar dann, wenn 3 mal hintereinander Werte im Toleranzbereich gemessen wurden.


----------



## papapete (25. Mai 2012)

Naja... leider wird's doch kompliziert. Ich habe nähmlich verschiedene Gebläse mit verschiedenen Werten. Somit lässt sich die Schieberposition keinem Unterdruckwert zuordnen, da er bei einem anderen Gebläse wieder anderst aussieht. Ich finde deinen ersten (einfacheren) Ansatz gar nicht so verkehrt.
Auch wenn sich der Unterdruck träge erst nach der Zustellung des Schiebers ändert, so bedeutet das doch nur, dass es zu einem Überschwingen kommt. Dann regelt der Schieber wieder runter. So sollte es sich dann auf den gewünschten Wert "einpendeln". 
Falls die "Schwinger" zu groß sind und das Einpendeln lange dauer oder gar nicht funktioniert (Oszillation um den Sollwert) kann mit der Zeit in Zeile 78 der Abstand bis zum nächsten Zustellen verlängert werden und so dem Unterdruck mehr Zeit gelassen werden sich "einzustellen". Ich denke das es funktionieren wird. Es soll nur noch mit rein, dass er - sobald er sich eingependelt hat - eine Zeit lang wartet bevor er den Wert speichert. Dies hatte ich ja mit einer For-Schleife gelöst und hatte das Problem, dass er die Schleife nicht unterbrochen hat wenn der Wert den Toleranzbereich verlassen hat, aber eine neue For-Schleife gestartet hat als der Wert wieder im Toleranzbereich war. Somit hatte ich mehrere Schleifen parallel laufen die mir die Tabelle wild füllten.


----------



## papapete (20. Jul 2012)

Hallo Leute... nochmal 

Durch EM und Urlaub bin ich erst vor kurzem dazu gekommen hier weiterzumachen. Habe die erste Lösungsversion versucht.

Erstmal Vielen Dank für die Hilfe... Ihr seid die besten.

Die Regelung an sich funktioniert wunderbar und ist viel eleganter als meine. Dies löst aber mein ursprüngliches Problem nicht.
Ich versuche hier nochmal zu erläutern s.Bild







Das Problem ist, dass das gemessene Signal überschwingt. Wenn ich einfach wie oben nur das überschreiten der Grenzen abfrage und dann den Wert speichere, dann kann es passieren, dass der Wert wieder "rausgeht" (Pos 2).
Deswegen möchte ich ein Zeitfenster einbauen das so aussehen soll: 

Pos1 wir erreicht --> 3sec laufen
nach z.B. 1sec Pos2 --> das Zählen der 3sec wird unterbrochen und die Regelung geht weiter
Pos3 --> 3sec laufen wieder
Pos4 --> das Zählen der 3sec wird unterbrochen und die Regelung geht weiter
Pos5 ---> 3sec laufen wieder
---> 3sec sind abgelaufen---> Wert speichern.

Dies hatte ich bisher mit einer for-Schleife innerhalb einerwhile-Schleife mit Steuervariable loop gelöst (s.o.) doch bei mir läuft es folgendermaßen ab:

Pos1 ---> loop=true, 3sec laufen
Pos2 ---> loop=false aber 3 sec laufen trotzdem weiter (iss ja auch klar, er befindet sich ja noch in der for-schleife)
Pos3 ---> loop=true, 3sec laufen nochmal (doppelt)
Pos4,5 das gleiche.

Je nachdem wann nun die Positionen jeweils erreicht werden ergibt das ein wildes Durcheinander an Zählschleifen.

Bitte helft mir weiter, ich bin am verzweifeln.

Danke schon mal im Voraus.


----------



## SlaterB (20. Jul 2012)

was ist denn konkret der aktuelle Code? ist '(s.o.)' eines der vorherigen Postings oder meinst du nur dein Bild?

ich habe aktuell wenig Überblick im Thread, hatte auch nur ganz zu Anfang gepostet, aber selbst an die kann ich mich gar nicht mehr richtig erinnern,
vorest ohne große Einarbeit (die du durch eine saubere aktuelle Übersicht hinsichtlich Code, und was immer noch weiter zu wissen ist außer deinem aktuellen Posting, erleichtern könntest) :

verwende nur eine Schleife, lasse diese in regelmäßigen sinnvollen Takt laufen, 
steuere durch Variablen die aktuelle Richtung, den aktuellen Wartestand, der erhöht oder auch zurückgesetzt werden kann usw.,
alles in einer Schleife mit ifs und ähnlichem

der Code von Spacerat zuletzt sieht danach aus, eine Schleife für alles wird natürlich etwas voll,
"wildes Durcheinander an Zählschleifen" ist es aber nicht


----------



## Spacerat (22. Jul 2012)

Also, wenn die Vorschrift ist, dass diese 5 Punkte eintreffen müssen, dann könnte man das in einer Switch-Anweisung abhandeln.

```
int pos = 0;
int count = 0;
long time = 20;
double mw0, mw1;
boolean ug = false;
do {
  mw0 = getMesswertFromHardware();
  switch(pos) {
  case 0:
  case 3:
  case 6:
    if(count++ >= 3) {
      pos++;
      // Drei Sekunden wurden ueberschritten
      // Wert speichern
    }
    if(mw0 >= untergrenze || mw0 <= obergrenze) {
      ug = mw1 < mw0; // feststellen ob Wert von oben oder unten einschwingt
      count = 0;
      pos++;
    }
    mw1 = mw0;
    break;
  case 1:
  case 4:
    time = 1000;
    if(ug) {
      // Messwert schwingt von unten ein
      if(mw0 >= obergrenze) {
        count = 0;
        pos++;
      }
    } else {
      // Messwert schwingt von oben ein
      if(mw0 <= untergrenze) {
        count = 0;
        pos++;
      }
    }
    break;
  case 2:
  case 5:
    if(ug) {
      // runterregeln
    } else {
      // raufregeln
    }
    pos++;
  }
  try {
    Thread.sleep(time);
  } catch(InterruptedException ie) {
    interrupt();
  }
} while(pos <= 6);
```
So, oder ähnlich sollte es gehen. Leider wird mir nicht Klar, warum diese Punkte unbedingt in diesen Zeitabständen angefahren werden müssen. Ein Regler für solche Zwecke überwacht die Hardware doch normalerweise ständig in gewissen Zeitabständen und wenn Werte über- bzw. unterschritten werden, wird halt proportioniert, integriert und/oder differenziert zugestellt.


----------



## papapete (26. Jul 2012)

Spacerat hat gesagt.:


> Leider wird mir nicht Klar, warum diese Punkte unbedingt in diesen Zeitabständen angefahren werden müssen. Ein Regler für solche Zwecke überwacht die Hardware doch normalerweise ständig in gewissen Zeitabständen und wenn Werte über- bzw. unterschritten werden, wird halt proportioniert, integriert und/oder differenziert zugestellt.



Ich möchte einen bestimmten Wert einregeln. Da dieser nie exakt "getroffen" wird gibt es die ober und untergrenze. Die Regelung an sich funktioniert ganz gut. D.h. der Messwert nähert sich langsam dem Sollwert und überschreitet irgendwann den grenzwert. Wenn ich jetzt einfach an dieser Stelle den Messwert speichern würde, könnte es passieren, dass der Wert die Obergrenze passiert hat und ich demnach einen falschen Wert gespeichert habe. Aus diesem Grund möchte ich erst speichern, nachdem eine gewisse "Beruhigungszeit" abgelaufen ist und der Wert sich immernoch innerhalb der Grenzen befindet.
Dies hatte ich wie gesagt mit einer for Schleife erledigt. Das Signal (Messwert) ist aber so "unruhig", dass beim Annähern und Überschreiten der Grenzen eine Art "prellen" (Wie bei einem Taster) entsteht und die For-Schleife dadurch mehrmals aufgerufen wird.


----------



## Spacerat (26. Jul 2012)

Dazu ist der Ansatz aber doch relativ falsch. Ein Regler regelt ständig zwischen Ober- und Untergrenze nach, weil das Medium nun mal ebenso dynamisch wie träge ist. Messwerte können sich also nur in einem Bereich bewegen, denn strömende Luft beruhigt sich nun mal nicht. Kurz, der Messwert nach den angefahrenen 6 Punkten sagt gar nichts aus. Während der Regelung kann man diese Werte aber integrieren, so dass man einen Durchschnittswert erhält, den man dann auch speichern kann.


----------



## papapete (26. Jul 2012)

Ich will die Punkte ja nicht anfahren. Die Regelung funktioniert wie in deinem (ersten) Vorschlag... sogar sehr gut. 
Mit dem Bild wollte ich nur verdeutlichen wie der Wert eben überschwingt und an den Punkten die Grenzen "passiert".
Da aber in der Regelung genau das überwacht wird (Wenn Grenze passiert, dann speichern) habe ich keine Beruhigungszeit und könnte einen falschen Wert speichern.


----------



## Spacerat (26. Jul 2012)

Dann würd' ich sagen, lass den Regler seine Arbeit tun, also die Regelstrecke dauerhaft überwachen. Jeder Messwert erfordert eine Zustellung und wird obendrein zu einem Durchschnittswert integriert. Ändert sich der Durchschnittswert in gewissen kleineren Grenzen (evtl. 1% oder weniger) nicht mehr, meldet der Regler 'beruhigt'. Dann Wert ablesen und speichern. Mal schauen, ob ich da was hinbekomme.


----------



## papapete (27. Jul 2012)

Jaaaa...! Genau sowas brauche ich.
Wie gesagt, habe ich diese Beruhigungszeit in eine For-Schleife gepackt, was aber nicht funktioniert hat.
Ich bin echt am Verzweifeln.
VIELEN VIELEN DANK FÜR DEINE HILFE!!!

Sobald das Ganze funktioniert, werde ich den kompletten code hier posten für Andere die evtl ähnliche Probleme haben.


----------



## papapete (9. Aug 2012)

*PUSH*

... wollt mal fragen ob du schon eine Idee hast...


----------



## Spacerat (10. Aug 2012)

Oh... nee, nicht wirklich. 
Ich such' grad' bei 'nem eigenen Problem nach einer und hab's deswegen aus den Augen verloren. Ich kümmere mich drum, sobald ich kann.
[EDIT]Ausserdem schien das Thema ja erledigt.[/EDIT]


----------



## Mujahiddin (10. Aug 2012)

@TomateSalat:

```
boolean run=true;
for(int i=0;i<abc.length && run;i++) {
    for(int j=0;j<abc.length && run;j++) {
        System.out.println(abc[j]);
        run=false;
    }
}
System.out.println("Ende");
```

Wie willst du denn sowas mit deiner Variante darstellen?:

```
String[] abc={"a","b","c"};

System.out.println("Entering loop");
outer: for(String a:abc) {
    for(String b:abc) {
        System.out.println(a);
        break outer;
    }
    System.out.println("Inner loop done"); /* << soll bei "break outer;" NICHT geprinted werden */
}
System.out.println("Ende");
```

Wohl so?:

```
boolean run=true;
System.out.println("Entering loop");
for(int i=0;i<abc.length && run;i++) {
    for(int j=0;j<abc.length && run;j++) {
        System.out.println(abc[j]);
        run=false;
    }
    if(!run) break;
    System.out.println("Inner loop done!");
}
System.out.println("Ende");
```
Das sieht für mich ziemlich umständlich und unschön aus.
Die Argumentation "labels kennt nicht jeder" finde ich auch ziemlich weit hergeholt. Es gibt für alles ein erstes Mal!
Soll nicht heißen, dass ich nicht lieber labels umgehe, aber manchmal sind sie wirklich unabdingbar und oft vereinfachen sie Sachen.


----------



## Tomate_Salat (10. Aug 2012)

Mujahiddin hat gesagt.:


> Wie willst du denn sowas mit deiner Variante darstellen?:


Labels sind nicht unabdingbar. Ich musste diese noch nie verwenden. Selbst in der Zeit, als ich diese noch nicht kannte, hatte ich sie nicht vermisst. In diesem Fall würde ich wohl einfach zu einer Methode greifen.



Tomate_Salat hat gesagt.:


> ... oder lager es gleich in Methoden aus.


----------



## Spacerat (10. Aug 2012)

@Mujahiddin: Man sollte niemals auch nur annähernd in Erwägung ziehen, Labels zu verwenden, das kann man in Batch-Dateien machen. In OOP's aber zerstören sie das komplette Gefüge. Darüber hinaus sind sie ohnehin nur rückwärts verwendbar (es können nur Labels angesprungen werden, die in Zeilen vor dem Sprung definiert wurden). Zuletzt sei noch gesagt (das musste ich mir auch erst anlesen...), dass Labels zwar *vor* einem Anweisungsblock stehen, der Ablauf jedoch genau hinter diesem Block fortgesetzt wird, wenn der Label angesprungen wird. So gesehen sorgen Labels stets für unvorherzusehende Dinge und es gibt bessere Methoden, z.B. mehr Methoden (also Codeauslagerung in solche).


----------



## papapete (26. Aug 2012)

Hallo nochmal... Bist mit deinem Projekt weitergekommen?
Kannst mir evtl. ein Stichwort geben wie Du das lösen würdest?
Kann dann mal selber probieren ob ich das hinbekomme.


----------



## Spacerat (26. Aug 2012)

Also ganz banal würde ich den Regler statt mit nur einem Wert schon mal mit zweien initialisieren, dazu muss der Konstruktor in [c]Regler(double outer, double inner)[/c] geändert werden. Aus dem zusätzlichen Wert konstuiert man sich dann zu den beiden äusseren Begrenzungen (roter Bereich) noch zwei innere dazu (grüner Bereich). Der Regler muss im roten Bereich ständig Werte zustellen und die Tendenz zwischen den Messpunkten differenzieren, daraus sollte sich ein immer kleiner werdender Zustellwert ergeben und die Messwerte irgendwann im grünen Bereich landen. Einmal im grünen Bereich, stellt der Regler nur noch zu, wenn ein Messwert wieder im roten Bereich auftaucht. 3 Messwerte hintereinander im grünen Bereich ergeben dann die Meldung "beruhigt", ein Messwert im roten Bereich hebt diese Meldung wieder auf. Dazu muss die Regelstrecke wie gehabt dauerhaft überwacht werden, das bedeutet, dass der Thread niemals beendet werden darf.


----------



## papapete (29. Aug 2012)

Ok... sowas ähnliches versuchte ich ja zu realisieren, aber wie meinst Du das mit den "3 Messwerte hintereinander im grünen Bereich"? Das geht doch wieder nur über eine for-schleife oder? Dann habe ich wieder das gleiche Problem, dass die schleife durchlaufen wird (3mal) ob der wert nun den grünen Bereich verlässt oder nicht.


----------



## Spacerat (29. Aug 2012)

Eine Endlosschleife, wenn man so will. Diese läuft im Thread Stellglied und fragt statt der äusseren Grenzen, die inneren ab und zählt den counter entsprechend. Der Thread des Messglieds legt sich aber im Gegensatz zu vorher nicht schlafen, sondern überwacht die Hardware dauerhaft, ob die Messwerte den inneren Bereich wieder verlassen. Bin mir kaum sicher, ob das so geht... aber wenn ja, dann herzlichen Glückwunsch.

```
public final class Regler {
	private final double outer, inner;
	private double ot, ob, it, ib;
	private final Stellglied sg;
	private final Messglied mg;

	private Regler(double outer, double inner) {
		this.outer = outer;
		this.inner = inner;
		sg = new Stellglied();
		mg = new Messglied();
	}

	/**
	 * Sollwert setzen und erneutes Setzen durch syncObject.wait()
	 * verhindern.
	 * @param sollwert
	 */
	public void setSollwert(double sollwert) {
		ot = sollwert * (1.0 + outer);
		ob = sollwert * (1.0 - outer);
		it = sollwert * (1.0 + inner);
		ib = sollwert * (1.0 - inner);
	}

	public void waitCalm() {
		synchronized(this) {
			try {
				wait();
			} catch(InterruptedException e) {
				// ignore
			}
		}
	}

	/**
	 * Unterdrucksensor auslesen und Wert zurückgeben.
	 * @return messwert
	 */
	private double getMesswertFromHardware() {
		// TODO Auto-generated method stub
		return 0;
	}

	/**
	 * Volumenstromsensor auslesen und Wert zurückgeben.
	 * @return messwert
	 */
	private double getVolumenstromFromHardware() {
		// TODO Auto-generated method stub
		return 0;
	}

	/**
	 * Schieberhardware einstellen. Negative Werte öffnen, positive
	 * schliessen. Die Zustellbereiche für die Druckdifferenzen
	 * müssen bereits eingemessen sein.
	 * @param stellwert
	 */
	private void setHardwareStellwert(double stellwert)
	{
		// TODO Auto-generated method stub
		
	}

	/**
	 * gemessenen Werte speichern.
	 * @param unterdruck
	 * @param volumenstrom
	 */
	private void saveValues(double unterdruck, double volumenstrom) {
		// TODO Auto-generated method stub
		
	}

	private final class Stellglied extends Thread {
		private double itLast, ibLast, stellwert;
		private int counter;

		private Stellglied() {
			super("Stellglied");
			// es wurde noch nicht zugestellt, Schieber bewegt sich nicht
			double messwert = getMesswertFromHardware();
			itLast = messwert * (1.0 + inner);
			ibLast = messwert * (1.0 - inner);
			start();
		}

		public void addStellwert(double stellwert) {
			setHardwareStellwert(stellwert);
			this.stellwert += stellwert;
			itLast = this.stellwert * (1.0 + inner);
			ibLast = this.stellwert * (1.0 - inner);
		}

		public void subStellwert(double stellwert) {
			setHardwareStellwert(-stellwert);
			this.stellwert -= stellwert;
			itLast = this.stellwert * (1.0 + inner);
			ibLast = this.stellwert * (1.0 - inner);
		}

		@Override
		public void run() {
			while(!isInterrupted()) {
				try {
					synchronized (this) {
						wait();
					}
					counter = 0;
					do {
						double messwert = getMesswertFromHardware();
						if(messwert >= ibLast && messwert <= itLast) {
							counter++;
						}
						Thread.sleep(1000);
					} while(counter != 3);
					mg.notifyCalm();
				} catch(InterruptedException e) {
					interrupt();
				}
			}
		}
	}

	private final class Messglied extends Thread {
		private double pressure;

		private Messglied() {
			super("Messglied");
			start();
		}

		private void notifyCalm() {
			synchronized (Regler.this) {
				Regler.this.notify();
			}
			saveValues(pressure, getVolumenstromFromHardware());
		}

		@Override
		public void run() {
			while (!isInterrupted()) {
				try {
					pressure = getMesswertFromHardware();
					while(pressure < ob && pressure > ot) {
						if (pressure < ob && pressure > ib) {
							sg.addStellwert((ob - pressure));
						} else if (pressure > ot && pressure < it) {
							sg.subStellwert((pressure - ot));
						}
						if(pressure < ib && pressure > it) {
							if (pressure < ib) {
								sg.addStellwert((ib - pressure));
								synchronized (sg) {
									notify();
								}
								synchronized (this) {
									wait();
								}
							}
							if (pressure > it) {
								sg.subStellwert((pressure - it));
								synchronized (sg) {
									notify();
								}
								synchronized (this) {
									wait();
								}
							}
						}
						pressure = getMesswertFromHardware();
						Thread.sleep(100);
					}
				} catch (InterruptedException e) {
					interrupt();
				}
			}
		}
	}

	public static void main(String[] args) {
		Regler r = new Regler(0.04, 0.001);
		// Punkte anfahren
		r.setSollwert(350.45);
		r.waitCalm();
		r.setSollwert(247.34);
		r.waitCalm();
		r.setSollwert(765.55);
		r.waitCalm();
		r.setSollwert(564.67);
		// ...
	}
}
```


----------



## papapete (15. Okt 2012)

Hi... Sorry dass ich wieder störe und mich erst so spät wieder melde. War in einem anderen Projekt gebunden.
Habe Deinen Vorschlag eingebaut und an mein Prog angepasst. Die Regelung scheint soweit zu laufen Aber... Das Prog bleibt an dieser Stelle im wait() hängen:


```
@Override
        public void run() {
            while(!isInterrupted()) {
                try {
                    synchronized (this) {
                        wait(); [COLOR="Red"]<---HIER[/COLOR]
                    }
                    counter = 0;
                    do {
                        double messwert = getMesswertFromHardware();
                        if(messwert >= ibLast && messwert <= itLast) {
                            counter++;
                        }
                        Thread.sleep(1000);
                    } while(counter != 3);
                    mg.notifyCalm();
                } catch(InterruptedException e) {
                    interrupt();
                }
            }
        }
```

D.h. an dieser Stelle wird der Thread nicht wie gewünscht "geweckt":


```
@Override
        public void run() {
            while (!isInterrupted()) {
                try {
                    pressure = getMesswertFromHardware();
                    DruckField.setText(String.valueOf(pressure));
                    while(pressure > ob || pressure < ot) {
                        if (pressure < ob ) {
                            sg.addStellwert((ob - pressure));
                        } else if (pressure > ot) {
                            sg.subStellwert((pressure - ot));
                        }
                        if (pressure > ob && pressure < ib) {
                            sg.addStellwert((pressure - ob));
                        } else if (pressure < ot && pressure > it) {
                            sg.subStellwert((ot - pressure));
                        }
                        if(pressure > ib && pressure < it) {
                            if (pressure > ib) {
                                sg.addStellwert((pressure - ib));
                                synchronized (sg) {
                                    notify();                            <---HIER
                                }
                                synchronized (this) {
                                    wait();
                                }
                            }
                            if (pressure < it) {
                                sg.subStellwert((it - pressure));
                                synchronized (sg) {
                                    notify();                 <---UND HIER
                                }
                                synchronized (this) {
                                    wait();
                                }
                            }
                        }
                        pressure = getMesswertFromHardware();
                        DruckField.setText(String.valueOf(pressure));
                        Thread.sleep(100);
                    }
                } catch (InterruptedException e) {
                    interrupt();
                }
            }
        }
```

Ich bekommt im Thread Messglied dann ein "illegalmonitorstateexception"

Danke für die Geduld und Mühe mit mir


----------



## Spacerat (15. Okt 2012)

Auf Anhieb, würde ich auf Flüchtigkeit meinerseits tippen, dass hätte in beiden Fällen evtl.

```
sg.notify();
```
heissen müssen.
Ansonsten: Wie genau sieht die Exception denn aus also der Stacktrace?


----------



## papapete (15. Okt 2012)

jop... funktioniert und läuft weiter... bis zum nächsten Stillstand 
Kannst Du bitte noch folgende Passage überprüfen?

Hier itLast und ibLast = messwert+- gesetzt... dann aber auf stellwert+-


```
private Stellglied() {
            super("Stellglied");
            // es wurde noch nicht zugestellt, Schieber bewegt sich nicht
            double messwert = getMesswertFromHardware();
            itLast = messwert * (1.0 + inner);
            ibLast = messwert * (1.0 - inner);
            start();
        }
 
        public void addStellwert(double stellwert) {
            statMeld=""+stellwert;
            meldArea.setText(statMeld);
        	setHardwareStellwert(stellwert);
            this.stellwert += stellwert;
            itLast = this.stellwert * (1.0 + inner);
            ibLast = this.stellwert * (1.0 - inner);
        }
 
        public void subStellwert(double stellwert) {
            statMeld=""+stellwert;
            meldArea.setText(statMeld);
            setHardwareStellwert(-stellwert);
            this.stellwert -= stellwert;
            itLast = this.stellwert * (1.0 + inner);
            ibLast = this.stellwert * (1.0 - inner);
        }
```

Je näher der Messwert sich dem Sollwert ja annähert, wird der Stellwert kleiner... somit wird hier:


```
public void run() {
            while(!isInterrupted()) {
                try {
                    synchronized (this) {
                        wait();
                    }
                    counter = 0;
                    do {
                        double messwert = getMesswertFromHardware();
                        if(messwert >= ibLast && messwert <= itLast) {
                            counter++;
                        }
                        Thread.sleep(1000);
                    } while(counter != 3);
                    mg.notifyCalm();
                } catch(InterruptedException e) {
                    interrupt();
                }
            }
        }
```

...diese if-Bedingung ja nie erfüllt ode sehe ich das falsch???


----------



## Spacerat (15. Okt 2012)

Das sollte so seine Richtigkeit haben, in beiden Fällen wird ein aktueller Messwert von der Hardware geholt.
Im ersten Fall ist das der initiale Wert für das Stellglied, damit der Regler nicht unaufgefordert und unkontrolliert anfängt zu regeln. Man könnte da eigentlich x beliebige als initiale Werte nehmen, nur gerade bei Druck (insbesondere hydrostatischem), wäre ich in jeder Hinsicht damit vorsichtig.
Im zweiten Fall wird der Wert des Stellgliedes verändert und es beginnt ein Zustellzyklus, bei welchem sich der Messwert in Richtung ib->it ändern sollte.
BTW.: dieses "statMeld" kommt nicht von mir. Erkennt man daran, dass beim Stellwert Abziehen anscheinend das Vorzeichen vergessen wurde.  Will sagen: An die beiden Zustellmethoden werden (bzw. ist's von mir so gedacht) nur positive Werte übergeben.


----------



## papapete (16. Okt 2012)

Ahh... verstehe jetzt warum Du den Sollwert so angefahren hast... Der Druck den ich messe ist kein hydrostatischer... also kein Absolutwert. Ich messe die Druckdifferenz als Unterdruck. Somit steigt mein Unterdruck wenn die Klappe schließt. Habe es jetzt aber umgebaut und es funktioniert soweit, dass es jetzt die Tabelle sauber füllt. VIELEN VIELEN DANK erstmal dafür.

Da ich aber den Regler von wo anders aufrufe, bleibt er entweder hängen oder startet die Threads mehrmals.


```
public void StartMessung(){
	Regler r = new Regler(0.04, 0.01);
	while (zeile <DatenTableModel.getRowCount()-2){
		zuMessenderWert= Double.parseDouble(DatenTableModel.getValueAt(zeile, 0).toString());
		statMeld="Messe folgenden Messpunkt: " + zuMessenderWert;
		meldArea.setText(statMeld);	
		r.setSollwert(zuMessenderWert);
                r.waitCalm();
		
	}
	
        meldArea.setText("Messung beendet");
		
}


public final class Regler {
    private final double outer, inner;
    private double ot, ob, it, ib;
    private final Stellglied sg;
    private final Messglied mg;
 
    private Regler(double outer, double inner) {
        this.outer = outer;
        this.inner = inner;
        sg = new Stellglied();
        mg = new Messglied();
    }
 
    /**
     * Sollwert setzen und erneutes Setzen durch syncObject.wait()
     * verhindern.
     * @param sollwert
     */
    public void setSollwert(double sollwert) {
        ot = sollwert * (1.0 + outer);
        ob = sollwert * (1.0 - outer);
        it = sollwert * (1.0 + inner);
        ib = sollwert * (1.0 - inner);
    }
 
    public void waitCalm() {
        synchronized(this) {
            try {
                wait();
            } catch(InterruptedException e) {
                // ignore
            }
        }
    }
 
    /**
     * Unterdrucksensor auslesen und Wert zurückgeben.
     * @return messwert
     */
    private double getMesswertFromHardware() {
    	double messwert;
    	messwert=jv.ReadAnalogChannel(2)*10000/255;
        return messwert;
    }
 
    /**
     * Volumenstromsensor auslesen und Wert zurückgeben.
     * @return messwert
     */
    private double getVolumenstromFromHardware() {
        // TODO Auto-generated method stub
    	double messwert;
    	messwert=jv.ReadAnalogChannel(1)*800/255;
        return messwert;
    }
 
    /**
     * Schieberhardware einstellen. Negative Werte öffnen, positive
     * schliessen. Die Zustellbereiche für die Druckdifferenzen
     * müssen bereits eingemessen sein.
     * @param stellwert
     */
    private void setHardwareStellwert(double stellwert)
    {
    	
        // TODO Auto-generated method stub
        if (stellwert<0) {
        	schieberPos=schieberPos-10;
			jv.OutputAnalogChannel(1, schieberPos);
			SchieberProg.setValue((int)Math.round(schieberPos/255));
		} else {
			schieberPos=schieberPos+10;
			jv.OutputAnalogChannel(1, schieberPos);
			SchieberProg.setValue((int)Math.round(schieberPos/255));

		}
    }
 
    /**
     * gemessenen Werte speichern.
     * @param unterdruck
     * @param volumenstrom
     */
    private void saveValues(double unterdruck, double volumenstrom) {
    	DatenTableModel.setValueAt(unterdruck, zeile, 2);
    	DatenTableModel.setValueAt(volumenstrom, zeile, 3);
    	yData[zeile]= (int)unterdruck;
    	xData[zeile]=(int)volumenstrom;
    	zeile++;
        f.repaint();
        //StartMessung(); Wenn ich das aufrufe --> mehrere Threads
        
    }
 
    private final class Stellglied extends Thread {
        private double itLast, ibLast, stellwert;
        private int counter;
 
        private Stellglied() {
            super("Stellglied");
            // es wurde noch nicht zugestellt, Schieber bewegt sich nicht
            double messwert = getMesswertFromHardware();
            itLast = messwert * (1.0 + inner);
            ibLast = messwert * (1.0 - inner);
            start();
        }
 
        public void addStellwert(double stellwert, double ob, double ot) {
            statMeld=""+stellwert;
            meldArea.setText(statMeld);
        	setHardwareStellwert(stellwert);
            this.stellwert += stellwert;
            itLast = (ob + ot)/2* (1.0 + inner);
            ibLast = (ob + ot)/2 * (1.0 - inner);
        }
 
        public void subStellwert(double stellwert, double ob, double ot) {
            statMeld=""+stellwert;
            meldArea.setText(statMeld);
            setHardwareStellwert(-stellwert);
            this.stellwert -= stellwert;
            itLast = (ob + ot)/2 * (1.0 + inner);
            ibLast = (ob + ot)/2 * (1.0 - inner);
        }
 
        @Override
        public void run() {
            while(!isInterrupted()) {
                try {
                    synchronized (this) {
                        wait();
                    }
                    counter = 0;
                    do {
                        double messwert = getMesswertFromHardware();
                        if(messwert >= ibLast && messwert <= itLast) {
                            counter++;
                        }
                        Thread.sleep(1000);
                    } while(counter != 3);
                    mg.notifyCalm();
                } catch(InterruptedException e) {
                    interrupt();
                }
            }
        }
    }
 
    private final class Messglied extends Thread {
        private double pressure;
 
        private Messglied() {
            super("Messglied");
            start();
        }
 
        private void notifyCalm() {
            synchronized (Regler.this) {
                Regler.this.notify();
            }
            saveValues(pressure, getVolumenstromFromHardware());
        }
 
        @Override
        public void run() {
            while (!isInterrupted()) {
                try {
                    pressure = getMesswertFromHardware();
                    DruckField.setText(String.valueOf(pressure));
                    while(pressure > ob || pressure < ot) {
                        if (pressure < ob ) {
                            sg.addStellwert((ob - pressure), ot, ob);
                        } else if (pressure > ot) {
                            sg.subStellwert((pressure - ot), ot, ob);
                        }
                        if (pressure > ob && pressure < ib) {
                            sg.addStellwert((pressure - ob), ot, ob);
                        } else if (pressure < ot && pressure > it) {
                            sg.subStellwert((ot - pressure), ot, ob);
                        }
                        if(pressure > ib && pressure < it) {
                            if (pressure > ib) {
                                sg.addStellwert((pressure - ib), ot, ob);
                                synchronized (sg) {
                                    sg.notify();
                                }
                                synchronized (this) {
                                    wait();
                                }
                            }
                            if (pressure < it) {
                                sg.subStellwert((it - pressure), ot, ob);
                                synchronized (sg) {
                                    sg.notify();
                                }
                                synchronized (this) {
                                    wait();
                                }
                            }
                        }
                        pressure = getMesswertFromHardware();
                        DruckField.setText(String.valueOf(pressure));
                        Thread.sleep(100);
                    }
                } catch (InterruptedException e) {
                    interrupt();
                }
            }
        }
    }
}
}
```

Das mit den mehreren Threads ist zwar nicht schlimm und funktioniert trotzdem ist aber denke ich nicht "im Sinne des Erfinders"  Ich kenn mich halt nicht so gut mit Threads/notify etc aus und weiss nicht wo ich ansetzen soll.


----------



## Spacerat (16. Okt 2012)

Wie oft rufst du denn "StartMessung" auf? Evtl. ist es nicht sinnvoll, wenn innerhalb dieser Methode ständig ein neuer Regler instanziert wird. Sicher gehört diese Methode zu einer Klasse. In dieser Klasse könnte man einmalig einen statischen Regler instanzieren, auf den dann von allen Aufrufen zugergriffen wird, so wie das z.B. "java.lang.Math" mit Random macht.


----------



## papapete (16. Okt 2012)

Also... so wie ich Deinen Code verstehe soll ja dass Messglied solange messen bis es "passt" und dann per notify das Stellglied wecken. Dieses überprüft dann ob der Wert 3s innerhalb der Grenzen bleibt, schreibt die Daten in die Tabelle und weckt per notify wieder das Messglied für den nächsten Wert.
Wenn ich nun wie im Code oben StartMessung nicht wieder aufrufe, dann bleiben die Threads mg und sg im wait() hängen !?!
Wenn ich aber StartMessung nach jedem erfolgreich gemessenen Wert wieder aufrufe (an der auskommentierten Stelle) dann Starten die Threads bei jedem neuen Sollwert neu und somit doppelt... dreifach... etc. Zudem habe ich das Problem, dass die Threads nach Ende der Messung weiterlaufen.


----------



## Spacerat (16. Okt 2012)

Okay, dann eben anders:

```
class ClassWithStartMessung {
  private final Regler r = new Regler(0.04, 0.01);

  public void startMessung() {
    while (zeile <DatenTableModel.getRowCount()-2){
      zuMessenderWert= Double.parseDouble(DatenTableModel.getValueAt(zeile, 0).toString());
      statMeld="Messe folgenden Messpunkt: " + zuMessenderWert;
      meldArea.setText(statMeld); 
      r.setSollwert(zuMessenderWert);
      r.waitCalm();
    }
    meldArea.setText("Messung beendet");
  }
}
```
ClassWithStartMessung sollte nun nur einmal pro Regelstrecke instanziert werden (dadurch wird auch nur ein Regler instanziert). Die Methode "startMessung()" kann danach beliebig oft aufgerufen werden.


----------



## papapete (16. Okt 2012)

Also entweder ist es zu spät oder ich hatte 2 bier zu viel  scheint nicht zu fukntoinienren ;-D
Werd mich Morgen nochmal melden... Gutn8


----------



## Spacerat (16. Okt 2012)

:lol: Ich hab' ja auch die Parameter des Reglers vergessen.


----------

