Quellcode für controller

"""Das Modul regelt die serielle Kommunikation mit dem CNC-Controller. 

"""

import hilfsfunktionen
import serial
import time
import threading


[Doku]class Controller:
[Doku] def __init__(self, grundeinstellungen): """Der Konstruktor wird aufgerufen, wenn ein Controller-Objekt erzeugt wird und speichert unter Anderem Grundeinstellungen wie Verbindungsparameter und Korrekturfaktoren in lokale Variablen. In ihm wird auserdem die Methode *verbindung_initialisieren()* aufgerufen, welche den Handshake mit dem Controller durchführt. Args: grundeinstellungen (dict): Aus dem Config-File eingelesene Grundeinstellungen des Roboters. """ # Threading Lock Objekt erzeugen self.codelock = threading.Lock() # Grundeinstellungen einlesen self.basiseinstellungen = grundeinstellungen # Verbindungseinstellungen self.schnittstelle = grundeinstellungen['usb_interface'] self.baudrate = int(grundeinstellungen['usb_baudrate']) self.timeout = int(grundeinstellungen['usb_timeout']) # Drehzahlkorrektur self.steigung = grundeinstellungen['spindeldrehzahl_steigung'] self.offset = grundeinstellungen['spindeldrehzahl_offset'] # Serielle Verbindung instanziieren self.serielle_verbindung = serial.Serial( self.schnittstelle, self.baudrate, timeout=self.timeout) # Verbindung zum Controller checken self.verbindung_initialisieren() # Variableninitialisierung self.x_position = 0 self.y_position = 0 self.z_position = 0 self.cmd = "" self.controller_status = "" self.antwort = ""
# Einen Befehl an den CNC-Controller senden
[Doku] def gcode_senden(self, cmd): """Übernimmt einen G-CODE und sendet diesen über eine serielle Verbindung (USB) an den CNC-Controller. Examples: Beispiel für einen G-CODE: ``G01 X120.5 Y20 Z-3.25 F950`` Note: Um einen Mehrfachzugriff (durch Threads) auf die Serielle- Schnittstelle zu vermeiden, wird der entsprechende Codeteil mit ``lock.aquire()`` gesperrt und mit ``release()`` wieder freigegeben. Args: cmd (str): Enthält den zu sendenden G-CODE. Returns: antwort (str): Gibt die Antwort des Controllers zurück. """ try: # Programmabschnitt für andere Threads sperren um Mehrfachzugriff # auf die serielle Schnittstelle zu verhindern self.codelock.acquire() # Empfangsbuffer leeren self.serielle_verbindung.flushInput() # Carriage Return und Linefeed anhängen, damit der Controller das # Ende des Befehls erkennt cmd += '\n\r' # Befehlsstring binär codieren cmd = cmd.encode() # Daten senden self.serielle_verbindung.write(cmd) # Kurz warten bevor die Antwort gelesen wird time.sleep(0.01) # Abfragen wieviel Bytes zu erwarten sind bytesleft = self.serielle_verbindung.inWaiting() antwort = "" if self.serielle_verbindung.inWaiting() > 0: antwort = self.serielle_verbindung.read(bytesleft) # print(antwort) # Programmabschnitt für andere Threads wieder freigeben self.codelock.release() # Antwort des Controllers zurückgeben return antwort except: print("Fehler beim Senden/Empfangen über die serielle Verbindung!") antwort = "Error" return antwort
[Doku] def verbindung_initialisieren(self): """Führt den Handshake mit dem CNC-Controller durch. Note: Ein erfolgreicher Aufbau wir vom Controller mit der Zeichenkette ``Grbl 1.1f [$ for help]`` beantwortet. """ print("Initialisiere Verbindung zum Controller ...") # Auf Anfrage des Controllers warten init_string = self.serielle_verbindung.readline() if b'\r\n' in init_string: init_string = self.serielle_verbindung.readline() # Nach spezieller Init-Zeichenkette suchen if b'Grbl 1.1f [\'$\' for help]\r\n' in init_string: print("Verbindung erfolgreich aufgebaut.") else: print("Verbindung zu Controller NICHT erfolgreich.") else: print("Verbindung zu Controller NICHT erfolgreich.#2")
[Doku] def geraete_status(self): """Fragt den aktuellen Maschinenstatus ab und speichert die Ergenisse in lokale Variablen. Der Gerätestatus kann ``Idle``, ``Run``, ``Alarm`` usw. annehmen. Die aktuelle Position wird als X-, Y-, und Z-Koordinate gespeichert. """ # Statusabfrage starten status_string = self.gcode_senden("?") if len(status_string) >= 39: # Gerätestatus aus Statusstring extrahieren self.controller_status = hilfsfunktionen.status_extrahieren( status_string) # Koordinaten aus Statusstring extrahieren koordinaten = hilfsfunktionen.koordinaten_extrahieren(status_string) # Aktuelle Koordinaten des Gerätes speichern self.x_position = koordinaten[0] self.y_position = koordinaten[1] self.z_position = koordinaten[2]
[Doku] def controller_initialisieren(self): """Führt eine Refernzfahrt durch und legt den Nullpunkt des Koordinatensystems fest. Note: Der Befehl ``$H`` fährt die Schlitten zum Endtaster der jeweiligen Achse. """ self.gcode_senden("$H") self.gcode_senden("G92 X0 Y0 Z0")
# while not self.controller_status == "Idle": # self.geraete_status(lock) # print (self.controller_status) # time.sleep(0.1) # pass
[Doku] def geraet_halten(self): """Pausiert die aktuelle Fahrt, indem alle Schrittmotoren gestoppt werden. Beim Pausieren gehen keine Schritte verloren. Note: Drehteller dreht sich auch beim Pausieren weiter. """ self.gcode_senden("!")
[Doku] def geraet_fortsetzen(self): """Setzt die Fahrt fort, indem alle Schrittmotoren wieder aktiviert werden. Note: Es wird das Zeichen ``~`` an den Controller gesendet. """ self.gcode_senden("~")
[Doku] def geraet_entsperren(self): """Hebt den Alarmstatus auf. Note: Es wird das Zeichenkette ``$X`` an den Controller gesendet. """ self.gcode_senden("$X")
[Doku] def geraet_softreset(self): """Führt einen Software-Reset des CNC-Controllers durch. Note: Es wird ``CTRL+X`` an den Controller gesendet, welches im Oktalformat ``\030`` entspricht. """ self.gcode_senden("\030")
[Doku] def drehteller_einschalten(self, drehzahl): """Schaltet den Drehteller durch Aktivierung des DC-Getriebemoters ein. Note: Vor dem Senden an den CNC-Controller wird die Drehzahl korrigiert, damit eingestellte und tatsächliche Drehzahl übereinstimmen. Das ist Aufgrund der Untersetzungen und dem nicht-sauberen PWM-Signal des CNC-Controllers notwendig. Args: drehzahl (int): Gewünschte Drehzahl in 1/min. """ # Drehzahl korrigieren korrigierte_drehzahl = hilfsfunktionen.drehzahlkorrektur( drehzahl, self.steigung, self.offset) print("Korrigierte Drehzahl: ", korrigierte_drehzahl, " 1/min") # An den Controller senden cmd = "M03 S" + str(korrigierte_drehzahl) self.gcode_senden(cmd)
[Doku] def drehteller_ausschalten(self): """Stoppt den Drehteller. """ self.gcode_senden("M05")
[Doku] def reinigungsposition_anfahren(self): """Fährt die Reingung-Startsposition lt. Grundeinstellungen an. Wird vor der Reinigung angefahren. Das Polyester-Pad befindet sich in dieser Position zentral über der Optik. Note: X-, Y- und Z-Position lassen sich in den Grundeinstellungen unter den Attributen ``reinigungs_start_position_x`` , ``reinigungs_start_position_y`` und ``reinigungs_start_position_z`` ändern. """ x_pos = float(self.basiseinstellungen['reinigungs_start_position_x']) y_pos = float(self.basiseinstellungen['reinigungs_start_position_y']) z_pos = float(self.basiseinstellungen['reinigungs_start_position_z']) xy_start = "G00 X" + str(x_pos) + " Y" + str( y_pos) + " Z" + str(z_pos) + " F1500" self.gcode_senden(xy_start)
# Warten bis Endposition erreich ist # while not ((self.x_position == x_pos) and (self.y_position == y_pos) # and (self.z_position == z_pos)): # pass
[Doku] def beladeposition_anfahren(self): """Fährt die Beladeposition lt. Grundeinstellungen an. Wird vor der Reinigung angefahren, damit die Optik eingelegt werden kann. Note: X-, Y- und Z-Position lassen sich in den Grundeinstellungen unter den Attributen ``belade_position_x`` , ``belade_position_y`` und ``belade_position_z`` ändern. """ x_pos = float(self.basiseinstellungen['belade_position_x']) y_pos = float(self.basiseinstellungen['belade_position_y']) z_pos = float(self.basiseinstellungen['belade_position_z']) xy_belade = "G00 X" + str(x_pos) + " Y" + str( y_pos) + " Z" + str(z_pos) + " F1500" self.gcode_senden(xy_belade)
[Doku] def abtastposition_anfahren(self): """Fährt die Abtast-Startsposition lt. Grundeinstellungen an. Wird benötigt, wenn ein Oberflächenprofil abgetatet wird. Die Sonde des Nivellierungssensors befindet sich in dieser Position zentral über der Optik. Note: X-, Y- und Z-Position lassen sich in den Grundeinstellungen unter den Attributen ``babtast_start_position_x`` , ``abtast_start_position_y`` und ``abtast_start_position_z`` ändern. """ x_pos = float(self.basiseinstellungen['abtast_start_position_x']) y_pos = float(self.basiseinstellungen['abtast_start_position_y']) z_pos = float(self.basiseinstellungen['abtast_start_position_z']) xyz_profilposition = "G00 X" + str(x_pos) + " Y" + str( y_pos) + " Z" + str(z_pos) + " F1500" self.gcode_senden(xyz_profilposition)