Ein Roboter mit bürstenlosem Antrieb, differenzial und NRF24L01 Funk. Großflächig gebaut um ein großes Solarpanel aufzunehmen. https://gitlab.informatik.hs-fulda.de/fdai5253/roboter
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

606 lines
41 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. %---------------------------------------------
  2. % Lachaise Assignment
  3. % LaTeX Template
  4. % Version 1.0 (26/6/2018)
  5. %
  6. % This template originates from:
  7. % http://www.LaTeXTemplates.com
  8. %
  9. % Authors:
  10. % Marion Lachaise & François Févotte
  11. % Vel (vel@LaTeXTemplates.com)
  12. %
  13. % License:
  14. % CC BY-NC-SA 3.0 (http://creativecommons.org/licenses/by-nc-sa/3.0/)
  15. %
  16. %---------------------------------------------------
  17. %----------------------------------------------------------------------------------------
  18. % PACKAGES AND OTHER DOCUMENT CONFIGURATIONS
  19. %----------------------------------------------------------------------------------------
  20. \documentclass{article}
  21. % Include the file specifying the document structure and custom commands
  22. \input{structure.tex}
  23. \usepackage{hyperref}
  24. \usepackage[utf8]{inputenc}
  25. \usepackage{caption}
  26. %----------------------------------------------------------------------------------------
  27. % INFORMATION
  28. %----------------------------------------------------------------------------------------
  29. % Title
  30. \title{Open Source Roboter Plattform}
  31. \author{Lukas Reichwein\\ Yves Ehrlich\\ Nick Gnoevoj}
  32. \date{University of Applied Science Fulda --- \today}
  33. %----------------------------------------------------------------------------------------
  34. \begin{document}
  35. \maketitle % Print the title
  36. \tableofcontents % Inhaltsverzeichniss, Achtung zweimal Compilerien!
  37. %\newpage
  38. %----------------------------------------------------------------------------------------
  39. % INTRODUCTION
  40. %----------------------------------------------------------------------------------------
  41. \section{Vorwort} % Unnumbered section
  42. \paragraph{Motivation: }
  43. Eine Plattform bieten ist etwas, das momentan sehr stark im Trend liegt, sei es im Software oder im Hardware Bereich. Im Softwarebereich zeigt sich dies meist durch Open-Source Bibliotheken, welche möglichst variabel einsetzbaren Code für jeden frei zugänglich machen.
  44. Ein solches Projekt war auch von einem der Projektmitglieder (Yves Ehrlich) als Privates Projekt geplant und so kam die Überlegung dies innerhalb des Modules Embedded Networking zu wählen.
  45. \paragraph{Basis des Projektes: }
  46. Als Basis des Projektes dient einer schon bereits von Yves Ehrlich angefertigter Arduino Nano Shield samt Code,
  47. \cite{nanoGame} welcher als Fernsteuerung verwendet wird.
  48. \paragraph{Ziel des Projektes: }
  49. Ziel des Projektes ist ein ferngesteuerte, Open-Source basierende Roboterplattform.
  50. \newpage
  51. \section{Überlegung}%Yves
  52. Die urprüngliche Idee war die Entwicklung eines Solarroboters, also eines Roboters, der tagsüber mit Hilfe der Sonneneinstrahlung seinen Eigenbedarf decken kann und somit nur einen kleinen Pufferakku benötigt.
  53. Praktische Anwendungen könnten z.B. die Nutzung als kompakte Straßenkehrmaschine oder als Rasenmäher sein. Bedingt durch die eingeschränkte Leistungsabgabe der Solarzellen vermutlich nur für kleine zu bearbeitende Flächen.
  54. Da es nur wenige brauchbare und frei zugängliche Quellen für solche Plattformen gibt, wollten wir eine eigene schaffen. Daher sollte das Projekt exemplarisch als Grundlage für eine Quelloffene Plattform dienen, die auch von anderen genutzt und weiterentwickelt werden kann.
  55. Da wir bei der Entwicklung der mechanischen Komponenten schnell feststellen mussten, dass das Fahrwerk recht komplex ist, insbesondere die Vorderachse, schwenkten wir schnell auf eine andere Bauweise um. Zunächst war der Aufbau mit 4 gleichen Rädern geplant, von denen zwei Stück (Hinterachse) von einem bürstenlosen Gleichstrommotor angetrieben werden sollten. Die Entwicklung eines Differenzials gestaltete sich noch als relativ einfach. Die Vorderachse aber mit dem Servo gestaltete sich dann, hinsichtlich des Zeitaufwandes, für zu komplex.
  56. \begin{figure}[h]
  57. \includegraphics[width=12cm]{hinterachse.png}
  58. \centering
  59. \caption{Hinterachse des urpsrünglichen Aufbaus}
  60. \end{figure}
  61. \begin{figure}[h]
  62. \includegraphics[width=12cm]{lagerschalen.png}
  63. \centering
  64. \caption{Lagerschalen}
  65. \end{figure}
  66. Somit schwenkten wir kurzer Hand zu einem sehr viel einfacheren Aufbau um, um uns schneller den wichtigeren Komponenten widmen zu können.
  67. Der neue Aufbau sah eine schlichte Grundplatte als Plattform für die weiteren Bauteile, wie Motoren (Mabuchi N20 mit Getriebe), Ultraschallsensor, Akku, Hauptplatine und uvm. vor.
  68. Um möglichst viele Montagemöglichkeiten zu bieten, wurde die Grundplatte mit Bohrungen in regelmäßigen Abständen versehen. Diese Bohrungen können zum durchstecken für Schrauben oder zum versenken von Gewindemuffen genutzt werden.
  69. Zum anbringen unserer Komponenten haben wir auf Messinggewindebuchsen und passende M3 Schrauben gesetzt.
  70. Alle selbstentworfenen Komponenten haben wir mit einem FFF 3D-Drucker aus PLA gedruckt.
  71. Mit Ausnahme der Hauptplatine natürlich.
  72. Bedingt durch den Zeitaufwand des gesamten Projektes und anderer Studienmodule haben wir uns entschieden, die Implementierung eines MPPT Ladereglers fallen zu lassen, somit wurde die Idee des Solarroboters auf die Idee der Entwicklung eines Roboters reduziert.
  73. \begin{figure}[h]
  74. \includegraphics[width=12cm]{roboter.png}
  75. \centering
  76. \caption{Der Roboter, aktueller Aufbau}
  77. \end{figure}
  78. \newpage
  79. \section{Mechanik}%Yves
  80. Wie bereits unter „Überlegung“ erwähnt, gestaltete sich der Aufbau mit Achsträger, Radlager und Lagerschalen uvm. als zu Zeitintensiv um in der vorgegebenen Zeit bewältig werden zu können.
  81. Zum Entwurf der mechanischen Bauteile wurde das CAD Programm Fusion 360 von Autodesk verwendet. Dabei gab es kaum Schwierigkeiten, da Yves Ehrlich bereits sehr viel Erfahrung mit 3D-CAD Programmen gesammelt hat. Lediglich der Zwang Windows zu benutzen stellt eine ständige Unannehmlichkeit dar.
  82. Alle Entwürfe wurden mit einem 3D Drucker gedruckt, einem HCmaker7, ein Klon des bekannten Creality CR-10S.
  83. Das Material der Wahl war PLA. Für einen Außeneinsatz ist das Material wegen der geringen Witterungsbeständigkeit kaum geeignet. Insbesondere die geringe Temperaturbeständigkeit (max. 60°C) disqualifizieren das Material für den Einsatz in der Sonne. Da dies aber ohnehin nicht mehr geplant war, ist das Material für unseren Zweck geeignet.
  84. \subsection{Montagemöglichkeiten}
  85. Die zur Befestigung von Bauteilen nötigen Gewindebuchsen in den Kunststoff einzusetzen ist relativ einfach, man benötigt dafür lediglich eine Schraube die man in die Buchse einschraubt und einen Lötkolben mit einer Temperatur von etwa 240°C. Ohne Druck auszuüben legt man die Spitze des Lötkolbens auf den Schraubenkopf. Wenn die Schraube ausreichend Wärme an die Muffe übertragen hat, fängt die Muffe an im Kunststoff zu versinken. Die Schwerkraft sorgt hier für alles nötige. Wenn die Muffe weit genug versunken ist, kann der Lötkolben entfernt werden und man sollte die Schraube schnell abkühlen, z.B. durch pusten oder ein kleines Gebläse wie z.B. einen Radiallüfter.
  86. Beim Design der Kunststoffteile muss man darauf achten, dass für Gewindemuffen stehts eine ausreichend große Fase vorhanden sein muss, damit die Muffe einerseits zentriert wird beim versinken und andererseits kein verdrängtes Material die Muffe beim versinken behindert oder verstopft. Letzterem wird aber auch durch die eingeschraubte Schraube vorgebeugt.
  87. \subsection{Antrieb}
  88. Der Aufbau sieht zwei Antriebsmotoren vor, welche jeweils ein Rad treiben. Zum abstützen verfügt der Roboter über ein selbstentworfenes Kugelrad. Dieses Kugelrad verwendet als Kugeln vier handelsübliche Airsoft Kugeln mit einem Durchmesser von 6mm.
  89. Die Gleiteigenschaften dieser Konstruktion sind nicht die besten, aber für diesen Prototypen ausreichend. Um die Reibung zu vermindern haben wir Silikonöl auf die Kugeln aufgetragen.
  90. \subsection{Verbesserung}
  91. Da Kunststoffe auf glatten Oberflächen sehr wenig Bodenhaftung haben, wurden die Räder mit einer Nut versehen. In diese Nut kann man später ein einfaches Haushaltsgummiband einlegen, somit hat der Roboter auch auf glatten Oberflächen relativ gute Haftung.
  92. \newpage
  93. \section{Elektronik}%Yves
  94. Lochrasterplatinen, wie sie häufig für Prototypzwecke genutzt werden, sind nicht nur unpraktisch für SMD Komponenten, auch wenn man ein 2,54mm Raster mit einigen Tricksereien durchaus auch für SMD Komponenten nutzen kann, sie sind auch relativ unzuverlässig und die Fehlersuche gestaltet sich z.T. als schwierig (je nach Menge und Komplexität der Verdrahtungslagen).
  95. Deshalb entschieden wir uns, eine eigene Platine zu entwickeln.
  96. Als Software nutzten wir dafür das kommerzielle Programm Sprint Layout 6 von der Firma Abacom.
  97. Da die Herstellung der Platine von Hand erfolgen sollte, haben wir die Strukturen der Platine sehr grob gezeichnet. Was auch durch die geringe Anzahl an Komponenten und deren modulare Bauweise begünstigt wurde.
  98. \subsection{Verfahren}%Yves
  99. Als Verfahren zum beschichten der Platine diente die Tonertransfermethode. Dabei wird die Schaltung mit einem Laserdrucker auf geeignetes Papier gedruckt, in diesem Fall Photopapier, und dann mit Hitze auf die blanke Platine gedrückt. Für diesen Zweck hat Yves Ehrlich ein Laminiergerät umgebaut, welches den Vorgang erheblich erleichtert.
  100. Da unsere Platine doppelseitig ist, müssen zuvor die zwei Seiten, welche die Schaltung enthalten Deckungsgleich aufeinander ausgerichtet werden und dann an den Rändern verklebt werden, damit man am Ende eine Art Tasche erhält, in welche dann die Platine eingesteckt werden kann.
  101. Das ganze läuft dann einige Male durch das Laminiergerät. Nach dem das erfolgt ist, lässt man die Platine etwas abkühlen und ab einer Temperatur von etwa 30-40°C schneidet man die Tasche seitlich auf und zieht vorsichtig das Papier ab. Der Toner bleibt am Kupfer haften und schützt an diesen Stellen, wie ein Fotolack, das Kupfer davor weggeätzt zu werden.
  102. Anschließen gibt man die beschichtete Platine in eine Ätzküvette welche mit einer Natriumpersulfat-Lösung gefüllt ist. Nach einiger Zeit kann man beim durchleuchten der Küvette sehen, wie sich das Kupfer immer weiter auflöst, bis am Ende die Schaltung klar und deutlich zu sehen ist. Dann wird die Platine entnommen und gründlich mit Wasser abgespült.
  103. Zum entfernen des Toners benötigt man etwas Aceton und einen Lappen.
  104. Für die THT Komponenten müssen nun noch Bohrungen gesetzt werden. 1,2mm, passend für die Durchkontaktiernieten von Bungard.
  105. Nach dem verpressen (mangels passender Presse eher mit einem Körner breitschlagen) der Nieten, müssen diese beidseitig verlötet werden. Danach können alle Komponenten bestückt werden.
  106. \begin{figure}[h]
  107. \includegraphics[width=16cm]{laminiergeraet.png}
  108. \centering
  109. \caption{Laminiergerät}
  110. \end{figure}
  111. %Platine
  112. \begin{figure}[h]
  113. \centering
  114. \subfigure[Top-Layer]{\includegraphics[width=7.5cm]{pcbTop.png}}
  115. \subfigure[Bottom-Layer]{\includegraphics[width=7.5cm]{pcbBottom.png}}
  116. \caption{fertig geätzte Platine}
  117. \end{figure}
  118. \newpage
  119. \subsection{Bestückung}%Yves
  120. Zum verlöten der Komponenten kam SMD-Lot mit Bleianteil zum Einsatz.
  121. Für SMD Komponenten wurde eine Pinzette als Hilfswerkzeug verwendet.
  122. \subsection{Schaltung}%Yves
  123. Die Schaltung ist relativ einfach gehalten. Im wesentlichen dient die Platine nur als Träger für die modularen Komponenten und für diverse Anschlussmöglichkeiten. Für den NRF24 wurde ein 3,3V Spannungsregler integriert.
  124. Um etwaige Motorenwechsel zu erleichtern, sind zu deren Anschluss Federzugklemmen verbaut worden.
  125. Wegen der Überschaubarkeit der Schaltung haben wir auf einen Schaltplan verzichtet, da das Layout selbsterklärend ist.
  126. \newpage
  127. \section{Fernsteuerung}%Yves
  128. Auf die Fernsteuerung soll an dieser Stelle nicht näher eingegangen werden, da diese zum Zeitpunkt der Erstellung dieses Projektes bereits „fertig“ war.
  129. Es wurden lediglich ein Joystick sowie ein NRF24 ergänzt.
  130. Detaillierte Informationen finden sich im dazugehörigen Repositorium\cite{nanoGame}.
  131. Im Rahmen eines Arduino Workshops für Anfänger entwickelte Yves Ehrlich eine Platine, welche als Shield für einen Arduino Nano fungiert. Sie enthält grundlegende Dinge wie Tasten, einen Akku, eine stabile 5V Spannungsversorgung sowie ein monochromes LCD Display mit Hintergrundbeleuchtung, um nur die wichtigsten Sachen zu nennen.
  132. Dank der Buchsenleiste auf der Rückseite, welche neben 3,3V und 5V Spannungsversorgung auch diverse I/Os und Analogeingänge bereitstellt, lässt sich das Shield „nanoGame“ hervorragend erweitern und für viele verschiedene Dinge nutzen, so auch als Fernsteuerung für unseren Roboter.
  133. Bei dem Joystick handelt es sich um eine Platine welche ein original Ersatzteil der Sony PSP enthält. Dieser Joystick ist sehr kompakt und ließ sich dadurch recht einfach in unsere Projekt integrieren. Es musste lediglich eine Halterung konstruiert werden, um den Joystick an das Gehäuse der Fernsteuerung zu schrauben.
  134. Beim Funkmodul sind wir kompromissloser vorgegangen. Dieses wurde mit ein wenig Silikonklebstoff an der Oberseite fixiert.
  135. Alle Verbindungsleitungen wurden Freiluft auf der Rückseite der Fernsteuerung zum Schacht der bereits erwähnten Buchsenleiste gelegt und dort mit Steckerleisten angeschlossen.
  136. \begin{figure}[h]
  137. \includegraphics[width=12cm]{rcVorn.png}
  138. \centering
  139. \caption{Fernsteuerung vorn}
  140. \end{figure}
  141. \begin{figure}[h]
  142. \includegraphics[width=12cm]{rcHinten.png}
  143. \centering
  144. \caption{Fernsteuerung hinten}
  145. \end{figure}
  146. \newpage
  147. \section{LCD}
  148. Als LCD kam, entsprechend dem nanoGame \cite{nanoGame} Projekt, ein monochromes Grafik-LCD mit Hintergrundbeleuchtung und einer Auflösung von 84 x 48 Pixeln zum Einsatz. Beim integrierten Controller handelt es sich um den PCD8544. Angesteuert per SPI und diversen Steuerleitungen.
  149. Da aktuell im Projekt keine Grafiken dargestellt werden, entschieden wir uns, das LCD einfach fest in 6 Zeilen einzuteilen. Um kollisionsfrei Texte ausgeben zu können, verwendeten wir ein global deklariertes Stringarray. Jeder Teil des Codes, der etwas ausgibt schreibt in ein Element bzw. in eine Zeile. die Methode "`refreshLCD()"' liest dieses Stringarray ein und gibt die 6 Zeilen auf dem LCD aus.
  150. \section{Code allgemein}%Yves
  151. Um die Einsatzmöglichkeiten für den Code möglichst flexibel zu gestalten, haben wir uns bemüht, nicht blockierenden Quelltext zu schreiben.
  152. Somit lässt sich auch mit dem recht kleinen Atmega328p bei 16 MHz Takt eine ganze Menge bewältigen.
  153. Aktuell ist der Roboter in der Lage auf Kommandos, die er von der Fernsteuerung erhält, zu reagieren. Aus Zeitgründen konnten wir leider nur einen manuellen Fahrmodus implementieren. Dieser beinhaltet das fahren mit digitalen Tasten sowie „analog“ mit dem ergänzten Joystick.
  154. Weiterhin implementiert wurden das erfassen von Temperaturen mit Hilfe eines DS1820 und eine Distanzmessung mit einem HC-SR04 Ultraschallsensor.
  155. Die Übertragung von Kommandos ist relativ einfach gehalten. Das erste Byte im commands Array ist ein Kommando, gefolgt von 2 Bytes mit Daten. Diesem Muster folgend ist jedes dritte Byte ein Kommando, gefolgt von zwei Datenbytes.
  156. Da das Array eine feste Größe von 32 Byte hat, lassen sich folglich bis zu 10 Kommandos übertragen. Wie viele Kommandos jeweils übertragen werden und in welcher Reihenfolge diese im Array vorkommen, also ob Byte 0,3,6,9...usw., spielt keine Rolle.
  157. \newpage
  158. \section{SPI}%Lukas
  159. \subsection{Was ist SPI?} %Lukas
  160. SPI - Serial Peripheral Interface ist der Standard für ein Synchronen Seriellen Datenbus. Dieser Datenbus kann zwei digitale Schaltungen mittels Master-Slave prinzip verbinden \cite{SPI}. Der Bus ermöglicht die verwendung von Mehreren Slaves, jedoch wird die Anzahl der Slaves durch die Anzahl der CS - ChipSelect Leitungen begrenzt. Die Datenübertragung geschiet über eine Seperate Leitung, auch SD (Serial Data) genannt.
  161. \paragraph{Rolle des Masters}
  162. Der Master gibt das Taktsignal über den SCK (Serial Clock) Ausgang an, desweiteren wählt er einen Slave mit welchem er kommunizieren möchte über den CS (ChipSelect).
  163. \paragraph{Rolle des Slaves}
  164. Der Slave ist solange inaktiv bis dieser über den CS Pin aktiviert wird. Nach der Aktivierung wird über Serial Data kommuniziert, das Taktsignal wird über den SCK Synchronisiert bzw vom Master übernommen.
  165. \subsection{Einsatz von SPI innerhalb des Projektes}
  166. \paragraph{Verbindung: }
  167. Um die Verbindung zwischen dem nRF24L01 Chip und dem Arduino herzustellen wurden zunächst alle Verbindungen getätigt. Im Folgender Graphik ist das Pinout vom nRF24L01 Chip abgebildet. Dabei sind die Kürzel wie folgt benannt: CE - Chip Enable dieser entspricht dem Chip Select Pin, CSN -Ship Select Not dieser ist die Invertierte version des CE, SCK - Serial Clock, MISO - Master in Slave out, MOSI - Master out Slave in und die beiden Pins für die Stromversorgung VCC und Ground. Die beiden pins MISO und MOSI sind die Datenleitungen und werden an den Gleichnamingen Pins des Arduinos angeschlossen. Desweiteren ermöglicht der IRQ Interruptsteuerung dieser Pin ist Optional zu verwenden.
  168. \begin{figure}[h]
  169. \includegraphics[width=8cm]{nRF24L01Pinout.png}
  170. \centering
  171. \caption{Pinout des nRF24L01 Chips \cite{nRF24Pinout}}
  172. \end{figure}
  173. \newpage
  174. \section{Drahtlose Verbindung} %Lukas
  175. Wie schon zuvor erwähnt wird für die Basis der Funksteuerung das Arduino Shield verwendet, welches mit dem nRF24L01 Chip erweitert wurde. Der Roboter wurde ebenfalls mit dem nRF24L01 ausgestattet.
  176. \subsection{Allgemeine Verwendung von RF24} %Oder nur als paragraph je nachdem wie viel zusammen kommt.
  177. Die Opensoucre Bibliothek RF24 \cite{RF24Lib} diente als Codebasis für die Funksteuerung. Da diese Bibliothek bei korrekter Verwendung genau auf die Kommunikation zwischen zwei nRF24L01 Chips abgestimmt ist.
  178. Zur Verwendung der Bibliothek muss sie nur inkludiert und Instanziiert werden dabei werden die Beiden Pins CE und CSN für das Hardware-SPI konfiguriert.
  179. \begin{file}[RF24 initialisieren]
  180. \begin{lstlisting}[language=C++]
  181. #include <RF24.h>
  182. RF24 radio(A2, A3); // CE, CSN
  183. const byte address[6] = "00001";
  184. \end{lstlisting}
  185. \end{file}
  186. Damit sind bereits Sämtliche Konfigurationen für die Hardware-SPI Kommunikation zwischen Arduino nano und dem nRF24L01 erledigt.
  187. Kommunizieren zwischen zwei dieser Setups wird dann durch die Funktionen read und wirite,
  188. jedoch muss vor dem Start einer Kommunikation die Methoden begin(),
  189. openWritingPipe(address) mit address als Kommunikationsleitung und stopListening() bei Sender bzw startListening() beim Empfänger aufgerufen werden.
  190. Die Methode setPALevel() setzt den Power Amplifiyer Level umso höher dieser Wert umso Stärker das Signal,
  191. wodurch der Stromverbrauch Steigt.
  192. Der Anstieg des Stromverbrauchs kann auch bei einer nicht ganz konstanten Stromversorgung dazu führen das das Modul nicht korrekt funktioniert.
  193. \begin{file}[RF24 initialisieren]
  194. \begin{lstlisting}[language=C++]
  195. //An der Sender Seite
  196. radio.begin();
  197. radio.openWritingPipe(address);
  198. radio.setPALevel(RF24_PA_MAX);
  199. radio.stopListening();
  200. radio.write(&payload, sizeof(payload));
  201. //An der Empfaenger Seite
  202. radio.begin();
  203. radio.openReadingPipe(0, address);
  204. radio.setPALevel(RF24_PA_MAX);
  205. radio.startListening();
  206. if (radio.available()) {
  207. radio.read(&payload, sizeof(payload));
  208. //Payload weiter verarbeiten.
  209. }
  210. \end{lstlisting}
  211. \end{file}
  212. \subsection{Verwendung von RF24 innerhalb dieses Projektes}
  213. \paragraph{Am Anfang des Projektes: }
  214. Zu Begin des Projektes wurde zuerst die Funkkommunikation zwischen zwei Arduino's mittels nRF24L01 getestet, dabei gab es schon die ersten Komplikationen. Da der Chip nicht korrekt mit den Hardware SPI Anschlüssen des Arduino verbunden wurde. Nach dem weiteren Einlesen in die Funktionsweise von SPI konnten die Verbindungen richtig gesetzt und diese Komplikation wieder aufgehoben werden.
  215. \paragraph{Logik hinter der Kommunikation: }
  216. Um den Roboter mit der Fernsteuerung auch Steuern zu können musste erst ermittelt werden welche Daten der Roboter benötigt um zu fahren. Diese Daten wurden dann in ein 32Byte großes Commands Array gespeichert, welches dann übertragen wurde. Das Array besteht aus Folgenden Inhalten:
  217. \begin{enumerate}
  218. \item speedA - Geschwindigkeit des rechten Motors.
  219. \item dirA - Vorzeichen der Geschwindigkeit des rechten Motors.
  220. \item speedB - Geschwindigkeit des linken Motors.
  221. \item dirB - Vorzeichen der Geschwindigkeit des linken Motors.
  222. \item goDrive - startet autodrive.
  223. \item stopDrive - stoppt autodrive.
  224. \item getTemp - löst Temperaturübertragung aus.
  225. \item timeToDrive - Zeit die der Roboter fahren soll.
  226. \item nothing - Stoppt den Roboter.
  227. \end{enumerate}
  228. \paragraph{Übertragung der Commands}
  229. Das Commands Array wurde dann wie in der Sektion allgemeine Verwendung von RF24 beschrieben Übertragen, dabei ist die Payload das Commands Array. Der Sender ist Die Fernsteuerung und der Roboter ist der Empfänger. Der Empfänger besitzt daher auch die commandInterpretation() Funktion, welche die entsprechenden Kommandos liest und umsetzt.
  230. \newpage
  231. \section{Steuerung} %Lukas
  232. Der Roboter kann über ein Steuerkreuz mit 4 Buttons oder einen Joystick gesteuert werden. Begonnen wurde mit der Steuerung über die Buttons, dann wurde die Steuerung mittels Joystick realisiert und anschließend wurde diese dann noch stark variable als C++ Library Implementiert.
  233. \subsection{Button Steuerung} %Yves/Lukas
  234. Das ansprechen der Buttons erfolgte mithilfe der ShiftRegButtonLib Library
  235. \cite{nanoGame}
  236. Die Button Steuerung ermöglicht entweder Vorwärts, Rückwärts, Links oder Rechts zu fahren. Dabei werden die Beiden Motoren mit den jeweilig maximalen PWM-Werten angesprochen, sprich sie sind entweder eingeschaltet oder abgeschaltet.
  237. \paragraph{Logik hinter der Steuerung}
  238. Der Roboter soll für Folgende Tasten folgende Bewegungen durchführen:
  239. \begin{itemize}
  240. \item Oben - vorwäts fahren
  241. \item Unten - rückwärts fahren
  242. \item Rechts - Drehung im Uhrzeigersinn
  243. \item Links - Drehung gegen den Uhrzeigersinn
  244. \end{itemize}
  245. Realisiert wurde es folgendermaßen:
  246. \begin{itemize}
  247. \item vorwäts fahren - setzte PWM-Werte beider Motoren auf das Maximum
  248. \item rückwärts fahren - setzte PWM-Werte beider Motoren auf das minimum
  249. \item Drehung im Uhrzeigersinn - setze den PWM-Wert des rechten Motors auf das minimum und den des linken auf das maximum
  250. \item Drehung gegen den Uhrzeigersinn - setze den PWM-Wert des rechten linken auf das minimum und den des rechten auf das maximum
  251. \end{itemize}
  252. \subsection{Joystick Steuerung} %Lukas
  253. Die Steuerung über einen Joystick ermöglicht das kontrollieren über die Aussteuerung des Joysticks. Verwendet wurde ein klassischer Joystick, welcher aus dem Consolen Bereich stammt. Da der verwendet Joystick von einen Billigproduzenten auch China stammt gibt es auch leider kein Datenblatt oder sonstige Informationen die hier verlinkt hätten werden können.
  254. \paragraph{Grundlegende Verwendung des Joysticks}
  255. Der Joystick besitzt zwei analoge Anschlüsse und überträt dort werte von 0 bis 511 je nach aussteuerung des Joysticks, jede Achse hat somit ihren eigenen Pin.
  256. Die Werte der jeweiligen Achsen können dann über AnalogRead() mit dem Pin der Achse als Argument abgefragt werden.
  257. Die Mittelstellung des Joysticks ist demnach bei 255.
  258. \subparagraph{Mapping:}
  259. Da der Bereich der Werte nicht zu dem der benötigten PWM-Werten passt werden diese mithilfe der map() Funktion von 0 bis 511 auf -255 bis 255 gemapt.
  260. Nach dem Mapping kann die Auswertung über die Richtung durchgeführt werden um dann in den entsprechenden fällen die gemappten werte als geschwindigkeit zu interpretieren.
  261. \subparagraph{Anbringung und dessen Auswrikung auf die Steuerung}
  262. Der Joystick wurde so an das Shield angebracht, so dass druch ein nach Vorne drücken die Achsenwerte für die Y-Achse kleiner werden und ein nach Links drücken die X-Achse ebenfalls kleiner werden. Die Aussteuerung nach Rechts folgt demnach zu einer erhöhung der Achsenwerte der X-Achse und die Aussteuerung nach unten eine erhöhung der Achsenwerte der Y-Achsen.
  263. \paragraph{Logik hinter der Steuerung}
  264. Zuerst wurde die Logik der Button Steuerung übernommen, jedoch mit folgenden veränderungen.
  265. Vorwärtsfahren wird jetzt aktiviert, wenn der Achsenwert der Y-Achse kleiner als die Mittelstellung abzüglich einses toleranzbereiches ist.
  266. Das Rückwärtsfahren wird aktiviert, wenn der Achsenwert der Y-Achse größer als die Mittelstellung zuzüglich eines toleranzbereiches ist.
  267. Eine Drehung im Uhrzeigersinn wrid ausgelöst, wenn der Achsenwert der X-Achse größer als die Mittelstellung zuzüglich eines toleranzbereiches ist. Demnach wird eine Drehung gegen den Uhrzeigersinn ausgelöst, wenn der Achsenwert der X-Achse kleiner als die Mittelstellung abzüglich eines toleranzbereiches ist.
  268. In dieser Version ist der Toleranzbereich im Code mit 20 Festgeschrieben.
  269. \paragraph{Umsetzung der Steuerung}
  270. Die Umsetzung ist nichts anderes als die PWM-Werte für die beiden Motoren in jedem der Steuerungsfälle zu ermitteln. Da die werte schon gemappt wurden können diese nun hier wieder verwendet werden. In der Folgenden Graphik ist zu erkennen wann welche Aktion Ausgeführt werden soll. Wenn zum Beispiel der Joystick nach Vorne-rechts gerückt wird ist der wert von der X-Achse über dem Mittelwert und der der Y-Achse unter dem Mittelwert. Demnach werden dann die PWM-Werte entsprechend gesetzt.
  271. \begin{figure}[h]
  272. \includegraphics[width=8cm]{JoystickToLogic.png}
  273. \centering
  274. \caption{Interpretation der Aussteuerung}
  275. \end{figure}
  276. \subsection{Überführung der Joystick Steuerung in eine Library} %Lukas
  277. Hier wurde besonderes Augenmerk auf Wiederverwendbarkeit und Variabilität gelegt.
  278. Des weiteren ist die Library komplett in C++ geschrieben. Wie genau eine C++ Library erstellt wird, wird in dieser Sektion nicht aufgefasst sondern nur die Besonderheiten betreffend der Joystick Library.
  279. \subsection{Aufbau der Klassen}
  280. Um eine höhere Variabilität und Wiederverwendbarkeit zu ermöglichen wurde die Library Objekt Orientiert programmiert. Dazu wurden drei Klassen Implementiert: Joystick, Motor und Steuerung.
  281. \begin{figure}[h]
  282. \includegraphics[width=13cm]{JoystickUML.PNG}
  283. \centering
  284. %\caption{Interpretation der Aussteuerung}
  285. \end{figure}\begin{figure}[h]
  286. \includegraphics[width=7cm]{MotorUML.PNG}
  287. \centering
  288. %\caption{Interpretation der Aussteuerung}
  289. \end{figure}\begin{figure}[h]
  290. \includegraphics[width=8cm]{SteuerungUML.PNG}
  291. \centering
  292. %\caption{Interpretation der Aussteuerung}
  293. \end{figure}
  294. Von diesen Klassen ist die Steuerung diejenige, welche die die eigentliche Logik beinhaltet, jedoch benötigt man zur Verwendung der implementierten Steuerung zwei Motoren und einen Joystick. Um einen Motor zu erstellen reicht es den Höchsten und den Niedrigsten PWM-Wert anzugeben. Über das Attribut PWMValue lässt sich nach dem Aufruf der updateValues() Funktion der Steuerungsklasse der Aktuelle PWM-Wert jedes Motors einzeln abrufen. Beim instantiieren der Joystick-klasse müssen mehr Daten angegeben werden. Die ersten beiden Parameter legen die Pins fest an welchen die jeweilige Achse angeschlossen ist. Die nächsten zwei sind wieder der niedrige und Höchste Wert. Zum Schluss benötigt der Joystick noch einen Wert, der einen Abstand zum Mittelpunkt von der Aktivierung der Steuerung ausschließt das sogenannte spaceing. Es wird benötigt, da der Joystick selbst in der Mittelstellung werte sendet, die über bzw unter 0 liegen.
  295. \newpage
  296. \section{Gedruckte Bauteile} %Yves
  297. Alle gedruckten Bauteile haben wir selbst entworfen. einsehbar sind diese im Repositorium als STL oder aber auch unter den öffentlichen Fusion 360 Links.
  298. \newline
  299. %Platine
  300. \begin{figure}[h]
  301. \centering
  302. \subfigure[Rahmen \cite{HC-SR04_Halterung}]{\includegraphics[width=7.5cm]{hc-sr04_rahmen.png}}
  303. \subfigure[Winkel \cite{HC-SR04_Halterung}]{\includegraphics[width=7.5cm]{hc-sr04_winkel.png}}
  304. \caption{HC-SR04 Halterung}
  305. \begin{minipage}[t]{0.48\textwidth}
  306. \includegraphics[width=\textwidth]{schalterhalterung.png}
  307. \caption{Schalterhalterung \cite{Schalterhalterung}}
  308. \end{minipage}\hfill
  309. \begin{minipage}[t]{0.48\textwidth}
  310. \includegraphics[width=\textwidth]{akkuhalterung.png}
  311. \caption{Akkuhalterung \cite{Akkuhalterung}}
  312. \end{minipage}
  313. \end{figure}
  314. \begin{figure}
  315. \centering
  316. \begin{minipage}[t]{0.48\textwidth}
  317. \includegraphics[width=\textwidth]{joystickhalterung.png}
  318. \caption{Joystick Halterung \cite{Joystick_Halterung}}
  319. \end{minipage}\hfill
  320. \begin{minipage}[t]{0.48\textwidth}
  321. \includegraphics[width=\textwidth]{kugelrad.png}
  322. \caption{Kugelrad \cite{Kugelrad}}
  323. \end{minipage}
  324. \medskip
  325. \begin{minipage}[t]{0.48\textwidth}
  326. \includegraphics[width=\textwidth]{rad.png}
  327. \caption{Räder \cite{Raeder}}
  328. \end{minipage}\hfill
  329. \begin{minipage}[t]{0.48\textwidth}
  330. \includegraphics[width=\textwidth]{plattform.png}
  331. \caption{Roboter Plattform \cite{Plattform}}
  332. \end{minipage}
  333. \end{figure}
  334. \newpage
  335. \section{Motorsteuerung} %Yves
  336. \subsection{Funktionsweise eines PWM}
  337. Die Pulsbreitenmodulation oder engl. Pulse Width Modulation (PWM) dient zur Variation der ausgegebenen Effektivspannung eines Ausgangs. Umgesetzt wird ein PWM überlicherweise mit einem Timer, welcher zählt bis er überläuft und wieder von vorn beginnt, sowie einem Komparator als auch einem Vergleichswert, welcher vorgibt, wie lang der Impuls ausgegeben werden soll. Ist der Wert vom Timer und dem PWM Sollwert identisch, so wird das Ausgangssignal abgeschalten.
  338. Durch Variation der Impulsbreite im Verhältnis zur Periodendauer ergibt sich ein Effektivwert \ <\ = der max. Signalspannung. Das Tastverhältnis hängt von der Auflösung des Timers ab. Im Falle unseres Projektes arbeitet Timer1 als 8-Bit Timer. Somit ergibt sich ein Tastverhätnis von 1:256.
  339. Die Grafik aus dem Atmega328p Datenblatt von Seite 133 illustriert dies noch einmal.
  340. \begin{figure}[h]
  341. \includegraphics[width=16cm]{fastPWM.png}
  342. \centering
  343. \caption{Funktion des PWM Moduls im Atmega328p} \cite{fastPWM}
  344. \end{figure}
  345. \subsection{Implementierung}
  346. Die Steuerung der Motoren wurde über den IC MX1508 realisiert. Dieser ist sehr günstig als Modul für etwa 1€ erhältlich.
  347. Mit seinen Spezifikationen von max. 10V Versorgungsspannung und maximal 1,5A war er perfekt für dieses Projekt geeignet.
  348. Leider konnten wir kein Datenblatt zu diesem IC finden, die Angaben stammen lediglich aus den Beschreibungen der Händler die dieses Modul verkaufen.
  349. Es scheint sich um einen Treiber mit H-Brücke bzw. doppelter H-Brücke zu handeln, er verfügt über jeweils zwei Kanäle mit je zwei Eingängen. Je nach Polung der Eingänge kann ein Motor vorwärts oder rückwärts drehen.
  350. Um die Geschwindigkeit der Motoren regulieren zu können schrieben wir eine Bibliothek mit dem Namen L298N (Achtung, nicht mit der gleichnamigen Bibliothek im Librarymanager der Arduino IDE zu verwechseln!).
  351. Der Name ist angelehnt an den gleichnamigen IC, welcher dem MX1508 in seiner Ansteuerung ähnelt.
  352. Die Bibliothek nutzt Timer1 als 8-Bit Timer für die im Atmega328p integrierten PWM-Module OC1A und OC1B.
  353. Ein PWM Pin ist mit jeweils einem der beiden Eingangspins eines Kanals des MX1508 verbunden. Der jeweils andere Pin muss kein PWM Pin sein, muss aber je nach Drehrichtung korrekt gepolt sein. Für diese nicht-PWM-Pins haben wir die Portpins B0 (Kanal A) und D7 (Kanal B) verwendet.
  354. \newline
  355. Im folgenden Code ist exemplarisch zu sehen, wie das setzen eines PWM Wertes für Kanal A abläuft. Valide PWM-Werte sind -255 bis +255.
  356. \begin{file}[MX1508]
  357. \begin{lstlisting}[language=C++]
  358. L298N::setPWM_A(int16_t pwmA) {
  359. if(pwmA < 0) {
  360. PWMA = 0xFF + pwmA;
  361. PORT_A |= PIN_A;
  362. } else {
  363. if(pwmA == 0) {
  364. PWMA = 0;
  365. PORT_A &= ~PIN_A;
  366. } else {
  367. PWMA = pwmA;
  368. PORT_A &= ~PIN_A;
  369. }
  370. }
  371. }
  372. \end{lstlisting}
  373. \end{file}
  374. Zunächst wird geprüft, ob der PWM-Wert "`pwmA"' negativ ist. Davon hängt die Polung von "`PIN\_A"' ab und ob der PWM-Wert negiert werden muss.
  375. \newline
  376. Anschließend werden PWM-Wert und der Zustand des nicht-PWM-Pins entsprechend gesetzt.
  377. \begin{figure}[h]
  378. \includegraphics[width=12cm]{MX1508.png}
  379. \centering
  380. \caption{MX1508 Anschluss \cite{MX1508}}
  381. \end{figure}
  382. %Folgende beiden ließen sich auch durch subsections mittels sensoric als section realisieren, kommt aber auf die menge des textes an subsections sollten nicht über eine halbe seite lang sein.
  383. \newpage
  384. \section{Thermosensor} %Nick
  385. \subsection{OneWire}
  386. OneWire ist eine serielle Schnittstelle, die nur mit einer Datenleitung auskommt. Jedes angeschlossene Gerät hat eine eigene 64bit ROM Adresse, die man gezielt ansprechen kann. Alternativ, kann man Befehle an alle Geräte senden indem man den Skip ROM-Command (0xCC) benutzt. Anschließend kommt der eigentliche Befehl mit write(), der ausgeführt werden soll. Danach werden die Daten auf ein Scratchpad-Speicher geschrieben von wo sie per read() gelesen werden können.
  387. \subsection{Sensor und dessen Integration}
  388. Wie bereits erwähnt benutzen wir einen Dallas DS18b20 1-Wire Digital Thermometer, um die Motortemperatur zu messen. Der DS18b20 speichert die Temperatur als einen 9bit - 12bit Wert und kann Temperaturen im Bereich von -55°C bis 125°C messen. Für unsere Bedürfnisse reicht es wenn wir in 1-er Schritten messen. Der Sensor kommt aber auch mit kleineren Inkrementen zu recht. Der Sensor benötigt die OneWire-Library um angesprochen zu werden.\\
  389. \begin{figure}[h]
  390. \includegraphics[width=12cm]{ds18b20.jpg}
  391. \centering
  392. \caption{Der benutzte Sensor \cite{DALLAS} \\1) Erdung 2) Datenleitung 3) Spannung}
  393. \end{figure}
  394. \\
  395. Eine Messung wird durchgeführt indem der Sensor Takte, innerhalb eines Zeitfensters zählt. Der Zähler startet bei einem Wert, der -55°C darstellt. Erreicht der Zähler 0 schneller als das vorgegebene Zeitfenster wird das Temperaturregister inkrementiert. Der Zähler wird dann auf einen vom Slope Accumulator Circuitry abhängigen wert gestellt und wieder runtergezählt. Dies wiederholt sich solange bis das festgelegte Zeitfenster abgelaufen ist. \\
  396. \\
  397. Es gibt verschiedene Wege den Code für den Sensor zu implementieren. Der einfachste Weg wäre die DallasTemperature-Library zu benutzen.
  398. \begin{file}[DS18B20]
  399. \begin{lstlisting}[language=C++]
  400. #include <OneWire.h>
  401. #include <DallasTemperature.h>
  402. OneWire oneWire(x);
  403. DallasTemperatures sensors(&oneWire);
  404. void setup(){
  405. Serial.begin(9600);
  406. // Die Library starten
  407. sensors.begin();
  408. }
  409. void loop(){
  410. // Temperaturmessung anfordern
  411. sensors.requestTemperatures();
  412. // Temperatur anzeigen
  413. Serial.print(sensors.getTempCByIndex(y));
  414. }
  415. \end{lstlisting}
  416. \end{file}
  417. OneWire wird auf Pin 4 initialisiert, dann wird OneWire an sensors() übergeben. Damit weiß die Library wo der Sensor angeschlossen ist. Mit sensors.begin() startet man die Library. Eine Messung fordert man mit requestTemperatures() an und mit getTempCByIndex(y) kann man einen bestimmten Sensor, wenn man mehrere hat, nach der Temperatur in Grad Celsius abfragen. Mit der Library ist das ganze also sehr einfach.\\
  418. \\
  419. Das war auch der erste Ansatz. Der Clue an der Sache ist jedoch, dass die Prozedur auf die Weise etwa 600ms dauert und das den Roboter viel zu lange blockieren würde, da er in der Zeit keine weiteren Befehle verarbeiten kann. Also wurde diese Idee mitsamt der Library gestrichen und nach einer effizienteren Alternative gesucht.\\
  420. \\
  421. Für unsere Implementierung haben wir uns an\\ \url{https://www.scargill.net/reading-dallas-ds18b20-chips-quickly/} orientiert. Dieses Beispiel ermöglicht es eine Messung in nur 5ms durchzuführen. Es wurden jedoch einige Änderungen in der Umrechnung der Temperatur gemacht. Da ein Einsatz in negativen Temperaturen nicht vorgesehen ist, machen wir eine viel simplere Umrechnung als die im Blog. \\
  422. \\
  423. \begin{file}[DS18B20]
  424. \begin{lstlisting}[language=C++, inputencoding={utf8}, extendedchars=false]
  425. #include <OneWire.h>
  426. int16_t dallas(int x){
  427. // Initialisiergung
  428. OneWire ds(x);
  429. byte data[2];
  430. int16_t result = 0;
  431. // Auf Scratchpad schreiben
  432. ds.reset();
  433. ds.write(0xCC);
  434. ds.write(0xBE);
  435. // Vom Scratchpad lesen
  436. for(int i = 0; i < 2; i++){
  437. data[i] = ds.read();
  438. }
  439. result = (data[1]<<8)|data[0];
  440. result = result/16;
  441. // Messen
  442. ds.reset();
  443. ds.write(0xCC);
  444. ds.write(0x44, 1);
  445. return result;
  446. }
  447. \end{lstlisting}
  448. \end{file}
  449. Wir initialsieren im Beipspiel OneWire auf einen beliebigen Pin und setzen den Sensor mit reset() zurück. Die ROM Adresse wird dabei mit write(0xCC) übersprungen, da wir nur einen Temperatursensor haben und es somit reicht, dass wir alle Geräte auf dieser OneWire-Verbindung ansprechen.Mit write(0xBE) wird dem Sensor gesagt, dass er die Werte auf dem Scratchpad speichern soll, die wir dann mit read() in einen Array einlesen. Die Werte im Array führen wir dann zusammen und teilen sie durch 16. Die 16 ergibt sich aus einer Tabelle aus dem Datenblatt. Bei genauerer Betrachtung stellt man Fest, dass die Temperatur Werte über 0 einfach nur die Binärwerte geteilt durch 16 sind. da es für unsere Bedürfnisse genügt, dass wir nur die positiven Werte messen, belassen wir es bei dieser einfachen Umrechnung. Dann wird der Chip wieder resetet, die Addresierung übersprungen und mit write(0x44) eine Messung durchgeführt. Es empfiehlt sich in der setup() Funktion die dallas() Funtion aufzurufen, damit er in der loop() den richtigen Wert erhält.\\
  450. \\
  451. Um den Roboter so wenig wie möglich zu belasten und somit eine eine schnelle Reaktionszeit zu ermöglichen, wird die Temperaturmessung nur alle 100ms durchgeführt und nur jede Sekunde durch den Funkcontroller abgefragt. Die Abfrage wird, aus Übersichtsgründen, abseits der Steuerung gemacht.
  452. \newpage
  453. \section{Ultraschallsensor} %Nick
  454. Zur Messung der Distanz zu einem Objekt vor dem Robotor benutzen wir einen HC-SR04 Ultraschallsensor. Dieser kann einen Abstant bis ca 450cm messen. Das ganze funktioniert, durch ein Signal, das der Sensor von sich gibt und die Zeit zählt bis er ein Echo zurückbekommt.\\
  455. \begin{figure}[h]
  456. \includegraphics[width=12cm]{HC-SR04.jpg}
  457. \centering
  458. \caption{Der benutzte Sensor \cite{HC} \\1) Spannung 2) Trigger Pin 3) Echo Pin 4) Erdung}
  459. \end{figure}
  460. \\
  461. Die Implementation ist relativ einfach. Wir setzen den Trigger Pin als Ausgang und den Echo Pin als Eingang. Wir senden mit dem Trigger Pin, dann ein Signal, welches vom Echo Pin empfangen wird und rechnen dann die Zeit die dafür gebraucht wurde in cm um.\\
  462. \\
  463. Zum Empfangen des Echo nutzen wir einen Pinchange Interrupt. Diese ISR wird ausgeführt, wenn ein Signal an einen bestimmten Pin kommt. Dazu aktivieren wir die nötigen PCINTs im PCIRC Register und PCMSK2 das bit für unseren Pin.\\
  464. \\
  465. In der ISR messen wir die Zeit bis ein Echo ankommt und teilen es, wie im Datenblatt beschrieben, durch 58 um die Distanz in Centimetern zu bekommen.
  466. \begin{file}[HC-SR04]
  467. \begin{lstlisting}[language=C++, inputencoding={utf8}, extendedchars=false]
  468. int trig;
  469. int echo;
  470. //ISR for PCINT2
  471. ISR(PCINT2_vect) {
  472. if((PIND & 64) > 0) {
  473. pulseStart = micros();
  474. } else {
  475. startNewMeasurement = true;
  476. pulseLength = micros() - pulseStart;
  477. newResult = true;
  478. }
  479. PCIFR = 0;
  480. }
  481. void measureDistance(){
  482. digitalWrite(trig, HIGH);
  483. // ... wait for 10 µs ...
  484. delayMicroseconds(10);
  485. // ... put the trigger down ...
  486. digitalWrite(trig, LOW);
  487. //Serial.println("messe...");
  488. startNewMeasurement = false;
  489. }
  490. \end{lstlisting}
  491. \end{file}
  492. In einer setup() Funktion müssen wir den Trigger Pin als Ausgang und den Echo Pin als Eingang definieren und ein initiales Sigal mit dem trigger Pin senden. Im Anschluss aktivieren wir die nötigen Bits im PCICR und PCMSK2 Register um den Pinchange Interrupt für unseren Echo Pin zu aktivieren.\\
  493. \\
  494. Die measureDistance() Funktion, leitet die Messung ein. Sie gibt aus dem Trigger mit digitalWrite(trig, HIGH) Pin ein Signal an den Sensor, der dann ein Ultraschallsignal von sich für 10 Mikrosekunden abgibt, welches mit digitalWrite(trig, LOW) wieder abgestellt wird. Die ISR führt dann die eigentliche Messung durch. Da die ISR bei Anfang und bei Ende des Signals aufgerufen wird, haben wir eine Fallunterscheidung eingebaut die zu Beginn des Signals die Startzeit speichert und am Ende des Signals, daraus die Pulslänge berechnet, mit der wir die Distanz bestimmen können. Dazu müssen wir die Pulslänge, wie im bereits erwähnt, durch 58 teilen.\\
  495. \\
  496. Mit der Distanz die wir nun haben können wir den Roboter stoppen lassen, wenn er zu nah an einen Gegenstand ranfährt. Ihn aber komplett zu stoppen wäre unsinnig, da er sich überhaupt nicht mehr bewegen könnte. Also gucken wir nach den Motorgeschwindigkeiten und setzen diese nur auf 0 wenn sie mit einer Vorwärtsbewegung übereinstimmen. Somit kann sich unser Roboter immer noch auf der Stelle drehen oder rückwärts fahren um das Hindernis zu umgehen.
  497. \newpage
  498. %----------------------------------------------------------------------------------------
  499. % BIBLIOGRAPHY
  500. %----------------------------------------------------------------------------------------
  501. \bibliographystyle{unsrt}
  502. \bibliography{references.bib}
  503. %----------------------------------------------------------------------------------------
  504. \end{document}