Muis Sensor - Universiteit van Amsterdam

32
Muis Sensor Bachelor AI Afstudeerproject Louis Fontaine, 0306142 Begeleid door Peter van Lith Samenvatting Een optische muis sensor zoals we die vinden in pc-muizen kan gebruikt worden in een robot om diens positie te bepalen. Tijdens dit project is onderzocht hoe een dergelijke muis sensor de prestatie van een robot bij robotvoetbal kan verbeteren. De optische muis sensor is onder meer in staat om verplaatsingen over een oppervlak en een waar- genomen beeld weg te schrijven. Naast een aantal theorieën over het gebruik van de sensor worden ook enkele experimenten besproken. Geëxperimenteerd is met een robot uitgerust met optische muis sensor, en een robotvoetbal simulatie-omgeving. Uit de experimenten met de robot is gebleken dat de simulatie en de werkelijkheid sterk van elkaar verschillen. Complicaties met interfaces en hardwareproblemen zorgen ervoor dat het testen met de simulator geprefereerd wordt door de snelheid en eenvoud. Daarom is een simulatie van de muis sensor in de simulatie-omgeving geïmplemen- teerd. Het grootste nadeel van de muis sensor is het niet in staat zijn om rotaties op te merken. Tijdens roterende verplaatsingen wordt een plaatsverandering waargenomen in een richting anders dan de beweegrichting van de robot. Dit aspect van de sensor is niet aanwezig in de simulatie, welke alleen representatief is voor situaties waarin de robot strikt in rechte lijnen beweegt. De resultaten van de experimenten met de simulator kunnen echter pas worden geverifieerd met goed werkende hardware. Uit de huidige waarnemingen lijkt het zeer waarschijnlijk dat de eigenschappen van de muis sensor op positieve wijze de prestaties van de robot bij robotvoetbal kunnen beïnvloeden. Universiteit van Amsterdam Faculteit der Natuurwetenschappen, Wiskunde en Informatica Juni 2006

Transcript of Muis Sensor - Universiteit van Amsterdam

Muis Sensor Bachelor AI Afstudeerproject

Louis Fontaine, 0306142 Begeleid door Peter van Lith

Samenvatting Een optische muis sensor zoals we die vinden in pc-muizen kan gebruikt worden in een robot om diens positie te bepalen. Tijdens dit project is onderzocht hoe een dergelijke muis sensor de prestatie van een robot bij robotvoetbal kan verbeteren. De optische muis sensor is onder meer in staat om verplaatsingen over een oppervlak en een waar-genomen beeld weg te schrijven. Naast een aantal theorieën over het gebruik van de sensor worden ook enkele experimenten besproken. Geëxperimenteerd is met een robot uitgerust met optische muis sensor, en een robotvoetbal simulatie-omgeving. Uit de experimenten met de robot is gebleken dat de simulatie en de werkelijkheid sterk van elkaar verschillen. Complicaties met interfaces en hardwareproblemen zorgen ervoor dat het testen met de simulator geprefereerd wordt door de snelheid en eenvoud. Daarom is een simulatie van de muis sensor in de simulatie-omgeving geïmplemen-teerd. Het grootste nadeel van de muis sensor is het niet in staat zijn om rotaties op te merken. Tijdens roterende verplaatsingen wordt een plaatsverandering waargenomen in een richting anders dan de beweegrichting van de robot. Dit aspect van de sensor is niet aanwezig in de simulatie, welke alleen representatief is voor situaties waarin de robot strikt in rechte lijnen beweegt. De resultaten van de experimenten met de simulator kunnen echter pas worden geverifieerd met goed werkende hardware. Uit de huidige waarnemingen lijkt het zeer waarschijnlijk dat de eigenschappen van de muis sensor op positieve wijze de prestaties van de robot bij robotvoetbal kunnen beïnvloeden.

Universiteit van Amsterdam Faculteit der Natuurwetenschappen, Wiskunde en Informatica Juni 2006

2

Inhoudsopgave Inleiding 3 Doelstellingen 3

Theoretisch onderzoek 3 Simulatie experimenten 4 Hardware experimenten 4

Software, hardware en documentatie 4 Aanpak 5 Praktijkfase 6

Optische muis 6 Robot 7 Simulator 8

Theoretische ondersteuning 9 Kalibratie 10 Meetonnauwkeurigheden 10 Sensor parameters 11 Voordelen en nadelen bij robotvoetbal 12 Rotatieprobleem 12

Conclusie 14 Referenties 15 Bijlagen 16

3

Inleiding Ter afsluiting van de Bachelor Kunstmatige Intelligentie aan de Universiteit van Am-sterdam wordt door de student een project uitgevoerd waarin een wetenschappelijk onderzoek wordt verricht. Het is hierbij de bedoeling dat diverse aspecten uit de studie aan bod komen. Mijn afstudeerproject betreft een onderzoek naar het gebruik van een sensor uit een optische muis bij een robot. Een dergelijke sensor kan worden gebruikt om de odometrie, oftewel het registreren van de horizontale en verticale verplaatsing, van de robot af te handelen. Momenteel wordt hiertoe in het RoboCup Jr. robotvoetbal project van Peter van Lith een reflectiesensor gebruikt om de grijswaarde op de onder-grond van het veld te meten. Via die waarde, die tussen wit en zwart varieert, kan de positie op de lengteas van het veld worden bepaald. De odometrie kan ook worden bepaald aan de hand van wielomwentelingen van de robot. Deze methodes zijn echter onderhevig aan fouten en daardoor beperkt bruikbaar. De voornaamste vraag bij het onderzoek is dan ook hoe het gebruik van een optische muis sensor de prestatie van de robot bij robotvoetbal kan verbeteren. Door begeleider Peter van Lith zijn diverse materialen beschikbaar gesteld om het onderzoek uit te voeren. Naast een robot die beschikt over een opti-sche muis sensor is er een simulator beschikbaar, ontwikkeld voor de Java-based Omnidirectional Robot. Door deze simulator uit te breiden met een simulatie van de optische sensor, kun-nen experimenten makkelijker uit worden gevoerd dan met de echte robot. In dit verslag zullen de verschillende doelstellingen van het project worden besproken, de aanpak van de verschillende onderdelen, de resultaten van de experi-menten en theoretische ondersteuning. Tot slot volgt een conclusie met suggesties voor toekomstig werk.

Doelstellingen Het project is onderverdeeld in drie onderdelen: een theoretisch onderzoek, experi-menten die zijn uitgevoerd in de simulatie-omgeving, en experimenten die zijn uitge-voerd met een fysieke robot die beschikt over een optische muis sensor. In eerste in-stantie lag de nadruk voornamelijk op het onderzoek en de experimenten met de hard-ware. Door problemen met de hardware is besloten het project met een andere invals-hoek te benaderen. De experimenten met de simulator, welke eigenlijk meer als een bijzaak werden beschouwd, hebben daardoor een grotere rol gekregen. Theoretisch onderzoek Het voornaamste doel van het project is het onderzoeken hoe de optische sensor bij-draagt aan robots bij robotvoetbal. Hoewel sommige aspecten daarvan alleen uit prak-tijkonderzoek kunnen blijken, kunnen veel theorieën met een kleine hoeveelheid prak-tijkervaring worden opgesteld. Hierbij komen zaken aan bod als: kalibratie van de po-sitie bij het observeren van een muur, het voordeel van een alternatieve ondergrond in

Figuur 1 - JoBot uitgerust met muis sensor

4

plaats van het standaard zwart-naar-wit robotvoetbalveld, het bepalen van meeton-nauwkeurigheden, de toevoeging van een tweede muis sensor, de diverse parameters van de sensor en de nadelen van de muis sensor. Simulatie experimenten Met de JoBot simulator kan geëxperimenteerd worden met een simulatie van de muis sensor. Het voordeel hiervan is dat het experimenteren met de simulator veel makkelij-ker is dan met een echte robot. Het nadeel is dat de simulatie geen perfecte weerspie-geling is van de werkelijkheid, en je daardoor de subtiliteiten mist die het gebruik van de sensor in de praktijk zou kunnen belemmeren. Aanvankelijk zou de output van de sensor op de echte robot rechtstreeks in de simula-tor worden geplugd. Doordat de sensor defect bleek, is gekozen om een gesimuleerde sensor te implementeren. Met een simulatie van de sensor is het een stuk makkelijker om snel experimenten op te zetten. Hardware experimenten Alleen met een robot die uitgerust is met een optische muis sensor kan worden onder-zocht of het gebruik van een dergelijke sensor daadwerkelijk iets op kan leveren. Hier-toe zijn een aantal experimenten gepland die de positieve kanten en beperkingen van de sensor test. Jammer genoeg zijn er enkele problemen geweest waardoor bepaalde as-pecten van de sensor niet konden worden getest. Om de globale werking van de muis sensor te observeren, zijn ook enkele experimen-ten uitgevoerd met optische muizen. Door deze op normale wijze aan te sluiten op een pc kunnen de basisprincipes en tekortkomingen van de optische sensor worden achter-haald. Software, hardware en documentatie Voor het project is een softwarepakket met daarin de RoboCup Junior simulator, bijbe-horende software, en software die door voorgaande teams is gemaakt, te downloaden van UvA BlackBoard (UvANetId login vereist) [1]. Deze simulator is de afgelopen jaren door zowel AI studenten als studenten Software Engineering van het CWI ont-wikkeld. Met de simulator is het mogelijk een op Muvium gebaseerd Java programma te runnen binnen een gesimuleerde omgeving. De Muvium software vormt de link tussen de si-mulator en de echte robot. Door deze software kan software ontwikkelt voor robots in de simulator, runnen op de PIC processors die de JoBot aanstuurt. Hiervoor dient ge-compileerde Java byte code eerst online op de Muvium-server gecompileerd te worden met behulp van de Muvium uVM-IDE. De nieuwste versie van de Muvium Develop-ment Kit uVMDK kan worden gedownload van de Muvium website [2]. De simulator software is ontwikkeld met behulp van de Eclipse Java IDE. Deze ont-wikkelomgeving heb ik ook gebruikt om de simulator aan te passen. Dit betrof Eclipse-SDK versie 3.1 voor Windows XP [3]. Zowel de RoboCup Junior simulator als de Eclipse ontwikkelomgeving vereisen een Java 2 Virtual Machine Runtime Engine. Ik heb gebruik gemaakt van versie 1.4.2 [4]. Voor een gedetailleerde beschrijving hoe de software geïnstalleerd dient te worden, verwijs ik u graag door naar de RoboCup Junior Simulator Manual, welke te downloa-den is van UvA BlackBoard [5].

5

De robot waarover in eerste instantie beschikking is gekregen is een door MultiMotions [6] ontwikkelde JoBot, of Java omnidirectionele robot. Dit is een klein robot platform dat met gehercompileerde Java code te programmeren is. Het gebruikt Muvium PIC processors en is door middel van de beschreven software makkelijk te programmeren en te debuggen. Op het circuit van de robot bevinden zich vier dip-switches, waarmee de robot in 16 verschillende programma’s geschakeld kan worden. De robot heeft drie standaard servomotoren die de omnidirectionele wielen aandrijven. Deze wielen stellen de robot in staat zijwaarts te bewegen met minimale wrijving. De robot beschikt over een vijftal infraroodsensoren: drie gelijk verdeelde actief infrarood afstandssensoren, die door middel van triangulatie nauwkeurig objecten binnen 10 en 80 cm afstand van de sensor kunnen detecteren, onafhankelijk van de kleur van het object; een passief infraroodsensor die een RoboCup Junior bal kan detecteren; een infraroodsensor in het midden van de onderkant van de robot, die de lichtintensiteit van het oppervlak waar de robot op rijdt kan waarnemen. De robot is speciaal uitgerust met een Agilent ADNS-2051 optische muis sensor. De sensor is gebaseerd op navigatietechniek die veranderingen in positie meet door uit

optisch verkregen ondergrondbeelden mathema-tisch de richting en grootheid van beweging te bepalen. Het beeld van de ondergrond bestaat uit 16 × 16 beeldpunten, of ‘Mickeys’, genaamd naar een bekende muis. Door de verplaatsing van puntfragmenten te registreren, wordt bepaald hoeveel de sensor is verplaatst ten opzichte van de ondergrond sinds de vorige beeldregistratie. De standaard resolutie van de sensor is 400 counts per inch, en snelheden tot 14 inch per seconde kunnen worden geregistreerd. Naast de

geregistreerde verplaatsing in beide richtingen kan onder andere ook een pixeldump en de gemiddelde grijswaarde van het geregistreerde beeld worden teruggegeven. In Fi-guur 3 is een schematisch diagram van de sensor weergegeven. Meer informatie over de joBot of de simulator kunt u vinden in de documentatie op BlackBoard, evenals gedetailleerde documentatie van de optische muis sensor.

Figuur 3 - Schematisch diagram van een doorgesneden optische muis sensor

Aanpak Sinds het project in eerste instantie was gericht op experimenten met de robot, leek het een logische stap om er eerst voor te zorgen dat ik de robot kon programmeren en de sensor uit kon lezen. Om dit te bereiken kan de robot kan via een USB-kabel worden verbonden met een pc. Een driver zorgt ervoor dat de USB-verbinding gezien wordt als

Figuur 2 - Optische muis sensor

6

een virtueel aangesloten COMM-poort. Als men nu de uVM-IDE start kan met behulp van een XML configuratiebestand verbinding worden gemaakt met de robot. Let er op dat het configuratiebestand verwijst naar de locatie waar de gecompileerde Java code terechtkomt. Bovendien moet het gebruikte COMM-poortnummer overeenkomen met het nummer van de virtuele COMM-poort, en moet de juiste Bootloader versie gebruikt worden (in mijn geval 14). Zet de robot aan voordat de IDE gestart wordt, anders wordt de verbinding niet gedetecteerd. Als het goed is kan de IDE nu communiceren met de robot. Na de code online gecompileerd te hebben, kan deze worden gedownload naar de robot. Wanneer het programma van de robot gerund wordt kan deze gegevens naar het scherm van de IDE schrijven, waarmee bijvoorbeeld de werking van de muis sensor geïnspecteerd kan worden. Ook zal de output van de sensor in de simulator kunnen worden geplugd, waardoor een hybride situatie van simulatie en werkelijkheid ontstaat. In deze opstellingen kan getest worden hoe nauwkeurig de sensor is, welke problemen optreden en hoe bruikbaar de beeldoutput is voor bepaalde taken die kunnen bijdragen aan de prestaties van de robot. Bij het implementeren van een gesimuleerde muis sensor, is aanvankelijk gericht op het verkrijgen van gesimuleerde verplaatsingswaarden. Hiertoe wordt een nieuwe sensor geïmplementeerd waarin de positie van een robotsimulatie op het gesimuleerde voet-balveld wordt opgeslagen, en zodoende de verplaatsing van de robot kan worden afge-leid aan de hand van een nieuwe positie. De beeldoutput van de sensor wordt gesimu-leerd door een fragment van de bitmap die dient als ondergrond te nemen en weer te geven. Deze methode is niet erg representatief voor de werkelijke situatie, maar deze taak werd aanvankelijk ook slechts als optionele bijkomstigheid beschouwd. Een mooi-ere oplossing wordt in het hoofdstuk ‘Praktijkfase’ besproken. Aan de hand van de resultaten worden theorieën over het gebruik van de sensor uitge-werkt. Hierbij wordt met behulp van de documentatie en de aanwijzingen van de bege-leider geprobeerd een overzicht te creëren van voor- en nadelen van het gebruik van de muis sensor.

Praktijkfase Om het profijt van de muis sensor bij het robotvoetbalspel te achterhalen zijn een aantal experimenten uitgevoerd en situaties gesimuleerd. Experimenten zijn uitgevoerd met optische pc-muizen, om de basiswerking van de muis sensor te achterhalen; met een robot uitgerust met optische muis sensor, om praktische problemen te ontdekken; met de simulator, om makkelijk experimenten op te zetten en uit te voeren. Optische muis Met behulp van een simpele optische muis aangesloten op een pc kunnen de basisprin-cipes achter de plaatsbepaling van de muis sensor achterhaald worden. De cursor op het scherm vormt een vertaling van de verplaatsing. Uit deze experimenten blijkt dat de sensor plaatsveranderingen in elke richting kan waarnemen, zij het dat de muis bij deze beweging niet geroteerd wordt. Het roteren van de muis zorgt ervoor dat de geregi-streerde richting van plaatsverandering met de muis mee roteert, waardoor de werke-lijke plaatsverandering afwijkt van de geregistreerde. Dit probleem zou opgelost kun-nen worden door een tweede muis sensor toe te voegen. Door de positie van de ene sensor ten opzichte van de andere en de robot te weten, kan uit de waarnemingen van beide sensoren ook de rotatie bepaald worden. Deze rotatie kan namelijk worden bere-kend uit het verschil in plaatsverandering bij beide sensoren. Een andere manier waarop

7

de rotatie mogelijk bijgehouden kan worden is aan de hand van de voetbalondergrond. Zie voor deze twee oplossingen de sectie ‘Theoretische ondersteuning’. Het effect van het simultaan aansluiten van twee muizen op een pc is ook getest. Als twee muizen zijn aangesloten, wordt de input van beide muizen automatisch gemid-deld. Met een dergelijke opstelling van twee muis sensoren op een robot wordt echter niets bereikt, omdat de middeling van de input ervoor zorgt dat de waardes die verkre-gen worden hetzelfde zijn als die van een enkele muis sensor die zich op de plaats be-vindt in het midden tussen de twee sensors. Robot Veel van de tijd die in het project is gestoken is doorgebracht met de robot. Het werken met de robot leverde echter vanaf het begin al problemen op. Zo bleek de virtuele COMM-verbinding tussen robot en pc zeer instabiel. Wanneer een van de dip-switches op de robot wordt omgezet terwijl de pc met de robot is verbonden, resulteert dit bijna

gegarandeerd in een systeem crash. Ook het laden van code op de robot die de robot doet vertragen, resulteert in een crash van de pc. Na veel experimenteren blijkt dat het resetten van de robot in veel gevallen een crash kan voorkomen. Het is ook verstandig om de dip-switches van de robot voor het verbinden al in de ge-wenste positie te brengen. De Java code in de .class file die op de robot wordt geladen, moet eerst online op de Muvium server gecompileerd worden. Dit leverde ook enkele problemen op. Zo was de Muvium server tijdens het

project meermalig offline, waardoor code niet gecompileerd kon worden. Ik wist aanvankelijk ook niet dat de robot geen Java code met numerieke data types ander dan integers om kon gaan. Wanneer de code bijvoorbeeld een ‘Double’ bevat, weigert de online compilatie dienst zonder de oorzaak te vermelden. Op een gegeven moment had ik het voor elkaar gekregen om online gecompileerde code op de robot te laden en de robot het programma uit te laten voeren, zonder het optreden van een systeem crash. Deze code zou het pixelbeeld van de sensor uit moeten lezen, en de eerste pixel hiervan naar het scherm moeten schrijven. In de voorbeeldcode die mij aangeleverd was kwam naar voren dat de sensor voor het uitlezen van de pixels eerst moet worden gereset. Een resetSensor aanroep naar de sensor leverde echter een gegarandeerde systeemcrash op. De geladen code die de pixels uitlas en de eerste weg-schreef liet deze reset dan ook achterwege. Aanvankelijk leek de poging succesvol, omdat niets crashte en er iets naar het scherm geschreven werd. Dit was echter geen pixelwaarde maar een vreemd karakter. Een teleurstellend resultaat na een week van experimenteren. Wanneer ik Peter van Lith het resultaat laat observeren, constateert hij dat de sensor niet goed functioneert en niet toegankelijk is door de robot. Het resetten van de sensor - wat tevens noodzakelijk is - zorgt ervoor dat de software blijft hangen. Hoewel voor een vervangende robot gezorgd kan worden, is duidelijk dat de invulling van het pro-ject wegens tijdsrestricties iets moet worden veranderd. De simulatie van de sensor krijgen nu de prioriteit, en de experimenten met een robot zouden misschien later nog uitgevoerd worden. Het is niet meer gelukt om op tijd een robot te vinden met een wer-kende muis sensor.

Figuur 4 - De robot verbonden met een pc

8

Figuur 5 - De JoBot Simulator. In de linker balk zien we de diverse sensoroutputs van de robot. DXMouseSensor geeft de verplaatsing in Mickeys in de horizontale richting, als berekent door de gesimuleerde muis sensor, en DYMouseSensor doet dit voor de verticale richting. Door op de knop ‘Open Mouse Sensor’ te klikken wordt het vierkante venster in het midden van het beeld geopend. Dit venster geeft een pixelfragment uit de achter-grondbitmap weer, ter simulatie van de muis sensor. De robot die we zien is er een van de klasse JPB2MouseBot. Op de achtergrond zien we het RoboCup Jr. voetbalveld.

Simulator De JoBot simulator is een uitgebreid Java programma waarin makkelijk uitbreidingen kunnen worden gemaakt. Om te beginnen heb ik een extra robot klasse toegevoegd die dient als basis voor de robotsimulatie met muis sensor (klasse JB2MouseBot, zie Bijla-gen). In eerste instantie heb ik één extra sensor toegevoegd. Deze sensor huisde de mogelijkheid om de verplaatsing van de robot in X en Y richting te geven, alsmede deze verplaatsing een bepaalde tijd bij te houden en op te tellen tot een reset wordt gegeven. De simulator gaat er echter van uit dat elke geïmplementeerde sensor een enkele waarde teruggeeft. De muis sensor klasse is daarom opgesplitst in twee afzon-derlijke sensorklassen, DXMouseSensor en DYMouseSensor. Deze twee klassen retour-neren afzonderlijk een verplaatsing in de X-richting en Y-richting aan het simulator-venster. De DXMouseSensor beschikt tevens over de geaccumuleerde verplaatsing in beide richtingen sinds de laatste reset. Het bepalen van de verplaatsing gebeurt niet in de afzonderlijke sensorklassen zelf, maar in een klasse welke voorheen alleen de waarde van de lichtintensiteitmeter onder de robot bepaalde. Deze FieldSensorInformation klasse wordt continue aangeroepen om die sensorwaarde te updaten, en het was daarom handig om deze klasse uit te brei-den zodat ook de DX en DY muis sensors worden geüpdate. Voor het berekenen van de verplaatsing wordt in de sensorklassen opgeslagen wat de huidige positie van de robot

9

is in meters. Deze positie kan direct opgevraagd worden uit een robot klasse. Wanneer de sensors worden geüpdate, kan uit deze opgeslagen positie en de nieuwe huidige po-sitie de plaatsverandering in meter worden berekend. Uit de documentatie van de Agi-lent 2051 optische sensor [7] volgt dat de muis sensor standaard een resolutie heeft van 400 counts per inch. Door de verplaatsing in meter om te rekenen naar inch en te ver-menigvuldigen met 400, wordt een meting verkregen die ruwweg gelijk is aan de echte sensor output. Naast de verplaatsing gemeten door de sen-sor was ook gewenst dat een gesimuleerde pixeldump van de sensor verkregen wordt. In de simulator was reeds rekening gehou-den voor de toekomstige implementatie hiervan. Een knop in de Graphical User Interface van de robot, welke weergegeven wordt in het hoofdvenster, opende een ven-ster waarin een ‘smiley’ werd gegenereerd door de klasse OpticalMouseAdaptor. Ik heb de klasse aangepast zodat wanneer de robot waartoe de GUI behoord beschikt over een optische muis sensor, een pixelfragment van 16 × 16 uit de voetbalveldbitmap wordt gehaald. In de huidige implementatie wordt er geen rekening mee gehouden of de voet-balveldachtergrond daadwerkelijk weergegeven wordt, maar ik verwacht dat het niet moeilijk is om dit aan te passen zodat het sensorvenster ook bitmaps van andere onder-gronden kan gebruiken. Natuurlijk is deze implementatie geen realistische benadering van de echte sensor, omdat deze op een veel kleinere schaal een beeldfragment ver-

krijgt. De resolutie van de ondergrondbit-map is veel te klein om een realistisch pixelfragment aan te bieden. Bij een toe-komstige implementatie zou de gesimu-leerde sensor van een random gegenereerd pixelgrid gebruik kunnen maken. Het ge-genereerde pixelgrid is een abstracte re-presentatie van het onregelmatige karakter van optisch waargenomen ondergronden (zie Figuur 6 voor het sensorbeeld bij een ondergrond van wit papier). Door de vere-niging van dit pixelgrid met een uitver-grote en geïnterpoleerde versie van de achtergrondbitmap te nemen, kan een realistischere simulatie van het sensor-beeld worden weergegeven zoals in Figuur 7.

Theoretische ondersteuning De theorieën die hier gepresenteerd worden gaan in op bepaalde aspecten van het ge-bruik van de muis sensor. Veel van wat hier besproken wordt is door de problemen met de hardware nog niet getest.

Figuur 6 - Sensorbeeld van wit papier

Figuur 7 - Simulatie van sensorbeeld

10

Kalibratie De muis sensor kan gebruikt worden om de positie van de robot bij te houden, maar hiervoor moet wel een eerdere positie van de robot bekend zijn. De positie van de robot op de lengte-as van het voetbalveld is ten alle tijden goed te bepalen. De ondergrond van het voetbalveld bestaat namelijk uit een gradiënt van zwart naar wit over de hele lengte van het veld (zie hiervoor Figuur 5). Met behulp van de lichtintensiteitmeter van de robot kan worden bepaald hoe zwart de ondergrond onder de robot is, en aan de hand daarvan is gemakkelijk te bepalen waar op de lengte-as de robot zich bevindt. De grijswaarde van de ondergrond onder de robot kan ook met de muis sensor worden bepaald; er is zelfs een ingebouwde functie die de gemiddelde grijswaarde van de waargenomen pixels retourneert. Hierbij is het wel belangrijk dat de pixelwaardes van de robot niet eerst genormaliseerd zijn, wat standaard wel het geval is. Ook moeten er hiervoor natuurlijk eerst ijkwaardes worden verkregen aan beide uiteindes van het veld. Om de positie van de robot in beide dimensies te verkrijgen, moet er een bepaalde ma-nier van kalibratie zijn. Het is natuurlijk een optie om de robot altijd op dezelfde positie te laten beginnen en de software hier vanuit laten gaan. Naast dat dit erg onhandig is, zal de berekende positie hoogstwaarschijnlijk na verloop van tijd niet meer nauwkeurig zijn door afwijkingen. Een oplossing hiervoor is om de bijgehouden positie van de robot elke keer wanneer een muur wordt geobserveerd te herkalibreren. De robot be-schikt over drie afstandssensoren waarmee de afstand tot een object kan worden be-paald, mits deze zich binnen een afstand van 10cm tot 80cm van de sensor bevindt. Als een muur namelijk wordt geobserveerd, worden de mogelijke posities van de robot teruggebracht naar twee (aan beide zijdes van het veld, op gelijke afstand van de muur). Als we echter ook continue de oriëntatie van de robot van de robot bijhouden, weten we absoluut zeker waar de robot zich bevindt (zie voor ideeën over het bijhouden van de oriëntatie, ‘Rotatieprobleem’). Een extra probleem doet zich voor wanneer er ook andere robots op het veld aanwezig zijn, iets dat gebruikelijk is bij een potje robotvoetbal. De afstandssensoren op de robot kunnen namelijk geen onderscheid maken tussen een muur en een robot. Wanneer het waargenomen object beweegt is er geen probleem, omdat muren in het algemeen niet bewegen. Als er echter een stilstaande robot wordt waargenomen, zal de robot moeten berusten op zijn wereldkennis en diens verwachte positie. Als in de bijgehouden positie de afstand tot de muur sterk afwijkt van de afstand waarbinnen het object wordt waar-genomen, is aan te nemen dat het object een robot betreft. Deze methode is natuurlijk niet geheel betrouwbaar, maar het is een hele verbetering ten opzichte van de situatie waarin de positie in de breedte-as helemaal niet wordt bijgehouden. Meetonnauwkeurigheden Met de komst van de muis sensor kunnen een hoop gegevens nauwkeuriger worden bepaald. De lokalisatie van de robot staat daarbij natuurlijk voorop. Eén van de metho-des waarop dit voorheen werd bepaald is aan de hand van de draaiing van de wielen. Zelfs in een wereld zonder obstakels is deze methode nogal onnauwkeurig, doordat deze methode standaard een kleine afwijking heeft. Na verloop van tijd is deze afwij-king geaccumuleerd tot een flinke drift. Het wordt nog erger naarmate er ook muren en robots bij worden betrokken, omdat de wielen flink door kunnen slippen bij botsingen. Aan de hand van de wieldraaiingen werd ook de snelheid van de robot berekend. Met de muis sensor kan de snelheid veel nauwkeuriger worden bepaald. Door de berekende snelheid aan de hand van de wieldraaiing te vergelijken met de snelheid berekent met behulp van de muis sensor, kunnen we meten hoeveel drift er nou eigenlijk optreedt bij die eerste methode. Om de meetonnauwkeurigheden van de muis sensor te bepalen, zijn andere technieken nodig. Door de robot twee afstanden van ongelijke lengte af te laten leggen, kan aan de

11

hand van de sensorwaardes opgemaakt worden hoeveel de sensor afwijkt. Ook is het interessant om te onderzoeken of de robot de maximaal meetbare snelheid van 14 inch per seconde weet te overschrijden. Als de voetbalrobots zich doorgaans op snelheden voortbewegen die hoger zijn, kan dit een groot probleem vormen voor de algemene bruikbaarheid van de sensor. Door ervoor te kiezen binnen de meetbare snelheid te blijven zijn de tegenstanders mogelijk sneller, terwijl je door hun snelheid bij te houden je de nauwkeurigheid van je plaatsbepaling verliest. Sensor parameters De prestaties van de muis sensor zijn naast de bewegingssnelheid van een groot aantal parameters afhankelijk. Behalve de interne parameters is het ook belangrijk dat de hardware-as-pecten in orde zijn. Uit de documen-tatie van de Agilent 2051 optische sensor volgt onder andere dat de af-stand van de sensor tot de grond heel nauw luistert. In de grafiek in Figuur 8 zien we gemiddelde genormaliseerde ‘squal’ waardes uitgezet tegen de af-stand van de ondergrond tot de brand-puntsafstand van de lens. De squal geeft aan hoeveel beeldpunten van een waargenomen frame door de sensor zichtbaar zijn. Uit de genormaliseerde squal waardes in de grafiek volgt dat bij een bepaalde brandpuntsafstand van de sen-sorlens, een afwijking van slechts 1mm er voor kan zorgen dat nagenoeg niets wordt waargenomen. Als het dus niet mogelijk is om de sensor binnen de juiste afstandsmar-ges te plaatsen, kan overwogen worden een lens te nemen met een andere brandpunts-afstand. Een bijkomend probleem hierbij is echter dat het beeld dat op de optische sen-sor geprojecteerd wordt hierdoor veranderd. In Figuur 8 zien we dat lenzen met ver-schillende brandpuntsafstanden ook andere maximale squal waardes hebben. De af-stand van de sensor tot de grond kan dus een flink probleem opleveren. De sensor is standaard ingesteld op een resolutie van 400 counts per inch. Deze resolu-tie kan ook verdubbeld worden naar 800cpi. Het is nog maar de vraag of we hiermee ook beter af zijn. Als we de namelijk de sensor niet alleen willen gebruiken voor het bepalen van de verplaatsing maar ook voor het verkrijgen van beeldinformatie, kan deze resolutie misschien wel te hoog zijn. Als we op het verkregen beeld beeldbewer-kingen willen toepassen, kan de hogere resolutie ervoor zorgen dat we teveel informatie verliezen door de grofheid van de ondergrond. Het verhogen van de resolutie zorgt er daarnaast voor dat de sensor minder hoge snelheden kan registreren. Hoewel steeds van hetzelfde type sensor is uitgegaan, kunnen anderen natuurlijk ook gebruikt worden. Tegenwoordig zijn er ook optische laser muizen met een veel hogere resolutie. Voor deze muizen gelden andere beperkingen dan voor reguliere optische muizen. Een toe-komstig vervolgproject zou mogelijk dergelijke muizen kunnen onderzoeken. Naast het verhogen van de resolutie kan ook de frequentie van de sensor worden aan-gepast. Met een hogere frequentie worden meer frames per seconde vergaard. Maar meer informatie is niet altijd beter. Ook hierbij geldt dat we tegen problemen aan kun-nen lopen als we de sensorbeelden voor beeldbewerkingstoepassingen willen gebrui-ken. Deze toepassingen eisen doorgaans wat meer inspanning van de hardware, en du-ren daardoor ook lang. In de verwerkingstijd kan echter allang nieuwe informatie be-

Figuur 8 - Squal waardes uitgezet tegen de afstand tot het brandpunt

12

schikbaar zijn gekomen. Het is daarom niet vanzelfsprekend dat een hogere frequentie de prestaties goed zal doen. Een van de ingebouwde functies in de muis sensor is het normaliseren van verkregen beelden. Hierdoor wordt het contrast van de beelden groter, en wordt het makkelijker om bepaalde beeldbewerkingen uit te voeren. Voor sommige toepassingen is het echter gewenst dat de ruwe data kan worden gebruikt, bijvoorbeeld om ‘handmatig’ de ge-middelde pixelwaarde te berekenen. Hiertoe kan normalisatie uitgezet worden, hoewel dit mogelijk andere bewerkingen beïnvloed. Er moet dus een trade-off gemaakt worden tussen wel of niet normaliseren, of er moeten procedures worden geschreven die reke-ning houden met het in- danwel uitschakelen van de normalisatie. Voordelen en nadelen bij robotvoetbal Een hoop aspecten van het gebruik van de muis sensor zijn inmiddels besproken, maar het is nog niet goed duidelijk in hoeverre de sensor bij kan dragen aan robotvoetbal. Het sterkste punt van de muis sensor is het bepalen van de verplaatsing. Hiermee kan de lokalisatie van de robot veel nauwkeuriger worden bepaald dan met conventionele methodes. De positie van de robot tot het doel kan ook opeens worden berekend, iets dat voorheen een kompas-sensor vereiste. Zelfs zonder veel kennis van het voetbalspel is te bedenken dat het vinden van het doel een geweldige vooruitgang betekend voor de speelprestaties. Met behulp van de betere lokalisatie is het tevens een stuk makkelijker geworden om muren, van andere objecten - tegenstanders - te onderscheiden, aangezien in theorie bekend is waar de muren zich precies bevinden ten opzichte van de robot. De muis sensor zorgt er dus voor dat er een betere interne representatie van de hele spelsituatie kan worden gemaakt. Dit stelt de robotvoetbal ‘spelers’ in staat veel geavanceerdere strategieën uit te voeren. Waar het voorheen gebruikelijk was om met de inmiddels bekende zwart-wit-gradiënt ondergrond te spelen, kan met de komst van de muis sensor ook overwogen worden een alternatief speelveld te gebruiken. De gradiënt is immers niet meer noodzakelijk voor een goede bepaling van de robotpositie. Bij alternatieve speelvelden kan bijvoor-beeld gedacht worden aan een klassiek groen veld met witte belijning. Met behulp van de muis sensor kunnen deze lijnen overigens ook worden waargenomen en geïnter-preteerd, en heeft de ondergrond zelfs enige toegevoegde waarde. Hoewel een dergelijk speelveld realistischer over zal komen, is het verlies van de gradiënt misschien toch wel jammer. De gradiënt kan immers nog steeds gebruikt worden om de verwachte positie van de robot in de lengte-as te herkalibreren. Het grootste nadeel van de muis sensor blijft het niet in staat zijn om rotaties te detecte-ren. We kunnen argumenteren dat dit rotatieprobleem geen nadeel is, omdat het niet door de toevoeging van de muis sensor wordt veroorzaakt. Zonder de muis sensor zou dit probleem immers ook aanwezig zijn en zelfs in het niet vallen bij de andere proble-men met plaatsbepaling. Behalve wat extra stroomverbruik, het beleid waarmee de sensor moet worden gemonteerd en de nauw luisterende sensor parameters, zijn er dan ook geen nadelen te vinden die de sensor met zich meebrengt. Maar hoewel het rotatie-probleem dan geen nadeel mag heten, is het wel vervelend. Rotatieprobleem Om de oriëntatie van de robot te bepalen en bij te houden zijn verschillende technieken te gebruiken. Het is gebruikelijk om dit, net als bij de verplaatsing, te doen door de draaiing van de wielen bij te houden. Ook hierbij geldt dat deze methode sterk onder-hevig is aan fouten en afwijking. Met de muis sensor kan dit probleem misschien ver-holpen worden.

13

De ondergrond van het voetbalveld bestaat uit een gradiënt van zwart naar wit (of wit naar zwart, afhankelijk van speelrichting). Als deze gradiënt perfect analoog is, is in theorie uit elk fragment van minimaal vier verschillende grijswaarden de richting van de gradiënt te bepalen. In Figuur 9 zien we hier een simpel voorbeeld van. De pixel-waarden zijn hierbij genormaliseerd om de verschillen zichtbaar te maken. Als de voetbalveld-gradiënt nauwkeurig genoeg is, kan de richting van de gradiënt ook bepaald worden uit het 16 × 16 beeld van de muis sen-

sor. Door de pixels van een frame te verdelen in twee groepen op basis van pixelwaarde, ontstaat een simpel classificatieprobleem. Met behulp van een classificatie-methode als de Bayes regel of misschien door het leren van een kunstmatig perceptron kan deze puntenwolk van lichte en donkere pixels worden gescheiden door een rechte lijn. De richting van de gradiënt staat loodrecht op deze scheidslijn (zie Figuur 10 voor een voorbeeld). Helaas heb ik door de hardwareproblemen niet kunnen testen of zowel de muis sensor als de voetbalondergrond nauwkeurig genoeg zijn om een geschikt beeldfragment te verkrijgen waaruit genoeg informatie te halen is. Een manier die waarschijnlijk beter zal werken vereist het toevoegen van een tweede muis sensor. Wanneer de

robot beschikt over twee muis sensoren op een vaste afstand, kan uit het verschil tussen de waargenomen waardes van de twee sensoren de rotatie van de robot worden be-paald. In het geval dat beide sensoren dezelfde waardes van plaatsverandering teruggeven, roteert de robot meestal niet (Er is een speciaal geval waarbij dit niet op gaat, hier kom ik zo op terug). Wan-neer de sensoren elkaars inverse waarde teruggeven, betekent dit dat de robot ro-teert rond het punt in het midden van de twee sensoren (zie Figuur 11). In de an-dere gevallen kan de rotatie worden bere-kend. In het linker deel van Figuur 12 zien we een roterende beweging van de robot. De muis sensoren zijn hier aangeduid met s1 en s2. De rode lijn geeft het gemiddelde van de afgelegde weg door beide sensoren aan. Doordat de beweegrichting van de sen-

soren met de robot meedraait, detecte-ren de sensoren een verplaatsing die wordt beschreven door een rechte lijn, zoals in het rechterdeel van de figuur wordt weergegeven. De gemiddelde waarneming s’ geeft de lengte van de afgelegde weg gezien vanuit het mid-delpunt. Om hieruit de rotatie te be-palen, moeten we eerst de grootte van straal r bepalen. Straal r loopt van het draaipunt tot het middelpunt van de twee sensoren. Lengte x is de afstand van een sensor tot dit middelpunt. Straal r wordt als volgt berekend:

Figuur 9 - Gradiëntrichting bepaling

Figuur 10 - Scheidslijn en gradiëntrichting

Figuur 11 - Rotatie rond het middelpunt van twee muis sensoren

Figuur 12 - Roterende beweging met twee muis sensoren

14

Wanneer r berekend is, kan draaihoek a worden berekend:

Het speciale geval dat ik noemde waarbij de rotatie niet kan worden bepaald, is wanneer beide sensoren op de lijn liggen waarover bewogen wordt (zie Figuur 14). In deze situaties zullen beide sensoren dezelfde rechtlijnige verplaatsing, schuin opzij aangeven. Ik ben steeds uit gegaan van het geval dat de sensoren naast elkaar worden geplaatst, maar als deze zich achter elkaar bevinden zal natuurlijk dezelfde verplaatsing vooruit of achteruit worden geobserveerd. Het probleem van dit geval kan opgelost worden door een derde muis sensor aan de robot toe te voegen

Conclusie Het gebruik van optische muis sensoren bij robots voor robotvoetbal heeft vele voor-delen. De meeste van deze voordelen resulteren in een betere plaatsbepaling. Doordat de plaatsbepaling zoveel beter is dan voorheen, zijn nieuwe spelstrategieën uitvoerbaar geworden. Het bepalen van de positie van het doel is daar een belangrijk onderdeel van. De keuze om tijdens het project de invulling ervan te wijzigen is een goede gebleken. Het werken met de simulator is veel gemakkelijker dan het werk met de fysieke robots. Hoewel bij beide gesimuleerde aspecten van de muis sensor, ruimte is voor verbetering om een realistischere simulatie te verkrijgen, kan uit de huidige implementatie al op-gemaakt worden dat de toevoeging van de muis sensor een verrijking is voor het robot-voetbal. Sommige elementen uit de theoretische ondersteuning zullen misschien niet zo goed werken als verwacht, maar in het algemeen denk ik dat met verder uitgewerkte technieken, de muis sensor een belangrijke toevoeging aan het robotvoetbal zal blijken. Bij toekomstige projecten naar het gebruik van muis sensors bij robots is het belangrijk dat uitgezocht wordt welke verschillen er zijn tussen de gesimuleerde sensor en de hardware sensor. Met name de mogelijke onnauwkeurigheid van de sensor lijkt me interessant om te meten. Ook kan worden onderzocht of het type sensor dat we vinden in laser muizen betere resultaten oplevert dan de hier onderzochte sensor. Het lijkt me ook dat er een betere oplossing voor het rotatieprobleem te vinden moet zijn dan het toevoegen van een extra, of zelfs twee extra muis sensoren. Ik ben zelf zeer geïnteres-seerd zijn in de ideeën die hier nog over ontstaan in de toekomst.

Figuur 14 - Onmeetbare rotatie

15

Tot slot wil ik vermelden dat ik dit een heel leuk project heb gevonden, en ook een leuke manier om mijn periode als Kunstmatige Intelligentie student af te sluiten. Hope-lijk zal ik de komende twee jaar als student Artificial Intelligence net zo leuke en leer-zame ervaringen op doen als deze. Graag wil ik Peter van Lith bedanken voor de begeleiding van het project.

Louis Fontaine

Referenties [1] JoBot simulator package http://blackboard.ic.uva.nl/courses/1/15.OWII.BAIAP6.1.20052006/content/_5

65013_1/JobotSim19x.rar [2] Muvium website

http://www.muvium.com [3] Eclipse-SDK 3.1 voor Windows XP download pagina

http://download.eclipse.org/eclipse/downloads/drops/R-3.1-200506271435/in-dex.php

[4] Java 2 Virtual Machine Runtime Engine download pagina

http://java.sun.com/j2se/1.4.2/download.html [5] RoboCup Junior simulator manual

http://blackboard.ic.uva.nl/courses/1/15.OWII.BAIAP6.1.20052006/content/_565013_1/JoBot_Manual_EngV1.6.pdf

[6] MultiMotions website http://www.multimotions.com [7] Agilent 2051 optische sensor documentatie

http://blackboard.ic.uva.nl/courses/1/15.OWII.BAIAP6.1.20052006/content/_565013_1/ADNS2051_data_sheet.pdf

16

Bijlagen De Java klassen hieronder zijn vervangende of aanvullende klassen op de JoBot Simulator. Deze klassen zijn aangepast of gecreëerd om de nieuwe simulatie robot met gesimuleerde optische muis sensor en de simulatie van de sensor output te creëren. De klasse CalibrateBehavior was een poging om de sensor output van de fysieke robot in de simulator te pluggen. Klasse JobotBaseController was hiertoe uitgebreid met twee nieuwe functies. De Simulator klasse is lichtelijk uitgebreid om de nieuwe JPB2MouseBot aan te kunnen maken. Deze klasse is echter niet toegevoegd vanwege de minisculiteit van de veranderingen. De klasse MouseSensor is wat later is geëvolueerd tot DXMouseSensor en DYMouseSensor. JPB2MouseBot package javaBot; import org.openVBB.interfaces.IopenVBBRTI; import org.openVBB.robotKit.controllers.JoBotJPB2Controller; import org.openVBB.robotKit.interfaces.Units; import org.openVBB.sim.rti.OpenVBBRTIImpl; public class JPB2MouseBot extends UVMRobot { private static final String IMAGE_FILE = Simulator .getRelativePath("./resources/jobot.gif"); private static final String CONFIG_XML = Simulator.getRelativePath("JPB2/jobot.xml"); private static final int DIAMETER_IN_IMAGE = 100; public static final double BASE_RADIUS = 0.072; public static final double WHEEL_RADIUS = 0.020; public static final int RED_LED = 0; public static final int YELLOW_LED = 1; public static final int GREEN_LED = 2; public static final int BLUE_LED = 3; /** Not Documented yet */ JoBotServoMotor[] servoMotors; /** * Creates a new UVMRobot instance * * @param name * @param positionX * @param positionY */ public JPB2MouseBot(String name, double positionX, double positionY) { /* * friction = 7.0 * diameter = 2.0 * mass = 3.0 */ super(name, 7.0, positionX, positionY, BASE_RADIUS * 2, 3); try { // Create the sensors

17

setSensors(new Sensor[7]); // addSensor parameters: sensorClassName, radius,position [, direction] getSensors()[0] = addSensor("ReflectionSensor",BASE_RADIUS, 270); getSensors()[1] = addSensor("ReflectionSensor",BASE_RADIUS, 30); getSensors()[2] = addSensor("ReflectionSensor",BASE_RADIUS, 150); getSensors()[3] = addSensor("IRSensor", WHEEL_RADIUS, 270, 90); getSensors()[4] = addSensor("FieldSensor" , BASE_RADIUS, 270); getSensors()[5] = addSensor("DXMouseSensor" , BASE_RADIUS, 270); getSensors()[6] = addSensor("DYMouseSensor" , BASE_RADIUS, 270); } catch( ReflectionException e ) { e.printStackTrace(); } // Create the leds setLeds(new Led[4]); getLeds()[GREEN_LED] = new Led(java.awt.Color.GREEN, 0); getLeds()[RED_LED] = new Led(java.awt.Color.RED, 0); getLeds()[YELLOW_LED] = new Led(java.awt.Color.YELLOW, 0); getLeds()[BLUE_LED] = new Led(java.awt.Color.BLUE, 0); loadApp(CONFIG_XML); vbbRTI.start(); if (servoMotors != null) { setActors(new Actor[3]); getActors()[0] = servoMotors[0]; getActors()[1] = servoMotors[1]; getActors()[2] = servoMotors[2]; } } /** * TODO METHOD: DOCUMENT ME! * * @return $returnType$ TODO RETURN: return description */ protected String getConfigXMLDoc() { return CONFIG_XML; } /** * This returns the sensor values * * @param channel DOCUMENT ME! * * @return DOCUMENT ME! */ public double getADCSample(int channel) { if (getSensors() == null) { System.out.println("Sample requested by null sensorValues"); return 0; }

18

// if (channel == 3) Debug.printDebug("Reading channel " + channel); return getSensors()[channel].getValue() / 1000; } /* (non-Javadoc) * @see javaBot.PhysicalObject#createGraphicalRepresentation() */ public GraphicalRepresentation createGraphicalRepresentation() { return new GraphicalRepresentation(this, IMAGE_FILE, DIAMETER_IN_IMAGE, true); } /** * DOCUMENT ME! * * @param vout DOCUMENT ME! * @param pinId DOCUMENT ME! */ public void digitalOutputPinChanged(boolean vout, int pinId) { if (vout == true) { getLeds()[pinId].setValue(1.0); } else { getLeds()[pinId].setValue(0.0); } } /** * Loads the application * * @param configXML */ public void loadApp(String configXML) { System.out.println("Loading from config file: " + configXML); /** * If there is an existing simulation RTI then we need to rip it up and * release the resources associated with the RTI so we can start over */ if (vbbRTI != null) { vbbRTI.ripUp(); } vbbRTI = new OpenVBBRTIImpl(); controller = new JoBotJPB2Controller(this, .1, (IopenVBBRTI) vbbRTI, configXML); /** * Register JoBotServoMotors as ServoPulseListeners */ servoMotors = new JoBotServoMotor[3]; for (int i = 0; i < servoMotors.length; i++) { servoMotors[i] = new JoBotServoMotor(0.0, 156, 1 * Units.MILLISECONDS,

19

2 * Units.MILLISECONDS); controller.registerServoPulseListener(servoMotors[i], i); } /** * Register ADCSampleListeners to read the sensors */ controller.registerADCSampleListener(this, 0); controller.registerADCSampleListener(this, 1); controller.registerADCSampleListener(this, 2); controller.registerADCSampleListener(this, 3); controller.registerADCSampleListener(this, 4); /** * Register DigitalOutputListeners to read update the LED values */ controller.registerDigitalOutputListener(this, RED_LED); controller.registerDigitalOutputListener(this, YELLOW_LED); controller.registerDigitalOutputListener(this, GREEN_LED); controller.registerDigitalOutputListener(this, BLUE_LED); controller.setPortBDIP(15); // Initialize the DIP settings } /* (non-Javadoc) * @see javaBot.MovableObject#update(double) * Please note that the standard futaba servo's rotate in the opposite * direction compared to the HiTec servos. */ public void updatePosition(double elapsed) { double w0 = servoMotors[0].getValue(); double w1 = servoMotors[1].getValue(); double w2 = servoMotors[2].getValue(); if (servoMotors != null) { /* * rvx and rvy are the x and y components of the * driving velocity relative to the robot's orientation */ double rvx = (WHEEL_RADIUS / 3.) * ((-2 * w0) + w1 + w2); double rvy = (WHEEL_RADIUS / Math.sqrt(3.)) * (-w1 + w2); setDrivingVelocityX(0 - ((rvx * Math.cos(rotation)) - (rvy * Math.sin(rotation)))); setDrivingVelocityY(0 - ((rvx * Math.sin(rotation)) + (rvy * Math.cos(rotation)))); this.setRotationSpeed(0 - ((WHEEL_RADIUS / (3. * BASE_RADIUS)) * (w0 + w1 + w2))); } } /** * Get a led's on/off status * * @return $returnType$ TODO RETURN: return description */ public boolean getGreenLed() { return (getLeds()[GREEN_LED].getValue() != 0); }

20

/** * TODO METHOD: DOCUMENT ME! * * @return $returnType$ TODO RETURN: return description */ public boolean getRedLed() { return (getLeds()[RED_LED].getValue() != 0); } /** * TODO METHOD: DOCUMENT ME! * * @return $returnType$ TODO RETURN: return description */ public boolean getYellowLed() { return (getLeds()[YELLOW_LED].getValue() != 0); } /** * TODO METHOD: DOCUMENT ME! * * @return $returnType$ TODO RETURN: return description */ public boolean getBlueLed() { return (getLeds()[BLUE_LED].getValue() != 0); } } DXMouseSensor /* * Created on Jun 22, 2006 */ package javaBot; /** * Simulates the optical mouse sensor on the robot to determine the last * location change on the playingfield in horizontal direction. Also holds * the sum of the total position change since the last sensor reset. */ public class DXMouseSensor extends Sensor { private int[] dxy = new int[2]; private double lastX; /** * Creates a new DXMouseSensor object. * * @param position The position relative to the robot the sensor placed on * @param angle The angle relative to the robot under which the sensor * placed */ public DXMouseSensor(Location position, double angle) { // create sensor with position, angle and default value 0 super("DXMouseSensor", position, angle, 0); lastX = position.getX(); dxy[0] = 0;

21

dxy[1] = 0; } public double getLastLocation(){ return lastX; } public void setLastLocation(double loc){ lastX = loc; } /** * Clears the travelled distance and returns its former value */ public int[] resetSensor(){ int[] temp = (int[])dxy.clone(); dxy[0] = 0; dxy[1] = 0; return temp; } public int[] getDistance(){ return dxy; } public void setDistance(int nx, int ny){ dxy[0] += nx; dxy[1] += ny; } } DYMouseSensor /* * Created on Jun 22, 2006 */ package javaBot; /** * Simulates the optical mouse sensor on the robot to determine the last * location change on the playingfield in vertical direction. */ public class DYMouseSensor extends Sensor { private double lastY; /** * Creates a new DYMouseSensor object. * * @param position The position relative to the robot the sensor placed on * @param angle The angle relative to the robot under which the sensor * placed */ public DYMouseSensor(Location position, double angle) { // create sensor with position, angle and default value 0 super("DYMouseSensor", position, angle, 0); lastY = position.getY(); } public double getLastLocation(){ return lastY; }

22

public void setLastLocation(double loc){ lastY = loc; } } FieldSensorInformation package javaBot; import java.awt.Image; import java.awt.Point; /** * Created on 20-02-2006 * Copyright: (c) 2006 * Company: Dancing Bear Software * * @version $Revision$ * last changed 20-02-2006 * * TODO CLASS: DOCUMENT ME! */ public abstract class FieldSensorInformation extends NonMovableObject { private String name; protected Image img; final double scale = 400 * 39.37; // Mouse sensor resolution is 400 mickeys per inch, 1m = 39.37" /** * Creates a new FieldSensorInformation object. * * @param name TODO PARAM: DOCUMENT ME! */ public FieldSensorInformation(String name) { super("field"); this.name = name; } /** * Returns the image of the map * * @return $returnType$ TODO RETURN: return description */ public abstract Image getImage(); /** * Returns the value of the pixel on the rescuefield on the robot's * position * * @param r TODO PARAM: DOCUMENT ME! * * @return $returnType$ TODO RETURN: return description */ public double[] giveSensoryInformationTo(Robot r) { double[] returnValue = r.newSensorValues(); try { Sensor[] sar = r.getSensors(); // Loop through the robot's sensor to locate a FieldSensor (and MouseSensor)

23

for (int i = 0; i < sar.length; i++) { if (sar[i] instanceof FieldSensor) { PixelGrab pixelGrab = new PixelGrab(); Sensor s = sar[i]; Location sensorLocation = getSensorLocation(r, s); // Location robotLocation = r.getLocation(); // Location relativeSensorLocation = s.getPosition(); // Location sensorLocation = new Location(robotLocation.getX() // + relativeSensorLocation.getX(), robotLocation.getY() // + relativeSensorLocation.getY()); Point location = Simulator.toPixelCoordinates(sensorLocation); int pg = pixelGrab.handlepixels(getImage(), location.x, location.y, 1, 1); returnValue[i] = (double) pg; //Debug.printInfo("Pixelvalue("+location.x+","+location.y+")="+pg); } else if (sar[i] instanceof DXMouseSensor && sar[i+1] instanceof DYMouseSensor){ DXMouseSensor sx = (DXMouseSensor)sar[i]; DYMouseSensor sy = (DYMouseSensor)sar[i+1]; Location sensorLocation = getSensorLocation(r,sx); Location deltaLocation; double dx = scale*(sensorLocation.getX() - sx.getLastLocation()); double dy = scale*(sensorLocation.getY() - sy.getLastLocation()); sx.setLastLocation(sensorLocation.getX()); sy.setLastLocation(sensorLocation.getY()); sx.setDistance((int)dx,(int)dy); returnValue[i] = dx; returnValue[i+1] = dy; } } return returnValue; } catch (Exception e) { Debug.printError("An error occurred in " + name + ": " + e.toString()); } return returnValue; } public Location getSensorLocation(Robot r, Sensor s) {

24

double diam = Math.sqrt(Math.pow(s.getPosition().getX(), 2) + Math.pow(s.getPosition().getY(), 2)); double posX = r.getLocation().getX(); double posY = r.getLocation().getY(); posX += Math.cos(s.getAngle() + r.getRotation()) * diam; posY += Math.sin(s.getAngle() + r.getRotation()) * diam; return new Location(posX, posY); } /** * Rescales the field sensor information image * @param width: <strong>absolute<strong> width of Image * @param heigth: <strong>absolute<strong> width of Image */ public void rescaleImage(int width, int heigth) { img=img.getScaledInstance(width,heigth,Image.SCALE_DEFAULT); } } OpticalMouseAdaptor package javaBot; import java.awt.Image; import java.awt.Point; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.PixelGrabber; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.File; import javax.imageio.ImageIO; import javax.swing.WindowConstants; public class OpticalMouseAdaptor implements Runnable{ private Robot robot; public OpticalMouseAdaptor(Robot robot){ super(); this.robot = robot; } public Location robotLocation = new Location(); private byte[] inputByte = new byte[256]; private DataInputStream inputStream = null; private boolean bRunning = true; public void run(){ final SerialGUI serialGUI = new SerialGUI(); serialGUI.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); serialGUI.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ serialGUI.setVisible(false); bRunning = false; }

25

}); serialGUI.setVisible(true); readInputStream(serialGUI); } private void readInputStream(SerialGUI serialGUI){ while (bRunning){ for (int Offset = 0; Offset <= 13; Offset++){ //Read serial input (Real stream input!) //inputStream = new // DataInputStream(serialPort.getInputStream()); // does not // work! inputByte = pixelArea(Offset); ByteArrayInputStream randomData = new ByteArrayInputStream( inputByte); inputStream = new DataInputStream(randomData); // end Use random data // Convert to local bytearray serialGUI.setData(inputStream); // Show data on screen serialGUI.DrawOutput(); } } } /** * Grabs an area of pixels from the football playingfield image * Currently, it grabs from the football field image regardless * of it actually being displayed. * * @return byte array with pixelvalues */ private byte[] pixelArea(int Offset){ Sensor[] sar = robot.getSensors(); for (int i = 0; i < sar.length; i++){ if (sar[i] instanceof DXMouseSensor){ // The football field image and its dimensions are hardcoded in File file = new File(Simulator.getRelativePath("./resources/field.gif")); int imageWidth = 816; int imageHeight = 479; try{ Image img = ImageIO.read(file); byte[] b = new byte[256]; int[] pixels = new int[256]; Location senloc = getSensorLocation(robot, sar[i]); int pixelX = (int)(imageWidth*senloc.getX()/World.WIDTH); int pixelY = (int)(imageHeight*senloc.getY()/World.HEIGHT); Point loc = Simulator.toPixelCoordinates(senloc); PixelGrabber pg = new PixelGrabber(img, pixelX-7, pixelY-7, 16, 16, pixels, 0, 16); pg.grabPixels();

26

for (int j = 0; j < 256; j++){ b[j] = (byte)(100+handleSinglePixel(pixels[j])); } b[255] = 127; return b; }catch (Exception e){ Debug.printError("An error occurred in OpticalMouseAdaptor: "+ e.toString()); } } } return Smilie(Offset); } /** * Geniest piece of simulator, made by Maarten and Jakob! :D * * For demo purposes! * * @param Offset * @return Smilie existence out of byte array */ private byte[] Smilie(int Offset){ byte[] b = new byte[1024]; // Should be 1024 due the smilie will be // drawed beneath the borders int Color; // Oog links Color = 250; b[((2 + Offset) * 16) + 3] = (byte)(Color); b[((2 + Offset) * 16) + 4] = (byte)(Color); b[((3 + Offset) * 16) + 3] = (byte)(Color); b[((3 + Offset) * 16) + 4] = (byte)(Color); // Oog rechts Color = 250; b[((2 + Offset) * 16) + 10] = (byte)(Color); b[((2 + Offset) * 16) + 11] = (byte)(Color); b[((3 + Offset) * 16) + 10] = (byte)(Color); b[((3 + Offset) * 16) + 11] = (byte)(Color); // Neus Color = 30; b[((4 + Offset) * 16) + 7] = (byte)(Color); b[((5 + Offset) * 16) + 7] = (byte)(Color); b[((6 + Offset) * 16) + 7] = (byte)(Color); b[((7 + Offset) * 16) + 7] = (byte)(Color); b[((8 + Offset) * 16) + 7] = (byte)(Color); b[((7 + Offset) * 16) + 6] = (byte)(Color); b[((7 + Offset) * 16) + 8] = (byte)(Color); b[((8 + Offset) * 16) + 6] = (byte)(Color); b[((8 + Offset) * 16) + 8] = (byte)(Color); // Mond Color = 210; b[((9 + Offset) * 16) + 2] = (byte)(Color); b[((9 + Offset) * 16) + 12] = (byte)(Color); b[((10 + Offset) * 16) + 2] = (byte)(Color); b[((10 + Offset) * 16) + 12] = (byte)(Color); b[((11 + Offset) * 16) + 3] = (byte)(Color); b[((11 + Offset) * 16) + 11] = (byte)(Color); b[((12 + Offset) * 16) + 4] = (byte)(Color); b[((12 + Offset) * 16) + 5] = (byte)(Color); b[((12 + Offset) * 16) + 6] = (byte)(Color);

27

b[((12 + Offset) * 16) + 7] = (byte)(Color); b[((12 + Offset) * 16) + 8] = (byte)(Color); b[((12 + Offset) * 16) + 9] = (byte)(Color); b[((12 + Offset) * 16) + 10] = (byte)(Color); b[(15 * 16) + 15] = 127; return b; } public Location getSensorLocation(Robot r, Sensor s){ double diam = Math.sqrt(Math.pow(s.getPosition().getX(), 2) + Math.pow(s.getPosition().getY(), 2)); double posX = r.getLocation().getX(); double posY = r.getLocation().getY(); posX += Math.cos(s.getAngle() + r.getRotation()) * diam; posY += Math.sin(s.getAngle() + r.getRotation()) * diam; return new Location(posX, posY); } public double handleSinglePixel(int pixel) { //int alpha = (pixel >> 24) & 0xff; int red = (pixel >> 16) & 0xff; int green = (pixel >> 8) & 0xff; int blue = (pixel) & 0xff; return (red + green + blue)/3; } } CalibrateBehavior /* * Created on Feb 14, 2006 * Copyright: (c) 2006 * Company: Dancing Bear Software * * @version $Revision: 1.1 $ * * The Calibratebehavior (dip=1) class sits on the base Behavior class * It keeps the servos to their neutral position * Reads the sensors and sets the status leds to * indicate which sensor is read * To ease testing it reacts only to close objects * */ package javaBot.JPB2; import com.muvium.apt.PeriodicTimer; /** * DOCUMENT ME! * * @version $Revision: 1.1 $ last changed Feb 14, 2006 */ public class CalibrateBehavior extends Behavior{ private boolean firstRun = true; private int[] dist = {0,0}; /** * Creates a new CalibrateBehavior object. * * @param initJoBot * TODO PARAM: DOCUMENT ME!

28

* @param initServiceTick * TODO PARAM: DOCUMENT ME! * @param servicePeriod * TODO PARAM: DOCUMENT ME! */ public CalibrateBehavior(JobotBaseController initJoBot, PeriodicTimer initServiceTick,int servicePeriod){ super(initJoBot, initServiceTick, servicePeriod); getJoBot().resetSensor(); } /** * Implements the behaviour. Can be considered as an infinite loop. */ public void doBehavior(){ dist[0] += getJoBot().getSensor(5); dist[1] += getJoBot().getSensor(6); System.out.print(dist[0]+","+dist[1]+" "); /* Code below is for real robot byte[] pixels; int i = 0; int j = 0; getJoBot().resetSensor(); // Reset the mouse sensor pixels = getJoBot().readPixels(); System.out.print("Pix="); for (i = 0; i < pixels.length; i++){ j = pixels[i]; if (i < 10){ System.out.print(j); // dump pixels on serial line System.out.print(","); } } System.out.print(" X="); System.out.print(getJoBot().mouse.getDX()); System.out.print(",Y="); System.out.print(getJoBot().mouse.getDY()); System.out.println(); if (pixels[0] >= 0){ // Show distance detected getJoBot().setStatusLeds(false, false, true); }else{ // Reset lamps if no input read getJoBot().setStatusLeds(false, false, false); } */ } } JobotBaseController /* * Created on Aug 13, 2004 * Controller for an OmniDirectional Robot Base * Provides the basic functionality for every joBot. * When creating a new application, make sure an instance * of this class is created, that the robot can inherit from. * Ver 0.5 - 07-09-2004 Modified wheel base * */ package javaBot.JPB2;

29

import javaBot.Debug; import javaBot.JPB2.ServoLinearizator; import com.muvium.apt.ADCReader; import com.muvium.apt.MultiServoController; import com.muvium.apt.PeripheralFactory; import com.muvium.driver.opticalMouse.Agilent2051; import com.muvium.io.PortIO; /** * Created on 20-02-2006 Copyright: (c) 2006 Company: Dancing Bear Software * * @version $Revision$ last changed 20-02-2006 * * TODO CLASS: DOCUMENT ME! */ public class JobotBaseController{ private static final byte ledRED = (byte)0x04; private static final byte ledYEL = (byte)0x05; private static final byte ledGRN = (byte)0x06; private static final byte ledBLU = (byte)0x07; ToneGenerator tonePlayer; MultiServoController servoDirect; int servoMax; int servoMid; ADCReader adc; Agilent2051 mouse; /** * Creates a new JobotBaseController object. * * @param factory * TODO PARAM: DOCUMENT ME! */ public JobotBaseController(PeripheralFactory factory){ servoDirect = factory .createMultiServoController(MultiServoController.IMPLEMENTATION_DIRECT); servoMax = servoDirect.getMaxPosition(); servoMid = servoMax >> 1; System.out.print("Servo="); System.out.println(servoMax); adc = factory.createADCReader(0, ADCReader.READ_INT); mouse = new Agilent2051(); tonePlayer = new ToneGenerator(factory); try{ servoDirect.start(); }catch (Exception e){ System.out.println("Failed!"); } } /** * TODO METHOD: DOCUMENT ME! */ public void heartBeat(){ PortIO.toggleOutputPin(ledRED, PortIO.PORTE);

30

} /** * TODO METHOD: DOCUMENT ME! * * @param red * TODO PARAM: param description * @param yel * TODO PARAM: param description * @param grn * TODO PARAM: param description */ public void setStatusLeds(boolean red, boolean yel, boolean grn){ PortIO.setOutputPin(red, ledRED, PortIO.PORTE); PortIO.setOutputPin(yel, ledYEL, PortIO.PORTE); PortIO.setOutputPin(grn, ledGRN, PortIO.PORTE); PortIO.setOutputPin(false, ledBLU, PortIO.PORTE); } /** * TODO METHOD: DOCUMENT ME! * * @param red * TODO PARAM: param description * @param yel * TODO PARAM: param description * @param grn * TODO PARAM: param description * @param blu * TODO PARAM: param description */ public void setStatusLeds(boolean red, boolean yel, boolean grn, boolean blu){ PortIO.setOutputPin(red, ledRED, PortIO.PORTE); PortIO.setOutputPin(yel, ledYEL, PortIO.PORTE); PortIO.setOutputPin(grn, ledGRN, PortIO.PORTE); PortIO.setOutputPin(blu, ledBLU, PortIO.PORTE); } /** * TODO METHOD: DOCUMENT ME! * * @param value * TODO PARAM: param description * @param servo * TODO PARAM: param description */ public void setServo(int value, int servo){ servoDirect.setPosition(value, servo); } /** * TODO METHOD: DOCUMENT ME! * * @param sensor * TODO PARAM: param description * * @return $returnType$ TODO RETURN: return description */ public int getSensor(int sensor){ adc.setChannel(sensor); int i = adc.getSample(); if (i == 1023){ i = 0; }

31

return i; } /* * Drive directly drives the servo's */ public void drive(int x, int y, int z){ servoDirect.setPosition(scaleToServoSpeed(x), 0); servoDirect.setPosition(scaleToServoSpeed(y), 1); servoDirect.setPosition(scaleToServoSpeed(z), 2); } /** * Checks the boundary's and makes sure the preconditions are met. * * @param val * Percentage between -100 to 100 * @return The non lineair speed of the servo motor */ public int scaleToServoSpeed(int val){ int value = val; if (val >= 100){ value = 99; } if (val <= -100){ value = -99; } int servoValue = ServoLinearizator.convertPowerToServoSpeed(value); int servoCalculated = servoValue * servoMid; int roundCorrection = 0; /* * Because the muvium controller cannot use doubles, the formula in the * return statement of this method, servoCalculated / 100 can result in * a double value, losing the rounding precision. To correct this, we * see if the servoCalculated value is a number with the last two digits > * 50. If it is, add 1 to the result. Do the opposite for negative * values. * * Examples: 167 ===> 67 is larger than 50 ==> result is 2 (167/100 + 1) * 410 ===> 10 is smaller than 50 ==> result is 4 (410/100) -310 ==> -10 * is larger than -50 ==> result is -3 (-310/100) -193 ==> -93 is * smaller than -50 => result is -2 (-193/100 - 1) */ if (servoValue > 0 && servoCalculated % 100 >= 50) roundCorrection = 1; else if (servoCalculated % 100 < -50) roundCorrection = -1; return (int)(((servoCalculated / 100) + servoMid) + roundCorrection); } /* * If vx=0 and vy=0, and omega=100 the robot will rotate counterclockwise at

32

* roughly its maximum speed. If vx=0 and vy=100 and omega=0, the robot will * go "north" at roughly its maximum speed. */ public void vectorDrive(int vx, int vy, int omega){ int bb = 72 * omega; int bx = 50 * vx; int by = 87 * vy; servoDirect.setPosition(scaleToServoSpeed(((-100 * vx) + bb) / 100), 0); servoDirect.setPosition(scaleToServoSpeed(((bx - by) + bb) / 100), 1); servoDirect.setPosition(scaleToServoSpeed(((bx + by) + bb) / 100), 2); } /** * TODO METHOD: DOCUMENT ME! * * @param toneId * TODO PARAM: param description */ public void tone(int toneId){ tonePlayer.playTone(toneId); } /** * Do a pixeldump. * * @return the pixeldump values */ public byte[] readPixels(){ byte[] pixels = new byte[256]; try{ mouse.readPixels(pixels); }catch (Exception e){ Debug.printError("An error occurred" + e.toString()); } return pixels; } /** * Reset the configuration register for the Agilent 2051. * */ public void resetSensor(){ mouse.writeReg(Agilent2051.A2051_CONFIG_BITS, 0x19); } } - end of file -