Recientemente, y debido al proceso de documentación que estoy realizando para el curso de TIA Portal sobre la serie 1200 de Siemens (en el cual veremos ejemplos también en SCL), me he topado con este ejemplo de Seguimiento solar con Siemens 1200 realizado en TIA Portal.
Es un ejemplo publicado en inglés de la empresa Bytex Automation, en Italia. Me he puesto en contacto con ellos para pedirles la oportunidad de traducir el ejemplo a castellano y compartirlo contigo.
Su contacto Massimo me ha dado permiso, por lo que aquí te lo traigo para que lo conozcas si no lo habías visto o bien si la lengua de Shakespeare se te resiste un poco.
La traducción es lo más literal posible para ser fiel a la entrada original.
Contenido
- 1 Seguimiento solar con Siemens 1200 y TIA Portal
Seguimiento solar con Siemens 1200 y TIA Portal
Este artículo explica como construir un sistema de seguimiento solar con usando un PLC Simatic S7-1200. La función astronómica estças desarrollada en lenguaje SCL. El objetivo principal es desarrollar una función capaz de retornar la elevación del Sol (ángulo de altitud solar), y su ángulo con el norte (ángulo azimutal).
La función retornará también el tiempo que falta para el amanecer y el ocaso, la duración total de horas de sol, el momento en el que se hace de día y cuándo se hace de noche. Puedes usar esta característica para encender una lámpara en tu jardín cuando el sol se pone o dirigir uno o varios paneles, manejados por ejes motorizados, siguiendo el sol para conseguir el máximo de energía.
Ejemplos de paneles solares usando uno o dos ejes motorizados
La función necesita algunos parámetros de entrada, como la latitud, longitud y elevación local, la zona horaria, ajuste de luz de día, y finalmente la hora actual dada desde el reloj del PLC.
Función astronómica – Parámetros de entrada
- LocalLatitude Número decimal representando la latitud local. Asigna números positivos para el hemisferio norte y negativos para el hemisferio sur. Por ejemplo 45.838073
- LocalLongitude Número decimal que representa la longitud local. Asigna números positivos para meridianos del Este y negativos para el Oeste de Greenwich. Por ejemplo -13.406095)
- Elevation Número decimal que representa la elevación local sobre el mar medido en metros.
- TimeZone (Número decimal que representa la zona horaria respecto a Greenwich.
- DayLightAdjustement Fija DayLightAdjustement = 1 en verano y DayLightAdjustement = 0 para invierno
- ActualDateAndTime Fecha y hora actual
Función astronómica – Parámetros de salida
- AltitudeAngle Número decimal que representa el ángulo entre la posición del sol y el horizonte del observador local.
- AzimuthAngle Número decimal que representa el ángulo entre una dirección de referencia (Norte) y una línea desde el observador hasta la posición del sol proyectada en el mismo plano como la dirección de referencia.
- SunRiseTime Amanecer en tipo de datos DTL
- SunSetTime Puesta del Sol en tipo de datos DTL
- SunDurationTime Duración total de sol en tipo de datos Time
- IsDay Booleana que indica el el evento del amanecer
- IsNight Booleana que indica el evento del anochecer
Cómo funciona: Ajuste de luz solar
Si tu país tiene un sistema de ahorro de luz solar (como por ejemplo España), tienes que ajustar el parámetro DayLightAdjustement=1 en verano, y DayLightAdjustement=0 en invierno. Si no lo tiene, el parámetro tiene que estar siempre a 0.
¿Cómo hacerlo?
Usando la función RD_LOC_T puedes leer la fecha y hora actual del PLC Simatic S7-1200 y leyendo el valor RET_VAL de la función, puedes leer el estado del tiempo de luz solar actual (W#16#0001)
Cómo funciona: Sincronizar el relos del PLC con la hora de internet
¿Cómo hacerlo?
Si tienes una conexión de internet para el PLC es bastante simple. Ve a la configuración del dispositivo en el panel izquierdo del TIA Portal; pica y haz click en el interface PROFINET y selecciona Activar sincronización horaria via servidor NTP y añade una dirección de servidor de hora de internet. Por ejemplo 192.204.114.232.
Cómo funciona: Función astronómica de un sistema de seguimiento solar con Siemens 1200
Lenguaje SCL – Esta es la lista de declaración de variables
// Input parameters
//-------------------------------
// LocalLatitude: Real
// LocalLongitude: Real
// Elevation: Real
// TimeZone: Int
// DayLightAdjustement: Int
// ActualDateAndTime: DTL
// Output parameters
//-------------------------------
// AltitudeAngle: Real
// AzimuthAngle: Real
// SunRiseTime: DTL
// SunSetTime: DTL
// SunDurationTime: Time
// IsDay: Bool
// IsNight: Bool
// PreSet: Bool
// Static declarations
//-------------------------------
// #RadiansToDegrees Real
// #DegreesToRadians Real
// #Meridian Real
// #HoursAfterMidnight Real
// #MinutesAfterMidnight Real
// #UT Real
// #CorrectedYear UInt
// #CorrectedMonth USInt
// #t Real
// #g Real
// #gn Real
// #C Real
// #L Real
// #Alpha Real
// #GHA Real
// #GHAn Real
// #Obliquity Real
// #Declination Real
// #EotAdjustment Real
// #ClockTimeToLSOTAdjustment Real
// #SolarHourAngle Real
// #ApparentSolarTime Real
// #SolarMinutesAfterMidnight Real
// #whichDay Int
// #HourAngle Real
// #PreAzimuthAngle Real
// #x Bool
// #SunRiseSetLSoTMinutes Real
// #SunRiseTime_R Real
// #SunSetTime_R Real
// #SunDurationTime_R Real
// #RHour Real
// #RMin Real
// #RSec Real
// #IHOUR Int
// #IMIN Int
// #ISEC Int
Lenguaje SCL – Código ejemplo de seguimiento solar
//******************************************************
// THIS CODE MUST BE COMPILED AS FUNCTION_BLOCK
//******************************************************
// Define Radians and Degrees conversion
// -------------------------------------
#RadiansToDegrees := 57.295779513082323;
#DegreesToRadians := 0.017453292519943295;
#Meridian := -15.0 * INT_TO_REAL(#TimeZone);
// Calculate Hours after midnight
// ------------------------------
#HoursAfterMidnight := INT_TO_REAL(#ActualDateAndTime.HOUR) +
INT_TO_REAL(#ActualDateAndTime.MINUTE) / 60.0 +
INT_TO_REAL(#ActualDateAndTime.SECOND) / 3600.0;
// Calculate Minutes after midnight
// --------------------------------
#MinutesAfterMidnight := INT_TO_REAL(#ActualDateAndTime.HOUR) * 60.0 +
INT_TO_REAL(#ActualDateAndTime.MINUTE) +
INT_TO_REAL(#ActualDateAndTime.SECOND) / 60.0;
// calculate Universal Time
// ------------------------
#UT := #HoursAfterMidnight - INT_TO_REAL(#TimeZone) - INT_TO_REAL(#DayLightAdjustment);
IF #ActualDateAndTime.MONTH > 2 THEN
#CorrectedYear := #ActualDateAndTime.YEAR;
#CorrectedMonth := #ActualDateAndTime.MONTH - 3;
ELSE
#CorrectedYear := #ActualDateAndTime.YEAR -1;
#CorrectedMonth := #ActualDateAndTime.MONTH + 9;
END_IF;
#t := ((#UT / 24.0) + USINT_TO_REAL(#ActualDateAndTime.DAY) +
DINT_TO_REAL(FLOOR(30.6 * USINT_TO_REAL(#CorrectedMonth) + 0.5)) +
DINT_TO_REAL(FLOOR(365.25 * (UINT_TO_REAL(#CorrectedYear) - 1976.0))) - 8707.5) / 36525.0;
#g := 357.528 + 35999.05 * #t;
#gn := "NormalizeTo360"(#g);
#C := (1.915 * SIN(#gn * #DegreesToRadians)) +
(0.02 * SIN((2.0 * #gn) * #DegreesToRadians));
#L := 280.46 + (36000.77 * #t) + #C;
#Alpha := #L - 2.466 * SIN((2.0 * #L) * #DegreesToRadians) +
0.053 * SIN((4.0 * #L) * #DegreesToRadians);
#GHAn := #UT * 15.0 - 180.0 - #C + #L - #Alpha;
#GHA := "NormalizeTo360"(#GHAn);
#Obliquity := 23.4393 - 0.013 * #t;
#Declination := ATAN(TAN(#Obliquity * #DegreesToRadians) * SIN(#Alpha * #DegreesToRadians));
#Declination := #Declination * #RadiansToDegrees;
#EotAdjustment := (#L - #C - #Alpha) / 15.0; // EOT adjustment in hours
#ClockTimeToLSOTAdjustment := ((#LocalLongitude - #Meridian) / 15.0) -
#EotAdjustment + #DayLightAdjustment;
#SolarHourAngle := 0.0;
#SolarHourAngle := #GHA - #LocalLongitude;
#TempReal := "NormalizeTo180"(#SolarHourAngle);
#SolarHourAngle := #TempReal;
#ApparentSolarTime := 0.0;
#TempReal := 12.0 + #SolarHourAngle / 15.0;
#ApparentSolarTime := "NormalizeTo24"(#TempReal);
#SolarMinutesAfterMidnight := #MinutesAfterMidnight - (#ClockTimeToLSOTAdjustment * 60.0);
#whichDay := 0;
#HourAngle := (#SolarMinutesAfterMidnight - 720.0) / 4.0 * -1.0;
#AltitudeAngle := #RadiansToDegrees *
(ASIN((SIN(#LocalLatitude * #DegreesToRadians) *
SIN(#Declination * #DegreesToRadians)) -
(COS(#LocalLatitude * #DegreesToRadians) *
COS(#Declination * #DegreesToRadians) *
COS((#SolarHourAngle + 180.0) * #DegreesToRadians))));
#PreAzimuthAngle := #RadiansToDegrees * ACOS((COS(#Declination * #DegreesToRadians) *
((COS(#LocalLatitude * #DegreesToRadians) *
TAN(#Declination * #DegreesToRadians)) +
(SIN(#LocalLatitude * #DegreesToRadians) *
COS((#SolarHourAngle + 180.0) * #DegreesToRadians)))) /
COS(#AltitudeAngle * #DegreesToRadians));
#x := False;
IF (#HourAngle > 0.0) THEN
IF (#HourAngle < 180.0) THEN
#x := True;
END_IF;
END_IF;
IF #x THEN
#AzimuthAngle := (360.0 - #PreAzimuthAngle);
ELSE
#AzimuthAngle := #PreAzimuthAngle;
END_IF;
#SunRiseSetLSoTMinutes := #RadiansToDegrees * ACOS(-1.0 *
(SIN(#LocalLatitude * #DegreesToRadians) *
SIN(#Declination * #DegreesToRadians) -
SIN((-0.8333 - 0.0347 * SQRT((#Elevation))) * #DegreesToRadians)) /
COS(#LocalLatitude * #DegreesToRadians) /
COS(#Declination * #DegreesToRadians)) * 4.0;
#SunRiseTime_R := ((720.0 - #SunRiseSetLSoTMinutes + (#ClockTimeToLSOTAdjustment * 60.0)));
#TempReal := #SunRiseTime_R;
#RSec := DINT_TO_REAL(FLOOR((#TempReal - DINT_TO_REAL(FLOOR(#TempReal))) * 60.0));
#RSec := #RSec + DINT_TO_REAL(FLOOR(#TempReal)) * 60.0;
#RHour := DINT_TO_REAL(FLOOR(#RSec / 3600.0));
#RMin := DINT_TO_REAL(FLOOR((#RSec / 3600.0 - #RHour) * 60.0));
#RSec := #RSec - #RHour * 3600.0 - #RMin * 60.0;
IF #RSec >= 30.0 AND #RMin < 59 THEN
#RMin := #RMin + 1.0;
END_IF;
#IHOUR := REAL_TO_INT(#RHour);
#IMIN := REAL_TO_INT(#RMin);
#ISEC := REAL_TO_INT(#RSec);
#SunRiseTime := #ActualDateAndTime;
#SunRiseTime.HOUR := INT_TO_USINT(#IHOUR);
#SunRiseTime.MINUTE := INT_TO_USINT(#IMIN);
#SunRiseTime.SECOND := INT_TO_USINT(#ISEC);
#SunSetTime_R := ((720.0 + #SunRiseSetLSoTMinutes + (#ClockTimeToLSOTAdjustment * 60.0)));
#TempReal := #SunSetTime_R;
#RSec := DINT_TO_REAL(FLOOR((#TempReal - DINT_TO_REAL(FLOOR(#TempReal))) * 60.0));
#RSec := #RSec + DINT_TO_REAL(FLOOR(#TempReal)) * 60.0;
#RHour := DINT_TO_REAL(FLOOR(#RSec / 3600.0));
#RMin := DINT_TO_REAL(FLOOR((#RSec / 3600.0 - #RHour) * 60.0));
#RSec := #RSec - #RHour * 3600.0 - #RMin * 60.0;
IF #RSec >= 30.0 AND #RMin < 59 THEN
#RMin := #RMin + 1.0;
END_IF;
#IHOUR := REAL_TO_INT(#RHour);
#IMIN := REAL_TO_INT(#RMin);
#ISEC := REAL_TO_INT(#RSec);
#SunSetTime := #ActualDateAndTime;
#SunSetTime.HOUR := INT_TO_USINT(#IHOUR);
#SunSetTime.MINUTE := INT_TO_USINT(#IMIN);
#SunSetTime.SECOND := INT_TO_USINT(#ISEC);
#SunDurationTime_R := (#SunSetTime_R - #SunRiseTime_R) / 60.0;
IF #ActualDateAndTime >= #SunRiseTime AND #ActualDateAndTime <= #SunSetTime THEN
#IsDay := true;
#IsNight := false;
ELSE
#IsDay := false;
#IsNight := true;
END_IF;
IF #ActualDateAndTime >= (#SunSetTime - 1) THEN
#PreSet := true;
ELSE
#PreSet := false;
END_IF;
Lenguaje SCL – Código de la función NormalizeTo24
//***********************************************
// Assign to the FUNCTION the name=NormalizeTo24
//***********************************************
// Input parameters
//-------------------------
// aTime: Real
// Return variable
//-------------------------
// Ret_Val Real
#NormalizeTo24 := (#aTime - DINT_TO_REAL(FLOOR(#aTime / 24.0)) * 24.0);
Lenguaje SCL – Código de la función NormalizeTo180
//************************************************
// Assign to the FUNCTION the name=NormalizeTo180
//************************************************
// Input parameters
//-------------------------
// Angle: Real
// Temporary variables
//-------------------------
// TempAngle: Real
// Return variable
//-------------------------
// Ret_Val Real
#TempAngle := "NormalizeTo360"(#Angle);
IF "NormalizeTo360"(#Angle) > 180.0 THEN
#TempAngle := "NormalizeTo360"(#Angle) - 360.0;
END_IF;
#NormalizeTo180 := #TempAngle;
Lenguaje SCL – Código de la función NormalizeTo360
//************************************************
// Assign to the FUNCTION the name=NormalizeTo360
//************************************************
// Input parameters
//-------------------------
// Angle: Real
// Return variable
//-------------------------
// Ret_Val Real
#NormalizeTo360 := (#Angle - DINT_TO_REAL(FLOOR(#Angle / 360.0)) * 360.0);
Últimas recomendaciones sobre esta función para el Seguimiento solar con Siemens 1200 y TIA Portal.
Recuerda llamar al bloque principal dentro de un OB de interrupción fijando el tiempo de interrupción a 1000 milisegundos o 10000 milisegundos.
Esta entrada de Seguimiento solar con Siemens 1200 es original de:
Autor:Bytex Automation es una compañía italiana con muchos años de experiencia internacional en automatización industrial (especialmente en el sector de acero), webs en tiempo real para análisis y manejo de procesos industriales como manufactura y logistica. Su fortaleza radica en la capacidad de desarrollar sistemas que comunican PLC y bases de datos EPR para producir plataformas web integradas y amigables.
Enseño a programar PLC de Siemens a través de mis cursos.
Más información sobre mi aquí
Puedes seguirme en cualquiera de las siguientes redes sociales.
16 Comentarios
Hola Íñigo tienes el proyecto completo para poder descargarlo, no lo encuentro en la página donde dices que lo has sacado.
saludos y gracias
Hola Victor,
No, no hay proyecto para descargar. Solo el código fuente. Tendrás que copiarlo y generar los bloques.
Saludos
Íñigo, no me queda claro la explicación de comparar el ret_val de la instrucción de extracción de hora local, con w#16#0001
saludos
La usa para saber si tiene horario de verano o de invierno. La compara con un «1» en hexadecimal. Si está a uno, es que tiene esa hora de diferencia, y si está a cero, que no. De ahí, que le sume una hora o no tras la comparación.
Saludos
No lo entendía porque en las instrucciones de siemens indicaba otra cosa para ret val 0 si no había error.
saludos
No exactamente. Sacado de la ayuda de la instrucción:
Parámetro RET_VAL
Código de error*
(W#16#….)
Descripción
0000
Ningún error
0001
Ningún error. La hora local se devuelve como horario de verano.
Saludos
Lo había mirado en el manual en pdf manual del sistema 1200, no en tia portal
En general suele ser así, pero lo mejor siempre es ver la ayuda de cada instrucción.
Saludos
Hola Iñigo,
Muy bueno este artículo. Este código o programa se necesita especialmente el ST-1200 o cualquier otro autómata podría dar el mismo resultado, porque no sé si el SCL se podría hacer servir en otros, parece que es como el Visual Basic?, vaya por cierto dispones de autómatas o colaboras con más Voltaje. Quiero hacerme una instalación solar y necesitaría también al menos un autómata. Podrías conseguirme uno que no fuera nuevo y que hiciera el trabajo
Hola,
EL SCL es como Pascal, no como VB.
En cuanto al autómata, si no lo quieres nuevo, tendras que buscarlo en ebay o segunda mano
Saludos!
Hola Iñigo
Estoy intentando poner en práctica el código SCL para generar el FB del seguidor solar, al compilar me da bastantes errores de operandos que no están definidos y que no están en el listado de declaración de variables del ejemplo, la verdad es que no se si debo definir estas variables y con que tipo de dato se tendría que hacer.
Saludos
Pues no sé que decirte. Solo compartí en su día el código que facilitaba la empresa italiana. Supongo que por el contexto deberás sacar el tipo de variable que es además de estar haciendo el programa con el PLC 1200 como es el ejemplo.
Observa, eso sí, que no solamente hay variables en cada bloque, sino un listado al inicio.
Saludos
Buen día!
Una pregunta, la serie 1200 maneja diferentes plc. ¿Estaría bien utilizar un plc 1215 ac/dc/rly? ¿O que plc me sugeriría ocupar?
Eso lo tienes que decidir tú en función de lo que vayas a hacer, pero con el 1215 no deberías tener demasiados problemas ya que es de los más potentes.
Gracias, una duda más, como puedo hacer para direccionar las variables del DB a DBW para que la variable salga como %DB9.DBW es que cuando creo el bloque de datos numero 9 no puedo direccionar para que me salga como anteriormente mencioné.
Entiendo que el problema es que tienes marcado el DB como optimizado y deberías ponerlo como no optimizado. Todas esas dudas se resuelven en los cursos.
Saludos