FB CTRL_PID

Alguien del foro me pidió que le mostrara un FB PID en ST.He pensado que mejor mostrarlo aquí.

Este es el CALL TREE o árbol de llamadas del FB.

 

Lo primero que necesitamos para el FB es medir el ciclo de scan. Para eso esta la función T_PLC_US que basicamente recoge en un DWORD una marca de tiempo del plc. Luego el las funciones derivada e integral calcula el ciclo de scan restando la marca de tiempo actual – anterior. 

FT_DERIV

DECLARACIÓN DE VARIABLES

FUNCTION_BLOCK FT_DERIV
VAR_INPUT
    in : REAL;
    K : REAL := 1;
    run : BOOL := 1;
END_VAR
VAR_OUTPUT
    out : REAL;
END_VAR
VAR
    old: REAL;
    tx: DWORD;
    last: DWORD;
    init: BOOL;
END_VAR
 
(*
version 1.4    6. nov. 2008
programmer     hugo
tested by    oscat
 
FT_deriv calculates the derivate over the signal "in" with Faktor "K".
a run input enables or stops the calculation, if left unconnected its true and therfore the calculation is executed.
if K is not specified the default is 1.
 
*)

PROGRAMA

(* read system time *)
tx := T_PLC_US();
 
(* init on firsat startup *)
IF NOT init THEN
    init := TRUE;
    last := tx;
    old := in;
ELSIF run AND tx - last > 0 THEN
    out := (in - old) / DWORD_TO_REAL(tx - last) * 1000000.0 * K;
    last := tx;
    old := in;
ELSE
    out := 0;
END_IF;
 
(*
hm 3.1.2007            rev 1.1
    added init code for startup
    set the default for K to 1
 
hm    15. sep 2007    rev 1.2
    replaced Time() with T_PLC_US for compatibility and performance reasons
    increased accuracy and work in microseconds internally
 
hm 29 oct 2007    rev 1.3
    prohibit calculation when tx - last = 0 to avoid division by 0 and increase accuracy on fast systems
 
hm    6. nov. 2008    rev 1.4
    improved performance
*)

Como se puede ver, básicamente el programa hace este calculo (in – old) / tiempo de ciclo de scan * K.
Lógicamente (in – old) es el error del proceso.

FT_PIWL
DECLARACION DE VARIABLES

FUNCTION_BLOCK FT_PIWL
VAR_INPUT
    IN : REAL;
    KP : REAL := 1.0;
    KI : REAL := 1.0;
    LIM_L : REAL := -1E38;
    LIM_H : REAL := 1E38;
    RST : BOOL;
END_VAR
VAR_OUTPUT
    Y : REAL;
    LIM : BOOL;
END_VAR
VAR
    init: BOOL;
    tx: DWORD;
    tc : REAL;
    t_last: DWORD;
    in_last : REAL;
    i: REAL;
    p: REAL;
END_VAR
 
(*
version 1.2    25. jan. 2009
programmer     hugo
tested by        oscat
 
FT_PIWL is a PI controller.
The PID controller works according to the fomula Y = IN *(KP+ KI * INTEG(e) ).
a rst will reset the integrator to 0
lim_h and Lim_l set the possible output range of the controller.
the output flag lim will signal that the output limits are active.
the integrator ist equipped with anti wind-up circuitry which limits trhe total output ranke to lim_l and lim_h
 
default values for KP = 1, KI = 1, ILIM_L = -1E37, iLIM_H = +1E38.
*)

PROGRAMA

(* initialize at power_up *)
IF NOT init OR RST THEN
    init := TRUE;
    in_last := in;
    t_last := T_PLC_US();
    i := 0;
    tc := 0;
ELSE
    (* read last cycle time in Microseconds *)
    tx := T_PLC_US();
    tc := DWORD_TO_REAL(tx - t_last);
    t_last := tx;
 
    (* calculate proportional part *)
    p := KP * IN;
 
    (* run integrator *)
    i := (IN + in_last) * 5E-7 * KI * tc + i;
    in_last := IN;
 
    (* calculate output Y *)
    Y := p + i;
 
    (* check output for limits *)
    IF Y >= LIM_H THEN
        Y := LIM_H;
        IF ki <> 0 THEN
            i := LIM_H - p;
        ELSE
            i := 0;
        END_IF;
        LIM := TRUE;
    ELSIF Y <= LIM_L THEN
        Y := LIM_L;
        IF ki <> 0 THEN
            i := LIM_L - p;
        ELSE
            i := 0;
        END_IF;
        LIM := TRUE;
    ELSE
        LIM := FALSE;
    END_IF;
END_IF;
 
(* revision history
hm 13. jun. 2008     rev 1.0
    original version
 
hm    27. oct. 2008   rev 1.1
    integrator will not be adjusted when ki = 0
 
hm    25. jan 2009    rev 1.2
    module will also work with negative K
 
*)

Igualmente, en este caso el calculo integral es este:
i := (IN + inlast) * 5E-7 * KI * tc + i;
in
last := IN;

Visto de otra forma:

integral = [(Error + Error anterior)  * Cte * Ciclo scan ] + integral anterior.

Lavadora Web 2.0. Los recursos necesarios.

Para poder afrontar los siguientes pasos de la lavadora web, necesitamos ciertos recursos para poder interactuar con la base de datos. MySql dispone de un conector para vb.net pero no es compatible con las versiones express. Por este motivo utilizaremos MySqlDriverCs que podéis descargar desde aquí.

Para crear el código de las páginas web, se puede utilizar el bloc de notas, pero es de agradecer ciertas ayudas como el resaltado de código y algunas ayudas mas. En mi caso para las aplicaciones web utilizo Pspad.

En cuanto a la gestión de la base de datos, xammp incluye phpMyAdmin que permite interactuar con la base de datos para crear usuarios, tablas, etc. De todas formas os recomiendo MySqlWorkbench que es mucho mas potente y amigable (para mi). Lo podéis descargar desde aquí.

Respecto a Workbench tenemos varias posibilidades, yo he marcado dos. En la primera (flecha negra) es para instalar, la segunda opción no se instala. Es la que yo utilizo. Descargamos el archivo, lo descomprimimos y guardamos la carpeta en C/. Si queremos, podemos crear un acceso directo y ponerlo en el escritorio o anclarlo en la barra de W7.

Lavadora web 2.0. Configurar la seguridad.

Antes de empezar comentaros que aunque por el momento no haremos mucho caso de la seguridad, es importante tenerlo en cuenta. Para realizar estas comprobaciones deberemos arrancar el servidor web, mediante el acceso directo que se encuentra en la carpeta C:\xampp\xampp_start.exe. Una vez arrancado el servidor web, abrimos el navegador y vamos a la dirección http://localhost. En la barra de la izq pinchamos en chequeo de seguridad:

Llamamos al comando, tal y como nos dicen:

Y el asistente nos permite cambiar las contraseñas y algunas configuraciones de seguridad.

Por el momento no cambiare la contraseña. En caso de hacerlo, sera necesario cambiar la configuración de phpMyAdmin, para poder utilizarlo. Para esto abrimos con el bloc de notas C:\xampp\phpMyAdmin\config.inc y cambiamos el password:

Lavadora web 2.0. Interface HMI en Vb.net

Bueno, os dejo el video de la aplicación en vb.net funcionando.

Lavadora web 2.0

He modificado la clase encargada de comunicar con el plc. En este caso llamaremos a las variables por su nombre. Esta el la clase:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
Imports TwinCAT.Ads
Public Class ClassAds
    Private adsClient As TcAdsClient
    Dim Conectado As AdsState
    Enum AdsState
        Desconectado
        ErrorConect
        ConectadoOk
    End Enum
 
#Region "PLC ADS"
    Public Function Conectar() As String
        Try
            adsClient = New TcAdsClient
            adsClient.Connect("192.168.255.2.1.1", 801)
            adsClient.Timeout = 5000
 
            If adsClient.ReadState.AdsState.ToString = "Run" Then
                Conectado = AdsState.ConectadoOk
            Else
                Conectado = AdsState.ErrorConect
            End If
            Return adsClient.ReadState.AdsState.ToString
        Catch err As Exception
            Conectado = AdsState.ErrorConect
            Return "Error"
        End Try
 
    End Function
 
    Public Function ValorIntPorNombre(ByVal Name As String)
 
        Dim dataStream As AdsStream
        Dim Read As AdsBinaryReader
 
        Try
            'Recuperar Numero Var
            Dim Var As Integer
            Var = adsClient.CreateVariableHandle(Name)
 
            dataStream = New AdsStream(2)
            adsClient.Read(Var, dataStream)
            Read = New AdsBinaryReader(dataStream)
            Return Read.ReadInt16
        Catch err As Exception
 
            Conectado = AdsState.ErrorConect
            Return 0
        End Try
    End Function
    Public Function txtPorNombre(ByVal Name As String)
 
        Dim dataStream As AdsStream
        Dim Read As AdsBinaryReader
        Dim txt As String
        Dim length As Integer
 
        Try
            'Recuperar Numero Var
            Dim Var As Integer
            Var = adsClient.CreateVariableHandle(Name)
 
            dataStream = New AdsStream(31)
            length = adsClient.Read(Var, dataStream)
 
 
            Read = New AdsBinaryReader(dataStream)
            'txt = Read.ReadString
            txt = New String(Read.ReadChars(length))
            'txt = txt.Substring(0, txt.IndexOf("\0"))
            Return txt
        Catch err As Exception
 
            Conectado = AdsState.ErrorConect
            Return 0
        End Try
 
    End Function
    Public Sub EscribirBoolPorNombre(ByVal Name As String, ByVal Valor As Boolean)
 
        Dim dataStream As AdsStream
        Dim Escribir As AdsBinaryWriter
 
        Try
            'Recuperar Numero Var
            Dim Var As Integer
            Var = adsClient.CreateVariableHandle(Name)
            dataStream = New AdsStream(1)
            Escribir = New AdsBinaryWriter(dataStream)
            Escribir.Write(Valor)
 
            adsClient.Write(Var, dataStream)
        Catch err As Exception
            Conectado = AdsState.ErrorConect
        End Try
    End Sub
 
    Public Sub Desconectar()
        If Conectado = AdsState.ConectadoOk Then adsClient.Dispose()
        Conectado = AdsState.Desconectado
    End Sub
    Public Function StateAds() As String
        If Conectado = AdsState.ConectadoOk Then
            Return 1
        Else
            Return 0
        End If
    End Function
#End Region
End Class

Para poder leer las variables por su nombre, lo que hacemos es recuperar el Valor que identifica esta variable. Esto lo realizamos con la siguiente función:
Var = adsClient.CreateVariableHandle(Name)
Name es el nombre de la variable. Para las variables globales las llamaremos por .NombreDeLaVariable y para el resto NombrePrograma.NombreVariable.

He creado una enumeración para definir los estados de la comunicación. Y una nueva función para recuperar texto del plc. En concreto me interesa la variable MAIN.txtAviso, esta variable nos informa del estado actual de la secuencia.

Este es el código del form principal:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
Public Class Form1
    Dim Plc1 As New ClassAds
 
 
 
    Private Sub buConectar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buConectar.Click
        Plc1.Conectar()
        Timer1.Enabled = True
    End Sub
 
    Private Sub buDesconectar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buDesconectar.Click
        If Plc1.StateAds = 1 Then Plc1.Desconectar()
 
    End Sub
 
    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Timer1.Enabled = False
 
        If Plc1.StateAds <> 1 Then
            MessageBox.Show("Error Ads")
            Exit Sub
        End If
 
        laTemp.Text = "Temperatura = " & Plc1.ValorIntPorNombre(".Temperatura") & "ºC"
        laNivelAgua.Text = "Nivel de Agua  = " & Plc1.ValorIntPorNombre(".NivelAgua")
        laEstado.Text = Plc1.txtPorNombre("MAIN.txtAviso")
 
        pbM1.Visible = Plc1.ValorIntPorNombre(".M1")
        pbBombo.Visible = pbM1.Visible
        pbM2.Visible = Plc1.ValorIntPorNombre(".M2")
        pbY1.Visible = Plc1.ValorIntPorNombre(".Y1")
        pbY2.Visible = Plc1.ValorIntPorNombre(".Y2")
 
        pbX1.Visible = Plc1.ValorIntPorNombre(".X1")
        ImgFondo(Plc1.ValorIntPorNombre(".CajonCerrado"))
 
        Timer1.Enabled = True
    End Sub
    Private Sub ImgFondo(ByVal Estado As Integer)
        If Estado Then
            pbFondo.ImageLocation = "../../Resources/LavPreparada.png"
        Else
            pbFondo.ImageLocation = "../../Resources/TodoParado.png"
        End If
    End Sub
 
    Private Sub buMarcha_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buMarcha.Click
        If Plc1.StateAds <> 1 Then Exit Sub
        Plc1.EscribirBoolPorNombre(".InicioLavado", True)
    End Sub
 
    Private Sub buCerrarCajon_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buCerrarCajon.Click
        If Plc1.StateAds <> 1 Then Exit Sub
        Plc1.EscribirBoolPorNombre(".CajonCerrado", True)
        Plc1.EscribirBoolPorNombre(".PuertaCerrada", True)
    End Sub
    Private Sub buAbrirCajon_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buAbrirCajon.Click
        If Plc1.StateAds <> 1 Then Exit Sub
        Plc1.EscribirBoolPorNombre(".CajonCerrado", False)
        Plc1.EscribirBoolPorNombre(".PuertaCerrada", False)
    End Sub
    Private Sub Form1_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
        If Plc1.StateAds = 1 Then Plc1.Desconectar()
    End Sub
End Class

Este codigo no tiene mucha historia. Se trata de establecer la conexión. Mediante un timer, leer el estado de los motores y valvulas, para mostrar o no los pictureBox. La imagen de fondo la cambiamos mediante la funcion ImgFondo, en función del estado, mostrando una u otra imagen. El resto de codigo son los eventos de los Buttons para abrir/cerrar o poner en marcha la lavadora.
Aquí, dejo tanto el programa del plc como la aplicación en vb.net. Recordaros que deberéis cambiar la dirección AMS en ClassAds. Para seguir adelante con nuestro proyecto deberemos poner en marcha el servidor web y crear las funciones (vb.net) para grabar en la base de datos.

La secuencia de la lavadora web.

He creado una secuencia en plc control para continuar con la lavadora web. En un principio pensé en hacer esta secuencia en vb.net, pero me ha parecido más interesante hacerla con plc control. Así, de paso, vemos una secuencia creada en ST (Texto Extructurado).Despues de tener la lavadora funcionando, haré la supervisión en vb.net y el guardado en MySql.

La secuencia es una versión beta que modificaremos sobre la marcha. En el siguiente paso crearé la interface en vb.net.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
VAR_GLOBAL
	Y1 AT %Q*:BOOL; (*Electroválvula cajon*)
	Y2 AT %Q*:BOOL;	(*Electroválvula Bombo*)
	M1 AT %Q*:BOOL;	(*Motor bombo*)
	M2 AT %Q*:BOOL;	(*Motor desagüe*)
	X1 AT %Q*:BOOL;	(*Bloqueo puerta*)
	Resistencia AT %Q*:BOOL;
	CajonCerrado AT %I*:BOOL;
	PuertaCerrada AT %I*:BOOL;
 
	InicioLavado:BOOL;
	Temperatura:INT;
	NivelAgua:INT;
 
END_VAR
 
PROGRAM MAIN
VAR
	stateMain:INT;
	Aviso:INT;
	txtAviso:STRING;
	PermisoCalentar: BOOL;
	Termostato: BOOL;
	Pulso1Sec: TON;
	Espera: INT;
END_VAR
 
(*LLamada a subprogramas*)
SecCalentar();
 
(*Otros*)
Pulso1Sec(IN:=NOT Pulso1Sec.Q, PT:= T#1s);
 
 
 
 
CASE stateMain OF
0:(*Comprobar condiciónes para inicio*)
	IF NOT  CajonCerrado THEN
		Aviso := 1;
		txtAviso :='Cajon sin cerrar';
	ELSE
		IF NOT PuertaCerrada THEN
			Aviso := 2; (*Puerta sin cerrar*)
			txtAviso :='Puerta sin cerrar';
		ELSE
			Aviso := 3;
			txtAviso :='Preparado para inicio';
			IF InicioLavado THEN
				stateMain:= 10;
				InicioLavado := FALSE;
			END_IF
		END_IF
	END_IF
 
10:(*Bloqueo de puerta*)
	X1 := TRUE;
	stateMain := 20;
20:(*Llenar de agua I*)
	Espera := 30;
	stateMain :=21;
	Y2:= TRUE;
21:(*Llenar de agua II*)
	IF Espera > 0 AND Pulso1Sec.Q THEN
		Espera := Espera - 1;
		Aviso := 20;
		txtAviso :='Llenado de agua';
	END_IF
	IF Espera < 1 THEN
		Espera := 0;
		stateMain := 30;
	END_IF;
30:(*Calentar agua*)
	PermisoCalentar := TRUE;
	stateMAIN := 40;
40:(*Esperar hasta conseguir temperatura*)
	IF Temperatura > 60 THEN
		stateMain:= 50;
	END_IF
	Aviso := 40;
	txtAviso :='Calentando agua';
50:(*Mover bombo con agua, esto tendrá un nombre pero...*)
	Espera := 20;
	stateMain := 51;
	M1 :=TRUE;
51:(*Continua mover bombo*)
	IF Espera > 0 AND Pulso1Sec.Q THEN
		Espera := Espera - 1;
		Aviso := 50;
		txtAviso :='Moviendo bombo';
	END_IF
	IF Espera > 1 THEN
		Espera := 0;
		stateMain := 60;
	END_IF;
60:(*Abrimos electroválvula jabon I*)
	Espera := 5;
	stateMain := 61;
	Y1 :=TRUE;
61:(*Continua mover bombo*)
	IF Espera > 0 AND Pulso1Sec.Q THEN
		Espera := Espera - 1;
		Aviso := 60;
		txtAviso :='Introducir jabon';
	END_IF
	IF Espera < 1 THEN
		Espera := 0;
		stateMain := 70;
	END_IF;
70:(*Cerramos jabon*)
	Y1:= FALSE;
	stateMain := 80;
80:(*Lavando*)
	Espera := 25;
	stateMain := 81;
81:(*Continua lavado*)
	IF Espera > 0 AND Pulso1Sec.Q THEN
		Espera := Espera - 1;
		Aviso := 60;
		txtAviso :='Lavando';
	END_IF
	IF Espera < 1 THEN
		Espera := 0;
		stateMain := 90;
	END_IF;
90:(*Extraer agua*)
	Espera := 25;
	stateMain := 91;
	M2 := TRUE;
91:(*Continua Extraer agua*)
	IF Espera > 0 AND Pulso1Sec.Q THEN
		Espera := Espera - 1;
		Aviso := 90;
		txtAviso :='Sacando agua';
	END_IF
	IF Espera < 1 THEN
		Espera := 0;
		stateMain := 100;
	END_IF;
100:(*Llenar agua  y extraer*)
	Espera := 25;
	stateMain := 101;
 
101:(*Continua llenar agua y extraer*)
	IF Espera > 0 AND Pulso1Sec.Q THEN
		Espera := Espera - 1;
		Aviso := 60;
		txtAviso :='Llenar agua y extraer';
	END_IF
	IF Espera < 1 THEN
		Espera := 0;
		stateMain := 110;
	END_IF;
110:(*Paramos agua y extraer*)
	M2:= FALSE;
	Y2:= FALSE;
	stateMain := 120;
120:(*Centrifugar, para simplificar sólo dejo el bombo en marcha un tiempo*)
	Espera := 25;
	stateMain := 121;
 
121:(*Continúa centrifugado*)
	IF Espera &gt; 0 AND Pulso1Sec.Q THEN
		Espera := Espera - 1;
		Aviso := 120;
		txtAviso :='Centrifugado';
	END_IF
	IF Espera < 1 THEN
		Espera := 0;
		stateMain := 130;
	END_IF;
130:(*Fin lavado*)
	M1:= FALSE;
	X1:= FALSE;
	Aviso :=0;
	stateMain :=0;
END_CASE
 
PROGRAM Simular
VAR
	Pulso1Sec: TON;
END_VAR
 
Pulso1Sec(IN:=NOT Pulso1Sec.Q, PT:= T#1s);
 
IF Pulso1Sec.Q AND Resistencia THEN
	Temperatura := Temperatura + 1;
END_IF
 
IF Y2 THEN
	NivelAgua := NivelAgua + 1;
END_IF;

Dentro del programa creado en ST he añadido una ACTION en LEADER. Esto nos permite hacer ciertas líneas de código en otro lenguaje por diferentes razones.

Este es el árbol del programa:

Y este el action:

La secuencia se construye con un CASE. Cuando el plc lee la instrucción CASE, lee el valor de la variable que sigue a esta palabra clave. Luego leerá sólo el código que este seguido de este valor y sólo ese hasta el siguiente ciclo de scan. 

CASE <variable> OF
<Valor>: Codigo
<Valor>: Codigo
END_CASE

En el siguiente ejemplo si Var = 1, se pone M1 a true y si Var = 2, se pone Y2 a FALSE. Esto es equivalente a hacer un SET.

CASE Var OF
1:M1:=TRUE;
2:Y2:=FALSE;
END_CASE

Otra cosa que me parece interesante es la variable txtAviso. Esta variable de tipo STRING nos informa de el estado actual de la máquina, a efecto de depuración creo que puede ser interesante.

Bueno y por el momento esto es todo, cualquier cosa un comentario. Y el programa lo dejo en la próxima entrada con la aplicación en vb.net.

Simular Modbus

Bueno, primero de todo quería pedir disculpas por dejar parado el blog. Últimamente me he metido en demasiados líos y ando con el tiempo justito, justito.

Hace poco tiempo, me vi en la necesidad de desarrollar una aplicación web, para supervisar una instalación con un autómata telemecanique. Como protocolo de comunicaciones preferí utilizar Modbus rtu. Pero tenía que terminar el proyecto en casa, y no me apetecía montar un autómata con el jaleo de cables y demás, para hacer las pruebas. Así que busque la forma de poder simular el funcionamiento y, por suerte, pronto encontré la solucción.

Utilicé un simulador de modbus libre llamado Modbus_RcSim, lo siguiente era encontrar la forma de comunicar éste con mi aplicación, para esto usé VSPE, Virtual Serial Port Emulator. Este interesante programa, nos permite realizar algunas cosas interesantes con los puertos series. En este caso, lo usé para crear dos puertos series virtuales conectados entre sí. De esta manera podía establecer una comunicación con RcSim y mi aplicación.

El resto del trabajo era poner en marcha una aplicación en Vb.net, que fuera capaz de leer modbus y servir los datos a php para hacer  la aplicación web. Para poder leer modbus utilice una libreria libre modbus llamada NModbus.

Mucho pequeño = Muy grande.

En mi humilde opinión, creo que un mundo nuevo se abre en el futuro próximo, por no decir el presente. Y la verdad, no veo movimientos en este sentido. ¿Por qué?. Bueno, bueno, me explico.

Con este blog y mis proyectos he utilizado mucho software libre, y la verdad es que he quedado  gratamente sorprendido por lo que he visto. Hay maravillas esperando a ser utilizadas. Como son el software que hace posible este blog (wordpress), bases de datos, servidores web, IDE`s, programas de retoque fotográfico, gráficos vectoriales, etc.

Y yo me pregunto, ¿Por qué no podemos hacer nosotros lo mismo?. De hecho, ya existen desarrollos en este sentido, como la librería OSCAT para plc programados con Codesys.

Recientemente, he andado programando con php para hacer aplicaciones web, para la supervisión de cámaras frigoríficas. El resultado me tiene aún alucinando, aunque quede mucho trabajo por hacer. El coste de una aplicación de este tipo permite crear sistemas de supervisión con un coste realmente asequible y con posibilidades infinitas. Sólo requiere una cosa, tiempo.

Sí, estamos de acuerdo, el tiempo vale dinero, perdón mucho dinero. Pero lo importante de todo esto, es que una vez creada una función, ésta puede ser reutilizada un número infinito de veces y mejorarla requiere poco tiempo.

Está claro que yo, como programador que hago mis propios desarrollos, no soy nada comparado con marcas como eliwell, ako, osaka (frio) o siemens, telemecanique, indusoft, etc (SCADAS). Pero sí veo que tengo un hueco en este mundo, mis proyectos salen a delante, los clientes quedan contentos, etc. El secreto es trabajar, trabajar y trabajar.
Trabajar para crear FB, por ejemplo, que convierten presión en temperatura para el 404, otra para el 134, 22, NH3,… Trabajar para crear unas funciones que permiten graficar temperatura, envío de mail y sms, recibir sms, etc. Otro programador se verá en las mismas necesidades y creará sus propias funciones, y ahí estamos trabajando, trabajando, trabajando para hacer todos lo mismo.

Sinceramente, creo que se podrían aunar esfuerzos en este sentido. No es una tarea fácil sentar las bases de una colaboración, aún no sé ni cómo se podría hacer, pero creo firmemente en esta idea.

Bueno, ¿Qué pensáis de esto?.

Lavadora web I.

Durante algunos post, realizaré un sistema de supervisión  de una lavadora. El hecho de utilizar la lavadora, es por hacer algo genérico que todos entenderemos. ¿Quién no ha puesto una lavadora? …

La idea es crear una simulación de la lavadora en vb.net, que esta aplicación guarde los estados en Mysql y más tarde generar una web de supervisión. He utilizado Inkscape para realizar las imágenes, mwsnap y beneton movie gif para realizar los gif animados. Esta es la lavadora:

La cuestión es sustituir los motores, el bombo y las válvulas por gif animados cuando estén en marcha. Además añadiremos algunos valores como: tiempo restante de funcionamiento, nivel de agua, temperatura del agua, etc. Por supuesto que mis conocimientos sobre lavadoras son meramente contemplativos, y esto es solo un ejemplo que nada tiene que ver con la realidad. Es la única lavadora web del mundo y no creo que consigamos que limpie nada.

Elementos:
Y1 es una electroválvula que permite el paso de  agua en el cajón del jabón para que se limpie.
Y2 es la electroválvula de llenado.
M1 es el motor que hace girar el bombo.
M2 es la bomba de desagüe.
X1 es un pequeño cerrojo eléctrico que bloquea la puerta.
Ademas de esto, tenemos un sensor para saber cuando el cajón del jabón está cerrado, y otro para cuando la puerta esta cerrada.

Estos son los elementos que sustituyen para dar la sensación de funcionamiento:

Fig. 1 Preparada para empezar, puerta y cajón cerrados.

Fig. 2 Bomba desagüe.

Fig. 3 Motor.

Fig. 4 Bombo con la puerta cerrada.

Fig. 5 Bloqueo puerta.

Fig. 6 Electroválvulas.

El siguiente paso es crear la aplicación en vb.net, y guardar los datos en la bd (MySql), para poder crear la aplicación en php.

Hola mundos, web.

HTML. Definición según wikipedia:

HTML, siglas de HyperText Markup Language (Lenguaje de Marcado de Hipertexto), es el lenguaje de marcado predominante para la elaboración de páginas web. Es usado para describir la estructura y el contenido en forma de texto, así como para complementar el texto con objetos tales como imágenes. HTML se escribe en forma de “etiquetas”, rodeadas por corchetes angulares (<,>). HTML también puede describir, hasta un cierto punto, la apariencia de un documento, y puede incluir un script (por ejemplo Javascript), el cual puede afectar el comportamiento de navegadores web y otros procesadores de HTML.

PHP. Definición según wikipedia:

PHP es un lenguaje de programación interpretado, diseñado originalmente para la creación de páginas web dinámicas. Es usado principalmente en interpretación del lado del servidor (server-side scripting) pero actualmente puede ser utilizado desde una interfaz de línea de comandos o en la creación de otros tipos de programas incluyendo aplicaciones con interfaz gráfica usando las bibliotecas Qt o GTK+.

Apache. Definición según wikipedia:

El servidor HTTP Apache es un servidor web HTTP de código abierto para plataformas Unix (BSD, GNU/Linux, etc.), Microsoft Windows, Macintosh y otras, que implementa el protocolo HTTP/1.11 y la noción de sitio virtual. Cuando comenzó su desarrollo en 1995 se basó inicialmente en código del popular NCSA HTTPd 1.3, pero más tarde fue reescrito por completo. Su nombre se debe a que Behelendorf quería que tuviese la connotación de algo que es firme y enérgico pero no agresivo, y la tribu Apache fue la última en rendirse al que pronto se convertiría en gobierno de EEUU, y en esos momentos la preocupación de su grupo era que llegasen las empresas y “civilizasen” el paisaje que habían creado los primeros ingenieros de internet. Además Apache consistía solamente en un conjunto de parches a aplicar al servidor de NCSA. Era, en inglés, a patchy server (un servidor “parcheado”).

El servidor Apache se desarrolla dentro del proyecto HTTP Server (httpd) de la Apache Software Foundation.

Apache presenta entre otras características altamente configurables, bases de datos de autenticación y negociado de contenido, pero fue criticado por la falta de una interfaz gráfica que ayude en su configuración.

Apache tiene amplia aceptación en la red: desde 1996, Apache, es el servidor HTTP más usado. Alcanzó su máxima cuota de mercado en 2005 siendo el servidor empleado en el 70% de los sitios web en el mundo, sin embargo ha sufrido un descenso en su cuota de mercado en los últimos años. (Estadísticas históricas y de uso diario proporcionadas por Netcraft2 ).

La mayoría de las vulnerabilidades de la seguridad descubiertas y resueltas tan sólo pueden ser aprovechadas por usuarios locales y no remotamente. Sin embargo, algunas se pueden accionar remotamente en ciertas situaciones, o explotar por los usuarios locales malévolos en las disposiciones de recibimiento compartidas que utilizan PHP como módulo de Apache

MySql. Definición según wikipedia:

MySQL es un sistema de gestión de base de datos relacional, multihilo y multiusuario con más de seis millones de instalaciones.1 MySQL AB —desde enero de 2008 una subsidiaria de Sun Microsystems y ésta a su vez de Oracle Corporationdesde abril de 2009— desarrolla MySQL como software libre en un esquema de licenciamiento dual.

Por un lado se ofrece bajo la GNU GPL para cualquier uso compatible con esta licencia, pero para aquellas empresas que quieran incorporarlo en productos privativos deben comprar a la empresa una licencia específica que les permita este uso. Está desarrollado en su mayor parte en ANSI C.

Al contrario de proyectos como Apache, donde el software es desarrollado por una comunidad pública y el copyright del código está en poder del autor individual, MySQL es patrocinado por una empresa privada, que posee el copyright de la mayor parte del código.

Esto es lo que posibilita el esquema de licenciamiento anteriormente mencionado. Además de la venta de licencias privativas, la compañía ofrece soporte y servicios. Para sus operaciones contratan trabajadores alrededor del mundo que colaboran vía Internet. MySQL AB fue fundado por David Axmark, Allan Larsson y Michael Widenius.

XAMMP. Definición según wikipedia:

XAMPP es un servidor independiente de plataforma, software libre, que consiste principalmente en la base de datos MySQL, el servidor Web Apache y los intérpretes para lenguajes de script: PHP y Perl. El nombre proviene del acrónimo de X (para cualquiera de los diferentes sistemas operativos), Apache, MySQL, PHP, Perl. El programa está liberado bajo la licencia GNU y actúa como un servidor Web libre, fácil de usar y capaz de interpretar páginas dinámicas. Actualmente XAMPP esta disponible para Microsoft Windows, GNU/Linux, Solaris, y MacOS X.

CSS. Definición según wikipedia:

Las hojas de estilo en cascada (en inglés Cascading Style Sheets), CSS es un lenguaje usado para definir la presentación de un documento estructurado escrito en HTML o XML (y por extensión en XHTML). El W3C (World Wide Web Consortium) es el encargado de formular la especificación de las hojas de estilo que servirán de estándar para los agentes de usuario o navegadores.

La idea que se encuentra detrás del desarrollo de CSS es separar la estructura de un documento de su presentación.

Por ejemplo, el elemento de HTML <h1> indica que un bloque de texto es un encabezamiento y que es más importante que un bloque etiquetado como <H2>. Versiones más antiguas de HTML permitían atributos extra dentro de la etiqueta abierta para darle formato (como el color o el tamaño de fuente). No obstante, cada etiqueta <H1> debía disponer de la información si se deseaba un diseño consistente para una página y, además, una persona que lea esa página con un navegador pierde totalmente el control sobre la visualización del texto.

Cuando se utiliza CSS, la etiqueta <H1> no debería proporcionar información sobre como va a ser visualizado, solamente marca la estructura del documento. La información de estilo separada en una hoja de estilo, especifica cómo se ha de mostrar<H1>: color, fuente, alineación del texto, tamaño y otras características no visuales como definir el volumen de un sintetizador de voz (véase Sintetización del habla), por ejemplo.

La información de estilo puede ser adjuntada tanto como un documento separado o en el mismo documento HTML. En este último caso podrían definirse estilos generales en la cabecera del documento o en cada etiqueta particular mediante el atributo “style”.

Leer el resto de esta entrada »

Analisis de circuitos II. Resistencias en estrella.

Esta es la típica conexión en estrella de resistencia. La tensión en las resistencias es Raiz(3) * V entre fases. Como es un circuito equilibrado la intensidad en el neutro es prácticamente 0.

La siguiente figura muestra el caso de desconectar una de las resistencias. Como podemos ver la intensidad en el neutro aumenta hasta la intensidad de fase.

Con el neutro cortado y solo dos resistencia, la tensión en bornas de la resistencias disminuye.

En la siguiente figura podemos ver un sistema desiquilibrado. La tensión en bornas sigue siendo RAIZ(3)* V entre fases.

El mismo circuito que el anterior con el neutro cortado. La tensión en bornas de la resistencia se eleva.

Este es un caso crítico de desequilibrio donde podríamos encontrar rotura de equipos.