Profiel werkstuk JOHNNY 5
Profielwerkstuk door Albert Wieland en Friso Rietstra. Eerste begeleider: dhr.E.Kok Tweede begeleider: dhr. D.Swavingdijkstra
Datum: 10 december 2014
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
1
INHOUDSOPGAVE Samenvatting......................................................................................................................................4 Inleiding..............................................................................................................................................4 Onderzoeksvraag/eisen ......................................................................................................................5 Onze hoofdvraag: ...............................................................................................................................5 Deelvragen......................................................................................................................................5 Hypothese ......................................................................................................................................5 THEORIE .............................................................................................................................................6 Aandrijving......................................................................................................................................6 Servomotor7 ................................................................................................................................6 Stappen motor9 ...........................................................................................................................7 Hoe werkt het? ...........................................................................................................................7 Detecteren ......................................................................................................................................8 Sonar sensor11 .............................................................................................................................8 Computerplatform (chip) ................................................................................................................9 De Arduino Uno1 .........................................................................................................................9 De Arduino Motorshield R32 ........................................................................................................9 De intelligentie, programmering ................................................................................................... 10 De Taal C/C++10 ......................................................................................................................... 10 Variabelen in C en toekenning van waarden aan de variabele ................................................... 11 De Arduino program.12 .............................................................................................................. 15 Materiaal .......................................................................................................................................... 18 Arduino Uno.............................................................................................................................. 18 Arduino Motorshield R3. ........................................................................................................... 18 2x Aangepaste servomotoren.................................................................................................... 18 Standaard Servomotor .............................................................................................................. 18 2x Servomotor wielen ............................................................................................................... 18 Ultrasone sensor ....................................................................................................................... 18 Batterij doosje voor 4x AA batterijen ......................................................................................... 19 Vrij draaibaar wiel ..................................................................................................................... 19 4x Vaste weerstanden van 2,5 kOhm ......................................................................................... 19 Behuizing .................................................................................................................................. 19
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
2
Methode........................................................................................................................................... 20 Constructie ................................................................................................................................... 20 Elektronica .................................................................................................................................... 21 Modificatie van de servomotoren8 ............................................................................................ 21 Toepassing Motorshield ............................................................................................................ 22 De sensor11 ............................................................................................................................... 22 Voeding..................................................................................................................................... 23 Programmering ......................................................................................................................... 23 Aansturen van de gemodificeerde servomotor3......................................................................... 23 Omgeving detecteren................................................................................................................ 25 Algoritme om de voorwerpen te bepalen .................................................................................. 26 Multitasking .............................................................................................................................. 27 Resultaten ........................................................................................................................................ 28 RichtingscoĂŤfficiĂŤnt linker en de rechter motor ............................................................................. 28 De volledige code .......................................................................................................................... 29 Conclusie .......................................................................................................................................... 36 Discussie ........................................................................................................................................... 36 Meetfouten sensor ....................................................................................................................... 37 Toepassingen van robot ................................................................................................................ 37 Bronnenlijst ...................................................................................................................................... 38 Logboek ............................................................................................................................................ 39 Bijlagen............................................................................................................................................. 40 Bijlage 1, Het elektronisch schema Arduino UNO .......................................................................... 40 Bijlage 2, Het elektronisch schema Arduino Motorshield ............................................................... 41
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
3
SAMENVATTING Ons PWS gaat over robotica. Wij willen graag een robot maken maar weten nog niet precies hoe. We hebben gezocht naar chips, motoren, sensoren etc. Uiteindelijk hebben we gekozen voor een Arduino Uno met een motorshield als hart voor de robot. Voor de aandrijving hebben we gekozen voor 2 servomotoren die we aangepast hebben zodat ze continu door kunnnen draaien. Om zijn omgeving waar te kunnen nemen hebben we voor een ultrasone sensor gekozen die gebruik maakt van geluidsgolven om te kunnen ‘zien’. De sensor heeft maar een hele kleine kijkhoek, van 15°, dus hadden we nog een servomotor nodig om onze robot meer te kunnen laten zien. Als ‘lichaam’ voor onze robot hebben wij van plexiglas een behuizing gemaakt. De robot zal zelf moeten rijden dus we moesten ook een energiebron voor onze kleine vriend vinden. Albert vond een klein doosje waar 4 AA-batterijen in kunnen. In totaal zal dit een spanning van 6V leveren, dit is voldoende om de robot te laten werken.
INLEIDING Voor ons PWS maken wij een robot bouwen. Dit was omdat wij beiden zeer geïnteresseerd maar ook onervaren zijn in een robot maken. Dit past ook goed bij onze plannen voor een vervolg studie. Friso Rietstra zou graag in de computerscience willen studeren en Albert Wieland Nano-biologie. Robotica is een vrij breed onderwerp, het vereist verschillende disciplines zoals: programmering vaardigheden en natuurkundig inzicht. Wij laten onze robot autonoom werken. Dit vereist het gebruik van een sensor, want de robot moet een dynamische omgeving kunnen detecteren. Ook moeten we uitzoeken hoe we de robot het beste (vooruit) willen laten bewegen. We moeten iets hebben waarmee we via een computer opdrachten kunnen geven aan de robot en om de wielen aan te sturen. We kunnen niet een sensor boven op een motor lijmen dus zullen we ook een behuizing moeten maken, hier moet ook een geschikt materiaal voor gevonden worden. Voor inspiratie voor dit PWS zijn wij ook naar de Jaarbeurs Utrecht geweest. In oktober was daar vierdagen lang de beurs ‘”World of technology and science”. Daar hebben wij gekeken naar verschillende bedrijven die zich bezig houden met robotica. Het resultaat van deze dag was dat een beeld kregen van de mogelijke toepassing die er zijn.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
4
ONDERZOEKSVRAAG/EISEN Als je een computer wilt integreren in een dynamische omgeving, kan dat gauw heel ingewikkeld worden. Daarom bakenen wij onze robot af in een specifieke omgeving. Deze omgeving is een veld met een harde/gladde ondergrond. In deze omgeving staan grote blokken met hoeken van 90 graden. De blokken zijn ook van een hard materiaal (bijvoorbeeld hout, metaal, plastic). Daarnaast geven wij onze robot een simpel doel: beweeg in deze omgeving zonder te botsen tegen de blokken.
Figuur 1, Een schets van de omgeving. In deze omgeving staan alleen grote blokken met een hard oppervlak.
ONZE HOOFDVRAAG: Kunnen wij een autonome robot maken?
Deelvragen Wat wordt de vormgeving van de robot? Kunnen wij de robot vooruit bewegen? Kunnen wij de robot laten draaien? Kunnen wij de robot zijn omgeving detecteren? Hoe wordt de robot aangestuurd?
Hypothese Voor de robot hebben wij een aantal dingen nodig. Hij heeft in principe 2 motoren nodig, om vooruit te bewegen en om te draaien. Om de omgeving te detecteren hebben wij minimaal 1 sensor nodig. Wij hebben ook een programmeerbare chip nodig om zowel de motoren als de sensor aan te spreken.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
5
THEORIE Aandrijving Om de robot vooruit te laten bewegen zijn er motoren nodig om de wielen aan te drijven. Er is echter een verscheidenheid aan keuze voor de soorten motoren op de markt. Wij bespreken niet elke bestaande motor op de markt maar alleen de meest gebruikelijke voor ons PWS.
Servomotor7 Een servomotor is een kleine motor die op gelijkstroom werkt. De motor heeft een ingebouwde versnellingsbak en een positie feedback schakeling. Voor deze motor is geen externe besturing nodig. Omdat een servomotor klein is zijn ze goed te gebruiken bij modelbouw en robotica. Servomotoren draaien vaak in een hoek van ongeveer 90o tot ongeveer 180o. Hoewel er servomotoren zijn die 360o kunnen draaien, zijn ze niet in staat om continu door te blijven draaien, om dit te kunnen moet de servomotor aangepast worden. Doordat een servomotor heel exact is, zijn ze uitstekend te gebruiken voor bijvoorbeeld de arm van een robot of voor een sensor die rond moet worden gedraaid voor een grotere kijkhoek. Voor de koppeling van een servomotor aan bijvoorbeeld een arduinobord zijn er drie draden. Het zwarte bruine draadje gaat naar de aarde. Het rode draadje gaat naar de spanningsbron. Het gele, oranje of witte draadje is voor het signaal dat de servomotor krijgt om te gaan draaien. Wat in de servomotor zit ziet er redelijk simpel uit. Er zit een DC-motor in, ook wel een gelijkstroommotor. Om te bepalen in welke hoek de motor is gedraaid zit er een potentiometer in, deze geeft feedback door aan de stuurschakeling. De motor van de servomotor is door middel van tandwielen aan het controlewiel Figuur 2 Potentiometer vastgemaakt. Als de motor dan gaat draaien verandert de weerstand van de potentiometer en kan de stuurschakeling nauwkeurig waarnemen hoeveel beweging er in welke richting is. Als de schacht van de motor dan op de gewenste positie staat, zal de stroom die aan de motor wordt geleverd, worden afgesneden. Als dit niet het geval is, zal de motor in de juiste richting worden gedraaid. Om de positie die wordt gevraagd door te geven wordt er een signaal van elektrische pulsen doorgegeven via het signaaldraad naar de stuurschakeling. De snelheid van de draaiing wordt bepaald door het verschil in de huidige positie van de motor en de gewenste positie. Dus hoe verder motor van de gewenste positie is des te harder draait hij. Dit wordt ook wel ‘Proportional control’ genoemd. Een servomotor is dus ook heel efficiënt.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
6
Een servomotor wordt gestuurd door een elektrische puls van een variabele lengte naar de stuurschakeling te sturen, ook wel ‘Pulse Width Modulation’(PWM). Zo is er een maximum puls, een minimum puls en een herhalingsfrequentie. Normaal zou een servomotor 90o graden met de klok mee en 90o tegen de klok in kunnen draaien wat in totaal 180o is. De ‘neutraal’ positie van de motor is bepaald als de positie waar de motor dezelfde potentiële draaiing in beide richtingen heeft. De lengte die door de PWN gestuurd wordt geeft aan in welke richting de motor Figuur 3 Pulsbreedte met bijbehorende hoek van een servo gaat draaien. Bijv: zal een pulslengte van 1.5ms de motor naar 90o laten draaien, korter dan 1.5ms zal de motor naar 0o draaien en lager dan 1.5ms zal de motor naar 180o draaien.
Stappen motor9 Het principe van een stappenmotor is bijna hetzelfde als dat van een DC-motor. Het verschil is dat er in een stappenmotor veel spoelen zitten en in een DC-motor maar één. Men moet dus deze spoelen in een speciale volgorde activeren om rotatie van de motor te verkrijgen. Om rotatie te verkrijgen moet men dus een signaal van patronen naar de stappenmotor sturen. Zo’n signaal bestaat uit hoog en laag over meerdere regels, dit moet in een bepaalde volgorde en combinatie gepulst worden. Een nadeel van een stappenmotor kan zijn dat er een externe stappenmotorcontroller nodig is om de motor aan te sturen.
Figuur 4 De binnenkant van een stappenmotor
Hoe werkt het? Stroom door een spoel laten lopen creëert een elektromagnetisch veld met een noordpool en een zuidpool. De stator zal zich dan richten naar het veld van de spoel(en) waardoor het anker zal roteren. Het magnetisch veld kan veranderd worden door achtereenvolgens spoelen stroom te geven of ‘stappen’. Door meerdere spoelen tegelijk te ‘stappen’ blijft de stator tussen de geactiveerde spoelen in staan. Zo kunnen dus verschillende hoeken en rotatie gemaakt worden.
Figuur 5 Magnetisch veld door een spoel
Figuur 6 Rotatie door stappen van de spoelen
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
7
Detecteren Voor ons PWS moet de robot obstakels kunnen detecteren. De meest gebruikelijke detectie sensoren zijn: laser sensoren, inductieve nabijheidsensoren en ultrasone sensoren. Zowel bij de laser sensoren als de inductieve nabijheidsensoren moet de ontvanger geplaatst worden in de omgeving, ook zijn ze een stuk duurder dan ultrasone sensor. In dit geval maken wij gebruik van een sonar systeem.
Sonar sensor11 Het principe van een sonar is simpel. Er wordt een hoogfrequent geluid uitgezonden en gebaseerd op de tijd die het geluid er over doet om terug te kaatsen op een voorwerp wordt de waarneming gedaan. Dieren zoals de vleermuis gebruiken hetzelfde principe om hun omgeving waar te nemen en dolfijnen gebruiken hetzelfde om mee te jagen. De microcontroller vertelt de sonar om geluid uit te zenden, in de meeste gevallen is dit een toon die niet door het menselijk oor is waar te nemen, en neemt dan de terugkaatsing van het geluid weer. Na de waarneming stuurt de sonar meteen een voltage terug naar de microcontroller die ondertussen, door de tijd bij te houden, kan berekenen hoe groot de afstand is tot het waargenomen voorwerp.
Figuur 6 De sensor die wij hebben gebruikt
Figuur 7 Principe van een ultrasone sensor
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
8
Computerplatform (chip) De chip is het hart van de robot. De chip zorgt voor alle interne processen en signaal verwerking. De chip bestaat uit een circuit van verschillende componenten zoals voltage regulators, condensatoren, weerstanden, LED’s enz. De meest voorkomende kant en klare chips zijn Arduino en Raspberry Pi. Voor beide platforms heb je toegang tot open-source software, die je vrij kunt downloaden.
De Arduino Uno1 De Arduino Uno is een chip die gebruik maakt van de microcontroller ATmega328. Hij bevat onder andere 2 grond pinnen, één 5V pin een 14 digitale I/O pins, waarvan 6 gebruikt kunnen worden voor PWM. Het maximale geheugen van de UNO is 32 Kb. De Arduino IDE (Integrated development enviroment) kun je vrij downloaden. Dit programma bevat een aantal kant en klare library’s, waaronder de Servo.h library. Om een stuk programmatuur naar de UNO te uploaden, kun je de UNO met een USB kabel aan de computer verbinden. De stroom kun je via de USB-hub of via de powerjacket (zie afbeelding … ) leveren. De UNO werkt met een spanning tussen 6V en 20V. De optimale spanning voor de UNO is tussen de 7V en 12V (als je 5V wilt leveren). Zie bijlagen 1 voor het elektronisch schema van de Arduino UNO.
Figuur 8, De Arduino UNO vanuit bovenaanzicht.
De Arduino Motorshield R32 De Arduino Motorshield R3 is een externe boord die je kunt aansluiten aan de Arduino UNO. De Motorshield geeft de mogelijkheid de snelheid en de richting van een gelijkstroom motor gemakkelijk te bepalen. Ook biedt de Motorshield de mogelijkheid om meerdere motoren aan te sluiten en om de motors aan een gescheiden voedingsbron te sluiten. Aan de Motorshield zitten ook trinkets (zie afbeelding), dit is een speciaal slot, gemaakt om iets makkelijk aan te sluiten, zoals een servomotor. De trinkets zijn verbonden aan een aantal pinnen. Zo is er één pin verbonden aan de GND (grond) een andere aan de Digitale I/O pin 6 en de derde aan de 5V power pin. Zie in bijlage 2 voor het elektronisch schema van de Arduino Motorshield.
Figuur 9, De Arduino Motorshield R3 vanuit bovenaanzicht. De twee oranje ‘pluggen’ zijn de OUTPUT trinkets.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
9
De intelligentie, programmering De programmering van de Arduino gaat in C/C++.
De Taal C/C++10 De programmeertaal C is een imperatieve programmeertaal, en is een algemeen toepasbare taal speciaal ontwikkelt in 1972 door Brian Kernighan en Dennis M. Ritchie bij de Bell Telphone Laboraties om het UNIX operating system te ontwikkelen. C is de meest gebruikte computertaal. De invloed van C is zo groot dat de meeste nieuwe talen zoals C++, Objective-C, Java, JavaScript, C# en PHP grotendeels de syntaxis van C gebruiken. De taal C is procedureel, d.w.z. alle code is onderdeel van een functie. Het hoofdprogramma dat ‘main’ heet, is zelf ook een functie. Hieronder behandelen we summier de C syntax, we zullen alleen die onderdelen verklaren die we in ons project gebruiken. Voor een complete beschrijving van de taal C verwijzen we naar het boek van D.M Ritchie. Omdat het een taal is die in het Engels geschreven is, ontkomen we er niet om specifieke termen onvertaald te laten en geen Nederlandse term te bedenken. Tokens in C Een C programma bestaat uit verscheidene “tokens” en een token kan zowel een sleutelwoord, een identificator, een constante, een tekst of een symbool zijn. Een voorbeeld is de volgende C “statement”: printf(“Hello, world! \n”); Deze bestaat uit de volgende 5 tokens: printf ( “Hello, world! /n” ) ; Puntkomma’s In C program is de puntkomma een statement einde, d.w.z. elke afzonderlijke statement moet afgesloten worden met een puntkomma (;) Commentaar Commentaar om de code te verduidelijken starten we met ‘/*’ en eindigen we met ‘*/’ of we gebruiken de ‘//’. Hier is alle tekst na dit teken tot het einde van de regel commentaar. Identificatoren en sleutelwoorden Een C identificator is een naam om een variabele, functie of ieder ander item te identificeren. Het start met een letter of een underscore (_) gevolgd door letters of cijfers. In C bestaan ook gereserveerde woorden. Deze woorden mogen niet gebruikt worden als constanten of variabele of ieder ander item. Voorbeelden zijn: auto, break, if, else, default, while, do, end, return, struct etc.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
10
Datatypes De types in C kunnen we als volgt classificeren: 1) Basic typen, dit zijn rekenkundige typen en bestaan uit (a) integer type en (b) floating-point type. 2) Types om opsommingen te doen de z.g. “enumerated types� 3) De type void, geeft aan dat er geen waarde beschikbaar is. 4) Afgeleide typen, kunnen bestaan uit (a) Pointer type, (b) Array type, (c)Structure typen, (d)Function typen. Integer type Type
Storage size
Value range
char
1 byte
-128 to 127 or 0 to 255
unsigned char
1 byte
0 to 255
signed char
1 byte
-128 to 127
int
2 or 4 bytes
-32,768 to 32,767 or -2,147,483,648 to 2,147,483,647
unsigned int
2 or 4 bytes
0 to 65,535 or 0 to 4,294,967,295
short
2 bytes
-32,768 to 32,767
unsigned short
2 bytes
0 to 65,535
long
4 bytes
-2,147,483,648 to 2,147,483,647
unsigned long
4 bytes
0 to 4,294,967,295
Floating-point typen Type
Storage size
Value range
Precision
float
4 byte
1.2E-38 to 3.4E+38
6 decimal places
double
8 byte
2.3E-308 to 1.7E+308
15 decimal places
long double
10 byte
3.4E-4932 to 1.1E+4932
19 decimal places
Variabelen in C en toekenning van waarden aan de variabele Een variabele is niets meer dan een naam gegeven aan een stukje geheugen (memory) dat een programma kan manipuleren. Elke variabele in C heeft een specifiek type, het type bepaalt de grootte en de structuur van de variabele in het geheugen. Voorbeelden van variabelen zijn: 1) int i; // de variabele i is van het type integer 2) char ch; // ch is een variabele van het type char 3) int getal; getal = 20; // hier geven we een waarde aan de variabele getal.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
11
Operatoren C heeft de volgende typen operatoren: rekenkundige, relatie, logische, bitgewijs en toekennings operatoren. Rekenkundige operatoren Operator Description
Example
+
Adds two operands
A + B will give 30
-
Subtracts second operand from the first
A - B will give -10
*
Multiplies both operands
A * B will give 200
/
Divides numerator by de-numerator
B / A will give 2
%
Modulus Operator and remainder of after an integer division B % A will give 0
++
Increments operator increases integer value by one
A++ will give 11
--
Decrements operator decreases integer value by one
A-- will give 9
Relatie operatoren Operator Description
Example
==
Checks if the values of two operands are equal or not, if yes then condition becomes true.
(A == B) is not true.
!=
Checks if the values of two operands are equal or not, if values are not equal then condition becomes true.
(A != B) is true.
>
Checks if the value of left operand is greater than the value of right operand, if yes then condition becomes true.
(A > B) is not true.
<
Checks if the value of left operand is less than the value of right operand, if yes then condition becomes true.
(A < B) is true.
>=
Checks if the value of left operand is greater than or equal to the value of right operand, if yes then condition becomes true.
(A >= B) is not true.
<=
Checks if the value of left operand is less than or equal to the value of right operand, if yes then condition becomes true.
(A <= B) is true.
Logische (Boolean) Operatoren Operator Description
Example
&&
Called Logical AND operator. If both the operands are non-zero, then condition becomes true.
(A && B) is false.
||
Called Logical OR Operator. If any of the two operands is non-zero, then condition becomes true.
(A || B) is true.
!
Called Logical NOT Operator. Use to reverses the logical state of its operand. If a condition is true then Logical NOT operator will make false.
!(A && B) is true.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
12
Toekennings operatoren Operator Description
Example
=
Simple assignment operator, Assigns values from right side operands to left side operand
C=A+B will assign value of A + B into C
+=
Add AND assignment operator, It adds right operand to the left operand and assign the result to left operand
C += A is equivalent to C = C + A
-=
Subtract AND assignment operator, It subtracts right operand from the left operand and assign the result to left operand
C -= A is equivalent to C = C -
Het if statement en de switch statement In C hebben we beschikking tot meerdere besluitvormige structuren.
If ( boolean expressie) { statements; }
Figuur 10, schematische uitleg van een boolean statement.
switch( expression) { case constant-expression: case constant-expression: .. .. default : }
statements(s); break; statements(s); break;
statement(s);
.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
Figuur 11, schematische uitleg van een case statement.
13
Loops In C hebben we de volgende loop typen: Loop Type
Description
while loop
Repeats a statement or group of statements while a given condition is true. It tests the condition before executing the loop body.
for loop
Execute a sequence of statements multiple times and abbreviates the code that manages the loop variable.
do...while loop
Like a while statement, except that it tests the condition at the end of the loop body
nested loops
You can use one or more loop inside any another while, for or do..while loop.
Arrays Om een array in C te definiĂŤren moeten we het type en het aantal elementen opgeven. type arrayNaam[ array grootte]; Bijvoorbeeld: long afstand[20]; afstand[0] is het eerste element, afstand[19] is het laatste element. Pointers, NULL pointers en pointers naar functies en typedefs Een pointer in C is niets anders dan variabele waarvan de waarde het adres (van het geheugen) bevat waar de waarde van een ander variabele is opgeslagen. Een pointer geeft we aan met *. Voorbeelden: int *ip; // Dit is een pointer naar een integer. In C moeten we altijd een pointer initialiseren op NULL, anders veroorzaken we dat er naar een ongedefinieerde locatie wordt verwezen en we een ongedefinieerd gedrag krijgen. Een NULL-pointer is bij bepaalde operating systems de geheugen locatie 0. NULL betekent dus niets anders dan dat het naar NIETS verwijst. Dus altijd dit doen: Int *ptr = NULL; Net zoals verwijzing naar de locatie van een variabele n hebben we in C ook de mogelijkheid om te verwijzen naar de locatie van een functie. We krijgen dan een function- pointer. Voorbeeld: We definiĂŤren hier een functiepointer en verwijzen het naar NULL, het verwijzen naar NULL is niets anders dan verwijzen naar niets. void (*pFunc)(void) = NULL; In onze code definieren we het volgende type: typedef void (*FunctionPointer) (); Hier definieren we een nieuwe type, wat een functiepointer is naar een functie die geen input argumenten heeft en void afgeeft. En vervolgens maken we een array die deze nieuw gedefinieerde type bevatten:
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
14
FunctionPointer xActions[] = { functie1, functie2, â&#x20AC;Ś, functieN} De aanroep xActions[0]; roept de functie1 aan. De aanroep xActions[N]; roept de functieN aan. Als de functie1 t/m N niet gedefinieerd zijn moeten we de array initialiseren op NULL, dus: FunctionPointer xActions[5] = {NULL, NULL, NULL, NULL, NULL}; Structures Om een structure in C te definieren maken we gebruik van de struct statement: struct [structure tag] { member definition; member definition; ... member definition; } [one or more structure variables];
Array van structures In onze code maken we gebruik van array van structures: struct{ int hoek; // in graden -90 tot 90 in stappen van 2 graad. long afstand; // in cm } omgeving_map[91]; Dit is een array die 91 elementen van de structuren bevatten.
De Arduino program.12 Een programma in Arduino heet een SKETCH. De taal die ze gebruiken is niets anders dan onze oude vertrouwde C. Een SKETCH programma bestaat uit niets anders dan 2 Hoofdfuncties, deze moeten altijd aanwezig zijn n.l de setup() ende loop() functies: void setup() { initialisatie statements; } void loop() { loopstatments; }
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
15
De setup() functie wordt alleen eenmalig bij de start van het SKETCH programma aangeroepen. De loop() functie wordt doorlopend aangeroepen en dit gaat continu door. Hoe verhoudt zich dat tot onze bekende main() functie in C? Onder water wordt door de ontwikkelomgeving (de IDE) het volgende programma in C gemaakt: int main(void) { init(); setup(); onze setup functie in SKETCH for (;;){ loop(); } oneindige forloop waarbij telkens de functie loop() wordt aangesproken return 0; }
De Arduino IDE biedt een aantal standaard C bibliotheken. Dit zijn kant-en klare bibliotheken waarmee bepaalde dingen kunnen worden aangesproken. Een voorbeeld van een bibliotheek is de ‘WiFi Library’, die je mogelijkheid biedt om de Arduino aan het internet te verbinden met de functies begin(), disconnect(), localIP() en WifiServer() Voor het aansturen van een servomotor via de Arduino , is er een ‘Servo.h library’. Deze biedt de volgende functies met zich mee:3 attach(pin, min, max) De attach zorgt ervoor dat de variabele van de servomotor aangesloten wordt aan een digitale PWM pin. Pin staat voor de pin waaraan de servomotor wordt vastgemaakt. Met de min (optioneel) kun je de minimale puls breedte in microsecondes aangeven. De minimale puls breedte is evenredig aan de meest linkse hoek van de servomotor. De minimale puls breedte is standaard 544 ( 0-graden). Met de max (optioneel) kun je maximale de puls breedte in microsecondes aan geven. De maximale puls breedte is evenredig aan de meest rechtse hoek van de servomotor. De minimale puls breedte is standaard 2400 (180- graden).
write(in graden) In de write kun je de hoek geven die je de servomotor moet hebben. Dus als je de waarde 180 aangeeft gaat de servomotor naar 180 graden. Geef je de waarde 180 aan een volledig rotatie servomotor, gaat hij met volle snelheid in één richting. Geef je hem de waarde 0 gaat hij met volle snelheid in de andere richting, en als je hem de waarde 90 geeft staat hij stil. writeMicroseconds(in microsecondes) De writeMicrosecondes is bijna hetzelfde als de write() functies. Het verschil is dat bij writeMicrosecondes() het argument in microsecondes is en niet in graden. Geef je het 1000 dan gaat de standaard servomotor uiterst links, geef je het 2000 gaat hij uiterst rechts. Bij 1500 zal de servomotor in het midden staan. detach()
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
16
Met deze functie kun je de variabele van de servomotor afkoppelen van de Arduino.
Naast de ’Servo.h library’ wordt er ook gebruik gemaakt van de bibliotheek NewPing.h. De ‘NewPing library’ heeft de functies sonar.ping_median( ) en de sonar.convert_cm().4 Sonar.ping_median(aantal keer herhalingen) De Sonar.ping_median() is opgebouwd uit een aantal andere functies. Om te begrijpen hoe de Sonar.ping_median() werkt, leggen eerst het aansturen van een sonar sensor uit. Eerst worden de variabelen gedefinieerd. long getDistance(){ long duration = 0;
Daarna moet wordt er aangegeven welke pin er gebruikt moet worden als de signaal output(de Trigger pin van de sensor). pinMode(PIN_TRIGGER, OUTPUT);
Dan zendt de trigger van de sensor 1 puls die 2ms een LOW signaal heeft en daarna 10ms HIGH signaal. digitalWrite( PIN_TRIGGER, LOW); delayMicroseconds(2); digitalWrite( PIN_TRIGGER, HIGH); delayMicroseconds(10);
De puls verzonden door de trigger pin moet worden ontvangen door de echo pin. Hier wordt aangegeven welke pin gebruikt moet worden als echo. pinMode(PIN_ECHO, INPUT);
Nadat de puls verzendt is, meet de echo van de sensor de tijd die puls nodig heeft om te worden ontvangen. duration = pulseIn( PIN_ECHO, HIGH);
De Sonar.ping_median() heeft deze functies inbegrepen. Daarnaast kan deze functie meerdere pulsen uitvoeren en daar het gemiddelde van berekenen. Het voordeel hiervan is dat de eventuele verkeerde meetresultaten ‘’verworpen’’ worden. Het argument van de functie geeft aan hoeveel je pulsen de sensor wilt laten maken. Sonar.convert_cm() rekent de door de echo bepaalde tijd om in cm met de formule .
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
17
MATERIAAL Niet al het materiaal dat wij gebruikt hebben, is zelfgemaakt. De elektronische componenten van onze robot hebben wij gekocht op het internet. De dingen die we zelf konden maken, hebben wij zoveel mogelijk zelf gemaakt. Arduino Uno De Arduino is een opensource computer platform. Dat betekent dat er vrije toegang tot de bronmaterialen is. Dit geeft onafhankelijke ontwikkelaars of ontwerpers de vrijheid om zelf te bepalen hoe zij het platform willen gebruiken. De Arduino is gemakkelijk in gebruik en heeft veel te bieden voor een redelijke prijs.
Arduino Motorshield R3. De Arduino motorshield gebruiken wij om de motoren aan te sluiten aan de Arduino.
2x Aangepaste servomotoren Voor de aandrijving kozen we voor servomotoren. Servomotoren zijn relatief goedkoop en gemakkelijk in gebruik. Het enige nadeel van een standaard servomotor is dat hij maar 180 graden kan roteren. Om deze te gebruiken voor de aandrijving moesten wij handmatig de servomotor aanpassen.
Standaard Servomotor Deze motor gebruiken wij om de ultrasone sensor 180 graden te laten draaien.
2x Servomotor wielen Speciale wielen die je direct aan de servomotor kunt aan sluiten. De diameter van deze wielen zijn 66mm.
Ultrasone sensor
Figuur 12, De servomotorwielen met diameter van 66mm. Deze wielen zijn speciaal gemaakt voor een servomotor.
Voor het detecteren van de omgeving is een ultrasone sensor beste oplossing. De sensor zendt een (hoog) golf uit en ontvangt de golf op basis van de omgeving terug. De sensor die wij gebruiken, was de goedkoopste ultrasone sensor op de markt. Het heeft een bereik van 2 tot 300 cm en een hoek van 15 graden.
Figuur 13, Ultrasone sensor vastgezet met lego techniek. De oranje kabel is +5V, de rode is de Trigger, de bruine is Echo en de zwarte is GND.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
18
Batterij doosje voor 4x AA batterijen Een batterij doosje waar 4 AA batterijen in kunnen. Het doosje kan maximaal een spanning leveren van 6,0 V. Dit moet voldoende zijn om de robot te laten werken.
Vrij draaibaar wiel Dit wiel is nodig om de robot in balans te houden.
Figuur 14, Batterij doosje met 4 AAbatterijen. Het batterij doosje is aan een 2.1 mm positive centered jack.
4x Vaste weerstanden van 2,5 kOhm De vaste weerstanden zijn nodig om de servomotor aan te passen.
Behuizing De derde versie van de behuizing van de robot is gemaakt van plexiglas. Om de servomotoren en de Arduinobord aan de behuizing vast te maken, hebben wij precies passende moeren en bouten gebruikt. Om de ultrasone sensor vast te zetten, hebben wij lego blokken gebruikt.
Figuur 15, Behuizing met daaraan de twee aangepaste servomotoren aan de zijkanten. In het midden zit de derde servomotor. Het gaatje links is gemaakt voor de servokabeltjes.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
19
METHODE De robot heeft een aantal acties. De eerste actie is vooruit rijden. Terwijl hij vooruit rijdt, zendt hij geluidsgolven uit. Als deze geluidsgolven tegen een object botsen (hierin nemen wij aan dat het object loodrecht op de robot staan) dan worden de geluidsgolven weerkaatst en vangt de ontvanger de geluidsgolf weer op. Je kunt de afstand bepalen tot een object door de snelheid maal de tijd te doen. De afstand die gemeten wordt moet gedeeld worden door 2, want je meet zowel de tijd heengaand als teruggaand. Hieruit volgt dat
.
Als de robot een afstand meet kleiner dan 8cm, dan volgt de 2e actie. Bij de 2e actie zijn de servomotoren uit en gaat de 3e servomotor, die bevestigd is aan de sensor, draaien. Terwijl de servomotor 180o draait, zendt de sensor een aantal sonar pings uit. Uit deze pings laten wij de robot een map van de omgeving maken. Dan wordt de optimale ook met een algoritme. Als de optimale hoek bepaald is, draait de robot door ĂŠĂŠn van de twee servomotoren naar achteren te draaien. Vervolgens zijn we bij het begin af en gaat de robot weer vooruit. Figuur 16, Robot met alle componenten eraan.
Constructie Voor de constructie is er eerst een schets gemaakt (zie afbeelding ). Het idee achter de constructie is doelgericht. Zo klein en compact mogelijk. De robot moet wel stabiel en sterk genoeg zijn. Met de schets wordt er een handgemaakt kastje gebouwd (zie afbeelding)
Figuur 17
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
20
Elektronica Modificatie van de servomotoren8 Om de servomotor volledig te laten roteren, moet de potentiometer verwijderd worden. De potentiometer is een variabele weerstand, (zie afbeelding). De potentiometer kan maar van 0 tot 180 graden draaien, zodoende (dus bij elke graad hoger of lager) verandert de weerstand ( in ons geval van 0 tot 5 Kâ&#x201E;Ś).
Figuur 19, Schema van de servomotor met de potentie meter.
Figuur 18, Potentiemeter met het bereik in Ohm.
De potentiometer zorgt ervoor dat als de aangegeven positie bereikt is, de motor geen stroom meer ontvangt en stopt. De potentiemeter is aangesloten aan het hoofdtandwiel van de servomotor, wat er voor zorgt dat de servomotor maar 180 graden kan draaien. Om de servomotor volledig te laten roteren, moet de potmeter verwijderd worden. Dit zorgt ervoor dat de servomotor nooit zijn doel behaalt en altijd blijft draaien. Om te vermijden dat er andere problemen ontstaan, wordt de potmeter vervangen door 2 gelijke vaste weerstanden van 2,5kOhm.
Figuur 20, Schema van de vervanging van de potentiemeter van de servomotor.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
21
Toepassing Motorshield De motorshield R3 kun je aansluiten aan de Arduino UNO. De Motorshield heeft beschikking over speciale trinkets, waar je servomotoren op kunt aansluiten. Zie afbeelding. Dit zijn de Orange pluggen op het board. Om de kabel van de servomotor aan te sluiten aan de trinket, moesten wij de rode (+) en het gele (signaal) kabeltjes omwisselen. (voeg foto van de omwisseling in).
Figuur 22, De twee OUTPUT trinkets van de Arduino Motorshield R3.
Figuur 21, De kabelplug van de servomotoren, oranje is signaal, rood is +5V en zwart is GND.
De sensor11 De Ultrasone sensor die wij gebruiken heeft een gezichtsveld van 15o. De robot moet de omgeving vaststellen, daarom wordt de sensor gemonteerd aan de derde servomotor. Deze servomotor is niet aangepast en kan alleen maar van 0 tot 180 graden draaien. De sensor kan in een bepaalde frequentie een geluidssignaal versturen en ontvangen. Omdat wij onze omgeving vastgesteld hebben, wordt de kans op â&#x20AC;&#x2DC;ghost echoâ&#x20AC;&#x2122; (zie figuur 25) zo veel mogelijk verminderd. De snelheid van de servomotor, waaraan de sensor is vast gemaakt, mag niet sneller zijn dan de tijd die de echo nodig heeft om te worden ontvangen. Als dit wel het geval is, kan de ontvanger geen echo meten omdat de ontvanger al van positie veranderd is. Zie figuur 24.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
22
Figuur 24, Situatie schets van ghost echo.
Figuur 23, Probleemschets van de situatie als de motor sneller draait dan de echo nodig heeft om terug te komen.
Om de minimale tijd uit te rekenen, die de servomotor moet wachten om een graad te draaien, is:
Hierin is de maximale afstand 3 meter, snelheid van het geluid 343 m/s bij 20째C. Dus de minimale tijd waarin de servomotor 1 positie vast moet houden is 17,5 ms.
Voeding De robot krijgt zijn energie door AA-batterijen. De batterijen zitten in een doosje waarin 4 batterijen passen en waarin ze in serie zijn geschakeld. Zo leveren 4 batterijen van 1.5V de benodigde hoeveelheid van 6V. Het doosje hebben we met de plus- en minpool aan een 2.1 mm center-positive stekker vastgemaakt die in de voedingsjack van de Arduino past.
Programmering Het eerste probleem voor de programmering is het aansturen van de aangepaste servomotoren. Het tweede probleem is het detecteren van de omgeving. Het derde probleem is het gelijktijdig uitvoeren van verschillende functies (multitasking).
Aansturen van de gemodificeerde servomotor3 Om de robot vooruit te laten bewegen moet de linkse motor linksom draaien en de rechtse motor rechtsom. In code: void moveForward(){ servoLeft.write(90); servoRight.write( -90); }
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
23
Voor een rotatie linksom laten wij de linkse motor met de klok meedraaien en voor een rotatie rechtsom laten wij de rechtse motor tegen de klok in draaien. Doordat de aangepaste servomotoren alleen een maximale snelheid kunnen hebben, moet experimenteel bepaald worden hoe lang de servomotor moeten draaien om de gewenste hoek te krijgen. Hetzelfde principe wordt gebruikt voor een rotatie rechtsom. De resultaten worden verwerkt in grafieken. In code: void leftMotorRotate() { servoLeft.write(-90); delay (tijd); } void rightMotorRotate() { servoLeft.write(90); delay (tijd); }
Figuur 25, Experimentele bepaald van de draaihoek van de robot.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
24
Omgeving detecteren Om de omgeving digitaal op te slaan, maken we gebruik van 2 buffers (array) van C–structuren. struct{ int hoek; // in graden -90 tot 90 in stappen van 2 graden long afstand; // in cm } omgeving_map[181]; // i = 90 is 0 graad // i = 0 is +90 graad // i = 180 is -90 graad
Bovenstaande structuur gebruiken we om per hoek de afstand op te slaan die de sensor meet. Omgevings_map[i], bevat een hoek en een afstand. Bijvoorbeeld, voor i = 0, is de hoek= +90 graden en afstand= de gemeten afstand. Wat wij doen: voor elke hoek die de servomotor draait, wordt er een afstand gemeten met de sensor. Om de optimale hoek te bepalen, definieert de robot objecten. In de afbeelding hieronder zie je een situatie waarin de robot tussen 3 blokken bevindt. De robot definieert elk object door de meest rechtse hoek te bepalen en de meest linkse hoek.
Figuur 26, Situatie schets van een omgeving hoe de robot een omgeving zal detecten. struct{ int lhoek; int rhoek; long afstand; } Voorwerp[20];
Een voorbeeld van hierboven beschreven situatie. Object[0] = 0 (hoek links), 15 (hoek rechts), 200 (gemiddelde afstand tot de hoek in cm) Object[1] = 15, 30, ∞ Object[2] = 30, 120, 8 Object[3] = 120, 160, ∞ Object[4] = 120, 180, 20
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
25
Algoritme om de voorwerpen te bepalen De robot moet kunnen bepalen waar objecten beginnen en eindigen. Dit doet de robot met behulp van de omgeving map en een algoritme. In het algoritme worden er twee parameters, i en j, gebruikt. De i is de index van het begin van een gevonden voorwerp. De j is de index van het begin van het volgende voorwerp. Als de map van de omgeving gevuld is met waarden, krijgen i en j beide nul als hun begin waarden. Hierbij krijgt het eerste voorwerp altijd een rechtse hoek van 0째. Vervolgens wordt j vergeleken met i. Als het verschil groter is dan een bepaalde variatie, betekent dat dat i het eind van zijn voorwerp heeft gevonden. Nu is de rechtse en de linkse hoek van het eerste voorwerp bekend. Het volgende voorwerp begint nu bij j, dus wordt i gelijk gesteld aan j. Is het verschil tussen i en j niet groter dan een bepaalde variatie dan wordt j met 1 verhoogd. Als we het eind van de buffer hebben bereikt, is dat ook het eind van het laatste voorwerp. 0 i=0 v=0
44 i=v1
45 j i=v
8 9
void calcVoorwerpen(long variatie){ int i,v; // v is index van de gevonden objecten, kan max 20 objecten bevatten 0 -19 // We beginnen met i = 0, dit is de meest rechtse hoek van de eerste object i = 0; v = 0 ; long afstand1, afstand2; Voorwerp[v].rhoek = omgeving_map[i].hoek; afstand1 = omgeving_map[i].afstand; while( i<90){ if( i+1 == 90){ // We hebben de uiterste linkse hoek van de laatste object. Voorwerp[v].lhoek = omgeving_map[i+1].hoek; afstand2 = omgeving_map[i+1].afstand; // Bepaal hier de gemiddelde afstand Voorwerp[v].afstand = (afstand1 + afstand2)/2; break; } if(abs( omgeving_map[i].afstand - omgeving_map[i+1].afstand ) > variatie){ // We hebben een jump // linkerhoek huidig object = i // rechterhoek volgende object = i+1 Voorwerp[v].lhoek = omgeving_map[i].hoek; afstand2 = omgeving_map[i].afstand; // Bepaal hier de gemiddelde afstand Voorwerp[v].afstand = (afstand1 + afstand2)/2; v = v +1 ; Voorwerp[v].rhoek = omgeving_map[i+1].hoek; } i = i +1 ; afstand1 = omgeving_map[i].afstand; } }
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
26
Multitasking Sommige functies moeten gelijktijdig gebeuren. Omdat het Arduino operating system geen gebruik maakt van multitasking, zouden we een aparte operating system (RTOS) moeten gebruiken om gebruik te maken van multitasking. Dit gebruiken we niet. Wij maken gebruik van quasi-multitasking. In de loopfunctie van de Arduino worden zoveel mogelijk geen delay’s gebruikt. Het sequentieel uitvoeren van de functies lijkt dan alsof het multitasking is. Hiervoor gebruiken we de functie-pointer in C. In de functie-pointer definiëren we de acties die uitgevoerd moeten worden. In onderstaand voorbeeld is de loopActionA tot aan loopActionI (in de echt source code gaan de functies anders heten). Vervolgens wordt er een actionFlag gedefineerd. Een nul betekent dat de actie niet uitgevoerd mag worden (disabled worden), een 1 betekent dat de actie uitgevoerd wordt in de loop. Met de functie xActionTrigger kunnen we de desbetreffende acties in de loop aan-of uitzetten. In de setup() geven we aan welke acties als eerste éénmalig worden uitgevoerd. En in de loop hoeven we alleen maar xDoAction aan te roepen. Deze zal door een array van functie pointers lopen, en als hij een actie vindt die uitgevoerd mag worden, gaat hij deze uitvoeren.
// Defineer eerste de een functie pointer en intitialiseer het naar NULL. typedef void (*FunctionPointer) (); // Defineer hier de acties in de loop. FunctionPointer xActions[] = {loopActionA,loopActionB,loopActionC ,loopActionD,loopActionE,loopActionF ,loopActionG,loopActionH,loopActionI}; // Defineer hier de actie status flags. Actie status 1 betekent dat hij uitgevoerd mag worden, // 0 betekent dat hij niet uitgevoerd mag worden. int xActionsFlags[] = {0,0,0,0,0,0,0,0,0}; int xActionsCount = sizeof(xActions); void xActionTrigger(int id=0, int action=0) { // De id presenteerd zijn posititie in de flags array voor . xActionsFlags[id] = action; }
// Voer alle loop functies uit. void xDoActions() { // Voer alel geloopde functies uit. for(unsigned int j=0; j < xActionsCount; j++) { if( xActionsFlags[j] == 1 ) { // Voer actie uit als, xActions[j](); // Benoem de gerelateerde loop actie. } } } void setup() { xActionTrigger(0,1); // Eerste actie. xActionTrigger(2,1); // Derde actie. } void loop() { xDoActions(); }
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
27
RESULTATEN Richtingscoëfficiënt linker en de rechter motor Voor elke 100ms hebben wij de hoek die de robot maakt bepaald. De resultaten uit de bijlage van de rotatie linksom en rechtsom zijn geëxtrapoleerd en verwerkt in de grafieken 1 en 2. void leftMotorRotate() { servoLeft.write(0); delay (tijd);
Rotatie robot linksom (graden)
}
120 100
Rc (Servomotor links) = 7,7212 ᵒ/100ms
80 Servomotor Links
60
Linear (Servomotor Links)
40 20 0 100 200 300 400 500 600 700 800 900 1000 Tijd (ms)
Grafiek 1, De rotatie van de robot in graden door de linker servomotor uitgezet tegen de tijd in milliseconden.
Rotatie robot rechtsom (graden)
120
Rc (Servomotor rechts) = 7,6545ᵒ/100ms
100 80 60
Servomotor Rechts
40
Linear (Servomotor Rechts)
20 0 100 200 300 400 500 600 700 800 9001000 Tijd (ms)
Grafiek 2, De rotatie van de robot in graden door de rechter servomotor uitgezet tegen de tijd in milliseconden.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
28
De volledige code De volledige code zal ondersteund worden met commentaar ter verduidelijking van de verschillende functies en processen die worden uitgevoerd. // Auteurs: Albert Wieland en Friso Rietstra. // Datum: 21-11-2014. #include #include #include #include bron 5
<Servo.h> <stdio.h> //Deze library wordt gebruikt voor de functie sprintf(),zie bron 6 <NewPing.h> <math.h> //Deze library wordt gebruikt voor de wiskunde functie abs() en round(, zie
//===========CONSTANTEN en GLOBALE VARIABELEN===================== // aandrijf pinnen const int PIN_LEFTSERVO=6; const int PIN_RIGHTSERVO=5; const int ZERO_LEFTSERVO=92; // experimenteel bepaald const int ZERO_RIGHTSERVO=95; // experimenteel bepaald // sensor const int const int const int const int
pinnen PIN_TRIGGER=12; PIN_ECHO=11; PIN_SENSOR_SERVO = 9; MAX_DISTANCE = 300; // maximale afstand die de sonar kan detecteren
// Volgende constanten zijn experimenteel bepaald. const long VARIATIE = 5; // in (cm) const long HOEKVAR = 15; // in (graden) const float RC_LEFT = 7.7212; // graden per 100 msec const float OFFSET_LEFT = 8.53; // graden const float RC_RIGHT = 7.6545; // graden per 100 msec const float OFFSET_RIGHT = 8.60; // graden const int STOP_AFSTAND= 8; // in (cm) //===========status robot======================================= enum eStatus{STOP, MOVING_FORWARDS, ROTATE, DETECTING_ANGLE,MOVING_BACKWARDS}; eStatus status=STOP; //==========STRUCTURES========================================== // map omgeving // i = 90 is 0 graad // i = 0 is +90 graad // i = 180 is -90 graad struct{ int hoek; // in graden -90 tot 90 in stappen van 2 graad. long afstand; // in cm } omgeving_map[91]; // Hier worden de voorwerpen opgeslagen // die de swap sensor gevonden heeft. // Er kunnen maximaal 20 objecten opgeslagen worden. // Een voorwerp met een afstand < 0 is ongeldig struct{ int lhoek; int rhoek; long afstand; } Voorwerp[20]; int huidigAfstand=0; //==========De servo objecten en het sonar object================== Servo servoLeft; Servo servoRight; Servo sensorServo; NewPing sonar(PIN_TRIGGER,PIN_ECHO,MAX_DISTANCE); // Definieer een nieuwe type van het type function pointer. // die geen input paramaters en void als return geeft. typedef void (*FunctionPointer) (); // Declare looping actions function names, declared lower.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
29
FunctionPointer xActions[] = {loopStop,loopPingForwards ,loopFindNextAngle,loopForward}; // Define actions status flags. Set to 1 to auto execute a start. int xActionsFlags[] = {0,0,0,0}; int xActionsCount = sizeof(xActions); void xActionTrigger(int id=0, int action=0) { // The id represent it's position in the flags array. // Action 1 = executed, 0 not. xActionsFlags[id] = action; } //====Hier moeten de LOOP FUNCTIES gedefinieerd worden========== // Let op in de functies die gelijktijding (realtime) // uitgevoerd moeten worden, mogen geen delay() voorkomen // Dit geldt dus niet als de status = STOP. //============================================================== //---------------------------------------------------------------// Enable loopStop() // Zet richting sensor naar voren (90 graden) // Doe een Ping(0 graden) om de forwardbeweging te accorderen // ALS "huidigAfstand" > ZOEK_AFSTAND // DAN DO Geef dan opdracht "vooruit" // zet status=MOVING_FORWARDS // Disable loopForward // enable loopStop // enable loopPingForwards // ENDDO //---------------------------------------------------------------void loopForward() { if( status != MOVING_FORWARDS){ // Richt sensor naar voren sensorServo.attach(PIN_SENSOR_SERVO); sensorServo.write(90); // 90 is de midden positie delay(50); // wacht 50 ms tot positie bereikt is. sensorServo.detach(); huidigAfstand = getDistance(); if( huidigAfstand > STOP_AFSTAND){ // We mogen vooruit moveForward(); status = MOVING_FORWARDS; xActionTrigger(1,1); // Enable loopStop xActionTrigger(0,1); // Enable loopPingForwards xActionTrigger(2,0); // Disable loopFindNextAngle xActionTrigger(3,0); // Disable loopForward } } } //-----------------------------------------------------------// ALS status == MOVING_FORWARDS // DAN DO ALS huidigAfstand < STOP_AFSTAND // DAN DO stoppen // zet status = STOP // disable loopForwards // disable loopPingForwards // zet status = DETECTING_ANGLE // enable loopFindNextAngle // ENDDO // ENDDO //-----------------------------------------------------------void loopStop() { if( status == MOVING_FORWARDS){ if( huidigAfstand <= STOP_AFSTAND){ // stop afstand is bereikt, stop de beweging status = STOP; servoLeft.write(ZERO_LEFTSERVO + 0); servoRight.write(ZERO_RIGHTSERVO + 0); servoLeft.detach(); servoRight.detach(); xActionTrigger(1,0); // Disable loopStop xActionTrigger(0,0); // Disable loopPingForwards xActionTrigger(2,1); // Enable loopFindNextAngle xActionTrigger(3,0); // Disable loopForward
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
30
} } } //------------------------------------------------------------// ALS status == STOP // DAN DO reset de diverse arrays // scan de omgeving // bepaal de objecten // vindt de meest geschikte hoek // Draai de robot // enable loopForwards // enable loopPingForwards // enable loopStop // disable loopFindNextAngle // ENDDO //------------------------------------------------------------void loopFindNextAngle(){ int nextRichting; if( status == STOP){ status = DETECTING_ANGLE; resetOmgevingMap(); resetVoorwerpen(); swapOmgeving(); calcVoorwerpen(VARIATIE); nextRichting = findNextHoek(); status = ROTATE; if( nextRichting > 0){ // Draai robot naar rechts robotRotateRight( abs(nextRichting)); } else { // Draai de robot naar links robotRotateLeft( abs( nextRichting)); } // Rotatie is afgelopen status = STOP; xActionTrigger(1,1); // Enable loopStop xActionTrigger(0,1); // Enable loopPingForwards xActionTrigger(2,0); // Disable loopFindNextAngle xActionTrigger(3,1); // Enable loopForward } } //-----------------------------------------------------------// Doe een ping om de afstand te bepalen. // Bepaal de afstand // Zet huidigAfstand = afstand //-----------------------------------------------------------void loopPingForwards(){ if( status == MOVING_FORWARDS){ huidigAfstand = getDistance(); } } //=======EINDE LOOP FUNCTIES==================================== //----------------------------------------------------------// Voer alleen die functies uit die toegestaan is ("enable"). //----------------------------------------------------------void xDoActions() { // Voer de loop functies achter elkaar uit.. for(unsigned int j=0; j < xActionsCount; j++) { if( xActionsFlags[j] == 1 ) { // Als de flag 1 is, voer de actie uit xActions[j](); // Roep de loopFunctie aan } } } //----------------------------------------------------------// We beginnen met loopStop, loopPingForwards en loopForwards // toestaan. En dus de status op MOVING_FORWARDS zetten //----------------------------------------------------------void setup() { status = MOVING_FORWARDS; xActionTrigger(1,1); // Enable loopStop
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
31
xActionTrigger(0,1); // Enable loopPingForwards xActionTrigger(2,0); // Disable loopFindNextAngle xActionTrigger(3,1); // Enable loopForward } //----------------------------------------------------------// De Arduino loop functie. // Er wordt elke keer gekeken welke functiepointer we moeten // aanspreken, en dan worden ze ook aangesproken. //----------------------------------------------------------void loop() { xDoActions(); } //=======HULP FUNCTIES======================================== /*----------------------------------------------------moveForward() robot gaat met MAX snelheid naar voren parameter: none linkerServo gaat tegen de wijzers van de klok draaien rechterServo gaat met de wijzers van de klok draaien -----------------------------------------------------*/ void moveForward(){ // ALS status <> MOVING_FORWARDS // DAN DO linkerServo gaat tegen de wijzers in draaien MAX en continu // rechterServo gaat met de wijzers mee draaien MAX en continu // ENDDO if( status != MOVING_FORWARDS){ leftMotorRotate( 90, 0); rightMotorRotate( -90, 0); status = MOVING_FORWARDS; } } /*----------------------------------------------------moveBackward() robot gaat met MAX snelheid naar achteren parameter: none linkerServo gaat met de wijzers van de klok draaien rechterServo gaat tegen de wijzers van de klok draaien -----------------------------------------------------*/ void moveBackward(){ // ALS status <> MOVING_BACKWARDS // DAN DO linkerServo gaat met de wijzers in draaien MAX en continu // rechterServo gaat tegen de wijzers mee draaien MAX en continu // ENDDO if( status != MOVING_BACKWARDS){ status = MOVING_BACKWARDS; leftMotorRotate( -90, 0); rightMotorRotate( 90, 0); } } /*-------------------------------------------------------Om de robot naar links te draaien laten we de rechterwiel stilstaan en draaien de linkerwiel met de wijzers van de klok mee. Hierdoor kunnen we precies bepalen hoeveel graden de robot draaid. De berekening om de linkermoter aan te sturen is: aantal 100 ms = (gewenste hoek - OFFSET_LEFT)/ RC_LEFT --------------------------------------------------------*/ void robotRotateLeft( int graad){ int duration; duration = (int) round((graad - OFFSET_LEFT)*100/RC_LEFT); leftMotorRotate( -90, duration); } /*-------------------------------------------------------Om de robot naar rechts te draaien laten we de linkerwiel stilstaan en draaien de rechterwiel tegen de wijzers van de klok mee. Hierdoor kunnen we precies bepalen hoeveel graden de robot draaid. De berekening om de rechtermoter aan te sturen is: aantal 100 ms = (gewenste hoek - OFFSET_RIGHT)/ RC_RIGHT --------------------------------------------------------*/ void robotRotateRight( int graad){ int duration;
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
32
duration = (int) round((graad - OFFSET_RIGHT)*100/RC_RIGHT); rightMotorRotate( 90, duration); } /*----------------------------------------------------leftMotorRotate(), left servo gaat draaien parameter: velocity < 0 servo gaat links draaien velocity > 0 servo gaat rechts draaien zie verder tabel voor de waarden duration < 0, er gebeurt niets duration = 0 servo blijft draaien duration > 0 tijd dat servo draaid in ms ----------------------------------------------------*/ void leftMotorRotate( int velocity, int duration) { if( duration >= 0){ servoLeft.attach(PIN_LEFTSERVO); servoLeft.write(ZERO_LEFTSERVO + velocity); if( duration != 0){ delay (duration); servoLeft.detach(); } } } /*----------------------------------------------------rightMotorRotate(), rightservo gaat draaien parameter: velocity < 0 servo gaat links draaien velocity > 0 servo gaat rechts draaien zie verder tabel voor de waarden duration < 0, er gebeurt niets duration = 0 servo blijft draaien duration > 0 tijd dat servo draaid in ms ----------------------------------------------------*/ void rightMotorRotate( int velocity, int duration) { if( duration >= 0){ servoRight.attach(PIN_RIGHTSERVO); servoRight.write(ZERO_RIGHTSERVO + velocity); if( duration != 0){ delay (duration); servoRight.detach(); } } } /*-------------------------------------------------De sensor send een singaal uit ter lengte van 10 microsec Voor het signaal zetten we een op de PIN_TRIGGER een LOW signaal van 2 microsec Daarna lezen we op de PIN_ECHO het binnenkomend echo signaal in microseconden. LET OP!! afstand van 2m = 200 cm duurt 11600 microsec afstand van 2cm duurt 116 microsec afstand van 10 cm duurt 290 microsec input: GEEN return: afstand in cm ----------------------------------------------------*/ long getDistance(){ long duration = 0; long d; // We maken nu gebruik van de NewSonar library delay(50); duration = sonar.ping_median(5); // Nu omzetten duration in cm d = sonar.convert_cm(duration); return d; } /* -----------------------------------------------------resetten omgevingsmap i = 90 is 0 graad i = 0 is -90 graad i = 180 is +90 graad
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
33
Op alle graden wordt afstand op 0 cm gezet. -------------------------------------------------------*/ void resetOmgevingMap(){ for(int i=0; i<91; i++){ omgeving_map[i].hoek = -90 + 2*i; omgeving_map[i].afstand = 0; } } /* -----------------------------------------------------resetten Voorwerpen i = 0 tot 20 -------------------------------------------------------*/ void resetVoorwerpen(){ for(int i=0; i<20; i++){ Voorwerp[i].lhoek = 360; Voorwerp[i].rhoek = 360; Voorwerp[i].afstand = -1; } } /*------------------------------------------------------Deze functie vult de array omgeving_map met waarden. Gaat van -90 graden naar +90 graden -------------------------------------------------------*/ void swapOmgeving(){ long afstand; int i, graad; // attach de sensor servo sensorServo.attach(PIN_SENSOR_SERVO); // sweep van 0 tot 180, 90 is de midden stand // 0 is de uiterste linkse stand, dus -90 graag // 90 is 0 graad // 180 is de uiterste rechtse stand, dus +90 graad sensorServo.write(90); delay(50); // wacht 50 ms tot positie bereikt is. for( i=0; i<91; i++){ sensorServo.write(2*i); delay(50); // wacht 50 ms tot positie bereikt is. afstand = getDistance(); // Serial.println(afstand); delay(30); // wacht 30 ms tot afstand bepaalt is // Vul de omgeving map omgeving_map[i].afstand = afstand; omgeving_map[i].hoek = 90-2*i; } // Swap is gereed, zet sensor weer op 0 positie (is vooruit) sensorServo.write(90); delay(1000); // servo heeeft tijd nodig om in zijn basis te komen wacht 200 ms tot positie bereikt is. sensorServo.detach(); } /*---------------------------------------------------------------Deze functie bepaalt de volgende richting van de robot. We maken gebruik van parameters die experimenteel bepaald zijn. variatie in afstand in cm -----------------------------------------------------------------*/ void calcVoorwerpen(long variatie){ int i,v; // v is index van de gevonden objecten, kan max 20 objecten bevatten 0 -19 // We beginnen met i = 0, dit is de meest rechtse hoek van de eerste object i = 0; v = 0 ; long afstand1, afstand2; Voorwerp[v].rhoek = omgeving_map[i].hoek; afstand1 = omgeving_map[i].afstand; while( i<90){ if( i+1 == 90){ // We hebben de uiterste linkse hoek van de laatste object. Voorwerp[v].lhoek = omgeving_map[i+1].hoek; afstand2 = omgeving_map[i+1].afstand; // Bepaal hier de gemiddelde afstand Voorwerp[v].afstand = (afstand1 + afstand2)/2;
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
34
break; } if(abs( omgeving_map[i].afstand - omgeving_map[i+1].afstand ) > variatie){ // We hebben een jump // linkerhoek huidig object = i // rechterhoek volgende object = i+1 Voorwerp[v].lhoek = omgeving_map[i].hoek; afstand2 = omgeving_map[i].afstand; // Bepaal hier de gemiddelde afstand Voorwerp[v].afstand = (afstand1 + afstand2)/2; v = v +1 ; Voorwerp[v].rhoek = omgeving_map[i+1].hoek; } i = i +1 ; afstand1 = omgeving_map[i].afstand; } } //--------------------------------------------------------------------------// We bepalen uit de voorwerpen array welk object het verst verwijderd is. // Vinden we meerdere objecten dan we die met de verst mogelijke hoek. //--------------------------------------------------------------------------int findNextHoek(){ long maxAfstand = 0; int maxVoorwerp =0; int hoek = 0; for( int i=0; i<20; i++){ if( Voorwerp[i].rhoek - Voorwerp[i].lhoek > HOEKVAR ){ // de doorgang is groter dan 15 graden // Deze mag meedoen if( Voorwerp[i].afstand >= maxAfstand){ maxVoorwerp = i; maxAfstand = Voorwerp[i].afstand; } } } // we hebben een max voorwerp gevonden // bepalen nu d hoek die we moeten draaien hoek = (int)(Voorwerp[maxVoorwerp].rhoek + Voorwerp[maxVoorwerp].lhoek)/2; return hoek; } int findMiddelsteObject(){ int i=0; int iObject; for(int i=0; i<20; i++){ if( Voorwerp[i].lhoek <= 0 && Voorwerp[i].rhoek >= 0){ // We hebben de middelste object gevonden iObject = i; break; } } // Voorwerp[object] is het middelste object return iObject; }
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
35
CONCLUSIE Uit de resultaten van de servomotoren blijkt dat vanaf de eerste 100ms de rotatie in graden recht evenredig is met de tijd in milliseconden. Van 0 tot 100ms nemen wij aan dat de rotatie proportioneel aan de tijd is Voor dit PWS is het ons gelukt om een simpele autonome robot te maken. De robot heeft echter weinig intelligentie, wat komt door het eenvoudige algoritme en gebrek aan geld, tijd en kennis. De robot kan alleen in de afgebakende omgeving operenen. De vormgeving van onze robot is minimaal. Dit komt door het tekort aan faciliteiten en vaardigheden.
DISCUSSIE De keuze om voor het PWS een robot te maken, heeft ons veel geleerd. Wij hebben ons in de programmeer taal C/C++ verdiept. Het belangrijkste onderdeel van dit project is het programmeerwerk. Hierbij hebben wij hebben geleerd dat zowel het maken als het debuggen van een programma veel tijd kost. Het resultaat van ons project, de robot, is simpel. We hebben onze omgeving, waarin de robot moet opereren, in het begin gedefinieerd. Daarom is Johnny 5 niet operationeel in een dynamische omgeving. Om een functionelere robot te maken, die kan opereren in een dynamisch omgeving, zouden we een real time operating system (RTOS) moeten gebruiken. Het real time mechanisme werkt met een interruptie procedure, waarmee er meerdere functies gelijktijdig kunnen lopen.
De keuze om een servomotor en een Arduino Motorschield aan te schaffen, was geen verstandige keuze. Door verwarring in het begin, dachten wij beiden dat wij de Motorschield nodig hadden om de richting en snelheid van een motor te kunnen controleren. Daarnaast dachten wij ook dat het gebruik van een servomotor de beste keuze was. Het bleek echter dat de snelheid en de richting gecontroleerd kan worden door verschillende PWM signalen. Daarom was een Arduino Motorschield 端berhaupt niet nodig. Ons vooronderzoek was niet volledig. Achteraf bleek dat er kan- en klare aangepaste servomotoren op de markt zijn. Als we dit eerder hadden geweten, hadden we ons enorm veel tijd kunnen besparen.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
36
Meetfouten sensor In de tests om de zien hoe en wat de sensor meet, hebben we gebruik gemaakt van de functie sprintf(). De sprintf() functie zet de aangegeven variabelen in een venster. Dit gebruikten wij om de eigenschappen van de sensor, in een beperkte ruimte, te onderzoeken. Zie afbeelding [].Uit de metingen bleek dat de ultrasone sensor afwijkingen geeft. Als de sensor een afstand zou moeten meten van 20 cm, kwam het voor dat de sensor een waarde van 8 cm waarnam. Deze afwijking zou kunnen liggen aan de processnelheid van de Arduino. De processnelheid van de Arduino kan veel invloed hebben op de gemeten echotijd, waardoor er verkeerde afstanden gemeten worden. Als de opeenvolging van de functies digitalWrite( PIN_TRIGGER, HIGH); en de pulseIn( PIN_ECHO, HIGH); relatief groot is, zal de tijd die pulseIn( PIN_ECHO, HIGH); meet kleiner zijn, waardoor de gemeten afstand ook kleiner zal zijn.
Figuur 27, Experimenten om te testen of de sensor goede waarden geeft.
Toepassingen van robot Onze robot, of een soortgelijke robot, zou op veel verschillende manieren kunnen worden toegepast. Zo zou er een roterende bezem of stofzuiger op kunnen worden bevestigd zodat de robot een magazijn van een groot bedrijf zou kunnen schoonmaken. De robotmoet dan wel groter zijn, maar het principe is hetzelfde. Een soortgelijke robot wordt al gebruikt in de vorm van een grasmaaier. Met alleen de servomotoren zou je allemaal verschillende dingen kunnen doen. Zo zou je op afstand deuren op slot kunnen doen door er met een servomotor een grendel voor te doen. Als je een ander shield op de Arduino zet zou je de robot ook op afstand kunnen besturen en er een soort battlebot van kunnen maken. Figuur 28, De mobipulator, deze robot is gemaakt voor de ASME studenten design competitie. Deze robot kan over muren/hoge obstakels klimmen.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
37
BRONNENLIJST [1]- Arduino SA, ArduinoBoard UNO, Arduino.cc, November 2014, http://arduino.cc/en/Main/ArduinoBoardUno. [2]- Arduino SA, Adruino MotorshieldR3, Arduino.cc, November 2014, http://arduino.cc/en/Main/ArduinoMotorShieldR3. [3]- Arduino SA, Servo Library, Arduino.cc, November 2014, http://arduino.cc/en/reference/servo. [4]- Tim Eckel, NewPing, Arduino.cc, November 2014, http://playground.arduino.cc/Code/NewPing. [5]- Robtillaart, ComplexMath, A complex math library for Arduino, Arduino.cc, November 2014, http://playground.arduino.cc/Main/ComplexMath. [6]- Arduino SA, Printf, Arduino.cc. November 2014, http://playground.arduino.cc/Main/Printf. [7]- Darren Sawicz, Hobby Servo, Fundamentals, Princeton.edu, November 2014, http://www.princeton.edu/~mae412/TEXT/NTRAK2002/292-302.pdf. [8]- Rick Winscot, Modifying Servos for Continuous Rotation, learn.Adafruit.com, November 2014, https://learn.adafruit.com/modifying-servos-for-continuous-rotation?view=all. [9]- HaydonKerk, Stepper Motor Theory, November 2014, http://www.haydonkerk.com/Resources/StepperMotorTheory/tabid/192/Default.aspx. [10]- Herbert Schildt, eerste editie, 1988, C: The Complete Reference, Berkeley California, Osborne/McGraw-Hill Inc. [11]- Ultrasonic Acoustic Sensing, Brown University, November 2014, http://cs.brown.edu/people/tld/courses/cs148/02/sonar.html. [12]- Arduino SA, Software, Arduino.cc, November 2014, http://arduino.cc/en/main/software.
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
38
LOGBOEK Datum 10-9 3-10 11&12-10 18&19-10 30-10 31-10 4-11 8&9-11 15&16-11 18-11 22&23 24-11 25-11 28-11 29&30-11 1-12 2-12 6&7-12 Totaal aantal uur
Wat Begin plan opstellen Jaarbeurs Utrecht WOTS Informatie zoeken boards Informatie zoeken motors PWS middag PWS dag Bouwen Theorie zoeken Start programmeren Bouwen Programmeren en verslag Bouwen Verslag en debuggen Debuggen Debuggen/Programmeren en verslag Verslag en bouwen Bouwen Verslag
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
Wie Albert en Friso Albert en Friso Albert en Friso Albert en Friso Albert en Friso Albert en Friso Friso Albert en Friso Albert Albert en Friso Albert en Friso Albert en Friso Albert en Friso Albert Albert en Friso Albert en Friso Friso Albert en Friso
Tijd (Albert+Friso) 3 14 6 5 8 16 2 5 10 4 19 6 6 3 18 8 2 18 158
39
BIJLAGEN Bijlage 1, Het elektronisch schema Arduino UNO
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
40
Bijlage 2, Het elektronisch schema Arduino Motorshield
Profiel Werkstuk Johnny 5, Albert Wieland en Friso Rietstra
41