72
Umbau und Verbesserung der Aktuatorplatine in einem autonomen Fußballroboter Universit¨ at Kassel Projektarbeit von Lukas Will Matrikel-Nr.: 30210239 Vorgelegt im Fachgebiet Verteilte Systeme Betreuer Stephan Opfer Andreas Witsch 17. August 2015

Umbau und Verbesserung der Aktuatorplatine in einem ...das-lab.vs.eecs.uni-kassel.de/publications/Will2015-BachelorProject... · 2 AUFGABENSTELLUNG 2 Aufgabenstellung Das Ziel dieser

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Umbau und Verbesserung derAktuatorplatine in einemautonomen Fußballroboter

Universitat Kassel

Projektarbeit von

Lukas WillMatrikel-Nr.: 30210239

Vorgelegt im

Fachgebiet Verteilte Systeme

Betreuer

Stephan OpferAndreas Witsch

17. August 2015

Zusammenfassung

Das Team Carpe Noctem Kassel nimmt seit einiger Zeit an internationalen Roboter-Fußballturnieren im Rahmen des RoboCup teil. Diese Arbeit hat das Ziel, die Platinedes Roboters zu verbessern, die fur die Ansteuerung der Ballfuhrung zustandig ist.Dabei wird die eigens dafur entwickelte Mikrocontrollerplatine durch ein BeagleBoardBlack mit Peripherieplatine ersetzt. Neben der Ballfuhrung konnen weitere Sensorenausgelesen und Aktoren angesteuert werden.

INHALTSVERZEICHNIS

Inhaltsverzeichnis

1 Einleitung 2

2 Aufgabenstellung 3

3 Losungsansatz 43.1 Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

3.1.1 Recherche nach einem geeigneten Einplatinencomputer . . . . 43.1.2 Beschreibung des BeagleBoard Black . . . . . . . . . . . . . . 63.1.3 Inertiale Messeinheit . . . . . . . . . . . . . . . . . . . . . . . 103.1.4 Lichtdetektor . . . . . . . . . . . . . . . . . . . . . . . . . . . 123.1.5 High Power Motortreiber . . . . . . . . . . . . . . . . . . . . . 133.1.6 Optischer Fluss Sensor . . . . . . . . . . . . . . . . . . . . . . 133.1.7 Verschaltung und Platinenlayout . . . . . . . . . . . . . . . . 14

3.2 Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183.2.1 Ansteuern der Pinfunktion . . . . . . . . . . . . . . . . . . . . 183.2.2 Beschreibung der Programmstruktur . . . . . . . . . . . . . . 20

4 Evaluierung 234.1 Inbetriebnahme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

4.1.1 Einrichten des BeagleBoard Black . . . . . . . . . . . . . . . . 234.1.2 Spannungsversorgung . . . . . . . . . . . . . . . . . . . . . . . 24

4.2 Test einzelner Komponenten . . . . . . . . . . . . . . . . . . . . . . . 274.2.1 Funktionsprufung der inertialen Messeinheit . . . . . . . . . . 274.2.2 Lichtschranke . . . . . . . . . . . . . . . . . . . . . . . . . . . 284.2.3 Servomotor . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284.2.4 High Power Motortreiber . . . . . . . . . . . . . . . . . . . . . 284.2.5 Optischer Fluss Sensor . . . . . . . . . . . . . . . . . . . . . . 29

5 Zusammenfassung und Ausblick 30

A Anhange 31A.1 Vollstandige Tabelle der Einplatinencomputer . . . . . . . . . . . . . 31A.2 Quellcode der rc.local-Datei . . . . . . . . . . . . . . . . . . . . . . . 32A.3 Quellcode der am335x-bone-robot.dtsi-Datei . . . . . . . . . . . . . . 33A.4 Schaltplan der Peripherieplatine . . . . . . . . . . . . . . . . . . . . . 34A.5 Quellcode BeagleBoard Black . . . . . . . . . . . . . . . . . . . . . . 39

1

1 EINLEITUNG

1 Einleitung

Seit einigen Jahren nimmt die Universitat Kassel mit dem Team Carpe Noctem Cas-sel1 im Rahmen des RoboCup2 an internationalen Roboter-Fußballturnieren teil. Dasursprungliche Ziel des RoboCup Soccer-Projektes ist es, den Fußballweltmeister desJahres 2050 mit einer humanoiden Fußballrobotermannschaft besiegen zu konnen.Neben den verschiedenen Fußballligen gibt es noch viele weitere Disziplinen, in de-nen Roboter gegeneinander antreten konnen. Beim RoboCup Rescue geht es zumBeispiel um die Entwicklung von Robotern, die nach Katastrophen die Einsatzkrafteunterstutzen. In dieser Disziplin wird bewertet, welches Roboterteam die Anforde-rungen am besten bewaltigt.

Das Team Carpe Noctem Cassel tritt in der MiddleSize League des RoboCupSoccer an. In dieser Klasse durfen Roboter gegeneinander antreten, deren Grundflachebis zu 52cm x 52cm betragt. Sie spielen zu sechst auf einem Spielfeld mit 12m x 18m,welches einem normalen Fußballfeld gleicht.

In jedem Roboter des Teams befindet sich eine zentrale Recheneinheit. Um mitden Aktoren und Sensoren kommunizieren zu konnen, benotigt sie verschiedene Mi-krocontrollerplatinen, welche auf die unterschiedlichen Aufgaben angepasst sind unddiese ausfuhren. Die PowerSwitch-Platine ist dabei fur die Spannungsversorgung derverschiedenen Bereiche zustandig. Uber die Schaltung auf der Platine des Schuss-mechanismus wird ein großer Kondensator geladen, der die Schussspule mit Stromversorgt. Die Aktuatorplatine steuert die Ballfuhrung an und sendet Sensordaten andie zentrale Recheneinheit.Eine Eigenentwicklung mit einem Mikrocontroller war fruher die einzige Moglichkeit,diese Platinen zu realisieren. Mittlerweile ist die Technik weiter fortgeschritten. Esgibt kleine Einplatinencomputer zu akzeptablen Preisen und mit geringem Energie-verbrauch. Wird hierzu eine Peripherieplatine entwickelt, konnen damit ebenfalls Sen-soren ausgelesen und Aktoren angesteuert werden.

Damit die Weiterentwicklung der Roboter nicht ins Stocken gerat, wird das Re-glement jedes Jahr ein wenig starker an die FIFA-Fußballregeln angepasst.

1http://www.das-lab.net2http://www.robocup.org/

2

2 AUFGABENSTELLUNG

2 Aufgabenstellung

Das Ziel dieser Projektarbeit ist die Weiterentwicklung der Aktuatorplatine, die in deraktuellen Roboter-Generation verbaut ist. Auf der Platine lauft der MikrocontrollerATmega128 der Firma Atmel. Dieser besitzt eine Taktfrequenz von 16MHz und kom-muniziert per Controller Area Network (CAN) mit einem Industriecomputer, welcherdie Recheneinheit des Roboters ist und alle Befehle an die Aktoren verschickt. DieAktuatorplatine ist im Roboter fur die Ansteuerung der Ballfuhrung und die Auswahlder Schussschaufel zustandig. Sie gibt Informationen uber Ballbesitz und Ballrotationan den zentralen Computer weiter, erhalt Befehle von diesem und steuert daraufhindie Motoren der Ballfuhrung oder den Servomotor zum Auswahlen der Schussschaufelan. Einige an die Aktuatorplatine angeschlossene Sensoren wie die Lichtschranke undder Kompasssensor funktionierten in der Vergangenheit nicht zuverlassig und wurdendaher nicht verwendet.

Durch den technischen Fortschritt ergeben sich neue Moglichkeiten, die Aktorenund Sensoren anzusteuern. Das Ziel dieser Projektarbeit ist ein fertiges System ausEinplatinencomputer und Peripherieplatine. Der Vorteil eines Einplatinencomputersgegenuber einem Mikrocontroller ist die leichtere Programmierbarkeit. Um Program-me fur einen Mikrocontroller zu schreiben, benotigt man Vorwissen uber seine Registerund ihre Funktionen. Dieses Wissen ist bei einem Einplatinencomputer nicht mehrnotig.

Die Aufgabe ist nun, die bisherige Aktuatorplatine auf ein linuxbasiertes Systemzu portieren. Hierbei ist die Idee, einen Einplatinencomputer wie den Raspberry Pizu verwenden, um die Kommunikation und Verarbeitung der Daten zu ubernehmen.Die zentrale Recheneinheit soll uber einen Ethernetanschluss mit dem Einplatinen-computer verbunden werden. Außerdem sollen die bisher nicht genutzten Sensorenuberarbeitet und funktionstuchtig gemacht werden. Uber eine Peripherieplatine sol-len die Aktoren und Sensoren an den Einplatinencomputer angeschlossen werdenkonnen. Zur Verbesserung der Orientierung eines Roboters soll statt des Kompass-sensors eine inhertiale Messeinheit (engl. Inertial Measurement Unit, IMU) bestehendaus Beschleunigungs-, Drehraten- und Magnetfeldsensor eingebaut werden.

3

3 LOSUNGSANSATZ

3 Losungsansatz

In diesem Abschnitt werden zunachst die Hardwarekomponenten der Platine unter-sucht. Dabei wird zuerst nach einem geeigneten Einplatinencomputer und anschlie-ßend nach den Aktoren und Sensoren gesucht, die an diesen angeschlossen werdensollen. Auf der Softwareseite wird die verwendete Bibliothek erklart und auf die eige-ne Programmstruktur eingegangen.

3.1 Hardware

Im Folgenden werden die Hardwarekomponenten genauer beschrieben und auf ihreVerschaltung eingegangen. Zuerst wird nach dem Einplatinencomputer gesucht. ImAnschluss werden die Komponenten ausgewahlt, die auf der Peripherieplatine unter-gebracht werden sollen. Zuletzt geht es um den Schaltplan und die Positionierung dereinzelnen Bauteile auf der Platine.

3.1.1 Recherche nach einem geeigneten Einplatinencomputer

Zunachst geht es um die Recheneinheit der neuen Aktuatorplatine. Diese soll ein Ein-platinencomputer ubernehmen. Ein Einplatinencomputer ist ein Computersystem,bei dem alle fur den Betrieb relevanten Komponenten auf einer einzigen Platine un-tergebracht sind. Zum Einrichten werden ein Monitor und eine Tastatur benotigt.Eingesetzt werden sie z. B. in der Mess- und Regelungstechnik der Industrie oder imprivaten Bereich als Media Center, Cloud Speicher oder Homeserver.

Fur unseren Anwendungsfall ist es wichtig, dass am Einplatinencomputer vielefrei programmierbare digitale Ein- und Ausgange (engl. General Purpose Input/Out-put, GPIO) zur Verfugung stehen. Einige von ihnen mussen zusatzliche Funktionenunterstutzen, damit die externen Komponenten korrekt angesteuert oder ausgelesenwerden konnen.

Auf der bisherigen Aktuatorplatine benotigen die beiden Motortreiber der Ball-fuhrung jeweils 2 Ein- und 3 Ausgange, wobei einer der Ausgange ein pulsweitenmo-duliertes Signal (PWM-Signal) generieren muss. Fur den Servomotor wird lediglichein PWM-Signal benotigt. Ein Pin des Analog-zu-Digital-Wandlers (ADC) wird vonder Lichtschranke belegt. Jeweils 3 Ein- und Ausgange werden fur die Schalterboxbenotigt. Der Optische Fluss Sensor benutzt ein Serial Peripheral Interface (SPI) und3 weitere Signalleitungen zur Kommunikation. Die SPI-Schnittstelle steht bei der Ak-tuatorplatine ebenfalls der Kommunikation mit dem CAN-Controller zur Verfugung.Per CAN-Bus werden Daten zwischen ihr und dem Kompasssensor oder dem zentralenComputer ausgetauscht.

Fur den Einplatinencomputer ist es daher wichtig, dass dieser mindestens 25 di-gitale Ein- und Ausgange sowie eine SPI-Schnittstelle besitzt. Um das neue System

4

3 LOSUNGSANSATZ

im Nachhinein leichter erweitern zu konnen, ware es von Vorteil, wenn der Einplati-nencomputer neben den PWM-Signalen und der SPI-Schnittstelle weitere Kommuni-kationsbusse, wie z. B. Inter-Integrated Circuit (I2C) oder Universal AsynchronousReceiver Transmitter (UART) und analoge Eingange zum Messen von Spannungenzur Verfugung stellt. Die Kommunikation zwischen dem zentralen Computer und demneuen System soll per Ethernet stattfinden. Falls dies nicht moglich ist, ware auch dieKommunikation uber den CAN-Bus moglich. Um weitere Sensoren im Roboter inte-grieren zu konnen, ware es von Vorteil, wenn der Einplatinencomputer per CAN-Buskommunizieren kann.Zur leichteren Programmierung sollte das Betriebssystem (engl. Operating System,OS) eine Linux-Distribution sein. Das Programm kann in diesem Fall in C++ ge-schrieben und auf dem Computer selbst kompiliert werden. So fallt ein extra Pro-grammieradapter weg, der bisher notig ist, um den ATmega128 zu programmieren.Wenn das Robot Operating System (ROS) vom Betriebssystem unterstutzt wird undder Computer einen Ethernetanschluss besitzt, konnen die Daten einfach per ROS-Nachricht uber eine TCP- oder UDP-Verbindung ausgetauscht werden.

Am Markt gibt es derzeit eine große Auswahl an Einplatinencomputern mit ei-ner Linux-Distribution als Betriebssystem. Folgende Computer habe ich auf unsereAnspruche hin untersucht:

• Intel Galileo 1

• Intel Galileo 2

• Raspberry Pi (Model B)

• Beagle Board Black

• Beagle Board xM

• Banana Pro

• Wandboard Quad

• Cubie Board 2

• Cubie Board 3

• Cubie Board 4

Die interessantesten Gerate sind in Tabelle 1 aufgefuhrt. Eine vollstandige Tabelleist im Anhang A.1 enthalten. Ist ein Feld rot hinterlegt, so sind die an den Einpla-tinencomputer gestellten Anspruche nicht erreicht. Grune Felder zeigen an, dass dieMindestanforderungen erfullt sind oder mehr zur Verfugung steht, als benotigt wird.

Bei der Untersuchung der Computer fiel auf, dass viele eher fur den Multimedia-bereich gedacht sind. Sie besitzen mehrere USB-Anschlusse und sind fur Bild- und

5

3 LOSUNGSANSATZ

AnforderungenGalileo

2

Pi(Model

B)

BeagleBoardBlack

BeagleBoard

xM

CubieBoard 4

Takt 400MHz 700MHz 1GHz 1GHz 2GhzRAM 256MB 512MB 512MB 512MB 2GBSpeicher k. A. k. A. 4GB k. A. 8GBMaße [mm] 124x72 86x56 86x53 79x76 146x142Preis 70AC 40AC 50AC 140AC $200

OS Linux Linux Linux Linux Linux LinuxEthernet 1+ ja ja ja ja jaSPI 1+ ja ja ja ja k. A.I2C 0+ ja nein ja ja jaUART 0+ ja ja ja ja jaCAN 0+ ja nein ja nein neinDigital I/O 25+ 20 17 65 22 k. A.PWM 3+ 6 1 8 3 5Analog I/O 0+ 6 nein 7 k. A. nein

Tabelle 1: Vergleich der Einplatinencomputer

Tonverarbeitung optimiert. Ihnen fehlt es allerdings an digitalen GPIOs, die fur unse-re Anforderungen wichtig sind. Diese konnten mit einem IC auf der Peripherieplatineerweitert werden, welcher uber I2C oder SPI mit dem Einplatinencomputer kommu-niziert. Dies wurde jedoch den Schaltungsaufwand vergroßern.

Als interessanteste Kandidaten stellten sich das Intel Galileo 2 und das Beagle-Board Black heraus. Beide besitzen neben dem SPI-Bus weitere Kommunikationsbus-se wie CAN, UART und I2C sowie ausreichend analoge Eingange und PWM-Signale.Beim Intel Galileo 2 mussen die digitalen Ein- und Ausgange noch erweitert wer-den. Sonst sind alle Voraussetzungen erfullt. Das Beagle Board Black kann ohnezusatzlichen IC zur Erweiterung der I/O-Pins genutzt werden. Mit einer Große von86mm x 53mm ist es einer der kleineren Einplatinencomputer. Das Galileo 2 ist mit124mm x 72mm fast doppelt so groß. Bei den Kosten ist das Beagle Board Blacks mit50AC gunstiger als das 70AC teure Galileo 2. Zum Betrieb des neuen Aktuatorsystemsfiel die Entscheidung daher auf das BeagleBoard Black.

3.1.2 Beschreibung des BeagleBoard Black

Das Beagle Board Black wird von einem 32-bit ARM Cortex-A8 Prozessor betrieben.Es besitzt eine Taktfrequenz von 1GHz, 512MB RAM und einen internen Flashspei-cher von 4GB, was fur unseren Einsatz mehr als ausreichend ist. An Kommunikations-

6

3 LOSUNGSANSATZ

bussen stehen mehrere CAN-, I2C-, SPI- oder UART-Schnittstellen zur Verfugung.Uber die beiden Buchsenleisten, welche in Abbildung 1 gut zu erkennen sind, konnendie Kommunikationsbusse und weitere GPIO-Pins fur externe Anwendungen genutztwerden. Nach dem Anschließen eines Monitors an den HDMI-Anschluss und einerUSB-Tastatur kann das BeagleBoard gestartet werden. Diese beiden Peripheriegeratesind zum Einrichten notig. Alternativ kann es auch uber eine Ethernet-Verbindungund SSH von einem anderen Computer eingerichtet werden. Wird eine grafische Ober-flache installiert, kann es wie ein Computer bedient werden. Da es lediglich einenUSB-Anschluss besitzt, wird jedoch ein USB-Hub benotigt, um Tastatur und Mausanzuschließen.

(a) Oberseite des BeagleBoard Black [2] (b) Unterseite des BeagleBoard Black [3]

Abbildung 1: BeagleBoard Black

Auf dem BeagleBoard Black konnen verschiedene Linux-Distributionen installiertwerden. Im Auslieferungszustand ist zunachst Angstrom-Linux installiert. Fur dasneue Aktuatorsystem bietet sich Ubuntu 14.04 Trusty an. Der Vorteil dieser Distri-bution ist die Moglichkeit, das teameigene Framework mit ROS Indigo zu installie-ren. Uber den Ethernetanschluss werden die Daten mit ROS und einer TCP- oder

7

3 LOSUNGSANSATZ

UDP-Verbindung zwischen dem BeagleBoard Black und dem zentralen Computer desRoboters ausgetauscht.

Fur den Betrieb benotigt das BeagleBoard Black eine 5V Eingangsspannung. Diesewird auf dem Board auf 3,3V heruntergeregelt. Alle Ein- und Ausgange des Beagle-Boards arbeiten mit 3,3V. Lediglich der ADC darf nicht an Spannungen uber 1,8Vangeschlossen werden, da er sonst kaputtgeht.

Device Tree und Pinfunktionen

Die Pins des ARM-Prozessors werden uber die beiden Buchsenleisten (P8 und P9)des BeagleBoards nach außen gefuhrt. Viele der Pins haben mehrere Funktionen. EineGrundfunktion jedes Pins ist ein einfacher digitaler Ein- oder Ausgang mit einer Pul-lup3- oder Pulldown4-Funktion. Die anderen Funktionen lassen sich uber den DeviceTree aktivieren bzw. deaktivieren. Der Device Tree beschreibt dem Prozessor, wieer die verschiedenen Datenleitungen nutzen soll. Fur die Ansteuerung der Kompo-nenten sind die Funktionen ADC, PWM, SPI und I2C wichtig. Um den Device Treebearbeiten zu konnen, wird der dtb-rebuilder5 von RobertCNelson benotigt. Dieserbringt schon einen Basis Device Tree mit, der so angepasst werden muss, dass dasBeagleBoard die benotigten Funktionen ausfuhren kann. Ein Device Tree setzt sichaus mehreren Dateien zusammen. In einer .dts-Datei werden alle .dtsi-Dateien ein-gebunden, die zu dem Device Tree gehoren sollen. In den einzelnen .dtsi-Dateienwird dem Prozessor beschrieben, wie die Struktur aufgebaut ist und welche Datenlei-tungen mit Funktionen belegt werden sollen. Der fur das Projekt angepasste DeviceTree heißt am335x-boneblack-cnmod.dts. In diesen werden die .dtsi-Dateien fureMMC, HDMI, CAN, I2C und SPI eingebunden. Diese sind bereits als Vorlagen inden Dateien des dtb-rebuilder vohanden. Nach einem Neustart stehen die Funktionenzur Verfugung. Fur das Auslesen der ADC- und die Ansteuerung der PWM-Pins musseine neue dtsi-Datei angelegt und es mussen weitere Einstellungen in den Systemda-teien vorgenommen werden.

1 &tscadc

2 status = "okay";

3 adc

4 ti ,adc -channels = <0 1 2 3 4 5 6>;

5 ;

6 ;

Listing 1: Quellcode zum Aktivieren des ADC und einzelner Kanale

3Verbindung einer Signalleitung uber einen Widerstand mit einem hoheren Spannungspotential.4Verbindung einer Signalleitung uber einen Widerstand mit einem niedrigeren Spannungspoten-

tial.5https://github.com/RobertCNelson/dtb-rebuilder

8

3 LOSUNGSANSATZ

Fur die Aktivierung des ADC wird die neue Datei am335x-bone-robot.dtsi an-gelegt und in den Device Tree eingebunden. In Listing 1 steht der Quellcode, der indie Datei eingefugt wird, um den Status des ADC-Gerates auf okay zu setzen unddie Kanale, welche genutzt werden sollen, zu aktivieren. Es konnen bis zu 7 Kanaleaktiviert werden.

Um die Spannungswerte der einzelnen ADC-Kanale zu erhalten, muss die Datei /sys/bus/iio/devices/iio:device0/in_voltage*_raw6 ausgelesen werden. Dies isterst nach einem Neustart des Systems mit neuem Device Tree moglich. An diesenKanalen konnen Spannungen bis zu 1,8V angelegt und ausgelesen werden. Die 1,8Vwerden in 1024 Stufen aufgelost. Daraus ergibt sich eine Genauigkeit von etwa 1,8mV.Multipliziert man das ausgelesene Ergebnis mit dem Faktor 18/10240, so erhalt mandie Spannung am jeweiligen ADC-Pin.

Um die PWM-Funktion nutzen zu konnen, muss der Status der PWM-Moduleauf okay gesetzt werden. Dies kann ebenfalls in der Datei geschehen, die fur dieAktivierung des ADC angelegt wurde.

1 &epwmss0

2 status = "okay";

3 ;

4 &epwmss1

5 status = "okay";

6 ;

7 &epwmss2

8 status = "okay";

9 ;

10

11 &ehrpwm0

12 status = "okay";

13 ;

14 &ehrpwm1

15 status = "okay";

16 ;

17 &ehrpwm2

18 status = "okay";

19 ;

Listing 2: Quellcode zum Aktivieren der EHRPWM-Kanale

Zuerst mussen drei epwmss-Module und im Anschluss die drei PWM-Module ehrpwm

aktiviert werden. Sie besitzen jeweils zwei Kanale (A und B). Zusatzlich gibt es zweieCAP-Module, welche entweder ein PWM-Signal generieren konnen oder zum Erfas-sen (engl. Capture) eines externen Signals dienen. Ist der eCAP-Modus ausgewahlt,so zahlt ein interner Zahler aufwarts und speichert den Wert, wenn ein Wechsel der Si-

6Fur das Sternchen sind die Ziffern 0 bis 6 entsprechend des Kanals einzutragen.

9

3 LOSUNGSANSATZ

gnalflanke erkannt wird. So kann die Zeit zwischen zwei Pulsen gemessen werden. Dafur die Ansteuerung der Komponenten keine acht PWM-Signale benotigt werden, wirdauf die eCAP-Signale nicht weiter eingegangen. Die benotigten Kanale konnen nichtim Device Tree eingefugt werden, sondern erst nach einem Neustart des Systems inden Systemdateien eingestellt werden. Hierfur wird in das Verzeichnis /sys/devices/ocp.3/ navigiert. Die PWM-Kanale konnen auf verschiedene Pins der Buchsenleistendes BeagleBoards gelegt werden. Fur die Peripherieplatine soll EHRPWM2A (auf derBuchsenleiste P8 Pin 19), EHRPWM2B (P8 Pin 13), EHRPWM1A (P9 Pin 14) undEHRPWM1B (P9 Pin 16) genutzt werden. Jeder Pin besitzt einen eigenen Ordner.Der Name ist entsprechend seiner Position auf der Buchsenleiste gewahlt worden. DieOrdner der ausgewahlten PWM-Pins mussen geoffnet und in die state-Dateien pwmeingetragen werden. Um die PWM-Signale zu aktivieren und zu konfigurieren, mussin das Verzeichnis /sys/class/pwm/ navigiert werden. Die drei darin enthaltenenOrdner stehen fur die drei PWM-Kanale EHRPWM0, EHRPWM1 und EHRPWM2.In diesen Ordnern wiederum befinden sich, sofern die entsprechenden PWM-Pins ex-portiert wurden, die Ordner pwm0/ und pwm1/. 0 steht dabei fur Pin A, 1 fur PinB. Um einen Pin zu exportieren, wird der Datei export die Ziffer des Pins mit echo[Ziffer] > export ubergeben. In den Ordnern pwm0/ bzw. pwm1/ kann nun das

entsprechende Signal eingestellt werden. In die Datei period wird die Periodendauerdes Signal in Nanosekunden hineingeschrieben. duty_cycle enthalt die Pulsdauer desSignals in Nanosekunden. Mit der Datei polarity kann das PWM-Signal invertiertwerden. Tragt man in enable eine 1 ein, so beginnt das BeagleBoard Black das Signalzu generieren.

Zum Schluss muss der erstellte Device Tree kompiliert und eingebunden werden.Der Befehl make im dtb-rebuilder-Verzeichnis erstellt aus allen *.dts-Dateien furdas BeagleBoard interpretierbare *.dtb-Dateien, welche mit dem Befehl sudo make

install in das entsprechende Systemverzeichnis kopiert werden. Damit die geanderte.dtb-Datei beim Bootvorgang geladen wird, muss dies in der /boot/uEnv.txt ver-merkt werden. Dazu wird die Zeile mit dtb= zu dtb=am335x-boneblack-cnmod.dtb

geandert. Wird das BeagleBoard neu gestartet, so stehen die im Device Tree vorge-nommenen Anderungen zur Verfugung.

3.1.3 Inertiale Messeinheit

Bisher nutzten die Roboter zur Orientierung unter anderem einen Kompasssensor.Dieser wurde uber den CAN-Bus vom ATmega128 ausgelesen. In Zukunft wird an-gestrebt, weitere Daten wie Beschleunigungen und Drehraten zu messen und auszu-werten. Hierzu bietet sich eine inertiale Messeinheit an. Sie besteht aus mehrerenkombinierten Inertialsensoren, welche Beschleunigungen oder Drehraten messen. Umdie Genauigkeit der Sensoren zu verbessern, sind IMUs haufig mit Magnetfeldsensoren(Kompasssensoren) ausgestattet.

10

3 LOSUNGSANSATZ

Bei den Recherchen fiel zunachst die Razor IMU von Sparkfun auf. Sie besitzt dreieinzelne ICs, die Beschleunigungen, Drehraten und Magnetfelder messen. Ausgelesenwerden die drei ICs von einem ATmega328. Dieser gibt sie uber eine serielle Schnitt-stelle aus. Allerdings ist sie mit $75 (ca. 70AC) relativ teuer.Bei der Suche nach einer gunstigeren IMU fiel die GY-80 mit ca. 17AC auf. Sie istdie gunstigste gefundene IMU und besitzt neben den Sensoren fur Beschleunigungen,Drehraten und Magnetfeldern auch Sensoren fur Temperatur und Druck. Die Datender einzelnen Sensoren konnen per I2C ausgelesen werden. Dieser Sensor ist allerdingsnur in Asien verfugbar und musste importiert werden.Die IMU LSM9DS0 von Adafruit vereint alle ihre Sensoren in einem IC. Sie kannneben Beschleunigungen, Drehraten und Magnetfeldern auch die Umgebungstempe-ratur messen und ist fur 24AC in Europa erhaltlich.

Sensor Wertebereich Genauigkeit

Beschleunigung

± 2g 0.061mg± 4g 0.122mg± 6g 0.183mg± 8g 0.244mg± 16g 0.732mg

Kompass

± 2gauss 0.08mgauss± 4gauss 0.16mgauss± 8gauss 0.32mgauss± 12gauss 0.48mgauss

Drehraten± 245dps 8.75mdps± 500dps 17.50mdps± 2000dps 70mdps

Tabelle 2: Genauigkeit der einzelnen Inertialsensoren

Die LSM9DS0 von Adafruit kann mit 3,3V oder Dank des auf dem Board vor-handenen Linearreglers auch mit 5V betrieben werden. Die Daten der einzelnen Sen-soren konnen per SPI oder I2C ausgelesen werden. Außerdem stehen Interrupts zurVerfugung, die anzeigen, wann neue Daten zum Auslesen bereit sind. Im LSM9DS0werden die Daten der einzelnen Inertialsensoren in 8 Bit großen Registern gespeichert.Pro Achse stehen dafur zwei Register (16 Bit) zur Verfugung. Wie diese auszulesensind, ist im Datenblatt des LSM9DS0 nachzulesen. Die Genauigkeit der einzelnenSensoren hangt von der Große des zu messenden Bereichs ab und ist in Tabelle 2nachzulesen. Je kleiner dieser gewahlt wird, desto genauer konnen die Sensoren denWert ausgeben.

Die Entscheidung unter den drei untersuchten inertialen Messeinheiten fiel auf dieLSM9DS0 von Adafruit. Sie vereint einen gunstigen Preis mit ausreichender Genau-

11

3 LOSUNGSANSATZ

Abbildung 2: Inertiale Messeinheit Adafruit LSM9DS0 [1]

igkeit und ist in Europa erhaltlich.

3.1.4 Lichtdetektor

Die Lichtschranke soll dem Roboter helfen zu erkennen, ob sich der Ball in derBallfuhrung befindet oder nicht, da dies durch die Kamera fur den Roboter nichtimmer korrekt erkennbar ist. Hierzu wurde in den Robotern bisher ein fertiges Mo-dul von Conrad7 verbaut. Da dieses nicht zuverlassig funktionierte, wurde es außerBetrieb genommen. Das alte Modul war zudem recht groß. Es bestand aus zwei Plati-nen. Eine diente als Sender, die andere als Empfanger. Die Empfangerplatine musstemittels Potentiometer zunachst eingestellt werden, um das richtige Signal des Sen-ders zu empfangen. Erkannte sie das richtige Signal, so wurde ein Relais ausgelostmit dem großere Strome geschaltet werden konnen. Fur das Aktuatorsystem ist esjedoch nicht notig einen großen Strom zu schalten. Das BeagleBoard muss lediglicheinen geanderten Spannungspegel des Lichtdetektors detektieren. Der Lichtdetektorsollte moglichst klein, gunstig und Resistent gegen Storungen sein.Bei den Recherchen ist der Lichtdetektor IS471 von Sharp aufgefallen. Er besitzt einintegriertes Modulationssystem. Uber dieses steuert er eine Infrarot-LED (IR-LED)an. Empfangt der Detektor sein eigenes moduliertes Signal, so weiß er, dass sichnichts in der Lichtschranke befindet. Kann er sein Signal nicht erkennen, so signali-siert er durch eine Spannungspegelanderung, dass sich ein Objekt zwischen Senderund Empfanger befindet. Auf diese Weise lassen sich Storungen durch Umgebungs-licht reduzieren. Als IR-LED wird in Zusammenhang mit dem IS471 haufig die OsramLED LD274 verwendet. Sie besitzt eine hohe Lichtstarke und eine Wellenlange von950nm, auf die der Lichtdetektor IS471 am besten reagiert. Fur den Einbau im Ro-

7IR-Lichtschranke Sender/Empfanger Best.-Nr.: 19 17 10

12

3 LOSUNGSANSATZ

boter sind daher der Lichtdetektor IS471 zusammen mit der IR-LED LD274 gewahltworden.

3.1.5 High Power Motortreiber

Die Ballfuhrung des Roboters wird uber zwei Motoren angesteuert. Diese erhaltenihren Strom von zwei High Power Motortreibern. Diese wurden als fertiges Modul beirobotikhadware.de8 gekauft und auch schon auf der alten Aktuatorplatine eingesetzt.Fur das neue Aktuatorsystem sollen die Treiber beibehalten werden, da sie bisherohne Fehler oder Storungen funktionierten.

Funktion PWM DIR OUTA OUTB

Vorwarts High Low Low HighRuckwarts High High High Low

Bremse Low egal Low Low

Tabelle 3: Ansteuerung des Motortreibers

Angesteuert werden die Motortreiber uber jeweils zwei Signale. Mit dem PWM-Signal wird die Ausgangsspannung und somit die Geschwindigkeit des Motors be-stimmt. Das DIR-Signal legt fest, in welche Richtung sich der Motor dreht. Zur siche-ren Anderung der Drehrichtung sollte das PWM-Signal auf 0 gesetzt werden. In derTabelle 3 ist die Ansteuerung kurz dargestellt. Die Spannungspegel werden dabei mitL fur Low und H fur High beschrieben. Auftretende Fehler werden uber die zwei Feh-lersignale FF1 und FF2 aufgezeigt. Bei einem Kurzschluss schaltet sich der Treiberaus. Um ihn zu aktivieren muss das RESET-Signal kurz auf Low gezogen werden.

3.1.6 Optischer Fluss Sensor

Zur Erkennung der Ballbewegung dient ein Optischer Fluss Sensor des Herstellers3DRobotics9. Dieser ist in der Projektarbeit Erkennung der Ballbewegung bei einemautonomen Fußballroboter von Timo Heumuller untersucht und ausgewahlt worden.

Der Optische Fluss Sensor ist eine Platine, die mit dem Maussensor ADNS-3080und einigen Bauteilen zur Spannungsversorgung bestuckt ist. Vor der Linse des Maus-sensors ist ein Objektiv angebracht, mit dem das Bild scharf gestellt werden kann.Dies kann uber den Wert Quality of Surface uberpruft werden. Je besser die Ober-flache erkannt wird, desto großer ist der Wert. Zum Auslesen dieses Wertes und denWerten der Ballbewegung besitzt der Optische Fluss Sensor eine SPI-Schnittstelle.Erkannt werden Bewegungen in x- bzw. y-Richtung, jedoch keine Drehungen. Um

8http://www.robotikhardware.de/9http://3drobotics.com/

13

3 LOSUNGSANSATZ

den Optischen Fluss Sensor neu zu starten, kann das Resetsignal auf das High-Levelgezogen werden. Soll Energie gespart werden, kann der Sensor uber das NPD-Signalin einen Schlafmodus versetzt werden.

3.1.7 Verschaltung und Platinenlayout

Die Verschaltung der Bauteile ist mit Hilfe des Programms EAGLE vorgenommenworden. EAGLE ist eine Software der Firma CadSoft10 zum Erstellen von Leiter-platten. Im Schaltplaneditor wird bestimmt, welche Bauelemente verwendet werdenund in welcher Weise sie verbunden sein sollen. Ihre Position auf der Platine und derVerlauf der elektrischen Leitungen wird mit dem Layouteditor festgelegt.

Der Schaltplan und das Layout wurden großtenteils selbst erstellt. Die Beschaltun-gen einzelner Bauteile wurde in den Datenblattern recherchiert. Dabei wurde daraufgeachtet, die Pins der Bauteile und Stecker jeweils an die richtige Spannungsver-sorgung anzuschließen und mit den ausgewahlten Bussen zu verbinden. Im Layoutwurden die Bauteile so platziert, dass Bauteile und Leitungen, die hohere Stromefuhren, nicht in der Nahe von Daten- oder Sensorleitungen liegen, um diese moglichstnicht zu storen. So sind auf der einen Halfte der Platine die Spannungsversorgungsowie die Motortreiber und Servomotoranschlusse und auf der anderen Halfte dasBeagleBoard Black sowie die Stecker zu den Sensoren untergebracht.

Abbildung 3: Schematische Darstellung der Platine

10http://www.cadsoft.de/

14

3 LOSUNGSANSATZ

Ein Fußballroboter des Carpe Noctem Cassel -Teams besitzt mehrere Spannungs-level. Mit 12V wird im Roboter der zentrale Computer betrieben. Am 24V Netzsind großere Verbraucher, wie die Motoren des Antriebs und der Ballfuhrung, dieAktuatorplatine sowie die Platine und Spule des Schussmechanismus, angeschlossen.Um die Recheneinheit - das BeagleBoard Black - des neuen Aktuatorsystems mitStrom zu versorgen, wird eine 5V Spannung benotigt. Diese wird von dem Linearreg-ler LM340 bereitgestellt, welcher die Spannung von 24V auf 5V herunterregelt undbis zu 1A an Strom liefern kann. Verbunden wird das BeagleBoard mit der Periphe-rieplatine durch das Aufstecken auf zwei Stiftleisten (2x23). Fur die Komponenten,die eine 3,3V Spannung benotigen, wird die geregelte 3,3V Spannung des Beagle-Board genutzt. Bei der alten Aktuatorplatine war der Mikrocontroller am selben 5VNetz angeschlossen wie der Servomotor, der unter Last mehr Strom verbraucht undsomit fur einen Spannungsabfall im 5V Netz sorgt. Dies hatte dazu fuhren konnen,dass der Microcontroller sich auf Grund zu geringer Spannung neu startet. Um einenSpannungsabfall auf der neuen Peripherieplatine zu verhindern, ist ein zweiter 5V Li-nearregler auf der Platine platziert worden. Dieser soll den Servomotor und bei Bedarfexterne Elektronik versorgen. Hierfur wird der LM1085 gewahlt. Er kann bis zu 3Aan Strom liefern. Damit konnte ein zusatzlicher Servomotor betrieben werden, fallsin Zukunft Bedarf dafur entsteht. Die externen Verbraucher konnen an diesen Regleruber die beiden Stiftleisten JP3 und JP4 angeschlossen werden. Um den Servomotoransteuern zu konnen, muss zunachst das 3,3V PWM-Signal des BeagleBoard auf 5Vgewandelt werden. Dies ubernimmt der Pegelwandler TXB0108. Neben diesem Signalwerden die SPI-Signale sowie CAN RX und CAN TX ebenfalls gewandelt. Die 5VSPI-Signale sind fur neue Sensoren oder Erweiterungsplatinen vorgesehen. Die bei-den CAN-Signale sind am CAN-Transceiver MCP2551 angeschlossen. Dieser stelltden Treiberbaustein fur die CAN-Buskommunikation der Peripherieplatine dar.

Um den HDMI-Anschluss und den SD-Kartenslot des BeagleBoard Blacks sto-rungsfrei nutzen zu konnen, ist auf insgesamt 29 GPIO-Pins verzichtet worden. Sobesteht die Moglichkeit, im Notfall das BeagleBoard zu uberprufen, indem man es miteinem Monitor verbindet oder Systemdaten auf einer Speicherkarte mitloggt. Diesekann spater ausgelesen werden, um den Fehler zu finden und beheben zu konnen.Trotz dieser Entscheidung bleiben genug freie GPIOs, um die notigen Komponentenanzusteuern. Sollten der HDMI-Anschluss und der SD-Kartenslot nicht mehr benotigtwerden, konnen die 29 Pins in zukunftigen Erweiterungen andere Aufgaben ausfuhren.Unter anderem wurden zwei PWM-Signale und eine UART-Schnittstelle nutzbar wer-den.

Ein Teil der Aufgabe besteht darin, Arbeiten an der Elektronik im Roboter weiterzu vereinfachen. Daher wurde versucht das neue Aktuatorsystem sehr kompakt zugestalten und alle externen Komponenten - wenn moglich - auf der neuen Periphe-rieplatine zu platzieren. Um bei Defekten die Komponenten leichter austauschen zu

15

3 LOSUNGSANSATZ

konnen, sind Stiftleisten vorgesehen, auf die sie auf- oder von denen sie abgestecktwerden konnen.

(a) ADUM1200 (b) ADUM1300

Abbildung 4: Beschaltung der ADUM-Bausteine

Wie schon bei der alten Platine ist das Design so ausgelegt, dass die Motor-treiber uber eine Stiftleiste mit der Platine verbunden werden konnen. Um even-tuelle Storungen durch die Motortreiber auf das restliche System ausschließen zukonnen, werden die Signalleitungen von den beiden Treibern zum BeagleBoard Blackgalvanisch getrennt. Hierzu werden pro Motortreiber die zwei digitalen IsolatorenADUM1200 und ADUM1300 des Herstellers Analog Devices11 verwendet. Im Ver-gleich zu Optokopplern haben sie eine geringere Leistungsaufnahme und konnenhohere Frequenzen schalten. Sie ubernehmen auch das Wandeln der Pegel von 3,3Vauf 5V bzw. von 5V auf 3,3V. In Abbildung 4 ist die Beschaltung der beiden ADUM-Bausteine zu sehen. Das zwischen VDD1 und GND1 anliegende Potential ist diemaximale Spannung, die an den Eingangspins VIA und VIB sowie beim ADUM1300VIC anliegt. Fur die Ausgangspins VOA, VOB und VOC ist die Spannung maximalso groß, wie das Potential zwischen VDD2 und GND2. Die NC-Pins des ADUM1300sind im IC nicht verbunden und mussen daher nicht beschaltet werden. Mit dem PinVE2 kann der ADUM1300 ein- oder ausgeschaltet werden. Da der ADUM dauerhaftbetrieben werden soll, muss dieser Pin ebenfalls nicht verbunden werden.

Weiterhin kann auch die IMU einfach auf- oder abgesteckt werden. Im Vergleichzum alten Kompasssensor, welcher auf einer extra Platine an anderer Stelle im Ro-boter untergebracht war, werden die Kabel und der Platz eingespart. Die IMU wird

11http://www.analog.com/

16

3 LOSUNGSANSATZ

an die 3,3V Spannungsversorgung des BeagleBoard Black angeschlossen. Die Kom-munikation zwischen den beiden Komponenten findet uber den I2C-Bus statt. Dasie unmittelbar nebeneinander auf der Peripherieplatine untergebracht sind, besitzenihre kurzen Leitungen geringe Leitungskapazitaten. Eine Terminierung ist in diesemFall nicht notig, wird allerdings vorgesehen, um spater die Moglichkeit zu haben,hohe Takt-Frequenzen nutzen zu konnen. Dazu wird pro Busleitung jeweils ein 10kΩ-Widerstand zu 3,3V geschaltet. Zum Schutz des BeagleBoard vor Uberspannung wer-den 330Ω Serienwiderstande in die Leitungen eingebaut. Weitere vier GPIO-Pins desBeagleBoard werden mit den Interruptpins der IMU verbunden. Vom Sensor aus-geloste Interrupts konnen nun vom BeagleBoard erkannt und bearbeitet werden.

Abbildung 5: Beschaltung des Lichtdetektors IS471

Die Platinen der alten Lichtschranke werden wie der Kompasssensor ebenfallsnicht mehr benotigt. Ihre Aufgabe, die Modulation und Demodulation des Lichts,ubernimmt nun der Lichtdetektor IS471. Zusammen mit der IR-LED wird dieser imChassis verbaut. Fur den Einbau kann die alte Vorrichtung genutzt werden. Hierbeiwerden IR-LED und Lichtdetektor gegenuberliegend angebracht, sodass die Licht-schranke unterbrochen wird, sobald sich ein Ball im Kicker befindet. Die Versor-gungsspannung von 5V, Masse und die Signalleitung konnen uber das bereits verlegteChassis Connector Cable zum Chassis-Stecker gefuhrt werden. In Abbildung 5 ist zusehen, wie der Lichtdetektor mit dem Stecker und der IR-LED verbunden ist. Um dieIR-LED nicht zu beschadigen wird ein Vorwiderstand von 68Ω benotigt und zwischendie IR-LED und 5V eingefugt. Da die Signalleitung Vo einen Pegel von 5V besitzt,muss dieser auf der Peripherieplatine mit Hilfe eines Spannungsteilers auf 1,8V ge-senkt werden. Wird das Signal nicht auf 1,8V angepasst, konnte der ADC-Eingangdes BeagleBoards beschadigt werden.

In Tabelle 4 sind die verwendeten Stecker aufgelistet, welche zum Verbinden derPlatine mit den externen Komponenten und der Spannungsversorgung genutzt wer-den. Die JST EH Stecker besitzen ein Rastermaß von 2,5mm, werden durch die Platinegesteckt und verlotet. Der Kontakt des Buchsengehauses kann an das Kabel gekrimpt

17

3 LOSUNGSANSATZ

Komponente Steckerart Anzahl der Pins

BeagleBoard BlackStiftleiste 2x23 46Stiftleiste 2x23 46

CAN Wannenstecker AKL 330-04 4

IMUStiftleiste 1x5 5Stiftleiste 1x8 8

Lichtschranke JST EH 3Motortreiber (links) Stiftleiste 1x8 8Motortreiber (rechts) Stiftleiste 1x8 8Optischer Fluss Sensor JST EH 8Potentiometer Stiftleiste 1x3 3Spannungsversorgung 24V Wannenstecker AKL 230-02 2Schalterbox Wannenstecker 2x5 10Servomotor Stiftleiste 1x3 3SPI Wannenstecker 2x3 6

Tabelle 4: Steckverbindungen auf der Platine

werden und rastet beim Schieben in das Gehause ein. Wird das Buchsengehause inden Stecker auf der Platine gesteckt, so sichert ein kleiner Widerhaken, dass sichdie Buchse durch Vibration nicht von selbst lost. Mit diesen Steckern werden dieLichtschranke und der Optische Fluss Sensor mit der Peripherieplatine verbunden.Die Schalterbox wird uber einen 10-poligen Wannenstecker angebunden. Vibrationenkonnten jedoch dazu fuhren, dass sich dieser Stecker lost. Da dies bisher jedoch nichtgeschehen ist, werden diese Stecker weiterhin verwendet.

3.2 Software

Im Folgenden wird die Software auf dem BeagleBoard Black genauer beschrieben.Dabei wird zunachst auf die genutzte Bibliothek eingegangen und im Anschluss dieeigene Programmstruktur dargestellt.

3.2.1 Ansteuern der Pinfunktion

Um die Funktionen des BeagleBoards zu nutzen, ist es moglich, Bibliotheken zu ver-wenden. Hierbei fallt die Entscheidung auf die BlackLib12 (v2.0). Sie ist eine C++-Bibliothek fur das BeagleBoard Black und erstellt worden, um analoge Eingangeauszulesen, PWM-Signale zu generieren, GPIO-Pins anzusteuern oder mit anderen

12http://www.blacklib.yigityuce.com/index.html

18

3 LOSUNGSANSATZ

Bauteilen uber I2C, SPI oder UART zu kommunizieren. Damit deckt sie alle Funk-tionen ab, die benotigt werden, um mit externen Komponenten arbeiten zu konnen.Die BlackLib ist in mehrere Klassen unterteilt, die nach Bedarf eingebunden undverwendet werden konnen.

Fur die Ansteuerung und das Auslesen der externen Komponenten werden dieKlassen fur GPIO (BlackGPIO), ADC (BlackADC) und PWM (BlackPWM), fur dieKommunikation die Klassen fur I2C (BlackI2C) und SPI (BlackSPI) eingebunden.Operationen zum Setzen oder Loschen eines Pins werden mit Methoden der KlasseBlackGPIO ausgefuhrt. Fur jeden GPIO-Pin wird mit dem Konstruktor ein Objekterstellt und festgelegt, ob dieser als Ein- oder Ausgangspin fungieren soll. Mit denMethoden des Objekts kann nun der Wert eines Ausgangspins gesetzt oder eines Ein-gangspins ausgelesen werden. Auch eine spatere Anderung der Datenrichtung, ob einPin als Ein- oder Ausgang arbeitet, ist moglich.Die Klasse BlackADC stellt dem Benutzer Funktionen und Methoden zur Benutzungdes Analog-Digital-Wandlers zur Verfugung. Pro ADC-Kanal, der im Programm aus-gelesen werden soll, wird mit dem Konstruktor ein Objekt erstellt. Mit seinen Me-thoden konnen die Werte, die am jeweiligen Kanal anliegen, ausgelesen werden undals String, Integer oder Float zuruckgegeben werden.Die Objekte der Klasse BlackPWM steuern die einzelnen PWM-Pins an. Mit den Me-thoden ist das Einstellen der Perioden- und Pulsdauer moglich. Außerdem kann mitihnen das Generieren des Signals gestartet und gestoppt werden. Damit der richtigePWM-Pin angesteuert werden kann, muss zunachst die Funktion findPwmTestName(

pwmName pwm) modifiziert werden. Die Funktion searchDirectoryOcp(BlackCore::

PWM_P8_13) kann nicht genutzt werden, da sie einen Fehler beim Suchen des Pfadesfeststellt. Daher wird der Pfad manuell eingetragen. Dies liegt daran, dass die Black-Lib v2.0 fur das BeagleBoard mit der Kernelversion 3.8 geschrieben ist. Fur denEinsatz im Roboter ist jedoch der 3.14 Kernel notwendig, da erst ab dieser VersionUbuntu 14.04 und ROS unterstutzt werden.Die BlackI2C -Klasse stellt Funktionen zur Benutzung des I2C-Bus zur Verfugung.Zunachst wird ein Objekt erstellt, mit dem ein Kommunikationsbus geoffnet wird.Hierbei wird bereits festgelegt, mit welchem Bauteil kommuniziert werden soll. Sol-len zwei oder mehr Bauteilen angesprochen werden, mussen mehrere Objekte erstelltoder die Adresse zwischen dem Auslesen der einzelnen Sensoren geandert werden. DieRegister der Bauteile konnen mit Hilfe der read- und write-Methoden ausgelesen bzw.beschrieben werden.Die BlackSPI -Klasse stellt Funktionen zur Benutzung des SPI-Bus zur Verfugung.Zunachst wird ein Objekt erstellt, mit dem ein Kommunikationsbus geoffnet wird.Mit der uberladenen transfer -Methode werden die Daten, 8 Bit oder ein vielfaches,an den Baustein ubertragen. Die anderen Methoden helfen dabei Einstellungen unddie Geschwindigkeit des SPI-Bus zu andern.

19

3 LOSUNGSANSATZ

Alle Klassen besitzen Methoden, um zu kontrollieren, ob die zuletzt ausgefuhrteOperation erfolgreich ausgefuhrt werden konnte. Hierzu kann die Methode fail()

aufgerufen werden. Falls es einen Fehler gibt, liefert sie true zuruck. Wird ein Para-meter mit ubergeben, so wird lediglich auf diesen Fehler uberpruft. Die Fehlertypensind in der BlackErr.h festgelegt. Die Datei BlackDef.h enthalt alle wichtigen Kon-stanten und Aufzahlungstypen der Bibliothek.

Jeder Pin besitzt einen Ordnerpfad und Dateien, in denen festgehalten wird, wel-che Funktion er gerade ausfuhrt und wie er eingestellt wurde. Die Klasse BlackCorestellt Methoden zur Verfugung, die zum Ausfuhren von Systembefehlen oder zumAuffinden der Treiberpfade dienen. Alle anderen Klassen erben von dieser. Die Sys-tembefehle werden per popen-Funktion ausgefuhrt. Der Zugriff auf die Treiberdateienwird uber die Klasse fstream abgewickelt. Diese Dateizugriffe benotigen jedoch einegewisse Zeit, sodass es mehr als 300µs dauert, um einen Pin zu setzen oder auszule-sen. Will man den Spannungswert eines ADC-Pins auslesen, dauert diese Operationbis zu 1,3ms. Im spateren Programm muss daher darauf geachtet werden, dass dieGeschwindigkeit des Systems nicht unter den zu langsamen Dateizugriffen leidet.

3.2.2 Beschreibung der Programmstruktur

Das selbstgeschriebene Programm actuator.cpp wird erstellt, um alle Sensoren ausle-sen und Aktoren ansteuern zu konnen. Die Hauptroutine soll mit einer Frequenz vonmindestens 30Hz ausgefuhrt werden, da der zentrale Computer ebenfalls mit 30Hzarbeitet und das Aktuatorsystem schnell auf neue Anforderungen reagieren soll. Diegesamten Befehle mussen daher in weniger als 33ms abgearbeitet werden.

Im Hauptprogramm wird zunachst ROS mit den einzelnen ROS-Topics initiali-siert. Uber die ROS-Topics werden die Informationen mit dem Industriecomputerausgetauscht. Danach werden sieben Threads gestartet, um Zeit zu sparen, die durchdie langen Dateizugriffe verlorengeht. Die Hauptschleife wurde fur einen Durchlaufsonst zu lange benotigen und zu langsam auf neue Befehle reagieren.Es gibt jeweils einen Thread fur den linken und rechten Motortreiber, die Auswahlder Schaufel, das Auslesen des Maussensors, der IMU, die Lichtschranke und dieSchalterbox.

Im Thread fur den linken bzw. rechten Motortreiber wird jeweils die MethodecontrolBallHandling() der BallHandle-Klasse ausgefuhrt. Sie stellt das DIR- undPWM-Signal fur den Motortreiber ein. Beim Wechsel der Drehrichtung achtet dieseFunktion darauf, dass zum Zeitpunkt des Richtungswechsels das PWM-Signal auf 0gesetzt wurde, da sonst der Motortreiber schaden nehmen konnte [High-Power-SerieMotortreiber 23, S. 6]. Die Daten, nach denen das PWM- und DIR-Signal eingestelltwerden, berechnet zunachst die Funktion setBallHandling(int8_t value). Sie wirdjedes Mal aufgerufen, wenn eine neue Nachricht im ROS-Topic BallHandleCmd ein-trifft. In der Nachricht sind zwei Werte enthalten, welche die Geschwindigkeiten der

20

3 LOSUNGSANSATZ

beiden Motortreiber angeben. Der Betrag dieses Wertes ist proportional zur Geschwin-digkeit. Das Vorzeichen gibt die Drehrichtung des jeweiligen Motors an. Uber denParameter value wird die Geschwindigkeit an die jeweilige Funktion ubergeben.Die Methode setTimeout() stoppt, wenn neue Befehle vom zentralen Computer aus-bleiben, die Ballfuhrung und damit auch den Motor. Mit der Methode getError()

wird der Fehlerzustand des Motortreibers ausgelesen. Eine Funktion, die auf diesenFehler reagiert, muss noch programmiert werden.

Im Thread fur die Auswahl der Schussschaufel wird zunachst uberpruft, wann derletzte Befehl vom zentralen Computer eingegangen ist. Sollte ein Timeout vorliegen,so wird das PWM-Signal des Servomotors deaktiviert. Andernfalls, wird uberpruft, obdie Schaufelauswahl aktiv ist und ein PWM-Signal passend zur ausgewahlten Schau-fel generiert. Die Periodendauer wird dabei auf 20ms festgelegt und die Pulsdauerzwischen 1ms und 2ms variiert. Die genauen Werte mussen, damit die Schussschaufelrichtig ausgewahlt wird, individuell fur jeden Roboter eingestellt werden. Aktualisiertwird die Schaufelauswahl durch die Funktion handleShovelSelectControl(const

msl_actuator_msgs::ShovelSelectCmd msg), die aufgerufen wird, sobald eine neueNachricht im ROS-Topic ShovelSelectCmd eintrifft.

Im Thread des Optischen Fluss Sensors werden die ausgelesen Sensorwerte mitder Funktion send_motion_burst(timeval time_now, ros::Publisher *mbcPub)

der OpticalFlow -Klasse an den zentralen Computer geschickt. Als Vorlage fur dieeinzelnen Methoden dieser Klasse dient der Quellcode des Projektes [9], in welchembereits das Auslesen des Sensors programmiert wurde. Er muss lediglich an C++und die BlackLib angepasst werden. Bevor die Daten an den zentralen Computerubertragen werden, werden sie mit der Methode update_motion_burst(timeval

time_now) ausgelesen. Falls der Sensor aufgrund schlechter Lichtverhaltnisse die Be-wegung des Balls schlecht erkennen kann, besteht die Moglichkeit, mit einer rotenLED die zu detektierende Flache zu beleuchten. Hierzu kann eine Nachricht an dasROS-Topic MotionLight gesendet werden.

Im Thread der inertialen Messeinheit sendet die Methode sendData(timeval

time_now, ros::Publisher *imuPub) die ausgelesenen Informationen an den zen-tralen Computer. Die Methode ist Teil der IMU -Klasse. In ihr gibt es weitere Metho-den, um die verschiedenen Informationen aus dem Sensor auszulesen. Ruft man dieMethode updateData(timeval time_now) auf, so werden alle notigen Funktionenzum Auslesen der Beschleunigung, Drehraten und Magnetfelder aufgerufen und dieDaten in Variablen gespeichert. Zur Zeit muss diese Methode regelmaßig aufgerufenwerden, um die aktuellen Daten zu erhalten. Richtet man den Sensor so ein, dass erInterrupts auslost, konnen diese dazu genutzt werden, um die einzelnen Informationenauszulesen, sobald sie verfugbar sind. Dies ist allerdings noch nicht implementiert.

Im Thread der Lichtschranke wird bei jedem Durchlauf kontrolliert, ob ein Ballim Kicker liegt und sie dadurch unterbrochen wurde. Sie sendet in jedem Fall eine

21

3 LOSUNGSANSATZ

Nachricht an das ROS-Topic HaveBallInfo. Der Thread der Schalterbox kontrolliert,ob und welcher Schalter bzw. Taster betatigt wird und sendet diese Information anden zentralen Computer. Hierfur stehen zwei ROS-Topics zur Verfugung. Der Statusdes Bundle-Schalters wird uber das Topic BundleStatus ubermittelt, die Informationuber den Vision-Taster wird uber das Topic VisionRelocTrigger mitgeteilt.

22

4 EVALUIERUNG

4 Evaluierung

Zur Evaluierung wurden alle Funktionen des Prototyps einzeln am Fußballrobotergetestet. Dazu wurde die Peripherieplatine mit den Aktoren und Sensoren, die im Ro-boter verbaut sind, verbunden. Der Quellcode wurde dafur so verandert, dass immernur eine Funktion getestet wurde, um mogliche Fehler auszuschließen. In Abbildung6 sieht man den bereits modifizierten Prototyp.

(a) Oberseite des Prototypen (b) Unterseite des Prototypen

Abbildung 6: Abbildung der Prototypenplatine

4.1 Inbetriebnahme

Dieser Abschnitt behandelt die erste Inbetriebnahme des BeagleBoard Black undder Peripherieplatine. Zunachst wird das BeagleBoard Black eingerichtet und im An-schluss die Spannungsversorgung der Peripherieplatine untersucht.

4.1.1 Einrichten des BeagleBoard Black

Zum Einrichten ist das BeagleBoard Black mit einem 5V Netzteil betrieben worden.Zunachst ist auf ihm die Linux-Distribution Ubuntu 14.04 Trusty installiert worden.Diese ist erforderlich fur die Installation von ROS Indigo und der Einrichtung des vomTeam genutzten Framework. Anschließend werden die GIT-Repositories cnc-msl, alicaund supplementary heruntergeladen und kompiliert. Hierbei fallt auf, dass aufgrunddes 32-bit ARM Prozessors einige Pakete nicht kompiliert werden konnen und so an-gepasst werden mussen, damit sie vom BeagleBoard Black nicht bzw. nur teilweise mitkompiliert werden. Die Computer auf denen das Framework bisher eingesetzt wordenist, besitzen 64-bit Prozessoren. Ein weiteres Problem ist das vollstandige Kompi-lieren des Workspaces. Fur den ersten kompletten Durchlauf benotigt es uber eine

23

4 EVALUIERUNG

Stunde. Dies ist besonders auf den RoboCup-Turnieren zu lange. Daher ist nur dasPaket msl_beagle_board_black zu kompilieren. Nach Abschluss des ersten Kompi-lierdurchlaufs fiel auf, dass die internen 4GB Flashspeicher zum großten Teil belegtwaren. Dies konnte dazu fuhren, dass das BeagleBoard Black etwas langsamer arbei-tet, da nicht genug Speicherplatz fur die Auslagerungsdateien zur Verfugung steht.Werden alle Pakete, die das BeagleBoard Black benotigt, in ein eigenes GIT-Reositoryverschoben, konnte neuer Speicherplatz geschaffen werden. Zudem verkurzt sich da-durch die Zeit des Kompilieren.

Anschließend mussen der Device Tree Compiler installiert und der dtb-rebuilderheruntergeladen werden. Mit diesen beiden Tools lassen sich die in Abschnitt 3.1.2angepassten Device Tree Dateien einbinden und installieren.

Damit das Programm mit Hilfe der BlackLib auf alle GPIO- und PWM-Pinszugreifen kann, mussen die Pins per export-Befehl zuganglich gemacht und dem Be-nutzerkonto, unter dem das Programm ausgefuhrt werden soll, Lese- und Schreibrech-te einiger Ordner gewahrt werden. Hierzu wird die Datei /etc/rc.local bearbeitet.Per export-Befehl werden den Pins Treiberdateien bereitgestellt. Die PWM-Funktionmuss in der state-Datei durch das Eintragen von pwm aktiviert werden. Anschließendwerden dem Benutzer Lese- und Schreibrechte in den Ordnern /sys/class/gpio, /sys/class/pwm und /sys/devices gegeben, die zum Ansteuern der Pins benotigtwerden. Ohne diese Berechtigungen muss das Programm mit Administratorrechtengestartet werden. Die einzelnen Befehle, die in der rc.local ausgefuhrt werden, konnenim Anhang A.2 nachgelesen werden.

4.1.2 Spannungsversorgung

Fur die ersten Tests der Peripherieplatine ist eine Eingangsspannung von 12V ange-legt worden. Bei dieser Spannung funktionieren zunachst alle angeschlossenen Kom-ponenten und es fließt ein Strom von etwa 200mA. Hierbei wird jedoch der Linear-regler LM340 sehr heiß. Wird der Kompiliervorgang der Pakete gestartet, steigt derStrom auf etwa 400mA an. Nach etwa einer Minute bricht die Spannungsversorgungzusammen und das BeagleBoard Black geht aus. Dies liegt an einer zu großen Ver-lustleistung, die vom LM340 produziert wird. Er wird zu heiß, da die passive Kuhlunguber die Platine nicht mehr ausreichend ist. Wie viele Linearregler besitzt auch derLM340 einen Schutzmechanismus, welcher den Stromfluss bei zu hoher Temperaturbegrenzt. Dies schutzt den LM340 vor Zerstorung, verringert jedoch den Ausgangs-strom so stark, dass das BeagleBoard nicht mehr betrieben werden kann.

Unter der Naherung, dass der Eingangsstrom dem Ausgangsstrom entspricht, kanndie Verlustleistung eines Linearreglers mit folgender Formel berechnet werden:

Pv = (Ue − Ua) ∗ Ia

24

4 EVALUIERUNG

Der Wirkungsgrad ergibt sich aus:

η =Ua ∗ IaUe ∗ Ie

Fur Ue = 12V , Ua = 5V und Ie ≈ Ia = 0, 2A ergibt sich dabei eine Verlustleistungvon Pv,12V = 1, 4W und ein Wirkungsgrad von η12V ≈ 41, 7%. Bei doppelt so großemStrom, wie es beim Kompilieren der Fall ist, wird auch doppelt so viel Warme alsVerlustleistung abgegeben, die nicht mehr passiv gekuhlt werden kann. Es ist daherdarauf zu achten, dass die Verlustleistung unter 1,4W liegt.Bei einer Spannung von 26V, wie sie bei voll aufgeladenen Akkus anliegt, steigt dieVerlustleistung im normalen Betrieb auf Pv,26V = 4, 2W an. Der Wirkungsgrad liegtnur noch bei η26V ≈ 19, 2%. Wird auf dem BeagleBoard Black kompiliert, mussen8,4W an Verlustleistung abgefuhrt werden.

Zur Losung des Problems gibt es zwei Moglichkeiten. Zum einen kann ein an-derer Linearregler verwendet und mit einem Kuhlkorper versehen werden. Diesermusste so dimensioniert werden, dass der Linearregler dabei seine maximale Be-triebstemperatur nicht uberschreitet. Ein schlechter Wirkungsgrad und eine hoheWarmeentwicklung mussen bei dieser Losung in Kauf genommen werden. Durch dieerhohte Warmeproduktion kann es in der Box, in der alle Platinen untergebracht sind,heiß werden, sodass die Kuhlung nicht mehr optimal funktioniert und der Kuhlergroßer ausgelegt werden muss.Alternativ verwendet man einen Schaltregler. Dieser besitzt gerade bei großeren Dif-ferenzen zwischen Ein- und Ausgangsspannung einen besseren Wirkungsgrad als Li-nearregler. Dies ist fur den Betrieb mit Akkumulatoren wichtig, da sonst unnotigEnergie in Warme umgewandelt wird.Der Schaltregler regelt die Ausgangsspannung durch Ein- und Abschalten der Ein-gangsspannung. Diese Pulse werden genutzt, um Energie in einer Spule zu Speichern.Zwischen den Pulsen entladt sich die Spule und stellt dem Verbraucher genugendStrom zur Verfugung. Ein ausreichend großer Kondensator sollte eingebaut werden,damit die Spannung stabilisiert wird. Der Kondensator sollte einen moglichst klei-nen inneren Verlustwiderstand (engl. Equivalent Series Resistance, ESR) besitzen.Er fasst die ohmschen Leitungs- und die dielektrischen Umpolungsverluste zusam-men. Ein kleiner ESR-Widerstand kann dadurch erreichen werden, dass man mehrereKondensatoren parallel schaltet. Uber ein Feedback an den Schaltregler kann dieser jenach Verbrauch die Spannung nachregeln. Sein Nachteil ist der großere Schaltungsauf-wand auf der Platine. Neben den Kondensatoren zur Spannungsstabilisierung werdeneine Spule und eine Freilaufdiode benotigt. Diese Bauteile benotigen extra Platz undkosten Geld.

Da die Spannungsversorgung mit dem Schaltregler den hoheren Wirkungsgradund dadurch geringere Verluste hat, wird diese Losung bevorzugt. Fur weitere Testsist daher der Schaltregler LM2575 ausgewahlt worden. Er ist fur einen Dauerstrom

25

4 EVALUIERUNG

von etwa 1A ausgelegt. Aus seinem Datenblatt (Seite 10, Diagramm Efficiency) gehthervor, dass die gesamte Schaltung mit Spule, Kondensator und Freilaufdiode beieiner Eingangsspannung von Ue = 12V und einer Ausgangsspannung von Ua = 5Veinen Wirkungsgrad zwischen 79% und 82% besitzt. Je mehr Strom die Schaltungdabei regelt, desto effektiver arbeitet der Schaltregler.

Die Verlustleistung lasst sich uber die Ausgangsleistung Pa = Ua ∗ Ia und demWirkungsgrad η wie folgt berechnen:

Pv =Pa

η∗ (1 − η)

Fur einen Wirkungsgrad von η = 79% bei Ia = 0, 2A und einer Ausgangsspannungvon Ua = 5V ergibt sich eine Verlustleistung von Pv ≈ 0, 266W . Bei gleichem Strom-verbrauch und einer Eingangsspannung von Ue = 26V , wie sie normalerweise amAktuatorboard anliegt, besitzt der Schaltregler einen Wirkungsgrad von η = 76%.Daher ergibt sich eine etwas hohere Verlustleistung von Pv ≈ 0, 32W . Bei Maxi-malbelastung des LM2575 mit Ue = 26V , Ua = 5V und Ia = 1A besitzt er einenWirkungsgrad von η ≈ 82%. Die Verlustleistung belauft sich mit den Werten aufPv ≈ 1, 1W und ist somit geringer als beim LM340 mit Ue = 12V und Ia = 0, 2A. Dasich diese Verlustleistung auf den LM2575, die Spule und die Freilaufdiode aufteilt,besteht kein Problem, die Warme passiv uber die Platine abzufuhren.

Bevor der Schaltplan und das Platinendesign geandert werden, wird die Schaltungder neuen Spannungsversorgung auf einem Steckbrett aufgebaut und getestet. An denLM2575 wird dabei eine Eingangsspannung von Ue = 28V angelegt und die geregel-te 5V Ausgangsspannung mit einem Strom von Ia = 0, 4A belastet. Der LM2575erwarmt sich dabei leicht, kann jedoch ausreichend durch die Luft gekuhlt werden.Die in den Abbildungen 7 abgebildeten Graphen zeigen unten die gepulste Spannungam Ausgang des LM2575 und oben die geregelte 5V Spannung nach der Spule. InAbbildung 7a wird die geregelte Ausgangsspannung mit einem 220µF Kondensatorgestutzt. Hierbei wurde ein Elko mit schlechtem ESR-Wert verwendet. Neben demRauschen ist zu erkennen, dass jeder Puls den Kondensator aufladt. Zwischen denPulsen fallt die Spannung langsam. In Abbildung 7b wird ein weiterer baugleicherKondensator parallel zum ersten geschaltet. Dadurch verdoppelt sich die Kapazitatund der ESR-Wert verringert sich. Die Ausgangsspannung wird nun bei gleicher Be-lastung konstant bei 5,1V gehalten.

Im Schaltplan wird daher der LM340 mit dem LM2575 ausgetauscht. Um Pro-blemen bei der Servomotoransteuerung zu vermeiden, wird der Linearregler der 5VServospannung ebenfalls durch einen Schaltregler ersetzt. Der LM1085 wird mit demLM2576 getauscht. Dieser liefert bei besserem Wirkungsgrad ebenfalls bis zu 3A anStrom.

26

4 EVALUIERUNG

(a) Ausgangsspannung mit 220µF gestutzt (b) Ausgangsspannung mit 440µF gestutzt

Abbildung 7: Graphen der per Schaltregler geregelten Ausgangsspannung

4.2 Test einzelner Komponenten

In diesem Abschnitt wird beschrieben, wie die einzelnen Komponenten des Aktuator-systems getestet wurden und welche Komplikationen dabei aufgetreten sind.

4.2.1 Funktionsprufung der inertialen Messeinheit

Zunachst wird mit dem Konsolenbefehl i2cdetect -l gepruft, ob der benotigte zwei-te I2C-Bus installiert und verfugbar ist. Ist er verfugbar, kann der Befehl i2cdetect -

r ausgefuhrt werden, um eine Tabelle der angeschlossenen Devices mit ihren Adressenzu erhalten. Dabei muss darauf geachtet werden, dass die Adressen 0x54 bis 0x57 vomTreiber des EEPROM reserviert sind. Mit i2cset und i2cget konnen einzelne Regis-ter an den vorhandenen Adressen ausgelesen oder beschrieben werden. Diese Befehlewerden genutzt, um die inertiale Messeinheit zu initialisieren und Werte der einzelnenSensoren auszulesen. Dies gelingt ohne Komplikationen. Die getesteten Einstellungenwerden in die Methoden der Klasse IMU im actuator.cpp Programm ubernommen.Zunachst gab es hierbei kleine Probleme mit den Adressen des Sensors. Bereits beimInitialisieren des I2C-Bus muss die Adresse des auszulesenden Device angegeben wer-den und nicht eine, mit der das eigene Board angesprochen werden kann. Ein weite-res Problem stellt die readBlock(uint8_t registerAddr, uint8_t *readBuffer,

size_t bufferSize)-Methode der I2C-Klasse dar. Sie soll mit einem Aufruf sechsRegister nacheinander auslesen und die empfangenen Daten in einem Array speichern.Sie erhalt jedoch nicht, wie erwartet, die Inhalte von sechs Registern, sondern gibt denWert des ersten ausgelesenen Registers sechs Mal zuruck. Sie wird mit der readByte(uint8_t registerAddr) ausgetauscht, welche man nun sechs Mal aufrufen muss, umdieselbe Anzahl an Registern auslesen zu konnen. Dies kostet mehr Zeit, als einmaldie readBlock()-Methode aufzurufen.

27

4 EVALUIERUNG

Nach dem Losen der beiden Problem kann das Programm Werte aus der inertialenMesseinheit auslesen. Diese mussen anschließend mit der Genauigkeit der einzelnenSensoren multipliziert werden, um die Werte weiter nutzen zu konnen.

4.2.2 Lichtschranke

Fur die Lichtschranke werden in das Chassis eines Roboters der Lichtdetektor unddie IR-LED eingebaut und aufeinander ausgerichtet. Zunachst wird per Konsole dieanliegende Spannung ausgelesen, anschließend ein Programm geschrieben, welchesden ADC-Wert des Lichtdetektors alle 100ms auf der Konsole ausgibt. Mit diesemProgramm wird die Lichtschranke auf Storanfalligkeit getestet. Ohne extra Licht-quellen funktioniert das Erkennen eines Objektes in der Lichtschranke problemlos.Als Storlichtquelle wird ein 500W Scheinwerfer genutzt. Mit verschiedenen Winkelnund Entfernungen wird in Richtung des Chassis geleuchtet. Dabei fallt auf, dass dieLichtschranke zuverlassig funktioniert, solange der Scheinwerfer mehr als 2m entferntist. Unter 2m Entfernung braucht es spezielle Winkel, um den Lichtdetektor zu storen.Bei Entfernungen mit weniger als einem Meter wird die Lichtschranke haufig gestort.

Auf den Turnieren werden die Spielflachen haufig beleuchtet. Dies geschieht wiebeim normalen Fußball mit Scheinwerfern, die von schrag oben auf das Spielfeld leuch-ten. Diese Scheinwerfer sind in der Regel mehr als zwei Meter entfernt und solltendaher keine Probleme fur das Detektieren von Objekten in der Lichtschranke darstel-len. Da Turniere haufig in großen Hallen stattfinden, konnte Sonnenlicht ungunstigauf den Sensor treffen, wenn der Roboter nicht in Ballbesitz ist. Dieser Fall wur-de nicht getestet, lasst sich jedoch haufig ausschließen, indem weitere Informationenuber die Ballposition von der Kamera zur Verifizierung des Ballbesitzes hinzugezogenwerden.

4.2.3 Servomotor

Der Servomotor muss mit einer 5V Spannungsversorgung und einem PWM-Signalverbunden werden. Bei den Tests treten keine Probleme bei der Ansteuerung auf. DiePeriodendauer wird, wie bei Servomotoren ublich, auf 20ms eingestellt. Die Pulsdauerkann zwischen 1,3ms und 1,95ms variiert werden. Werden 1,3ms eingestellt, so wirddie Schaufel zum Passen, bei 1,95ms die Schussschaufel ausgewahlt.

4.2.4 High Power Motortreiber

Fur die Tests mit den Ballfuhrungsmotoren werden diese an die Motortreiber ange-schlossen und zur Ansteuerung verschiedene PWM-Signale vom BeagleBoard Blackgeneriert. Die ersten Tests verlaufen erfolglos, da die digitalen Isolatoren mehr Strombenotigen, als der geregelte Vcc-Ausgang des Motortreibers zur Verfugung stellt. Um

28

4 EVALUIERUNG

genugend Strom bereitzustellen, werden die Vcc-Ausgange abgeklemmt und ein Li-nearregler eingebaut, der aus den 24V fur die Motoren eine 5V Spannung regelt.

Nach dieser Anderung gibt es keine Probleme bei der Ansteuerung der Motorenmehr. Bei den Tests ist mit einer Periodendauer von 10000µs gearbeitet worden. Jelanger die Pulsdauer eingestellt war, desto schneller drehten sich die Motoren. Auchder Wechsel der Drehrichtung funktionierte problemlos.

4.2.5 Optischer Fluss Sensor

Bei den Tests mit dem Optischen Fluss Sensor gibt es ein weiteres Problem. Er wur-de, wie bei der Vorgangerplatine auch, mit 5V angesteuert. Laut Datenblatt arbeiteder Sensor jedoch mit 3,3V. Es bestehe allerdings die Moglichkeit, ihn an die 5VSpannung eines Mikrocontrollers ohne Pegelwandler anzuschließen (vgl. DatenblattADNS-3080 von Avago Technologies, S. 15).Auf der Peripherieplatine wird der Sensor an die 5V des Pegelwanders TXB0108 ange-schlossen. Er reagiert bei den ersten Tests auf keine vom BeagleBoard Black gesendeteNachricht. Die Signalleitungen werden deshalb mit einem Oszilloskop uberpruft. DieSignale sehen jedoch sauber aus und das Timing zwischen Takt- und Datensignalstimmt.Der Sensor wird daraufhin direkt an das 3,3V SPI-Signal des BeagleBoard Black an-geschlossen und reagiert auf ankommende Nachrichten. Nach der Initialisierung desSensors liefert dieser Daten uber die Bewegungsrichtung des Balls und die Qualitatder detektieren Oberflache.

29

5 ZUSAMMENFASSUNG UND AUSBLICK

5 Zusammenfassung und Ausblick

Die Aufgabe, ein linuxbasiertes System als Ersatz der Aktuatorplatine zu entwickeln,ist mit dem BeagleBoard Black und der Peripherieplatine gelungen. Der Einplatinen-computer ist in der Lage, per Ethernet und ROS mit dem zentralen Industriecomputerzu kommunizieren und Daten auszutauschen. Die Anzahl der Ein- und Ausgange desBeagleBoard Black ermoglichen es, alle Sensoren und Aktoren auszulesen und anzu-steuern. Neue Sensoren konnen uber I2C oder SPI mit dem BeagleBoard verbundenwerden und so das System erweitern. Das bisher nicht genutzte Lichtschrankenmodulist durch einen kleinen Lichtdetektor ersetzt worden, dessen Signalleitung lediglichvom BeagleBoard Black ausgelesen werden muss. Die bisherigen Tests mit einem500W Scheinwerfer waren positiv und zeigten, dass es lediglich zu Storungen kommt,wenn sich die storende Lichtquelle in einem bestimmten Winkel und innerhalb eines2m Radius um den Lichtdetektor befindet. Der alte Kompasssensor ist durch eine in-ertiale Messeinheit ersetzt worden. Die Roboter konnen jetzt neben ihrer Ausrichtungam Magnetfeld auch Beschleunigungen in drei Richtungen oder Drehungen um dieeigene Achse messen. Diese Daten konnen genutzt werden, um z. B. Informationenuber den zuruckgelegten Weg und die Ausrichtung des Roboters zu validieren.

Das neue System besitzt zum Vorganger auch einige Nachteile. Da ein kompletterLinuxkernel gebootet werden muss, ist die Dauer des Bootvorgangs im Vergleich zueinem Mikrocontroller deutlich langer. Wahrend ein Mikrocontroller, z. B. der AT-mega128, nur wenige Sekunden zum Booten und Initialisieren der Sensoren benotigt,betragt die Dauer beim BeagleBoard allein zum Booten 30 Sekunden. Dies muss beiden Turnieren bedacht und das System rechtzeitig gestartet werden. Durch Modifi-kationen am Linuxkernel lasst sich diese Zeit um einige Sekunden verkurzen.

Ein weiterer Nachteil ist die Zeit, die einzelne Pinoperationen benotigen. Wirdmit Hilfe der BlackLib ein Pin gesetzt oder geloscht, so dauert dies zwischen 0,3msund 0,4ms. Das Auslesen des ADC dauert mit 1,3ms am langsten. Die langen Zeitenliegen an dem Zugriff auf die Pins. Die BlackLib greift uber das Linux-Datei-Systemauf die Werte zu, was viel Zeit kostet. Schnellere Bibliotheken wie die BeagleBoneBlack BBB C++ API 13 von Peter Mancuso greifen uber den Arbeitsspeicher auf dieeinzelnen Pins zu. Dadurch ist es moglich, Pinoperationen bis zu tausendmal schnellerauszufuhren. Allerdings unterstutzt die Bibliothek momentan nur das Auslesen undSetzen normaler GPIO-Pins. ADC, I2C oder PWM werden noch nicht unterstutzt.

13https://github.com/petermancuso/bbb

30

A ANHANGE

A Anhange

A.1 Vollstandige Tabelle der Einplatinencomputer

31

A ANHANGE

A.2 Quellcode der rc.local-Datei

1 # PWM Export

2 # P9.14

3 echo 0 > /sys/class/pwm/pwmchip2/export

4 # P9.16

5 echo 1 > /sys/class/pwm/pwmchip2/export

6 # P8.19

7 echo 0 > /sys/class/pwm/pwmchip4/export

8 # P8 13

9 echo 1 > /sys/class/pwm/pwmchip4/export

10

11 # PWM Change State

12 echo pwm > /sys/devices/ocp .3/ P9_14_pinmux .41/ state

13 echo pwm > /sys/devices/ocp .3/ P9_16_pinmux .43/ state

14 echo pwm > /sys/devices/ocp .3/ P8_13_pinmux .10/ state

15 echo pwm > /sys/devices/ocp .3/ P8_19_pinmux .16/ state

16

17 # GPIO Export

18 echo 20 > /sys/class/gpio/export

19 echo 26 > /sys/class/gpio/export

20 echo 27 > /sys/class/gpio/export

21 echo 30 > /sys/class/gpio/export

22 echo 31 > /sys/class/gpio/export

23 echo 44 > /sys/class/gpio/export

24 echo 45 > /sys/class/gpio/export

25 echo 46 > /sys/class/gpio/export

26 echo 47 > /sys/class/gpio/export

27 echo 48 > /sys/class/gpio/export

28 echo 49 > /sys/class/gpio/export

29 echo 60 > /sys/class/gpio/export

30 echo 61 > /sys/class/gpio/export

31 echo 65 > /sys/class/gpio/export

32 echo 66 > /sys/class/gpio/export

33 echo 67 > /sys/class/gpio/export

34 echo 68 > /sys/class/gpio/export

35 echo 69 > /sys/class/gpio/export

36 echo 112 > /sys/class/gpio/export

37 echo 115 > /sys/class/gpio/export

38 echo 116 > /sys/class/gpio/export

39 echo 117 > /sys/class/gpio/export

40

41 # Zugriffsberechtigung

42 chown -R ubuntu:ubuntu /sys/class/gpio

43 chown -R ubuntu:ubuntu /sys/class/pwm

44 chown -R ubuntu:ubuntu /sys/devices

45

46 exit 0

32

A ANHANGE

A.3 Quellcode der am335x-bone-robot.dtsi-Datei

1 /* Copyright (C) 2012 Texas Instruments Incorporated - http :// www.

ti.com/

2 *

3 * This program is free software; you can redistribute it and/or

modify

4 * it under the terms of the GNU General Public License version 2 as

5 * published by the Free Software Foundation.

6 */

7

8 &tscadc

9 status = "okay";

10 adc

11 ti,adc -channels = <0 1 2 3 4 5 6>;

12 ;

13 ;

14

15 &epwmss0

16 status = "okay";

17 ;

18 &epwmss1

19 status = "okay";

20 ;

21 &epwmss2

22 status = "okay";

23 ;

24

25 &ehrpwm0

26 status = "okay";

27 ;

28 &ehrpwm1

29 status = "okay";

30 ;

31 &ehrpwm2

32 status = "okay";

33 ;

33

A ANHANGE

A.4 Schaltplan der Peripherieplatine

34

A ANHANGE

35

A ANHANGE

36

A ANHANGE

37

A ANHANGE

38

A ANHANGE

A.5 Quellcode BeagleBoard Black

1 /*

2 * actuator.h

3 *

4 * Created on: Apr 7, 2015

5 * Author: Lukas Will

6 */

7

8 #ifndef CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_ACTUATOR_H_

9 #define CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_ACTUATOR_H_

10

11

12 #include "config.h"

13 #include "ballhandle.h"

14 #include "opticalflow.h"

15 #include "imu.h"

16

17 #include <mutex >

18 #include <condition_variable >

19

20 /*

21 Axis.msg

22

23 int16_t x;

24 int16_t y;

25 int16_t z;

26

27

28 IMUInfo.msg

29

30 Axis accel;

31 Axis gyro;

32 Axis magnet;

33 int16_t temperature;

34

35 */

36

37

38 using namespace BlackLib;

39

40

41 struct Shovel

42 bool enabled;

43 uint32_t value;

44 timeval last_ping;

45 ;

46

47 struct CV

39

A ANHANGE

48 std:: mutex mtx;

49 std:: condition_variable cv;

50 bool notify = false;

51 ;

52

53

54 BlackGPIO LED_Vision(GPIO_49 , output , FastMode); // P9 23

55 BlackGPIO LED_Bundle(GPIO_20 , output , FastMode); // P9 41

56 BlackGPIO LED_Power(GPIO_7 , output , FastMode); // P9 42

57

58 BlackGPIO SW_Vision(GPIO_30 , input , FastMode); // P9 11

59 BlackGPIO SW_Bundle(GPIO_31 , input , FastMode); // P9 13

60 BlackGPIO SW_Power(GPIO_48 , input , FastMode); // P9 15

61

62 BlackI2C myI2C(I2C_2 , ADR_G);

63 BlackSPI mySpi(SPI0_0 , 8, SpiMode0 , 2000000);

64

65

66 BallHandle BH_right(P8_19 , GPIO_69 , GPIO_68 , GPIO_46 , GPIO_65);

/* pwm , dir , reset , ff1 , ff2 */

67 BallHandle BH_left(P8_13 , GPIO_66 , GPIO_67 , GPIO_44 , GPIO_26);

/* pwm , dir , reset , ff1 , ff2 */

68 OpticalFlow adns3080(GPIO_112 , GPIO_117 , GPIO_115 , GPIO_60 , &mySpi

); /* ncs , npd , rst , led */

69 IMU lsm9ds0(GPIO_45 , GPIO_47 , GPIO_27 , GPIO_61 , &myI2C); /*

magnet , accel , temp , gyro Interrupt -Pins */

70

71 BlackADC ADC_light(AIN0);

72

73 BlackPWM ShovelSelect(P9_14);

74 Shovel shovel;

75

76 timeval time_now;

77 timeval last_ping;

78

79 CV threw [6], cv_main;

80

81 bool ex = false;

82

83

84 #endif /* CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_ACTUATOR_H_ */

Listing 3: actuator.h

1 /*

2 * main.cpp

3 *

4 * Created on: Mar 10, 2015

5 * Author: Lukas Will

40

A ANHANGE

6 */

7

8

9 #include "actuator.h"

10

11 // fuer Tests

12 //#include <thread > // this_thread :: sleep_for

13 //#include <chrono > // chrono :: seconds

14 //#include <stdio.h> // File Open

15 //#include <unistd.h> // File Open

16

17 using namespace std;

18 using namespace BlackLib;

19

20 mutex mtx;

21 // condition_variable cv , cv2;

22

23 uint8_t th_count;

24

25 bool th_activ = true;

26

27

28

29

30 void handleBallHandleControl(const msl_actuator_msgs :: BallHandleCmd

msg)

31 if (msg.enabled)

32 BH_right.setBallHandling(msg.rightMotor);

33 BH_left.setBallHandling(msg.leftMotor);

34 else

35 BH_right.setBallHandling (0);

36 BH_left.setBallHandling (0);

37

38

39

40 void handleShovelSelectControl(const msl_actuator_msgs ::

ShovelSelectCmd msg)

41 shovel.last_ping = last_ping;

42

43 // Schussauswahl (ggf Wert fuer Servoposition mit uebergeben

lassen)

44 if (msg.passing)

45 shovel.value = ShovelSelect_PASSING;

46 else

47 shovel.value = ShovelSelect_NORMAL;

48

49 shovel.enabled;

50

51

41

A ANHANGE

52 void handleMotionLight(const msl_actuator_msgs :: MotionLight msg)

53 // LED vom Maussensor ansteuern

54 adns3080.controlLED(msg.enable);

55

56

57

58 void controlBHLeft ()

59 unique_lock <mutex > l_bhl(threw [0]. mtx);

60 while(th_activ)

61 threw [0].cv.wait(l_bhl , [&] return !th_activ || threw [0].

notify; ); // protection against spurious wake -ups

62 if (! th_activ)

63 return;

64

65 BH_left.controlBallHandling ();

66

67 threw [0]. notify = false;

68 cv_main.cv.notify_all ();

69

70

71

72 void controlBHRight ()

73 unique_lock <mutex > l_bhr(threw [1]. mtx);

74 while(th_activ)

75 threw [1].cv.wait(l_bhr , [&] return !th_activ || threw [1].

notify; ); // protection against spurious wake -ups

76 if (! th_activ)

77 return;

78

79 BH_right.controlBallHandling ();

80

81 threw [1]. notify = false;

82 cv_main.cv.notify_all ();

83

84

85

86 void contolShovelSelect ()

87 unique_lock <mutex > l_shovel(threw [2]. mtx);

88 while(th_activ)

89 threw [2].cv.wait(l_shovel , [&] return !th_activ || threw [2].

notify; ); // protection against spurious wake -ups

90 if (! th_activ)

91 return;

92

93 if (( TIMEDIFFMS(time_now , shovel.last_ping) >

ShovelSelect_TIMEOUT) && shovel.enabled)

94 shovel.enabled = false;

95 ShovelSelect.setRunState(stop);

96

42

A ANHANGE

97

98 if (shovel.enabled)

99 if (ShovelSelect.getRunValue () == "0")

100 ShovelSelect.setRunState(run);

101

102 ShovelSelect.setSpaceRatioTime(shovel.value , microsecond);

103

104

105 threw [2]. notify = false;

106 cv_main.cv.notify_all ();

107

108

109

110 void getLightbarrier(ros:: Publisher *hbiPub)

111 unique_lock <mutex > l_light(threw [3]. mtx);

112 while(th_activ)

113 threw [3].cv.wait(l_light , [&] return !th_activ || threw [3].

notify; ); // protection against spurious wake -ups

114 if (! th_activ)

115 return;

116

117 msl_actuator_msgs :: HaveBallInfo msg;

118 uint16_t value = ADC_light.getNumericValue ();

119

120 if (value > LIGHTBARRIER_THRESHOLD)

121 msg.haveBall = true;

122 cout << "Ja - " << value << endl;

123 else

124 msg.haveBall = false;

125 cout << "Nein - " << value << endl;

126

127 hbiPub ->publish(msg);

128

129 threw [3]. notify = false;

130 cv_main.cv.notify_all ();

131

132

133

134 void getSwitches(ros:: Publisher *bsPub , ros:: Publisher *brtPub , ros

:: Publisher *vrtPub)

135 unique_lock <mutex > l_switches(threw [4]. mtx);

136 while(th_activ)

137 threw [4].cv.wait(l_switches , [&] return !th_activ || threw [4].

notify; ); // protection against spurious wake -ups

138 if (! th_activ)

139 return;

140

141 msl_actuator_msgs :: VisionRelocTrigger msg;

142 std_msgs ::Empty msg_empty;

43

A ANHANGE

143 uint8_t bundle , power , vision;

144

145 bundle = SW_Bundle.getNumericValue ();

146 vision = SW_Vision.getNumericValue ();

147 power = SW_Power.getNumericValue ();

148

149 msg.usePose = false;

150

151 if (bundle == 1)

152 bsPub ->publish(msg);

153 brtPub ->publish(msg_empty);

154

155

156 if (vision == 1)

157 vrtPub ->publish(msg);

158

159

160 if (power == 1)

161

162

163

164 threw [4]. notify = false;

165 cv_main.cv.notify_all ();

166

167

168

169 void getIMU(ros:: Publisher *imuPub)

170 unique_lock <mutex > l_imu(threw [5]. mtx);

171 while(th_activ)

172 threw [5].cv.wait(l_imu , [&] return !th_activ || threw [5].

notify; ); // protection against spurious wake -ups

173 if (! th_activ)

174 return;

175

176 // TODO IMU

177 lsm9ds0.sendData(time_now , imuPub);

178

179 threw [5]. notify = false;

180 cv_main.cv.notify_all ();

181

182

183

184 void getOptical(ros:: Publisher *mbcPub)

185 unique_lock <mutex > l_optical(threw [6]. mtx);

186 while(th_activ)

187 threw [6].cv.wait(l_optical , [&] return !th_activ || threw [6].

notify; ); // protection against spurious wake -ups

188 if (! th_activ)

189 return;

44

A ANHANGE

190

191 // TODO MotionBurst

192 adns3080.send_motion_burst(time_now , mbcPub);

193

194 threw [6]. notify = false;

195 cv_main.cv.notify_all ();

196

197

198

199 void exit_program(int sig)

200 ex = true;

201 cout << "Programm wird beendet." << endl;

202 th_activ = false;

203 cv_main.cv.notify_all ();

204 for (int i=0; i<6; i++)

205 threw[i].cv.notify_all ();

206

207

208

209

210

211 int main(int argc , char** argv)

212 cout << "Test Actuator -Beagle -Board" << endl;

213

214 // ROS Init

215 ros::init(argc , argv , "ActuatorController");

216 ros:: NodeHandle node;

217 ros::Rate loop_rate (1); // in Hz

218

219 ros:: Subscriber sscSub = node.subscribe <msl_actuator_msgs ::

ShovelSelectCmd >("ShovelSelectControl", 25,

handleShovelSelectControl);

220 ros:: Subscriber mlcSub = node.subscribe <msl_actuator_msgs ::

MotionLight >("CNActuator/MotionLight", 25, handleMotionLight);

221 ros:: Subscriber bhcSub = node.subscribe <msl_actuator_msgs ::

BallHandleCmd >("BallHandleControl", 25, handleBallHandleControl

);

222

223 ros:: Publisher bsPub = node.advertise <msl_actuator_msgs ::

VisionRelocTrigger >("CNActuator/BundleStatus", 10);

224 ros:: Publisher brtPub = node.advertise <std_msgs ::Empty >("

CNActuator/BundleRestartTrigger", 10);

225 ros:: Publisher vrtPub = node.advertise <msl_actuator_msgs ::

VisionRelocTrigger >("CNActuator/VisionRelocTrigger", 10);

226 ros:: Publisher mbcPub = node.advertise <msl_actuator_msgs ::

MotionBurst >("CNActuator/MotionBurst", 10);

227 ros:: Publisher hbiPub = node.advertise <msl_actuator_msgs ::

HaveBallInfo >("HaveBallInfo", 10);

228 // ros:: Publisher imuPub = node.advertise <YYeigene msg bauenYY >("

45

A ANHANGE

IMU", 10);

229

230 /* thread th_controlBHRight(controlBHRight);

231 thread th_controlBHLeft(controlBHLeft);

232 thread th_controlShovel(contolShovelSelect);

233 thread th_lightbarrier(getLightbarrier , &hbiPub);

234 thread th_switches(getSwitches , &bsPub , &brtPub , &vrtPub); */

235 // thread th_adns3080(getOptical , &mbcPub);

236 // thread th_imu(getIMU , &imuPub);

237

238 // Shovel Init

239 ShovelSelect.setPeriodTime(ShovelSelect_PERIOD); // in us - 20ms

Periodendauer

240 ShovelSelect.setSpaceRatioTime (1500000); // in us - Werte

zwischen 1ms und 2ms

241 shovel.enabled = false;

242

243 // I2C

244 bool i2c = myI2C.open(ReadWrite);

245 bool spi = mySpi.open(ReadWrite);

246 bool imu = lsm9ds0.init();

247 adns3080.reset ();

248 adns3080.adns_init ();

249

250 cout << "SPI: " << spi << ", I2C: " << i2c << ", IMU: " << i2c

<< endl;

251

252

253 usleep (50000);

254

255

256 uint8_t testy = 0;

257

258 (void) signal(SIGINT , exit_program);

259 while(ros::ok() && !ex)

260 // Frequency: 30Hz - set with loop_rate ()

261

262 gettimeofday (&time_now , NULL);

263 timeval vorher , mitte , nachher;

264

265 //TODO ADNS3080 Test

266 adns3080.update_motion_burst(time_now);

267 adns3080.send_motion_burst(time_now , &mbcPub);

268

269

270

271 // ros::Time::now();

272 gettimeofday (&vorher , NULL);

273

46

A ANHANGE

274 // Thread Notify

275 // TODO wieder einklammern

276 /*for (int i=0; i<5; i++)

277 threw[i]. notify = true;

278 threw[i].cv.notify_all ();

279

280

281 // auf beenden aller Threads warten

282 unique_lock <mutex > l_main(cv_main.mtx);

283 cv_main.cv.wait(l_main , [&] return !th_activ || (! threw [0].

notify && !threw [1]. notify && !threw [2]. notify && !threw [3].

notify && !threw [4]. notify && !threw [5]. notify); ); //

protection against spurious wake -ups

284 */

285 // TODO ende wieder einklammern ^^

286

287 gettimeofday (&nachher , NULL);

288

289

290 // MotionBurst

291

292 ros:: spinOnce ();

293 loop_rate.sleep ();

294

295

296 cout << "Programm beendet." << endl;

297

298 return 0;

299

Listing 4: actuator.cpp

1 /*

2 * ballhandle.h

3 *

4 * Created on: Mar 11, 2015

5 * Author: Lukas Will

6 */

7

8 #ifndef CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_BALLHANDLE_H_

9 #define CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_BALLHANDLE_H_

10

11 #include <stdint.h>

12 #include <chrono >

13

14 #include "config.h"

15 #include "BlackDef.h"

16 #include "BlackGPIO.h"

17 #include "BlackPWM.h"

47

A ANHANGE

18

19

20

21 class BallHandle

22 private:

23 BlackLib :: BlackPWM *pwm;

24 BlackLib :: BlackGPIO *dir , *reset , *ff1 , *ff2;

25

26 BlackLib :: digitalValue direction = static_cast <BlackLib ::

digitalValue >( right);

27 BlackLib :: digitalValue direction_desired = static_cast <

BlackLib :: digitalValue >(right);

28

29 bool enabled = false;

30 uint16_t speed = 0, speed_desired = 0;

31

32 public:

33 enum errorList

34 none = 0,

35 bypass = 1,

36 temperature = 2,

37 voltage = 3

38 ;

39

40 enum directionList

41 left = 0,

42 right = 1

43 ;

44

45

46 BallHandle(BlackLib :: pwmName pwm_P , BlackLib :: gpioName dir_P

, BlackLib :: gpioName reset_P , BlackLib :: gpioName ff1_P ,

BlackLib :: gpioName ff2_P);

47 ~BallHandle ();

48

49

50 void setBallHandling(int8_t value);

51 void setTimeout ();

52 void controlBallHandling ();

53

54 uint8_t getError ();

55 ;

56

57

58 #endif /* CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_BALLHANDLE_H_ */

Listing 5: ballhandle.h

1 /*

48

A ANHANGE

2 * ballhandle.cpp

3 *

4 * Created on: Mar 11, 2015

5 * Author: Lukas Will

6 */

7

8

9 #include "ballhandle.h"

10

11 using namespace BlackLib;

12

13 BallHandle :: BallHandle(pwmName pwm_P , gpioName dir_P , gpioName

reset_P , gpioName ff1_P , gpioName ff2_P)

14 pwm = new BlackPWM(pwm_P);

15 dir = new BlackGPIO(dir_P , output , FastMode);

16 reset = new BlackGPIO(reset_P , output , FastMode);

17 ff1 = new BlackGPIO(ff1_P , input , FastMode);

18 ff2 = new BlackGPIO(ff2_P , input , FastMode);

19

20 // PWM Frequenz setzen pwm ->setPeriodTime (5000, microsecond);

21 pwm ->setPeriodTime (10000 , nanosecond);

22

23 dir ->setValue(low);

24 reset ->setValue(high);

25

26

27 BallHandle ::~ BallHandle ()

28 delete pwm;

29 delete dir;

30 delete reset;

31 delete ff1;

32 delete ff2;

33

34

35 void BallHandle :: setBallHandling(int8_t value)

36 // value > 0 -> left

37 // value < 0 -> right

38 if (( value > 0) && (direction == static_cast <digitalValue >( right

)))

39 direction_desired = static_cast <digitalValue >(left);

40

41

42 if (( value < 0) && (direction == static_cast <BlackLib ::

digitalValue >(left)))

43 direction_desired = static_cast <BlackLib :: digitalValue >(right)

;

44

45

46 speed_desired = abs(value) * 39;

49

A ANHANGE

47

48

49 void BallHandle :: setTimeout ()

50 if (enabled)

51 this ->setBallHandling (0); // Beim naechsten Aufruf von

controlBallHandling () wird das BallHandling deaktiviert

52

53

54

55 void BallHandle :: controlBallHandling ()

56 if (speed_desired == 0)

57 enabled = false;

58

59 if (pwm ->getRunValue () == "1") // 300us

60 pwm ->setRunState(stop); // ?us

61

62 else if (( speed_desired != 0) && (! enabled))

63 enabled = true;

64 pwm ->setRunState(run);

65

66

67 if (enabled) // Gesamt ca. 900us oder 1500us

68 // BallHandling active

69

70 if (direction != direction_desired)

71 // Direction Change 1500us

72 direction = direction_desired;

73 speed = 0;

74 pwm ->setSpaceRatioTime(speed , nanosecond); // 900us

75 dir ->setValue(direction); // 550us

76

77

78 if (speed != speed_desired)

79 // Speed Change 900us

80 speed = speed_desired;

81 pwm ->setSpaceRatioTime(speed , nanosecond); // 900us

82

83

84

85

86

87

88 /* ALTE FUNKTION

89 if (speed_desired == 0)

90 enabled = false;

91

92 if (pwm ->getRunValue () == "1") // 300us

93 pwm ->setRunState(stop); // ?us

94

50

A ANHANGE

95 else if (( speed_desired != 0) && (! enabled))

96 enabled = true;

97 pwm ->setRunState(run);

98

99

100 if (enabled) // Gesamt ca. 900us oder 1500us

101 // BallHandling aktiviert

102

103 if (direction != direction_desired) // Direction Change ,

Slow Down Speed (Gesamt: 900us oder 1500us)

104 speed -= BallHandle_PWM_STEP_SIZE;

105 if (speed < 0)

106 direction = direction_desired;

107 speed = 0;

108 dir ->setValue(direction); // 550us

109

110 else // Keep Direction , Modify Speed

111 if (speed_desired > speed)

112 speed += BallHandle_PWM_STEP_SIZE;

113 if (speed > speed_desired)

114 speed = speed_desired;

115 else

116 speed -= BallHandle_PWM_STEP_SIZE;

117 if (speed < speed_desired)

118 speed = speed_desired;

119

120

121 pwm ->setSpaceRatioTime(speed , microsecond); // 900us

122

123 */

124

125

126

127 uint8_t BallHandle :: getError ()

128 uint8_t ff = (ff1 ->getNumericValue () << 1) | ff2 ->

getNumericValue ();

129

130 return ff;

131

Listing 6: ballhandle.cpp

1 /*

2 * config.h

3 *

4 * Created on: Mar 12, 2015

5 * Author: Lukas Will

6 */

7

51

A ANHANGE

8 #ifndef CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_CONFIG_H_

9 #define CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_CONFIG_H_

10

11 #include <iostream >

12 #include <signal.h>

13 #include <sstream >

14 #include <stdint.h>

15 #include <sys/time.h>

16

17 // ROS

18 #include "ros/ros.h"

19 #include "std_msgs/Empty.h"

20 #include "std_msgs/String.h"

21 #include "msl_actuator_msgs/BallCatchCmd.h"

22 #include "msl_actuator_msgs/BallHandleCmd.h"

23 #include "msl_actuator_msgs/HaveBallInfo.h"

24 #include "msl_actuator_msgs/MotionLight.h"

25 #include "msl_actuator_msgs/MotionBurst.h"

26 #include "msl_actuator_msgs/ShovelSelectCmd.h"

27 #include "msl_actuator_msgs/VisionRelocTrigger.h"

28

29 // BlackLibs

30 #include "BlackADC.h"

31 #include "BlackDef.h"

32 #include "BlackGPIO.h"

33 #include "BlackI2C.h"

34 #include "BlackPWM.h"

35 #include "BlackSPI.h"

36

37 // Threads

38 #include <thread >

39 #include <mutex >

40 #include <condition_variable >

41

42

43

44 #define TIMEDIFFUS(n,o) (((n).tv_usec -(o).tv_usec))

45 #define TIMEDIFFMS(n,o) (((n).tv_sec -(o).tv_sec)*1000+((n).tv_usec -(

o).tv_usec)/1000)

46

47 #define PING_TIMEOUT 1000 // ms

48

49 #define BallHandle_TIMEOUT 1000 // ms

50 #define BallHandle_PWM_STEP_SIZE 50

51

52 #define IMU_UPDATE_TIMEOUT 10 // ms

53 #define IMU_SEND_TIMEOUT 30 // ms

54

55 #define OpticalFlow_UPDATE_TIMEOUT 1 // ms

52

A ANHANGE

56 #define OpticalFlow_BURST_TIMEOUT 1 // ms

57

58 #define ShovelSelect_TIMEOUT 1000 // ms

59 #define ShovelSelect_PASSING 1300000 // 1000 - PWM ( 1,30ms /

20ms )

60 #define ShovelSelect_NORMAL 1950000 // 2000 - PWM ( 1,95ms /

20ms )

61 #define ShovelSelect_PERIOD 20000000 // Servo Period Time 20ms

62

63

64 // Entscheidungsschwelle fuer Ball (0 bis 65000)

65 const uint16_t LIGHTBARRIER_THRESHOLD = 500;

66

67

68 #endif /* CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_CONFIG_H_ */

Listing 7: config.h

1 /*

2 * imu.h

3 *

4 * Created on: Mar 12, 2015

5 * Author: Lukas Will

6 */

7

8 #ifndef CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_IMU_H_

9 #define CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_IMU_H_

10

11 #include "config.h"

12

13

14 const uint8_t ADR_G = 0x6B; // LSM9DS0

15 const uint8_t ADR_XM = 0x1D; // LSM9DS0

16

17 const uint8_t WHO_AM_I_G = 0xD4;

18 const uint8_t WHO_AM_I_XM = 0x49;

19

20 const uint8_t ACCEL_OUT_X = 0x28;

21 const uint8_t ACCEL_OUT_Y = 0x2A;

22 const uint8_t ACCEL_OUT_Z = 0x2C;

23 const uint8_t GYRO_OUT_X = 0x28;

24 const uint8_t GYRO_OUT_Y = 0x2A;

25 const uint8_t GYRO_OUT_Z = 0x2C;

26 const uint8_t MAGNET_OUT_X = 0x08;

27 const uint8_t MAGNET_OUT_Y = 0x0A;

28 const uint8_t MAGNET_OUT_Z = 0x0C;

29 const uint8_t TEMP_OUT = 0x05;

30

31 const uint8_t CTRL_REG0_XM = 0x1F;

53

A ANHANGE

32 const uint8_t CTRL_REG1_XM = 0x20;

33 const uint8_t CTRL_REG2_XM = 0x21;

34 const uint8_t CTRL_REG3_XM = 0x22;

35 const uint8_t CTRL_REG4_XM = 0x23;

36 const uint8_t CTRL_REG5_XM = 0x24;

37 const uint8_t CTRL_REG6_XM = 0x25;

38 const uint8_t CTRL_REG7_XM = 0x26;

39

40 const uint8_t CTRL_REG1_G = 0x20;

41 const uint8_t CTRL_REG2_G = 0x21;

42 const uint8_t CTRL_REG3_G = 0x22;

43 const uint8_t CTRL_REG4_G = 0x23;

44 const uint8_t CTRL_REG5_G = 0x24;

45

46 const uint8_t ACC_AFS_2G = 0x00;

47 const uint8_t ACC_AFS_4G = 0x08;

48 const uint8_t ACC_AFS_6G = 0x10;

49 const uint8_t ACC_AFS_8G = 0x18;

50 const uint8_t ACC_AFS_16G = 0x20;

51 const uint8_t GYR_FS_245DPS = 0x00;

52 const uint8_t GYR_FS_500DPS = 0x01;

53 const uint8_t GYR_FS_2000DPS = 0x10;

54 const uint8_t MAG_MDR_2GAUSS = 0x00;

55 const uint8_t MAG_MDR_4GAUSS = 0x20;

56 const uint8_t MAG_MDR_6GAUSS = 0x40;

57 const uint8_t MAG_MDR_8GAUSS = 0x60;

58

59 const float ACC_2G_SENSE = 0.061;

60 const float ACC_4G_SENSE = 0.122;

61 const float ACC_6G_SENSE = 0.183;

62 const float ACC_8G_SENSE = 0.244;

63 const float ACC_16G_SENSE = 0.732;

64 const float GYR_245DPS_SENSE = 8.75;

65 const float GYR_500DPS_SENSE = 17.5;

66 const float GYR_2000DPS_SENSE = 70;

67 const float MAG_2GAUSS_SENSE = 0.08;

68 const float MAG_4GAUSS_SENSE = 0.16;

69 const float MAG_8GAUSS_SENSE = 0.32;

70 const float MAG_12GAUSS_SENSE = 0.48;

71 const float TEMP_SENSE = 0.125;

72

73

74

75

76 class IMU

77 private:

78 BlackLib :: BlackGPIO *i_acc , *i_gyro , *i_mag , *i_temp;

79 BlackLib :: BlackI2C *i2c;

80 timeval last_sended , last_updated;

54

A ANHANGE

81 int16_t temperature;

82

83 struct Koordinaten

84 float x, y, z, sense;

85 gyro , accel , magnet;

86

87 bool whoami ();

88 void setupAccel(uint8_t range);

89 void setupGyro(uint8_t scale);

90 void setupMagnet(uint8_t scale);

91 void getAccel ();

92 void getGyro ();

93 void getMagnet ();

94 void getTemp ();

95

96 public:

97 IMU(BlackLib :: gpioName acc_P , BlackLib :: gpioName gyro_P ,

BlackLib :: gpioName mag_P , BlackLib :: gpioName temp_P ,

BlackLib :: BlackI2C *i2c_P);

98 ~IMU();

99 bool init();

100 void updateData(timeval time_now);

101 void sendData(timeval time_now , ros:: Publisher *imuPub);

102

103 ;

104

105

106

107 #endif /* CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_IMU_H_ */

Listing 8: imu.h

1 /*

2 * imu.cpp

3 *

4 * Created on: Mar 12, 2015

5 * Author: Lukas Will

6 */

7

8

9 #include "imu.h"

10

11 using namespace BlackLib;

12

13 IMU::IMU(gpioName acc_P , gpioName gyro_P , gpioName mag_P , gpioName

temp_P , BlackLib :: BlackI2C *i2c_P)

14 i2c = i2c_P;

15

16 i_acc = new BlackGPIO(acc_P , input , FastMode);

55

A ANHANGE

17 i_gyro = new BlackGPIO(gyro_P , input , FastMode);

18 i_mag = new BlackGPIO(mag_P , input , FastMode);

19 i_temp = new BlackGPIO(temp_P , input , FastMode);

20

21 temperature = 0;

22

23

24 IMU ::~ IMU()

25 delete i_acc;

26 delete i_gyro;

27 delete i_mag;

28 delete i_temp;

29

30

31 bool IMU::init()

32 // Enable Accel

33 i2c ->setDeviceAddress(ADR_XM);

34 i2c ->writeByte(CTRL_REG1_XM , 0x67); // Accel Frequecy: 100Hz

35

36 // Enable Magnet & Temp

37 i2c ->writeByte(CTRL_REG5_XM , 0xF4); // Magnet Frequecy: 100Hz

& high resolution

38 i2c ->writeByte(CTRL_REG7_XM , 0x80); // high -pass Filter:

Normal Mode & Continuous Conversation

39

40 // Enable Gyro

41 i2c ->setDeviceAddress(ADR_G);

42 i2c ->writeByte(CTRL_REG1_G , 0x0F); // Gyro

43

44 //TODO Anpassen der Multiplikatoren

45 accel.sense = ACC_2G_SENSE / 1000;

46 this ->setupAccel(ACC_AFS_2G);

47 gyro.sense = GYR_2000DPS_SENSE / 1000;

48 this ->setupGyro(GYR_FS_2000DPS);

49 magnet.sense = MAG_8GAUSS_SENSE / 1000;

50 this ->setupMagnet(MAG_MDR_2GAUSS);

51

52 if(!this ->whoami ())

53 return false;

54 else

55 return true;

56

57

58

59 bool IMU:: whoami ()

60 uint8_t g, xm;

61

62 i2c ->setDeviceAddress(ADR_G);

63 g = i2c ->readByte (0x0f);

56

A ANHANGE

64

65 i2c ->setDeviceAddress(ADR_XM);

66 xm = i2c ->readByte (0x0f);

67

68 if((g == WHO_AM_I_G) && (xm == WHO_AM_I_XM))

69 return true;

70 else

71 return false;

72

73

74

75 void IMU:: setupAccel(uint8_t range)

76 uint8_t reg;

77

78 if (i2c ->getDeviceAddress () != ADR_XM)

79 i2c ->setDeviceAddress(ADR_XM);

80

81

82 reg = i2c ->readByte(CTRL_REG2_XM);

83 reg &= ~(0 b00111000);

84

85 i2c ->writeByte(CTRL_REG2_XM , reg | range);

86

87

88 void IMU:: setupGyro(uint8_t scale)

89 uint8_t reg;

90

91 if (i2c ->getDeviceAddress () != ADR_G)

92 i2c ->setDeviceAddress(ADR_G);

93

94

95 reg = i2c ->readByte(CTRL_REG4_G);

96 reg &= ~(0 b00110000);

97

98 i2c ->writeByte(CTRL_REG4_G , reg | scale);

99

100

101 void IMU:: setupMagnet(uint8_t scale)

102 uint8_t reg;

103

104 if (i2c ->getDeviceAddress () != ADR_XM)

105 i2c ->setDeviceAddress(ADR_XM);

106

107

108 reg = i2c ->readByte(CTRL_REG6_XM);

109 reg &= ~(0 b01100000);

110

111 i2c ->writeByte(CTRL_REG6_XM , reg | scale);

112

57

A ANHANGE

113

114 void IMU:: getAccel ()

115 uint8_t val [6] = 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ;

116

117 if (i2c ->getDeviceAddress () != ADR_XM)

118 i2c ->setDeviceAddress(ADR_XM);

119

120 for(int i=0; i<6; i++)

121 val[i] = i2c ->readByte(ACCEL_OUT_X + i);

122

123

124 accel.x = ((( int16_t) val[1] << 8) | val [0]) * 9.81 * accel.sense;

125 accel.y = ((( int16_t) val[3] << 8) | val [2]) * 9.81 * accel.sense;

126 accel.z = ((( int16_t) val[5] << 8) | val [4]) * 9.81 * accel.sense;

127

128

129 void IMU:: getGyro ()

130 uint8_t val [6] = 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ;

131

132 if (i2c ->getDeviceAddress () != ADR_G)

133 i2c ->setDeviceAddress(ADR_G);

134

135 for(int i=0; i<6; i++)

136 val[i] = i2c ->readByte(GYRO_OUT_X + i);

137

138

139 gyro.x = ((( int16_t) val [1] << 8) | val [0]) * gyro.sense;

140 gyro.y = ((( int16_t) val [3] << 8) | val [2]) * gyro.sense;

141 gyro.z = ((( int16_t) val [5] << 8) | val [4]) * gyro.sense;

142

143

144 void IMU:: getMagnet ()

145 uint8_t val [6] = 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ;

146

147 if (i2c ->getDeviceAddress () != ADR_XM)

148 i2c ->setDeviceAddress(ADR_XM);

149

150 for(int i=0; i<6; i++)

151 val[i] = i2c ->readByte(MAGNET_OUT_X + i);

152

153

154 magnet.x = ((( int16_t) val [1] << 8) | val [0]) * magnet.sense;

155 magnet.y = ((( int16_t) val [3] << 8) | val [2]) * magnet.sense;

156 magnet.z = ((( int16_t) val [5] << 8) | val [4]) * magnet.sense;

157

158

159 void IMU:: getTemp ()

160 uint8_t val [2] = 0x00 , 0x00 ;

161

58

A ANHANGE

162 if (i2c ->getDeviceAddress () != ADR_XM)

163 i2c ->setDeviceAddress(ADR_XM);

164

165 for(int i=0; i<2; i++)

166 val[i] = i2c ->readByte(TEMP_OUT + i);

167

168

169 // TODO Temperature Offset

170 // temperature = 21.0 + (float) dof.temperature /8.;

171 temperature = ((( int16_t) val [1] << 8) | val [0]) * TEMP_SENSE +

21;

172

173

174 void IMU:: updateData(timeval time_now)

175 if(TIMEDIFFMS(time_now , last_updated) > IMU_UPDATE_TIMEOUT)

176 this ->getAccel ();

177 this ->getGyro ();

178 this ->getMagnet ();

179 this ->getTemp ();

180

181 last_updated = time_now;

182

183 std::cout << "Accel: " << accel.x << " - " << accel.y << " - "

<< accel.z << std::endl;

184 std::cout << "Gyro: " << gyro.x << " - " << gyro.y << " - " <<

gyro.z << std::endl;

185 std::cout << "Magnet: " << magnet.x << " - " << magnet.y << " -

" << magnet.z << std::endl;

186 std::cout << "Temp: " << temperature << std::endl;

187

188

189

190

191

192 void IMU:: sendData(timeval time_now , ros:: Publisher *imuPub)

193 if(TIMEDIFFMS(time_now , last_sended) > IMU_SEND_TIMEOUT)

194 // x-, y- und z-Werte von ACCEL , GYRO und MAGNET publishen

195 // Temperatur publishen

196

197 /* msl_actuator_msgs :: IMUInfo msg;

198

199 msg.accel = accel;

200 msg.gyro = gyro;

201 msg.magnet = magnet;

202 msg.temperature = temperature;

203

204 imuPub ->publish(msg);*/

205 last_sended = time_now;

206

59

A ANHANGE

207

Listing 9: imu.cpp

1 /*

2 * opticalflow.h

3 *

4 * Created on: Mar 26, 2015

5 * Author: Lukas Will

6 */

7

8 #ifndef CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_OPTICALFLOW_H_

9 #define CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_OPTICALFLOW_H_

10

11

12 #include "config.h"

13

14

15 // ADNS3080 Registers

16 #define PRODUCT_ID 0x00

17 #define MOTION 0x02

18 #define DELTA_X 0x03

19 #define DELTA_Y 0x04

20 #define SQUAL 0x05

21 #define PIXEL_SUM 0x06

22 #define MAXIMUM_PIXEL 0x07

23 #define CONFIGURATION_BITS 0x0A

24 #define EXTENDEND_CONFIG 0x0B

25 #define DATA_OUT_LOWER 0x0C

26 #define DATA_OUT_UPPER 0x0D

27 #define SHUTTER_LOWER 0x0E

28 #define SHUTTER_UPPER 0x0F

29 #define FRAME_PERIOD_LOWER 0x10

30 #define FRAME_PERIOD_UPPER 0x11

31 #define MOTION_CLEAR 0x12

32 #define FRAME_CAPTURE 0x13

33 #define INVERSE_PRODUCT_ID 0x3F

34 #define PIXEL_BURST 0x40

35 #define MOTION_BURST 0x50

36

37 #define RESOLUTION 30

38

39

40 class OpticalFlow

41 private:

42 BlackLib :: BlackGPIO *ncs , *npd , *rst , *led;

43 BlackLib :: BlackSPI *spi;

44 uint8_t img [1536];

45

60

A ANHANGE

46 int16_t x, y;

47 int16_t qos , vQos;

48 int8_t motionBurst [7];

49 int8_t debugOF;

50

51 timeval last_updated , last_sended;

52

53

54

55 void write(uint8_t address , uint8_t value);

56

57 uint8_t getConfigurationBits(void);

58 void getFrame(uint8_t *image);

59 void getFrameBurst(uint8_t *image , uint16_t size);

60 void getMotionBurst(int8_t *burst);

61

62 void setConfigurationBits(uint8_t conf);

63

64

65 public:

66 void reset(void);

67 uint8_t read(uint8_t address);

68

69 OpticalFlow(BlackLib :: gpioName ncs_P , BlackLib :: gpioName

npd_P , BlackLib :: gpioName rst_P , BlackLib :: gpioName

led_P , BlackLib :: BlackSPI *spi_P);

70 ~OpticalFlow ();

71

72 void adns_init(void);

73 void controlLED(bool enabled);

74 void update_motion_burst(timeval time_now);

75 void send_motion_burst(timeval time_now , ros:: Publisher *

mbcPub);

76

77 uint8_t getInverseProductId(void);

78 uint8_t getProductId(void);

79

80

81

82

83 ;

84

85

86

87 #endif /* CNC_MSL_MSL_BEAGLE_BOARD_BLACK_INCLUDE_OPTICALFLOW_H_ */

Listing 10: opticalflow.h

1 /*

61

A ANHANGE

2 * opticalflow.cpp

3 *

4 * Created on: Mar 26, 2015

5 * Author: Lukas Will

6 */

7

8 #include "opticalflow.h"

9

10 using namespace BlackLib;

11

12 OpticalFlow :: OpticalFlow(gpioName ncs_P , gpioName npd_P , gpioName

rst_P , gpioName led_P , BlackSPI *spi_P)

13 ncs = new BlackGPIO(ncs_P , output , FastMode);

14 npd = new BlackGPIO(npd_P , output , FastMode);

15 rst = new BlackGPIO(rst_P , output , FastMode);

16 led = new BlackGPIO(led_P , output , FastMode);

17 spi = spi_P;

18

19

20 x = 0;

21 y = 0;

22 qos = 0;

23 vQos = 0;

24 debugOF = 0;

25

26 /* BlackLib :: BlackGPIO OF_NPD(GPIO_117 , output , FastMode); // P8

07

27 * BlackLib :: BlackGPIO OF_RST(GPIO_115 , output , FastMode); // P8

07

28 * BlackLib :: BlackGPIO OF_NCS(GPIO_112 , output , FastMode); // P8

07 */

29

30

31

32 OpticalFlow ::~ OpticalFlow ()

33 delete ncs;

34 delete npd;

35 delete rst;

36 delete led;

37

38

39 void OpticalFlow :: adns_init(void)

40 //init of sensor

41

42 ncs ->setValue(high);

43 reset();

44

45 usleep (4000);

46

62

A ANHANGE

47 setConfigurationBits (0x00); // set resolution (0x00 = 400 counts

per inch , 0x10 = 1600 cpi)

48 led ->setValue(high);

49

50

51 void OpticalFlow :: controlLED(bool enabled)

52 led ->setValue(static_cast <digitalValue >( enabled));

53

54

55 uint8_t OpticalFlow ::read(uint8_t address)

56 ncs ->setValue(low);

57 spi ->transfer(address , 75); // wait t_SRAD

58

59 uint8_t ret = spi ->transfer (0x00);

60 ncs ->setValue(high);

61

62 return ret;

63

64

65 void OpticalFlow :: reset(void)

66 rst ->setValue(high);

67 rst ->setValue(low);

68 usleep (500);

69

70

71 void OpticalFlow :: write(uint8_t address , uint8_t value)

72 ncs ->setValue(low);

73 spi ->transfer(address | 0x80 , 50);

74

75 spi ->transfer(value);

76 ncs ->setValue(high);

77

78

79 uint8_t OpticalFlow :: getConfigurationBits(void)

80 return read(CONFIGURATION_BITS);

81

82

83 void OpticalFlow :: getFrame(uint8_t *image)

84 reset();

85

86 uint8_t regValue;

87 bool isFirstPixel = false;

88

89 write(FRAME_CAPTURE , 0x83);

90

91 // wait 3 frame periods + 10 us for frame to be captured

92 // min frame speed is 2000 frames/second so 1 frame = 500 us. so

500 x 3 + 10 = 1510

93 usleep (1510);

63

A ANHANGE

94

95 for(int i=0; i<RESOLUTION ;)

96 for(int j=0; j<RESOLUTION ;)

97 regValue = read(FRAME_CAPTURE);

98 if( !isFirstPixel && (regValue & 0x40) == 0 )

99 i=0;

100 j=0;

101 break;

102 else

103 isFirstPixel = true;

104 // pixelValue = ( regValue << 2);

105 *image = ( regValue << 2);

106 //*image = regValue;

107 image ++; // next array cell address

108

109 usleep (50);

110 j++;

111

112 if( isFirstPixel )

113 i++;

114

115

116

117 reset();

118

119

120 void OpticalFlow :: getFrameBurst(uint8_t *image , uint16_t size)

121 uint8_t write_arr[size];

122 uint8_t read_arr[size];

123

124 write(FRAME_CAPTURE , 0x83);

125

126 // wait 3 frame periods + 10 us for frame to be captured

127 // min frame speed is 2000 frames/second so 1 frame = 500 us. so

500 x 3 + 10 = 1510

128 usleep (1510); // wait t_CAPTURE

129

130 ncs ->setValue(low);

131 spi ->transfer(PIXEL_BURST);

132 usleep (50); // wait t_SRAD

133

134 spi ->transfer(write_arr , read_arr , size , 10); // max. 1536 Pixels

135 for(int i = 0; i < size; i++)

136 image[i] = (read_arr[i] << 2);

137

138

139 ncs ->setValue(high);

140

141

64

A ANHANGE

142 uint8_t OpticalFlow :: getInverseProductId(void)

143 return read(INVERSE_PRODUCT_ID);

144

145

146 void OpticalFlow :: getMotionBurst(int8_t *burst)

147 uint8_t write [7] = 0;

148 uint8_t read [7];

149

150 ncs ->setValue(low);

151

152 spi ->transfer(MOTION_BURST);

153 usleep (75);

154

155 // read all 7 bytes (Motion , Delta_X , Delta_Y , SQUAL ,

Shutter_Upper , Shutter_Lower , Maximum Pixels)

156 spi ->transfer(write , read , 7);

157 for (int i = 0; i < 7; i++)

158 motionBurst[i] = read[i];

159

160

161 ncs ->setValue(high);

162

163

164 uint8_t OpticalFlow :: getProductId(void)

165 return read(PRODUCT_ID);

166

167

168 void OpticalFlow :: setConfigurationBits(uint8_t conf)

169 write(CONFIGURATION_BITS , conf);

170

171

172 void OpticalFlow :: update_motion_burst(timeval time_now)

173 if (TIMEDIFFMS(time_now , last_updated) >

OpticalFlow_UPDATE_TIMEOUT)

174 last_updated = time_now;

175

176 /* getMotionBurst(motionBurst);

177 x += motionBurst [1];

178 y += motionBurst [2];

179 qos += motionBurst [3];*/

180

181 if( x!=0 || y!=0 )

182

183 vQos ++;

184

185

186 getMotionBurst(motionBurst);

187 x += motionBurst [1];

188 y += motionBurst [2];

65

A ANHANGE

189 qos += motionBurst [3];

190

191

192

193 void OpticalFlow :: send_motion_burst(timeval time_now , ros:: Publisher

*mbcPub)

194 msl_actuator_msgs :: MotionBurst msg;

195 uint8_t mData [6];

196

197 if (TIMEDIFFMS(time_now , last_sended) > OpticalFlow_BURST_TIMEOUT)

198 last_sended = time_now;

199

200 int16_t tqos = 0;

201 if( vQos != 0 )

202 tqos = qos/vQos;

203

204

205 msg.x = x;

206 msg.y = y;

207 msg.qos = tqos;

208 mbcPub ->publish(msg);

209

210

211

212 x = 0;

213 y = 0;

214 qos = 0;

215 vQos = 0;

216

217

218

219

220 x = 0;

221 y = 0;

222 qos = 0;

223 vQos = 0;

224

Listing 11: opticalflow.cpp

66

ABBILDUNGSVERZEICHNIS

Abbildungsverzeichnis

1 BeagleBoard Black . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Inertiale Messeinheit Adafruit LSM9DS0 [1] . . . . . . . . . . . . . . 123 Schematische Darstellung der Platine . . . . . . . . . . . . . . . . . . 144 Beschaltung der ADUM-Bausteine . . . . . . . . . . . . . . . . . . . 165 Beschaltung des Lichtdetektors IS471 . . . . . . . . . . . . . . . . . . 176 Abbildung der Prototypenplatine . . . . . . . . . . . . . . . . . . . . 237 Graphen der per Schaltregler geregelten Ausgangsspannung . . . . . . 27

67

TABELLENVERZEICHNIS

Tabellenverzeichnis

1 Vergleich der Einplatinencomputer . . . . . . . . . . . . . . . . . . . 62 Genauigkeit der einzelnen Inertialsensoren . . . . . . . . . . . . . . . 113 Ansteuerung des Motortreibers . . . . . . . . . . . . . . . . . . . . . 134 Steckverbindungen auf der Platine . . . . . . . . . . . . . . . . . . . . 18

68

QUELLENVERZEICHNIS

Quellenverzeichnis

[1] Bild der inertialen Messeinheit Adafruit LSM9DS0. 1. Aug. 2014. url: https://learn.adafruit.com/system/assets/assets/000/018/541/large1024/

sensors_pinout.jpg?1406844041 (besucht am 21. 07. 2015).

[2] Bild des BeagleBoard Black Oberseite. 23. Apr. 2013. url: http://www.ti.com / ww / en / beagleboard / product _ detail _ black _ lg . jpg (besucht am22. 07. 2015).

[3] Bild des BeagleBoard Black Unterseite. 3. Apr. 2014. url: https : / / cdn .

sparkfun . com / /assets / parts / 9 / 7 / 2 / 3 / 12076 - 03 . jpg (besucht am21. 07. 2015).

[4] John Clark. Using BeagleBone Black GPIOs. 26. Mai 2013. url: http://www.armhf.com/using-beaglebone-black-gpios/ (besucht am 18. 02. 2015).

[5] Fairchild Semiconductor Corporation, Hrsg. MBRS140 Schottky Rectifier. 2004.

[6] Taiwan Semiconductor Corporation, Hrsg. SD101AW THRU SD101CW Schott-ky Barrier Switching Diode. 2010.

[7] Stein Hardy Danielsen. I2C devices. 14. Juni 2014. url: http://beaglebone.cameon.net/home/i2c-devices (besucht am 05. 03. 2015).

[8] C. M. Dunkers. Beaglebone Black Kernel 3.14 Hardware Encoders and PWM.26. Apr. 2015. url: https://cmumrsdproject.wikispaces.com/Beaglebone+Black+Kernel+3.14+Hardware+Encoders+and+PWM (besucht am 06. 05. 2015).

[9] Timo Heumuller.”Erkennung der Ballbewegung bei einem autonomen Fußball-

roboter“. Projektarbeit. Universitat Kassel, 2014.

[10] Microchip Technology Incorporated, Hrsg. MCP2551 High-Speed CAN Tran-sceiver. 2010.

[11] Texas Instruments, Hrsg. LM2576/LM2576HV Series SIMPLE SWITCHER3A Step-Down Voltage Regulator. 2013.

[12] Jason Kridner. BeagleBone Black switching to 3.14 kernel. 18. Aug. 2014. url:https://groups.google.com/forum/#!topic/beagleboard/4eDQvQOkUkc

(besucht am 19. 03. 2015).

[13] Make: Magazin, Hrsg. c’t Make: (Feb. 2015).

[14] Peter Mancuso. BeagleBone Black BBB C++ API. 3. Feb. 2014. url: https://github.com/petermancuso/bbb (besucht am 08. 06. 2015).

[15] ST Microelectronics, Hrsg. LSM9DS0 iNEMO inertial module. 2013.

69

QUELLENVERZEICHNIS

[16] Robert Nelson. Beagleboard:Capes 3.8 to 3.14. 1. Marz 2015. url: http://

elinux.org/Beagleboard:Capes_3.8_to_3.14#Custom_dtb (besucht am19. 03. 2015).

[17] Robert Nelson. dtb-rebuilder. 27. Aug. 2014. url: https : / / github . com /

RobertCNelson/dtb-rebuilder/tree/3.14-ti (besucht am 19. 03. 2015).

[18] International Rectifier, Hrsg. MBRS360TR Schottky Rectifier. 2003.

[19] National Semiconductor, Hrsg. LM1575/LM2575/LM2575HV SIMPLE SWIT-CHER 1A Step-Down Voltage Regulator. 2004.

[20] Sharp, Hrsg. IS471F. 2010.

[21] Siemens, Hrsg. LD 274 GaAs-IR-Lumineszenzdiode. 1997.

[22] Avago Technologies, Hrsg. ADNS-3080 High-Performance Optical Mouse Sen-sor. 2008.

[23] www.robotikhardware.de, Hrsg. High-Power-Serie Motortreiber 24V12. 2010.

[24] Yigit Yuce. BlackLib v2.0. 2. Okt. 2014. url: http://blacklib.yigityuce.com/v2_0/index.html (besucht am 05. 03. 2015).

70