oscat.lib > Bestehende Module / Existing Modules

Vorschläge für BLIND_SHADE, BLIND_CONTROL und BLIND_ACTUATOR

(1/7) > >>

mattsches:
Hallo zusammen,

ich habe seit einiger Zeit die Building Lib (danke dafür!) für die Steuerung unserer Raffstores. Dabei habe ich einige Dinge modifiziert, um das Verhalten besser an meine Vorstellungen anzupassen. Betroffen sind BLIND_SHADE, BLIND_CONTROL und BLIND_ACTUATOR. Vielleicht sind die Punkte ja für den einen oder anderen interessant. Weitere Details gerne bei Bedarf; doch bevor ich mir die Finger hier wund tippe, wollte ich erstmal sehen, ob überhaupt Interesse besteht.

Also los - Folgende Punkte habe ich für meine Zwecke geändert bzw. ergänzt:

* Winkelberechnung auch für Raffstores, die beim Hochfahren nicht ganz senkrecht (0°) gestellt werden. In meinem Fall sind es 18°, der von BLIND_SHADE errechnete Winkel wurde daher nicht korrekt eingestellt.
* Winkel- und Positionsangabe von der größenlosen Skalierung 0..255 umgestellt auf 0..90° (für meine Zwecke reicht 1° Auflösung völlig) und 0..100% (mit 100%=geöffnet).
* Winkelberechnung in BLIND_SHADE erweitert um die Auswirkung des horizontalen Sonnenwinkels. Steht die Sonne beispielsweise bei 200°, also sehr weit im Süden, können die Raffstores auf der Westseite deutlich weiter geöffnet (bezogen auf den Lamellenwinkel) bleiben als auf der Südseite.
* Zusätzliche Verzögerungszeit in BLIND_SHADE, um den Raffstore nach erkanntem Sonnenschein verzögert zu schließen.
* ... und noch eine weitere Verzögerungszeit in BLIND_SHADE für die Schattenerkennung; sie führt dazu, dass kurz nach erkanntem Schatten (bei mir nach 10s) die Lamellen waagrecht gestellt werden, um die Sicht zu maximieren. Erst nach weiterer Verzögerung (tofShadeDelayPos, ehemals sun_delay) fährt die Jalousie dann hoch.
Und hier der Code:

BLIND_SHADE:

--- Code: ---FUNCTION_BLOCK BLIND_SHADE
VAR_INPUT
UP, DN : BOOL;
S_IN : BYTE;
PI, AI : BYTE;
ENABLE : BOOL;
SUN : BOOL;
DIRECTION : REAL := 180.0;
ANGLE_OFFSET : REAL := 80.0;
DISABLE_TRACKING : BOOL := FALSE; (* disable tracking of sun/slat angle -> always maximize shading *)
END_VAR
VAR_IN_OUT
CX : CALENDAR;
END_VAR
VAR_INPUT CONSTANT
sunrise_offset : TIME := T#1h;
sunset_preset : TIME := T#1h;
slat_width : REAL := 80.0;
Slat_spacing : REAL := 70.0;
Shade_pos : BYTE := 0;

tSunDelay : TIME := t#60s; (* delay after sun detection until slat angle is calculated *)
tShadeDelayAngle : TIME := t#30s; (* delay after shade detection until slat angle is set to 90=horizontal *)
tShadeDelayPos : TIME := t#10m; (* delay after shade detection until slat position is set to 100=fully opened *)
END_VAR
VAR_OUTPUT
QU, QD : BOOL;
STATUS : BYTE;
PO, AO : BYTE;
END_VAR
VAR
angle: REAL;
max_angle : REAL;
angle_old : REAL;

fEffectiveSlatWidth : REAL; (* effective slat width, including effect of horizontal sun angle *)

tonSunDelay : TON; (* timer for delay after sun detection until shade is closed and angle is calculated *)
tofShadeDelayAngle : TOF; (* timer for delay after shade detection until slat angle is set to 90=horizontal *)
tofShadeDelayPos : TOF; (* timer for delay after shade detection until slat position is set to 100=fully opened *)

sun_ver_last : REAL; (* last vertical sun angle (for change detection) *)
sun_hor_last : REAL; (* last horizontal sun angle (dto.) *)
END_VAR

--- Ende Code ---


--- Code: ---(* delay sun/shade detection in order to prevent shade from constantly going up and down *)
tonSunDelay(IN:=sun, PT:=tSunDelay);
tofShadeDelayAngle(IN:=tonSunDelay.Q OR tofShadeDelayAngle.Q AND sun, PT:=tShadeDelayAngle);
tofShadeDelayPos(IN:=tofShadeDelayAngle.Q, PT:=tShadeDelayPos);


IF UP AND DN AND enable AND (tonSunDelay.Q OR tofShadeDelayPos.Q)
AND cx.SUN_HOR > direction - angle_offset AND cx.SUN_HOR < direction + angle_offset
AND DT_TO_TOD(cx.UTC) > cx.SUN_RISE + sunrise_offset AND DT_TO_TOD(cx.UTC) < cx.SUN_SET - sunset_preset THEN
   status := 151;
   QU := UP;
   QD := DN;

   (* position is predefined *)
   po := shade_pos;

   (* shading is active now calculate the slat angle *)
   (* calculate the max angle for the blind *)
   fEffectiveSlatWidth := slat_width / COS(RAD(ABS(DIRECTION - cx.SUN_HOR)));
   max_angle := DEG(ATAN(slat_spacing / fEffectiveSlatWidth));

   (* check if sun angle is between 0 and max angle *)
   IF cx.SUN_VER > 0.0 AND cx.SUN_VER < max_angle AND NOT DISABLE_TRACKING AND tofShadeDelayAngle.Q THEN
      (* only recalculate blind angle if vertical sun angle has changed *)
      IF   cx.SUN_VER <> sun_ver_last OR cx.SUN_HOR <> sun_hor_last THEN
         angle := cx.SUN_VER + DEG(ACOS(COS(RAD(cx.SUN_VER))*slat_spacing / fEffectiveSlatWidth));
         sun_ver_last := cx.SUN_VER;         (* store current sun angles *)
         sun_hor_last := cx.SUN_HOR;
      END_IF;
      ao := INT_TO_BYTE(LIMIT(0,TRUNC(angle), 90));
   ELSIF DISABLE_TRACKING THEN               (* tracking of sun/slat angle disabled -> always maximize shading *)
      ao := 0;
   ELSE
      ao := 90;
   END_IF;
ELSE
   QU := UP;
   QD := DN;
   po := pi;
   ao := ai;
   status := S_IN;
END_IF;

--- Ende Code ---


BLIND_CONTROL:

--- Code: ---FUNCTION_BLOCK BLIND_CONTROL
VAR_INPUT
UP, DN : BOOL;
S_IN : BYTE;
PI : BYTE;
AI : BYTE;
T_UD, T_ANGLE : TIME;
END_VAR
VAR_INPUT CONSTANT
SENS : BYTE := 5;
T_LOCKOUT: TIME := T#100ms;
MIN_ANGLE : BYTE := 0; (* minimum slat angle *)
MAX_ANGLE : BYTE := 90; (* maximum slat angle *)
END_VAR
VAR_OUTPUT
POS, ANG : BYTE;
MU, MD : BOOL;
STATUS : BYTE;
END_VAR
VAR
act : BLIND_ACTUATOR;
delta : BYTE;
bTimeTest:BOOL:=FALSE;
iPos:BYTE;
iAngel:BYTE;
END_VAR

--- Ende Code ---



--- Code: ---(* limit angle setpoint *)
ai := LIMIT(MIN_ANGLE, ai, MAX_ANGLE);


(* Check Position*)
act(T_UD:=T_UD, T_ANGLE:=T_ANGLE, T_lockout := T_Lockout, MIN_ANGLE := MIN_ANGLE, MAX_ANGLE := MAX_ANGLE);

IF UP AND DN THEN
(* automatic modus detected *)
(* first find correct position *)
IF BYTE_TO_INT(act.pos) < BYTE_TO_INT(pi) - delta THEN
act.UP := TRUE;
act.DN := FALSE;
delta := 0;
STATUS := 121;
ELSIF BYTE_TO_INT(act.pos) > BYTE_TO_INT(pi) + delta THEN
act.UP := FALSE;
act.DN := TRUE;
delta := 0;
STATUS := 122;
(* regulate angle *)
ELSIF BYTE_TO_INT(act.ang) < BYTE_TO_INT(ai) - delta AND T_angle > T#100ms THEN
act.UP := TRUE;
act.DN := FALSE;
delta := sens/2;
STATUS := 123;
ELSIF BYTE_TO_INT(act.ang) > BYTE_TO_INT(ai) + delta AND T_angle > T#100ms THEN
act.UP := FALSE;
act.DN := TRUE;
delta := sens/2;
STATUS := 124;
(* correct position reached *)
ELSE
act.UP := FALSE;
act.DN := FALSE;
delta := sens;
STATUS := S_IN;
END_IF;
ELSE
act.UP := UP;
act.DN := DN;
STATUS := S_IN;
END_IF;

(* blind control calls blind_actuator *)
act(T_UD:=T_UD, T_ANGLE:=T_ANGLE, T_lockout := T_Lockout);
pos := act.pos;
ang := act.ang;
MU := act.QU;
md := act.QD;

--- Ende Code ---


BLIND_ACTUATOR:

--- Code: --- FUNCTION_BLOCK BLIND_ACTUATOR
VAR_INPUT
UP, DN : BOOL;
S_IN : BYTE;
T_UD : TIME := T#10s;
T_ANGLE : TIME := T#3s;
MIN_ANGLE : BYTE := 0; (* minimum slat angle; 0 would equal full vertical position *)
MAX_ANGLE : BYTE := 90; (* maximum slat angle; 90 would equal horizontal position *)
END_VAR
VAR_INPUT CONSTANT
T_LOCKOUT : TIME := t#100ms;
END_VAR
VAR_OUTPUT
POS, ANG : BYTE;
QU, QD : BOOL;
STATUS : BYTE;
END_VAR
VAR
position, angle : RMP_B;
lock : INTERLOCK;
END_VAR

--- Ende Code ---


--- Code: ---(* make sure only one moto r is active at a given time *)
lock(i1 := UP, I2 := DN, TL := T_lockout);

(* ramp up or down to simulate the angle position of the blind slats *)
angle(e := lock.Q1 OR lock.Q2, UP := lock.Q1, PT := T_Angle);
position(e := lock.Q1 AND angle.high OR lock.Q2 AND angle.low, up := lock.Q1, PT := T_UD);

(* set the outputs *)
pos := position.Out * 100 / 255;
ang := angle.OUT * (MAX_ANGLE - MIN_ANGLE) / 255 + MIN_ANGLE;


(* set the outputs *)
QU := lock.Q1;
QD := lock.Q2;

(* set the status output *)
IF UP AND DN THEN
status := 1; (* error up and down together are not allowed *)
ELSIF UP THEN
status := 121;
ELSIF DN THEN
status := 122;
ELSE
status := S_IN;
END_IF;

--- Ende Code ---

Majaestix:
Hallo mattsches,

danke!

Interessiert mich auch.
Deinen Code guck ich mir am WE mal an.

Gruss

Majaestix

mattsches:
Um die ekstatische Euphorie hier noch weiter anzuheizen  ;), ich hatte noch ein kleines Feature unterschlagen:

Der neue Eingang "DISABLE_TRACKING" am BLIND_SHADE führt dazu, dass die Jalousie zwar geschlossen, der Lamellenwinkel jedoch nicht nachgeführt, sondern bleibt immer voll geschlossen. Ich nutze das im Schlafzimmer, wo ich immer eine maximale Verschattung haben möchte.

Grüße,
mattsches

mattsches:
Huch! Es interessiert sich tatsächlich ein einsamer Programmierer für das Thema... Da man per PN offenbar keine Anhänge mit verschicken kann, auf diesem Wege anbei die aktuellen Versionen der von mir modifizierten BLIND_*-Bausteine.

[gelöscht durch Administrator]

fu_zhou:
So, ich bin jetzt auch mal dabei...

Navigation

[0] Themen-Index

[#] Nächste Seite

Zur normalen Ansicht wechseln