Robotik Informationen und Anleitungen zu den Bauteilen und den Zusammenbau des SMARS-Roboters Allgemeine Hinweise Umgang mit Elektronikteilen Die hier veröffentlichten Anleitungen sind nicht als alleinige Anleitung gedacht, sondern sollen immer zusammen mit dem Unterricht benutzt werden. Sie dienen als Gedächtnisstütze oder für diejenigen, die einzelne Stunden verpasst haben, als Möglichkeit, beim Aufbau aufzuholen. Grundsätzlich gilt, dass alle verbauten elektronischen Teile sehr empfindlich gegen Verpolung und zu hohe Spannungen sind. Daher sollte man sich nach dem Hinzufügen eines Bauteils immer vergewissern, dass alles richtig angeschlossen ist. Am besten zeigt man die Anschlüsse immer noch jemand anderem. Hier einige Beispiele für explodierende Elektronikteile: Kondensator Diode Allgemeine Tipps für die Programmierung Python und Micropython definieren Programmierblöcke über Einrückungen. Es ist also wichtig, dass von Anfang an darauf geachtet wird, Einrückungen immer sauber und vor allem einheitlich zu machen. Bei einer falschen Einrückung taucht in der Fehlermeldung das Wort Indent auf. Auch dürfen Blöcke nicht leer sein, da sonst die Einrückung nicht erkannt werden kann. Wenn man also Code schreibt und erst einmal etwas anderes implementieren möchte, dann schreibt man den Platzhalter pass in den Code. Bevor man Code auf den Roboter lädt, muss dieser getestet werden. Dazu muss das Programm in Thonny gestartet werden, damit man Fehlermeldungen und Debug-Nachrichten lesen kann. Wer ungetesteten Code hochlädt und dann erwartet, dass der Roboter funktioniert, ist selbst schuld. Eine Python-Datei wird auf dem Pico automatisch gestartet, wenn sie main.py heißt. Das bedeutet aber auch, dass das Programm gestartet wird, wenn man den Pico am Rechner über USB einsteckt. Das kann beim Testen zeitraubend sein, da man immer erst das Programm beenden muss. In der Testphase bietet es sich also an, einen anderen Namen für die Startdatei zu wählen. Elektronische Bauteile für den Roboterbau Die LED Die LED oder Leuchtdiode hat heute die Glühlampe fast vollständig verdrängt. Und das hat auch gute Gründe. Der Wirkungsgrad einer LED liegt bei 30–40 %. Der Wirkungsgrad einer Glühlampe liegt bei ca. 5 % ¹ . Das heißt, dass eine LED 30–40 % der eingesetzten Energie in Licht umwandelt. Eine normale Glühlampe ist damit zu 95 % eine Heizung und nur zu 5 % ein Leuchtmittel. Die LED ist damit immer noch nicht perfekt, aber das Beste, das es zurzeit für die Lichterzeugung gibt. Außerdem lebt sie länger als die Glühlampe, die aufgrund ihrer Konstruktion schnell altert. Die Polung der LED Eine LED muss richtig gepolt werden, um zu leuchten. Wird sie verpolt, kann sie dabei kaputtgehen. Das lange Beinchen heißt Anode und ist die positive Seite. Die kurze Seite ist die Kathode und die negative Seite oder Masse. Eine LED muss immer zusammen mit einem Widerstand geschaltet werden. Wie eine LED mit dem Pico an- und ausgeschaltet werden kann, steht hier Der Widerstand Der Widerstand ist dafür da, andere elektronische Bauteile vor Überlastung zu schützen. Es gibt ihn in mit sehr vielen verschiedenen Widerstandswerten. Diese sind mit einem Farbcode angegeben. Der Raspberry Pi Pico Der Pico ist das Herzstück des Roboters, denn er führt den Code aus, der den Roboter steuert. Der Pico wird mit Micropython programmiert, das eine kleinere Ausgabe des großen Pythons ist. Der Pico ist, wie die meisten elektronischen Teile, sehr empfindlich gegen Verpolung oder Überlastung oder Kurzschlüsse. Daher muss man immer sehr sorgfältig alle Verbindungen überprüfen, bevor eine Spannung angelegt wird. Detaillierter Pinout-Plan des Pico zum Download Er wird über einen Mikro-USB-Anschluss an den Computer angeschlossen. Als Entwicklungsumgebung benutzen wir Thonny . Um die Pin-Anschlüsse ansteuern zu können, muss zunächst aus der Bibliothek machine Pin importiert werden: from machine import Pin Nicht alle Pins haben dieselben Fähigkeiten. Welcher Pin was kann, steht im detaillierten Pinout-Plan. Generell sollten für den Roboterbau die angegebenen Pins verwendet werden. Diese sind auf jeden Fall geeignet für die benötigte Funktion und die Fehlersuche wird erleichtert, wenn man nicht jedes Mal auch die Zuordnung der Pins überprüfen muss. Der Transistor Das Schaltzeichen Transistoren gibt es in vielen verschiedenen Ausfertigungen. Dies ist ein Beispiel. Das heißt, mit einem Transistor kann man mit einer niedrigen Spannung eine größere Spannung regulieren. Das kann ein einfacher Schaltvorgang sein oder die relative Regelung einer Spannung. Damit ist der Transistor in seiner Grundfunktion ein Verstärker. In einer digitalen Schaltung wird der Transistor auch wieder nur an- oder ausgeschaltet. Die Regelung der Helligkeit einer LED oder der Geschwindigkeit eines Motors erfolgt genauso wie ohne Transistor. Für den Roboterbau werden wir nicht direkt mit einem Transistor arbeiten. Sie sind aber Teil fast aller Bauteile, die verwendet werden. Der Transistor ist die Grundvoraussetzung, dass es moderne Computer gibt. Ein Transistor ist ein elektronisches Halbleiter-Bauelement zum Steuern oder Verstärken meistens niedriger elektrischer Spannungen und Ströme. Er ist der weitaus wichtigste „aktive“ Bestandteil elektronischer Schaltungen, der beispielsweise in der Nachrichtentechnik, der Leistungselektronik und in Computersystemen eingesetzt wird. Besondere Bedeutung haben Transistoren – zumeist als Ein/Aus-Schalter – in integrierten Schaltkreisen, was die weit verbreitete Mikroelektronik ermöglicht. Die Bezeichnung „Transistor“ ist ein Kofferwort des englischen transfer resistor, was in der Funktion einem durch eine angelegte elektrische Spannung oder einen elektrischen Strom steuerbaren elektrischen Widerstand entspricht. Die Wirkungsweise ähnelt der einer entsprechenden Elektronenröhre, nämlich der Triode. Quelle: Wikipedia: https://de.wikipedia.org/wiki/Transistor Der Motortreiber Aktuelle Variante Dieser Motortreiber beinhaltet gleichzeitig einen Spannungswandler, der genau 5V Gleichspannung liefert. Vorherige Variante Dieser Typ Motortreiber ist häufiger mal durchgebrannt. Daher wurde er durch ein stärkeres Modell ersetzt. Der Spannungswandler Der Spannungswandler wird mittlerweile nicht mehr benötigt, da dieser im neuen Motortreiber integriert ist. Mit dem Spannungswandler können wir eine Gleichspannung in eine niedrigere Spannung umwandeln. Da wir für die Motoren 6-9V benötigen, der Pico und die elektronischen Komponentenn aber nur 3,3V - 5 V vertragen, betreiben wir den Roboter mit einer 9V Batterie und nutzen den Spannungswandler für den Pico. Der Pico wiederum stellt 3,3V für den Betrieb der anderen Teile bereit. Der Spannungswandler muss vor dem Anschluss an den Pico auf die richtige Spannung eingestellt werden. Dafür haben wir Spannungsmessgeräte. Das Wukong 2040 Board Das Wukong 2040 Board wird für die Roboter „Walky“ und „Crawly“ benötigt. Es bietet praktische Anschlüsse für bis zu 12 Servomotoren und 4 Motoren. Außerdem bietet es zwei farbige LEDs, zwei Druckknöpfe und einen Buzzer. Die Stromversorgung läuft über einen 3,7V-Akku, der in dem Board aufladbar ist. Als Gehirn dient natürlich wieder ein Raspberry Pi Pico. Der Drehgeber (rotary encoder) Grundlagen der Programmierung des Raspberry Pi Pico mit Micropython Schritt-für-Schritt-Anleitung, um einige der vielen Möglichkeiten des Picos kennenzulernen. LEDs schalten Die interne LED Der Pico hat eine interne LED, die folgendermaßen angesteuert werden kann: import time from machine import Pin #led=Pin("LED", Pin.OUT) # Für den Pico mit eingebautem WLAN led=Pin(25, Pin.OUT) # Für den Pico ohne WLAN led.value(1) time.sleep(1) led.value(0) Soll die LED unabhängig vom Programmablauf blinken, dann kann man das mit einem Timer realisieren. from machine import Pin,Timer # led=Pin("LED", Pin.OUT) # Für den Pico mit eingebautem WLAN led=Pin(25, Pin.OUT) # Für den Pico ohne WLAN timer = Timer() timer.init(freq=2, mode=Timer.PERIODIC, callback=lambda t: led.toggle()) Soll der Timer beendet werden, so kann man das mit dem Befehl timer.deinit() erreicht werden. Möchte man mehr Kontrolle haben oder komplexere Funktionen einbauen, dann geht das so: import time from machine import Pin,Timer # led=Pin("LED", Pin.OUT) # Für den Pico mit eingebautem WLAN led=Pin(25, Pin.OUT) # Für den Pico ohne WLAN led.value(1) time.sleep(1) led.value(0) def blink(timer): led.toggle() timer = Timer() Timer().init(freq=2, mode=Timer.PERIODIC, callback=blink) Ein Timer läuft auch nach dem Ende des Programms weiter. Also nicht wundern, wenn es weiter blinkt. Aufgabe: Die LED zum Blinken bringen. Eine externe LED Das war zwar schon spannend, aber nun wollen wir eine externe LED an den Pico anschließen. Dazu benötigen wir eine LED, einen 100 Ω Widerstand sowie zwei Kabel. Stecke die Schaltung genau so zusammen, wie abgebildet. Achte vor allem darauf, dass die LED richtig herum ist. Hier ist der dazugehörige Schaltplan: Externe LED mit Transistor Der Pico liefert an den Pins nur eine Spannung von 3,3 Volt und die Stromstärke ist auch nicht sehr hoch. Es ist leicht möglich, die Anschlüsse zu überlasten, zwar nicht mit nur einer LED, jedoch bleibt es dabei ja nicht. Daher müssen Transistoren verwendet werden. Es gibt zwei mögliche Schaltungen für die LED mit Transistor. Der Unterschied ist nur, ob die Schaltung auf Anoden- oder auf Kathodenseite geschieht. Regelung der Helligkeit Egal, ob du die LED mit oder ohne Transistor betreibst, so ist die Helligkeit bislang immer die gleiche. Glühlampen lassen sich sehr einfach dimmen, indem man die Spannung regelt. Bei der LED funktioniert das nicht, da die Spannung an der LED immer dieselbe ist. Die LED ist nämlich kein ohmsches Bauteil. Außerdem haben wir mit dem Pico die Schwierigkeit, dass er ein digitales Gerät ist und bekanntermaßen kennen digitale Geräte nur 1 und 0 oder an und aus. Wie lässt sich damit also die Helligkeit regulieren? Ampelschaltung mit LEDs Ampelschaltung Verwende die LED-Ampel, um eine Ampelschaltung zu programmieren. Schaltet dann mehrere Ampeln zu einer Kreuzung zusammen, indem ihr die Picos miteinander kommunizieren lasst. Dazu müsst ihr einen Pin auf dem Pico, der Befehle erhält, als Eingangspin definieren. Empfange Daten auf Pin 16 und blinke mit der internen LED from machine import Pin sensor=Pin(16, Pin.IN, Pin.PULL_UP) led=Pin(25, Pin.OUT) while True: while sensor.value(): led.value(1) led.value(0) Sende Daten mit Pin 15 und blinke mit der internen LED import time from machine import Pin #led=Pin("LED", Pin.OUT) # Für den Pico mit eingebautem WLAN led=Pin(25, Pin.OUT) # Für den Pico ohne WLAN sender=Pin(15,Pin.OUT) while True: led.value(1) sender.value(1) time.sleep(1) led.value(0) sender.value(0) time.sleep(1) Nur einer der beiden Picos muss über USB an Strom angeschlossen werden. Beide Programme werden unter dem Namen "main.py" auf dem Pico abgespeichert, dann laufen die Programme automatisch, sobald die Picos Strom bekommen. Zwei Ampeln koordinieren Code für den Sender from machine import Pin from time import sleep_ms red = Pin(10,Pin.OUT) yellow = Pin(11,Pin.OUT) green = Pin(12,Pin.OUT) trigger = Pin(15, Pin.OUT) wait = 800 phase = 3000 alarm_wait = 500 def go_red(): red.off() yellow.on() green.off() sleep_ms(wait) red.on() yellow.off() trigger.off() sleep_ms(wait*2) def go_green(): trigger.on() sleep_ms(wait*3) red.on() yellow.on() green.off() sleep_ms(wait) red.off() yellow.off() green.on() while True: go_red() sleep_ms(phase) go_green() sleep_ms(phase) Code für den Empfänger from machine import Pin from time import sleep_ms red = Pin(10,Pin.OUT) yellow = Pin(11,Pin.OUT) green = Pin(12,Pin.OUT) trigger = Pin(16, Pin.IN, Pin.PULL_UP) wait = 800 phase = 3000 alarm_wait = 500 def go_red(): red.off() yellow.on() green.off() sleep_ms(wait) red.on() yellow.off() def go_green(): red.on() yellow.on() green.off() sleep_ms(wait) red.off() yellow.off() green.on() while True: if trigger.value():# Wenn trigger == True go_red() while trigger.value(): pass if not trigger.value(): go_green() while not trigger.value(): pass Knopfsteuerung der Ampel Für die Programmierung eines Ampelknopfes, muss man den Knopf entprellen , damit keine Geisterbewegungen registriert werden. Ein minimales Codebeispiel ist dieses: from machine import Pin import time button = Pin(15, Pin.IN, Pin.PULL_DOWN) pressed = False num_pressed = 0 last_pressed = 0 DEBOUNCE_WAIT = 100 def button_handler(pin): global pressed, num_pressed, last_pressed #mit dem Befehl global teilt man Python mit, dass man die Variabel verwenden möchte, die außerhalb der Funktion initialisiert wurde. while utime.ticks_diff(utime.ticks_ms(), last_pressed) < DEBOUNCE_WAIT: # Hier wird verhindert,dass mehrere Auslösungen hintereinander registriert werden. pass last_pressed = utime.ticks_ms() if not pressed: while time.ticks_diff(time.ticks_ms(), last_pressed) < DEBOUNCE_WAIT: pass if pin.value() == 1: pressed=True #Damit kann im Programmablauf der Knopfdruck registriert werden. num_pressed +=1 print(pin.value(), "number presses: ", num_pressed) last_pressed = time.ticks_ms() pressed=False # Dies hier eher im weiteren Programmablauf verwenden. button.irq(trigger=Pin.IRQ_RISING, handler=button_handler) # Hier weiterer Programmablauf while True: pass Programmiergrundkurs in Python Der Motor Ein Motor wird genauso gesteuert wie eine LED. Man kann ihn entweder einfach an- und ausschalten, oder mithilfe der Pulsweitenmodulation die Geschwindigkeit regeln. Probiert es einfach einmal aus. Da ein Motor deutlich mehr Leistung hat als eine LED, kann man den Raspberry Pi Pico schnell überlasten. Daher betreiben wir den Motor nur über einen Transistor. Es sorgt dafür, dass das Steuersignal des Picos verstärkt von der 9V Batterie an den Motor geleitet wird. Aber Achtung: Der Motor ist für dauerhaft 6V ausgerichtet und sollte daher nicht zu lange mit 9V betrieben werden. Für diese Schaltung könnt ihr die Schaltung der LED mit Transistor ohne den Widerstand verwenden. Der Code für diese Steuerung ist genauso wie für eine LED. In dem Schaltbild wird der Pin 15 benutzt. Richtungssteuerung Wie könnte man nun die Drehrichtung des Motors ändern, ohne die Kabel umzustecken? Überlegt erst einmal und dann schaut ihr euch das nächste Bauteil an: AB Die H-Brücke Der Ultraschallsensor Schließt den Ultraschallsensor an den Pico an: Zur Ansteuerung des Ultraschalsensors wird die Roboterbibliothek benutzt. Der Infrarotsensor Der IR-Sensor wird folgendermaßen an den Pico angeschlossen. Der OUT-Pin kann natürlich auch geändert werden. So kann der Infrarotsensor ausgelesen werden: from machine import * import time # Der Pin für den Infrarotsensor wird initialisiert. ir=Pin(16,Pin.IN,Pin.PULL_UP) while True: print(ir.value()) #Es wird einmal der Wert ausgegeben, der am Pin anliegt. while ir.value() == 0: # Solange der Wert 0 bleibt, ändert sich die Anzeige nicht. time.sleep_ms(50) print(ir.value()) # Ist/Wird der Wert 1, wird erneut auf der Konsole ausgegeben. while ir.value() == 1: time.sleep_ms(50) # Solange der Wert 1 bleibt, ändert sich die Anzeige nicht. Für die Benutzung in den Robotern verwenden wir die Roboterbibliothek . Zusammenbau des SMARS-Roboters In diesem Kapitel werden die mechanischen Aufbauschritte erklärt. Die ursprüngliche Variante des SMARS-Roboters kann man von Thingiverse herunterladen. Die meisten Roboterteile im Unterricht sind von mir verändert worden. Diese kann man auch auf dieser Seite herunterladen. Das Steckbrett mit Raspberry Pi Pico und Abdeckplatte Es gibt verschiedene Varianten von Platten, auf denen das Steckbrett aufgeklebt ist. Aktuelle Variante Diese Variante ist für den „Theo III“!! In dieser Variante wird das Steckbrett quer aufgeklebt. Die Abdeckplatte wir von hinten in den Roboter eingeschoben. Ältere Varianten älteste Variante Die ältere Variante wird von oben auf das Gehäuse gesteckt. neuere Variante Die neuere Variante wird von hinten in das Gehäuse eingeschoben. Gehäuse und Räder Es gibt mehrere Varianten von Gehäusen für die SMARS-Roboter. Das aktuellste ist der „Theo III“. Theo III Ein neu gedrucktes Gehäuse enthält noch einige Stützstrukturen um die Halterungen für die passiven Räder und in dem Schlitz für den Schalter. Diese müssen zunächst entfernt werden. Das Gehäuse wird mit den passiven Rädern montiert ausgeteilt. Diese sollten nicht mehr entfernt werden, da das Gehäuse dabei brechen kann. Generell ist darauf zu achten, dass die Seitenwände nicht belastet werden, da sie schnell abbrechen können. Es gibt bei dem Gehäuse ein vorne und hinten. Hinter erkennt man an der Einprägung „Theo III“. Dort befindet sich auch der Schalter. Beim Einsetzen der Motoren ist darauf zu achten, dass der Motor mit den längeren Kabeln nach vorne kommt. Für die aktiven Räder müssen zunächst die Motoren eingesetzt werden. Im Idealfall rasten die Motoren ein und sind dann schon fest. Wenn der 3D-Druck ungenau war, kann es sein, dass die Motoren nur sehr schwer einrasten oder gar nicht. Die Löcher an den Rädern, in die die Motorwellen eingesteckt werden, haben, genau wie die Motorwellen, eine abgeflachte Seite. Diese müssen zusammengebracht werden. Es kann sein, dass die Motorwelle nicht passt. In diesem Fall muss das Loch vorsichtig erweitert werden. Hier kann es schnell passieren, dass das Loch zu groß wird. Dann hilft nur noch Klebstoff. Ältere Versionen Gehäuse für Kettenfahrzeug Das Gehäuse kann direkt nach dem Druck noch einige Rückstände der Stützstrukturen enthalten. Das bedeutet vor allem, dass die Löcher für die Motorwellen zu sind und dass die Aufnahme für die passiven Räder noch gesäubert werden müssen. Grundsätzlich muss man beim Entfernen von Material sehr vorsichtig sein, da man schnell zu viel weggenommen hat. Als Erstes sollten die passiven Räder aufgesteckt werden. Dazu wird das Gehäuse hochkant flach auf die Tischfläche gelegt und dann werden die Räder aufgesteckt. Dies kann sehr schwer sein. Da die Gehäuse leicht brechen können, muss man darauf achten, keinen Druck auf die oberen Ränder auszuüben. Sind die Räder erst einmal aufgesteckt, sollten sie nicht mehr entfernt werden. Gehäuse für Gummireifenfahrzeug Diese Gehäuse sollten sofort einsatzbereit sein. Dennoch sollte man vorher schauen, ob es noch irgendwo Überbleibsel von Stützstrukturen gibt, die vorher entfernt werden sollten. Die passiven Räder haben keine Gummireifen und werden mithilfe von kurzen Stiften auf den Achsen befestigt. Aktive Räder an beiden Gehäusetypen Die 9V-Batterie wird zwischen die Motoren gelegt. Der Clip sollte auch schon befestigt werden. Dabei ist darauf zu achten, dass sich die blanken Kabelenden nicht berühren können (Isolierband). Die Kabel der Motoren sollten durch die Halterungen für die 9V-Batterie geführt werden. Damit kann der SMARS Roboter schon auf eigenen Rädern stehen. Anschluss der Motoren Folgende Verbindungen werden benötigt, um die Motoren zum Laufen zu bringen: Die 9V Batterie versorgt die Motoren mit Strom. Die vier Datenkabel IN1, IN2, IN3, IN4 steuern den Motor. Dabei sind IN1 und IN2 für den einen und IN3 und IN$ für den anderen Motor zuständig. Diese steuern die Brückenschaltung im Motortreiber. Die Richtungssteuerung erfolgt, indem die Signale an den Pins vertauscht werden. Ein Pin muss aus sein, der andere ist an. Wird dieser mithilfe der PWM-Modulation gesteuert, lässt sich auch die Geschwindigkeit regulieren. Hierfür kann dann die Bibliothek für die Motorsteuerung in der robotlibrary benutzt werden. Der Ultraschallsensor Der Ultraschallsensor wird von oben in die Halterung geschoben und danach wird das Gehäuse von vorne aufgesteckt. Die beiden Augen des Sensors schließen dann bündig mit dem Gehäuse ab. Die Halterung wird dann von oben auf das Gehäuse vorne oder hinten aufgeschoben und die Anschlüsse für die Kabel müssen nach oben geführt werden. Für den Betrieb des Ultraschallsensors verwendet man eine Bibliothek . Diese ist in der robotlibrary enthalten. Für die neueste Version des Roboters (Theo III) gibt es verschiedene Varianten von Halterungen, die ein Verstellen und alternative Befestigungen ermöglichen. Der komplette Roboter Komplett zusammengebaut sollte der Roboter dann so aussehen (schematische Darstellung): Neueste Version (Theo III) Grundsätzlich müssen alle Bauteile auf die richtige Polung überprüft werden. Es reicht nicht, alles so zu stecken, wie es auf dem Schaubild steht, da es beim Steckbrett und den Bauteilen Abweichungen geben kann. Beim Verpolen gehen die Bauteile schnell kaputt und die Batterie läuft leer. Deshalb lohnt es sich, alles gut zu überprüfen! Ältere Version des Roboters (v1 und v2) Der Kettenantrieb Die Kette ist das mechanisch komplizierteste Element des SMARS-Roboters. Die einzelnen Kettenglieder (16 Stück pro Seite) werden mit Stücken von Filament zusammengesetzt. Dabei ist darauf zu achten, dass die Stücke nicht seitlich herausgucken und am Gehäuse hängenbleiben können. Eines könnte ein Stück heraus stehen bleiben, um die Kette einfacher aufmachen zu können. Die Kette darf weder zu stramm noch zu locker sein. Eine zu kurze Kette zieht die Räder zusammen und der Motor kann diese Reibung nicht überwinden. Eine zu lockere Kette spurt leicht aus und setzt sich dann auf die Rauten auf den Rädern. Dann wird die Spannung auch zu stark. Es kann eine ganze Weile dauern, bis man eine gut funktionierende Kette zusammengebaut hat. Außerdem werden sich die beiden Ketten nicht gleich schnell drehen, da die Motoren nicht miteinander synchronisiert sind. Hier kann man versuchen, die beiden Seiten mit unterschiedlichen Geschwindigkeiten zu betreiben, bis der Roboter möglichst geradeaus fährt. Unterschiedlich lange Kettenglieder Um die Kettenlänge anzupassen, gibt es unterschiedlich lange Kettenglieder. Diese sollten eins nach dem anderen in die Kette eingefügt werden, bis die richtige Länge erreicht ist. Zuviele Kettenglieder, die nicht die Standardlänge haben, können auch zu Problemen führen, da sie nicht mehr passgenau auf den Rädern sitzen. Normale Länge Die normal langen Kettenglieder sind an der vorderen Kante rechtwinklig geschnitten. kürzere Länge Die etwas kürzeren Kettenglieder haben auf der linken Seite eine Fase. längere Länge Und die längeren Kettenglieder sind rechts gefast. Elastische Kette Alternativ gibt es auch Ketten aus TPU, die elastisch sind. Erweiterungen Messung der Batteriestärke Den Spannungsteiler kann man verwenden, um den Ladestand der Batterie zu messen. Dazu muss die Spannung unter 3,3V gebracht werden, um die Pins des Picos nicht zu beschädigen. Dazu werden zwei Widerstände mit den richtigen Werten in Reihe geschaltet und die Spannung zwischen den Widerständen und Masse über einen Analog-Digital-Wandler gemessen. Beim Pico sind das die Pins 26, 27 und 28. Ein ADC-Pin wird folgendermaßen initialisiert: from machine import ADC batt_pin = ADC(28) while True: print(batt_pin.read_u16()) Nun muss man nur noch den zurückgelieferten Wert einer neuen Batterie messen und den Wert, wenn sie nicht mehr ausreichend Energie liefert. Dann kann man z. B. einen Alarm ausgeben oder die Funktionen des Roboters anpassen. Die robotlibrary stellt auch hierfür eine Methode in der Klasse Robot bereit. Das Universal Robotics Board (urb) Statt eines Steckbretts kann nun auch eine Platine, das universal robotics board (urb) genutzt werden. Auf der Platine finden sich geeignete Anschlüsse sowohl für den Theo III als auch für die Laufroboter. Damit gibt es weniger Kabelsalat. Zur Beachtung Die acht Steckplätze für Servomotoren P0–P7 können mit 5V oder mit 9V beschaltet werden. Normale Servomotoren laufen alle mit bis zu 6V. Daher muss darauf geachtet werden, dass der Jumper auf 5V gesteckt wird. Für Projekte, die eine höhere Spannung für Motoren erfordern, kann auf die Versorgungsspannung der Batterie umgeschaltet werden (normal 9V). Die Steckplätze für die Grundausstattung eines Roboters sind gesondert bezeichnet mit ML, MR, US, also den beiden Motoren und dem Ultraschallsensor. Natürlich können auch andere Pins benutzt werden. Beim Anschluss der Stromversorgung muss unbedingt auf die richtige Polung und Spannung geachtet werden! Der Zusammenbau Crawlys Crawly ist ein Roboter, der ähnlich wie eine Krabbe kriecht, aber mit nur vier statt acht Beinen.  Die Herausforderung liegt bei Crawly in der Gestaltung eines natürlichen Gangs.  Der komplette Crawly Komplett zusammengebaut sieht Crawly so aus. Der Prototyp des Bewegungsablaufs sieht so aus: Zusammenbau der Beine An den Beinen muss eventuell die Unterstützungsstruktur des 3D-Drucks noch entfernt werden. Das Bild oben zeigt, wie die Teile zusammengesetzt werden müssen. Bevor die Beine auf die Motorachsen gesetzt werden, müssen die Motoren noch auf einen Winkel von 90° eingestellt werden. Dazu kann die Methode calibrate() in der Klasse Crawly benutzt werden. Diese dreht jeden Motor auf 0°, gefolgt von 90°. Damit kann gleichzeitig überprüft werden, ob der Motor auch funktioniert. 2 Beine am Gehäuse befestigen Der Schenkel muss wie eine Klammer auf den Servomotor gesetzt werden. Dabei aufpassen, dass nicht zu viel Druck ausgeübt wird. 3 Anschlüsse und Software Es ist sinnvoll, die Servomotoren in einer vernünftigen Reihenfolge anzuschließen. Ich habe mit dem Bein links hinten angefangen (Pin 0) und bin dann im Uhrzeigersinn vorgegangen. Dabei kam der Hüftmotor immer vor dem Kniemotor. Bibliotheken für die verschiedenen Teile des Roboters mit Beispielcode für eine Vorwärtsbewegung sind in der robotlibrary integriert. Um eigene Funktionen zu implementieren, können wieder Methoden überschrieben werden, genauso wie bei den SMARS-Robotern. Zusammenbau von Walky Der komplette Walky Komplett zusammengebaut sieht Walky so aus: Der Prototype des Bewegunsablaufs sieht so aus: Der Code für Walky in der robotlibrary ist in einer sehr rudimentären Version. 1 Zusammenbau der Beine 2 Beine am Gehäuse befestigen 3 Anschlüsse und Software Weitere Robotikprojekte Linienverfolger Bau eines Roboters, der eine schwarze Linie auf dem Boden verfolgt. Dies kann der SMARS Roboter aber Ziel könnte es sein, einen schnelleren Roboter zu bauen. Dazu kann ein PID-Regler benutzt werden. Der Roboter hat zwei Motoren, die beide die hintere Achse bilden. Vorne schleift der Roboter nur auf einem Knopf. Er ist damit sehr gelenkig und vor allem die Vorderseite kann sich schnell bewegen. Ziel ist es, einen Algorithmus zu finden, der die Lenkung einerseits sehr schnell macht, andererseits aber auch verhindert, dass die Lenkung überkompensiert. So ein Algorthmus könnte der PID-Controller sein. In der Roboterbibliothek ist ein solcher PID-Controller vorhanden, der hierfür benutzt werden kann. Die Schwierigkeit ist es, diesen sinnvoll zu konfigurieren und auf die Lenkung anzuwenden. PID-Controller auf Wikipedia Programmierung der Roboter Micropython Software-Bibliotheken für den Betrieb der Roboter. Die Roboterbibliothek "robotlibrary" Dieses Modul, das von Codeberg 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. Oder hier ein Beispiel für die Benutzung des Servomotors. from robotlibrary.robot import Robot from time import sleep,sleep_ms try: r = Robot(False) r.set_angle(0) sleep_ms(500) r.set_angle(180) sleep_ms(500) r.set_angle(90) r.set_speed(80) while True: while r.get_dist() > 15: pass r.emergency_stop() sleep_ms(400) r.set_speed_instantly(80) r.spin_before_obstacle(20) r.set_forward(True) r.set_speed(80) except: r.emergency_stop() print("Robot stopped") 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. Under construction: 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 Dokumentation Documentation for robotlibrary/robot.py Robot This is the central class which manages and uses all the other components of the robot. The parameters are defined in config.py _drive This abstracted driving function is only called locally by the other functions with better names. It accelerates and decelerates to make driving more natural. Do not call directly! _drive_instantly This abstracted driving function is only called locally by the other functions with better names. It sets the speed immediately. Do not call directly! set_speed_instantly Sets the new speed immediately. Doesn't change the driving mode of the robot. :param s: the speed you want to set. set_speed Sets the new speed and accelerates and decelerates. Doesn't change the driving mode of the robot. :param s: the speed you want to set. set_forward Sets the direction of the robot. True means forward. :param f: True for forwards and False for backwards. spin_right Spin right indefinitely. spin_left Spin left indefinitely. turn_right This turns the robot to the right without it spinning on the spot. Each call makes the turn steeper. turn_left This turns the robot to the right without it spinning on the spot. Each call makes the turn steeper. go_left With Meccanum wheels the robot goes sideways to the left. go_right With Meccanum wheels the robot goes sideways to the right. turn This turns the robot right or left. Is mostly used by the remote control. :param turn: positive or negative value. Higher values mean steeper turn. go_straight Lets the robot go straight on. Usually called when a turn shall end. spin_before_obstacle This spins until the distance to an obstacle is greater than the given parameter distance . :param distance: The distance toggle_spin Toggle turn for the given duration. With each call the opposite direction(clockwise / anti-clockwise) is used. :param d: The duration for the turn in milliseconds. random_spin Randomly turn for the given duration. :param d: The duration for the turn in milliseconds. stop Stop the robot slowly by deceleration. emergency_stop Stop the robot immediately. ir_detected If implemented this method is called when the IR-sensor has detected a change. Fill in your code accordingly. get_dist Get the distance from the ultrasonic sensor. set_angle If implemented, turn the servo motor with the ultrasonic sensor to the given angle. :param a: The angle that is to be set. get_smallest_distance This returns the angle of the ultrasonic sensor where it measured the smallest distance get_longest_distance This returns the angle of the ultrasonic sensor where it measured the longest distance Documentation for robotlibrary/config.py Module This defines the parameters for the motors. MAX_DUTY: Set to lower than the maximum not to overload the motors. Absolute maximum is 65535. MIN_DUTY: Set this to the minimum duty cycle that the motor needs to start moving. MIN_SPEED: Only 0 is making sense here but if you want you can change that. Must be above 0 though. MAX_SPEED: If you want another scale than 0-100, set the maximum here. DEBOUNCE_WAIT: This defines the waiting time for the debouncing of the buttons. Leave as it is if you don't know what it means. WHITE_DETECTED: Use these constants to check for white or black with the IR-sensor. Don't change! BLACK_DETECTED: Use these constants to check for white or black with the IR-sensor. Don't change! Motors and ultrasonic sensor must use consecutive pins. so, f. ex. the left motor uses pins 12 and 13. Use >None< if you don't use the device. MLF and LRF are for four wheel drive. ML: pin number for left motor (or left rear motor for four wheel drive). MR: pin number for right motor (or right rear motor for four wheel drive). MLF: pin number for left motor (or left front motor for four wheel drive). Use None if not used. MRF: pin number for right motor (or right front motor for four wheel drive). Use None if not used. US: pin number for the ultrasonic sensor. Use None if not used. IR: pin number for the infrared sensor. Use None if not used. SERVO: pin number for the servo motor. Use None if not used. JS_X_MEDIAN JS_Y_MEDIAN JS_MAX_DUTY JS_MIN_DUTY: These define the parameters for the joystick. You need to calibrate the numbers. Look at joystick.py for details. ROBOT_NAME: You need to set a custom name if you use a remote control. SERVO_MIN_DUTY: Only change if the servo doesn't move the required 180°. SERVO_MAX_DUTY: Only change if the servo doesn't move the required 180°. Codebeispiele Theo III Best Practise Ausschalten der Motoren bei Unterbrechung des Programms Anfangs wird man sehr viel an dem Roboterprogramm testen müssen. Dabei wird das Programm dann häufig abstürzen. Damit die Motoren nicht weiter in dem Zustand laufen, in dem sie dabei geschaltet waren, kann man mit einem try/except arbeiten: try: # Hier läuft das Programm except Exception as err: print(err) # Nötig, um Fehlermeldungen angezeigt zu bekommen. r.emergency_stop() # Roboter anhalten, hier ein Beispiel mit der robotlibrary. print("Robot stopped") # Damit es ganz deutlich ist. except KeyboardInterrupt: r.emergency_stop() print("Keyboard interrupt") 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. Ein Beispiel für die Glättung der Entfernungswerte aus dem Ultraschallsensor: us = Ultra(16) dist_values = deque([0,0,0,0,0],5) while True: d = us.get_dist() dist_values.append(d) d = sum(dist_values)/len(dist_values) print(f"Entfernung: {d} cm") Eine andere Methode muss für das Auslesen des Infrarotsensors gefunden werden. Hier könnte man z.B. eine kurze Wartezeit einbauen und dann abfragen, ob der Sensor immer noch denselben Wert liefert wie bei Auslösung der Reaktion. Überschreiben von Methoden aus der Bibliothek Möchte man die Funktion einer Methode aus der Roboterbibliothek (robotlibrary) verändern, kann man die Methode überschreiben (Fachbegriff aus der objektorientierten Programmierung). Dafür wird die Klasse Robot vererbt, wie in dem Codebeispiel angegeben. Möchte man nun z.B. die Methode set_speed() verändern, dann definiert man sie einfach neu. Ist eine Methode nicht in der abgeleiteten Klasse (in diesem Fall MyRobot definiert, dann wird die Methode der Elternklasse ( Robot ) genommen. Probiere es aus, indem du das vorliegende Programm einmal mit und einmal ohne die Definition von set_speed() aufrufst. from robotlibrary.robot import Robot from time import sleep, sleep_ms class MyRobot(Robot): def __init__(self): super().__init__(False) print("start") def set_speed(self,x): print(f"Child method set_speed. Value: {x}") def main(): try: robot = MyRobot() robot.set_speed(90) while True: sleep(1) except KeyboardInterrupt: print("The robot was stopped by the user.") finally: robot.emergency_stop() if __name__ == "__main__": # execute only if run as a script main() Den Ultraschallsensor im Hintergrund laufen lassen In komplexeren Programmen kann es lästig werden, immer wieder die Entfernung zum nächsten Hindernis zu überpüfen. Dieses Beispiel erläutert, wie man das Problem löst, indem man die Entfernungsmessung in den Hintergrund verlegt. Dieses Beispiel vereint alle vorgestellten Techniken und sollte als Standard-Startdatei genutzt werden. from time import sleep, sleep_ms import uasyncio as asyncio from robotlibrary.robot import Robot ################################## Your class definition class MyRobot(Robot): def __init__(self): super().__init__(False) # Call the original constructor. print("Start MyRobot") # With this method defined here, the robot will not drive as the speed is not set in this function. # This is to illustrate how overwriting works. def set_speed(self,x): print(f"Child method set_speed. Value: {x}") ################################# End of class definition # Define functions for your program async def monitor_dist(): '''This checks the distance from the ultrasonic sensor continually. If the given distance is longer than the measured one, react_to_obstacle() will be called. ''' global distance while True: if robot.get_dist() < distance: react_to_obstacle() await asyncio.sleep_ms(100) def react_to_obstacle(): '''Do whatever you want to do when an obstacle is detected. ''' global distance robot.random_spin(300) robot.set_forward(True) robot.set_speed(80) async def driving_program(): robot.set_speed(90) while True: print("Driving program running.") await asyncio.sleep_ms(3000) async def main(): asyncio.create_task(monitor_dist()) await driving_program() ################################# Initialize the robot and start the program. robot = MyRobot() distance = 20 # Define the distance you want to have. if __name__ == "__main__": # execute only if run as a script try: asyncio.run(main()) except KeyboardInterrupt: print("The robot was stopped by the user.") finally: robot.emergency_stop() Beschleunigung mit Entfernungsmessung Diese Methode ist nur nötig, wenn man nicht asyncio benutzt. Beschleunigt man den Roboter langsam mit der Methode set_speed , dann kann er in der Zeit bis zum Erreichen der Geschwindigkeit keine Entfernungsmessung durchführen. Dies ist ein Beispiel, wie man beides erreichen kann: 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 Mit einem Timer arbeiten Diese Programmiertechnik könnte man z. B. nutzen, um nach einer bestimmten Zeit in das Programm einzuschalten, falls der Roboter zu lange dieselbe Funktion, z. B. vorwärts fahren, ausführt. Dann würde der Zähler zu gegebener Zeit eine Änderung herbeiführen können. from machine import Pin,Timer import time def do_something(t): print("do something!") def main(): timer = Timer() timer.init(period=1500, mode=Timer.PERIODIC, callback=do_something) while True: print("Running...") time.sleep_ms(700) if __name__ == "__main__": # execute only if run as a script main() Startdatei für den SMARS-Roboter Kopiere den Code und speichere die Datei als main.py auf dem Pico . from time import sleep, sleep_ms import uasyncio as asyncio from robotlibrary.robot import Robot ################################## Your class definition class MyRobot(Robot): def __init__(self): super().__init__(False) # Call the original constructor. print("Start MyRobot") # With this method defined here, the robot will not drive as the speed is not set in this function. # This is to illustrate how overwriting works. def set_speed(self,x): print(f"Child method set_speed. Value: {x}") ################################# End of class definition # Define functions for your program async def monitor_dist(): '''This checks the distance from the ultrasonic sensor continually. If the given distance is longer than the measured one, react_to_obstacle() will be called. ''' global distance while True: if robot.get_dist() < distance: react_to_obstacle() await asyncio.sleep_ms(100) def react_to_obstacle(): '''Do whatever you want to do when an obstacle is detected. ''' global distance robot.random_spin(300) robot.set_forward(True) robot.set_speed(80) async def driving_program(): robot.set_speed(90) while True: print("Driving program running.") await asyncio.sleep_ms(3000) async def main(): asyncio.create_task(monitor_dist()) await driving_program() ################################# Initialize the robot and start the program. robot = MyRobot() distance = 20 # Define the distance you want to have. if __name__ == "__main__": # execute only if run as a script try: asyncio.run(main()) except KeyboardInterrupt: print("The robot was stopped by the user.") finally: robot.emergency_stop() Startdatei für Crawly Um den Bewegungsablauf für Crawly anders als in der Bibliothek zu machen, können auch hier die entsprechenden Klassen überschrieben werden. from time import sleep, sleep_ms from robotlibrary.crawly import Crawly from robotlibrary.crawly_leg import Leg from robotlibrary.crawly_joint import Joint from robotlibrary import config_crawly as conf from robotlibrary.servo import Servo ################################## Your class definition class MyCrawly(Crawly): def __init__(self): self.legs = { "front_right" : MyLeg(4, True, True, "front right"), "rear_right" : MyLeg(6, True, False, "rear right"), "rear_left" : MyLeg(0, False, False, "rear left"), "front_left" : MyLeg(2, False, True, "front left") } def galumph(self): for l in self.legs.values(): l.leg_fully_up() sleep_ms(150) for l in self.legs.values(): l.leg_fully_forward() sleep_ms(150) for l in self.legs.values(): l.leg_fully_down() sleep_ms(150) for l in self.legs.values(): l.leg_fully_backward() sleep_ms(150) class MyLeg(Leg): def __init__(self, pin, right, front, name): if right and front: self.shoulder = MyJoint(conf.SHOULDER_FRONT, name, False, False, pin) if right and not front: self.shoulder = MyJoint(conf.SHOULDER_REAR, name, False, False, pin) if not right and front: self.shoulder = MyJoint(conf.SHOULDER_FRONT, name, True, False, pin) if not right and not front: self.shoulder = MyJoint(conf.SHOULDER_REAR, name, True, False, pin) self.knee = MyJoint(conf.KNEE, name, False, True, pin+1) class MyJoint(Joint): def __init__(self, j_type, name, left_side, inverted, pin): self.name = name self.j_type = j_type min_duty = conf.SERVO_MIN_DUTY max_duty = conf.SERVO_MAX_DUTY self.left_side = left_side if j_type == conf.SHOULDER_FRONT: self.__min_angle = conf.SHOULDER_FRONT_MIN_ANGLE self.__max_angle = conf.SHOULDER_FRONT_MAX_ANGLE elif j_type == conf.SHOULDER_REAR: self.__min_angle = conf.SHOULDER_REAR_MIN_ANGLE self.__max_angle = conf.SHOULDER_REAR_MAX_ANGLE elif j_type == conf.KNEE: self.__min_angle = conf.KNEE_MIN_ANGLE self.__max_angle = conf.KNEE_MAX_ANGLE # min_duty = conf.SERVO_MIN_DUTY_TYPE2 # Comment out if the duty cycle is different from the shoulder servo's duty cycle. # max_duty = conf.SERVO_MAX_DUTY_TYPE2 # Comment out if the duty cycle is different from the shoulder servo's duty cycle. self.servo = Servo(pin, inverted, min_duty, max_duty) ################################# End of class definition def move_program(): crawly.move_to_start_pos() for i in range(10): crawly.galumph() def main(): move_program() ################################# Initialize the robot and start the program. crawly = MyCrawly() if __name__ == "__main__": # execute only if run as a script try: main() except KeyboardInterrupt: print("The robot was stopped by the user.") finally: crawly.park() Hier wurden schon alle drei Hauptklassen des Crawly-Roboters überschrieben. Die anderen Methoden in den Klassen können bei Bedarf auch überschrieben werden. Fehlerbehebung Motoren Motoren drehen sich nicht oder nur sehr schwer Bei Kettenrobotern: Die Ketten sind zu stramm oder zu locker Wenn die Ketten zu stramm sind, dann hat der Motor nicht genügend Kraft sich zu drehen. Ein Anzeichen dafür ist, wenn die Räder von der Ketten zusammengezogen werden, sodass die Achsen auf einer Seite nicht parallel sind. In diesem Fall sollten längere Kettenglieder eingefügt werden, bis die Kette gut sitzt. Sind die Ketten zu locker, kann die Kette aus der Führung springen und auf den Führungsknubbeln aufsitzen. Dann muss die Kette wieder strammer gemacht werden. Die Motoren drehen sich auch ohne Kette nicht Drehen sich beide Motoren nicht, kann es sein, dass die Stromversorgung nicht richtig angeschlossen ist. Es ist unbedingt darauf zu achten, dass der Motortreiber nicht falsch herum gepolt wird. Dreht sich nur ein Motor nicht, ist zunächst zu überprüfen, ob die Steuerpins auch korrekt mit dem Motortreiber verbunden sind. Ist dies der Fall, dann sollte überprüft werden, ob an den Anschlüssen für den Motor auch eine Spannung anliegt. Ist dies nicht der Fall, ist der Motortreiber eventuell kaputt. Ein Motor dreht sich immer falsch herum Die Steuerpins sind verpolt Der Motor ist am Motortreiber verpolt. Es ist ein Fehler im Code Es ist grundsätzlich sinnvoll, die Verkabelung der Steuerpins zu vertauschen, da man hierfür nicht mit dem Schraubendreher arbeiten muss. Das Ergebnis ist dasselbe. Sobald der Pico Strom bekommt, dreht sich ein Motor und hört auch nicht mehr auf Der Pico ist womöglich beschädigt. Diesen mit dem Testprogramm und der Testplatine auf korrekte Funktion überprüfen. Testprogramm from machine import Pin, PWM import utime # Bestimme, welche Pins getestet werden sollen. Die Platine hat sieben LEDs. Somit können 7 Pins gleichzeitig getestet werden. p_start = 11 p_end = 16 pins = list() for i in range(p_start,p_end): pins.append(PWM(Pin(i))) # Die LEDs werden initialisiert. Hier nichts ändern. #leds=[PWM(Pin(pins[0], Pin.OUT)), PWM(Pin(pins[1], Pin.OUT)), PWM(Pin(pins[2], Pin.OUT)), PWM(Pin(pins[3], Pin.OUT)), PWM(Pin(pins[4], Pin.OUT)), PWM(Pin(pins[5], Pin.OUT)), PWM(Pin(pins[6], Pin.OUT))] # PWM Frequenz wird eingerichtet. print("Der Test beginnt.") for p in pins: p.freq(2000) # Zu Beginn werden alle LEDs ausgeschaltet. for p in pins: p.duty_u16(0) # Die LEDs werden einzeln langsam aufgeblendet und abgeblendet. Gehen Sie ruckartig an und aus, dann ist PWM defekt. for p in pins: for i in range (65535): p.duty_u16(i) for i in range (65535, 0, -1): p.duty_u16(i) utime.sleep_ms(800) # Alle LEDs blinken dreimal schnell hintereinander for x in range(3): for p in pins: p.duty_u16(65535) utime.sleep_ms(100) for p in pins: p.duty_u16(0) utime.sleep_ms(100) # Alle LEDs werden auf einer niedrigen Helligkeitsstufe angeschaltet und bleiben an. for p in pins: p.duty_u16(10000) print("Der Test ist fertig.") Der Ultraschallsensor funktioniert nicht Der Ultraschallsensor funktioniert am besten, wenn das Hindernis aus einem harten Material besteht, dass den Schall gut reflektieren kann. Ebenso kann es sein, dass das Hindernis sehr schräg steht und damit den Schall in eine andere Richtung reflektiert. Der SMARS reagiert nicht auf Hindernisse. In diesem Fall ist zunächst zu prüfen, ob auf Softwareseite alles in Ordnung ist. Zum Beispiel könnte der Code einer anderen Gruppe getestet werden, bei denen es funktioniert. Im nächsten Schritt sollte der Ultraschallsensor getestet werden. Dazu muss das Messprogramm von Thonny aus gestartet werden, damit die Messergebnisse angezeigt werden. Werden keine Messergebnisse gezeigt, dann zum nächsten Schritt. Es muss überprüft werden, ob die Pins für Trigger und Echo auch nicht vertauscht sind. Die beiden Pins lassen sich ohne Gefahr für den Pico vertauschen, sie funktionieren aber natürlich nur, wenn sie richtig herum sind. Funktioniert der Ultraschallsensor bei Start des Programms über Thonny aber nicht beim autonomen Start, dann muss überprüft werden, ob der Kondensator auch an der richtigen Stelle steckt. Wird das Programm als main.py ohne Thonny ausgeführt, kann es sein, dass der Code Fehler enthält, wenn er nicht vorher gut getestet war. Dann stürzt das Programm natürlich ab und es sieht nur so aus, als ob der Ultraschallsensor nicht funktionieren würde. In einigen Fällen hat der Ultraschallsensor auch Funktionsstörungen, die nach einigen Minuten Pause wieder behoben sind. 3D-Konstruktionsdateien für die Roboter Die Dateien für "Theo III" sind nicht mit der originalen Version des SMARS-Roboters kompatibel, da das Gehäuse leicht verändert wurde. Die Dateien (.FCSTD) sind mit dem Programm "Freecad" zu bearbeiten. Die Halterungen für "Theo III" sind mit den anderen Robotern "Crawly" und "Walky" kompatibel.  STL-Dateien können direkt in einem Slicer für den Druck auf einem 3D-Drucker vorbereitet werden.  Gute Tutorials für die Benutzung des Programms Freecad gibt es z.B. hier: https://www.youtube.com/@stolz3d   SMARS Roboter Das Chassis (Theo III) Das Chassis für Theo III Das Modell enthält die nötigen Stützstrukturen und muss daher ohne weitere Stützstrukturen gedruckt werden. Diese Version des Roboters hat etwas stärkere Vorder- und Rückseiten und einen Schlitz für einen Schalter. Des Weiteren stehen die Räder 2 mm näher zusammen, was reichen sollte, um die Kettenspannung genügend zu reduzieren, damit sich die Motoren frei drehen können. Es könnte eher das Problem sein, dass die Ketten zu locker sind. Die Steckbrettplatte für den Theo III Auf der Steckbrettplatte werden das Steckbrett und der Motortreiber befestigt. Der Druck erfolgt ohne Stützstrukturen. Steckbrettplatte für Theo III Konstruktionsdatei für den Ultraschallsensor-Halter Der Druck erfolgt ohne Stützstrukturen. Gehäuse für den Ultraschallsensor (Theo III) Halterung für den Ultraschallsensor (Theo III) Ultraschallhalter für allgemeinen Halter Konstruktionsdatei für den IR-Sensor-Halter: Der Druck erfolgt ohne Stützstrukturen. Die beiden Teile müssen korrekt auf der Druckplatte ausgerichtet werden. Dazu wird der allgemeine Halter benötigt. IR sensor Für diejenigen, die den IR-Halter selbst konstruieren wollen: Hier ist eine Konstruktionsskizze, die man benutzen kann: Konstruktionsskizze Konstruktionsdatei für den Motor- und Batteriehalter Motor- und Batteriehalter Bemaßungen für Motor- und Batteriehalter Allgemeine Halter Allgemeiner Halter Allgemeiner Halter hoch Allgemeiner Halter hinten Halterung für Servomotor Bemaßung der Halterung für eigene Designs. Selbst konstruierte alternative Teile für den Theo III Alternativ können auch folgende Bauteile genommen werden, die auch verändert werden können. TPU-Kette Kettenglied Aktives Rad Passives Rad Crawly Freecad Konstruktionsdateien Crawly Halterung gerade Crawly Halterung schräg (druckt nicht gut) Crawly Schuhe (Drucken in TPU) Crawly Oberschenkel Crawly Chassis Crawly Unterschenkel