Sensoren

Das Joy-Car ist mit verschiedenen Sensoren ausgestattet, die vielseitige Funktionen ermöglichen. Zu diesen Sensoren gehören Hindernissensoren, die Objekte in der Nähe erkennen und dem Joy-Car helfen, Kollisionen zu vermeiden. Linetracker sind ebenfalls vorhanden, mit denen das Joy-Car Linien oder Pfade auf dem Boden erkennen und verfolgen kann, was besonders für Anwendungen wie das Folgen einer Spur nützlich ist. Darüber hinaus verfügt das Joy-Car über Geschwindigkeitssensoren, die die Drehgeschwindigkeit der Räder messen und so eine präzise Bewegungssteuerung und Geschwindigkeitsüberwachung ermöglichen. Ergänzt wird die Sensorik durch Ultraschallsensoren, die Entfernungen zu Objekten messen und zur Navigation sowie zur Vermeidung von Hindernissen beitragen. Die Kombination dieser Sensoren macht das Joy-Car zu einem vielseitigen Fahrzeug, das sowohl für autonomes Fahren als auch für interaktive Steuerungsaufgaben geeignet ist.
Hier findest du auch mehr über den technischen Hintergrund der Sensoren.
Hindernissensor

Zuerst schauen wir uns die Hindernissensoren am Joy-Car an. Die sitzen vorne an den Seiten und helfen dabei, Hindernisse in der Umgebung zu erkennen. So kann das Joy-Car schon jetzt feststellen, wenn etwas im Weg ist. Später werden wir mit diesen Sensoren sogar lernen, Hindernissen auszuweichen, was ein großer Schritt Richtung autonomes Fahren ist.
In diesem Codebeispiel nutzen wir die Hindernissensoren, um anzuzeigen, wo sich ein Hindernis befindet. Erkennt nur der linke Sensor ein Hindernis, wird auf dem micro:bit ein Pfeil nach links angezeigt. Das Gleiche passiert, wenn der rechte Sensor ein Hindernis erkennt – dann zeigt der Pfeil nach rechts. Werden Hindernisse von beiden Sensoren gleichzeitig erkannt, zeigt der micro:bit einen Pfeil geradeaus an. So wissen wir immer genau, wo sich etwas im Weg befindet!
Hindernissensor abfragen

Prüft den Linken/Rechten Hindernis-Sensor, ob ein Hindernis erkannt wurde. Die Funktion gibt als Antwort Wahr oder Falsch (True
/False
) zurück.
Codebeispiel
JoyCar.initJoyCar(RevisionMainboard.OnepThree)
basic.forever(function () {
if (JoyCar.obstacleavoidance(SensorLRSelection.Left) && JoyCar.obstacleavoidance(SensorLRSelection.Right)) {
serial.writeLine("Hindernis vorne erkannt")
basic.showLeds(`
. . # . .
. . # . .
# . # . #
. # # # .
. . # . .
`)
basic.pause(500)
} else if (!(JoyCar.obstacleavoidance(SensorLRSelection.Left)) && JoyCar.obstacleavoidance(SensorLRSelection.Right)) {
serial.writeLine("Hindernis auf der linken Seite erkannt")
basic.showLeds(`
. . . . #
# . . # .
# . # . .
# # . . .
# # # # .
`)
basic.pause(500)
} else if (JoyCar.obstacleavoidance(SensorLRSelection.Left) && !(JoyCar.obstacleavoidance(SensorLRSelection.Right))) {
serial.writeLine("Hindernis auf der rechten Seite erkannt")
basic.showLeds(`
# . . . .
. # . . #
. . # . #
. . . # #
. # # # #
`)
basic.pause(500)
} else {
basic.clearScreen()
}
})
Sensordaten abrufen
Zunächst wollen wir die Daten aus der Methode fetchSensorData
auslesen. Dafür erstellen wir ein Array namens sensor_data
, in dem die von der Methode zurückgegebenen Informationen gespeichert werden. Dieses Array ermöglicht es uns, gezielt auf die Sensordaten zuzugreifen und sie in unserem Programm weiterzuverarbeiten.
# Daten vom IO-Expander abrufen
sensor_data = fetchSensorData()
Hindernissensor abfragen
Die Hindernissensoren werden, wie alle anderen Sensoren, durch die Methode fetchSensorData
ausgelesen. Die Informationen zu den einzelnen Sensoren sind im zurückgegebenen Array sensor_data
gespeichert.
Die Daten für den linken Hindernissensor befinden sich an der Position 5 des Arrays, während die Daten für den rechten Hindernissensor an der Position 6 hinterlegt sind. Wenn beispielsweise an der 5. Position des Arrays der Wert False
steht, bedeutet das, dass der linke Hindernissensor ein Hindernis erkannt hat. Steht dort hingegen der Wert True
, erkennt der Sensor kein Hindernis. Dasselbe gilt für die 6. Position, die den Status des rechten Hindernissensors anzeigt.
# Prüfen, ob beide Sensoren ein Hindernis erkennen
if sensor_data[5] is False and sensor_data[6] is False:
print("Hindernis vorne erkannt")
# Pfeil auf der LED-Matrix in diese Richtung anzeigen
display.show(front)
sleep(500)
Codebeispiel
# Notwendige Bibliotheken importieren
from microbit import *
# Definiere deine Joy Car Mainboard Revision
joycar_rev = 1.3
# Initialisierung der I2C-Schnittstelle für das Joy Car Mainboard
i2c.init(freq=400000, sda=pin20, scl=pin19)
# alle Sensordaten abrufen
def fetchSensorData():
# Da die zfill-Funktion nicht in micro:bit Micropython enthalten ist,
# muss sie als Funktion eingefügt werden
def zfill(s, width):
return '{:0>{w}}'.format(s, w=width)
# Hexadezimale Daten lesen und in binäre Daten umwandeln
data = "{0:b}".format(ord(i2c.read(0x38, 1)))
# Füllen Sie die Daten bei Bedarf auf 8 Stellen auf.
data = zfill(data, 8)
# bol_data_dict as dictionary deklarieren
bol_data_dict = {}
# Zähler für die Schleife, die die Daten aus data in bol_data_dict einträgt
bit_count = 7
# Übertragen Sie die Daten von data nach bol_data_dict
for i in data:
if i == "0":
bol_data_dict[bit_count] = False
bit_count -= 1
else:
bol_data_dict[bit_count] = True
bit_count -= 1
# Ab Mainboard-Revision 1.3 sind die Geschwindigkeitssensoren auf separaten Pins
if joycar_rev >= 1.3:
bol_data_dict[8], bol_data_dict[9] = bol_data_dict[0], bol_data_dict[1]
bol_data_dict[0] = bool(pin14.read_digital())
bol_data_dict[1] = bool(pin15.read_digital())
# Bit 0 = GeschwindigkeitLinks, Bit 1 = GeschwindigkeitRechts, Bit 2 = LineTrackerLinks,
# bit 3 = LineTrackerMitte, bit 4 = LineTrackerRechts,
# bit 5 = HindernisLinks, bit 6 = HindernisRechts, bit 7 = freier Pin(7)
# (bit 8 = frei (pin0) bit 9 = frei (pin1)) - nur mit Revision 1.3 oder neuer
return bol_data_dict
# Bilder definieren, die auf der LED-Matrix angezeigt werden sollen
right = Image("00009:"
"90090:"
"90900:"
"99000:"
"99990")
left = Image("90000:"
"09009:"
"00909:"
"00099:"
"09999")
front = Image("00900:"
"00900:"
"90909:"
"09990:"
"00900")
while True:
# Daten vom IO-Expander abrufen
sensor_data = fetchSensorData()
# Prüfen, ob beide Sensoren ein Hindernis erkennen
if sensor_data[5] is False and sensor_data[6] is False:
print("Hindernis vorne erkannt")
# Pfeil auf der LED-Matrix in diese Richtung anzeigen
display.show(front)
sleep(500)
# Prüfen, ob ein Hindernis auf der linken Seite erkannt wird
elif sensor_data[5] is False and sensor_data[6] is True:
print("Hindernis auf der linken Seite erkannt")
# Pfeil auf der LED-Matrix in diese Richtung anzeigen
display.show(left)
sleep(500)
# Prüfen, ob ein Hindernis auf der rechten Seite erkannt wird
elif sensor_data[6] is False and sensor_data[5] is True:
print("Hindernis auf der rechten Seite erkannt")
# Pfeil auf der LED-Matrix in diese Richtung anzeigen
display.show(right)
sleep(500)
else:
# LED-Matrix löschen
display.clear()
Liniensensoren

Kommen wir jetzt zu den Liniensensoren. Diese sind unter dem Joy-Car angebracht, und es gibt insgesamt drei davon. Sie sind dafür da, zu erkennen, wenn das Joy-Car von einer Linie abweicht. In späteren Projekten können sie dafür genutzt werden, dass das Joy-Car einer schwarzen Linie automatisch folgt und sich so gezielt auf einer vorgegebenen Strecke bewegt.
Liniensensor abfragen

Prüft den Linken/Mittleren/Rechten Linefinder-Sensor, ob eine Linie auf dem Boden erkannt werden konnte. Die Funktion gibt als Antwort Wahr oder Falsch (True
/False
) zurück.
Codebeispiel
JoyCar.initJoyCar(RevisionMainboard.OnepThree)
basic.forever(function () {
if (!(JoyCar.linefinder(SensorLCRSelection.Left)) && (JoyCar.linefinder(SensorLCRSelection.Center) && JoyCar.linefinder(SensorLCRSelection.Right))) {
serial.writeLine("Linie auf der linken Seite entdeckt")
basic.showLeds(`
. . . . #
. . . . #
. . . . #
. . . . #
. . . . #
`)
} else if (JoyCar.linefinder(SensorLCRSelection.Left) && (!(JoyCar.linefinder(SensorLCRSelection.Center)) && JoyCar.linefinder(SensorLCRSelection.Right))) {
serial.writeLine("Linie in der Mitte entdeckt")
basic.showLeds(`
. . # . .
. . # . .
. . # . .
. . # . .
. . # . .
`)
} else if (JoyCar.linefinder(SensorLCRSelection.Left) && (JoyCar.linefinder(SensorLCRSelection.Center) && !(JoyCar.linefinder(SensorLCRSelection.Right)))) {
serial.writeLine("Linie auf der rechten Seite entdeckt")
basic.showLeds(`
# . . . .
# . . . .
# . . . .
# . . . .
# . . . .
`)
} else {
basic.clearScreen()
}
})
Sensordaten abrufen
Zunächst wollen wir die Daten aus der Methode fetchSensorData
auslesen. Dafür erstellen wir ein Array namens sensor_data
, in dem die von der Methode zurückgegebenen Informationen gespeichert werden. Dieses Array ermöglicht es uns, gezielt auf die Sensordaten zuzugreifen und sie in unserem Programm weiterzuverarbeiten.
# Sensordaten vom IO-Expander abrufen
sensor_data = fetchSensorData()
Liniensensor abfragen
Auch die Liniensensoren werden mit der Methode fetchSensorData
ausgelesen. Die Informationen zu den einzelnen Sensoren werden dabei im zurückgegebenen Array sensor_data
gespeichert.
Die Daten des linken Liniensensors befinden sich an der Position 2 des Arrays. Der mittlere Liniensensor ist an der Position 3 hinterlegt, und die Informationen des rechten Liniensensors sind an der Position 4 zu finden.
Wenn der Wert an der 2. Stelle des Arrays False
ist, bedeutet das, dass der linke Liniensensor eine schwarze Fläche unter sich erkannt hat. Für den mittleren und den rechten Liniensensor gilt das Gleiche: Ein False
an den entsprechenden Stellen zeigt an, dass der jeweilige Sensor eine schwarze Fläche detektiert. Ein True
gibt an, dass sich eine hellere Fläche darunter befindet.
# Prüfen, ob nur der linke Sensor eine Linie erkennt
if sensor_data[2] is True and sensor_data[3] is False and sensor_data[4] is False:
print("Linie auf der linken Seite entdeckt")
display.show(left)
Codebeispiel
# Notwendige Bibliotheken importieren
from microbit import *
# Definiere deine Joy Car Mainboard Revision
joycar_rev = 1.3
# Initialisierung der I2C-Schnittstelle für das Joy Car Mainboard
i2c.init(freq=400000, sda=pin20, scl=pin19)
# alle Sensordaten abrufen
def fetchSensorData():
# Da die zfill-Funktion nicht in micro:bit Micropython enthalten ist,
# muss sie als Funktion eingefügt werden
def zfill(s, width):
return '{:0>{w}}'.format(s, w=width)
# Hexadezimale Daten lesen und in binäre Daten umwandeln
data = "{0:b}".format(ord(i2c.read(0x38, 1)))
# Füllen Sie die Daten bei Bedarf auf 8 Stellen auf.
data = zfill(data, 8)
# bol_data_dict as dictionary deklarieren
bol_data_dict = {}
# Zähler für die Schleife, die die Daten aus data in bol_data_dict einträgt
bit_count = 7
# Übertragen Sie die Daten von data nach bol_data_dict
for i in data:
if i == "0":
bol_data_dict[bit_count] = False
bit_count -= 1
else:
bol_data_dict[bit_count] = True
bit_count -= 1
# Ab Mainboard-Revision 1.3 sind die Geschwindigkeitssensoren auf separaten Pins
if joycar_rev >= 1.3:
bol_data_dict[8], bol_data_dict[9] = bol_data_dict[0], bol_data_dict[1]
bol_data_dict[0] = bool(pin14.read_digital())
bol_data_dict[1] = bool(pin15.read_digital())
# Bit 0 = GeschwindigkeitLinks, Bit 1 = GeschwindigkeitRechts, Bit 2 = LineTrackerLinks,
# bit 3 = LineTrackerMitte, bit 4 = LineTrackerRechts,
# bit 5 = HindernisLinks, bit 6 = HindernisRechts, bit 7 = freier Pin(7)
# (bit 8 = frei (pin0) bit 9 = frei (pin1)) - nur mit Revision 1.3 oder neuer
return bol_data_dict
# Bilder definieren, die auf der LED-Matrix angezeigt werden sollen
right = Image("90000:"
"90000:"
"90000:"
"90000:"
"90000")
middle = Image("00900:"
"00900:"
"00900:"
"00900:"
"00900")
left = Image("00009:"
"00009:"
"00009:"
"00009:"
"00009")
while True:
# Daten vom IO-Expander abrufen
sensor_data = fetchSensorData()
# Prüfen, ob nur der linke Sensor eine Linie erkennt
if sensor_data[2] is True and sensor_data[3] is False and sensor_data[4] is False:
print("Linie auf der linken Seite entdeckt")
display.show(left)
# Prüfen, ob nur der mittlere Sensor eine Linie erkennt
elif sensor_data[2] is False and sensor_data[3] is True and sensor_data[4] is False:
print("Linie in der Mitte entdeckt")
display.show(middle)
# Prüfen, ob nur der rechte Sensor eine Linie erkennt
elif sensor_data[2] is False and sensor_data[3] is False and sensor_data[4] is True:
print("Linie auf der rechten Seite entdeckt")
display.show(right)
else:
display.clear()
Geschwindigkeitssensoren
Das Joy-Car ist außerdem mit zwei Geschwindigkeitssensoren ausgestattet, die sich neben den Motoren befinden. Diese Sensoren messen die Umdrehungen der Motoren mithilfe eines kleinen Rädchens. Durch das Zählen der Umdrehungen können sie die aktuelle Geschwindigkeit berechnen. Das ist besonders praktisch, um einen Offset zwischen den Motoren präzise einzustellen und sicherzustellen, dass das Joy-Car geradeaus fährt oder eine gewünschte Geschwindigkeit exakt einhält.
Im folgenden Beispiel werden die Drehzahlen der beiden Motoren berechnet. Um sicherzustellen, dass das Joy-Car nicht vom Schreibtisch fährt, empfiehlt es sich, das Fahrzeug auf die mitgelieferte Parkhalterung zu stellen. So können die Motoren sicher getestet werden, ohne dass sich das Joy-Car bewegt.
Geschwindigkeitsensor abfragen

Prüft den Linken/Rechten Speed-Sensor, ob das Signal durch die Lochscheibe unterbrochen wurde. Die Funktion gibt als Antwort Wahr oder Falsch (True
/False
) zurück.
Revisionen ≥ 1.3
Codebeispiel für Revisionen ab 1.3
Beim Joy-Car ab Revision 1.3 wurden die Geschwindigkeitssensoren vom IO-Expander direkt an den micro:bit angeschlossen. Dadurch können die Sensoren schneller und präziser ausgelesen werden, was eine noch genauere Steuerung und Synchronisation der Motoren ermöglicht. Diese Änderung verbessert die Performance des Joy-Cars erheblich, insbesondere bei Projekten, die eine exakte Geschwindigkeitsregelung erfordern.
pins.onPulsed(DigitalPin.P15, PulseValue.High, function () {
counter_right += 1
})
pins.onPulsed(DigitalPin.P14, PulseValue.High, function () {
counter_left += 1
})
let speed_right = 0
let speed_left = 0
JoyCar.initJoyCar(RevisionMainboard.OnepThree)
let counter_left = 0
let counter_right = 0
let interval = 10
let wheel = 20
let calc = 60 / interval
let timer_start = control.millis()
JoyCar.drive(FRLRDirection.Forward, 100)
basic.forever(function () {
if (control.millis() - timer_start >= interval * 1000) {
speed_left = counter_left / 2 * calc / wheel
speed_right = counter_right / 2 * calc / wheel
serial.writeLine("Umdrehungen pro Minute linker Motor: " + speed_left)
serial.writeLine("Umdrehungen pro Minute rechter Motor: " + speed_right)
counter_left = 0
counter_right = 0
timer_start = control.millis()
}
})
Revision ≤ 1.2
Codebeispiel für Revisionen bis 1.2
Bei den aktuellen Joy-Cars sind die Geschwindigkeitssensoren noch am IO-Expander angeschlossen. Das hat den Nachteil, dass die Drehzahl nicht so präzise ausgelesen werden kann, da die Kommunikation mit dem IO-Expander zusätzliche Verzögerungen mit sich bringt. Das beeinträchtigt die Genauigkeit der Geschwindigkeitsmessung und damit auch die Feinabstimmung der Motoren.
Drehzahlberechnung
Für die Berechnung der Drehzahl benötigen wir verschiedene Variablen, die unterschiedliche Aufgaben übernehmen.
Zu den konstanten Variablen gehören:
one_round
: Gibt an, wie viele Impulse für eine vollständige Umdrehung des Rads nötig sind.interval
: Definiert das Zeitintervall, in dem die Drehzahl berechnet wird.calc
: Dient zur Durchführung der Berechnungen basierend auf den erfassten Daten.wheel
: Bezieht sich auf die Radgröße oder spezifische Parameter der Räder, die in die Berechnung einfließen.
Um die tatsächlichen Umdrehungen der Räder zu erfassen, verwenden wir folgende Variablen:
timer_start
: Hält den Startzeitpunkt des aktuellen Intervalls fest.counter_left
undcounter_right
: Zählen die Impulse, die von den linken und rechten Geschwindigkeitssensoren erfasst werden.
Zusätzlich benötigen wir Variablen, um Zustandsänderungen zu erkennen:
left_last
undleft_current
: Speichern den vorherigen und aktuellen Zustand des linken Geschwindigkeitssensors.right_last
undright_current
: Speichern den vorherigen und aktuellen Zustand des rechten Geschwindigkeitssensors.
# Anzahl der Schritte für eine Runde festlegen
one_round = 2056
# Definition der notwendigen Parameter für die Berechnung der Drehzahl
counter = 0
interval = 10 # in Sekunden
calc = 60 / interval
wheel = 20
timer_start = running_time()
# Festlegung spezifischer Parameter für den linken und rechten Geschwindigkeitssensor
counter_left = 0
counter_right = 0
# Parameter definieren, um zu prüfen, ob sich der Wert ändert
left_last = -1
left_current = -1
right_last = -1
right_current = -1
Motoren ansteuern
Damit die Drehzahl berechnet werden kann, muss das Joy-Car in Bewegung gesetzt werden. Erst durch das Fahren erzeugen die Geschwindigkeitssensoren die notwendigen Impulse, die dann von den Variablen erfasst und für die Berechnung der Drehzahl genutzt werden können. Während des Tests ist es wichtig, das Joy-Car entweder kontrolliert auf der Parkhalterung laufen zu lassen oder sicherzustellen, dass es genügend Platz hat, um frei zu fahren.
# Motoren auf Vorwärtsfahrt einstellen
drive(0, 255, 0, 255)
Geschwindigkeitsensor abfragen
Revisionen ≥ 1.3
Ab Revision 1.3 können die Geschwindigkeitssensoren des Joy-Cars direkt über die Pins 14 und 15 des micro:bit angesprochen werden. Dadurch ist eine schnellere und präzisere Erfassung der Sensordaten möglich.
Um die Umdrehungen der Räder zu messen, wird auch hier überprüft, ob sich der Zustand der Sensoren verändert hat. Diese Zustandsänderungen entstehen durch die Löcher im Rad, die von den Sensoren erkannt werden. Sobald 20 Zustandsänderungen gezählt wurden, entspricht dies genau einer vollständigen Umdrehung des Rads.
Dank des direkten Anschlusses an den micro:bit entfällt die Verzögerung durch den IO-Expander, was eine genauere Berechnung der Drehzahl ermöglicht.
# nach Mainboard-Revision sind 1.3 Geschwindigkeitssensoren auf separaten Pins
# und nicht auf IO-Expander
if joycar_rev >= 1.3:
# Wert von Pin 14 lesen
left_current = pin14.read_digital()
# Prüfen, ob der linke Geschwindigkeitssensor seinen Wert geändert hat
if left_current != left_last:
# letzten Wert auf den aktuellen setzen
left_last = left_current
# Zählerstand erhöhen
counter_left += 1
# Wert von Pin 15 lesen
right_current = pin15.read_digital()
# Prüfen, ob der rechte Geschwindigkeitssensor den Wert geändert hat
if right_current != right_last:
# letzten Wert auf den aktuellen setzen
right_last = right_current
# Zählerstand erhöhen
counter_right += 1
Revisionen ≤ 1.2
Bei älteren Revisionen des Joy-Cars, also vor Version 1.3, sind die Geschwindigkeitssensoren noch am IO-Expander angeschlossen. Daher wird in diesen Fällen die Methode fetchSensorData
verwendet, um die Sensordaten auszulesen.
Um die Umdrehungen der Räder zu messen, wird überprüft, ob sich der Zustand der Sensoren verändert hat. Diese Zustandsänderungen entstehen durch die Löcher im Rad, die von den Sensoren erkannt werden. Sobald 20 Zustandsänderungen gezählt wurden, entspricht dies einer vollständigen Umdrehung des Rads.
Dieses Verfahren ermöglicht es, die Drehzahl trotz der eingeschränkten Präzision des IO-Expanders zu berechnen.
else:
"""
Das Lesen der Daten aus dem IO-Expander ist sehr langsam. Aus diesem Grund sind die
Umdrehungen pro Minute ungenau. Dies kann nur durch neueren Revisionen gelöst werden.
"""
# Daten vom IO-Expander abrufen
sensor_data = fetchSensorData()
# Wert vom IO-Expander lesen
left_current = sensor_data[0]
# Prüfen, ob der linke Geschwindigkeitssensor seinen Wert geändert hat
if left_current != left_last:
# letzten Wert auf den aktuellen setzen
left_last = left_current
# Zählerstand erhöhen
counter_left += 1
# Wert vom IO-Expander lesen
right_current = sensor_data[1]
# Prüfen, ob der rechter Geschwindigkeitssensor seinen Wert geändert hat
if right_current != right_last:
# letzten Wert auf den aktuellen setzen
right_last = right_current
# Zählerstand erhöhen
counter_right += 1
Berechnung der Drehzahl und Ausgabe
Nach einem Zeitraum von 10 Sekunden wird die gemessene Drehzahl auf eine Minute hochgerechnet und ausgegeben.
Anschließend werden alle Variablen, die für die Messung verwendet wurden, zurückgesetzt, einschließlich der Zähler für die Zustandsänderungen und der Timer. Danach startet die Messung erneut, um kontinuierlich aktuelle Drehzahlen zu berechnen und anzuzeigen.
# Prüfen, ob das festgelegte Zeitintervall abgelaufen ist
if running_time() - timer_start >= interval * 1000:
# Umdrehungen pro Minute berechnen
speed_right = ((counter_right / 2) * calc) / wheel
speed_left = ((counter_left / 2) * calc) / wheel
# Ergebnis ausgeben
print("Umdrehungen pro Minute linker Motor: ", speed_left)
print("Umdrehungen pro Minute rechter Motor: ", speed_right)
# Parameter zurücksetzen
counter_left = 0
counter_right = 0
timer_start = running_time()
Codebeispiel
# Notwendige Bibliotheken importieren
from microbit import *
# Definiere deine Joy Car Mainboard Revision
joycar_rev = 1.3
# Initialisierung der I2C-Schnittstelle für das Joy Car Mainboard
i2c.init(freq=400000, sda=pin20, scl=pin19)
# PWM-Controller initialisieren
i2c.write(0x70, b'\x00\x01')
i2c.write(0x70, b'\xE8\xAA')
# die Verzögerung einer Motorverzögerung kann verwendet werden, um unterschiedliche Motordrehzahlen zu kompensieren
biasR = 0 # Verzögerung des rechten Motors in Prozent
biasL = 0 # Verzögerung des linken Motors in Prozent
# Motoren mit dem PWM-Controller steuern
# PWM0 und PWM1 für den linken Motor und PWM2 und PWM3 für den rechten Motor
def drive(PWM0, PWM1, PWM2, PWM3):
# Die Skalierungsfunktion wird verwendet, um die Bias-Variablen
# für die Berechnung der Motordrehzahl skaliert
def scale(num, in_min, in_max, out_min, out_max):
return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
# Skalierung des Verzögerungswertes auf den Wert in Prozent
PWM0 = int(PWM0 * (scale(biasR, 0, 100, 100, 0) / 100))
PWM1 = int(PWM1 * (scale(biasR, 0, 100, 100, 0) / 100))
PWM2 = int(PWM2 * (scale(biasL, 0, 100, 100, 0) / 100))
PWM3 = int(PWM3 * (scale(biasL, 0, 100, 100, 0) / 100))
# Wert für PWM-Kanal (0-255) an PWM-Controller übertragen
# 0x70 ist die I2C-Adresse des Controllers
# das Byte mit dem PWM-Wert wird zu dem Byte für den Kanal addiert
i2c.write(0x70, b'\x02' + bytes([PWM0]))
i2c.write(0x70, b'\x03' + bytes([PWM1]))
i2c.write(0x70, b'\x04' + bytes([PWM2]))
i2c.write(0x70, b'\x05' + bytes([PWM3]))
# alle Sensordaten abrufen
def fetchSensorData():
# Da die zfill-Funktion nicht in micro:bit Micropython enthalten ist,
# muss sie als Funktion eingefügt werden
def zfill(s, width):
return '{:0>{w}}'.format(s, w=width)
# Hexadezimale Daten lesen und in binäre Daten umwandeln
data = "{0:b}".format(ord(i2c.read(0x38, 1)))
# Füllen Sie die Daten bei Bedarf auf 8 Stellen auf.
data = zfill(data, 8)
# bol_data_dict as dictionary deklarieren
bol_data_dict = {}
# Zähler für die Schleife, die die Daten aus data in bol_data_dict einträgt
bit_count = 7
# Übertragen Sie die Daten von data nach bol_data_dict
for i in data:
if i == "0":
bol_data_dict[bit_count] = False
bit_count -= 1
else:
bol_data_dict[bit_count] = True
bit_count -= 1
# Ab Mainboard-Revision 1.3 sind die Geschwindigkeitssensoren auf separaten Pins
if joycar_rev >= 1.3:
bol_data_dict[8], bol_data_dict[9] = bol_data_dict[0], bol_data_dict[1]
bol_data_dict[0] = bool(pin14.read_digital())
bol_data_dict[1] = bool(pin15.read_digital())
# Bit 0 = GeschwindigkeitLinks, Bit 1 = GeschwindigkeitRechts, Bit 2 = LineTrackerLinks,
# bit 3 = LineTrackerMitte, bit 4 = LineTrackerRechts,
# bit 5 = HindernisLinks, bit 6 = HindernisRechts, bit 7 = freier Pin(7)
# (bit 8 = frei (pin0) bit 9 = frei (pin1)) - nur mit Revision 1.3 oder neuer
return bol_data_dict
# Anzahl der Schritte für eine Runde festlegen
one_round = 2056
# Definition der notwendigen Parameter für die Berechnung der Drehzahl
counter = 0
interval = 10 # in Sekunden
calc = 60 / interval
wheel = 20
timer_start = running_time()
# Festlegung spezifischer Parameter für den linken und rechten Geschwindigkeitssensor
counter_left = 0
counter_right = 0
# Parameter definieren, um zu prüfen, ob sich der Wert ändert
left_last = -1
left_current = -1
right_last = -1
right_current = -1
# Motoren auf Vorwärtsfahrt einstellen
drive(0, 255, 0, 255)
while True:
# nach Mainboard-Revision sind 1.3 Geschwindigkeitssensoren auf separaten Pins
# und nicht auf IO-Expander
if joycar_rev >= 1.3:
# Wert von Pin 14 lesen
left_current = pin14.read_digital()
# Prüfen, ob der linke Geschwindigkeitssensor seinen Wert geändert hat
if left_current != left_last:
# letzten Wert auf den aktuellen setzen
left_last = left_current
# Zählerstand erhöhen
counter_left += 1
# Wert von Pin 15 lesen
right_current = pin15.read_digital()
# Prüfen, ob der rechte Geschwindigkeitssensor den Wert geändert hat
if right_current != right_last:
# letzten Wert auf den aktuellen setzen
right_last = right_current
# Zählerstand erhöhen
counter_right += 1
else:
"""
Das Lesen der Daten aus dem IO-Expander ist sehr langsam. Aus diesem Grund sind die
Umdrehungen pro Minute ungenau. Dies kann nur durch neueren Revisionen gelöst werden.
"""
# Daten vom IO-Expander abrufen
sensor_data = fetchSensorData()
# Wert vom IO-Expander lesen
left_current = sensor_data[0]
# Prüfen, ob der linke Geschwindigkeitssensor seinen Wert geändert hat
if left_current != left_last:
# letzten Wert auf den aktuellen setzen
left_last = left_current
# Zählerstand erhöhen
counter_left += 1
# Wert vom IO-Expander lesen
right_current = sensor_data[1]
# Prüfen, ob der rechter Geschwindigkeitssensor seinen Wert geändert hat
if right_current != right_last:
# letzten Wert auf den aktuellen setzen
right_last = right_current
# Zählerstand erhöhen
counter_right += 1
# Prüfen, ob das festgelegte Zeitintervall abgelaufen ist
if running_time() - timer_start >= interval * 1000:
# Umdrehungen pro Minute berechnen
speed_right = ((counter_right / 2) * calc) / wheel
speed_left = ((counter_left / 2) * calc) / wheel
# Ergebnis ausgeben
print("Umdrehungen pro Minute linker Motor: ", speed_left)
print("Umdrehungen pro Minute rechter Motor: ", speed_right)
# Parameter zurücksetzen
counter_left = 0
counter_right = 0
timer_start = running_time()
Ultraschallsensor

Zuletzt gibt es den Ultraschallsensor, der sich frontal an der Vorderseite des Joy-Cars befindet. Dieser Sensor nutzt Ultraschallwellen, um den Abstand zu Objekten vor dem Fahrzeug zu messen. Dabei sendet der Sensor Schallwellen aus und misst die Zeit, die der Schall benötigt, um von einem Hindernis zurück zum Sensor reflektiert zu werden. Aus dieser Zeit kann der Abstand präzise berechnet werden. Der Ultraschallsensor ist ideal, um Hindernisse zu erkennen und Abstandsberechnungen durchzuführen.
Im folgenden Beispiel gibt der Ultraschallsensor seine Messwerte in Abständen von 500 Millisekunden aus. Das bedeutet, dass alle halbe Sekunde eine neue Messung durchgeführt und der ermittelte Abstand ausgegeben wird. So lassen sich kontinuierlich Änderungen im Abstand zu Objekten vor dem Joy-Car verfolgen.
Ultraschallsensor abfragen

Prüft den Ultraschallsensor auf die Entfernung zum nächstgelegenen erkannten Objekt. Die Funktion gibt die Entfernung als Antwort zurück.
Codebeispiel
JoyCar.initJoyCar(RevisionMainboard.OnepThree)
basic.forever(function () {
serial.writeLine("" + (Math.round(JoyCar.sonar())))
basic.pause(500)
})
Ultraschallsensor initialisieren
Zunächst müssen die Pins für den Ultraschallsensor definiert werden. Der Sensor verwendet zwei Pins:
- Trigger-Pin: Dieser Pin wird verwendet, um das Ultraschallsignal zu senden. Er initiiert die Schallwelle, die vom Sensor ausgesendet wird.
- Echo-Pin: Dieser Pin misst, wann das Ultraschallsignal zurückkehrt, nachdem es von einem Objekt reflektiert wurde.
Durch die Kombination dieser beiden Pins können die Sendedauer und die Rückkehrzeit erfasst werden, um die Entfernung präzise zu berechnen.
# Pins für Ultraschallsensor definieren
trigger = pin8
echo = pin12
# Initialisierung der Pins für den Ultraschallsensor
trigger.write_digital(0)
echo.read_digital()
Ultraschallsensor Abstand messen
In der Methode get_distance
wird die gemessene Distanz berechnet und als Ergebnis zurückgegeben.
Zunächst sendet der Ultraschallsensor über den Trigger-Pin einen Ultraschallimpuls aus. Gleichzeitig wird der Echo-Pin überwacht, um die Zeit zu messen, die das Signal benötigt, um zurückzukehren, nachdem es von einem Objekt reflektiert wurde.
Anhand der gemessenen Zeitdauer zwischen dem Senden und dem Empfangen des Signals berechnet die Methode die Distanz. Dabei wird die Schallgeschwindigkeit in der Luft berücksichtigt, um den exakten Abstand vor dem Ultraschallsensor zu ermitteln.
Diese Berechnung liefert die Entfernung in Zentimetern, die dann zurückgegeben wird.
# Methode zur Berechnung der Entfernung vom Ultraschallsensor
def get_distance():
# Garbage Collector aktivieren
gc.collect()
# kurzen Impuls auf den Trigger-Pin setzen
trigger.write_digital(1)
trigger.write_digital(0)
# Messung der Zeit, bis der Echo-Pin hoch wird
duration = time_pulse_us(echo, 1)
# Entfernung berechnen
distance = ((duration / 1000000) * 34300) / 2
# Rückgabe der Entfernung, gerundet auf 2 Dezimalstellen
return round(distance, 2)
Codebeispiel
# Notwendige Bibliotheken importieren
from microbit import *
import gc
from machine import time_pulse_us
# Definiere deine Joy Car Mainboard Revision
joycar_rev = 1.3
# Pins für Ultraschallsensor definieren
trigger = pin8
echo = pin12
# Initialisierung der Pins für den Ultraschallsensor
trigger.write_digital(0)
echo.read_digital()
# Methode zur Berechnung der Entfernung vom Ultraschallsensor
def get_distance():
# Garbage Collector aktivieren
gc.collect()
# kurzen Impuls auf den Trigger-Pin setzen
trigger.write_digital(1)
trigger.write_digital(0)
# Messung der Zeit, bis der Echo-Pin hoch wird
duration = time_pulse_us(echo, 1)
# Entfernung berechnen
distance = ((duration / 1000000) * 34300) / 2
# Rückgabe der Entfernung, gerundet auf 2 Dezimalstellen
return round(distance, 2)
while True:
# Ausgabe der gemessenen Entfernung vom Ultraschallsensor
print(get_distance())
# 500 ms warten
sleep(500)