Verschachtelte Schleife vorzeitig abbrechen.

papapete

Mitglied
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.

Java:
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
 
S

SlaterB

Gast
> 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

Mitglied
;) 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.
 
S

SlaterB

Gast
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

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

Java:
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.
 
S

Spacerat

Gast
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.
 
Zuletzt bearbeitet von einem Moderator:
T

Tomate_Salat

Gast
Die Schleife wird bei Ihm allerdings erneut durchlaufen.
Nein (dachte ich aber auch im ersten Moment [was gegen das Konstrukt spricht]):
Java:
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:
Code:
a
Ende

Aber dennoch. Ich würde soetwas verwenden:
Java:
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

Top Contributor
Bevor man über Sinn und Unsinn streitet, sollte man schon wissen, wie es funktioniert :p

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

Aber Labels können auch sehr nützlich sein:
Java:
http: //dgronau.wordpress.com
...anderer Code...
 

papapete

Mitglied
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:

Java:
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;
		}
}

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



Java:
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.


Java:
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.

Java:
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.

Java:
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ß
 
S

Spacerat

Gast
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

Mitglied
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?
 
S

Spacerat

Gast
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]
 
Zuletzt bearbeitet von einem Moderator:
S

Spacerat

Gast
So, ich habe die Ein-Threadversion mal zusammengefrickelt.
Java:
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

Mitglied
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.
 
S

Spacerat

Gast
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

Mitglied
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.
 
S

Spacerat

Gast
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
Java:
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.
 
Zuletzt bearbeitet von einem Moderator:

papapete

Mitglied
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

Mitglied
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

signal.png


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.
 
S

SlaterB

Gast
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
 
S

Spacerat

Gast
Also, wenn die Vorschrift ist, dass diese 5 Punkte eintreffen müssen, dann könnte man das in einer Switch-Anweisung abhandeln.
Java:
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.
 
Zuletzt bearbeitet von einem Moderator:

papapete

Mitglied
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.
 
S

Spacerat

Gast
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

Mitglied
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.
 
S

Spacerat

Gast
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

Mitglied
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.
 
S

Spacerat

Gast
Oh... nee, nicht wirklich. :oops:
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]
 
Zuletzt bearbeitet von einem Moderator:

Mujahiddin

Top Contributor
@TomateSalat:
Java:
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?:
Java:
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?:
Java:
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.
 
S

Spacerat

Gast
@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

Mitglied
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.
 
S

Spacerat

Gast
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.
 

Anhänge

  • regelverlauf.png
    regelverlauf.png
    10,4 KB · Aufrufe: 26

papapete

Mitglied
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.
 
S

Spacerat

Gast
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.
Java:
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

Mitglied
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:

Java:
        @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":

Java:
        @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 ;)
 
S

Spacerat

Gast
Auf Anhieb, würde ich auf Flüchtigkeit meinerseits tippen, dass hätte in beiden Fällen evtl.
Java:
sg.notify();
heissen müssen.
Ansonsten: Wie genau sieht die Exception denn aus also der Stacktrace?
 

papapete

Mitglied
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+-

Java:
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:

Java:
        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???
 
S

Spacerat

Gast
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.
 
Zuletzt bearbeitet von einem Moderator:

papapete

Mitglied
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.

Java:
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.
 
S

Spacerat

Gast
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

Mitglied
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.
 
S

Spacerat

Gast
Okay, dann eben anders:
Java:
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.
 
Zuletzt bearbeitet von einem Moderator:
Ähnliche Java Themen
  Titel Forum Antworten Datum
S Verschachtelte for-Schleife Java Basics - Anfänger-Themen 2
laxla123 Verschachtelte If-Else Schleife Java Basics - Anfänger-Themen 21
S Verschachtelte Schleife Java Basics - Anfänger-Themen 3
Y Verschachtelte For-Schleife Java Basics - Anfänger-Themen 5
S verschachtelte for-Schleife Java Basics - Anfänger-Themen 6
J verschachtelte Schleife Java Basics - Anfänger-Themen 10
S verschachtelte for Schleife und Ergebniss. Java Basics - Anfänger-Themen 3
C Verschachtelte For-Schleife Java Basics - Anfänger-Themen 6
J Verschachtelte for schleife mit dynamischer Anzahl an Schleifen Java Basics - Anfänger-Themen 10
J Verschachtelte for-Schleife mit Löschen von Iterationen. Wie über Iterator abbilden? Java Basics - Anfänger-Themen 6
W verschachtelte while schleife Java Basics - Anfänger-Themen 8
W verschachtelte For-Schleife - continue Java Basics - Anfänger-Themen 8
R Verschachtelte Schleife? Java Basics - Anfänger-Themen 6
W Verschachtelte If-else --> finde meinen Fehler nicht Java Basics - Anfänger-Themen 30
Düsseldorf2002 Datentypen Verschachtelte LinkedList Java Basics - Anfänger-Themen 5
J Verschachtelte Methoden Java Basics - Anfänger-Themen 9
P Verschachtelte Hashmap Java Basics - Anfänger-Themen 6
P Verschachtelte Array Liste Java Basics - Anfänger-Themen 2
B Verschachtelte For Schleifen Java Basics - Anfänger-Themen 8
W Verschachtelte Objekte wieder auspacken Java Basics - Anfänger-Themen 3
F Methoden Verschachtelte if else Methode Java Basics - Anfänger-Themen 10
Z Verschachtelte If-Bedingung Java Basics - Anfänger-Themen 6
D verschachtelte Schleifen Java Basics - Anfänger-Themen 6
M Verschachtelte Forschleifen Java Basics - Anfänger-Themen 2
F Klassen Zugriff auf verschachtelte Objekte Java Basics - Anfänger-Themen 11
J static verschachtelte Klassen und innere Klassen Java Basics - Anfänger-Themen 1
TheMenox Verschachtelte If Bedingung Java Basics - Anfänger-Themen 4
R Verschachtelte Arraylist und deren Größe auslesen Java Basics - Anfänger-Themen 7
C Verschachtelte Map auslesen Java Basics - Anfänger-Themen 4
H Best Practice Wie mit break verschachtelte Schleifen komplett verlassen? Java Basics - Anfänger-Themen 2
F Verschachtelte Schleifen Java Basics - Anfänger-Themen 4
J Hilfe verschachtelte Schleifen Java Basics - Anfänger-Themen 5
F Erste Schritte Switch case vs. Verschachtelte If Anweisung Java Basics - Anfänger-Themen 11
G Collections verschachtelte ArrayList abfüllen Java Basics - Anfänger-Themen 5
X verschachtelte suche Java Basics - Anfänger-Themen 8
S Verschachtelte Exceptions - Übersicht verbessern Java Basics - Anfänger-Themen 2
D Verschachtelte Objekterzeugung Java Basics - Anfänger-Themen 6
X Verschachtelte Annotationen Java Basics - Anfänger-Themen 9
J verschachtelte for-schleifen Java Basics - Anfänger-Themen 2
S Verschachtelte Klassen Java Basics - Anfänger-Themen 12
D Verschachtelte IF-Anweisung Java Basics - Anfänger-Themen 10
C Verschachtelte for-schleifen Java Basics - Anfänger-Themen 10
C Verschachtelte For-Schleifen Java Basics - Anfänger-Themen 5
3 Verschachtelte Zuweisung Java Basics - Anfänger-Themen 4
M Tief verschachtelte Packages Java Basics - Anfänger-Themen 7
T add-Methode für verschachtelte ArrayLists Java Basics - Anfänger-Themen 10
E Verschachtelte If-Anweisungen - "else without if" Java Basics - Anfänger-Themen 4
T Datentypen Verschachtelte Map durchlaufen Java Basics - Anfänger-Themen 4
P Verschachtelte For-Schleifen Java Basics - Anfänger-Themen 4
F Verschachtelte Arrays kopieren und überschreiben Java Basics - Anfänger-Themen 4
M Verschachtelte Strukturen. Java Basics - Anfänger-Themen 7
M Viele verschachtelte Schleifen Java Basics - Anfänger-Themen 14
A Verschachtelte Hashtable ausgeben. Java Basics - Anfänger-Themen 3
G Verschachtelte Case Fallunterscheidung Java Basics - Anfänger-Themen 7
M sehr weit verschachtelte XML-datei mit jdom auslesen Java Basics - Anfänger-Themen 4
S verschachtelte while Schleifen Java Basics - Anfänger-Themen 5
R Bedingte Opeatoren / Verschachtelte Operatoren Java Basics - Anfänger-Themen 4
M While-Schleife mit Wartezeit Java Basics - Anfänger-Themen 15
T Ich brauche eine Schleife die eine beliebige Zahl so lange durch 10 teilt bis zur Null Java Basics - Anfänger-Themen 5
DrahtEck Schleife soll wieder da anfangen wo ich es möchte ! Java Basics - Anfänger-Themen 17
Finn_lol Fehlermeldung bei Schleife mit Array Java Basics - Anfänger-Themen 4
Ranger229 Endless loop in while Schleife Java Basics - Anfänger-Themen 3
MaZ Quadrat Schleife(Pyramide) Java Basics - Anfänger-Themen 9
M Datentypen While-Schleife eine Java Methode erstellen Java Basics - Anfänger-Themen 3
P Wie kann diese Schleife beenden Java Basics - Anfänger-Themen 1
T float soll durch schleife die größte mögliche Zahl herausfinden, Ausgabe ist aber "Infinity" Java Basics - Anfänger-Themen 1
T Variable in Schleife deklarieren, Speicherplatz, Garbage Collector Java Basics - Anfänger-Themen 10
Ostkreuz While Schleife neustarten Java Basics - Anfänger-Themen 20
M Problem bei verschachtelter for-Schleife bei zweidimensionalen Arrays Java Basics - Anfänger-Themen 3
S Erste Schritte do-while Schleife Münzwurf Java Basics - Anfänger-Themen 1
S while Schleife Taschenrechner Java Basics - Anfänger-Themen 1
P Best Practice While loop schleife Java Basics - Anfänger-Themen 5
ohneInformatik; For Schleife. Was macht dieser Code?? Java Basics - Anfänger-Themen 5
I For Schleife Summe berechnen Java Basics - Anfänger-Themen 13
A Erste Schritte Aufgabe mit while Schleife Java Basics - Anfänger-Themen 11
R do while Schleife Verständnisfrage Java Basics - Anfänger-Themen 2
Say Fehlenden Code finden in einer while-Schleife? Java Basics - Anfänger-Themen 11
N Warum Springt iterator nur in der Schleife weiter Java Basics - Anfänger-Themen 9
J for Schleife kleinste Zufallszahl finden Java Basics - Anfänger-Themen 25
A Return in While Schleife Java Basics - Anfänger-Themen 6
M Erste Schritte While Schleife / Ausgabe von buchstabe & ASCII Wert Java Basics - Anfänger-Themen 4
J do..while Schleife Java Basics - Anfänger-Themen 14
J Java To String Methode, Array mit For-Schleife Java Basics - Anfänger-Themen 2
S Textausgabe in einer For-Schleife Java Basics - Anfänger-Themen 12
B Automatisierte Ausgabe (Schleife, If-Abfrage?) Java Basics - Anfänger-Themen 24
C 2D Array Ausgabe mit for-Schleife i,j Java Basics - Anfänger-Themen 4
T Mit jedem Wert in der for-Schleife weiter arbeiten Java Basics - Anfänger-Themen 3
berserkerdq2 Warum muss man manchmal in der RUnmethode sleep in eine schleife tun? Java Basics - Anfänger-Themen 9
F for-Schleife halbiert Durchläufe ungewollt Java Basics - Anfänger-Themen 6
ravenz Schleife mit for über String Array „zahlen“und prüfen ob Wert „a“ oder „b“ oder „c“ entspricht (mittels || ) Java Basics - Anfänger-Themen 4
Bugs Bunny Fehlerhafte Berechnung beim erneuten Durchlaufen der Schleife Java Basics - Anfänger-Themen 5
J Methoden iterator for-schleife (hasNext() ) Java Basics - Anfänger-Themen 7
S Was macht ++ ohne Schleife? Java Basics - Anfänger-Themen 4
LFB In einer For-Schleife alles in einer Zeile ausgeben Java Basics - Anfänger-Themen 14
Neuling47 for schleife Java Basics - Anfänger-Themen 6
M Variable in einer Schleife initialisieren Java Basics - Anfänger-Themen 46
B Zuweisungen und Methodenaufrufe in Bedingung der while Schleife? Java Basics - Anfänger-Themen 2
JavaBeginner22 Würfeln bis 6 while Schleife Java Basics - Anfänger-Themen 13
D EinMalEins mithilfe einer for-Schleife und Array Java Basics - Anfänger-Themen 1
xanxk Problem For-Schleife mit Charakter Java Basics - Anfänger-Themen 2

Ähnliche Java Themen

Neue Themen


Oben