Threading klappt nicht

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Kriccemis
User
Beiträge: 20
Registriert: Freitag 8. Mai 2020, 20:10

Hallo Zusammen,
ich bin gerade dabei eine kleine Anwendung mit einer automatisierten Messung zu entwicklen. manuell geht alles aber im Automodus startet das Thread nicht und ich weis nicht wo ich den Fehler mache.
Es kommt die Meldung "Type error int object is not callable.

Hier der Code:
Thread startet in Zeile 241.

Danke für eure Hilfe.

Code: Alles auswählen

# -*- coding: utf-8 -*-
"""
Created on Mon Oct  7 06:41:49 2024

@author: heewigandre
"""

import sys
import csv
import time
from threading import Thread
import serial
import serial.tools.list_ports
import pyqtgraph

from arduino import Arduino
from zumbach import Zumbach
from PyQt5 import  QtWidgets, uic

class Main(QtWidgets.QMainWindow, Arduino, Zumbach, Thread):
    "Programm zur Steuerung eines Messgerätes zur Durchmessererfassung"
    def __init__(self):
        super().__init__()
        Thread.__init__(self)
        self.ui = uic.loadUi("positionscan.ui", self)

        # Settings für das Positions-View
        self.graphicsView_durchmesser.setBackground("w")
        self.plotitem_durchmesser = self.graphicsView_durchmesser.getPlotItem()
        self.plotitem_durchmesser.setLabel("left",text="Position [mm]")
        self.plotitem_durchmesser.setLabel("bottom",text="Position [m]")
        self.plotdataitem_durchmesser_x = pyqtgraph.PlotDataItem([0],[0],pen="k")
        self.plotdataitem_durchmesser_y = pyqtgraph.PlotDataItem([0],[0],pen="r")
        self.plotitem_durchmesser.addItem(self.plotdataitem_durchmesser_x)
        self.plotitem_durchmesser.addItem(self.plotdataitem_durchmesser_y)
        self.plotitem_durchmesser.setRange(xRange=[0,300])
        self.plotitem_durchmesser.setLimits(xMin=0, xMax = 300)

        # Settings für das Dimension-View
        self.graphicsView_position.setBackground("w")
        self.plotitem_position = self.graphicsView_position.getPlotItem()
        self.plotitem_position.setLabel("left",text="Position [mm]")
        self.plotitem_position.setLabel("bottom",text="Längenposition [m]")
        self.plotdataitem_position_x = pyqtgraph.PlotDataItem([0],[0],pen="k")
        self.plotdataitem_position_y = pyqtgraph.PlotDataItem([0],[0],pen="r")
        self.plotitem_position.addItem(self.plotdataitem_position_x)
        self.plotitem_position.addItem(self.plotdataitem_position_y)
        self.plotitem_position.setRange(xRange=[0,300])
        self.plotitem_position.setLimits(xMin=0, xMax = 300)

        # Buttons
        self.pushButton_reset.clicked.connect(self.reset)
        self.pushButton_manualmode.clicked.connect(self.get_data)
        self.pushButton_automode.clicked.connect(self.auto_mode)

        # Buttons Manuelle Steuerung
        self.button_group_manuel = QtWidgets.QButtonGroup(self)
        self.button_group_manuel.addButton(self.pushButton_moveup, id=1)
        self.button_group_manuel.addButton(self.pushButton_movedown, id=2)
        self.button_group_manuel.addButton(self.pushButton_stop, id=3)
        self.button_group_manuel.buttonClicked[int].connect(self.manual_mode)

        self.horizontalScrollBar.sliderReleased.connect(self.dummy)

        self.pushButton_arduino.setStyleSheet("background-color: red")
        self.pushButton_zumbach.setStyleSheet("background-color: red")
        self.pushButton_stop.setStyleSheet("background-color: red")

        # Globale Variablen
        self.serial_connection = None
        self.arduino = None
        self.zumbach = None

        # Globale Listen zum Export der aufgenommenen Messwerte
        self.durchmesser_x = []
        self.durchmesser_y = []
        self.position_x = []
        self.position_y = []
        self.position = []
        self.export_data = []

        # Initialisierung
        self.init_arduino()
        self.init_zumbach()

    def init_arduino(self):
        "Routine zur automatischen seriellen Verbindung zum Arduino"
        # Abfrage ob sich an einem beliebigem Port ein Controller befindet
        # max_ports = 20
        # portnumber = 0
        # while True:
        #     try:
        #         self.serial_connection = serial.Serial(("COM" + str(portnumber)), 115200, timeout=None)
        #         time.sleep(1)
        #         self.serial_connection.write("asn\n".encode())
        #         snr = self.serial_connection.readline().decode().rstrip()
        #         self.serial_connection.close()
        #         snr_len = len(snr)
        #         if snr_len >= 5:
        #             break
        #     except serial.SerialException:
        #         pass
        #     portnumber = portnumber + 1
        #     # Wenn die maximale Anzahl an Ports erreicht ist wir die Schleife verlassen
        #     if portnumber > max_ports:
                # break
        # Das Gerät wird dauerhaft verbunden
        try:
            # self.arduino = serial.Serial(("COM" + str(portnumber)), 115200, timeout=None)
            self.arduino = serial.Serial("COM4", 115200, timeout=None)
            if self.arduino.isOpen():
                self.pushButton_arduino.setStyleSheet("background-color: green")
        except serial.SerialException:
            pass

    def init_zumbach(self):
        "Routine zur automatischen seriellen Verbindung zum Zumbach Odac 14xy"
        max_ports = 20
        portnumber = 0
        # while True:
        #     try:
        #         self.serial_connection = serial.Serial(("COM" + str(portnumber)), 115200, timeout=1)
        #         time.sleep(2)
        #         self.serial_connection.write("asn\n".encode())
        #         snr = self.serial_connection.readline().decode().rstrip()
        #         self.serial_connection.close()
        #         snr_len = len(snr)
        #         if snr_len >= 5:
        #             break
        #     except serial.SerialException:
        #         pass
        #     portnumber = portnumber + 1
        #     # Wenn die maximale Anzahl an Ports erreicht ist wir die Schleife verlassen
        #     if portnumber > max_ports:
        #         break
        # Das Gerät wird dauerhaft verbunden
        try:
            # self.zumbach = serial.Serial(("COM" + str(portnumber)), 115200, timeout = 1)
            self.zumbach = serial.Serial("COM5", baudrate=19200, bytesize=7, parity=serial.PARITY_EVEN, stopbits=1, timeout=None)
            if self.zumbach.isOpen():
                self.pushButton_zumbach.setStyleSheet("background-color: green")
        except serial.SerialException:
            pass

    def dummy(self):
        print("Test")

    def manual_mode(self, ID):
        "Steuert den Schrittmotor bei manueller Ansteuerung"
        # Motor dreht CW
        if ID == 1:
            self.motor_cw()
            self.pushButton_moveup.setStyleSheet("background-color: green")
            self.pushButton_movedown.setStyleSheet("background-color: lightgrey")
            self.pushButton_stop.setStyleSheet("background-color: lightgrey")

        if ID == 2:
            self.motor_ccw()
            self.pushButton_moveup.setStyleSheet("background-color: lightgrey")
            self.pushButton_movedown.setStyleSheet("background-color: green")
            self.pushButton_stop.setStyleSheet("background-color: lightgrey")

        if ID == 3:
            self.motor_stop()
            self.pushButton_moveup.setStyleSheet("background-color: lightgrey")
            self.pushButton_movedown.setStyleSheet("background-color: lightgrey")
            self.pushButton_stop.setStyleSheet("background-color: red")

    def get_data(self):
        "Holt sich die aktuellen Messwerte von den jeweiligen Geräten"
        da, dc, ec, ex = self.get_zumbach_data()
        length = self.horizontalScrollBar.value()
        self.durchmesser_x.append(da)
        self.durchmesser_y.append(dc)
        self.position_x.append(ec)
        self.position_y.append(ex)
        self.position.append(int(length))
        self.export_data.append([length, da, dc, ec, ex])
        self.plot_data(da, dc, ec, ex, length)

    def plot_data(self, da, dc, ec, ex, length):
        "Funktion die alle Werte in die entsprechenden Diagramme plottet"
        # LCD
        self.lcd_da.display(da)
        self.lcd_dc.display(dc)
        self.lcd_ec.display(ec)
        self.lcd_ex.display(ex)
        self.lcd_position.display(length)
        # Plots
        self.plotdataitem_durchmesser_x.setData(self.position, self.durchmesser_x)
        self.plotdataitem_durchmesser_y.setData(self.position, self.durchmesser_y)
        self.plotdataitem_position_x.setData(self.position, self.position_x)
        self.plotdataitem_position_y.setData(self.position, self.position_y)

    def reset(self):
        "Setzt alle Werte in der Oberfläche zurück"
        self.export()
        # LCD Anzeigen
        self.lcd_da.display(0)
        self.lcd_dc.display(0)
        self.lcd_ec.display(0)
        self.lcd_ex.display(0)
        self.lcd_position.display(0)
        self.horizontalScrollBar.setValue(0)
        self.durchmesser_x = []
        self.durchmesser_y = []
        self.position_x = []
        self.position_y = []
        self.position = []
        self.export_data = []
        self.plotdataitem_durchmesser_x.setData([0], [0])
        self.plotdataitem_durchmesser_y.setData([0], [0])
        self.plotdataitem_position_x.setData([0], [0])
        self.plotdataitem_position_y.setData([0], [0])

    def export(self):
        "Speichert alle Messwerte ab"
        result = time.localtime()
        year = result.tm_year
        month = result.tm_mon
        day = result.tm_mday
        hour = result.tm_hour
        minute = result.tm_min

        filename = f"Data\\{year}_{month}_{day}_{hour}_{minute}_export_data.csv"
        # Header definieren
        header = [["x-Position", "y-Position", "delta x", "delta y", "Position"]]
        with open(filename, "w", newline = "", encoding="utf8") as csv_file:
            # CSV Writer Objekt erstellen
            csvwriter = csv.writer(csv_file, quoting=csv.QUOTE_ALL,delimiter=';')
            # Header in CSV Schreiben
            csvwriter.writerows(header)
            # Pumpenplan in CSV Schreiben
            csvwriter.writerows(self.export_data)

    def auto_mode(self):
        "Startet das thread für die automatische Messung"
        start = 0
        step = 5
        stop = 40
        auto_thread = Autorun(start, step, stop, self.arduino, self.zumbach)
        auto_thread.start()
        auto_thread.join()
        print("start")

class Autorun(Thread, Arduino, Zumbach):
    "Funktion zur automitischen Messwerterfassung"
    def __init__(self, start, step, stop, arduino, zumbach):
        Thread.__init__(self)
        self.start = start
        self.step = step
        self.stop = stop
        self.arduino = arduino
        self.zumbach = zumbach
        self.kill = False
        self.durchmesser_x = []
        self.durchmesser_y = []
        self.position_x = []
        self.position_y = []
        self.position = []

    def run_thread(self):
        "Startet die automatische Messwertaufnahme"
        while self.start < self.stop and self.kill is True:
            self.get_data()
            self.motor_cw()
            time.sleep(2)
            self.motor_stop()
            self.start = self.start + self.step

    def get_data(self):
        "Holt sich die aktuellen Messwerte von den jeweiligen Geräten"
        da, dc, ec, ex = self.get_zumbach_data()
        # length = self.horizontalScrollBar.value()
        self.durchmesser_x.append(da)
        self.durchmesser_y.append(dc)
        self.position_x.append(ec)
        self.position_y.append(ex)
        # self.position.append(int(length))

    def stop_thread(self):
        "Stoppt die automatische Aufnahme"
        self.kill = False
        self.motor_stop()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    windows = Main()
    windows.show()
    sys.exit(app.exec_())
Sirius3
User
Beiträge: 18250
Registriert: Sonntag 21. Oktober 2012, 17:20

Bitte posten den gesamten Traceback.
Threads und GUIs darf man nicht mischen. Vor allem die Vielfachvererbung von Main ist falsch und bei Autorun zumindest sehr komisch.
Benutzeravatar
sparrow
User
Beiträge: 4525
Registriert: Freitag 17. April 2009, 10:28

@Kriccemis: Ergänzend: Bereits in einem anderen Thread hier im Forum gab es den Hinweis darauf, dass die Kommunikation mit einer GUI aus Threads heraus nicht einfach ist. Grunsätzlich solltest du dich mit dem Konzept von "Signals" in Qt auseinandersetzen. Denn das möchtest du verwenden. Deshalb wäre wohl auch QThread das Mittel der Wahl

GUI und Threads sind einzeln schon schwierige Themen. Gemeinsam sind sie komplex und man sollte schon ein grundlegendes Verständnis dafür haben, was der Eventloop ist und wie man aus Threads heraus kommuniziert.

Betreffend deiner Fehlermeldung: Da müssten jetzt alle potentiellen Helfer raten, in welcher Zeile das Problem auftritt. Hilfreich wäre, wenn du die komplette Fehlermeldung, inklusive Stacktrace/Traceback zeigst. Ansonsten kann man nur genau das sagen, was die Fehlermeldung bereits vermittelt. Ganzzahlen kann man icht aufrufen.
Antworten