Bibliotheken für die Roboter
Micropython Software-Bibliotheken für den Betrieb der Roboter.
- Motorsteuerung
- Ultraschallsensor
- Infrarotsteuerung
- Servosteuerung
- Das komplette Modul "robotlibrary"
- Codebeispiele
Motorsteuerung
Speichere diesen Code auf dem Pico unter dem Namen "motor.py".
Motorbibliothek
from machine import Pin, PWM
import utime
MIN_DUTY = 0
MAX_DUTY = 60000
MAX_SPEED = 100
MIN_SPEED = 30
class Motor:
'''This class manages the motor. Don't edit!'''
def __init__(self, pinNo):
self.gpio = pinNo
self.speed=0
self.forward=True
self.pwm1=PWM(Pin(pinNo))
self.pwm1.freq(50000)
self.pwm1.duty_u16(0)
self.pwm2=PWM(Pin(pinNo+1))
self.pwm2.freq(50000)
self.pwm2.duty_u16(0)
self.speed_offset = 0
def set_speed(self,s):
'''Sets the speed of the motor. Checks for sensible input.'''
if s + self.speed_offset <= MIN_SPEED:
s = 0
self.reset_offset()
elif s + self.speed_offset >= MAX_SPEED:
s = MAX_SPEED
self.pwm1.duty_u16(int(MAX_DUTY*(s+self.speed_offset)/100))
self.speed=s
def change_speed(self,sc):
'''This defines an offset to the speed in motor. It is used with the remote control to turn the robot.'''
if self.speed + sc > MIN_SPEED and self.speed + sc < MAX_SPEED:
self.speed_offset += sc
self.set_speed(self.speed)
def reset_offset(self):
self.speed_offset = 0
def off(self):
self.pwm1.duty_u16(0)
self.speed = 0
def set_forward(self,forward):
'''Sets the motor to forward or backward without changing the speed. '''
if self.forward==forward:
return
self.pwm1.duty_u16(0)
self.pwm1,self.pwm2=self.pwm2,self.pwm1
self.forward=forward
self.set_speed(self.speed)
#self.pwm1.duty_u16(int(MAX_DUTY*(self.speed+self.speed_offset)/100)) # uncommenting this causes problems with the remote control. After changing
# the direction the robot would drive even if the remote control speed said 0.
Beispiel für die Anwendung dieser Bibliothek
Kopiere diesen Code in eine andere Datei auf dem Pico, z. B. „motortest.py“.
from motor import Motor
from utime import sleep, sleep_ms
motor = Motor(12)
motor.set_speed(70)
motor.set_forward(True)
sleep(1)
motor.off()
Ultraschallsensor
Ultraschallbibliothek
Speichere diesen Code auf dem Pico unter dem Namen "ultrasonic.py".
from machine import Pin
from time import sleep
import utime
class Ultra:
'''This class manages the ultrasonic sensor. It returns the distance to an obstacle in cm. '''
def __init__(self, pinNo):
self.trigger = Pin(pinNo, Pin.OUT) # to trigger a sound impulse
self.echo = Pin(pinNo+1, Pin.IN) # records the echo of the trigger pulse
def get_dist(self):
'''This returns the measured distance in cm. (float)'''
timepassed = 0
signalon = 0
signaloff = 0
self.trigger.low()
utime.sleep_us(2)
self.trigger.high()
utime.sleep_us(5)
self.trigger.low()
while self.echo.value() == 0:
signaloff = utime.ticks_us()
while self.echo.value() == 1:
signalon = utime.ticks_us()
timepassed = signalon - signaloff
distance = round((timepassed * 0.0343) / 2, 2)
# print("The distance from object is ", distance, "cm.") # for debugging purposes uncomment the line.
utime.sleep_ms(10) # Wait necessary or program halts
return distance
Beispiel für die Anwendung dieser Bibliothek
Kopiere diesen Code in eine andere Datei auf dem Pico, z. B. „ultratest.py“.
from ultrasonic import Ultra
from utime import sleep, sleep_ms
us = Ultra(16)
while True:
print(f"gemessene Entfernung: {us.get_dist()} cm.")
sleep(1)
Zum Fahren siehe Motorsteuerung.
Infrarotsteuerung
Ein Infrarotsensor kann zum Erkennen von Hindernissen oder der Verfolgung einer schwarzen Linie genutzt werden. Die folgende Klasse steuert den Sensor.
from machine import Pin,Timer
import micropython
micropython.alloc_emergency_exception_buf(100)
class IR:
'''This class manages the IR-sensor. Write your code in Robot.ir_detected()'''
def __init__(self, pinNo,callback_func):
self.out = pinNo
self.ir_detected = callback_func
self.ir = Pin(pinNo, Pin.IN, Pin.PULL_UP)
self.ir.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=self.obstacle)
self.detected=False
self.timer = Timer()
def reset_detected(self,t):
self.detected = False
def obstacle(self, pin):
'''This is called on any change in the IR-sensor. '''
if not self.detected:
self.ir_detected(pin,self.out)
self.detected = True
self.timer.init(mode=Timer.ONE_SHOT, period=100, callback=self.reset_detected)
Der Code muss unter dem Dateinamen „infrared.py“ auf dem Pico gespeichert werden.
Der Infrarotsensor wird folgendermaßen im eigenen Programm eingebunden. Das Beispiel ist für zwei Infrarotsensoren.
from infrared import IR
IR_PIN_LEFT=0
IR_PIN_RIGHT=1
def ir_detected(pin, pinno):
print(f"Pin: {pin}, pin number: {pinno}")
if pinno == IR_PIN_LEFT:
print("links")
elif pinno == IR_PIN_RIGHT:
print("right")
ir_left = IR(0, ir_detected)
ir_right = IR(1, ir_detected)
Servosteuerung
Der Ultraschallsensor kann auch mit einem Servomotor drehbar gemacht werden. Die folgende Klasse steuert den Servomotor:
from machine import Pin, PWM
import utime
class Servo:
'''This class manages the servo motor that turns the ultrasonic sensor. You need a servo motor installed to get use out of this.
Don't use directly or edit.'''
def __init__(self,pin):
self.pin=PWM(Pin(pin))
self.pin.freq(50)
self.min=1350
self.max=8100
self.angle=0
def set_angle(self,a):
'''If installed, the servor motor will set the angle of the ultrasonic sensor. 90° ist straight ahead.'''
if a > self.angle:
for i in range(self._get_duty(self.angle),self._get_duty(a)):
self.pin.duty_u16(i)
elif a < self.angle:
for i in range(self._get_duty(self.angle), self._get_duty(a),-1):
self.pin.duty_u16(i)
self.angle = a
utime.sleep_ms(4)
def _get_duty(self,angle):
'''Internal function. Calculates the PWM duty for the given angle.'''
return round((self.max-self.min)/180*angle+self.min)
Dieser Code muss unter dem Dateinamen „servo.py“ auf dem Pico gespeichert werden.
Das komplette Modul "robotlibrary"
Dieses Modul, das von Github heruntergeladen werden kann, steuert die Roboter mit allen Peripheriegeräten (Motoren, Sensoren). Dazu muss das Paket heruntergeladen und entpackt werden. Das Verzeichnis „robotlibrary“ muss dann auf den Pico hochgeladen werden.
SMARS Roboter "Theo III"
Um das Modul zu benutzen, muss nur folgender Import gemacht werden: from robotlibrary.robot import Robot
.
Ein kurzes Codebeispiel, wie der Roboter funktioniert, ist in der Quelldatei zu finden.
Under construction:
Crawly
Crawly ist ein Roboter, der, ähnlich wie eine Schildkröte auf vier Beinen kriechen kann. Um Crawly zu steuern, muss nur folgender Import gemacht werden: from robotlibrary.crawly import Crawly
Ein kurzes Codebeispiel, wie der Roboter funktioniert, ist in der Quelldatei zu finden.
Walky
Walky ist ein Roboter, der, ähnlich wie ein Hund, auf vier Beinen laufen kann. Um Walky zu steuern, muss nur folgender Import gemacht werden: from robotlibrary.walky import Walky
Ein kurzes Codebeispiel, wie der Roboter funktioniert, ist in der Quelldatei zu finden.
Die Dokumentation für die Bibliothek ist unter docs
zu finden oder kann hier heruntergeladen werden: robotlibrary.pdf
Codebeispiele
Theo III
Best Practise
Effizienter Code
Auch wenn die Rechenleistung der Picos ausreichen sollte, ergibt es Sinn, sich über Effizienz Gedanken zu machen, da schwer zu erkennen ist, ob manche Probleme durch Überlastung des Prozessors hervorgerufen werden.
while True:
robot.drive()
if us.get_dist() > min_distance:
# stop or turn
robot.stop()
In diesem Beispiel wird in der Schleife der Befehl drive()
mit jedem Durchlauf aufgerufen, was nicht sonderlich effizient ist, da die Motoren weiterfahren, auch wenn das Programm gerade andere Befehle ausführt. Eine bessere Variante wäre diese:
robot.drive()
while us.get_dist() > min_distance:
pass
robot.turn()
Hier wird nur die Entfernung zum nächsten Hindernis überprüft. Sobald der Roboter zu nahe gekommen ist, wird die Schleife beendet und der Code wird weiter ausgeführt.
Fehlertoleranter Code
Die Sensoren, die wir benutzen, liefern nicht immer zuverlässige und korrekte Ergebnisse. Daher kann man sich nicht darauf verlassen, dass eine Messung ausreicht. Ist man auf genauere Ergebnisse angewiesen, kann es sinnvoll sein, die Ergebnisse von Sensormessungen (insbesondere des Ultraschallsensors) zu filtern. Dazu kann gehören, Extremwerte, die im vorliegenden Fall unwahrscheinlich sind, zu ignorieren oder Mittelwerte von mehreren Messungen zu bilden.
Beschleunigung mit Entfernungsmessung
obstacle_detected = False
new_speed = 100
speed_now = 0
min_distance = 15
while speed_now <= new_speed and not obstacle_detected:
#Set the speed for the motors, f. ex. motor.set_speed(speed_now)
utime.sleep_ms(10+int(speed_now/2))
speed_now += 1
if us.get_dist() < min_distance: # Adjust the code to your needs.
obstacle_detected = True
if obstacle_detected:
# Stop or turn or whatever
obstacle_detected = False
else:
# keep going
pass