"""Modul zum Steuern und Auslesen des Nivellierungssensors.
Das Modul bltouch.py verwendet die **pigpio** Bibliothek zur Generierung eines
PWM Signals, über welches sich die Sonde des Nivellierungssensors BLTouch
steuern lässt. Außerdem wird die Bibliothek **RPi.GPIO** verwendet, mit welcher
sich Pin-Interrupts erzeugen lassen.
"""
import RPi.GPIO as GPIO
import pigpio
import time
import numpy
[Doku]class Touchsensor():
[Doku] def __init__(self, grundeinstellungen):
"""Wird aufgerufen wenn ein Touchsensor-Objekt erzeugt wird.
Grundeinstellungen wie Pin-Konfiguration, Timingeinstellungen oder
PWM-Parameter werden ausgelesen und in lokale Variabeln gespeichert.
Args:
grundeinstellungen (dict): Aus dem Config-File eingelesene
Grundeinstellungen des Roboters.
"""
# Profil Array deklarieren
self.profil = []
# Z-Abstastung
self.z_offset = 0
# Flag
self.beruehrt = False
# Pinkonfiguration
self.pwm_pin = int(grundeinstellungen['gpio_bltouch_pwm'])
self.interrupt_pin = int(grundeinstellungen['gpio_bltouch_endschalter'])
# PWM Frequenz
self.pwm_frequenz = int(grundeinstellungen['bl_pwm_frequenz'])
# Stösselpsotionsmaxima
self.obere_position = int(grundeinstellungen['bl_obere_position'])
self.untere_position = int(grundeinstellungen['bl_untere_position'])
# Pulsweite für Selbsttest
self.selbsttest = int(grundeinstellungen['bl_selbsttest'])
# Anzahl der Wiederholungen auf einem X Punkt
self.wiederholungen = int(grundeinstellungen['bl_wiederholungen'])
# Sicherheitsfaktor damit Sonde nicht ins Leere fährt
self.sicherheitsfaktor = float(
grundeinstellungen['bl_sicherheitsfaktor'])
# Profilsamples
self.samples_pro_punkt = int(
grundeinstellungen['bl_samples_pro_punkt'])
# Z-Abstand zu Optik welche nach dem Abtasten eines Punktes
# angefahren wird
self.z_abtasthub = float(grundeinstellungen['bl_z_abtasthub'])
# Initialisierung
self.pwm = pigpio.pi()
self.pwm.set_mode(self.pwm_pin, pigpio.OUTPUT)
self.pwm.set_PWM_frequency(self.pwm_pin, self.pwm_frequenz)
[Doku] def interrupt_routine(self, dummyvariable):
"""Die ISR (Interrupt Service Routine) wird aufgerufen sobald ein
Interrupt am GPIO0 auftritt.
Note:
Ein Interrupt wird bei steigender Flanke (RISING) getriggert.
Die Dummyvariable darf nicht gelöscht werden, sonst funktionieren
die Interrupts nicht!
Args:
dummyvariable (-): Kein Verwendung, dient nur als Dummy
"""
print("Interrupt ausgelöst.")
# Sonde hochziehen
self.sonde_heben()
# Flag auf berührt setzten
self.beruehrt = True
return
[Doku] def z_einzel_abtastung(self, grbl):
"""Taset die Oberfläche einer Optik einmalig ab.
Diese Methode wird aufgerufen, wenn der Z-Offset (Abstand zwischen Optik
und Nivellierungssensor) erfasst werden soll.
Note:
Mittels Abtastung des Z-Offset, lässt sich der Reinigungsablauf
beschleunigen, da das CNC-Positionierungssystem den Kopf im Eilgang
absenkt und sich erst kurz vor Berührung an die Oberfläche
herantastet.
Args:
grbl (object): Objekt zur Kommunikation mit dem CNC-Controller.
"""
print("Z-Tastwert wird aufgenommen ...")
# Z-Offset setzen (optional), normalerweise 0, kenn bei Bedarf geändert
# in negative Richtung geändert werden.
z_aktuell = 0
# Kurz warten
time.sleep(1)
# Stoessl senken
self.sonde_senken()
# Den Reinigungskopf senken, solange die Oberfläche nichtg berührt wird.
while not self.beruehrt:
z_aktuell -= 0.01
cmd = "G01 Z" + str(z_aktuell) + " F1500"
grbl.gcode_senden(cmd)
time.sleep(0.015)
# Z-Position erfassen
self.z_offset = float(grbl.z_position)
time.sleep(1)
# Flag zurücksetzten
self.beruehrt = False
[Doku] def profil_aufzeichnen(self, grbl, samples, radius, fortschritt_signal):
"""Zeichnet ein Profil durch Abtastung von mindestens 3 Punkten der
Optikoberfläche auf.
Args:
grbl (object): Objekt zur Kommunikation mit dem CNC-Controller.
samples (int): Anzahl der abzutastenden Punkte.
radius (float): Radius der Linse in mm
(nicht der Oberflächenradius!).
fortschritt_signal (signal): Signal vom Typ *(float)*.
Dient zur Aktualisierung des Ladebalkens.
Returns:
list: Gibt eine Liste mit Koordinatenpaaren [X:Z] *(str)* zurück.
"""
# Mögliche alte Profildaten vor der Neuaufnahme löschen
profil = []
# Fortschittsvariable initialisieren
fortschritt = 0
print("Profil wird aufgezeichnet ...")
# Auflösung berechnen
aufloesung = (radius - self.sicherheitsfaktor) / (samples - 1)
print("Abtastauflösung beträgt", aufloesung, "mm abgetastet.")
print("Abtasthub beträgt", self.z_abtasthub, "mm.")
print("Zeichne mit", self.samples_pro_punkt,
"Samples pro Punkt auf ...")
for i in range(samples):
print("Koordinate", i + 1, "von", samples, "wird aufgenommen.")
# Punktliste wieder leeren
punkt = []
# Mehrere Wiederholungen pro Punkt und den Mittelwert nehmen
for j in range(self.samples_pro_punkt):
time.sleep(2)
# Aktuelle Position abfragen
x_aktuell = float(grbl.x_position)
z_aktuell = float(grbl.z_position)
# Sonde senken
self.sonde_senken()
# Warten
time.sleep(2)
while not self.beruehrt:
z_aktuell -= 0.01
cmd = "G01 Z" + str(z_aktuell) + " F1500"
grbl.gcode_senden(cmd)
time.sleep(0.02)
# X- und Z-position auslesen und speichern
x_pos = grbl.x_position
z_pos = grbl.z_position
punkt.append(float(z_pos))
time.sleep(2)
# Z-Schlitten hochfahren
z_aktuell += self.z_abtasthub
cmd = "G01 Z" + str(z_aktuell) + " F1500"
grbl.gcode_senden(cmd)
self.beruehrt = False
# Debug Ausgabe
print("Datenpunkte:", punkt)
median_z_pos = numpy.median(punkt)
print("Median des Abtastpunktes: ", str(median_z_pos))
# Koordinaten dem Oberflächenprofil anhängen
profil.append(str(x_pos) + ":" + str(median_z_pos))
# X-Schlitten zur nächsten Abtastposition verschieben
x_aktuell -= aufloesung
cmd = "G01 X" + str(x_aktuell) + " F500"
grbl.gcode_senden(cmd)
time.sleep(1)
# Fortschrittsbalken aktualisieren
fortschritt += 100 / samples
fortschritt_signal.emit(fortschritt)
# Auf sichere Z-position fahren
cmd = "G01 Z0 F1000"
grbl.gcode_senden(cmd)
print("Profil erfolgreich aufgezeichnet.")
return profil
[Doku] def touchsensor_initialisieren(self):
"""Initialsiert den Nivellierungssensor indem ein Selbsttest
durchgeführt wird.
Die Mehtode initialisert außerdem die Interrupt-Funktion am Pin GPIO0.
Note:
Beim Selbsttest wird die Sonde des Sensors 10x gehoben und wieder
gesenkt.
Returns:
list: Gibt eine Liste mit Koordinatenpaaren [X:Z] *(str)* zurück.
"""
print("Initialisierung des Touchsensors...")
# Sonde hochziehen
self.sonde_heben()
# Selbsttest durchführen
self.selbst_test()
# Interrupts aktivieren
GPIO.setmode(GPIO.BCM)
GPIO.setup(self.interrupt_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(
self.interrupt_pin, GPIO.RISING, callback=self.interrupt_routine,
bouncetime=200)
[Doku] def sonde_stellen(self, pulsweite):
"""Erzeugt das PWM Signal am Pin GPIO24 des Raspberry PI.
Note:
GPIO-Pin ist in den Grundeinstellungen unter ``gpio_bltouch_pwm``
zu finden.
Args:
pulsweite (int): Pulsweite des PWM-Signales in :math:`{\\mu s}`
"""
# PWM Signal generieren
self.pwm.set_servo_pulsewidth(self.pwm_pin, pulsweite)
[Doku] def sonde_senken(self):
"""Fährt die Sonde des Nivellierungssensors aus.
Note:
Pulsweite für die untere Position, lässt sich in den
Grundeinstellungen unter ``bl_untere_position`` ändern.
Args:
pulsweite (int): Pulsweite des PWM-Signales in :math:`{\\mu s}`
"""
print("Sonde wird ausgefahren.")
self.sonde_stellen(self.untere_position)
[Doku] def sonde_heben(self):
"""Fährt die Sonde des Nivellierungssensors ein.
Note:
Pulsweite für die obere Position, lässt sich in den
Grundeinstellungen unter ``bl_obere_position`` ändern.
Args:
pulsweite (int): Pulsweite des PWM-Signales in :math:`{\\mu s}`
"""
print("Sonde wird eingefahren.")
self.sonde_stellen(self.obere_position)
[Doku] def selbst_test(self):
"""Führt einen Selbsttest des Sensors durch.
Note:
Pulsweite für den Selbsttest lässt sich in den Grundeinstellungen
unter ``bl_selbsttest`` ändern.
"""
print("Touchsensor Selbsttest wird durchgeführt.")
self.sonde_stellen(self.selbsttest)