0% encontró este documento útil (0 votos)
7 vistas8 páginas

Wuolah-Free-Examen Julio - 22 - 23

El documento describe un examen de Informática Industrial para estudiantes de Ingeniería en Electrónica y Automática Industrial, centrado en la programación de un sistema de control para pasteurizadores en una fábrica de alimentos. Se detallan los requisitos para la interfaz de usuario, la comunicación con autómatas programables mediante OPC UA, y la implementación de una base de datos para gestionar productos y lotes de producción. Se incluye un ejemplo de código que ilustra la creación de clases y la interacción con la interfaz gráfica.

Cargado por

Rebeca VO
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
7 vistas8 páginas

Wuolah-Free-Examen Julio - 22 - 23

El documento describe un examen de Informática Industrial para estudiantes de Ingeniería en Electrónica y Automática Industrial, centrado en la programación de un sistema de control para pasteurizadores en una fábrica de alimentos. Se detallan los requisitos para la interfaz de usuario, la comunicación con autómatas programables mediante OPC UA, y la implementación de una base de datos para gestionar productos y lotes de producción. Se incluye un ejemplo de código que ilustra la creación de clases y la interacción con la interfaz gráfica.

Cargado por

Rebeca VO
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 8

Examen Julio_22/23.

pdf

noe_sanroman

Informática Industrial

3º Grado en Ingeniería en Electrónica y Automática Industrial

Escuela de Ingeniería Industrial


Universidad de Vigo

Reservados todos los derechos.


No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-8568303

Informática Industrial - julio 2023

1) En una factoría de una empresa del sector de la


alimentación se dispone de 5 pasteurizadores, cada
uno de ellos gobernados por un autómata
programable accesible mediante un servidor OPC
UA con la configuración indicada a la derecha,
donde se muestran los tags del dispositivo
Pasteurizador1. Para los restantes dispositivos
Pasteurizador2 al Pasteurizador5 se dispone de
los mismos tags. Existe un sensor que detecta si la
puerta del pasteurizador está abierta y que podemos consultar en el tag PuertaAbierta. En la aplicación hay que
visualizar de forma simultánea a todos los pasteurizadores con imágenes pastAbierta.png o pastCerrada.png
según la puerta esté abierta o cerrada. Un operario abre la puerta y carga una cierta cantidad de alimentos en el
pasteurizador y desde la aplicación tiene que poder indicarle al autómata la temperatura de pasteurización (tag
ProgTemperatura en grados), el tiempo de pasteurización (tag ProgTiempo en segundos) y el peso de la carga (tag
Peso en Kg). En el tag Estado el autómata indica y podemos leer si el pasteurizador está descargado (valor 0, tiene
un sensor que detecta si hay alimentos en el interior), está cargado con alimentos no pasteurizados (valor 1), está
pasteurizando alimentos (valor 2) o si está cargado con alimentos y finalizó su pasteurización (valor 3). Por cada
pasteurizador hay que mostrar una lámpara con imágenes LamparaGris.png (pasteurizador no cargado),
LamparaAzul.png (cargado con alimentos no pasteurizados), LamparaAmbar.png (pasteurizando) o
LamparaVerde.png (cargado con alimentos pasteurizados). Si hay cargados alimentos no pasteurizados y la puerta
está cerrada, el operario tiene que poder indicarle al autómata que arranque su pasteurización, para ello hay que
escribir un buleano cierto en el tag Arranque. El mismo autómata pone el tag Arranque a valor falso cuando
comienza la pasteurización. En todo momento hay que mostar simultáneamente para todos los pasteurizadores: la temperatura medida
mediante un sensor (que se puede solicitar al autómata mediante el tag Temperatura), la temperatura y tiempo total programados para
la pasteurización, los Kg cargados, el tiempo transcurrido de pasteurización y el estado del pasteurizador. El programa utilizará un
objeto de la clase PasteurizadorOPC (clase que es necesario definir) por cada pasteurizador, que se encargará de la comunicación con
el autómata correspondiente. Para la comunicación OPC UA, en el programa se creará un objeto clienteOPC =
OPC_UA("opc.tcp://usuario:clave@localhost:49320"). Para la programación del manejo de la interfaz de usuario no es necesario
definir clases, se utilizará un objeto ventana = leeInterfaz("interfaz.ui") resultado de leer la interfaz de usuario generada con
Qt Designer. Define la interfaz de usuario de la aplicación y descríbela. Define el código del programa y la clase PasteurizadorOPC.
No hay que escribir instrucciones de importación de paquetes.

Una solución:

Interfaz de usuario:

lampara1

pasteurizador1

etiquetaTemperatura1
etiquetaTiempo1

editorTemperatura1
editorTiempo1
editorPeso1
botonPasteurizar1

Para el primer pasteurizador se utilizan los siguientes componentes con identificadores terminados en 1 (para los demás
pasteurizadores se utilizan componentes similares con identificadores terminados en 2, 3, 4 o 5):
- lampara1 es un QLabel donde se muestra el estado del pasteurizador en imágenes de lámparas de varios colores.
- pasteurizador1 es un QLabel donde se muestra una imagen del pasteurizador con la puerta abierta o cerrada.
- etiquetaTemperatura1 es un QLabel donde se muestra la medida de la temperatura con un sensor.
- etiquetaTiempo1 es un QLabel donde se muestra en tiempo transcurrido de pasteurización.
- editorTemperatura1, editorTiempo1 y editorPeso1 son QLineEdit donde se introducen la temperatura, tiempo y Kg de carga para
la siguiente pasteurización.
- El operario arranca una pasteurización pulsando en el botón botonPasteurizar1.

El código del programa sería:

from InformaticaIndustrial.OPCUA import OPC_UA

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-8568303

from InformaticaIndustrial.Qt import leeInterfaz


import sys
from PySide6.QtCore import QTimer
from PySide6.QtGui import QPixmap
from PySide6.QtWidgets import QApplication, QLabel, QLineEdit, QPushButton

class PasteurizadorOPC:

DESCARGADO = 0
CARGADO = 1
PASTEURIZANDO = 2

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
FINALIZADO = 3

def __init__(self, numPasteurizador, clienteOPC):


self.__numPasteurizador = numPasteurizador
self.__clienteOPC = clienteOPC
self.__tags = {}
tipos = {OPC_UA.BOOL: ["PuertaAbierta", "Arranque"],
OPC_UA.UINT16: ["Temperatura", "ProgTemperatura", "ProgTiempo", "Peso", "Estado"]}
for tipo in tipos:
for tag in tipos[tipo]:
self.__tags[tag] = "Canal.Pasteurizador" + str(numPasteurizador) + "." + tag
clienteOPC.registraTag(self.__tags[tag], tipo)
self.__progTemperatura = clienteOPC.leeTag(self.__tags["ProgTemperatura"])
self.__progTiempo = clienteOPC.leeTag(self.__tags["ProgTiempo"])
self.__peso = clienteOPC.leeTag(self.__tags["Peso"])

@property
def puertaAbierta(self):
return self.__clienteOPC.leeTag(self.__tags["PuertaAbierta"])

@property
def estado(self):
return self.__clienteOPC.leeTag(self.__tags["Estado"])

def arrancar(self):
if self.estado == PasteurizadorOPC.CARGADO:
self.__clienteOPC.escribeTag(self.__tags["Arranque"], 1)

@property
def progTemperatura(self):
return self.__progTemperatura

@progTemperatura.setter
def progTemperatura(self, temperatura):
if self.estado != PasteurizadorOPC.PASTEURIZANDO:
self.__clienteOPC.escribeTag(self.__tags["ProgTemperatura"], temperatura)
self.__progTemperatura = temperatura

@property
def progTiempo(self):
return self.__progTiempo

@progTiempo.setter
def progTiempo(self, tiempo):
if self.estado != PasteurizadorOPC.PASTEURIZANDO:
self.__clienteOPC.escribeTag(self.__tags["ProgTiempo"], tiempo)
self.__progTiempo = tiempo

@property
def temperatura(self):
return self.__clienteOPC.leeTag(self.__tags["Temperatura"])

@property
def peso(self):
return self.__peso

@peso.setter
def peso(self, kg):
self.__clienteOPC.escribeTag(self.__tags["Peso"], kg)

Abre tu Cuenta NoCuenta con el código WUOLAH10 y llévate 10 € al hacer tu primer pago
Informática Industrial
Banco de apuntes de la
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-8568303

numPasteurizadores = 5

def botonPasteurizarClick(num):
p[num]["OPC"].progTemperatura = int(p[num]["editorTemperatura"].text())
p[num]["OPC"].progTiempo = int(p[num]["editorTiempo"].text())
p[num]["OPC"].peso = int(p[num]["editorPeso"].text())
p[num]["OPC"].arrancar()

def actualizaVisualizacion():
for i in range(1, numPasteurizadores+1):
p[i]["etiquetaTemperatura"].setText(str(p[i]["OPC"].temperatura) + "ºC")
abierta = p[i]["OPC"].puertaAbierta

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
p[i]["pasteurizador"].setPixmap(imagenPasteurizador[abierta])
estado = p[i]["OPC"].estado
p[i]["lampara"].setPixmap(imagenLampara[estado])
p[i]["botonPasteurizar"].setEnabled(estado == PasteurizadorOPC.CARGADO and not abierta)
if estado == PasteurizadorOPC.PASTEURIZANDO:
p[i]["tiempo"] += 1
else:
p[i]["tiempo"] = 0
p[i]["etiquetaTiempo"].setText(str(p[i]["tiempo"]) + "s.")

try:
clienteOPC = OPC_UA("opc.tcp://Administrator:lagoasmarcosende@localhost:49320")
except Exception as e:
sys.exit()
aplicacion = QApplication()
imagenLampara = {PasteurizadorOPC.DESCARGADO: QPixmap("LamparaGris.png"),
PasteurizadorOPC.CARGADO: QPixmap("LamparaAzul.png"),
PasteurizadorOPC.PASTEURIZANDO: QPixmap("LamparaAmbar.png"),
PasteurizadorOPC.FINALIZADO: QPixmap("LamparaVerde.png")}
imagenPasteurizador = {True: QPixmap("pasteurizadorAbierto.png"),
False: QPixmap("pasteurizadorCerrado.png")}
ventana = leeInterfaz("interfaz.ui")
p = {}
for i in range(1, numPasteurizadores + 1):
si = str(i)
p[i] = {
"OPC": PasteurizadorOPC(i, clienteOPC),
"tiempo": 0,
"lampara": ventana.findChild(QLabel, "lampara" + si),
"pasteurizador": ventana.findChild(QLabel, "pasteurizador" + si),
"etiquetaTemperatura": ventana.findChild(QLabel, "etiquetaTemperatura" + si),
"etiquetaTiempo": ventana.findChild(QLabel, "etiquetaTiempo" + si),
"editorTemperatura": ventana.findChild(QLineEdit, "editorTemperatura" + si),
"editorTiempo": ventana.findChild(QLineEdit, "editorTiempo" + si),
"editorPeso": ventana.findChild(QLineEdit, "editorPeso" + si),
"botonPasteurizar": ventana.findChild(QPushButton, "botonPasteurizar" + si)
}
exec("def botonPasteurizar" + si + "Click():\n" +
" botonPasteurizarClick(" + si + ")\n")
exec("p[" + si + "][\"botonPasteurizar\"].clicked.connect(botonPasteurizar" + si + "Click)")
temporizador = QTimer()
temporizador.timeout.connect(actualizaVisualizacion)
temporizador.start(1000)
ventana.show()
sys.exit(aplicacion.exec())

2) En una instalación industrial de producción de zumos naturales (de piña, de naranja, de tomate, o mezclas como zumos de frutos
rojos, cítricos, etc) existen 5 pasteurizadores donde se tratan estos productos para eliminar patógenos y aumentar su vida útil. Cada
tipo de zumo tiene una denominación comercial y se elabora con el zumo de una o varias frutas en determinadas proporciones,
necesita una cierta temperatura y tiempo de pasteurización y el producto es apto para el consumo durante una cierta cantidad de días
una vez pasteurizado. Estos productos se manejan en contenedores metálicos, cada uno de una cierta capacidad máxima. Cada
contenedor tiene un código numérico diferente escrito en un código de barras y una vez utilizado para tratar una cierta cantidad de un
producto fabricado en un lote de producción, se lava y esteriliza y se reutiliza para tratar una cierta cantidad de producto del mismo
lote o de otro. Los lotes de producción tienen un identificador (ej. A273), una fecha de creación, una fecha de caducidad y en él se
fabrica una cierta cantidad total de un determinado producto. Diseña y describe una base de datos donde se puedan indicar los tipos de
productos con sus datos y composición, los lotes de producción con sus datos, donde se pueda indicar el estado actual de los
contenedores y donde se registren las pasteurizaciones ejecutadas, cada una realizada dentro de un lote de producción, en un
pasteurizador en un instante determinado. Programa una clase de forma que con un objeto se pueda:

Abre tu Cuenta NoCuenta con el código WUOLAH10 y llévate 10 € al hacer tu primer pago
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-8568303

- comprobar si las composiciones de los productos son correctas, ya que los porcentajes de fruta tienen que sumar 100, y de forma que
se pueda obtener en una colección qué productos y composiciones (con sus datos) son incorrectas.
- reservar un contenedor para tratar una cierta cantidad del producto fabricado en un lote de producción, o liberarlo para poder
reutilizarlo, generando una excepción cuando se detecte algún error, como indicar un contenedor o lote no registrados previamente
en la base de datos, intentar reservar un contenedor que ya está reservado o liberar un contenedor que ya está vacío, reservar una
cantidad de producto para un contenedor mayor que la capacidad total del contenedor, o reservar una cierta cantidad de producto de
un lote para un contenedor con la que se supera la cantidad total de producto que hay que tratar en ese lote.
No hay que indicar instrucciones de importación de paquetes. Se utilizará un objeto para la comunicación con el servidor MySql
obtenido mediante conexionMySql = mysql.connector.connect(user='usuario', password='clave', host='127.0.0.1',
database='db').

Una solución:

La base de datos consta de las siguientes tablas:


- productos: cada registro corresponde a un tipo de producto, al que se le asigna un id como clave principal, nombre es su
denominación comercial, con temperatura y tiempo se describen los parámetros del pasteurizado y en caducidad se indican los
días de vida útil del producto una vez pasteurizado.
- composiciones: para indicar que una fruta se va a utiliza en un porcentaje para la fabricación del producto indicado en
idProducto, estableciendo una relación uno-varios con la tabla productos.
- lotes: cada registro corresponde a un lote indicado en el campo lote, clave principal. cantidad indica la cantidad total a pasteurizar
y en procesado la cantidad que ya se ha pasteurizado. El lote tiene una fecha de creacion y una fecha de caducidad.
- contenedores: cada registro corresponde a un contenedor disponible, cada uno tiene un identificador numérico indicado en el
campo id, clave principal. Para cada contenedor se indica su capacidad máxima. Cuando contiene una cierta cantidad de un zumo
que se va a procesar para un lote, esa información se indica en los campos cantidad e idLote, si no, estos campos contienen NULL.
- pasteurizaciones: cada registro indica una pasteurización de una cierta cantidad de zumo de un lote indicado por idLote,
realizada en el instante cuando en la máquina pasteurizador.

import sys
import mysql.connector

class Produccion:

def __init__(self, conexion):


self.__conexion = conexion
self.__cursor = conexion.cursor()

def compruebaComposiciones(self):
comprobacion = {}
self.__cursor.execute("SELECT id, nombre FROM productos")
resultadosProductos = self.__cursor.fetchall()
for (id, nombre) in resultadosProductos:
self.__cursor.execute("SELECT fruta, porcentaje FROM composiciones WHERE idProducto=" + str(id))
resultadosComposicion = self.__cursor.fetchall()
total = 0
for (fruta, porcentaje) in resultadosComposicion:
total += porcentaje

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-8568303

if total != 100:
porcentajes = []
for (fruta, porcentaje) in resultadosComposicion:
porcentajes.append((fruta, porcentaje))
comprobacion[nombre] = porcentajes
return comprobacion

def reservaContenedor(self, contenedor, lote, cantidad):


self.__cursor.execute("SELECT idLote, capacidad FROM contenedores WHERE id=" + str(contenedor))
resultado = self.__cursor.fetchone()
if resultado is None:
raise Exception("Error reservando contenedor: no existe el contenedor " + str(contenedor))

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
(loteActual, capacidadContenedor) = resultado
if loteActual is None:
if cantidad > capacidadContenedor:
raise Exception("Error reservando contenedor " + str(contenedor) + ": se está reservando " +
str(cantidad) + " y su capacidad es " + str(capacidadContenedor))
self.__cursor.execute("SELECT cantidad, procesado FROM lotes WHERE lote='" + lote + "'")
(cantidadLote, procesadoLote) = self.__cursor.fetchone()
if cantidad > cantidadLote - procesadoLote:
raise Exception("Error reservando contenedor " + str(contenedor) + ": se esstá reservando " +
str(cantidad) + " y en el lote " + lote + " falta por procesar " +
str(cantidadLote - procesadoLote))
self.__cursor.execute("UPDATE contenedores SET idLote='" + lote + "', cantidad=" + str(cantidad) +
" WHERE id=" + str(contenedor))
self.__cursor.execute("UPDATE lotes SET procesado=" + str(procesadoLote + cantidad) +
" WHERE lote='" + lote + "'")
self.__conexion.commit()
else:
raise Exception("Error reservando contenedor: el contenedor " + str(contenedor) + " no está vacío")

def liberaContenedor(self, contenedor):


self.__cursor.execute("SELECT idLote FROM contenedores WHERE id=" + str(contenedor))
resultado = self.__cursor.fetchone()
if resultado is None:
raise Exception("Error liberando contenedor: no existe el contenedor " + str(contenedor))
loteActual = resultado[0]
if loteActual is None:
raise Exception("Error liberando contenedor: el contenedor " + str(contenedor) + " está vacío")
else:
self.__cursor.execute("UPDATE contenedores SET idLote=NULL, cantidad=NULL WHERE id=" +
str(contenedor))
self.__conexion.commit()

try:
conexionMySql = mysql.connector.connect(user='root', password='marcosende', host='127.0.0.1',
database='ej2')
except Exception as ex:
print(ex)
sys.exit()
produccion = Produccion(conexionMySql)
errores = produccion.compruebaComposiciones()
try:
produccion.reservaContenedor(12, "A1", 100)
produccion.liberaContenedor(12)
except Exception as e:
print(e)
conexionMySql.close()

Abre tu Cuenta NoCuenta con el código WUOLAH10 y llévate 10 € al hacer tu primer pago

También podría gustarte