Commit 48ed1371 authored by Pedro Henrique Kopper's avatar Pedro Henrique Kopper

Remodelar a aplicação para torná-la ainda mais genérica

parent e54d68f9
Pipeline #30 failed with stages
......@@ -12,3 +12,4 @@ pyserial = "*"
pyqt5 = "*"
pyyaml = "*"
protobuf = "*"
sacada-python = "*"
# Este arquivo define a interface a ser utilizada
device:
type: mock
location: "/dev/ttyUSB0"
type: sacada
location: "/dev/ttyACM0"
channels:
- id: 0
name: "Tensão"
- id: "A0"
name: "Canal A0"
color: "#FF0000"
unit: "mV"
- id: 1
name: "Corrente"
unit: "V"
- id: "TC"
name: "Temperatura"
color: "#0000FF"
unit: "mA"
unit: "ºC"
tc: 25
type: "R"
from time import sleep
from datetime import datetime
from time import sleep, time
from serial import Serial
class Arduino(object):
def __init__(self, logger, location, channels):
logger("[ARDUINO]", "Opening serial port...")
try:
self.ser = Serial(location, 115200)
self.ser = Serial(location, 115200, timeout=0.1)
except Exception as e:
logger("[ARDUINO]", "ERROR: Could not open serial port")
raise FileNotFoundError("Serial port not found") from e
logger("[ARDUINO]", "Starting board...")
self._reset() # Reset do arduino para reinicio da leitura
self.ser.readline() # Espera o Arduino inicializar
self.ser.write(bytes("press",'utf-8'))
self.ser.readline()
#self._reset() # Reset do arduino para reinicio da leitura
#self.ser.readline() # Espera o Arduino inicializar
#self.ser.write(bytes("press",'utf-8'))
#self.ser.readline()
logger("[ARDUINO]", "Board started, good luck!")
today = datetime.now().strftime("%Y-%m-%d-%H:%M:%S")
self.logFile = open("/home/phckopper/logs/{}-calib.csv".format(today), "w")
self.logFile.write("Tempo (Unix), Calibrante (V), Pressão (bar)\n")
def read(self):
pass
def readAll(self):
print("Reading:")
self.ser.flushInput() # Limpeza do buffer de entrada
data = self.ser.readline().split(bytes(" ", "utf-8")) # Leitura de todos os valores em uma linha
return [int(x) for x in data]
val = []
self.ser.write(bytes(":MEAS:VOLT:DC? A0\r\n", "utf-8")) # Trigga leitura
reading = self.ser.readline().strip()
print(reading)
val.append(float(reading))
self.ser.write(bytes(":MEAS:VOLT:DC? A3\r\n", "utf-8")) # Trigga leitura
reading = self.ser.readline().strip()
print(reading)
val.append(float(reading) * (250.0/10.0))
self.logFile.write("{},{},{}\n".format(time(), val[0], val[1]))
self.logFile.flush()
#data = self.ser.readline().split(bytes(" ", "utf-8")) # Leitura de todos os valores em uma linha
#return [int(x) for x in data]
return val
def _reset(self):
self.ser.setDTR(False)
sleep(0.05)
self.ser.setDTR(True)
\ No newline at end of file
self.ser.setDTR(True)
......@@ -4,7 +4,11 @@ class Mock(object):
def __init__(self, logger, location, channels):
self.channels = len(channels)
logger("[MOCK]", "Generating fake data...")
self.reading = 10
def read(self, channel):
return random() * 20
self.reading += (random() - 0.5)
return self.reading
def readAll(self):
return [self.read(0) for i in range(self.channels)]
\ No newline at end of file
return [self.read(0) for i in range(self.channels)]
from random import random
from sacada import SACADA as _SACADA
class SACADA(object):
def __init__(self, logger, location, channels):
self.channels = channels
self.s = _SACADA(location)
logger("[SACADA]", "Opening SACADA at {}".format(location))
logger("[SACADA]", str(self.s.identify()))
logger("[SACADA]", "Valor do zero: {}".format(self.s.zero()))
def read(self, channel):
if channel["id"] == "TC":
return self.s.readTemperature(channel["tc"], channel["type"])
return self.s.readVoltage(channel["id"])
def readAll(self):
return [self.read("TC")]
# Comente fora as interfaces não utilizadas para reduzir o tamanho do programa
from interfaces.Mock import *
from interfaces.Arduino import *
from interfaces.InstrumentInterface import *
from .Mock import *
from .SACADA import *
from .Arduino import *
from .InstrumentInterface import *
INTERFACES = {
'mock': Mock,
'sacada': SACADA,
'arduino': Arduino,
'instrument-interface': InstrumentInterface,
}
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Generico</class>
<widget class="QMainWindow" name="Generico">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1366</width>
<height>823</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>SADAMAP - Análise de Dados: Etapa 1 - Calibração de Pressão</string>
</property>
<property name="styleSheet">
<string notr="true">background-color:rgb(250, 250, 250);
</string>
</property>
<widget class="QWidget" name="centralWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">QGroupBox::title {
top: 4px;
left: 4px;
}
QGroupBox {
border-radius: 4px;
background-color: rgb(240, 240, 240);
font-weight: bold;
}</string>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout_2" rowstretch="3,1,2,0" columnstretch="1,1,1,4,0">
<item row="0" column="0" rowspan="3" colspan="5">
<widget class="GraphicsLayoutWidget" name="mainGraph">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">border: 2px solid rgb(10, 10, 10);
</string>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>
<item row="3" column="3" colspan="2">
<widget class="QScrollArea" name="scrollArea">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>false</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>930</width>
<height>200</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="1">
<widget class="QLabel" name="consoleView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="styleSheet">
<string notr="true">padding: 2px;
border: 2px solid rgb(5, 5, 5);
font: 10pt &quot;Liberation Mono&quot;;</string>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item row="3" column="2">
<widget class="QGroupBox" name="samplingBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">border: 2px solid rgb(255, 75, 0);
</string>
</property>
<property name="title">
<string>Amostragem</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QComboBox" name="samplingCBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<item>
<property name="text">
<string>100 mseg</string>
</property>
</item>
<item>
<property name="text">
<string>200 mseg</string>
</property>
</item>
<item>
<property name="text">
<string>500 mseg</string>
</property>
</item>
<item>
<property name="text">
<string>1 seg</string>
</property>
</item>
<item>
<property name="text">
<string>1.5 seg</string>
</property>
</item>
<item>
<property name="text">
<string>2 seg</string>
</property>
</item>
<item>
<property name="text">
<string>2.5 seg</string>
</property>
</item>
<item>
<property name="text">
<string>5 seg</string>
</property>
</item>
<item>
<property name="text">
<string>10 seg</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QGroupBox" name="absValGBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">border: 2px solid rgb(26, 149, 172);
</string>
</property>
<property name="title">
<string>Valores Absolutos</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
<property name="topMargin">
<number>40</number>
</property>
<item>
<widget class="QGroupBox" name="calibratorGBox">
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="title">
<string>Tensão no Calibrante</string>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignRight|Qt::AlignTrailing</set>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item alignment="Qt::AlignRight">
<widget class="QLabel" name="calibratorLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>0 mV</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="forceGBox">
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="title">
<string>Força</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0">
<item alignment="Qt::AlignRight">
<widget class="QLabel" name="forceLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>0 Tonf</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1366</width>
<height>20</height>
</rect>
</property>
<widget class="QMenu" name="fileMenu">
<property name="title">
<string>Arquivo</string>
</property>
<addaction name="openButton"/>
<addaction name="saveButton"/>
<addaction name="saveAsButton"/>
</widget>
<widget class="QMenu" name="stageMenu">
<property name="title">
<string>Etapa</string>
</property>
<addaction name="alternaCalibraP"/>
<addaction name="alternaCalibraT"/>
<addaction name="alternaProc"/>
</widget>
<widget class="QMenu" name="serialMenu">
<property name="title">
<string>Porta</string>
</property>
</widget>
<widget class="QMenu" name="playPauseButton">
<property name="title">
<string>Iniciar/Pausar</string>
</property>
</widget>
<widget class="QMenu" name="finalizeButton">
<property name="title">
<string>Finalizar</string>
</property>
</widget>
<addaction name="fileMenu"/>
<addaction name="stageMenu"/>
<addaction name="serialMenu"/>
<addaction name="playPauseButton"/>
<addaction name="finalizeButton"/>
</widget>
<widget class="QStatusBar" name="menuStatusBar"/>
<action name="alternaCalibraP">
<property name="text">
<string>Calibração P</string>
</property>
</action>
<action name="alternaCalibraT">
<property name="text">
<string>Calibração T</string>
</property>
</action>
<action name="alternaProc">
<property name="text">
<string>Processamento</string>
</property>
</action>
<action name="openButton">
<property name="text">
<string>Abrir</string>
</property>
<property name="iconVisibleInMenu">
<bool>true</bool>
</property>
</action>
<action name="actionSalvar">
<property name="text">
<string>Salvar</string>
</property>
</action>
<action name="actionSalvar_Como">
<property name="text">
<string>Salvar Como</string>
</property>
</action>
<action name="saveButton">
<property name="text">
<string>Salvar</string>
</property>
</action>
<action name="saveAsButton">
<property name="text">
<string>Salvar Como</string>
</property>
</action>
<action name="selectPortaUSB">
<property name="text">
<string>Selecionar porta USB</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>GraphicsLayoutWidget</class>
<extends>QGraphicsView</extends>
<header>pyqtgraph</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
......@@ -5,40 +5,42 @@ from interfaces import *
from config import Config
class Graph(QThread):
def __init__(self, graph, interval, logger, parent=None):
def __init__(self, ui, interval, logger, parent=None):
super(Graph, self).__init__(parent)
self.running = True
self.logger = logger
self.interval = interval/1000.0
self.dataX = []
self.dataY = []
self.graph = graph
self.ui = ui
self.graph = ui.mainGraph
self.plots = []
self.axis = []
self.config = Config().data
self.device = self.config["device"]
self._configurePlots()
device = self.config["device"]
try:
self.interface = INTERFACES[device["type"]](logger, device["location"], device["channels"])
self.interface = INTERFACES[self.device["type"]](logger, self.device["location"], self.device["channels"])
except FileNotFoundError:
self.running = False
graph.setBackground((240, 240, 240))
self.graph.setBackground((240, 240, 240))
def run(self):
while self.running:
data = self.interface.readAll()
self.graph.getPlotItem().getViewBox().setRange(xRange=(self.dataX[0][-1] - 10, self.dataX[0][-1])) # Força atualização do range do x com span de 5 segundos
for i, channel in enumerate(self.plots):
self.dataX[i].append(self.dataX[i][-1] + self.interval)
self.dataY[i].append(data[i])
channel.setData(self.dataX[i], self.dataY[i])
sleep(self.interval)
while True:
if self.running:
for i, channel in enumerate(self.device["channels"]):
self.dataX[i].append(self.dataX[i][-1] + self.interval)
self.dataY[i].append(self.interface.read(self.device["channels"][i]))
self.plots[i].setData(self.dataX[i], self.dataY[i])
sleep(self.interval)
def setInterval(self, interval):
self.interval = interval/1000.0
def restart(self):
self.running = True
def stop(self):
self.running = False
......@@ -47,24 +49,18 @@ class Graph(QThread):
self.graph.getPlotItem().addItem(marker)
def _configurePlots(self):
first = True
pltItem = self.graph.getPlotItem()
pltItem.setClipToView(True)
pltItem.showGrid(True)
pltItem.addLegend()
pltItem.getViewBox().enableAutoRange()
pltItem.getViewBox().setAutoPan(x=True)
self.logger("[GRAPH]", "Found new device {}".format(self.config["device"]["type"]))
for channel in self.config["device"]["channels"]:
self.logger("[GRAPH]", "Added channel {}".format(channel["name"]))
for channel in self.device["channels"]:
plotItem = self.graph.addPlot()
plot = plotItem.plot(pen=mkPen(mkColor(channel["color"]), width=3), name=channel["id"])
self.plots.append(plot)
plotItem.setClipToView(True)
plotItem.showGrid(True)
plotItem.getViewBox().enableAutoRange()
plotItem.getViewBox().setAutoPan(x=True)
self.dataX.append([0])
self.dataY.append([0])
plot = self.graph.plot(pen=mkPen(mkColor(channel["color"]), width=2), name=channel["name"])
self.plots.append(plot)
if first:
pltItem.setLabel("left", text=channel["name"], units=channel["unit"])
first = False
else:
pltItem.setLabel("right", text=channel["name"], units=channel["unit"])
pltItem.setLabel("bottom", text="Tempo", units="s")
plotItem.setLabel("left", text=channel["name"], units=channel["unit"])
self.logger("[GRAPH]", "Added channel {}".format(channel["name"]))
......@@ -12,7 +12,7 @@ class MainThread(QThread):
super(MainThread, self).__init__(parent)
self.ui = ui
self.data = []
self.graph = Graph(self.ui.mainGraph, 100, self._log)
self.graph = Graph(self.ui, 100, self._log)
self.upTimer = Timer()
self.downTimer = Timer(delay=10)
try:
......@@ -26,27 +26,39 @@ class MainThread(QThread):
#self.ui.stopTimerButton.pressed.connect(self._stopTimer)
#self.ui.startRegTimerButton.pressed.connect(self._startTimer)
#self.ui.stopRegTimerButton.pressed.connect(self._stopTimer)
self.ui.playPauseButton.aboutToShow.connect(self._playPause)
self.ui.finalizeButton.aboutToShow.connect(self._finalize)
self.graph.start()
while True:
self._updateTimers()
sleep(1/30.0) # Updates at 30FPS
def _updateSamplingRate(self):
MAP = [100, 200, 500, 1000, 1500, 2000, 2500, 5000, 10000]
self._log("[DEBUG]", self.ui.samplingCBox.currentText())
self.graph.setInterval(MAP[self.ui.samplingCBox.currentIndex()])
def _fatal(self, msg):
error = QMessageBox()
error.setText(msg)
error.setWindowTitle("Erro")
error.exec()
exit(-1)
def _log(self, tag, msg):
self.ui.consoleView.setText("{} {}\n{}".format(tag, msg, self.ui.consoleView.text()))
def _playPause(self):
if self.graph.running:
self.graph.stop()
else:
self.graph.restart()
def _finalize(self):
pass
def _updateTimers(self):
if self.upTimer.active:
self.upTimer.update()
......@@ -55,7 +67,7 @@ class MainThread(QThread):
#self.ui.currentTimeLabel.setText(datetime.now().strftime("%H:%M:%S"))
#self.ui.timerLabel.setText(self.upTimer.getTimeString())