Herzlich willkommen zu meinem neuesten Blogbeitrag, in dem es um das Mapping von Sensorwerten mit MicroPython geht! Heute werde ich euch eine Funktion vorstellen und erklären, mit der ihr einen Messbereich von einem Sensor auf einen anderen umwandeln könnt. Diese Funktion ist besonders nützlich beim Visualisieren von Umweltsensoren und anderen Messwerten. Ich werde euch Schritt für Schritt durch den Prozess führen und euch zeigen, wie ihr diese Funktion unter Verwendung von MicroPython in euren Projekten nutzen könnt.
Wie man Sensorwerte am Mikrocontroller Calliope Mini im Open Roberta Lab mappt habe ich dir bereits im Beitrag Open Roberta Lab – analoges Signal auf PWM mappen erläutert. Hier greife ich auf die gesammelte Erkenntnis zurück und schreibe den Code für MicroPython um.
Wozu benötigen wir das Mapping von Sensorwerten in MicroPython?
Nehmen wir an du hast einen Temperatursensor welcher einen Messbereich von 0 °C bis 125 °C hat und eine LED Balkenanzeige mit 24 Segmenten. Dann könntest du nun den Messbereich des Sensors (0-125) auf die 24 LEDs mappen und somit je nach Temperatur die LEDs aktivieren.
Ein anderer Fall wäre ein Servomotor mit einem maximalen Winkel von 180° welchen du mit einem analogen Sensor (Drehpotentiometer, Joystick etc.) bewegen möchtest. Dann musst du in diesem Fall den Drehbereich des Servos 0° bis 180° auf die möglichen analogen Werte 0 bis, 65535 mappen.
Ein kleiner Aufbau mit dem Raspberry Pi Pico
Damit wir unsere Funktion testen können, benötigen wir einen Mikrocontroller, auf welchen MicroPython läuft. Hier kann man sich selber einen ESP32 flashen oder man verwendet einen Raspberry Pi Pico / Pico W welcher das ganze schon von hause aus kann.
Ich möchte das zuletzt genannte Beispiel aufgreifen und einen Servomotor mit einem Drehpotentiometer steuern. Ein recht kleines Projekt, welches jedoch sehr gut verdeutlicht, wie die Funktion map welche wir schreiben, möchten funktioniert.
Was benötigen wir für den Aufbau der Schaltung?
Für den Nachbau der Schaltung benötigst du:
- einen Raspberry Pi Pico / Pico W,
- ein Micro-USB Datenkabel,
- einen Servomotor SG90,
- einen Drehpotentiometer,
- sechs Breadboardkabel,
- ein 400 Pin Breadboard
Pinout des Raspberry Pi Pico
Für die Unterstützung beim Aufbau der Schaltung gebe ich dir hier noch das Pinout des Raspberry Pi Pico an die Hand.
Programmieren der Funktion map in MicroPython zum Erzeugen eines Mapping von Sensorwerten
In der Arduino IDE gibt es bereits die Funktion map welche genau das macht, was wir hier nachbauen möchten.
Die Parameter sind:
- value – der Wert, welcher verarbeitet werden soll,
- fromLow – die untere Grenze des aktuellen Bereichs des Werts,
- fromHigh – die obere Grenze des aktuellen Bereichs des Wertes,
- toLow – die untere Grenze des Zielbereichs für den Wert,
- toHigh – die obere Grenze des Zielbereichs des Wertes
Dieses übernehmen wir für die neue Funktion.
def map(value, fromLow, fromHigh, toLow, toHigh): return round((value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow)
Hier ist eine schrittweise Erklärung der Funktionsweise:
(value - fromLow)
: Dieser Ausdruck berechnet die Differenz zwischen dem Eingabewert und dem unteren Grenzwert des Eingabebereichs (fromLow
). Dieser Schritt normalisiert den Eingabewert auf den Bereich von 0 bis (fromHigh
–fromLow
).(toHigh - toLow)
: Dieser Ausdruck gibt die Größe des Ausgabebereichs an, also die Differenz zwischen dem oberen und unteren Grenzwert des Ausgabebereichs. Dieser Schritt bestimmt die Skalierung des transformierten Werts.(fromHigh - fromLow)
: Dieser Ausdruck gibt die Größe des Eingabebereichs an, also die Differenz zwischen dem oberen und unteren Grenzwert des Eingabebereichs. Dieser Schritt bestimmt die relative Position des Eingabewerts innerhalb des Eingabebereichs.((value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow)
: Dieser Ausdruck führt die eigentliche Transformation durch. Zuerst wird der normalisierte Eingabewert mit der Skalierung des Ausgabebereichs multipliziert, um den transformierten Wert zu erhalten. Dann wird der untere Grenzwert des Ausgabebereichs (toLow
) zum Ergebnis addiert, um den endgültigen transformierten Wert zu erhalten.round(...)
: Die Funktionround()
rundet den transformierten Wert auf die nächstgelegene ganze Zahl.
Steuern eines Servomotors mit einem Drehpotentiometer in MicroPython
Hier nun das kleine Programm, um mit einem Drehpotentiometer einen Servomotor zu steuern.
#import des Moduls um #den analogen Pin auszulesen #und den Servo per PWM zu steuern from machine import ADC, Pin, PWM #import des Moduls um eine #kleine Pause im Code einzulegen from time import sleep #wir benutzen in der Schaltung #den ADC0 Pin / GP26 für den Drehpotentiometer adc = ADC(Pin(26)) #der Servomotor ist am GP15 angeschlossen pwm = PWM(Pin(15)) pwm.freq(50) #untere & obere Grenze des Servomotors servoMin = 100 servoMax = 8000 #untere & obere Grenze des Drehpotentiometers drehpotiMin = 224 drehpotiMax = 65535 # Funktion zum setzen eines Winkels # als Parameter wird die Position erwartet def setServoCycle(position): pwm.duty_u16(position) sleep(0.01) #Funktion zum mappen eines Wertes mit einer oberen und unteren Grenze def map(value, fromLow, fromHigh, toLow, toHigh): return round((value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow) #starten der Endlosschleife while True: #auslesen des Wertes vom Drehpotentiometer value = adc.read_u16() #ermitteln der Servoposition servoPosition = map(value, drehpotiMin, drehpotiMax, servoMin, servoMax) #zuweisen der Servoposition setServoCycle(servoPosition) #eine kleine Pause von 125 Millisekunden sleep(0.125)
Im Video erkennst du, dass der Servo sich je nach Position des Drehpotentiometers bewegt. Ein Problem ist jedoch, dass der analoge Wert nicht konstant gleich ist, d.h. wenn du den Drehpotentiometer nicht bewegst, dass der Servo trotzdem zuckt.
Ermitteln der Grenzen des Sensors & Aktors
Hier jetzt der vollständigkeitshalber die beiden Programme um die untere & obere Grenze des Drehpotentiometers & des Servomotors zu ermitteln.
Die Werte des Servomotors habe ich selbst durch Trial-and-Error ermittelt, diese können je nach Modell variieren.
Auslesen des Drehpotentiometers am Raspberry Pi Pico
Zunächst einmal lesen wir den Drehpotentiometer aus, um die untere und obere Grenze zu ermitteln.
#import des Moduls um #den analogen Pin auszulesen from machine import ADC, Pin #import des Moduls um eine #kleine Pause im Code einzulegen from time import sleep #wir benutzen in der Schaltung #den ADC0 Pin / GP26 adc = ADC(Pin(26)) #starten der Endlosschleife while True: #auslesen des Wertes value = adc.read_u16() #ausgeben des Wertes print("Drehpotentiometer Wert: "+ str(value)) #eine kleine Pause von 125 Millisekunden sleep(0.125)
Mit dem Code habe ich jetzt ermittelt das die untere Grenze 224 und die obere Grenze 65535 ist.
Steuern des Servomotors per PWM Signal
Im Beitrag Raspberry PI Pico #3 – PWM Signale erzeugen habe ich dir bereits gezeigt, wie man einen Servomotor vom Typ SG90 per PWM Signal steuern kann. Mit dem nachfolgenden Code können wir diesen jetzt von 0° bis 180° drehen.
from time import sleep from machine import Pin from machine import PWM pwm = PWM(Pin(15)) pwm.freq(50) # Funktion zum setzen eines Winkels # als Parameter wird die Position erwartet def setServoCycle(position): pwm.duty_u16(position) sleep(0.01) while True: for pos in range(100, 8000,50): setServoCycle(pos) for pos in range(8000, 100,-50): setServoCycle(pos)