This commit is contained in:
matteo porta 2022-07-20 19:29:11 +02:00
commit ef0b6cda54
15 changed files with 167 additions and 121 deletions

View File

@ -9,9 +9,9 @@ exposure_time: 10000
; vertical_crop_resolution: 2048 ; vertical_crop_resolution: 2048
; rotate_90_clockwise times: 0 ; rotate_90_clockwise times: 0
; auto_white_balance: off ; auto_white_balance: off
; balance_red: 1.0 balance_red: 1.66
; balance_green: 1.0 balance_green: 1.0
; balance_blue: 1.0 balance_blue: 1.12
[vision_saver] [vision_saver]
time_format: %Y-%m-%d_%H-%M-%S time_format: %Y-%m-%d_%H-%M-%S
@ -43,5 +43,7 @@ port: COM1
baudrate: 9600 baudrate: 9600
[vision] [vision]
detection_threshold: 0.3 detection_threshold: 0.5
neural_network: hs3-20000
; recipes_path: ./config/vision_test_recipes ; recipes_path: ./config/vision_test_recipes

View File

@ -1,15 +1,10 @@
item { item {
id: 1 id: 1
name: 'hs-ok' name: 'hs-ok'
color: '0x00ff00' color: '0x000000'
} }
item { item {
id: 2 id: 2
name: 'hs-ko' name: 'hs-ko'
color: '0xff0000' color: '0xff0000'
} }
item {
id: 3
name: 'hs-empty'
color: '0x0000ff'
}

View File

@ -1,8 +1,8 @@
# LIEBHER RUBBER FLANGE # LIEBHER RUBBER FLANGE
[general] [general]
name: RICETTA 1 name: TERMORESTRINGENTE
instruction: APPORRE I SEGNI CON IL PENNARELLO COME INDICATO IN FIGURA instruction: CONTROLLARE PRESENZA TERMORESTRINGENTE
# POINTS FORMAT: # POINTS FORMAT:
# point_name: point_center point_size fill_color border_color border_thickness shape # point_name: point_center point_size fill_color border_color border_thickness shape
@ -20,15 +20,9 @@ instruction: APPORRE I SEGNI CON IL PENNARELLO COME INDICATO IN FIGURA
# name: X,Y S 0xAARRGGBB 0xAARRGGBB T TEXT # name: X,Y S 0xAARRGGBB 0xAARRGGBB T TEXT
[markers] [markers]
cross: 1100,1100 100,100 0x000000ff 0xff0000ff 25 cross
center: 1100,1100 2050,2050 0x0000ff00 0xff0000ff 50 ellipse
[zones] [zones]
p1: 610,550 200 hs-ok # TOP LEFT WHITE POINT p1: 800,850 300,100 hs-ok # HEATSINK PRESENT
p2: 1790,1290 200 hs-ok # RIGHT SIDE WHITE POINT
p3: 350,1190 200 hs-ok # LEFT SIDE BLUE POINT
[labels] [labels]
p1: 510,825 100 0xffffffff 0xff000000 10 BIANCO p1: 500,600 120 0xffffffff 0xff000000 4 TERMORESTRINGENTE
p2: 1690,1565 100 0xffffffff 0xff000000 10 BIANCO
p3: 250,1465 100 0xff0000ff 0xff000000 10 BLU

View File

@ -1,34 +0,0 @@
# LIEBHER RUBBER FLANGE
[general]
name: RICETTA 2
instruction: APPORRE I SEGNI CON IL PENNARELLO COME INDICATO IN FIGURA
# POINTS FORMAT:
# point_name: point_center point_size fill_color border_color border_thickness shape
# EXAMPLE:
# name: X,Y W,H 0xAARRGGBB 0xAARRGGBB T SHAPE CLASS
# ZONES FORMAT:
# region_name: region_center region_margin class
# margin can be a box (XM*2,YM*2) or a radius (R)
# EXAMPLES:
# name: X,Y XM,YM T SHAPE CLASS
# name: X,Y R T SHAPE CLASS
# LABELS FORMAT:
# label_name: label_start_location font_size fill_color border_color border_thickness text
# EXAMPLE:
# name: X,Y S 0xAARRGGBB 0xAARRGGBB T TEXT
[markers]
cross: 1100,1100 100,100 0x000000ff 0xff0000ff 25 cross
center: 1100,1100 2050,2050 0x0000ff00 0xff0000ff 50 ellipse
[zones]
p1: 610,550 200 hs-ok # TOP LEFT WHITE POINT
p2: 1790,1290 200 hs-ok # RIGHT SIDE WHITE POINT
p3: 350,1190 200 hs-ok # LEFT SIDE BLUE POINT
[labels]
p1: 510,825 100 0xffffffff 0xff000000 10 BIANCO
p2: 1690,1565 100 0xffffffff 0xff000000 10 BIANCO
p3: 250,1465 100 0xff0000ff 0xff000000 10 BLU

4
designer.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
cd "$(dirname "$0")"
source "./venv/bin/activate" || source "./venv/Scripts/activate" || :
"$(python3 -c "import sys; print(sys.path[-1])")/qt5_applications/Qt/bin/designer"

View File

@ -1,2 +0,0 @@
#!/bin/bash -e
./simulate.sh --diagnostic $*

View File

@ -13,12 +13,17 @@ export QT_NO_INFO_OUTPUT=1
export QT_NO_WARNING_OUTPUT=0 export QT_NO_WARNING_OUTPUT=0
# export QT_QPA_PLATFORM=${XDG_SESSION_TYPE} # export QT_QPA_PLATFORM=${XDG_SESSION_TYPE}
python -B -u "./src/main.py" \ python -B -u "./src/main.py" \
--auto-accept-test-admin-permission \
--auto-login-admin \ --auto-login-admin \
--auto-select \ --auto-select \
--debugger-workaround \
--no-edgetpu \ --no-edgetpu \
--no-gpu \ --no-gpu \
--panel \ --panel \
--sim-camera \
--sim-modbus \
--sim-os-label-printer \ --sim-os-label-printer \
--sim-serial \
--style windows \ --style windows \
$* 2> >(sed $'s/.*/\e[31m&\e[m/' >&2) # & $* 2> >(sed $'s/.*/\e[31m&\e[m/' >&2) # &
# --about \ # --about \
@ -34,9 +39,6 @@ $* 2> >(sed $'s/.*/\e[31m&\e[m/' >&2) # &
# --no-tflite \ # --no-tflite \
# --recipes-management \ # --recipes-management \
# --sim-archiver \ # --sim-archiver \
# --sim-camera \
# --sim-modbus \
# --sim-serial \
# --sim-vision \ # --sim-vision \
# --steps-management \ # --steps-management \
# --users-management \ # --users-management \

View File

@ -122,6 +122,7 @@ class GalaxyCamera(Component):
img_path = next(self.sim_imgs) img_path = next(self.sim_imgs)
self.log.debug(f"loading image {img_path}") self.log.debug(f"loading image {img_path}")
frame = cv2.cvtColor(cv2.imread(str(img_path)), cv2.COLOR_BGR2RGB) frame = cv2.cvtColor(cv2.imread(str(img_path)), cv2.COLOR_BGR2RGB)
QThread.msleep(1000)
else: else:
self.camera.TriggerSoftware.send_command() self.camera.TriggerSoftware.send_command()
frame = self.camera.data_stream[0].get_image() frame = self.camera.data_stream[0].get_image()

View File

@ -0,0 +1,33 @@
import sys
if "--sim-multimeter" in sys.argv:
from components.dummies.serial import serial
else:
import serial
from PyQt5.QtWidgets import QMessageBox
from .component import Component
class SerialMultimeter(Component):
def __init__(self, config=None, name=None):
super().__init__(config=config, name=name, threaded=False)
def write(self, command):
try:
conn = serial.Serial(
self.address,
baudrate=self.baudrate,
stopbits=self.stopbits,
parity=self.parity,
bytesize=self.bytesize,
)
conn.write(bytes(command, encoding="ascii"))
conn.close()
except serial.serialutil.SerialException as e:
QMessageBox.critical(
None,
"Errore Connessione Multimetro",
"Non e stato possibile connettersi al multimetro digitale.\n Verificare che lo strumento sia acceso e collegato\nErrore: " + str(e)
)

View File

@ -11,6 +11,7 @@ from PyQt5.QtCore import (QFileSystemWatcher, QLineF, QMutex, QPointF, QRectF,
Qt, QThread, pyqtSignal) Qt, QThread, pyqtSignal)
from PyQt5.QtGui import (QBrush, QColor, QFont, QImage, QPainter, QPainterPath, from PyQt5.QtGui import (QBrush, QColor, QFont, QImage, QPainter, QPainterPath,
QPen, QPixmap) QPen, QPixmap)
from PyQt5.QtWidgets import QApplication
from .component import Component from .component import Component
from .consumer import Consumer from .consumer import Consumer
@ -70,6 +71,10 @@ class Vision(Component):
self.vision_consumer.moveToThread(self.vision_consumer_thread) self.vision_consumer.moveToThread(self.vision_consumer_thread)
self.vision_consumer_thread.started.connect(self.vision_consumer.start) self.vision_consumer_thread.started.connect(self.vision_consumer.start)
self.vision_consumer_thread.start() self.vision_consumer_thread.start()
if "--debugger-workaround" in sys.argv:
QApplication.processEvents()
QThread.msleep(1000)
QApplication.processEvents()
self.vision_consumer.wait_ready() self.vision_consumer.wait_ready()
# RENDER THREAD # RENDER THREAD
self.render_consumer = Consumer(work=self.render_consumer_work, work_fifo=True, drop_fifo=True, work_maxlen=1, name="render_consumer", paused=False) self.render_consumer = Consumer(work=self.render_consumer_work, work_fifo=True, drop_fifo=True, work_maxlen=1, name="render_consumer", paused=False)
@ -78,6 +83,10 @@ class Vision(Component):
self.render_consumer.moveToThread(self.render_consumer_thread) self.render_consumer.moveToThread(self.render_consumer_thread)
self.render_consumer_thread.started.connect(self.render_consumer.start) self.render_consumer_thread.started.connect(self.render_consumer.start)
self.render_consumer_thread.start() self.render_consumer_thread.start()
if "--debugger-workaround" in sys.argv:
QApplication.processEvents()
QThread.msleep(1000)
QApplication.processEvents()
self.render_consumer.wait_ready() self.render_consumer.wait_ready()
# CONNECT CONSUMERS # CONNECT CONSUMERS
self.vision_consumer.out.connect(self.process_vision_consumed) self.vision_consumer.out.connect(self.process_vision_consumed)
@ -275,6 +284,8 @@ class Vision(Component):
"none", "none",
]: ]:
model_name = sorted([d for d in os.listdir(self.models_dir) if os.path.isdir(self.models_dir / d)], reverse=True)[0] model_name = sorted([d for d in os.listdir(self.models_dir) if os.path.isdir(self.models_dir / d)], reverse=True)[0]
else:
model_name = model
self.log.info(f"loading neural network: {model_name!r}") self.log.info(f"loading neural network: {model_name!r}")
self.loading_model_signal.emit({"status": "loading"}) self.loading_model_signal.emit({"status": "loading"})
self.lock.lock() self.lock.lock()
@ -433,6 +444,7 @@ class Vision(Component):
min_distance = sys.maxsize min_distance = sys.maxsize
closest_zone = None closest_zone = None
for zone_name, zone in self.zones.items(): for zone_name, zone in self.zones.items():
distance = self.get_distance(detection["center"], zone["center"])
if zone["shape"] == "rect": if zone["shape"] == "rect":
if self.zone_detection_filter_mode == "center_inside": if self.zone_detection_filter_mode == "center_inside":
outside_zone = any([ outside_zone = any([
@ -458,13 +470,14 @@ class Vision(Component):
else: else:
raise NotImplementedError(f"invalid zone_detection_filter_mode: {self.zone_detection_filter_mode!r}") raise NotImplementedError(f"invalid zone_detection_filter_mode: {self.zone_detection_filter_mode!r}")
elif zone["shape"] == "ellipse": # it's a circle elif zone["shape"] == "ellipse": # it's a circle
distance = self.get_distance(detection["center"], zone["center"])
if self.zone_detection_filter_mode == "center_inside": if self.zone_detection_filter_mode == "center_inside":
outside_zone = distance > zone["size"][0] / 2 outside_zone = distance > zone["size"][0] / 2
elif self.zone_detection_filter_mode == "box_inside": elif self.zone_detection_filter_mode == "box_inside":
outside_zone = distance + max(detection["size"]) / 2 > zone["size"][0] / 2 outside_zone = distance + max(detection["size"]) / 2 > zone["size"][0] / 2
elif self.zone_detection_filter_mode == "box_touches": elif self.zone_detection_filter_mode == "box_touches":
outside_zone = distance - max(detection["size"]) / 2 > zone["size"][0] / 2 outside_zone = distance - max(detection["size"]) / 2 > zone["size"][0] / 2
else:
raise NotImplementedError(f"invalid zone_detection_filter_mode: {self.zone_detection_filter_mode!r}")
else: else:
raise NotImplementedError(f"invalid zone shape: {zone['shape']!r}") raise NotImplementedError(f"invalid zone shape: {zone['shape']!r}")
if not outside_zone and distance < min_distance: if not outside_zone and distance < min_distance:

View File

@ -101,6 +101,10 @@ try:
component = self.components[component_name] component = self.components[component_name]
thread.started.connect(component.start) thread.started.connect(component.start)
thread.start() thread.start()
if "--debugger-workaround" in sys.argv:
QApplication.processEvents()
QThread.msleep(1000)
QApplication.processEvents()
if component_name == "vision": if component_name == "vision":
component.wait_ready(timeout=60) component.wait_ready(timeout=60)
else: else:

29
src/test/multicomp.py Normal file
View File

@ -0,0 +1,29 @@
import time
import serial
conn = serial.Serial(
"/dev/ttyUSB0",
baudrate=115200,
stopbits=serial.STOPBITS_ONE,
parity=serial.PARITY_NONE,
bytesize=serial.EIGHTBITS,
timeout=1
)
cmd_list = (("*IDN?\n", True), # QUERY ID
("CONF:RES 500\n", False), # SET RESISTANCE MEASURE, 500 Ohm range
("MEAS?\n", True), # GET MEASURE
("MEAS?\n", True), # GET MEASURE
("MEAS?\n", True)) # GET MEASURE
for cmditem in cmd_list:
cmd, expect_response = cmditem
conn.write(bytes(cmd, encoding="ascii"))
if expect_response:
response = conn.readline()
print(f"{cmd} RESPONSE: " + response.decode("ascii"))
else:
print(f"{cmd}")
time.sleep(1)
conn.close()

View File

@ -20,7 +20,7 @@ class Test_Admin_Permission(Widget):
self.continue_b.clicked.connect(self.verify) self.continue_b.clicked.connect(self.verify)
self.cancel_b.clicked.connect(self.cancel) self.cancel_b.clicked.connect(self.cancel)
# TESTING # TESTING
if "--test" in sys.argv: if "--auto-accept-test-admin-permission" in sys.argv or "--test" in sys.argv:
self.password_le.setText("123123") self.password_le.setText("123123")
self.test_timer = QTimer() self.test_timer = QTimer()
self.test_timer.setSingleShot(True) self.test_timer.setSingleShot(True)

View File

@ -1,57 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"> <ui version="4.0">
<class>Admin permission</class> <class>Admin permission</class>
<widget class="QWidget" name="Admin permission"> <widget class="QWidget" name="Admin permission">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>422</width> <width>422</width>
<height>139</height> <height>139</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Admin permission</string> <string>Admin permission</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="6" column="1"> <item row="6" column="1">
<widget class="QPushButton" name="cancel_b"> <widget class="QPushButton" name="cancel_b">
<property name="text"> <property name="text">
<string>Annulla</string> <string>Annulla</string>
</property> </property>
</widget>
</item>
<item row="6" column="0">
<widget class="QPushButton" name="continue_b">
<property name="text">
<string>Continua</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLineEdit" name="password_le">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
<property name="placeholderText">
<string>password</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="info_l">
<property name="text">
<string>-</string>
</property>
</widget>
</item>
</layout>
</widget> </widget>
<tabstops> </item>
<tabstop>password_le</tabstop> <item row="6" column="0">
<tabstop>continue_b</tabstop> <widget class="QPushButton" name="continue_b">
<tabstop>cancel_b</tabstop> <property name="text">
</tabstops> <string>Continua</string>
<resources/> </property>
<connections/> <property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLineEdit" name="password_le">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
<property name="placeholderText">
<string>password</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="info_l">
<property name="text">
<string>-</string>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>password_le</tabstop>
<tabstop>continue_b</tabstop>
<tabstop>cancel_b</tabstop>
</tabstops>
<resources/>
<connections/>
</ui> </ui>

View File

@ -86,10 +86,12 @@ class Test_Test(Widget):
data = self.last if self.last is not None else {} data = self.last if self.last is not None else {}
else: else:
data = data[-data_usable.index(True) - 1] data = data[-data_usable.index(True) - 1]
if not override: if fail:
result_ok = data.get("results", {}).get("ok", None) result_ok = False
else: elif override:
result_ok = True result_ok = True
else:
result_ok = data.get("results", {}).get("ok", None)
self.last = { self.last = {
**data, **data,
"overridden": override, "overridden": override,
@ -100,11 +102,10 @@ class Test_Test(Widget):
self.ok_counter = 0 self.ok_counter = 0
elif override: elif override:
self.ok_counter = self.ok_counter_limit self.ok_counter = self.ok_counter_limit
elif result_ok is True:
self.ok_counter += 1
else: else:
if result_ok is True: self.ok_counter = 0
self.ok_counter += 1
else:
self.ok_counter = 0
# check if completed # check if completed
if fail: if fail:
self.stop() self.stop()
@ -166,6 +167,7 @@ class Test_Test(Widget):
d.setCentralWidget(Test_Admin_Permission(info)) d.setCentralWidget(Test_Admin_Permission(info))
d.setModal(True) d.setModal(True)
d.show() d.show()
d.centralWidget.password_le.setFocus()
r = d.exec() r = d.exec()
if r == d.Accepted: if r == d.Accepted:
self.admin_challenged = True self.admin_challenged = True