Download as pdf or txt
Download as pdf or txt
You are on page 1of 257

De Quadrocopter

Arne Depoortere Laurens Scheldeman


Promotor: Dhr. Rubben F.








VTI-Brugge















De Quadrocopter



Arne Depoortere
Laurens Scheldeman



Promotor: Dhr. Rubben















Schooljaar 2013-2014

Woord vooraf

Wij studeren aan het VTI Brugge en volgen er tijdens het schooljaar 2013-
2014 het zesde jaar Industrile Wetenschappen. Als eindwerk kozen we voor
het bouwen en programmeren van een quadrocopter.

Enerzijds gaan onze interesses uit naar elektronica en mechanica.
Anderzijds stond al snel vast dat we een project wilden uitwerken rond
vliegtuigen. Na enig opzoekwerk besloten we om een quadrocopter te
bouwen. Dit is een op afstand bestuurde multicopter aangedreven door vier
rotors. De uitdaging bestond erin om de quadrocopter zo stabiel mogelijk te
laten vliegen.

Deze opdracht hebben we kunnen realiseren dankzij de raad en opvolging
van onze promotor en leerkracht elektriciteit, de heer Frank Rubben. Ook de
heren Patrick Gurdebeke en Geert Maes zijn we dankbaar voor hun steun en
uitleg. Verder ook dank aan Aerobertics voor het deskundig advies. Onze
ouders, familie en vrienden bedanken we ook voor hun morele en materile
steun.


Inhoudsopgave

Woord vooraf ......................................................................... 4

Inhoudsopgave ...................................................................... 5

Inleiding ................................................................................ 7

Opdracht geschiedenis: Ontstaan van de quadrocopter ......... 8

Hoofdstuk 1: De voorbereiding ............................................ 16
1.1 Het vliegtuig ..........................................................................16
1.2 De helikopter .........................................................................17
1.3 De quadrocopter ....................................................................19
1.4 Opstart van het project ...........................................................22
1.5 Modelbouwwinkels ..................................................................24
1.6 Bezoek KHBO ........................................................................25
1.7 De wetgeving m.b.t. quadrocopters ...........................................26

Hoofdstuk 2: Het frame ........................................................ 27
2.1 De armen .............................................................................28
2.2 De boven- en onderbaseplate ...................................................32
2.3 Het kartonnen frame...............................................................34
2.4 De stand-offs ........................................................................35
2.5 De deckplaat .........................................................................38
2.6 Montage ...............................................................................39

Hoofdstuk 3: De bouw .......................................................... 41
3.1 De batterij ............................................................................42
3.2 Het powerboard .....................................................................47
3.3 De snelheidsregelaars (ESCs) ..................................................48
3.4 De motoren ...........................................................................49
3.5 De propellers .........................................................................53
3.6 De UBEC ...............................................................................58
3.7 De zender en ontvanger ..........................................................59
3.8 Het controllerbordje ................................................................61


Hoofdstuk 4: Het programma ............................................... 64
4.1 Vlieg modes ..........................................................................64
4.2 Tuning ..................................................................................66

Hoofdstuk 5: De afwerking................................................... 68
5.1 Het landingsgestel ..................................................................68
5.2 De ledlampen ........................................................................69
5.3 De afgewerkte quadrocopter ....................................................70

Hoofdstuk 6: Paola wedstrijd ............................................... 72

Opdracht Frans .................................................................... 73

Opdracht Engels ................................................................... 82

Bijlagen.............................................................................. 111

Lijst van figuren ................................................................. 247

Literatuurlijst ..................................................................... 249

Nawoord ............................................................................ 254



Inleiding

Sinds het derde jaar volgen wij de richting industrile wetenschappen.
In het vijfde jaar werd ons verteld dat we in het zesde jaar de kans zouden
krijgen om een eindwerk te maken. Vol enthousiasme besloten we om in het
vijfde jaar al eens na te denken over een goed GIP-onderwerp.

Omdat elektronica en mechanica ons erg interesseren, kozen wij voor de
quadrocopter. Nochtans is dit niet de enige reden voor dit project.
We waren er ook van overtuigd dat we een project wilden uitvoeren in de
luchtvaart. Het fascineert ons hoe een vliegtuig in de lucht kan blijven en niet
neerstort.

Aangezien bij het bouwen van een quadrocopter verschillende disciplines zoals
fysica (stabiliteit van het vliegtuig), sterkteleer (keuze van de gebruikte
materialen), wiskunde (bijvoorbeeld berekenen hoe groot de propellers moeten
zijn) en elektriciteit/elektronica (keuze van de motoren, snelheidsregelaars,)
betrokken zijn, komen in dit project ook onze andere interesses aan bod.

Met de quadrocopter bouwen we ook aan een toestel dat in de toekomst verder
zal gebruikt worden. Wij denken bijvoorbeeld aan de toepassing van drones in
oorlogsgebieden. Wellicht zijn er voor de quadrocopter nog tal van nieuwe
mogelijkheden in de moderne technologie.

In ons GIP-boek kan u perfect volgen hoe we deze quadrocopter bouwen. Alle
aanwezige berekeningen en keuzes van materiaal die we maken staan in dit
boek beschreven.

Ons eindwerk bestaat uit zes hoofdstukken en enkele bijlagen.
In het eerste hoofdstuk wordt de voorbereiding besproken die vooraf ging aan
het effectief bouwproces.

In het volgende, tweede, hoofdstuk wordt het frame beschreven. Hier gaat het
voornamelijk over gewichtsbesparing. Dit is een zeer belangrijk aandachtspunt.

In het derde hoofdstuk vervolledigen we de bouw van onze quadrocopter. Dit
wil zeggen dat we de motors, het powerboard, het geheugenbord, de
propellers, aanbrengen.

Hoofdstuk vier heeft betrekking op het programmeren van de quadrocopter.
Het volledige geheugenbord moet namelijk correct worden geprogrammeerd.

In het vijfde hoofdstuk bespreken we onze ervaringen met het vliegen met de
quadrocopter. Ook de volledige afwerking wordt daarin beschreven.

In het zesde en laatste hoofdstuk wordt er nog aandacht gegeven aan onze
deelname aan de Paola wedstrijd.





Pagina 8


Opdracht geschiedenis: Ontstaan van de quadrocopter
De geschiedenis van de quadrocopter, een radio gestuurde multicopter
aangedreven door vier rotors, kan niet losgezien worden van de geschiedenis
van de helikopter. Alles begint in 400 voor Christus met de Chinese vliegers
aangedreven door propellers uit bamboe.


Via de handel met het Verre Oosten bereikte dit speelgoed Europa in de
renaissance. Dit inspireerde niemand minder dan Leonardo Da Vinci (1452
1519). Leonardo Da Vinci droomt van een
vliegmachine en denkt aan een constructie
die bewogen wordt door een hefschroef die
draait om een verticale as. Hij denkt daarbij
aan de schroef van Archimedes. Dit is een
apparaat dat over het algemeen gebruikt
wordt voor het oppompen van water. Het
transport gebeurt meestal opwaarts. Da Vinci
wil dit gebruiken voor het opstijgen en
lanceert hiermee het idee van het verticaal
opstijgen. Het is een soort voorontwerp van
een helikopter. Echter, de kracht om de
vliegmachine voor te stuwen moest van
mensen komen die de schroef van Archimedes
moesten laten draaien. Dit bleek onhaalbaar
omdat het toestel te zwaar werd.

fig. 0.2: Leonardo Da Vinci




Pagina 9


Drie eeuwen later, in 1754, stelt de Rus Mikhail Lomonosov (1711 1765) een
kleine tandem rotor voor aan de Russische Academie voor Wetenschappen.
Het toestel, de Aerodynamic, is bedoeld om meteorologische instrumenten te
laten opstijgen. Hier wordt het idee van het verticaal opstijgen dus weer
opgepikt. Twee propellers roteren in tegenovergestelde richting op eenzelfde
as. Het toestel wordt aangedreven door een horlogeveer.

In 1784 stellen Christian de Launoy en zijn mecanicien Bienvenu aan de
Franse Academie voor Wetenschappen een model voor met wiekjes die in
tegenovergestelde richting draaien. Dit toestelletje kan zelf (verticaal)
opstijgen en wordt voortbewogen door de spanning van de boog. Ook dit
toestelletje blijft speelgoed






Pagina 10


In 1843 experimenteert Sir George Cayley (1773 1857) met een toestel
met vier propellers die eruit zien zoals paraplus. Het wordt geen succes.


In 1863 gebruikt een tijdgenoot van Jules Verne, Gustave Vicomte de Ponton
dAmcourt (1825 1888), voor het eerst het woord helikopter, afgeleid uit
het Grieks : draaiende vleugels. Hij maakt verschillende ontwerpen, o.a. een
model aangedreven door stoom. Ook dit model blijkt over te weinig kracht te
beschikken om op te stijgen.





Pagina 11


In 1877 slaagt de Italiaan Enrico Forlanini (1847 1918) erin om tijdens een
demonstratie in Milaan een hefschroefmachine twintig seconden in de lucht te
houden op zon 13 meter hoogte. Het gaat om een model aangedreven door
een licht stoommachientje.

Een echte doorbraak komt er met de uitvinding van de ontploffingsmotor of
dieselmotor door Rudolf Diesel (1858 1913). Deze motor bezit meer kracht
om een toestel met persoon te kunnen laten opstijgen.
In 1907 komt er een eerste doorbraak met de Gyroplane No.1 van de broers
Louis (1880 1955) en Jacques Brguet (1881 1939) in samenwerking met
professor Charles Richet (1850 1935). Het toestel met n persoon kan
verticaal opstijgen en blijft een 2-tal minuten boven de grond hangen. Helaas
zijn er vier mensen nodig om het toestel van op de grond te stabiliseren. Er is
immers nog geen enkele mogelijkheid om de vlucht van het toestel te
controleren.








Pagina 12


Op 13/11/1907 maakt de fransman Paul Cornu (1881 1944) te Lisieux (Fr.)
de eerste vlucht met een helikopter met twee rotors, aangedreven door een
24-pk-motor. Hij verheft zich 0,3 meter boven de grond en vliegt ongeveer
twintig seconden. Ook hier is nog geen mogelijkheid om de vlucht te
controleren. Heden ten dage wordt getwijfeld of Cornu wel echt gevlogen
heeft. Na analyse van het toestel achten ingenieurs het onmogelijk dat het
toestel kon vliegen.

In 1922 laat George de Bothezat (1882 1940) een eerste quadrocopter
succesvol vliegen met vier 6-bladige rotors. Echter, het toestel blijft moeilijk te
besturen en kan enkel voorwaarts vliegen.

In 1923 maakt de Spaanse ingenieur Juan
de la Cierva (1895 1936) met de Autogiro
No.4 een vlucht van vier kilometer rond
Madrid. De autogyro heeft een propeller om
voorwaarts te bewegen en heeft een rotor die
werkt op aerodynamische krachten. Het is
geen helikopter want het toestel kan niet
verticaal opstijgen. Er wordt hier wel voor het
eerst een gecontroleerde vlucht gerealiseerd.
De scharnierende rotorbladen verhinderen
het overhellen van het toestel. Zijdelingse
bewegingen worden mogelijk.






Pagina 13


Op 04/05/1924 maakt de Franse ingenieur Etienne Oehmichen (1884 1955)
te Arbouans (Fr.) met de Oehmichen No.2 een vlucht van n kilometer op
een gesloten circuit gedurende zeven minuten en veertig seconden. Het is een
quadrocopter. Vier rotors en acht kleine verticaal gemonteerde propellers
worden elk aangedreven door een eigen motor.

In 1937 verbetert de Duitser Heinrich Focke (1890 1979) samen met de
Duitse ingenieur Gerd Achgelis (1908 1991) de autogyro van de la Cierva.
Bij de Fa-61 wordt de propeller vervangen door een aangedreven rotor.
De Rus Igor Sikorsky (1889 1972) wordt algemeen beschouwd als de vader
van de helikopter. Zijn VS-300 begint zeer goed te lijken op de helikopters die
we nu kennen.


Hij gebruikt een hoofdrotor met drie bladen en een verticaal gemonteerde
staartrotor met twee bladen. In mei 1940 blijft dit toestel meer dan 1,5 uur in
de lucht.





Pagina 14


De XR-4 van Sikorsky is de eerste helikopter die daadwerkelijk op grotere
schaal geproduceerd wordt.



Vele ontwerpen volgen.

In maart 1956 wordt het concept van Oemichen en van de Bothezat weer
opgepikt en vliegt de Convertawings Model A Quadrotor. Deze helikopter met
vier rotors (= een quadrocopter) bewijst de degelijkheid van het ontwerp.
Wegens besparingen binnen defensie (VS) wordt het project stilgelegd.




In 1958 wordt weerom op militaire vraag de Curtiss-Wright VZ-7 ontwikkeld.
Het is een quadrocopter die bedoeld is om vracht te vervoeren. Het toestel
kan verticaal opstijgen en is te besturen door de kracht van de verschillende
propellers te variren.





Pagina 15



Inmiddels worden hybride toestellen ontwikkeld. Die combineren de voordelen
van een helikopter (verticaal opstijgen) met de voordelen van een vliegtuig
(meer last meenemen + sneller voortbewegen). Daartoe worden kantelende
rotoren gebruikt die eerst zorgen voor het verticaal opstijgen en daarna
zorgen voor de horizontale vlucht.

De quadrocopter is dus een radio gestuurde helikopter aangedreven door vier
rotors. Een quadrocopter kan verticaal opstijgen, blijven hangen en vliegen in
alle richtingen, net zoals alle helikopters. Onbemande quadrocopters (UAVs
of Drones) worden reeds lang gebruikt voor militaire opdrachten. Ze worden
heden ten dage steeds meer ingezet voor burgerlijke doeleinden zoals
luchtfotografie, luchtfilms, landmetertoepassingen, 3D-kartering en
surveillance-opdrachten.

Er is een lange weg afgelegd van de Chinese vliegers met bamboepropellers
tot de radio gestuurde quadrocopters. Heel de zoektocht is steeds
genspireerd door het verlangen van de mens om te kunnen vliegen en om de
aarde te kunnen bekijken vanuit het perspectief van een vogel







Pagina 16


Hoofdstuk 1: De voorbereiding

Zoals in de inleiding gezegd wilden we iets doen in het kader van de
luchtvaart. Het meest logische was dan om een modelbouwvliegtuigje te
maken.

1.1 Het vliegtuig

Bij een vliegtuig zijn er vier krachten aanwezig: de draagkracht, de
zwaartekracht, de wrijvingskracht en de voortdrijvende kracht of stuwkracht.





Een vliegtuig heeft een grote draagkracht nodig om te kunnen blijven vliegen.
Die draagkracht moet gelijk zijn aan de zwaartekracht. Om zo een grote
draagkracht te ontwikkelen, moeten we door middel van de vleugels een
horizontale kracht (voortdrijvende kracht) opwekken, net zoals bij het
opstijgen. Deze voortdrijvende kracht zorgt ervoor dat er veel ruimte nodig is
om een vliegtuig te laten opstijgen en landen. Deze ruimte wilden we
beperken door een toestel te maken dat verticaal opsteeg en landde. Hierdoor
kwamen we op het idee om een helikopter te maken.
fig. 1.1: De vier krachten op een vliegtuig




Pagina 17


1.2 De helikopter

Een helikopter heeft een verticale rotor. Deze wekt rechtstreeks de
draagkracht op. Dit heeft als gevolg dat men geen voortdrijvende kracht nodig
heeft en dus ook geen vleugels. Doordat er geen voortdrijvende kracht
aanwezig is, heeft een helikopter geen landingsbaan nodig. Het voordeel
hiervan is dat een helikopter loodrecht kan opstijgen en landen, wat met een
vliegtuig niet mogelijk is. Een helikopter kan ook in de lucht blijven hangen en
is behendiger dan een vliegtuig. Een helikopter beweegt door de hoek van de
rotorbladen te wijzigen. Hij heeft 2 rotorbladen: de hoofdrotor (1) en de
staartrotor (2).




De hoofdrotor dient om de helikopter te laten opstijgen en te laten bewegen.
Om vooruit te kunnen bewegen moet de helikopter schuin naar voren hangen.
De rotor tilt dan de helikopter op en zo beweegt hij tegelijkertijd naar voren.




fig. 1.2: Een helikopter met zijn rotoren
fig. 1.3: Een helikopter die opstijgt




Pagina 18


De staartrotor dient als tegenkracht van de hoofdrotor. De staartrotor draait in
tegengestelde richting van de hoofdrotor om het koppel dat wordt veroorzaakt
met de ronddraaiende hoofdrotor te compenseren.
Wanneer de staartrotor niet aanwezig zou zijn, zou de helikopter in de
tegengestelde richting van de hoofdrotor draaien, waardoor hij zou beginnen
rondtollen en uiteindelijk crashen. Dit komt omdat de helikopter dan nergens
door tegengehouden wordt.






Stel dat de motor van de helikopter de wieken in de richting van de rode pijlen
doet draaien, dan zal de helikopter vanzelf een rotatie in tegengestelde
richting uitvoeren (groene pijl). De staartrotor trekt de helikopter de andere
kant op om deze draaiing te compenseren (gele pijl).
fig. 1.4: Doel van de staartrotor




Pagina 19


Omdat een helikopter alleen maar bestuurbaar is door de hoek van de
rotorbladen te wijzigen, wilden wij een nog veiliger toestel maken, namelijk
een quadrocopter. Een quadrocopter kan worden bestuurd door de hoek van
de rotorbladen te wijzigen (net als bij een helikopter), maar ook door de
snelheid van de rotoren op dezelfde as aan te passen. Daardoor zal het koppel
en de liftkracht wijzigen. Wanneer er een motor zou uitvallen, zal de
quadrocopter nog steeds vliegen, aangezien de tegenoverstaande motor de
kapotte motor zal compenseren.

1.3 De quadrocopter
De quadrocopter leek ons perfect om te bouwen. Hij kan loodrecht opstijgen
en landen en hij is ook nog zeer behendig. Het probleem van het koppel dat
gecompenseerd moet worden bij een helikopter is bovendien perfect opgelost
bij een quadrocopter. Een quadrocopter heeft namelijk 4 rotoren, waardoor de
kracht kan worden opgeheven door twee van de motoren in tegengestelde
richting te laten draaien.


De motoren op dezelfde assen draaien altijd dezelfde kant op.

1.3.1 Soorten
Er zijn twee soorten quadrocopters. Namelijk de +4 en de x4. Het verschil
tussen de twee is de orintatie van de motoren op de quadrocopter t.o.v. de
voorkant.
+4 x4

Wij kiezen hier voor het type x4.
fig. 1.5: Draairichting propellers op een quadrocopter
fig. 1.6: Vliegmodes van een quadrocopter




Pagina 20


fig. 1.8: Quadrocopters die een voorwerp verplaatsen
1.3.2 Toepassingen

Wij kiezen ook voor de quadrocopter omdat er veel toekomst zit in dit project.
De quadrocopter kost niet veel om te produceren en hij kan in verschillende
sectoren gebruikt worden.

1) Luchtfotografie

Een quadrocopter is veel sneller en goedkoper dan het huren van een
bemande helikopter met een fotograaf.



2) Filmindustrie

Door gebruikt te maken van quadrocopters met videocameras worden grote,
dure en lompe bemande helikopters overbodig. De kwaliteit is trouwens even
goed. Er zijn momenteel al multicopters met 4K cameras aan boord.

3) Verplaatsingen

Bij het verplaatsen van delicate voorwerpen in de industrie kunnen er
quadrocopters gebruikt worden. Wanneer men onder de quadrocopter een
zuignap plaatst kan men ideaal voorwerpen verplaatsen.

fig. 1.7: Een quadrocopter met een camera




Pagina 21


4) Inspectie van industrile installaties

Controle is zeer belangrijk bij industrile installaties. Een inspectie vanuit de
lucht is meestal wel erg duur. Quadrocopters kunnen hier een oplossing voor
zijn wanneer ze worden uitgerust met cameras voor live video. Ook zouden
quadrocopters toegepast kunnen worden bij een situatie als die in Fukushima.
Quadrocopters kunnen dankzij hun design makkelijk uitgerust worden met
apparatuur om bijvoorbeeld straling waar te nemen. Ook kunnen ze vanwege
hun wendbaarheid en grootte gemakkelijk op moeilijk bereikbare plekken
komen.

5) Leveren van pakjes

De webwinkel Amazon is van plan om in
de toekomst postpakketjes te leveren
met drones. De CEO kondigde aan dat
Amazon de nieuwe bezorgmogelijkheden
aan het testen is. Mensen zouden op
deze manier sneller hun pakket in huis
moeten hebben. Bovendien is het
efficinter volgens hem. Amazon
verwacht de drones onder de noemer
PrimeAir over vier tot vijf jaar te kunnen
inzetten.

De onbemande vliegtuigjes kunnen pakketjes tot 2 3 kilo afleveren in een
straal van ruim 16 kilometer rondom een Amazon-distributiecentrum. In de
Verenigde Staten zou het grootste deel van de bestellingen op deze manier
kunnen worden verwerkt.
Momenteel laten de Amerikaanse autoriteiten het gebruik van drones in de VS
enkel toe door hobbyisten. Diensten leveren in ruil voor geld kan dus nog niet.
Binnen twee jaar zouden er echter nieuwe regels moeten zijn (Bijlage 1).

6) Verkenning en ordehandhaving

Een kleine opvouwbare quadrocopter kan bijvoorbeeld in een oorlogssituatie
ingezet worden om een omgeving te verkennen of een situatie in te schatten.
De quadrocopter is onbemand, dus er kunnen geen slachtoffers vallen zoals bij
een bemande helikopter. De vliegtuigfabrikant Lockheed Martin is reeds bezig
met de ontwikkeling van zon onbemande VTOL. De Japanse politie is
momenteel ook al bezig met onderzoek naar de inzetbaarheid van
quadrocopters bij onder meer ordehandhaving.
Zoals u kan zien is het leger en de politie erg genteresseerd in quadrocopters.
Ons project heeft dus zeker een toekomst.

7) Meer toepassingen: zie bijlage 2 9.
fig. 1.9: Quadrocopter die pakje zal verzenden




Pagina 22


1.4 Opstart van het project

Nadat we zeker wisten dat we een quadrocopter wilden maken, begonnen we
met dieper onderzoek. We hadden namelijk nog nooit een quadrocopter zien
werken. Een kant-en-klare quadrocopter kopen was geen optie want dan was
de uitdaging weg. We wilden hem helemaal zelf ontwerpen en alle onderdelen
zelf berekenen.

Het eerste wat we moesten weten was hoe hij er zou uitzien. Er zijn namelijk
verschillende groottes en modellen van quadrocopters.





fig. 1.10: Voorbeelden van quadrocopters




Pagina 23





Onze quadrocopter lijkt het meest op de hier bovenstaande quadrocopter.

Nadat we dit beslist hadden, zijn we begonnen aan de technische tekeningen
van de quadrocopter (Bijlage 10-15).

Van zodra we de toestemming van de school hadden gekregen om een
quadrocopter te maken, wilden we geen tijd verliezen. We hadden dan ook al
de technische tekeningen van het frame op voorhand gemaakt.

Daarna hebben we de onderdelen van de quadrocopter verder bestudeerd.
Deze onderdelen zullen worden besproken in hoofdstuk 3 over de bouw. Daar
komt ook de liftkracht aan bod. We moeten namelijk berekenen hoe sterk
onze motors moeten zijn om onze quadrocopter te laten vliegen.

Nadat we al redelijk veel opgezocht hadden over de onderdelen, hadden we
een gesprek met onze promotor. Wij waren van plan om de onderdelen aan te
kopen via internet, maar hij wees ons erop dat er verschillende
modelbouwwinkels zijn in Brugge.


fig. 1.11: Een quadrocopter die het best op onze quadrocopter gelijkt




Pagina 24


1.5 Modelbouwwinkels

Met dit advies trokken we naar modelbouwwinkel Verbrugghe. Daar waren ze
zeer vriendelijk. We kregen er goed advies over ons project. Wanneer we
vermeldden dat we eventueel de onderdelen zouden aankopen via HobbyKing
wezen ze ons erop dat HobbyKing soms mindere kwaliteit levert. We mochten
ons opzoekwerk al eens doorsturen en ze zouden het bekijken om ons snel en
goed te kunnen helpen. Jammer genoeg bleek nadien dat de eigenaar geen
tijd had om alles in detail uit te werken voor ons (Bijlage 16). Hij verwees ons
dan ook vriendelijk door naar Aerobertics.



Op 11 oktober 2013 zijn we dan naar Aerobertics gegaan. Daar zijn ze
gespecialiseerd in modelbouwvliegtuigen en drones. Ideaal dus voor ons. Bij
modelbouwwinkel Verbrugghe hadden ze ook modelbouwautos maar daar
waren wij op dat moment niks mee. We hadden dan ook alle twee het gevoel
dat we bij Aerobertics in de juiste winkel terechtgekomen waren. We legden
ons project uit aan Bert (de eigenaar van Aerobertics). Hij kon ons goed
helpen en had een heleboel onderdelen in voorraad voor ons. Ook hier kregen
we deskundig advies en werden we een heel stuk vooruit geholpen.
Uiteindelijk betaalden we 354,50 euro (Bijlage 17) en hadden we goed en
degelijk materiaal, namelijk 2 carbonplaten van 1,5 millimeter dik, 4 brushless
DC-motoren (inclusief snelheidsregelaars), 4 propellers, 1 lipo batterij, 1
powerboard, 1 power set (batterijlader), 1 laadkabel en 1 aansluitpin om te
solderen aan het powerboard.

Deze prijs lag iets hoger dan onze eerste raming van ongeveer 260 euro
(Bijlage 18). We hebben beslist om ook een prijslijst bij te houden van de
werkelijke uitgaven (Bijlage 19).






Pagina 25


1.6 Bezoek KHBO

Nadat we alles opgezocht hadden over de quadrocopter, de onderdelen
berekend hadden, de technische tekeningen gemaakt hadden en de
onderdelen aangekocht hadden, hebben we ons opzoekwerk afgerond met een
bezoek aan het KHBO in Brugge tijdens de herfstvakantie. Daar zagen we ons
eerder opzoekwerk bevestigd, maar jammergenoeg vonden we er weinig
bijkomende informatie.

Nu konden we ons volledig aan de bouw van de quadrocopter wijden.









fig. 1.12: Het KHBO te Brugge




Pagina 26


1.7 De wetgeving m.b.t. quadrocopters


In Nederland en Belgi zijn steeds meer
liefhebbers in het bezit van een
quadrocopter of een drone. Deze drones
worden steeds goedkoper en ze zijn
makkelijker te besturen. Veel hobbyisten
zijn echter niet goed op de hoogte van
de wet- en regelgeving omtrent het
vliegen met een drone. Daarom zochten
wij deze wetgeving even op.

Ten eerste is er een onderscheid in het gebruik, namelijk voor recreatieve of
commercile doeleinden.

In Belgi is het momenteel verboden om met een drone te vliegen voor
commercile doeleinden. Om foto's te nemen vanuit de lucht moet er nog
altijd een piloot aan boord zijn. Men werkt momenteel wel hard aan een
wettekst zodat commercieel gebruik toch mogelijk wordt met onbemande
kleine luchttuigen.

Voor recreatief gebruik zijn er 3 gewichtscategorien: drones die minder dan
1 kg wegen, drones die tussen 1 kg en 150 kg wegen en drones die meer dan
150 kg wegen.

Onze drone weegt ongeveer 1 kg. Wanneer hij minder dan 1 kg weegt is er
geen probleem. De drone mag overal vliegen.

Wanneer de drone tussen de 1 kg en 150 kg weegt zijn er verschillende
voorwaarden. Die voorwaarden worden beschreven in een omzendbrief die je
kunt vinden in Bijlage 20.

fig. 1.13: Quadrocopter toegelaten in Belgi




Pagina 27


Hoofdstuk 2: Het frame

Het frame is de basis van de quadrocopter. Zonder een goed frame kan er
nooit een stevige quadrocopter gebouwd worden. Toch is het niet de bedoeling
om het frame zodanig sterk te construeren dat het enorm zwaar wordt. Dit is
namelijk allemaal extra gewicht wat ervoor zorgt dat er krachtigere motors
nodig zijn met als gevolg grotere propellers. De uitdaging bestaat er hier dus
in om het frame stevig te maken maar tegelijk ook licht. Door vele modellen
te bekijken op internet en in boeken, weten we welke materialen het beste
zijn om onze onderdelen uit te vervaardigen. We moeten namelijk weten uit
welk materiaal we onze vier armen (1), een boven baseplate (2), een onder
baseplate (3), stand-offs (4) en een deckplaat (5) gaan maken.




fig. 2.1: Het afgewerkte frame




Pagina 28


2.1 De armen

De armen van onze quadrocopter hebben we
uit aluminium gemaakt. Daarvoor zijn er
verschillende redenen.

1) Licht

Aluminium is zeer licht (2,755

). Het is
zelfs drie keer lichter dan staal (7,800

), maar wel even sterk. IJzer weegt


7,860

en inox 7,930

. Het is
duidelijk dat aluminium het lichtst is.
Dit is een groot pluspunt, omdat ons frame
niet te zwaar mag zijn, maar wel sterk moet
zijn.

2) Geen corrosie

Aluminium is bestand tegen corrosie, behalve tegen spanningscorrosie.
Aangezien er geen overdreven spanningscorrosie aanwezig is, is dit positief
voor een lange levensduur van onze quadrocopter.

3) Sterk

Aluminium is een sterk materiaal. Het is zelfs even sterk als staal. Dit komt
omdat aluminium ook nog bestaat uit 4% Cu, 1% Mg, 1% Mn en 0,5% Si.
Dit is ideaal voor de armen aangezien er rekening gehouden moet worden met
de motor op het uiteinde van iedere arm, een propeller op de motor, een
snelheidsregelaar op de arm en de bedrading.

4) Slijtvast

Aluminium is een zacht materiaal dat
slijtvast is. Het zal daardoor vuil opnemen
in plaats van afstoten. Bij het opnemen
ontstaan er geen krassen op het aluminium
en is de weerstand van het aluminium
groter dan die van het vuil. Hierdoor wordt het aluminium niet beschadigd. Bij
toevoeging van 4% Cu, 1% Mg, 1% Mn en 0,5% Si, is niet alleen het
oppervlaktemateriaal beschermd, maar ook het dieper gelegen materiaal. Het
aluminium is dus volledig beschermd tegen slijtage.

fig. 2.2: Een aluminium arm




Pagina 29


5) Gemakkelijk verkrijgbaar

Aluminium is in alle vormen en gewichten verkrijgbaar. Dit is zeer handig voor
onze armen. We hebben lange vierkante profielen nodig en niet n blok
aluminium. Gelukkig zijn deze profielen verkrijgbaar in de Stock Vermeersch
(Bijlage 21).

6) Goedkoop

Aluminium is tevens geen duur materiaal. Dit is een pluspunt, aangezien er
toch wel vrij veel aluminium nodig is per arm.

Berekening van het volume aluminium per arm:
Stel dat we een vol vierkant profiel hebben van 20x20
en een lengte van 200mm, dan is het volume van dit
profiel 80000mm.



Onze aluminium arm is echter een vierkant profiel dat
inwendig hol is met een dikte van 2mm. De binnenste
lengte en breedte zijn dus 16mm. De lengte blijft
200mm.



Het volume aan aluminium per arm is dus 28800mm.



Aangezien we vier armen nodig hebben, hebben we een volume van 115200
mm of 115,2 cm aluminium nodig.

Wanneer we dit profiel in een duurder materiaal moeten kopen, zal de prijs
per volume uiteraard veel hoger liggen.

Deze aluminium profielen hebben we gekocht aan 0,42 euro per stuk. Dit
maakte een totaal van 1,66 euro voor de vier profielen.

Om dan ook nog het gewicht te berekenen van een aluminium profiel maken
we volgende berekening:

gram

fig. 2.3: Onbewerkte
aluminium staaf




Pagina 30


7) Gemakkelijk bewerkbaar

Aluminium is gemakkelijk bewerkbaar. Dit was zeer handig, aangezien we
onze profielen op school konden laten bewerken. We hebben namelijk geen
CNC machine thuis en daarom lieten wij 152 grote gaten (4 keer 38) van
12 mm in de aluminium armen frezen. Dit was louter voor gewichtsbesparing.
We zijn de leerkrachten en leerlingen die dit gedaan hebben dankbaar. Zij
hebben dit goed en zeer snel gemaakt voor ons.



De afschuining op het einde van iedere arm dient om de motoren
gemakkelijker te monteren. Ook het design van de armen is mooier met een
afschuining.

De andere gaten hebben we zelf geboord, omdat deze overeen moeten komen
met de boven en onder baseplate.
Nu we extra gaten geboord hebben, verkleint ons volume terug en ook ons
gewicht.


fig. 2.4a: De afgewerkte aluminium armen fig. 2.4b: Zijkant van de afgewerkte armen




Pagina 31


Om het nieuwe volume en gewicht te kennen, berekenen we eerst het volume
van een gat



Daarnaast hebben we ook een afschuining op het uiteinde van de arm gezet.
Deze afschuining is 17mm bij 18mm



met


en



Hieruit kunnen we besluiten dat ons totale volume afneemt met die 38 gaten
en de afschuining.



Er is dus een volumebesparing van 9776 mm (

).

We weten dat de soortelijke massa van aluminium 2,755
gr
cm

is.



De massa van n arm is 52,3 gram en van onze vier armen samen dus 209
gram.

Er is dus een gewichtsbesparing van 27 gram per arm (79,3-52,3).





We hebben dus 33% gewicht bespaard op de aluminium armen!

Voor vier armen samen hebben we dus 108 gram bespaard door extra gaten
te maken en een afschuining te plaatsen in de aluminium profielen.





Pagina 32


fig. 2.5: De carbon baseplates
fig. 2.6: De carbonstructuur
2.2 De boven- en onderbaseplate

De boven- en onderbaseplate
hebben wij gemaakt uit carbon.

Ook carbon heeft verschillende
voordelen:

1) Geen corrosie

Carbon kan niet corroderen.
Dit is positief wanneer we onze quadrocopter lang willen gebruiken.

2) Nauwelijks materiaalmoeheid

Carbon zal normaal niet breken als gevolg van materiaalmoeheid.
Een goed doorgerekend frame kent geen overmatige interne spanningen en
als er 1 vezel breekt, dan liggen er nog honderden naast die de krachten
kunnen verwerken.

3) Licht

Carbon is een licht materiaal. Het is zelfs lichter dan aluminium. Het soortelijk
gewicht van aluminium is 2755 kg/m en van carbon 1800 kg/m.

4) Sterk

Carbon is niet alleen lichter dan aluminium maar ook sterker. Dit komt door de
structuur van carbon. Carbon bestaat enkel uit koolstofatomen. Koolstofvezel
wordt gemaakt door een gewone kunststofvezel te verbranden, te
'carboniseren' en daarna te grafitiseren. Hoe verder in het proces, hoe puurder
de koolstof. Het resultaat is een soort honingraatstructuur in zeshoekvorm van
koolstofatomen die zorgt voor een enorme hoge treksterkte. Een erg sterke
vezel dus.






Pagina 33


fig. 2.7: Zaag test
fig. 2.8: Afgewerkte baseplate (links) en deckplate (rechts)
Helaas zijn er aan carbon ook enkele nadelen verbonden:

1) Gevoelig voor puntbelasting

Carbon kan heel veel krachten aan, maar als de grens bereikt wordt, dan zal
het niet verbuigen of indeuken, maar direct breken. Daardoor kan het frame
onherstelbaar beschadigd worden.

2) Duur

Carbon is vele malen duurder dan aluminium. Wanneer dit niet zo was, dan
zouden wij het hele frame uit carbon (inclusief de armen) gemaakt hebben.
Jammer genoeg bleek dit niet haalbaar. Voor n carbonplaat betaalden we al
35,90 euro.

2.2.1 De uitvoering

Het maken van de baseplates was een grote uitdaging voor ons. We zijn uitleg
gaan vragen aan de leerkrachten praktijk, over hoe we het best carbon
konden bewerken. De praktijkleerkrachten hadden zelf geen ervaring met
carbon bewerken. We kregen wel verschillende adviezen, gaande van het laten
maken in de winkel tot het opsturen van de technische tekeningen zodat ze
het in de fabriek konden maken. Op school is er geen materiaal voorhanden
om te frezen of draaien in carbon.
Wij kozen voor een iets spectaculairdere oplossing: het zelf proberen. We
vonden het een leuke uitdaging en we waren benieuwd naar het
resultaat (net zoals de leerkrachten van praktijk). We zochten
informatie op het internet en daaruit bleek dat het nog niet zo
simpel zou zijn.

De dag nadien namen we echter de proef op de som. Met een
decoupeerzaag zaagden we een stukje carbon van de
carbonplaat en het resultaat was positief. Het carbon rafelde niet
uit zoals een leerkracht dacht. Het zagen erin maakte wel een
scherp geluid dat door merg en been ging, maar het resultaat
was in orde en dat was het belangrijkste.

Nadien hebben we de baseplates
uitgezaagd uit het carbon en er de
boringen in aangebracht. Dit bleek
allemaal geen probleem te zijn en we
kregen dan ook dit resultaat.
Hierna hebben we het positieve nieuws
meegedeeld aan de leerkrachten
praktijk, zij waren immers verrast door
het resultaat.




Pagina 34


fig. 2.9: Het maken van het kartonnen frame
fig. 2.10: Het kartonnen frame, schaal 1:1
fig. 2.11 a,b,c: Ons afgewerkt kartonnen frame
2.3 Het kartonnen frame

Voor we de aluminium armen lieten maken en het carbon gekocht hadden,
wilden we zeker zijn dat onze technische tekeningen juist waren en wilden we
ook eens zien hoe het frame er ongeveer zal gaan uitzien. Om een eenvoudige
voorstelling te geven van het frame, besloten we om een kartonnen versie te
maken. Dit was een goedkope en simpele manier.





Zoals te zien is op de fotos, komen het
aluminium frame en het kartonnen
frame perfect overeen met elkaar. Hier
stonden de aluminium stand-offs en de
deckplaat nog niet op de frames.







Voor een echt goede weergave hebben we later ook de aluminium stand-offs
en de deckplaat op het kartonnen frame geplaatst.







Pagina 35


fig. 2.12: De 2 soorten stand-offs
2.4 De stand-offs

We hebben 2 soorten stand-offs, namelijk nylon stand-offs (1) om het
powerboard en het geheugenbord te bevestigen aan de baseplates en de
armen, en aluminium stand-offs (2) om de deckplaat te bevestigen aan de
boven baseplate.








Pagina 36


fig. 2.13: De nylon stand-offs
fig. 2.14: Stand-offs gemonteerd op het frame
2.4.1 De nylon stand-offs





De nylon stand-offs (1) dienen om het powerboard (2) en het geheugenbord
(3) aan het frame (4) te bevestigen. We kozen hier niet voor aluminium
stand-offs omdat nylon een lichter materiaal is.

De nylon stand-offs zijn goedkoop en gemakkelijk verkrijgbaar. We moeten er
ook geen verdere bewerkingen meer aan uitvoeren.

De lengte van de stand-offs is 10 mm. Dit omdat we zo gemakkelijk het
powerboard en het geheugenbord nog kunnen monteren op het frame.
Verder gebruiken we plastieken bouten om alles aan elkaar te monteren.






Pagina 37


fig. 2.15: De aluminium stand-offs
fig. 2.16: Stand-offs gemonteerd op het frame
2.4.2 De aluminium stand-offs





De aluminium stand-offs (1) dienen om de deckplaat (2) aan het frame (3) te
bevestigen.Hier kozen we voor aluminium stand-offs omdat aluminium stevig
is en het een mooier design geeft aan de quadrocopter dan nylon stand-offs.
De nylon stand-offs zijn trouwens veel minder zichtbaar zijn dan de
aluminium stand-offs.

De aluminium stand-offs hebben we zelf uitgetekend en laten maken op
school. Opnieuw zijn we het VTI-Brugge daar erg dankbaar voor.

De lengte van de aluminium stand-offs is 49 mm. Daardoor hebben we nog
voldoende ruimte om eventuele aanpassingen te doen aan het geheugenbord.




Pagina 38


fig. 2.17: Deckplate
2.5 De deckplaat

De deckplaat heeft als functie het
geheugenbord en het powerboard te
beschermen. De deckplaat moet dus stevig
zijn. Daarom kozen we ervoor om de
deckplaat te maken uit carbon en die te
bevestigen op stevige aluminium stand-offs.

Ook hier is de dikte van de carbonplaat 1,5
mm. Dit omdat het goedkoper is om twee
carbonplaten van 1,5 mm te kopen (de twee
baseplates en het deck konden niet gemaakt
worden uit n carbonplaat), dan n
carbonplaat van 1,5 mm en n carbonplaat
van 2 mm.

We hadden eerst gedacht aan 2 mm dikte voor de deckplaat, dit was voor
extra stevigheid, voor als de quadrocopter zou crashen.

De grote gaten met diameter 8 mm zijn ook voor gewichtsbesparing net als de
grote gaten in de aluminium armen (zie punt 2.1).




Pagina 39


fig. 2.18: Inventor: hoe alles gemonteerd wordt
2.6 Montage

De meeste boringen hebben een diameter van 3 mm. Dit komt omdat het
goedkoper is om allemaal M3-bouten, moeren en sluitingsringen te kopen dan
bouten en moeren met een verschillende diameter. Ook waren de nylon stand-
offs gemakkelijk verkrijgbaar met gaten van 3 mm. De grote gaten in de
aluminium armen en de deckplaat zijn voor gewichtsbesparing. Daar moeten
geen bouten in aangebracht worden.

Het frame moet als volgt gemonteerd worden:






Pagina 40


fig. 2.19a: Inventor: afgewerkte quadrocopter getekend (schuin zicht)
fig. 2.19b: Inventor: afgewerkte quadrocopter getekend (zijaanzicht)









Zoals te zien is op de fotos komen de armen niet tot het midden van de
baseplates. Dit komt omdat de verbinding tussen het powerboard en de
batterij langs daar gebeurt.

Nadat we alle onderdelen gemonteerd hadden, zagen we dat het totaalgewicht
van het frame 330 gram was.







Pagina 41


fig. 3.1: Schematische voorstelling van de elektronica
Hoofdstuk 3: De bouw

In dit hoofdstuk worden de onderdelen besproken die we op het frame hebben
geplaatst. Hieronder ziet u het schakelschema van de gebruikte componenten.
Deze componenten zullen nu n voor n worden besproken.







Pagina 42


fig. 3.2: Onze 3S LiPo batterij
3.1 De batterij

De batterij heeft als functie om
alles van elektriciteit te voorzien
in de quadrocopter. Wij kozen
voor een lithium-ion-polymeer
batterij of kortweg LiPo batterij
genoemd. Dit omdat zon LiPo
batterij een groot vermogen kan leveren voor een batterij met een klein
gewicht. Een LiPo batterij heeft ook een lage interne weerstand waardoor de
batterij een hoge stroom kan afgeven.

We kozen voor een 3S 2400mAh 20C LiPo batterij.

De batterij wordt rechtstreeks verbonden met het powerboard en wordt
bevestigt onderaan de onderste baseplate.



3.1.1 LiPo accu t.o.v. NiMh accu

Het bijzondere aan LiPo accus is dat ze t.o.v. NiMh accus een hogere
spanning hebben. Ze kunnen ook bij veel hogere belastingen toch hun
verwachte capaciteit halen.

Verder is de inwendige weerstand zeer laag bij een LiPo batterij waardoor ze
uitermate geschikt zijn voor modelbouw. De batterij blijft zelfs bij een hoge
belasting dezelfde spanning geven. Een NiMh accu zou dan allang ingestort
zijn onder de benodigde spanning.

De lage inwendige weerstand in een LiPo accu heeft tot gevolg dat er weinig
verlies is, en dus ook weinig warmte ontwikkeling.

Een LiPo accu is ook super licht. Onze LiPo weegt 187 gram. Dat is veel
minder dan een normale NiMh accu zou wegen.








Pagina 43


fig. 3.3: Schematische voorstelling van een 3S LiPo
3.1.2 Soorten LiPo batterijen




Er zijn verschillende soorten LiPo
batterijen. Het verschil zit hem in de
schakeling van de cellen. De cellen
kunnen in serie, in parallel of
gemengd staan.





Een enkele LiPo cel zal 3,7V (nominale spanning) geven. Als je dezelfde cellen
combineert, kan je de spanning opdrijven door de cellen in serie te schakelen.
Wanneer je ze in parallel zet, vergroot je de capaciteit. Hoe groter de
capaciteit, hoe langer je met eenzelfde accu zult kunnen vliegen.

Wij hebben gekozen voor een 3S LiPo batterij. Dit is dus een batterij die 3
cellen in serie heeft staan. Deze zal dus 3 x 3,7V = 11,1V nominale spanning
geven.

We hebben geen cellen in parallel nodig. Dit komt omdat we met onze
2400mAh een lange tijd 4 motoren kunnen aansturen.



3.1.3 C-waarde
Toch is er nog een groot verschil in LiPo accus. Niet alle LiPos zijn even
geschikt om een groote stroom te kunnen leveren. Bij een LiPo accu hoort er
namelijk een C-waarde. In ons geval is dit 20C. Deze C staat voor het aantal
maal de capaciteit wat een accu als continue stroom mag leveren. 20C
betekent dus 20 keer de capaciteit.

Onze accu van 2400mAh 20C mag dus 48000mA of 48A continu leveren.

Er staat ook vermeld welke piekstromen de batterij kan leveren. Bij ons is dit
tot 25C. Onze batterij kan dus tot 60A piekstroom leveren. Dit moet wel van
korte duur zijn.






Pagina 44


fig. 3.4: Laadcurve van een LiPo batterij
3.1.4 Laden

Het laden van een LiPo batterij moet op een speciale manier gebeuren. Bij een
NiMh accu zal de spanning tijdens het laden eerst oplopen en daarna (bij het
bereiken van de maximale laadtoestand) terug afnemen. Dit is het moment
waarop de lader afslaat.

Bij een LiPo batterij zal tijdens het laden
de spanning blijven toenemen. De
spanning van een LiPo cel mag echter
nooit boven 4,21V komen. De batterij
zal eerst zijn 4,21V opbouwen, waarna
langzaam de stroom zal dalen. Wanneer
je nadat de stroom 0A bedraagt
blijft verder opladen, gaat de cel kapot
en kan er zelfs brand ontstaan.

Een LiPo lader werkt daarom ook anders dan een NiMh lader.
Een NiMh lader laadt met een constant amprage tot de accu vol is. Dan slaat
de lader af.
Een LiPo lader laadt in het begin met een hoog amprage en naarmate de
spanning van de cel dichter bij de 4,21V per cel komt, neemt het amprage af.
Wanneer de stroom de 0A bereikt is de batterij volledig opgeladen en zal de
lader automatisch afslaan.

Bij de moderne laders wordt niet alleen naar de totale spanning gekeken,
maar ook naar de onderlinge spanning in elke cel. Een LiPo batterij heeft ook
nog kleine aansluitingen. Deze zijn verbonen tussen de cellen door, om zo de
spanning per cel te kunnen meten. Een LiPo accu heeft dus niet alleen de plus
en min aansluiting waar de lader op aangesloten wordt, maar ook een paar
dunnere draden met een speciale kleine stekker die naar de balancer ingang
van de lader gaat. Daarmee kan de lader de spanning van elke cel apart
meten en aan de hand daarvan het laadproces aanpassen zodat alle cellen
even snel opladen.

3.2.5 Balanceren

De cellen zullen niet tegelijk ontladen. Dit zal nagenoeg wel gelijk lopen, maar
er zal altijd een verschil ontstaan. Dit komt omdat de interne weerstand niet
helemaal dezelfde is.

Bij grootte batterijen kan dit problemen geven en kun je tussendoor
balanceren. Dit wordt gedaan om de grote verschilspanningen weg te werken.

Bij ons is dat niet nodig.




Pagina 45


fig. 3.5: Ontlaadcurve van een LiPo batterij
3.1.6 Ontladen

Een LiPo batterij kan nooit helemaal ontladen worden. Dit betekent in de
praktijk dat wanneer wij met zon accu vliegen en het begint af te nemen, we
onmiddellijk moeten stoppen met vliegen.

Onze LiPo batterij is opgebouwd uit 3 cellen. Wanneer er n cel op de
ondergrens is en de andere cellen niet en je zou nog doorgaan met ontladen,
is de lege cel vrijwel direct kapot. Zeker bij een hoge belasting.

De duurdere LiPo batterijen kan je tijdens het ontladen ook aansluiten op een
balancer. Dit is een speciaal ontlaadprogramma waarbij de interne weerstand
wordt aangepast (vergroot), zodat de rest van de cellen rapper zullen
ontladen. Dit is om te voorkomen dat n van de cellen onder de 2,5V komt.
Wanneer hij onder de 2,5V komt zouden de condensatoren beschadigt kunnen
raken. Om er zeker van te zijn dat we de batterij niet kapot zullen maken,
werken we met een veiligheidsgrens van 0,5V. Verder bestaan er ook speciale
LiPo veiligheidsschakelaars. Die worden tussen de ontvanger en de regelaar
geplaatst om zo deze taak over te nemen. Hierdoor kan men toch nog op een
veilige manier met LiPo batterijen vliegen zonder dat er gevaar is voor het te
diep ontladen. Hieronder staat de ontlaadgrafiek van een LiPo-batterij. De
batterij mag nog verder ontlaadt worden onder 1/8, maar daarna gaat de
spanning snel achteruit en kom je dicht bij de gevarenzone van 3V. Bij 1/8 is
het tijd om te landen en te herladen.







Pagina 46


3.1.7 Opslaan
LiPo accus kunnen theoretisch het best half-opgeladen opgeborgen worden.
Dit heeft te maken met de chemische samenstelling van de accu. Door het
chemische verschil tussen de anode en kathode kan inwendige corrosie
optreden. Bij een half-opgeladen accu (celspanning 3.7V) is dit verschijnsel
het kleinst.
De meeste LiPo laders hebben een programma waarbij je op kan geven
hoeveel mAh er maximaal geladen mag worden. Door de accu leeg te maken
en deze waarde op de helft van de capaciteit in te stellen, zal de lader
automatisch afslaan zodra de helft van de capaciteit bereikt is. De meeste
moderne laders hebben zelfs een zogenaamde "storage mode", waarin de
lader de spanning door het laden of ontladen automatisch naar 3.7V per cel
brengt.

Daarbij hoor je een LiPo accu die langere tijd niet gebruikt wordt, elke 2 3
maanden dan weer een beetje bij te laden, want als de accu echt leeg gaat,
kan hij kapot gaan. Het is dus ook aangeraden bij lange inactiviteit, af en toe
eens de accu te herladen.

In de praktijk gebeurt dit half opgeladen wegleggen niet zo vaak. Het is beter
om de LiPo voor 50-80% weg te leggen. Dan is het risico dat hij door eigen
ontlading te diep ontlaadt kleiner en kan hij ook niet te ver opladen door
omgevingsspanningen wat brand zou kunnen veroorzaken.

3.1.8 Veiligheid
LiPo accu's bevatten in een klein pakketje een enorme concentratie van
energie. Daar moet men bewust mee omgaan. De oudere LiPo accu's waren
heel erg gevoelig voor mishandeling. Bij het kleinste foutje ging het mis en
wel op een heel heftige manier. Tegenwoordig zijn de LiPo accus veel
gebruiksvriendelijker en beter bestand tegen het niet goed behandelen, maar
men moet er wel nog met respect mee omgaan en goed opletten wat men
ermee doet.

LiPo accu's die op de juiste manier geladen en gebruikt worden, hoeven geen
enkel probleem te geven, maar zorg er bijvoorbeeld voor dat er geen
kortsluiting kan ontstaan. Als je bij het werken met een LiPo accu kortstondig
kortsluiting maakt, gaat er direct een dusdanig hoge stroom lopen, dat de
contactpunten direct aan elkaar "gepuntlast" worden en kun je de
kortsluitverbinding haast niet meer loskrijgen met alle gevolgen van dien. Op
zo een moment kan een LiPo batterij gevaarlijk worden.
Theoretisch zou het met laden ook verkeerd kunnen gaan. Wanneer de lader
bijvoorbeeld niet op tijd af zou slaan, of wanneer je iets verkeerd ingesteld
zou hebben. Daarom is het altijd verstandig om in de buurt te zijn wanneer de
LiPo batterij oplaadt.





Pagina 47


fig. 3.6: Ons powerboard
fig. 3.7: Connectors aan het powerboard solderen
fig. 3.8: Powerboard gemonteerd op het frame
3.2 Het powerboard

Het powerboard verdeeld de stroom en
spanning over de onderdelen die ervan
voorzien moeten worden. Zoals je kunt zien
zijn er verschillende aansluitingen. Acht
gewone aansluitingen (+ en -) en n keer
een grote aansluiting naar de batterij (1).
Van daar komt namelijk alle elektriciteit die
dan verdeeld wordt over de aansluitingen.
Aan deze grote aansluiting zijn de kabels
reeds aangesloten.

We hebben wel nog de connector
(zie afbeelding hiernaast) moeten
solderen aan de laadkabel en het
powerboard. Zo kunnen we de
batterij rechtstreeks aansluiten op
het powerboard. Dit is een
connector die er ook voor zorgt dat
je hem niet omgekeerd kan
aansluiten (+ aan klem en aan
+ klem)

Zoals gezegd zijn er acht gewone
aansluitingen. Vier ervan zullen in
verbinding staan met de
snelheidsregelaars (ESCs). Voor
elke ESC is er een aansluiting
voorzien. Verder is er ook nog een
aansluiting voorzien voor de UBEC
en een aansluiting voor de
ledlampen.

Het powerboard hebben wij op de
nylon stand-offs geplaatst. Net
boven de boven-baseplate en onder
de deckplaat zoals zichtbaar is op
de afbeelding hiernaast.

Het powerboard weegt verder
34gram (zonder de bekabeling).
Het heeft 3,5mm vrouwelijke aansluitingen, en de ESCs hebben mannelijke
aansluitingen. Dit is dus makkelijk te monteren zonder al te veel problemen.





Pagina 48


fig. 3.9: De ESC (snelheidsregelaar)
3.3 De snelheidsregelaars (ESCs)

De snelheidsregelaars (Elektronic Speed Controllers) hebben als functie om de
snelheid van de motoren te regelen en aan te
sturen. Ze worden verbonden aan de ene
kant met de motoren (1) en aan de andere
kant met het powerboard (2) en het
geheugenbord (3). De connecties naar de
motoren komen overeen met de connecties
van de motoren zelf. Hier hebben we dus
geen problemen bij het monteren.

Onze ESCs zijn geschikt voor LiPo batterijen met 2,3 of 4 cellen. Onze batterij
heeft 3 cellen.

De ESCs bij ons hebben geen BEC. Ze noemen dus Opto-ESCs (ook wel
optocoupler ESC genoemd). Het verschil tussen een ESC met een BEC en
zonder BEC ligt bij de extra voeding voor de elektronica (5V). Een ESC met
een BEC zal via de regelaar nog spanning zal sturen naar de elektronica om zo
bijvoorbeeld het controllerbordje te voeden. Bij een optocoupler is er geen
BEC aanwezig, en heb je dus een externe voeding nodig voor de elektronica

Wanneer je verschillende BECs zou gebruiken en dus verschillende keren
voeding zou sturen naar de elektronica, kan dit onderling conflicten geven.
Daarom wordt er aangeraden maar n BEC te gebruiken. Dat zou dus willen
zeggen n ESC met een BEC en dan 3 Opto-ESCs. Verschillende ESCs
combineren kan echter zorgen voor een slechte stabilisatie omdat niet alle
ESCs op dezelfde manier geijkt worden.

Wij kiezen daarom voor een aparte BEC om zo het motorcircuit en het
ontvangercircuit volledig van elkaar te scheiden. Daardoor zijn er minder
problemen met storingen van motor en regelaar die in de regelkring terecht
kunnen komen. Bij dit type is er dus nog een aparte voeding nodig voor de
elektronica. Deze wordt later besproken.







Pagina 49


fig. 3.10: Brushless DC-motor
3.4 De motoren

Bij een quadrocopter zijn er uiteraard vier motoren
aanwezig. Telkens op het uiteinde van iedere arm.
Daarop wordt er telkens een propeller bevestigt.
De motoren worden aangesloten aan de ESCs.

Wij kozen voor brushless DC-motoren in plaats van brushed DC-motoren.
Het verschil is dat bij brushless DC-motoren de overdracht van energie
elektronisch gebeurt (borstelloos) terwijl dat bij brushed DC-motoren wel met
borstels gebeurt.
We maken even de vergelijking tussen deze 2 elektrische motoren:
Brushless DC-motor Brushed DC-motor
Wrijving Geen Veel
Rendement Hoog Laag
Geluid Weinig Boog in de borstels
Onderhoud Minimaal Regelmatig
Duurzaamheid Uitstekend Minder
Omschakeling Elektronische omschakeling
gebaseerd op positiesensoren
met Hall-effect sensors
Omschakeling door borstels
Efficintie Hoog. De spanning kan niet
dalen door de borstels.
Matig
Kracht van de
uitlaat/grootte
Hoog. Beperkte grootte door
betere thermische
eigenschappen; Omzetting van
warmte is gemakkelijker
doordat er wikkelingen in de
stator zijn, die zich in het skelet
bevindt.
Laag. De warmte wordt
omgezet aan de binnenkant
van het skelet, waardoor de
temperatuur stijgt en de
eigenschappen beperkt
zijn.
Traagheid van
de rotor
Beperkt door duurzame
magneten in de rotor
Hoog.
Beperkt de dynamische
eigenschappen.
Versnellingen Snel. Zonder mechanische
beperkingen door borstels of
omschakeling.
Traag. Beperkt door
borstels.
Koppel Vlak. Werkt op volle snelheid
met de juiste last.
Matig. Bij hoge snelheid is
er meer wrijving van de
borstels en het koppel
vermindert.

Het is duidelijk dat brushless DC-motoren beter zijn dan brushed DC-motoren.
Brushless DC-motoren zijn wel duurder maar toch kozen wij voor dit type
motor omdat een brushless DC-motor zeer snel van toerental kan veranderen.
Dit is zeker nodig om goed te kunnen stabiliseren.




Pagina 50


fig. 3.11: Schematische voorstelling DC-motor
3.4.1 Werking van een brushless DC-motor

Een brushless of borstelloze motor is een motor die zonder koolborstels werkt.
De wikkelingen zitten in het huis en de magneten zitten op de ronddraaiende
as gemonteerd (de rotor).

Omdat zo'n motor dus geen koolborstels en geen collector heeft, moet de
motor aangestuurd worden met een speciale regelaar. Die zorgt ervoor dat de
spoelen in de motor (velden) precies op het juiste moment stroom krijgen
zodat de magneten van de rotor op het goede moment aangetrokken of
afgestoten worden.

Moderne regelaars hebben soms zelfs een LiPo programma ingebouwd. LiPo
batterijen mogen namelijk nooit diep ontladen worden (zie 3.1). De regelaar
schakelt zichzelf dan naar een lagere vermogen of zelfs helemaal uit indien
nodig wanneer de spanning een kritische ondergrens dreigt te bereiken.

Zoals gezegd wordt een borstelloze motor op een
speciale manier aangestuurd. Hierbij moet de
regelaar de 3 spoelen (A, B en C) precies op de
juiste manier en frequentie aansturen zodat de
magneet van de rotor op het juiste moment
aangetrokken of afgestoten wordt. Daardoor zal
de rotor draaien. Hoe meer toeren de motor
maakt, hoe sneller de regelaar de spoelen moet
aansturen. De regelaar moet dus op elk moment
"weten" in welke positie de rotor staat t.o.v. de
spoelen.

Om dat te weten kan dit op twee manieren: Met een sensorloze motor of via
een motor met sensor. Wij zitten in het eerste geval.






Pagina 51


Een sensorloze motor:
Een brushless DC-motor is eigenlijk een draaiveldmotor. Hij wordt met
permanente magneten aangestuurd. Zodra de borstelloze motor draait,
verandert de langskomende magneet de stroom door de spoel een beetje. De
stroom is dus veranderd. Dat kan de regelaar gebruiken om te bepalen waar
de magneten zich bevinden en dus ook hoe de spoel op dat moment
aangestuurd moet worden. Dit proces noemt men sensorloos. Het voordeel
van dit systeem is dat het heel erg efficint is en hele hoge toerentallen en
grote vermogens kan leveren.
Het nadeel was tot voor kort dat de motor al "even" moest draaien voor de
regelaar de motor optimaal kan aansturen. Bij auto's moet voor elke beweging
die de motor wil maken de hele auto direct mee verplaatst worden. Auto's
moeten bovendien snel accelereren, hard remmen en weer van stilstand of
lage snelheid weg trekken. De eerste sensorloze motoren hadden hier
problemen mee dus werd er een nieuw soort sensorloze motor/regelaar
ontwikkeld.

Bij de nieuwe soort motoren zonder sensor wordt een veel nauwkeurigere
meettechniek gebruikt. Die meettechniek laat probleemloos een auto
wegrijden en een gelijkwaardige acceleratie vanuit laag toerental uitvoeren
zoals bij een motor met een sensor, maar gekoppeld aan de hogere efficiency
en hogere topsnelheid van een sensorloze motor.
Dit is mogelijk gemaakt door een speciaal ontwikkelde chip en bijpassende
software.
Verder worden motoren zonder sensor alleen maar met 3 dikke stroomdraden
op de regelaar aangesloten. Dit wil zeggen met 3 paar spoelen.

Een motor met een sensor:
Voordat de 2e generatie sensorloze motor/regelaar in combinatie ontwikkeld
was, werd de motor met sensor gebruikt om bijvoorbeeld het startprobleem
bij auto's op te lossen. Er werd speciaal hiervoor een motor/regelaar systeem
ontwikkeld met 3 ingebouwde HAL sensoren die aan de regelaar feedback
geven in welke stand het anker staat en in welke richting hij draait. Dit kan
ervoor zorgen dat de motor nauwkeuriger geregeld kan worden qua positie,
stroom, en dus ook de snelheid. Dit geeft een minder aarzelende acceleratie
en een hoger koppel op lage toeren t.o.v. de eerste generatie borstelloze
regelaars. Het feit dat motoren met sensor een wat lagere efficientie en een
mindere topsnelheid hebben dan sensorloze motoren, werd ruimschoots
goedgemaakt door de betere eigenschappen. Deze motoren worden op de
regelaar aangesloten met de gebruikelijke 3 dikke stroomdraden en met een 5
of 6 aderige dunne bedrading met stekker voor de sensoren.






Pagina 52


3.4.2 Specificaties

Onze motoren hebben 930KV. Dit wil zeggen dat ze zonder weerstand 930
toeren per volt kunnen draaien. Aangezien onze batterij een spanning levert
van 11,1V kunnen onze motoren in perfecte omstandigheden 10323 toeren
leveren ( ). Met enige weerstand meegerekend bij
het opstijgen en het veranderen van de richting zullen de motoren maximaal
10000 toeren leveren. Verder zal het verlies ook toenemen in de motor
wanneer hij zijn maximum toerental bereikt. Wij hebben minder toeren nodig
om onze quadrocopter te laten vliegen maar hoe hoger het toerental is, hoe
sneller de quadrocopter verticaal in de lucht kan vliegen. Het is niet de
bedoeling om een te zware motor te nemen, want dan zal je een motor
hebben die aan een zeer laag toerental bjna geen koppel meer zal hebben.

De maximum thrust is 550 gram en de bijbehorende propellers zijn DJI 10x3.8
/ DJI 8x4.5 en DJI 10x4. Onze propellers zijn van het merk DJI type 10x3.8.
Verder is er ook smooth throttle en linear throttle aanwezig. Throttle zorgt
ervoor dat de snelheid in verhouding beperkt en bijgeregeld kan worden van
de motoren. Dit gebeurt via de afstandsbediening.






Pagina 53


fig. 3.12: Liftkracht
3.5 De propellers
3.5.1 Liftkracht

De liftkracht is de kracht die loodrecht op de propeller inwerkt.
Deze kracht is dus ongeveer tegengesteld aan de
gravitatiekracht. De liftkracht zorgt ervoor dat de
quadrocopter omhoog blijft. Liftkracht is het gevolg van
verscheidene effecten zoals de reactiekracht van de
luchtstroom op het oppervlak, het Bernoulli-effect en het
Coand-effect.

Het effect van de reactiekracht is als
volgt uit te leggen. Een vlakke plaat die
een hoek maakt met de luchtstroom,
zodat de luchtstroom aan de onderzijde
van de plaat wordt afgebogen naar
beneden toe, ondervindt behalve een
wrijvingskracht

in de richting van de
stroom, ook een naar boven gerichte
kracht. Deze kracht is de liftkracht

.

Een vlakke vleugel is echter om meerdere redenen niet optimaal. Naast de
vereiste kracht veroorzaakt een vlakke plaat ook turbulentie en
luchtweerstand. Uit vele experimenten en berekeningen is gebleken dat de
bovenkant van de vleugel beter een bolle vorm kan hebben. De luchtstroom
volgt het vleugeloppervlak en buigt hierdoor ook aan de bovenkant van de
vleugel naar beneden (dit is het Coand-effect). Zonder deze bolle vorm zou
de luchtstroom boven de vleugel bij een kleinere
invalshoek () al gewoon rechtdoor gaan en
zouden er luchtwervelingen ontstaan. Deze
turbulentie werkt remmend en omdat de lucht
aan de bovenkant van de vleugel niet meer
afgebogen wordt, is er ook minder liftkracht.


fig. 3.13: Liftkracht met reactiekrachten
fig. 3.14: Voorstelling invalshoek




Pagina 54


De luchtsnelheidsverschillen boven en onder een vleugelprofiel kunnen met
behulp van de Wet van Bernoulli worden omgerekend in drukverschillen, die
ook weer liftkracht veroorzaken.




De wet van Bernoulli:


Hierbij is:
v = de snelheid (m/s)
g = de valversnelling (m/s)
h = het hoogteverschil (m)
p = de druk (Pa)
= de massadichtheid (kg/m)

In de formule zien we
- de kinetische energiedichtheid of dynamische druk:


- de atmosferische druk: .

Omgerekend naar lengte-eenheden levert dit voor het totale energieniveau
van de stromende vloeistof:

[m]

Hierbij is:

= de snelheidscomponent

= de stijghoogte.


fig. 3.15: Voorstelling drukverschil op een vleugel




Pagina 55


De verplaatsing van de vleugel door de lucht veroorzaakt aan de onderkant
van de vleugel een overdruk en aan de bovenkant van de vleugel een
onderdruk. Deze drukverschillen veroorzaken zelf nog een extra effect. De
lucht aan de onderkant van de vleugel wordt door de overdruk ter plaatse
afgeremd. Door de onderdruk boven de vleugel wordt de lucht naar de
bovenkant van de vleugel gezogen. Dit veroorzaakt een grotere snelheid van
de lucht boven de vleugel dan er onder. Daardoor ontstaat de liftkracht
ongeveer 2/3 aan de bovenkant van de vleugel en 1/3 aan de onderkant.

In onderstaande figuur is een doorsnede van een vleugelprofiel getekend.
De luchtstroom is getekend in het groen. Dit is het pad dat luchtdeeltjes
afleggen als zij langs de vleugel stromen. In de lucht ver vr de vleugel
(rechts) zijn ze op gelijke afstand getekend. Als de stroomlijnen dichter bij
elkaar gaan lopen en de dichtheid blijft (ongeveer) gelijk, betekent dit dat de
deeltjes sneller gaan stromen. De luchtsnelheid en stromingsrichting zijn
aangegeven met de blauwe pijlen. De rode pijlen geven een indicatie van de
onderdruk boven de vleugel en de overdruk onder de vleugel. Tenslotte geeft
de paarse pijl de totale liftkracht weer en de grijze de weerstand. Men
probeert de stromingsweerstand altijd zo laag mogelijk te houden.





fig. 3.16: Totale voorstelling werking van een vleugel




Pagina 56


3.5.2 Liftformule

De liftkracht L wordt als volgt berekend:


Hierbij is:
= de dichtheid van lucht (kg/m
3
)
v = de luchtsnelheid (m/s) (t.o.v. het opgelifte deel)
s = het oppervlak (in m
2
) van het opgelifte deel

= de liftcofficint t.o.v. (aanstroomhoek)



Uit de liftformule kunnen we dan de liftcofficint bepalen:



In bovenstaande grafiek is de liftcofficint als functie van de aanstroomhoek
gegeven. De aanstroomhoek is de hoek die de onbenvloede stroming maakt
met de koorde van de vleugel.



C
L
heeft voor veel profielen al een positieve waarde bij een aanstroomhoek
van 0. Dat komt doordat de stroming over de gebogen achterkant al naar
onder wordt afgebogen als de koorde van de vleugel evenwijdig met de
stroming staat. Bij een bepaalde kritische hoek (10 20) neemt de liftkracht
plotseling zeer sterk af. De curve is specifiek voor een bepaald profiel, maar
heeft voor goede ontwerpen wel altijd ongeveer deze vorm.


fig. 3.17: Karakteristiek van de liftcofficint
fig. 3.18: Voorstelling koorde of invalshoek




Pagina 57


3.5.3 Specificaties

Wij hebben DJI 10x3.8 propellers. Deze zijn zoals al eerder gezegd, passend
bij onze brushless motoren. De propellers zijn van het merk DJI en zijn 10inch
lang. Ze hebben een kromming van 3,8. We gebruiken 4 propellers. 2
propellers draaien in wijzerzin (oranje) en 2 in tegenwijzerzin (geel).








fig. 3.19: Draairichting propellers




Pagina 58


3.6 De UBEC

De UBEC zorgt ervoor dat de spanning
van de batterij (11,1V) wordt omgezet
naar 5V voor de receiver en het
geheugenbord. De UBEC is dus een
soort kleine transformator.

3.6.1 Verschil tussen BEC en UBEC

De BEC is lineair terwijl de UBEC beschouwd wordt als een schakelende BEC.
De BEC heeft een betere ongestoorde signaalspanning en is goedkoper te
produceren. Ze zijn wel minder efficint en maken hogere temperaturen aan
bij grotere spanningen. De UBEC daarentegen is efficinter en koeler bij
hogere spanningen. Anderzijds hebben zij dan weer een verhoogd aantal
componenten zodat ze duurder zijn om te produceren.


fig. 3.20: De UBEC




Pagina 59


3.7 De zender en ontvanger
We hebben voor een zender en ontvanger gekozen die we van een vriend te
leen hebben gekregen. Beiden zijn van het merk Planet.

3.7.1 De frequentie

De zender moet draadloos met de ontvanger kunnen communiceren. Dit
gebeurt via een bepaalde frequentie. Voor modelbouw zijn er verschillende
frequenties legaal in Belgi (en Nederland):

35 MHz en 40 MHz: Deze frequentiebanden zijn uitsluitend gereserveerd voor
modelbouwvliegtuigen. Er is wel een nadeel aan verbonden. Wanneer je met
meerdere mensen samen vliegt kan je elkaars signaal storen en dus de
controle over je vliegtuig (tijdelijk) verliezen.

2,4 GHz: In het frequentiebereik van 2400 tot 2483,5MHz is het besturen van
modelbouwvliegtuigen toegestaan. Dit is een heel brede band waarin de
zender en ontvanger zelf een vrije frequentie zullen zoeken en deze
regelmatig veranderen waardoor er bijna geen sprake is van storing. Dit heeft
dus als gevolg dat je geen last hebt van andere medemodelbouwers.

3.7.2 De zender

Deze zender werkt op 4 oplaadbare batterijen. Er is
een aansluiting voorzien voor een oplader waardoor er
geen extra batterijlader nodig is.

De zender heeft een schermpje waar de spanning van
de batterijen op af te lezen is. Zo kan je op elk
moment weten hoe ver je batterij ontladen is. Het is de
bedoeling dat je de batterijen nooit onder de 4,6V laat
komen want anders kan je signaal verstoord zijn.

De zender heeft 5 kanalen. De kanalen 1 tot 4 dienen
voor het besturen van de quadrocopter in de 4
mogelijke richtingen (throttle, yaw, roll en pitch). Dit
wordt gedaan door de 2 sticks.
De linkse stick dient voor de throttle () en de yaw
().
De rechtste stick dient als roll () en pitch ().

Het 5
e
kanaal is een tweestandenschakelaar. Hiermee
zullen we de schakelaar bedienen die de ledlampjes
aan en uit zet.
fig. 3.21: De zender




Pagina 60


3.7.3 De ontvanger

De ontvanger heeft 7 connecties. 6 kanalen en nog een
extra ingang die voorzien is voor de voedingsingang.
De ontvanger werkt net zoals de rest van de
elektronica op 5V. We kunnen hierop dus de UBEC
aansluiten.

De kanalen 1 tot 4 zijn verbonden met het controllerbordje. Deze 4 signalen
dienen om de quadrocopter te bewegen in de richting die aangegeven is met
de 2 sticks van de zender.

Het 5e kanaal verbinden we met de schakelaar (transistor) die de ledlampjes
aan en uit schakelen.


fig. 3.22: De ontvanger




Pagina 61


3.8 Het controllerbordje


Dit controllerbordje zorgt voor de werking van de quadrocopter. Het is een
soort computer die aan de hand van sensoren en inputs (van de zender) de
motoren een bepaald toerental zal laten draaien.

Naast de motoren bedienen is er zijn er ook nog tal van extras om het vliegen
te vergemakkelijken. Een optie is bijvoorbeeld om een camera te bedienen.
Dit alles gebeurd in de processor.

Op dit bordje zit een Atmega 328P processor. Deze is helemaal
programmeerbaar en kunnen we dus een functie geven die we zelf willen. In
dit geval dus het vliegen en besturen van de quadrocopter. Het bordje zelf
moet gevoed worden met 5V. Dit is dus afkomstig van de UBEC (via de
zender) zoals al eerder besproken.

3.8.1 Voltage level converter TXS0102
De sensoren werken allemaal op 3,3V. Ons controller
bordje sturen we aan met 5V. Dit wordt door deze
transistor nog eens opgesplitst naar 3,3V. Om dit te
controleren staan er 2 ledlampjes op ons bordje die de
aanwezigheid van 3,3V en 5V aanduiden.

fig. 3.23: Het controllerbordje
fig. 3.24: Voltage level converter




Pagina 62


3.8.2 Sensoren:
Gyro ITG3205
Wat?
Een gyrometer (gyroscoop) meet de hellingshoek
van de quadrocopter over n van zijn assen. Dit is
nodig bij de sturing om de quadrocopter van richting
te doen veranderen bij het manueel bedienen via de
afstandsbediening. Deze gyro heeft als voordeel dat
hij de hellingshoek in de 3 richtingen meet. Dus
zowel voor de x, y als z-as. Met de gyrometer weten
we dus onder welke hoek de quadrocopter zich
bevind.

Werking?
Een gyro is een piezo-element die bij elke verbuiging
(door middel van rotatie van onze quadrocopter) een
spanningsverschil teweeg brengt tijdens dat het
elementje vervormd (verbogen rond een as) wordt.
Deze spanning wordt door de gyrometer opgemeten en
omgezet in een beweging van de quadrocopter rond
zijn assen.
Accelerometer BMA180
Wat?
Een accelerometer is bijna hetzelfde als een
gyrometer. De accelerometer meet net zoals de
gyrometer de hellingshoek, maar dan niet de
absolute hoek, maar de verandering van hoek. De
verandering van hoek wordt gebruikt om zo snel
mogelijk na een beweging terug naar zijn evenwicht
te komen. Deze accelerometer werkt net zoals de
gyrometer voor alle richtingen: x, y, z-richting.

Werking?
Een accelerometer maakt gebruik van het
traagheidsprincipe. Het is gebaseerd op de mechanische
versnellingsmeter. Het is een gewichtje dat verend is
opgehangen. Als de quadrocopter dan beweegt zal het
gewichtje achterkomen (traagheid). In de praktijk is er geen
gewicht die verend wordt opgehangen, maar veren die
gemaakt zijn van silicium. Die trillen heen en weer tussen
contactpunten. Wanneer deze veren bewegen en terwijl een verandering
ondergaan, zal de veer anders beginnen trillen. Het verschil van lading aan de
contactpunten meet de verandering van de verplaatsing op.
fig. 3.25: Gyrometer
fig. 3.26: Voorstelling gyrometer
fig. 3.27: Accelerometer
fig. 3.28: Voorstelling
accelerometer




Pagina 63


Barometer BMP085
Wat?
Een barometer meet de luchtdruk (atmosferische
druk) en de temperatuur om zo de hoogte te bepalen
waar de barometer zich bevind.

Werking?
De barometer zal dus de druk en temperatuur meten.
Die zal de onderstaande formule toepassen:

Magnetometer HMC5883
Wat?
Een magnetometer kan je vergelijken met een
kompas. De magnetometer bepaalt je positie aan de
hand van het magnetisch veld van de aarde. Het
nadeel hiervan is dat je geen andere magnetische
bronnen (zoals een magneet, een spoel, ) in de buurt
mag brengen.


Werking?
De magnetometer bevat een permanente magneet die bijna geen wrijving
heeft. Zo zal deze net zoals in een echt kompas het noorden aanwijzen.
Daardoor wordt de orintatie van de quadrocopter bepaalt.

3.8.3 De controller Atmega 328P
Dit is de effectieve controller. Deze is zoals reeds
gezegd helemaal programmeerbaar
(zie hoofdstuk 4).



M gemiddelde molaire massa van lucht (29
kg
kmol
)
g valversnelling (9,81
m
s
2

)
h hoogte (in m)
R algemene gasconstante (8,314

mol K
)
T temperatuur (in K)
P luchtdruk (in hPa)
P
0
luchtdruk op zeeniveau (0m hoogte)
fig. 3.29: Barometer
fig. 3.30: Magnetometer
fig. 3.31: Atmega 328P controller




Pagina 64


Hoofdstuk 4: Het programma

Zoals reeds besproken bij de flight controller is deze zelf programmeerbaar.
Hieronder staat een korte beschrijving van wat er allemaal in het programma
verwerkt zit. Het programma is een standaardprogramma dat wordt
meegeleverd bij het bordje, dat wij hebben aangepast voor onze
quadrocopter. Het programma is te vinden in bijlage 23.

4.1 Vlieg modes
Er zijn verschillende manieren om te vliegen, zowel voor beginners als voor
ervaren vliegers. Er zijn 3 belangrijke modes: ACRO-, ANGLE- en HORIZON-
mode. Daarnaast zijn er nog andere modes zoals MAG-mode en BARO-mode.
Er zijn ook speciale modes die niet bedoeld zijn om te vliegen.
Arming
Arm en disarm zijn 2 functies die bedoeld zijn om de quadrocopter te
beveiligen. Men moet eerst de quadrocopter uit zijn veiligheid halen want
anders kan het zijn dat de motoren beginnen te draaien zonder dat je dat
wenst.
Na het vliegen moet je hem weer in zijn veiligheid plaatsen. Anders zouden de
motoren direct kunnen draaien en zou je verwondingen kunnen oplopen.
ACRO-mode
Acro-mode staat voor acrobatic mode. Het is de moeilijkste manier om te
vliegen. De quadrocopter is enkel bestuurd door de inputs van de zender. Wat
je instuurt wordt direct naar het bordje gezonden. Hierbij wordt de gyroscoop
gebruikt om de quadrocopter onder een bepaalde hoek te brengen (afhankelijk
van de input) en die zolang in deze hoek te houden tot er een verandering van
input is.
ANGLE-mode
Angle-mode is de stable of self-levelling mode. Dit is de gemakkelijkste manier
om te vliegen. Deze manier van vliegen maakt gebruik van de gyroscoop om
zich (net zoals in ACRO-mode) te besturen. Wanneer er geen input van de
zender komt zal de quadrocopter zichzelf stabiliseren en zich terug horizontaal
brengen waardoor hij niet meer verder beweegt.
HORIZON-mode
HORIZON-mode is een combinatie van ANGLE en ACRO-mode. Dit is de beste
manier om in ACRO-mode te leren vliegen. Zolang er geen of weinig input is
zal de quadrocopter zichzelf stabiliseren, maar vanaf er grote inputs zijn zal de
quadrocopter in ACRO-mode staan. Daardoor bedien je de quadrocopter
helemaal zelf. Wanneer er terug geen inputs zijn (bijvoorbeeld als je denkt dat
je gaat crashen tijdens het oefenen) zal de quadrocopter zichzelf horizontaal
proberen te brengen.




Pagina 65


MAG-mode
Deze mode activeert de magnetometer. Dit zal als resultaat hebben dat de
quadrocopter zich in dezelfde positie zal houden en in dezelfde richting
voortbewegen zolang de MAG-mode aanstaat. De richting wordt bepaald vanaf
wanneer de MAG-mode actief wordt.
BARO-mode
Deze mode heeft een barometer nodig. Die zal ervoor zorgen dat de
quadrocopter op dezelfde hoogte blijft vliegen. Hierbij wordt ook de
accelerometer gedeeltelijk gebruikt om de versnelling in Z-richting (omhoog
en omlaag) minimaal te houden.



Extra: headfree
Dit zorgt ervoor dat de quadrocopter altijd dezelfde richting en hoogte zal
behouden (door middel van de magnetometer en de barometer). Zo kan je de
quadrocopter in een 2D vlak makkelijk bewegen. Dit is handig bij het leren
vliegen. Deze mode is dus niets meer dan de yaw-functie (draaien rond Z-as)
uitschakelen.
Combinatie: position hold
Position hold is niet echt om te vliegen. Het zal ervoor zorgen dat de
quadrocopter dezelfde positie zal behouden. Hierbij zal hij niet van richting
veranderen (MAG-mode), op een constante hoogte blijven (BARO-mode) en
zichzelf stabiel houden (ANGLE-mode). De quadrocopter zal dus bijna
stilhangen in de lucht. Aangezien we geen GPS hebben zal hij niet op dezelfde
positie blijven, maar zal hij ook geen versnelling ondergaan. Hij zal dus
gewoon meedrijven in de wind.





Pagina 66


fig. 4.1: Stick-inputs
4.2 Tuning
Om de quadrocopter te besturen naar eigen wens zijn er verschillende settings
die je kan toepassen. Dit wordt hoofdzakelijk gedaan door de gevoeligheid van
de stick-inputs aan te passen en door verschillende vliegmodes en andere
instellingen uit te kiezen. Daarnaast kan je elke vliegmode nog aanpassen
naar eigen wens via de PID-settings. De PID-settings zorgen voor de
soepelheid van de quadrocopter.

Stick-inputs
Aan de hand van de gevoeligheid van de stick-inputs kan
je de inputs van de afstandsbediening regelen. Bij de
throttle (blauwe grafiek) is dit rechtlijnig. D.w.z. dat
zowel bij het center als bij heel grote inputs de vergroting
evenveel effect zal hebben. Bij de pitch en de roll (groene
grafiek) is de grafiek niet lineair. Zo zie je dat bij een input dicht bij het center
er een zeer kleine verandering is en bij een zeer grote input er een grote
verandering zal optreden. Dit is handig om bij kleine bewegingen nauwkeurig
bij te regelen.

Instellingen selecteren
De instellingen worden geselecteerd
door schakelaars op de zender.

Je kan zelf kiezen door de vakjes aan te
klikken bij welke stand van de
schakelaar er welke optie moet
geactiveerd worden.

We hebben 4 ingangskanalen (AUX1 tot
AUX4). Elke schakelaar kan 3 standen
hebben (indien het er maar 2 zijn enkel
hoog en laag). Wij zijn geen professionele vliegers dus vliegen wij in de
gemakkelijkste vliegmode (ANGLE-mode). Omdat wij toch geen andere
vliegmodes nodig hebben selecteren we voor zowel laag, midden en hoge
spanning van de schakelaar dat we op ANGLE-mode vliegen. Dit kan je
herkennen op bovenstaande tekening door de witgevende vakjes.

Je ziet ook dat we via AUX1 (we hebben op AUX1 een 2-standen schakelaar
geplaatst dus hebben we enkel hoog en laag) de LED strips erop hebben
aangesloten. Als de schakelaar hoog staat zullen de lampjes oplichten.


fig. 4.2: Matrix van selecties (eigen voorkeur)




Pagina 67


fig. 4.3: PID settings
PID-tuning
Je kan zowel de P, I en D apart instellen. Dit zelfs voor
elke richting apart. Zowel de P, I als D hebben hun eigen
eigenschappen en effecten. Het is de bedoeling dat ze alle
drie samenwerken om zo een goed mogelijk resultaat te
verkrijgen. Hieronder verstaan we dat de quadrocopter
zichzelf snel, maar niet te snel corrigeert en dat hij direct reageert op
veranderingen.

P-tuning
De P staat voor proportioneel. Als je de quadrocopter wilt veranderen van
hoek ontstaat er een verschil tussen de werkelijke hoek en de gewenste
hoek. Hoe groter de P is, hoe meer het verschil versterkt wordt.

Hoe groter P, hoe sneller er zal worden gestabiliseerd met
onnauwkeurigheden en oscillaties (vibraties) tot gevolg.
Hoe kleiner P, hoe trager er zal worden gestabiliseerd. Er zal wel
nauwkeuriger gestabiliseerd worden dan bij een grote P.
I-tuning
De I staat voor integreren. Hoe langer dat het verschil van hoek blijft,
hoe groter het verschil zal versterkt worden (in de tijd). Stel dat de wind
de quadrocopter tegenhoudt voor bewegingsveranderingen, zal de I
ervoor zorgen dat er in de tijd meer gecorrigeerd zal worden.

Hoe groter I, hoe makkelijker het wordt om de quadrocopter in eenzelfde
positie te houden, maar daardoor wordt de quadrocopter gevoeliger voor
veranderingen.
Hoe kleiner I, hoe moeilijker het wordt om dezelfde positie te behouden,
maar de quadrocopter zal stabieler veranderen van positie.
D-tuning
De D staat voor differentiren. Dit zorgt ervoor dat hoe groter het
verschil is, hoe meer het verschil versterkt wordt. Indien het verschil
kleiner wordt, zal het verschil minder versterkt worden om teveel
corrigeren te voorkomen.

Hoe groter D, hoe meer het verschil versterkt wordt waardoor de
quadrocopter sneller zal corrigeren, maar hij zal trager reageren op snelle
veranderingen.
Hoe kleiner D, hoe minder het verschil zal versterkt worden waardoor de
quadrocopter langzamer zal corrigeren, maar sneller reageren op
kortstondige veranderingen.




Pagina 68


Hoofdstuk 5: De afwerking

Nadat de quadrocopter gebouwd en geprogrammeerd was hebben we nog een
paar extras aangebracht op de drone.

5.1 Het landingsgestel

Door het landingsgestel kan de quadrocopter nu overal opstijgen en landen.
Hij hoeft nu niet meer op zijn batterij te landen en kan ook op oneffen
ondergronden landen. We kozen ervoor om het landingsgestel uit carbon te
maken. Deze profielen hebben we gevonden bij Aerobertics.


Lengte monteerstuk (A): 40mm
Been breedte (B): 150mm
Hoogte (C): 80mm
Dikte (D): 20mm


fig. 5.1: Landingsgestel




Pagina 69


Wanneer we nu deze profielen in 2 delen
zagen (door de lengte A), bekomen we 2
stukken. Als we zo 2 profielen kopen hebben
we voldoende om een volledig landingsgestel
te maken. We monteren de 4 stukken dan
namelijk onder de armen aan de motoren.

De landingspoten passen qua dikte perfect op
onze aluminium armen (20 mm dik). Op de
aluminium armen hebben we 25 mm plaats
om ze te monteren. Er is dus genoeg plaats
om deze landingspoten mooi te monteren (20
mm). We monteren dit door middel van 2
bouten.

1 poot van Aerobertics kan 500 gram dragen.
Door ze middendoor te zagen en verder uit
elkaar te zetten vergroten we het draagvlak.
Daardoor kunnen we dus meer dan 500 gram
dragen. We doen dit 2 keer. Na de test
bekomen we dat deze landingspoten de
quadrocopter werkelijk kunnen dragen.

5.2 De ledlampen

De ledlampen hebben wij aangebracht aan de zijkanten
van de aluminium armen. Aan de voorkant van de
quadrocopter zijn het rode lampjes en aan de achterkant
blauwe. We hebben ze bevestigd doormiddel van
ledstrips. Dit zijn linten met ledlampen op die gemaakt
zijn om te werken op een 2S of 3S LiPo. Om ze van
spanning te voorzien hebben we ze aangesloten op het
powerboard.

Er is ook een schakelaar voorzien om de ledlampen aan en uit te zetten. Deze
schakelaar is gemonteerd op de negatieve draad van de ledlampjes en wordt
via het 5
e
kanaal op onze ontvanger gestuurd.

Nu deze lampjes aanwezig zijn op de quadrocopter kunnen we altijd bij het
vliegen zien wat de voorkant en de achterkant is van de quadrocopter.



fig. 5.2: Landingspoot
fig. 5.3: LED strips




Pagina 70


5.3 De afgewerkte quadrocopter

Nu is onze quadrocopter volledig af. We plaatsen dan ook graag nog enkele
fotos van ons volledig eindwerk.

We zien nu dat onze afgewerkte quadrocopter in totaal 995 gram weegt.






fig. 5.4: Weegschaal met het totaal gewicht
fig. 5.5a: Zijaanzicht quadrocopter
fig. 5.5b: Zijaanzicht quadrocopter (met lichten aan)




Pagina 71









fig. 5.6: Close-up van de elektronica
fig. 5.7: Bovenaanzicht




Pagina 72


Hoofdstuk 6: Paola wedstrijd
Het is momenteel 18 mei 2014. Ons praktisch deel is volledig af en het GIP-
boek krijgt nu een mooie vorm. Binnenkort gaan we naar de drukker om het
te laten inbundelen. Terwijl we bezig zijn met het GIP-boek krijgen we ons
deelname formulier voor de Koningin Paola wedstrijd Focus Aarde. (zie
bijlage 22).
De Koningin Paola wedstrijd Focus Aarde bestaat al sinds 1996 en wil het
technisch en beroepsonderwijs aanmoedigen. De prijs bekroont de beste
gentegreerde proeven die te maken hebben met de aarde of de ruimte. De
eerste prijzen hebben een waarde van 6500. De eervolle vermeldingen
worden beloond met respectievelijk 4000 en 2500.
We nemen deel aan deze wedstrijd omdat we willen weten hoe ons project
scoort ten opzichte van de andere deelnemers uit Belgi. Het lijkt ons wel
goed mogelijk om hier hoog te eindigen. Vorig jaar werden Mathisse en Jakob
namelijk knap tweede met hun waterstofauto.
Het lijkt ons ook veel toffer om mee te doen aan een competitie. Zo toon je
echt aan de mensen wat je bereikt hebt het voorbije jaar. We hopen natuurlijk
op een mooie eindplaats in Brussel. Dit zullen we wel niet kunnen meedelen in
dit GIP boek aangezien we ons project daar maar later moeten voorstellen.


fig. 6.1: Logo Paola wedstrijd




Pagina 73


Opdracht Frans

1. a. Stel een zakelijke brief op waarbij je (*)

- vertelt wat je GIP inhoudt
- uitlegt hoe je bij dit bedrijf terechtgekomen bent
- een (specifieke) technische vraag om documentatie stelt
opm:
...
b. Lees de tekst in bijlage en stel een woordenlijst op (minstens 20 termen) (**)
opm:
...
2. Beantwoord volgende vragen in het Frans (max 40 woorden / antw) (**)
a. Pourquoi Lonard De Vinci est-il important dans lhistoire de lhlicoptre?
b. Pourquoi faut-il attendre jusquau 20
ime
sicle pour les premiers vrais
hlicoptres ?
c. En 1907, le vol dune minute de Louis Breguet nest pas homologu.
Pourquoi ?
d. Qui a ralis le premier vol officiel avec un hlicoptre ? Comment avait-il
conu sa machine ?
e. Louis Breguet revient plus tard dans lhistoire de lhlicoptre pourquoi est-
ce quil est important ?
f. Quest-ce qui est typique pour le V-22 Osprey amricain ? Pensez-vous quil
sagit encore dun hlicoptre ? Motivez !

TIMING: bundel (brief + woordenlijst + beantwoorde vragen) worden ingediend op 26
februari 2014.

(*) = indivduele opdracht (elk maakt apart)
(**) = gezamenlijke opdracht (samen indienen)

Schooljaar 2013-2014 Trimester 2
ESSAI INTEGRE Datum 22/02/14
Leerkracht Laroy Christophe Vestiging Boeveriestraat
Vak Frans Behaald / 40
Leerling Depoortere-Scheldeman Klas + nr 6TIW 6 en 10




Pagina 74


1907-2007 : Lhlicoptre a 100 ans.
L'ide et le principe du vol stationnaire au moyen d'une voilure
rotative remontent pratiquement l'aube de la civilisation, puisque
la premire reprsentation connue en figure dans une peinture
chinoise du IVe sicle, plus de mille ans avant Lonard De VINCI
qui avait imagin son projet de "vis arienne" et qui est considr
comme l'anctre de l'Hlicoptre moderne. C'est en constatant que l'air tait un fluide
comme l'eau qu'il eut l'intuition d'une aile en vis qui, telle une hlice dans l'eau, pourrait
sustendre un objet. En dessinant son aile en vis, il ignorait que son croquis constituait
la premire manifestation de l'ide du vol humain sous une machine aile tournante
"l'hlicode".
En 1784, LAUNOY et BIENVENU ralisent la premire maquette
volante et la prsentent l'Acadmie Royale des
Sciences. Un systme ressort lame anime deux
hlices contrarotatives en forme de plumes d'oiseau.
Mais l'essor des montgolfires occulte compltement
cette invention, qui tombe dans l'oubli.
En 1861 Gustave de PONTON d'AMECOURT, qui
invente le mot hlicoptre (du grec hlix, hlice et pteron, aile) ralise une
machine fonctionnant la vapeur. En 1877, l'ingnieur italien Enrico
FORLANINI fait dcoller une maquette dhlicoptre modle rduit une hauteur de 13
mtres durant 20 secondes. L'engin pse 350 kilogrammes et est anim par une machine
vapeur.
Mais on est encore loin du premier vol autonome pilot dune machine voilure tournante.
Comme souvent, il faudra attendre la conjugaison de plusieurs avances techniques
majeures dont lavnement du moteur explosion et les tudes du colonel Charles
RENARD.
Directeur du centre arostatique militaire de Chalais-Meudon, cet officier polytechnicien
est considr comme le pre de laronautique franaise. Cest sous son impulsion quen
1905 sont dvelopps des moteurs la fois plus lgers, plus puissants et surtout plus
fiable comme le moteur Antoinette de LEVAVASSEUR. Alors quil travaille sur les hlices
sustentatrices, cest galement le colonel RENARD qui comprend le premier limportance
de larticulation des pales du rotor.





Pagina 75


Par une curieuse concidence, cest en France que trois pionniers vont presque au mme
moment tenter de russir lexploit de faire dcoller un appareil pilot :
En 1905, Le prince Albert 1
er
de Monaco confirme que Maurice
LEGER est parvenu faire dcoller un hlicoptre de sa
conception pendant 15 secondes et soulever un homme de
74 kilos. Cependant lhistoire ne retiendra pas cette tentative
dans la mesure o lappareil est reli au sol et
nemporte pas son propre moteur.
Au dbut de 1907, Louis BREGUET russit
faire dcoller une extraordinaire machine munie
de quatre rotors de plus de 8 mtres de diamtre
chacun. La machine est pilote par un homme,
lingnieur VOLUMARD, choisi pour son poids plume, et slve de 60
cm pendant prs dune minute. Lessai est attest par une photographie.
Cependant, une fois encore, la performance ne sera pas homologue dans la mesure o
4 hommes ont tenu en permanence lappareil par ses extrmits afin daider son
quilibre. Louis BREGUET persuad que les techniques de lpoque ne permettent plus
davances significatives, va se tourner avec succs vers laviation classique avant de
revenir lhlicoptre dans les annes 30.

Le premier vol homologu d'un hlicoptre avec son pilote.
Le 13 novembre 1907, sur un champ qui jouxte une usine dsaffecte, un jeune inconnu
du nom de Paul CORNU sinstalle dans une drle de machine avec la ferme intention de
raliser le premier vol dun appareil voilure tournante. Cest dans latelier paternel de
cycles et de mcaniques Lisieux, que Paul CORNU, qui a hrit les talents
dingnieur de son pre, a imagin puis construit le modle rduit qui lui a servi tester
toutes ses ides : Rotors (on dit alors hlices), transmissions, dflecteurs, tout a t
essay puis assembl grandeur relle dans lusine de Coquainvilliers non loin de Lisieux.
Sa machine est constitue dune structure en tubes dacier en forme de
V dans laquelle linventeur a plac un moteur Antoinette de 24 chevaux
qui entraine les deux rotors par lintermdiaire dune longue courroie de
plus 22 mtres. Ce nest pas son premier essai. Les semaines
prcdentes il a fallu rsoudre de nombreux problmes techniques et
notamment le patinage de la courroie qui peine entrainer les rotors.





Pagina 76


En ce matin de novembre sa machine a t perfectionne et il prend place sur la selle de
vlo qui lui sert de sige. Le moteur vibre, lappareil slance et puis slve de 30 cm
durant plusieurs secondes. Cest lexploit tant rv depuis de longues annes. La
performance est renouvele laprs-midi mme et lappareil slve alors de 1,5 mtre.
Quimporte que seuls Paul et son frre Jacques aient t tmoins de cette tentative, cest
la date du 13 novembre 1907 que lhistoire retiendra comme tant celle du premier vol
libre dun hlicoptre pilot.
Malgr tout, lhlicoptre reste encore un engin instable quil est difficile de contrler. Pour
arriver aux extraordinaires appareils que lon connat aujourdhui, il faudra attendre de
nombreuses annes pendant lesquelles des passionns connus ou inconnus ont particip
la mise au point et lvolution de lhlicoptre.
En 1923, lingnieur espagnol Juan de la Cierva, en dveloppant une
formule hybride appele autogire , trouve une des clefs du problme
en mettant au point larticulation des pales qui permet le vol contrl. De
nombreux autogires de Juan de la CIERVA taient en service dans
l'arme franaise en

Le 4 mai 1924 un technicien de Peugeot, Etienne OEHMICHEN,
ralise le premier kilomtre en circuit ferm alors que la mme
performance en avion date de 1908 (Henri FAIRMAN). C'est
galement OEHMICHEN qui met au point le principe de
lautorotation, permettant un hlicoptre de planer en cas d'avarie.
Le 26 juin 1935, Louis BREGUET est revenu vers l'hlicoptre.
Pilot par Maurice CLAISSE, son appareil quip d'un moteur
Wright de 420 cv effectue son premier vol puis bat le record de
vitesse (100 km/h), le record d'altitude avec 158 mtres et le
record de distance avec 44 Km en 1 heure 2 minutes et 50
secondes. Baptis Gyroplane Brguet-Dorand, c'est le premier hlicoptre fonctionnant
correctement dans tous les domaines de vol.




Pagina 77


L'hlicoptre peut alors prendre son essor. En un sicle des progrs fabuleux ont t
accomplis pour arriver dominer les voilures tournantes plus lourdes que l'air. Comme
souvent ce sont les recherches militaires qui ont permis le vritable dveloppement de
lhlicoptre. C'est en effet dans le domaine des oprations
militaires que l'hlicoptre a prouv son incomparable
efficacit ce qui a conduit les grands pays se doter d'une
industrie de l'hlicoptre, participant ainsi son essor.
Dernire volution en date, le convertible amricain V-22
OSPREY ralise le rve des premiers pionniers en tant le
premier appareil concilier les avantages de lavion et de lhlicoptre.





Pagina 78


1a. Zakelijke brief
Arne Depoortere Aalter-brug, 2014-01-18
Woestijne 24
9880 Aalter-brug


Aerobertics BVBA
Maalse Steenweg 367
8310 Sint-Kruis, Brugge


Sujet: demande de documentation sur les moteurs sans balais


Cher monsieur, chre madame,

e suis Arne Depoortere, jai dix-sept ans et je termine mes tudes de sciences
industrielles linstitut technique libre Bruges. ai trouv ladresse de votre
magasin sur internet pendant que jtais en train de chercher de linformation.

Pour mon travail de fin danne, je dois raliser une quadricoptre. Cest un
multicoptre avec quatre moteurs. ai trouv dans votre magasin en ligne des
moteurs sans balais. Avant dacheter, je voudrais avoir votre avis sur le poids,
la force et la dimension des moteurs. Est-il possible de me conseiller en cette
matire ou de menvoyer de la documentation ?

Dans le cas ngative, pourriez-vous me donner les coordonnes dune autre
firme o je peux madresser ?

Dans lattente de votre rponse, je vous prie daccepter mes salutations
distingues.

Arne Depoortere




Pagina 79




Laurens Scheldeman
Kapelrie 49 Brugge, 18/02/2014
8490 Varsenare
BELGI




HobbyKing Technology LTD
Mong Kok Road 33
U04, 7/F, Bright Way Tower
HONG KONG





Sujet : Demande des renseignements sur une batterie LIPO




Cher monsieur, chre madame,



e mappelle Laurens Scheldeman. e suis un tudiant dans la sixime anne
de sciences industrielles. Je suis en train de bricoler un quadrocopter.


Dans votre magasin en ligne jai trouv des batteries LIPO. Le modle LIPO
2450mAh 20C mintresse. Mais avant de commander, pourriez-vous
mexpliquer :
- comment la batterie fonctionne,
- le signification du terme 20C,
- combien de temps la batterie peut nourrir quatre moteurs 930 KVA,
- combien de temps il faut pour charger la batterie
- comment il faut charger la batterie.


Puis-je vous demander de formuler une rponse ds que possible?


e vous remercie davance,


Laurens Scheldeman







Pagina 80


1b. Woordenlijst
Lanctre de voorvader, de voorloper
Une voilure rotative een draaiend draagvlak
L aube de dageraad
Le vol stationnaire het verticaal opstijgen
Une aile en vis een schroefvleugel (= de schroef van
Archimedes)
Une hlice een schroef
Un croquis een schets
Ressort lame bladvering
Un montgolfire een luchtballon
La vapeur de stoom
Lengin het toestel
La conjugaison de verbinding
Lavnement de komst
Le moteur explosion de ontploffingsmotor
Fiable betrouwbaar
Le hlices sustentatrices de dragende schroeven
Une extrmit een uiteinde
Lquilibre het evenwicht
Jouxter grenzen aan
Une tube dacier een stalen buis
Une courroie een riem
Le patinage de la courroie het doorglijden van de riem
Planer zweven, een glijvlucht maken
Avarie schade
Battre un record een record breken
Prendre son essor opvliegen, zich vrij ontwikkelen
Concilier verzoenen




Pagina 81


2. Vragen
a. Pourquoi Lonard De Vinci est-il important dans lhistoire de
lhlicoptre ?
Il est important parce que son projet de vis arienne est considr comme
lanctre de lhlicoptre moderne. Il a lanc lide du vol humain sous une
machine aile tournante lhlicode .

b. Pourquoi faut-il attendre jusquau 20
ime
sicle pour les premiers
vrais hlicoptres ?
A ce moment-l, on a conjugu plusieurs avances techniques majeures
comme lavnement du moteur lexplosion et le dveloppement des moteurs
plus lgers, plus puissants et sustentatrices et larticulation des pales du rotor.

c. En 1907, le vol dune minute de Louis Breguet nest pas homologu.
Pourquoi ?
Ce vol nest pas homologu parce que quatre hommes ont tenu en
permanence lappareil par ses extrmits afin daider son quilibre.

d. Qui a ralis le premier vol officiel avec un hlicoptre ? Comment
avait-il conu sa machine ?
Monsieur Paul Cornu a ralis le premier vol officiel avec un hlicoptre. La
machine tait constitue dune structure en tubes dacier en forme de V. Un
moteur de 24 chevaux entrainait les deux rotors par lintermdiaire dune
longue courroie.

e. Louis Breguet revient plus tard dans lhistoire de lhlicoptre
pourquoi est-ce quil est important ?
Monsieur Louis Breguet a dvelopp un appareil qui a battu tous les records :
le record de vitesse (100 km/h), le record daltitude (158 mtres) et le record
de distance (44 km en 1 heure 2 minutes et 50 secondes). Ctait le premier
hlicoptre qui fonctionnait correctement dans tous les domaines de vol.

f. Quest-ce qui est typique pour le V-22 Osprey amricain ? Pensez-
vous quil sagit encore dun hlicoptre ? Motivez !
Le V-22 Osprey est le premier appareil qui concilie les avantages de lavion et
de lhlicoptre. Il sagit encore dun hlicoptre parce que lappareil peut
dcoller et atterrir verticalement grce aux hlices.




Pagina 82


Opdracht Engels







Pagina 83











Pagina 84




Build A Quadcopter From
Scratch Hardware Overview
Posted on June 25, 2013 by Oscar

How To Build A Quadcopter Choosing
Hardware
In this article I will be talking about quadcopter components and how to choose
them. This is part of the tutorial series on how to build a quadcopter. In the next post I will
be talking about software, how to go about the algorithm and programming.
If you are planning on building a quadcopter but not sure how, this is the right place for
you. Doing research is pretty boring, so I am trying to put together a comprehensive
tutorial about quadcopter, hope it helps you as much as it helped me.




Pagina 85



Building a quadcopter from scratch takes a lot of time and effort. If you are inpatient, afraid
of programming/maths and has a good budget, you can just buy a pre-built kit. You could
get it assembled within minutes before its flying (For example, like this one). But I have to
say, you are missing the fun part of building a quadcopter. From choosing the parts,
designing the circuits, to programming, you will be involved in every aspect of building a
quadcopter, and its FUN!
For more tutorials, check out this list. If you have any questions, feel free to ask on this
quadcopter message board.
This blog post is divided into a three parts
What is a Quadcopter and How It Work
Quadcopter Components Introduction
Conclusion
What Is A QuadCopter and How It Works
A QuadCopter is a helicopter with four rotors, so its also known as quadrotor. Because of
its unique design comparing to traditional helicopters, it allows a more stable platform,
making quadcopters ideal for tasks such as surveillance and aerial photography. And it is
also getting very popular in UAV research in recent years.
The Quadcopters exist in many different sizes. From as small as a CD up to something as
big as one meter in width.






Pagina 86


On a regular helicopter has one big rotor to provide all the lifting power and a little tail rotor
to offset the aerodynamic torque generated by the big rotor (without it, the helicopter
would spin almost as fast as the propeller)
Unlike a helicopter, a quadrotor has four rotors all work together to produce upward thrust
and each rotor lifts only 1/4 of the weight, so we can use less powerful and therefore
cheaper motors. The quadcopters movement is controlled by varying the relative thrusts
of each rotor.
These rotors are aligned in a square, two on opposite sides of the square rotate in
clockwise direction and the other two rotate in the opposite direction. If all rotors turn in
the same direction, the craft would spin would spin just like the regular helicopter without
tail rotor. (if you are not sure what I mean, check out this video) Yaw is induced
by unbalanced aerodynamic torques. The aerodynamic torque of the first rotors pair
cancelled out with the torque created by the second pair which rotates in the opposite
direction, so if all four rotors apply equal thrust the quadcopter will stay in the same
direction.





Pagina 87




To maintain balance the quadcopter must be continuously taking measurements from the
sensors, and making adjustments to the speed of each rotor to keep the body level.
Usually these adjustments are done autonomously by a sophisticated control system on
the quadcopter in order to stay perfectly balanced. A quadcopter has four controllable
degrees of freedom:Yaw, Roll, Pitch, and Altitude. Each degree of freedom can be
controlled by adjusting the thrusts of each rotor.





Pagina 88




Yaw (turning left and right) is controlled by turning up the speed of the regular
rotating motors and taking away power from the counter rotating; by taking away
the same amount that you put in on the regular rotors produces no extra lift (it
wont go higher) but since the counter torque is now less, the quadrotor rotates as
explained earlier.3.- control becomes a matter of which motor gets more power
and which one gets less.
Roll (tilting left and right) is controlled by increasing speed on one motor and
lowering on the opposite one.
Pitch (moving up and down, similar to nodding) is controlled the same way as roll,
but using the second set of motors. This may be kinda confusing, but roll and pitch
are determined from where the front of the thing is, and in a quadrotor they are
basically interchangeable; but do take note that you have to decide which way is
front and be consistent or your control may go out of control.





Pagina 89










Pagina 90


For example, to roll or pitch, one rotors thrust is decreased and the opposite rotors thrust
is increased by the same amount. This causes the quadcopter to tilt. When the
quadcopter tilts, the force vector is split into a horizontal component and a vertical
component. This causes two things to happen: First, the quadcopter will begin to travel
opposite the direction of the newly created horizontal component. Second, because the
force vector has been split, the vertical component will be smaller, causing the quadcopter
to begin to fall. In order to keep the quadcopter from falling, the thrust of each rotor must
then be increased to compensate.
This illustrates how the adjustments made for each degree of freedom must work together
to achieve a desired motion. Now, building and flying a quadrotor from a remote control is
simple and fun and stuff, but people noting the inherently stable flight (in theory with equal
speed of the motors the thing keeps itself level) and ease of control (only three functions
and they are all basically take speed from one and put in the other), people love to make
them autonomous (flies itself) and semi-autonomous (at least keeps itself level by
responding to disturbances and error).





Pagina 91


Quadcopter Components Introduction
There are sensors connected to a microcontroller to make the decision as to how to
control the motors. Depending on how autonomous you want it to be, one or more of
these sensors are used in combination.
In this section, I will talk about these essential quadcopter components:
Frame The structure that holds all the components together. They need to be
designed to be strong but also lightweight.
Rotors Brushless DC motors that can provide the necessary thrust to propel the
craft. Each rotor needs to be controlled separately by a speed controller.
Propeller
Battery Power Source
IMU Sensors
Microcontroller The Brain
RC Transmitter
Optional
Before we go into explaining how to choose each components, we can take a look some
quadcopters that people have built, and the parts they used to get a rough idea. I didnt
build these planes, so I cant guarantee their performance.
Multicopter Examples Page





Pagina 92


Frame
Frame is the structure that holds all the components together. The Frame should be rigid,
and be able to minimize the vibrations coming from the motors.

A QuadCopter frame consists of two to three parts which dont necessarily have to be of
the same material:
The center plate where the electronics are mounted
Four arms mounted to the center plate
Four motor brackets connecting the motors to the end of the arms
Most available materials for the frame are:
Carbon Fiber
Aluminium
Wood, such as Plywood or MDF (Medium-density fibreboard)
Carbon fiber is most rigid and vibration absorbent out of the three materials but also the
most expensive.
Hollow aluminium square rails is the most popular for the QuadCopters arms due to its
relatively light weight, rigidness and affordability. However aluminium could suffer from
motor vibrations, as the damping effect is not as good as carbon fiber. In cases of severe
vibration problem, it could mess up sensor readings.





Pagina 93


Wood board such as MDF plates could be cut out for the arms as they are better at
absorbing the vibrations than aluminium. Unfortunately the wood is not a very rigid
material and can break easily in quadcopter crashes.
Although it is not as important as for the arms which of the three material to use for the
center plate, plywood is most commonly seen because of its the light weight, easy to work
with and good vibration absorbing features.
As for arm length, the term motor-to-motor distance is sometimes used, meaning the
distance between the center of one motor to that of another motor of the same arm in the
QuadCopter terminology.

The motor to motor distance usually depends on the diameter of the propellers. To make
you have enough space between the propellers and they dont get caught by each other.
[Give example]





Pagina 94


Brushless Motors
A little background of Brushless motor. They are a bit similar to normal DC motors in the
way that coils and magnets are used to drive the shaft. Though the brushless motors do
not have a brush on the shaft which takes care of switching the power direction in the
coils, and this is why they are called brushless. Instead the brushless motors have three
coils on the inner (center) of the motor, which is fixed to the mounting.

On the outer side it contains a number of magnets mounted to a cylinder that is attached
to the rotating shaft. So the coils are fixed which means wires can go directly to them and
therefor there is no need for a brush.





Pagina 95



Generally brushless motors spin in much higher speed and use less power at the same
speed than DC motors. Also brushless motors dont lose power in the brush-transition like
the DC motors do, so its more energy efficient.
Brushless motors come in many different varieties, where the size and the current
consumption differ. When selecting your brushless motor you should take care of the
weight, the size, which kind of propeller you are going to use, so everything matches up
with the current consumption. When looking for the brushless motors you should notice
the specifications, especially the Kv-rating.
The Kv-rating indicates how many RPMs (Revolutions per minute) the motor will do if
provided with x-number of volts. The RPMs can be calculated in this way: RPM=Kv*U An
easy way to calculate rating of motor you need, check out the online calculator eCalc. Its
an amazing tool that helps you decide what components to purchase depending on the
payload that you want to carry.
Make sure you buy the counter-rotating to counteract the torque effect of the props.
I have written a more complete guide on how to choose Motor and propeller.





Pagina 96


Propellers
On each of the brushless motors there are mounted a propeller.
You might not have noticed this on the pictures, but the 4 propellers are actually not
identical. You will see that the front and the back propellers are tilted to the right, while the
left and right propellers are tilted to the left.
Like I mentioned before, 2 rotors rotates in the opposite directions to the other two to
avoid body spinning. By making the propeller pairs spin in each direction, but also having
opposite tilting, all of them will provide lifting thrust without spinning in the same direction.
This makes it possible for the QuadCopter to stabilize the yaw rotation, which is the
rotation around itself.

The propellers come in different diameters and pitches (tilting). You would have to decide
which one to use according to your frame size, and when that decision is made you
should chose your motors according to that. Some of the standard propeller sizes used for
QuadCopters are:
EPP1045 10 diameter and 4.5 pitch this is the most popular one, good for mid-
sized quads
APC 1047 10 diameter and 4.7 pitch much similar to the one above
EPP0845 8 diameter and 4.5 pitch regularly used in smaller quads
EPP1245 12 diameter and 4.5 pitch used for larger quads which requires lot of
thrust
EPP0938 9 diameter and 3.8 pitch used in smaller quads





Pagina 97


Aerodynamics is just way too complex for non-academic hobbyists. Its even unlikely we
can explain all that theory stuff in a few words. But in general when selecting propellers
you can always follow these rules:
1. The larger diameter and pitch the more thrust the propeller can generate. It also
requires more power to drive it, but it will be able to lift more weight.
2. When using high RPM (Revolutions per minute) motors you should go for the
smaller or mid-sized propellers. When using low RPM motors you should go for
the larger propellers as you can run into troubles with the small ones not being
able to lift the quad at low speed.
Analysis of Propeller Pitch, Diameter, and RPM
Pitch VS Diameter: the diameter basically means area while pitch means effective area.
So with the same diameter, larger pitch propeller would generate more thrust and lift more
weight but also use more power.
A higher RPM of the propeller will give you more speed and maneuverability, but it is
limited in the amount of weight it will be able to lift for any given power. Also, the power
drawn (and rotating power required) by the motor increases as the effective area of the
propeller increases, so a bigger diameter or higher pitch one will draw more power at the
same RPM, but will also produce much more thrust, and it will be able to lift more weight.
In choosing a balanced motor and propeller combination, you have to figure out what you
want your quadcopter to do. If you want to fly around stably with heavy subject like a
camera, you would probably use a motor that manages less revolutions but can provide
more torque and a longer or higher pitched propeller (which uses more torque to move
more air in order to create lift).





Pagina 98


ESC Electronic Speed Controller
The brushless motors are multi-phased, normally 3 phases, so direct supply of DC power
will not turn the motors on. Thats where the Electronic Speed Controllers (ESC) comes
into play. The ESC generating three high frequency signals with different but controllable
phases continually to keep the motor turning. The ESC is also able to source a lot of
current as the motors can draw a lot of power.

The ESC is an inexpensive motor controller board that has a battery input and a three
phase output for the motor. Each ESC is controlled independently by a PPM
signal (similar to PWM). The frequency of the signals also vary a lot, but for a Quadcopter
it is recommended the controller should support high enough frequency signal, so the
motor speeds can be adjusted quick enough for optimal stability (i.e. at least 200 Hz or
even better 300 Hz PPM signal). ESC can also be controlled through I2C but these
controllers are much more expensive.
When selecting a suitable ESC, the most important factor is the source current. You
should always choose an ESC with at least 10 A or more in sourcing current as what your
motor will require. Second most important factor is the programming facilities, which
means in some ESC you are allowed to use different signals frequency range other than
only between 1 ms to 2 ms range, but you could change it to whatever you need. This is
especially useful for custom controller board.





Pagina 99


Battery
As for the power source of the quadcopter, I would recommend LiPo Battery because
firstly it is light, and secondly its current ratings meet our requirement. NiMH is also
possible. They are cheaper, but its also a lot heavier than LiPo Battery.

Battery Voltage
LiPo battery can be found in a single cell (3.7V) to in a pack of over 10 cells connected in
series (37V). A popular choice of battery for a QuadCopter is the 3SP1 batteries which
means three cells connected in series as one parallel, which should give us 11.1V.
Battery Capacity
As for the battery capacity, you need to do some calculations on:
How much power your motors will draw?
Decide how long flight time you want?
How much influence the battery weight should have on the total weight?
A good rule of thumb is that you with four EPP1045 propellers and four Kv=1000 rated
motor will get the number of minutes of full throttle flight time as the same number of amp-
hours in your battery capacity. This means that if you have a 4000mAh battery, you will
get around 4 minutes of full throttle flight time though with a 1KG total weight you will get
around 16 minutes of hover.





Pagina 100


Battery Discharge Rate
Another important factor is the discharge rate which is specified by the C-value. The C-
value together with the battery capacity indicates how much current can be drawn from
the battery.
Maximum current that can be sourced can be calculated as:
MaxCurrent = DischargeRate x Capacity
For example if there is a battery that has a discharge rate of 30C and a capacity of 2000
mAh. With this battery you will be able to source a maximum of 30Cx2000mAh = 60A. So
in this case you should make sure that the total amount of current drawn by your motors
wont exceed 60A.
This tutorial about battery I found very informative.





Pagina 101


IMU Inertial Measurement Unit
The Inertial Measurement Unit (IMU) is an electronic sensor device that measures the
velocity, orientation and gravitational forces of the quadcopter. These measurements
allow the controlling electronics to calculate the changes in the motor speeds.
The IMU is a combination of the 3-axis accelerometer and 3-axis gyroscope, together they
represent a 6DOF IMU. Sometimes there is also an additional 3-axis magnetometer for
better Yaw stability (in total 9DOF).
How does IMU work
The accelerometer measures acceleration and also force, so the downwards gravity will
also be sensed. As the accelerometer has three axis sensors, we can work out the
orientation of the device.

A gyroscope measure angular velocity, in other words the rotational speed around the
three axis.






Pagina 102


Using Only Accelerometer?
With the accelerometer alone, we should be able to measure the orientation with
reference to the surface of earth. But the accelerometer tends to be very sensitive and
unstable sometimes, when motor vibration is bad, it could mess up the orientation.
Therefore we use a gyroscope to address this problem. With both the accelerometer and
gyroscope readings we are now able to distinguish between movement and vibration.
Using Only Gyroscope?
Since the gyroscope can tell us the rotational movement, why cant we just use the
gyroscope alone?
The gyroscope tends to drift a lot, which means that if you start rotating the sensor, the
gyroscope will output the angular velocity, but when you stop it doesnt necessarily go
back to 0 deg/s. If you then just used the gyroscope readings you will get an orientation
that continues to move slowly (drifts) even when you stopped rotating the sensor. This is
why both sensors has to be used together to calculate a good and useful orientation.
Magnetometer
The accelerometer cannot sense yaw rotation like it can with roll and pitch, and
therefore a magnetometer is sometimes used.
A magnetometer measures the directions and strength of the magnetic field. This
magnetic sensor can be used to determine which way is south and north. The pole
locations are then used as a reference together with the Yaw angular velocity around from
the gyroscope, to calculate a stable Yaw angle.
I am trying to keep the theory and maths minimal here, and I will go into more detail in the
next couple of tutorials.





Pagina 103


Buying an IMU
These three sensors are available individually on the market. But it is easier for
development to get an IMU sensor board with the first two sensors (6DOF) or all three
sensors (9DOF).

The raw sensor boards can communicate with the microcontroller via I2C or analogue.
Digital boards that support I2C is easier and faster for development, but Analogue ones
are cheaper.
There are even complete IMU units with processor available. Usually the processor is a
small 8-bit microprocessor which runs computations some kind of algorithms to work out
the Pitch, Roll and Yaw. The calculated data will then be put out on a serial bus or
sometimes also available by I2C or SPI.
The choice of IMU is going to narrow down what type of controller board you can use. So
before purchasing an IMU boards you should find out information about the controller
boards. Some controller boards even comes with built-in sensors.
Some commercially available IMU sensors boards:
Sparkfun 9DOF stick
Sparkfun 6DOF combo board
FreeIMU
IMU with processor:
Sparkfun 9DOF Razor
Mongoose 9DOF (10DOF)
ArduIMU





Pagina 104


Flight Controller Controlling electronics
You can either buy a controller board that is specially designed for quadcopter or buy all
the parts and assemble one yourself. Some of the controller boards already contain the
required sensors while other requires you to buy these on a separate board.
Here is a comprehensive list of ready to go flight controller boards:
http://robot-kingdom.com/best-flight-controller-for-quadcopter-and-multicopter/
The AeroQuad MEGA Shield The AeroQuad board is a shield for the Arduino, either the
Arduino UNO or the Arduino MEGA. The AeroQuad board requires the Sparkfun 9DOF
stick which is soldered to the shield.
The ArduPilot board contains an ATMEGA328, the same as on the Arduino UNO. Like the
AeroQuad shield this board doesnt contain any sensors either. You would have to buy the
ArduIMU and connect it to the board to use it.
The OpenPilot is a more advanced board which contains a 72MHz ARM Cortex-M3
processor, the STM32. The board also includes a 3-axis accelerometer and 3-axis
gyroscope. Together with the board comes a great piece of software for the PC to
calibrate, tune and especially set waypoints for your QuadCopter if you have installed a
GPS module which I will be talking more about in the next section.
Make You Own Quadcopter Controller Board
Alternatively you can also use general purpose microcontroller, such as Arduino.





Pagina 105


RC Transmitter
QuadCopters can be programmed and controlled in many different ways but the most
common ones are by RC transmitter in either Rate (acrobatic) or Stable mode. The
difference is the way the controller board interprets the orientations feedback together with
your RC transmitter joysticks.
In Rate mode only the Gyroscope values are used to control the quadcopter. The joysticks
on your RC transmitter are then used to control and set the desired rotation speed of the 3
axes, though if you release the joysticks it does not automatically re-balance. This is
useful when doing acrobatics with your quadcopter as you can tilt it a bit to the right,
release your joysticks, and then your quadcopter will keep that set position.
For the beginners the Rate mode might be too difficult, and you should start with the
Stable mode. All the sensors are used to determine the quadcopters orientation in the
stable mode. The speed of the 4 motors will be adjusted automatically and constantly to
keep the quadcopter balanced. You control and change the angle of the quadcopter with
any axis using the joystick. For example to go forward, you can simply tilt one of the
joysticks to change the pitch angle of the quadcopter. When releasing the joystick, the
angle will be reset and the quadcopter will be balanced again.
Check here for a more detailed RC transmitter article.





Pagina 106


Optional Components
After buying all the necessary parts, and you are still not broke, you might consider other
popular optional components such as GPS modules, ultrasonic sensors, barometers etc.
They can enhance the performance of your quadcopter, and bring more features.
A GPS module talks to the satellite and retrieve accurate location information. We can use
this information to calculate speed and path. It is especially useful for autonomous
quadcopters which needs to know its exact position and which way to fly.
An ultrasonic sensor measures the distance to the ground, i.e. altitude. This is useful if
you want to keep your quadcopter a certain distance from the ground without having to
adjust the height its flying at constantly yourself. Most of these sensors has a range
between 20cm to 7m.
When you gets higher, you might want to use a barometer. This sensor measures
humidity and pressure to work out the altitude, so when the quadcopter is close to the
ground (where these two factors doesnt change much), it becomes ineffective. Therefore
it is also common to use both of them at the same time.
Conclusion
Hopefully this article has given you a better understanding what each part of the
quadcopter does, and how to go about selecting the right product for your quadcopter.
Please do not hesitate writing a comment or giving us some feedback on this article. The
next post will be about the software side of the quadcopter.
If you are into FPV and Video taking, you might find this collection of FPV videos
interesting.








Pagina 107


1. Glossary:
Word Sentence Translation
The thrust The thrust of an airplane is provided by the
engines.
de stuwdruk, de
voortstuwingskracht
Torque The four rotors of a quadcopter are aligned in a
square. When the rotors one and three rotate in
clockwise direction and the rotors two and four
rotate counter-clockwise, the net aerodynamic
torque is zero if all four rotors apply equal thrust.
The quadcopter will stay in the same direction.
koppel
(aandrijftechniek), een
maat voor het rotatie-
effect van een kracht
To yaw Yaw is a horizontal (left and right) movement of
an airplanes nose.
gieren, in de luchtvaart
wordt hiermee bedoeld
de neus van het
vliegtuig draaien naar
rechts of links
To roll A fighter jet can do a full 360-degree barrel roll in
less than two seconds !
(over)hellen naar links
of rechts. In de
luchtvaart wordt
hiermee een beweging
om de lengteas (van
neus tot start) van het
vliegtuig aangeduid
To pitch The aircraft pitches the tail of the airplane up and
the nose down.
stampen, in de
luchtvaart wordt
hiermee een beweging
om de dwarsas (van
vleugeltip tot vleugeltip)
aangeduid, zoals
knikken
To tilt Do you know that sometimes a wing that is
horizontal for conventional forward flight can be
tilted for vertical takeoff and landing ?
doen overhellen
A remote control You can change the television channels or adjust
TVs volume by using the remote control.
een afstandsbediening
A microcontroller A microcontroller is a compact integrated
computer (chip) that is often part of embedded
systems in motor vehicles, robots, office
machines
een microcontroller




Pagina 108


A bracket A motor bracket helps you to mount the motor on
the arm of the quadcopter.
een beugel
A shaft A mechanical shaft is a long cylindrical rod that
rotates in order to transmit power.
een as
The damping effect The damping effect reduces or eliminates stored
energy created by sound.
het dempend effect
A brushless motor A brushless motor has less inside friction than a
brushed motor.
een borstelloze motor
A coil An electromagnetic coil is an electrical conductor
such as a wire in the shape of a spiral.
een spoel (elektriciteit)
The current An electric current is a flow of electric charge. de stroom
Manoeuvrability The manoeuvrability of this car is much better
thanks to the power steering.
wendbaarheid
Full throttle flight
time
After 30 minutes of full throttle flight time, the
battery was completely flat. We definitely need
more capacity.
volgas vluchttijd
To hover The helicopter hovered over the building while
the journalist took some pictures of the royal
couple.
zweven
The discharge rate The discharge rate is the ability to satisfy the load
demander.
de mate van ontladen
The angular
velocity
To examine how fast an object is rotating, we
define angular velocity as the rate of change of an
angle.
de hoeksnelheid
The gyroscope A gyroscope is a wheel that spins quickly and is
held in a frame that allows it to tilt in any
direction.
de gyroscoop, de tol






Pagina 109


2. Scheme:

Hoe bouw ik een quadrocopter?
1. Wat is een quadrocopter en hoe werkt dit?
1.1. Wat?
Een quadrocopter is een helikopter met 4 rotoren
stabiel platform ideaal voor bewaking, luchtfotografie en onderzoek.
1.2. Werking:
- Elk van de 4 rotoren tillen van het gewicht minder krachtige motoren gebruiken
goedkoper.
- Beweging wordt gecontroleerd door variatie in de voortstuwingskracht van elke rotor.
De rotoren zijn opgesteld in een vierkant: 2 tegenovergestelden draaien in wijzerzin en 2
tegenovergestelden draaien in tegenwijzerzin.
1) Alle 4 dezelfde voortstuwingskracht quadrocopter houdt richting.
2) Rotoren in wijzerzin draaien sneller (M2, M4) , rotoren in
tegenwijzerzin trager draaien (M1, M3) draaien naar links of rechts.
3) 1 rotor draait sneller (M2) en de tegenovergestelde rotor draait
trager (M4) knikken.
2. Bespreking van de onderdelen.
2.1. Kader: - Plaat waarop de elektronica gemonteerd wordt.
- 4 armen worden gemonteerd aan de centrale plaat.
- 4 beugels verbinden de motoren met de uiteinden van de armen.
- Best uit carbon (licht en sterk)
2.2. Rotoren: Best borstelloze motoren (hogere snelheid en minder energieverbruik)
2.3. Propellers: Hoe groter de diameter en de helling, hoe groter de voortstuwingskracht.
2.4. Snelheidsregelaars: Noodzakelijk voor stabiliteit.
2.5. Batterij: Lipo batterij (licht).
2.6. Sensoren: Gegevens geheugenbord snelheid motoren bepalen.
2.7. Geheugenbord: Zelf samenstellen of kant-en-klaar kopen.
2.8. Zender: Stabiele modus best voor beginners.




Pagina 110


3. Technical things you learned:

Brushless motors
Een brushless of borstelloze motor is een motor die zonder koolborstels werkt. De 3
spoelen zijn gemonteerd in het centrum van de motor en de magneten zitten op een
cilinder die vastzit aan de ronddraaiende as (de rotor). Zodra de magneten
ronddraaien langs de spoelen, begint de as te draaien en de motor te werken. De
spoelen zijn rechtstreeks verbonden met de motoren zonder tussenkomst van borstels.

Propellers
Wanneer de motoren een hoog toerental hebben, moeten de propellers klein of
middelmatig zijn. Wanneer de motoren een laag toerental hebben, moeten de
propellers groot zijn. Dit komt omdat je in problemen zou kunnen komen wanneer je
kleine propellers gebruikt in combinatie met motoren die maar een laag toerental
hebben. De kleine propellers zouden niet in staat zijn om de quadrocopter omhoog te
liften bij een lage snelheid.

RC transmitter
Quadrocopters kunnen geprogrammeerd en gestuurd worden op verschillende
manieren. De voornaamste twee zijn acrobatic mode en stable mode. Naargelang de
modus interpreteert de transmitter de signalen verschillend. De stable mode is voor
beginners. De quadrocopter stabiliseert zichzelf steeds opnieuw. Bij de acrobatic mode
is het bijvoorbeeld mogelijk om een bepaalde helling aan te houden na het loslaten van
de joysticks. De acrobatic mode kan handig zijn bij het uitvoeren van allerlei kunstjes.
Het nadeel is hier wel dat de quadrocopter zichzelf niet terug stabiliseert zoals bij de
stable mode.

4. Personal opinion:

We enjoyed reading the text and doing the assignment. The text is logically build up. It
gives a good synopsis of the consecutive steps you have to take when you make up
your mind to construct a quadrocopter. It is obvious that the text is meant for
hobbyists. Some technicalities are not sufficiently worked out. We already work some
months on the construction of a quadrocopter, so this text comes in fact too late. We
should have studied this text in the beginning. Now, it added little new knowledge to
our know-how.






Pagina 111


Bijlagen

Bijlage 1: Toepassing quadrocopter: aan huis leveren






Pagina 112


Bijlage 2: Toepassing quadrocopter: Google Earth fotos









Pagina 113


Bijlage 3: Toepassing quadrocopter: Woning verkopen







Pagina 114


Bijlage 4: Student krijgt een drone cadeau









Pagina 115


Bijlage 5: Toepassing quadrocopter: Bacterie opsporen






Pagina 116


Bijlage 6: Mobistar Newsletter





Deze vederlichte telegeleide vliegtuigjes vind je overal. Zijn
drones gewoon zomerspeelgoed of luiden ze een revolutie in?
Vandaag zijn drones zeer gegeerd en ze lijken alleen maar aan
populariteit te winnen: The sky is the limit!



Een drone is een onbemand, telegeleide vliegtuigje. Oorspronkelijk werden drones
gebruikt voor militaire verkenning en transport en voor bewakings-, inlichtingen- en
gevechtsmissies. Het Franse Parrot heeft er een vlot verkopend speeltje van gemaakt
dat je met je smartphone op afstand kan besturen: de AR Drone.
Vandaag is het gebruik van drones wijdverspreid. In de Verenigde Staten heeft
Amazon plannen om de vliegtuigjes in te zetten voor Amazon Air Prime, een nieuwe
dienst waarbij de drones de pakjes binnen het halfuur na de bestelling bij de klant aan
huis zouden leveren. In Genk kocht de gemeente twee jaar geleden al een
drone om sommige evenementen in de gaten te houden.
En stel je voor dat het internet, dankzij de drones, zomaar uit de lucht komt vallen!
Terwijl Google ballonnen heeft opgelaten om mensen die in ongunstige regios te
wonen toch toegang te geven tot het internet, stelt Facebook eenzelfde ervaring
voor met drones, eveneens met de bedoeling om internet mogelijk te maken in alle
uithoeken van de wereld waar het nog niet zo verspreid is.
Deze spectaculaire video van de uitbarsting van een vulkaan op het eiland Tanna in
Vanuatu werd ook gemaakt door een drone.
Iedereen kan een drone besturen. Je moet daarvoor nog geen Parrot kopen. Steek de
handen uit de mouwen met het ArduCopter-project dat online gelanceerd werd door
de community DIYdrones.com. Deze drone is uitgerust met een gps-ontvanger, een
barometer en gyroscopen. Bovendien is er plaats voor een uitgebreid assortiment aan
opties, zoals bijvoorbeeld een camera. Deze vliegende opensource robot viert
binnenkort zijn vierde verjaardag en is de eerste in zijn soort. Ben jij een doe-het-
zelver? Klik dan snel door naar de officile site.






Pagina 117


Bijlage 7: Toepassing quadrocopter:
De ronde van Vlaanderen volgen vanuit de lucht









Pagina 118


Bijlage 8: Toepassing quadrocopter: Meer dan enkel vliegen


Gedachten laten quadrocopter
opstijgen en rondvliegen
Geschreven door Nathalie Prez

Studenten lieten een quadrocopter die normaal met een afstandsbediening
bestuurbaar is, met hun gedachten opstijgen en rondvliegen. De quadrocopter
maakte geen brokken: hij vloog zelfs probleemloos door hoepels.
De uitvinding is niet bedoeld als speeltje hoe leuk dat ook moge zijn het helpt
toekomstige oplossingen te maken voor slachtoffers die verlamd zijn of een
neurodegeneratieve aandoeningen hebben. Zo kunnen mensen met een
neurodegeneratieve aandoening steeds moeilijker bewegen of spreken. Robots
kunnen dan aangestuurd worden door gedachten waardoor een patint zelfstandiger
kan blijven leven.

Gedachten
Ons onderzoek is het eerste dat laat zien dat mensen vliegende robots kunnen
besturen met alleen hun gedachten, in de vorm van onvoelbare hersengolven, zegt
Bin He, hoofd van het onderzoek aan de University of Minnesota College of Science
and Engineering. Met slechts onze gedachten kunnen we dus een object besturen. En
daar hebben we geen uitzonderlijke ruimtelijke skills of een vliegbewijs voor nodig.





Pagina 119


Testvlucht
Vijf deelnemers (drie vrouwen, twee mannen) testten de quadrocoptervlucht uit.
Oefening bleek bijna niet nodig te zijn: alle deelnemers konden voor lange tijd de
quadrocopter snel en zorgvuldig besturen. Met elektro-encefalografie (EEG), waarbij
een persoon een soort netje met 64 elektrodes over het hoofd krijgt, registreerden de
onderzoekers de elektrische activiteit van het brein. De deelnemers moesten eerst
zonder naar de quadrocopter te kijken, denken aan het ballen van de rechterhand, de
linkerhand of beide handen tegelijk. Hiermee bestuurden zij het vliegende apparaat
door het naar rechts te keren, naar links te keren of het te laten stijgen. De snelheid
waarop de quadrocopter vloog, was net zoals de gedachten waarop het apparaat
moest reageren vooraf ingesteld. Na deze test en uitleg namen de deelnemers plaats
achter een scherm waarop ze het beeld zagen van de camera aan boord van de
quadrocopter. Het EEG-netje nam de signalen van het brein op en zond ze met
behulp van WiFi door naar de quadrocopter.

De helikopter in actie
[youtube http://www.youtube.com/watch?v=6LWz4qa2XQA&w=600&h=315]
Ik koos voor een quadrocopter in plaats van een helikopter omdat deze stabieler is,
vloeiender beweegt en minder veiligheidsrisicos heeft, vertelt He. Na verschillende
trainingssessies moesten de deelnemers zo vaak als zij konden de quoadrocopter
door een kort parcours van ringen van schuim laten vliegen. Voor de vergelijking deed
een andere groep hetzelfde, maar dan met een toetsenbord in plaats van de
gedachtebesturing. De onderzoekers telden hoe vaak het lukte, hoe vaak de
quadrocopter de ringen raakte en hoe vaak het apparaat buiten zijn afgezette terrein
kwam. De quadrocopter met het toetsenbord besturen was gemakkelijker, maar de
gedachtenbestuurders deden het helemaal niet slecht. De score van de
toetsenbordbestuurders werd op 100 procent vastgesteld. Met de bovengenoemde
getelde foutjes kwamen de gedachtenbestuurders uit op een gemiddelde score van
76 procent.
Ons volgende doel is om robotarmen te besturen met het uiteindelijke doel brein-
computer-interfaces te ontwikkelen die patinten met een handicap of
neurodegeneratieve aandoeningen helpt, schrijft de bedenker van de
gedachtebesturing in zijn paper in Journal of Neural Engineering .






Pagina 120


Bijlage 9: Toepassing quadrocopter: Opsporingen


Drone ontdekt 1000 jaar oud
dorpje in Nieuw-Mexico
Geschreven door Caroline Kraaijvanger op 13 mei 2014

Een drone heeft in het noordwesten van Nieuw-Mexico een 1000 jaar oud dorpje
ontdekt. De resten van het dorpje gingen schuil onder beplanting en gerodeerd
zandsteen. Ondanks dat spoorde de drone het dorp in enkele dagen tijd op.
De drone was uitgerust met een warmtecamera en maakte heel veel fotos van het
betreffende gebied. Archeologen voegden al die fotos vervolgens samen en dat
resulteerde in een warmtekaart. De drone met zijn warmtecamera was niet alleen in
staat om begraven metselwerk waarvan ik niet wist dat het bestond, aan te tonen,
maar identificeerde ook een aantal cirkelvormige structuren, vertelt onderzoeker John
Kantner. De vorm en grootte van deze structuren wijzen erop dat het gaat om kivas:
ceremonile gebouwen waarin mensen samenkwamen om belangrijke beslissingen te
nemen en de goden te aanbidden.
Ik was heel blij met de resultaten, stelt archeoloog Jesse Casana. Dit onderzoek
laat zien dat drones een belangrijke rol kunnen spelen in wetenschappelijk
onderzoek. Het vinden van runes die begraven liggen onder zand of schuilgaan
onder begroeiing, is zonder de drone lastig. Het betekent dat mensen op de gok
moeten gaan graven en dan maar moeten hopen iets tegen te komen. Het is een
tijdrovend en duur proces. Met de drone kunnen dorpjes in een paar dagen tijd
worden opgespoord. Een paar dagen werk stelde ons in staat om iets te doen wat
normaal gesproken tien jaar werk zou zijn, stelt Kantner.





Pagina 121


Archeologen weten al tientallen jaren dat warmtecameras die vanuit de lucht fotos
maken van een gebied een veelbelovende manier zijn om oude gebouwen op te
sporen. Lang lag dat technologisch buiten bereik. Maar die tijd is voorbij, zo schrijven
de onderzoekers. Als het aan hen ligt, gaat de drone standaard deel uitmaken van de
gereedschappenkist van de archeoloog.

Boven: de drone die de onderzoekers gebruikten. Onder: de beelden die de drone maakte (links),
de structuren die daarop te zien zijn (midden) en het gebied zoals wij mensen dat vanuit de lucht
zien (rechts). Afbeeldingen: University of North Florida.





Pagina 122


Bijlage 10: Aluminium armen







Pagina 123


Bijlage 11: Onderste baseplate:







Pagina 124


Bijlage 12: Bovenste baseplate:






Pagina 125


Bijlage 13-14: Deckplate en aluminium stand-offs







Pagina 126


Bijlage 15: Afgewerkte quadrocopter









Pagina 127


Bijlage 16: Email naar modelbouwwinkel Verbrugghe









Pagina 128









Pagina 129


Bijlage 17: Aankoopticket bij Aerobertics (1)










Pagina 130


Bijlage 18: Theoretische prijslijst


Prijslijst

W
A
T


A
A
N
T
A
L

L
E
V
E
R
A
N
C
I
E
R


T
H
E
O
R
E
T
I
S
C
H
E

P
R
I
J
S

P
E
R

S
T
U
K


T
O
T
A
L
E

T
H
E
O
R
E
T
I
S
C
H
E

P
R
I
J
S


Carbonplaat 2 Conrad 29,99 59,98
Aluminium profielen 4 School 0,00 0,00
Aluminium stand-offs 4 School 0,00 0,00
Nylon standoffs 8 Stock Vermeersch 0,10 0,80
Brushless DC-motoren 4 Hobbyking 8,87 35,48
Propellors 6 Hobbyking 0,31 1,86
Flight Controller Board (Multiwii) 1 Multiwii 20,46 20,46
ESC 4 Hobbywing 7,40 29,60
Ontvanger Spektrum 1 Hellipal 11,05 11,05
Ontvanger Bluetooth 1 BlueSkyRC.com 11,12 11,12
Lipo Battery 1 Ultimate hobby's 58,60 58,60
Bananenstekker 12 Hobbyking 1,70 20,40
Isoleerslang 3 Conrad 0,45 1,35
Powerboard 1 Aliexpress.com 5,81 5,81

Led Lampen 4 0,00 0,00
M3 bouten en sluitringen 12 0,00 0,00
Afstandsbediening 1 Vriend 0,00 0,00
Landingsgestel 1 BlueSkyRC.com 5,19 5,19


TOTAAL: 261,70

De Led lampen hadden we nog niet gevonden voor we begonnen dus staat dit hier niet in.
De bouten en sluitringen kosten niet zo veel dus werd dit niet in rekening gebracht. De
afstandsbediening was van een vriend.




Pagina 131


Bijlage 19: Prijslijst werkelijk betaalde prijzen


Prijslijst project

W
A
T

A
A
N
T
A
L

L
E
V
E
R
A
N
C
I
E
R

E
E
N
H
E
I
D
S
P
R
I
J
S

T
O
T
A
L
E

T
H
E
O
R
E
T
I
S
C
H
E

P
R
I
J
S

Carbonplaat 350x150x1,5 2 Aerobertics 35,90 71,80
Brushless DC-motoren + ESC 4 Aerobertics 44,10 176,40
UBEC 1 Hobbyking 7,75 7,75
Propellors (2 pcs) 2 Aerobertics 4,95 9,90
Lipo Battery 1 Aerobertics 19,90 19,90
Powerboard 1 Aerobertics 10,90 10,90
Aluminium profielen 4 Stock Vermeersch 0,42 1,66
Aluminium stand-offs 4 School 0,00 0,00
Nylon standoffs (bouten) 30 Stock Vermeersch 0,05 1,50
Flight Controller Board (Multiwii) 1 Hobbyking 38,01 38,01
Receiver Rx + transmitter Tx 1 Vriend (lenen) 0,00 0,00
Led Lampen 2 Aerobertics 4,80 9,60
M3 bouten/moeren en sluitringen 30 Stock Vermeersch 0,05 1,50
Servo-leads (bedrading) 10 Hobbyking 0,72 7,20
Landingsgestel 4 Aerobertics 4,80 19,20
Kortingen 1 Aerobertics - 4,50 - 4,50


TOTAAL: 370,82

Ons project kost in totaal 370,82. Dit zijn alle onderdelen die in de quadrocopter zijn
gemonteerd.






Pagina 132





Prijslijst extra kosten

W
A
T

A
A
N
T
A
L

L
E
V
E
R
A
N
C
I
E
R

E
E
N
H
E
I
D
S
S
T
U
K

T
O
T
A
L
E

T
H
E
O
R
E
T
I
S
C
H
E

P
R
I
J
S

Powerset (baterijlader) 1 Aerobertics 56,00 56,00
Laadkabel 1 Aerobertics 8,50 8,50
Aansluitpin (solderen) 1 Aerobertics 1,10 1,10
Schuurpapier 3 Stock Vermeersch 0,39 1,17
Wipzaagjes (5 pcs) 1 Stock Vermeersch 2,94 2,94
Boor diameter 3 1 Stock Vermeersch 1,55 1,55
Boor diameter 8 1 Stock Vermeersch 1,95 1,95
Boor diameter 12 1 Stock Vermeersch 8,66 8,66
Servo lead splitter 1 Hobbyking 0,13 0,13
Flight Controller Board (Multiwii) 1 Hobbyking 36,01 36,01
Bananenstekkers 10 Aerobertics 1,10 11,00
Verlengkabel (baterijlader) 1 Aerobertics 3,35 3,35
Krimpkous 2 Aerobertics 1,40 2,80
0,00
0,00
0,00


TOTAAL: 135,16


Naast de kosten voor ons project hebben we nog kosten die we eenmalig moeten doen, zoals
bijvoorbeeld een batterijlader.





Pagina 133


Bijlage 20: De voorwaarden (quadrocopter tussen 1 en 150 kg)









Pagina 134









Pagina 135







Pagina 136







Pagina 137







Pagina 138







Pagina 139







Pagina 140







Pagina 141







Pagina 142







Pagina 143







Pagina 144







Pagina 145







Pagina 146







Pagina 147







Pagina 148







Pagina 149







Pagina 150







Pagina 151







Pagina 152







Pagina 153







Pagina 154


Bijlage 21: Aankoopticket Stock Americain Vermeersch









Pagina 155


Bijlage 22: Inschijving wedstrijd Paola





Pagina 156











Pagina 157


Bijlage 23: Het programma
Main program
#include <avr/io.h>

#include "config.h"

#include <avr/pgmspace.h>
#define VERSION 210

/*********** RC alias *****************/
#define ROLL 0
#define PITCH 1
#define YAW 2
#define THROTTLE 3
#define AUX1 4
#define AUX2 5
#define AUX3 6
#define AUX4 7

#define PIDALT 3
#define PIDPOS 4
#define PIDPOSR 5
#define PIDNAVR 6
#define PIDLEVEL 7
#define PIDMAG 8
#define PIDVEL 9 // not used currently

#define BOXACC 0
#define BOXBARO 1
#define BOXMAG 2
#define BOXCAMSTAB 3
#define BOXCAMTRIG 4
#define BOXARM 5
#define BOXGPSHOME 6
#define BOXGPSHOLD 7
#define BOXPASSTHRU 8
#define BOXHEADFREE 9
#define BOXBEEPERON 10
#define BOXLEDMAX 11 // we want maximum illumination
#define BOXLLIGHTS 12 // enable landing lights at any altitude (not needed)
#define BOXHEADADJ 13 // acquire heading for HEADFREE mode

#define PIDITEMS 10
#define CHECKBOXITEMS 14





Pagina 158


const char boxnames[] PROGMEM = // names for dynamic generation of config GUI
"ACC;"
"BARO;"
"MAG;"
"CAMSTAB;"
"CAMTRIG;"
"ARM;"
"GPS HOME;"
"GPS HOLD;"
"PASSTHRU;"
"HEADFREE;"
"BEEPER;"
"LEDMAX;"
"LLIGHTS;"
"HEADADJ;"
;

const char pidnames[] PROGMEM =
"ROLL;"
"PITCH;"
"YAW;"
"ALT;"
"Pos;"
"PosR;"
"NavR;"
"LEVEL;"
"MAG;"
"VEL;"
;

static uint32_t currentTime = 0;
static uint16_t previousTime = 0;
static uint16_t cycleTime = 0;// this is the number in micro second to achieve a full loop
static uint16_t calibratingA = 0; // the calibration is done in the main loop. Calibrating decreases at each cycle down to 0, then normal mode.
static uint16_t calibratingG;
static uint16_t acc_1G; // this is the 1G measured acceleration
static int16_t acc_25deg;
static int16_t headFreeModeHold;
static int16_t gyroADC[3],accADC[3],accSmooth[3],magADC[3];
static int16_t heading,magHold;
static uint8_t vbat; // battery voltage in 0.1V steps
static uint8_t rcOptions[CHECKBOXITEMS];
static int32_t BaroAlt;
static int32_t EstAlt; // in cm
static int16_t BaroPID = 0;
static int32_t AltHold;
static int16_t errorAltitudeI = 0;
#if defined(BUZZER)
static uint8_t toggleBeep = 0;




Pagina 159


#endif
#if defined(ARMEDTIMEWARNING)
static uint32_t ArmedTimeWarningMicroSeconds = 0;
#endif

static int16_t debug[4];
static int16_t sonarAlt; //to think about the unit

struct flags_struct {
uint8_t OK_TO_ARM :1 ;
uint8_t ARMED :1 ;
uint8_t I2C_INIT_DONE :1 ; // For i2c gps we have to now when i2c init is done, so we can update parameters to the i2cgps from eeprom
uint8_t ACC_CALIBRATED :1 ;
uint8_t NUNCHUKDATA :1 ;
uint8_t ACC_MODE :1 ;
uint8_t MAG_MODE :1 ;
uint8_t BARO_MODE :1 ;
uint8_t GPS_HOME_MODE :1 ;
uint8_t GPS_HOLD_MODE :1 ;
uint8_t HEADFREE_MODE :1 ;
uint8_t PASSTHRU_MODE :1 ;
uint8_t GPS_FIX :1 ;
uint8_t GPS_FIX_HOME :1 ;
uint8_t SMALL_ANGLES_25 :1 ;
uint8_t CALIBRATE_MAG :1 ;
} f;

static int16_t i2c_errors_count = 0;
static int16_t annex650_overrun_count = 0;



// *******************************
//Automatic ACC Offset Calibration
// *******************************
#if defined(INFLIGHT_ACC_CALIBRATION)
static uint16_t InflightcalibratingA = 0;
static int16_t AccInflightCalibrationArmed;
static uint16_t AccInflightCalibrationMeasurementDone = 0;
static uint16_t AccInflightCalibrationSavetoEEProm = 0;
static uint16_t AccInflightCalibrationActive = 0;
#endif






Pagina 160


// ************************
// power meter (not needed)
// ************************
#if defined(POWERMETER)
#define PMOTOR_SUM 8 // index into pMeter[] for sum
static uint32_t pMeter[PMOTOR_SUM + 1]; // we use [0:7] for eight motors,one extra for sum
static uint8_t pMeterV; // dummy to satisfy the paramStruct logic in ConfigurationLoop()
static uint32_t pAlarm; // we scale the eeprom value from [0:255] to this value we can directly compare to the sum in pMeter[6]
static uint16_t powerValue = 0; // last known current
#endif
static uint16_t intPowerMeterSum, intPowerTrigger1;

// **********************
// telemetry (not needed)
// **********************
#if defined(LCD_TELEMETRY)
static uint8_t telemetry = 0;
static uint8_t telemetry_auto = 0;
#endif
// ******************
// rc functions
// ******************
#define MINCHECK 1100
#define MAXCHECK 1900

static int16_t failsafeEvents = 0;
volatile int16_t failsafeCnt = 0;

static int16_t rcData[8]; // interval [1000;2000]
static int16_t rcCommand[4]; // interval [1000;2000] for THROTTLE and [-500;+500] for ROLL/PITCH/YAW
static int16_t lookupPitchRollRC[6];// lookup table for expo & RC rate PITCH+ROLL
static int16_t lookupThrottleRC[11];// lookup table for expo & mid THROTTLE
volatile uint8_t rcFrameComplete; // for serial rc receiver Spektrum

#if defined(OPENLRSv2MULTI)
static uint8_t pot_P,pot_I; // OpenLRS onboard potentiometers for P and I trim or other usages
#endif

// **************
// gyro+acc IMU
// **************
static int16_t gyroData[3] = {0,0,0};
static int16_t gyroZero[3] = {0,0,0};
static int16_t angle[2] = {0,0}; // absolute angle inclination in multiple of 0.1 degree 180 deg = 1800






Pagina 161


// *************************
// motor and servo functions
// *************************
static int16_t axisPID[3];
static int16_t motor[NUMBER_MOTOR];
#if defined(SERVO)
static int16_t servo[8] = {1500,1500,1500,1500,1500,1500,1500,1500};
#endif

// ************************
// EEPROM Layout definition
// ************************
static uint8_t dynP8[3], dynD8[3];
static struct {
uint8_t checkNewConf;
uint8_t P8[PIDITEMS], I8[PIDITEMS], D8[PIDITEMS];
uint8_t rcRate8;
uint8_t rcExpo8;
uint8_t rollPitchRate;
uint8_t yawRate;
uint8_t dynThrPID;
uint8_t thrMid8;
uint8_t thrExpo8;
int16_t accZero[3];
int16_t magZero[3];
int16_t angleTrim[2];
uint16_t activate[CHECKBOXITEMS];
uint8_t powerTrigger1;
#ifdef FLYING_WING
uint16_t wing_left_mid;
uint16_t wing_right_mid;
#endif
#ifdef TRI
uint16_t tri_yaw_middle;
#endif
#if defined HELICOPTER || defined(AIRPLANE)|| defined(SINGLECOPTER)|| defined(DUALCOPTER)
int16_t servoTrim[8];
#endif
#if defined(GYRO_SMOOTHING)
uint8_t Smoothing[3];
#endif
} conf;







Pagina 162


// **********************
// GPS common variables
// **********************
static int32_t GPS_coord[2];
static int32_t GPS_home[2];
static int32_t GPS_hold[2];
static uint8_t GPS_numSat;
static uint16_t GPS_distanceToHome; // distance to home in meters
static int16_t GPS_directionToHome; // direction to home in degrees
static uint16_t GPS_altitude,GPS_speed; // altitude in 0.1m and speed in 0.1m/s
static uint8_t GPS_update = 0; // it's a binary toogle to distinct a GPS position update
static int16_t GPS_angle[2] = { 0, 0}; // it's the angles that must be applied for GPS correction
static uint16_t GPS_ground_course = 0; // degrees*10
static uint8_t GPS_Present = 0; // Checksum from Gps serial
static uint8_t GPS_Enable = 0;

#define LAT 0
#define LON 1
// The desired bank towards North (Positive) or South (Negative) : latitude
// The desired bank towards East (Positive) or West (Negative) : longitude
static int16_t nav[2];
static int16_t nav_rated[2]; //Adding a rate controller to the navigation to make it smoother

// default POSHOLD control gains
#define POSHOLD_P .11
#define POSHOLD_I 0.0
#define POSHOLD_IMAX 20 // degrees

#define POSHOLD_RATE_P 2.0
#define POSHOLD_RATE_I 0.08 // Wind control
#define POSHOLD_RATE_D 0.045 // try 2 or 3 for POSHOLD_RATE 1
#define POSHOLD_RATE_IMAX 20 // degrees

// default Navigation PID gains
#define NAV_P 1.4
#define NAV_I 0.20 // Wind control
#define NAV_D 0.08 //
#define NAV_IMAX 20 // degrees

//navigation mode
#define NAV_MODE_NONE 0
#define NAV_MODE_POSHOLD 1
#define NAV_MODE_WP 2
static uint8_t nav_mode = NAV_MODE_NONE; //Navigation mode






Pagina 163


void blinkLED(uint8_t num, uint8_t wait,uint8_t repeat) {
uint8_t i,r;
for (r=0;r<repeat;r++) {
for(i=0;i<num;i++) {
#if defined(LED_FLASHER)
switch_led_flasher(1);
#endif
#if defined(LANDING_LIGHTS_DDR)
switch_landing_lights(1);
#endif
LEDPIN_TOGGLE; // switch LEDPIN state
BUZZERPIN_ON;
delay(wait);
BUZZERPIN_OFF;
#if defined(LED_FLASHER)
switch_led_flasher(0);
#endif
#if defined(LANDING_LIGHTS_DDR)
switch_landing_lights(0);
#endif
}
delay(60);
}
}

void annexCode() { // this code is excetuted at each loop and won't interfere with control loop if it lasts less than 650 microseconds
static uint32_t calibratedAccTime;
uint16_t tmp,tmp2;
#if defined(BUZZER)
static uint8_t buzzerFreq; // delay between buzzer ring
#endif
uint8_t axis,prop1,prop2;

#define BREAKPOINT 1500
// PITCH & ROLL only dynamic PID adjustemnt, depending on throttle value
if (rcData[THROTTLE]<BREAKPOINT) {
prop2 = 100;
} else {
if (rcData[THROTTLE]<2000) {
prop2 = 100 - (uint16_t)conf.dynThrPID*(rcData[THROTTLE]-BREAKPOINT)/(2000-BREAKPOINT);
} else {
prop2 = 100 - conf.dynThrPID;
}
}






Pagina 164


for(axis=0;axis<3;axis++) {
tmp = min(abs(rcData[axis]-MIDRC),500);
#if defined(DEADBAND)
if (tmp>DEADBAND) { tmp -= DEADBAND; }
else { tmp=0; }
#endif
if(axis!=2) { //ROLL & PITCH
tmp2 = tmp/100;
rcCommand[axis] = lookupPitchRollRC[tmp2] + (tmp-tmp2*100) * (lookupPitchRollRC[tmp2+1]-lookupPitchRollRC[tmp2]) / 100;
prop1 = 100-(uint16_t)conf.rollPitchRate*tmp/500;
prop1 = (uint16_t)prop1*prop2/100;
} else { // YAW
rcCommand[axis] = tmp;
prop1 = 100-(uint16_t)conf.yawRate*tmp/500;
}
dynP8[axis] = (uint16_t)conf.P8[axis]*prop1/100;
dynD8[axis] = (uint16_t)conf.D8[axis]*prop1/100;
if (rcData[axis]<MIDRC) rcCommand[axis] = -rcCommand[axis];
}
tmp = constrain(rcData[THROTTLE],MINCHECK,2000);
tmp = (uint32_t)(tmp-MINCHECK)*1000/(2000-MINCHECK); // [MINCHECK;2000] -> [0;1000]
tmp2 = tmp/100;
rcCommand[THROTTLE] = lookupThrottleRC[tmp2] + (tmp-tmp2*100) * (lookupThrottleRC[tmp2+1]-lookupThrottleRC[tmp2]) / 100; // [0;1000] -> expo ->
[MINTHROTTLE;MAXTHROTTLE]
if(f.HEADFREE_MODE) { //to optimize
float radDiff = (heading - headFreeModeHold) * 0.0174533f; // where PI/180 ~= 0.0174533
float cosDiff = cos(radDiff);
float sinDiff = sin(radDiff);
int16_t rcCommand_PITCH = rcCommand[PITCH]*cosDiff + rcCommand[ROLL]*sinDiff;
rcCommand[ROLL] = rcCommand[ROLL]*cosDiff - rcCommand[PITCH]*sinDiff;
rcCommand[PITCH] = rcCommand_PITCH;
}

#if defined(POWERMETER_HARD)
uint16_t pMeterRaw; // used for current reading
static uint16_t psensorTimer = 0;
if (! (++psensorTimer % PSENSORFREQ)) {
pMeterRaw = analogRead(PSENSORPIN);
powerValue = ( PSENSORNULL > pMeterRaw ? PSENSORNULL - pMeterRaw : pMeterRaw - PSENSORNULL); // do not use abs()
if ( powerValue < 333) { // only accept reasonable values. 333 is empirical
#ifdef LCD_TELEMETRY
if (powerValue > powerMax) powerMax = powerValue;
#endif
} else {
powerValue = 333;
}
pMeter[PMOTOR_SUM] += (uint32_t) powerValue;
}
#endif




Pagina 165


#if defined(VBAT)
static uint8_t vbatTimer = 0;
static uint8_t ind = 0;
uint16_t vbatRaw = 0;
static uint16_t vbatRawArray[8];
if (! (++vbatTimer % VBATFREQ)) {
vbatRawArray[(ind++)%8] = analogRead(V_BATPIN);
for (uint8_t i=0;i<8;i++) vbatRaw += vbatRawArray[i];
vbat = vbatRaw / (VBATSCALE/2); // result is Vbatt in 0.1V steps
}
if ( ( (vbat>VBATLEVEL1_3S)
#if defined(POWERMETER)
&& ( (pMeter[PMOTOR_SUM] < pAlarm) || (pAlarm == 0) )
#endif
) || (NO_VBAT>vbat) ) // ToLuSe
{ // VBAT ok AND powermeter ok, buzzer off
buzzerFreq = 0;
#if defined(POWERMETER)
} else if (pMeter[PMOTOR_SUM] > pAlarm) { // sound alarm for powermeter
buzzerFreq = 4;
#endif
} else if (vbat>VBATLEVEL2_3S) buzzerFreq = 1;
else if (vbat>VBATLEVEL3_3S) buzzerFreq = 2;
else buzzerFreq = 4;
#endif
#if defined(BUZZER)
buzzer(buzzerFreq); // external buzzer routine that handles buzzer events globally now
#endif

if ( (calibratingA>0 && ACC ) || (calibratingG>0) ) { // Calibration phasis
LEDPIN_TOGGLE;
} else {
if (f.ACC_CALIBRATED) {LEDPIN_OFF;}
if (f.ARMED) {LEDPIN_ON;}
}

#if defined(LED_RING)
static uint32_t LEDTime;
if ( currentTime > LEDTime ) {
LEDTime = currentTime + 50000;
i2CLedRingState();
}
#endif

#if defined(LED_FLASHER)
auto_switch_led_flasher();
#endif


if ( currentTime > calibratedAccTime ) {




Pagina 166


if (! f.SMALL_ANGLES_25) {
// the multi uses ACC and is not calibrated or is too much inclinated
f.ACC_CALIBRATED = 0;
LEDPIN_TOGGLE;
calibratedAccTime = currentTime + 500000;
} else {
f.ACC_CALIBRATED = 1;
}
}

#if defined(GPS_PROMINI)
if(GPS_Enable == 0) {serialCom();}
#else
serialCom();
#endif

#if defined(POWERMETER)
intPowerMeterSum = (pMeter[PMOTOR_SUM]/PLEVELDIV);
intPowerTrigger1 = conf.powerTrigger1 * PLEVELSCALE;
#endif

#ifdef LCD_TELEMETRY_AUTO
static char telemetryAutoSequence [] = LCD_TELEMETRY_AUTO;
static uint8_t telemetryAutoIndex = 0;
static uint16_t telemetryAutoTimer = 0;
if ( (telemetry_auto) && (! (++telemetryAutoTimer % LCD_TELEMETRY_AUTO_FREQ) ) ){
telemetry = telemetryAutoSequence[++telemetryAutoIndex % strlen(telemetryAutoSequence)];
LCDclear(); // make sure to clear away remnants
}
#endif
#ifdef LCD_TELEMETRY
static uint16_t telemetryTimer = 0;
if (! (++telemetryTimer % LCD_TELEMETRY_FREQ)) {
#if (LCD_TELEMETRY_DEBUG+0 > 0)
telemetry = LCD_TELEMETRY_DEBUG;
#endif
if (telemetry) lcd_telemetry();
}
#endif

#if GPS & defined(GPS_LED_INDICATOR)
static uint32_t GPSLEDTime;
if ( currentTime > GPSLEDTime && (GPS_numSat >= 5)) {
GPSLEDTime = currentTime + 150000;
LEDPIN_TOGGLE;
}
#endif

#if defined(LOG_VALUES) && (LOG_VALUES == 2)
if (cycleTime > cycleTimeMax) cycleTimeMax = cycleTime; // remember highscore




Pagina 167


if (cycleTime < cycleTimeMin) cycleTimeMin = cycleTime; // remember lowscore
#endif
#ifdef LCD_TELEMETRY
if (f.ARMED) armedTime += (uint32_t)cycleTime;
#if BARO
if (!f.ARMED) {
BAROaltStart = BaroAlt;
BAROaltMax = BaroAlt;
} else {
if (BaroAlt > BAROaltMax) BAROaltMax = BaroAlt;
}
#endif
#endif
}

void setup() {
#if !defined(GPS_PROMINI)
SerialOpen(0,SERIAL_COM_SPEED);
#endif
LEDPIN_PINMODE;
POWERPIN_PINMODE;
BUZZERPIN_PINMODE;
STABLEPIN_PINMODE;
POWERPIN_OFF;
initOutput();
readEEPROM();
checkFirstTime();
configureReceiver();
#if defined(OPENLRSv2MULTI)
initOpenLRS();
#endif
initSensors();
#if defined(I2C_GPS) || defined(GPS_SERIAL) || defined(GPS_FROM_OSD)
GPS_set_pids();
#endif
previousTime = micros();
#if defined(GIMBAL)
calibratingA = 400;
#endif
calibratingG = 400;
#if defined(POWERMETER)
for(uint8_t i=0;i<=PMOTOR_SUM;i++)
pMeter[i]=0;
#endif
#if defined(ARMEDTIMEWARNING)
ArmedTimeWarningMicroSeconds = (ARMEDTIMEWARNING *1000000);
#endif
/************************************/
#if defined(GPS_SERIAL)
SerialOpen(GPS_SERIAL,GPS_BAUD);




Pagina 168


delay(400);
for(uint8_t i=0;i<=5;i++){
GPS_NewData();
LEDPIN_ON
delay(20);
LEDPIN_OFF
delay(80);
}
if(!GPS_Present){
SerialEnd(GPS_SERIAL);
SerialOpen(0,SERIAL_COM_SPEED);
}
#if !defined(GPS_PROMINI)
GPS_Present = 1;
#endif
GPS_Enable = GPS_Present;
#endif
/************************************/

#if defined(I2C_GPS) || defined(TINY_GPS) || defined(GPS_FROM_OSD)
GPS_Enable = 1;
#endif

#if defined(LCD_ETPP) || defined(LCD_LCD03) || defined(OLED_I2C_128x64)
initLCD();
#endif
#ifdef LCD_TELEMETRY_DEBUG
telemetry_auto = 1;
#endif
#ifdef LCD_CONF_DEBUG
configurationLoop();
#endif
#ifdef LANDING_LIGHTS_DDR
init_landing_lights();
#endif
ADCSRA |= _BV(ADPS2) ; ADCSRA &= ~_BV(ADPS1); ADCSRA &= ~_BV(ADPS0); // this speeds up analogRead without loosing too much resolution:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1208715493/11
#if defined(LED_FLASHER)
init_led_flasher();
led_flasher_set_sequence(LED_FLASHER_SEQUENCE);
#endif
f.SMALL_ANGLES_25=1; // important for gyro only conf
}





Pagina 169


// ******** Main Loop *********
void loop () {
static uint8_t rcDelayCommand; // this indicates the number of time (multiple of RC measurement at 50Hz) the sticks must be maintained to run or
switch
off motors
uint8_t axis,i;
int16_t error,errorAngle;
int16_t delta,deltaSum;
int16_t PTerm,ITerm,DTerm;
static int16_t lastGyro[3] = {0,0,0};
static int16_t delta1[3],delta2[3];
static int16_t errorGyroI[3] = {0,0,0};
static int16_t errorAngleI[2] = {0,0};
static uint32_t rcTime = 0;
static int16_t initialThrottleHold;
#ifdef LCD_TELEMETRY_STEP
static char telemetryStepSequence [] = LCD_TELEMETRY_STEP;
static uint8_t telemetryStepIndex = 0;
#endif

#if defined(SPEKTRUM)
if (rcFrameComplete) computeRC();
#endif
#if defined(OPENLRSv2MULTI)
Read_OpenLRS_RC();
#endif

#define RC_FREQ 50

if (currentTime > rcTime ) { // 50Hz
rcTime = currentTime + 20000;
computeRC();
// Failsafe routine - added by MIS
#if defined(FAILSAFE)
if ( failsafeCnt > (5*FAILSAVE_DELAY) && f.ARMED) { // Stabilize, and set Throttle to specified level
for(i=0; i<3; i++) rcData[i] = MIDRC; // after specified guard time after RC signal is lost (in 0.1sec)
rcData[THROTTLE] = FAILSAVE_THROTTLE;
if (failsafeCnt > 5*(FAILSAVE_DELAY+FAILSAVE_OFF_DELAY)) { // Turn OFF motors after specified Time (in 0.1sec)
f.ARMED = 0; // This will prevent the copter to automatically rearm if failsafe shuts it down and prevents
f.OK_TO_ARM = 0; // to restart accidentely by just reconnect to the tx - you will have to switch off first to rearm
}
failsafeEvents++;
}
if ( failsafeCnt > (5*FAILSAVE_DELAY) && !f.ARMED) { //Turn of "Ok To arm to prevent the motors from spinning after repowering the RX with low
throttle and aux to arm
f.ARMED = 0; // This will prevent the copter to automatically rearm if failsafe shuts it down and prevents
f.OK_TO_ARM = 0; // to restart accidentely by just reconnect to the tx - you will have to switch off first to rearm
}
failsafeCnt++;
#endif // end of failsave routine - next change is made with RcOptions setting




Pagina 170


if (rcData[THROTTLE] < MINCHECK) {
errorGyroI[ROLL] = 0; errorGyroI[PITCH] = 0; errorGyroI[YAW] = 0;
errorAngleI[ROLL] = 0; errorAngleI[PITCH] = 0;
rcDelayCommand++;
if (rcData[YAW] < MINCHECK && rcData[PITCH] < MINCHECK && !f.ARMED) {
if (rcDelayCommand == 20) {
calibratingG=400;
#if GPS
GPS_reset_home_position();
#endif
}
} else if (rcData[YAW] > MAXCHECK && rcData[PITCH] > MAXCHECK && !f.ARMED) {
if (rcDelayCommand == 20) {
#ifdef TRI
servo[5] = 1500; // we center the yaw servo in conf mode
writeServos();
#endif
#ifdef FLYING_WING
servo[0] = conf.wing_left_mid;
servo[1] = conf.wing_right_mid;
writeServos();
#endif
#ifdef AIRPLANE
for(i = 4; i<7 ;i++) servo[i] = 1500;
writeServos();
#endif
#if defined(LCD_CONF)
configurationLoop(); // beginning LCD configuration
#endif
previousTime = micros();
}
}





Pagina 171


#if defined(INFLIGHT_ACC_CALIBRATION)
else if (!f.ARMED && rcData[YAW] < MINCHECK && rcData[PITCH] > MAXCHECK && rcData[ROLL] > MAXCHECK){
if (rcDelayCommand == 20){
if (AccInflightCalibrationMeasurementDone){ // trigger saving into eeprom after landing
AccInflightCalibrationMeasurementDone = 0;
AccInflightCalibrationSavetoEEProm = 1;
}else{
AccInflightCalibrationArmed = !AccInflightCalibrationArmed;
#if defined(BUZZER)
if (AccInflightCalibrationArmed){
toggleBeep = 2;
} else {
toggleBeep = 3;
}
#endif }
}
}
}
#endif
else if (conf.activate[BOXARM] > 0) {
if ( rcOptions[BOXARM] && f.OK_TO_ARM
#if defined(FAILSAFE)
&& failsafeCnt <= 1
#endif
) {
f.ARMED = 1;
headFreeModeHold = heading;
} else if (f.ARMED) f.ARMED = 0;
rcDelayCommand = 0;
#ifdef ALLOW_ARM_DISARM_VIA_TX_YAW
} else if ( (rcData[YAW] < MINCHECK ) && f.ARMED) {
if (rcDelayCommand == 20) f.ARMED = 0; // rcDelayCommand = 20 => 20x20ms = 0.4s = time to wait for a specific RC command to be acknowledged
} else if ( (rcData[YAW] > MAXCHECK ) && rcData[PITCH] < MAXCHECK && !f.ARMED && calibratingG == 0 && f.ACC_CALIBRATED) {
if (rcDelayCommand == 20) {
f.ARMED = 1;
headFreeModeHold = heading;
}
#endif
#ifdef ALLOW_ARM_DISARM_VIA_TX_ROLL
} else if ( (rcData[ROLL] < MINCHECK) && f.ARMED) {
if (rcDelayCommand == 20) f.ARMED = 0; // rcDelayCommand = 20 => 20x20ms = 0.4s = time to wait for a specific RC command to be acknowledged
} else if ( (rcData[ROLL] > MAXCHECK) && rcData[PITCH] < MAXCHECK && !f.ARMED && calibratingG == 0 && f.ACC_CALIBRATED) {
if (rcDelayCommand == 20) {
f.ARMED = 1;
headFreeModeHold = heading;
}
#endif





Pagina 172


#ifdef LCD_TELEMETRY_AUTO
} else if (rcData[ROLL] < MINCHECK && rcData[PITCH] > MAXCHECK && !f.ARMED) {
if (rcDelayCommand == 20) {
if (telemetry_auto) {
telemetry_auto = 0;
telemetry = 0;
} else
telemetry_auto = 1;
}
#endif
#ifdef LCD_TELEMETRY_STEP
} else if (rcData[ROLL] > MAXCHECK && rcData[PITCH] > MAXCHECK && !f.ARMED) {
if (rcDelayCommand == 20) {
telemetry = telemetryStepSequence[++telemetryStepIndex % strlen(telemetryStepSequence)];
LCDclear(); // make sure to clear away remnants
}
#endif
} else
rcDelayCommand = 0;
} else if (rcData[THROTTLE] > MAXCHECK && !f.ARMED) {
if (rcData[YAW] < MINCHECK && rcData[PITCH] < MINCHECK) { // throttle=max, yaw=left, pitch=min
if (rcDelayCommand == 20) calibratingA=400;
rcDelayCommand++;
} else if (rcData[YAW] > MAXCHECK && rcData[PITCH] < MINCHECK) { // throttle=max, yaw=right, pitch=min
if (rcDelayCommand == 20) f.CALIBRATE_MAG = 1; // MAG calibration request
rcDelayCommand++;
} else if (rcData[PITCH] > MAXCHECK) {
conf.angleTrim[PITCH]+=2;writeParams(1);
#if defined(LED_RING)
blinkLedRing();
#endif
} else if (rcData[PITCH] < MINCHECK) {
conf.angleTrim[PITCH]-=2;writeParams(1);
#if defined(LED_RING)
blinkLedRing();
#endif
} else if (rcData[ROLL] > MAXCHECK) {
conf.angleTrim[ROLL]+=2;writeParams(1);
#if defined(LED_RING)
blinkLedRing();
#endif
} else if (rcData[ROLL] < MINCHECK) {
conf.angleTrim[ROLL]-=2;writeParams(1);
#if defined(LED_RING)
blinkLedRing();
#endif
} else {
rcDelayCommand = 0;
}}




Pagina 173


#if defined(LED_FLASHER)
led_flasher_autoselect_sequence();
#endif

#if defined(INFLIGHT_ACC_CALIBRATION)
if (AccInflightCalibrationArmed && f.ARMED && rcData[THROTTLE] > MINCHECK && !rcOptions[BOXARM] ){ // Copter is airborne and you are turning it
off
via boxarm : start measurement
InflightcalibratingA = 50;
AccInflightCalibrationArmed = 0;
}
if (rcOptions[BOXPASSTHRU]) { // Use the Passthru Option to activate : Passthru = TRUE Meausrement started, Land and passtrhu = 0
measurement
stored
if (!AccInflightCalibrationActive && !AccInflightCalibrationMeasurementDone){
InflightcalibratingA = 50;
}
}else if(AccInflightCalibrationMeasurementDone && !f.ARMED){
AccInflightCalibrationMeasurementDone = 0;
AccInflightCalibrationSavetoEEProm = 1;
}
#endif

uint16_t auxState = 0;
for(i=0;i<4;i++)
auxState |= (rcData[AUX1+i]<1300)<<(3*i) | (1300<rcData[AUX1+i] && rcData[AUX1+i]<1700)<<(3*i+1) | (rcData[AUX1+i]>1700)<<(3*i+2);
for(i=0;i<CHECKBOXITEMS;i++)
rcOptions[i] = (auxState & conf.activate[i])>0;

// note: if FAILSAFE is disable, failsafeCnt > 5*FAILSAVE_DELAY is always false
if (( rcOptions[BOXACC] || (failsafeCnt > 5*FAILSAVE_DELAY) ) && ACC ) {
// bumpless transfer to Level mode
if (!f.ACC_MODE) {
errorAngleI[ROLL] = 0; errorAngleI[PITCH] = 0;
f.ACC_MODE = 1;
}
} else {
// failsafe support
f.ACC_MODE = 0;
}

if (rcOptions[BOXARM] == 0) f.OK_TO_ARM = 1;
if (f.ACC_MODE) {STABLEPIN_ON;} else {STABLEPIN_OFF;}






Pagina 174


#if BARO
if (rcOptions[BOXBARO]) {
if (!f.BARO_MODE) {
f.BARO_MODE = 1;
AltHold = EstAlt;
initialThrottleHold = rcCommand[THROTTLE];
errorAltitudeI = 0;
BaroPID=0;
}
} else {
f.BARO_MODE = 0;
}
#endif
#if MAG
if (rcOptions[BOXMAG]) {
if (!f.MAG_MODE) {
f.MAG_MODE = 1;
magHold = heading;
}
} else {
f.MAG_MODE = 0;
}
if (rcOptions[BOXHEADFREE]) {
if (!f.HEADFREE_MODE) {
f.HEADFREE_MODE = 1;
}
} else {
f.HEADFREE_MODE = 0;
}
if (rcOptions[BOXHEADADJ]) {
headFreeModeHold = heading; // acquire new heading
}
#endif

if (rcOptions[BOXPASSTHRU]) {f.PASSTHRU_MODE = 1;}
else {f.PASSTHRU_MODE = 0;}

} else { // not in rc loop
static uint8_t taskOrder=0; // never call all functions in the same loop, to avoid high delay spikes





Pagina 175


switch (taskOrder++ % 5) {
case 0:
#if MAG
Mag_getADC();
#endif
break;
case 1:
#if BARO
Baro_update();
#endif
break;
case 2:
#if BARO
getEstimatedAltitude();
#endif
break;
case 3:
#if GPS
if(GPS_Enable) GPS_NewData();
#endif
break;
case 4:
#if SONAR
Sonar_update();debug[2] = sonarAlt;
#endif
#ifdef LANDING_LIGHTS_DDR
auto_switch_landing_lights();
#endif
break;
}
}

computeIMU();
// Measure loop rate just afer reading the sensors
currentTime = micros();
cycleTime = currentTime - previousTime;
previousTime = currentTime;

#if MAG
if (abs(rcCommand[YAW]) <70 && f.MAG_MODE) {
int16_t dif = heading - magHold;
if (dif <= - 180) dif += 360;
if (dif >= + 180) dif -= 360;
if ( f.SMALL_ANGLES_25 ) rcCommand[YAW] -= dif*conf.P8[PIDMAG]/30; // 18 deg
} else magHold = heading;
#endif






Pagina 176


#if BARO
if (f.BARO_MODE) {
if (abs(rcCommand[THROTTLE]-initialThrottleHold)>ALT_HOLD_THROTTLE_NEUTRAL_ZONE) {
f.BARO_MODE = 0; // so that a new althold reference is defined
}
rcCommand[THROTTLE] = initialThrottleHold + BaroPID;
}
#endif

//**** PITCH & ROLL & YAW & PID ****
for(axis=0;axis<3;axis++) {
if (f.ACC_MODE && axis<2 ) { //LEVEL MODE
// 50 degrees max inclination
errorAngle = constrain(2*rcCommand[axis] + GPS_angle[axis],-500,+500) - angle[axis] + conf.angleTrim[axis]; //16 bits is ok here
#ifdef LEVEL_PDF
PTerm = -(int32_t)angle[axis]*conf.P8[PIDLEVEL]/100 ;
#else
PTerm = (int32_t)errorAngle*conf.P8[PIDLEVEL]/100 ; // 32 bits is needed for calculation: errorAngle*P8[PIDLEVEL]
could exceed 32768 16 bits is ok for result
#endif
PTerm = constrain(PTerm,-conf.D8[PIDLEVEL]*5,+conf.D8[PIDLEVEL]*5);

errorAngleI[axis] = constrain(errorAngleI[axis]+errorAngle,-10000,+10000); // WindUp //16 bits is ok here
ITerm = ((int32_t)errorAngleI[axis]*conf.I8[PIDLEVEL])>>12; // 32 bits is needed for calculation:10000*I8 could exceed
32768
16 bits is ok for result
} else { //ACRO MODE or YAW axis
if (abs(rcCommand[axis])<350) error = rcCommand[axis]*10*8/conf.P8[axis] ; // 16 bits is needed for calculation: 350*10*8 = 28000
16
bits is ok for result if P8>2 (P>0.2)
else error = (int32_t)rcCommand[axis]*10*8/conf.P8[axis] ; // 32 bits is needed for calculation: 500*5*10*8 = 200000
16
bits is ok for result if P8>2 (P>0.2)
error -= gyroData[axis];

PTerm = rcCommand[axis];

errorGyroI[axis] = constrain(errorGyroI[axis]+error,-16000,+16000); // WindUp 16 bits is ok here
if (abs(gyroData[axis])>640) errorGyroI[axis] = 0;
ITerm = (errorGyroI[axis]/125*conf.I8[axis])>>6; // 16 bits is ok here 16000/125 = 128 ; 128*250 = 32000
}
if (abs(gyroData[axis])<160) PTerm -= gyroData[axis]*dynP8[axis]/10/8; // 16 bits is needed for calculation 160*200 = 32000 16
bits
is ok for result
else PTerm -= (int32_t)gyroData[axis]*dynP8[axis]/10/8; // 32 bits is needed for calculation

delta = gyroData[axis] - lastGyro[axis]; // 16 bits is ok here, the dif between 2 consecutive gyro reads is
limited to 800
lastGyro[axis] = gyroData[axis];
deltaSum = delta1[axis]+delta2[axis]+delta;




Pagina 177


delta2[axis] = delta1[axis];
delta1[axis] = delta;
if (abs(deltaSum)<640) DTerm = (deltaSum*dynD8[axis])>>5; // 16 bits is needed for calculation 640*50 = 32000 16
bits is ok for result
else DTerm = ((int32_t)deltaSum*dynD8[axis])>>5; // 32 bits is needed for calculation

axisPID[axis] = PTerm + ITerm - DTerm;
}

mixTable();
writeMotors();
}





Pagina 178


Config.h
Hier wordt alles in gezet dat te maken kan hebben met onze hardware.
Dit hebben we nodig om uiteindelijk in ons main program (zie hierboven) juist in te stellen op onze hardware.






/*************************************************************************************************/
/**** PARAMETERS ****/
/*************************************************************************************************/

/* this file consists of several sections
* 1 - BASIC SETUP - everything about HobbyKing MultiWii 328P
* 2 - COPTER TYPE SPECIFIC OPTIONS - options for your copter type (optional)
* 3 - RECEIVER & TRANSMITTER SETUP
* 4 - ALTERNATE CPUs & BOARDS - (if you have)
* 5 - ALTERNATE SETUP - select gyro filters, ...
* 6 - OPTIONAL FEATURES - enable nice to have features here (failsafe,...)
* 7 - ESC AUTOMATIC CALLIBRATION - if you know what you are doing (not easy!!!)
*/









Pagina 179


/*************************************************************************************************/
/***************** ***************/
/***************** SECTION 1 - BASIC SETUP (HobbyKing MultiWii 328P) ***************/
/***************** ***************/
/*************************************************************************************************/

// STANDARDS for HobbyKing MultiWii 328P (Quadrocopter X-mode)

#define QUADX
#define MULTITYPE 3 //Quadrocopter X-mode
#define NUMBER_MOTOR 4 //Number of motor's

#define MINTHROTTLE 1150 //Set the minimum throttle command sent to the ESC's
#define MAXTHROTTLE 1850 //The maximum value for the ESCs at full power, (up to 2000)
#define MINCOMMAND 1000 //This is the value for the ESCs when they are not armed

// BOARD AND SENSOR DEFINITIONS for HobbyKing MultiWii 328P

#undef INTERNAL_I2C_PULLUPS //disable internal I2C pull ups
#define I2C_SPEED 400000L //I2C speed: 400kHz (fast mode)

#define ITG3200 //I2C gyroscope
#define GYRO 1 //Gyroscope (1=on board / 0=not)

#define BMA180 //I2C accelerometer
#define ACC 1 //Accelerometer (1=on board / 0=not)

#define BMP085 //I2C barometer
#define BARO 1 //Barometer (1=on board / 0=not)

#define HMC5883 //I2C magnetometer
#define MAG 1 //Magnetometer (1=on board / 0=not)

//individual sensor orientations:
#define ACC_ORIENTATION(X, Y, Z) {accADC[ROLL] = -X; accADC[PITCH] = -Y; accADC[YAW] = Z;}
#define GYRO_ORIENTATION(X, Y, Z) {gyroADC[ROLL] = Y; gyroADC[PITCH] = -X; gyroADC[YAW] = -Z;}
#define MAG_ORIENTATION(X, Y, Z) {magADC[ROLL] = X; magADC[PITCH] = Y; magADC[YAW] = Z;}

#define SONAR 0 //Sonar (1=on board / 0=not)
#define GPS 0 //GPS (1=on board / 0=not)









Pagina 180


/*************************************************************************************************/
/***************** ***************/
/***************** SECTION 2 - COPTER TYPE SPECIFIC OPTIONS ***************/
/***************** ***************/
/*************************************************************************************************/

// YAW DIRECTION

#define YAW_DIRECTION 1
//#define YAW_DIRECTION -1 // if you want to reverse the yaw correction direction

// ARM / DISARM optionally disable stick combinations to arm/disarm the motors.

#define ALLOW_ARM_DISARM_VIA_TX_YAW //use the yaw
#define ALLOW_ARM_DISARM_VIA_TX_ROLL //use the roll






/*************************************************************************************************/
/***************** ***************/
/***************** SECTION 3 - RECIEVER 1 TRANSMITTER SETUP ***************/
/***************** ***************/
/*************************************************************************************************/

// RECEIVER
#define STANDARD_RX // Standard receiver
#define MIDRC 1500 //neutral point of radio (1500)

// TRANSMITTER
/* introduce a deadband around the stick center
Must be greater than zero, comment if you dont want a deadband on roll, pitch and yaw */
//#define DEADBAND 6

/* defines the neutral zone of throttle stick during altitude hold, default setting is
+/-20 uncommend and change the value below if you want to change it. */
#define ALT_HOLD_THROTTLE_NEUTRAL_ZONE 20 //20 is default







Pagina 181


/*************************************************************************************************/
/***************** ***************/
/**************** SECTION 4 - ALTERNATE CPUs & BOARDS *******/
/***************** ***************/
/*************************************************************************************************/

// Aux 2 Pin
/* possibility to use PIN8 or PIN12 as the AUX2 RC input (only one, not both)
it deactivates in this case the POWER PIN (pin 12) or the BUZZER PIN (pin 8) */
//#define RCAUXPIN8
//#define RCAUXPIN12

// Atmega32u4 Boards

//#define A32U4ALLPINS // activate this for a better pinlayout if all pins can be used
//#define D8BUZZER // This moves the Buzzer pin from TXO to D8 for use with ppm sum or spectrum sat. RX (not needed if A32U4ALLPINS is
active)

//#define RCAUX2PINRXO // AUX2 pin on pin RXO

//#define RCAUX2PIND17 // AUX2 pin on pin D17 (RX LED)









Pagina 182


/*************************************************************************************************/
/***************** ***************/
/**************** SECTION 5 - ALTERNATE SETUP *******/
/***************** ***************/
/*************************************************************************************************/

// Serial com speed

#define SERIAL_COM_SPEED 115200 // This is the speed of the serial interface
#define INTERLEAVING_DELAY 3000 // Interleaving delay in micro seconds between 2 readings WMP/NK in a WMP+NK config
#define NEUTRALIZE_DELAY 100000 // when there is an error on I2C bus, we neutralize the values during a short time. (microseconds)

// Gyro filters

/* ITG3200 Low pass filter setting. In case you cannot eliminate all vibrations to the Gyro, you can try
to decrease the LPF frequency, only one step per try. As soon as twitching gone, stick with that setting.
It will not help on feedback wobbles, so change only when copter is randomly twiching and all dampening and
balancing options ran out. Uncomment only one option!
IMPORTANT! Change low pass filter setting changes PID behaviour, so retune your PID's after changing LPF.*/
//#define ITG3200_LPF_256HZ // This is the default setting, no need to uncomment, just for reference
//#define ITG3200_LPF_188HZ
//#define ITG3200_LPF_98HZ
//#define ITG3200_LPF_42HZ
//#define ITG3200_LPF_20HZ
//#define ITG3200_LPF_10HZ // Use this only in extreme cases (rather change motors and/or props)

/* GYRO_SMOOTHING. In case you cannot reduce vibrations _and_ _after_ you have tried the low pass filter options, you
may try this gyro smoothing via averaging. Not suitable for multicopters!
Good results for helicopter, airplanes and flying wings (foamies) with lots of vibrations.*/
//#define GYRO_SMOOTHING {20, 20, 3} // separate averaging ranges for roll, pitch, yaw

// Moving Average Gyros
//#define MMGYRO // Active Moving Average Function for Gyros
//#define VECTORLENGHT 10 // Lenght of Moving Average Vector
// Moving Average ServoGimbal Signal Output
//#define MMSERVOGIMBAL // Active Output Moving Average Function for Servos Gimbal
//#define MMSERVOGIMBALVECTORLENGHT 32 // Lenght of Moving Average Vector









Pagina 183


/*************************************************************************************************/
/***************** ***************/
/**************** SECTION 6 - OPTIONAL FEATURES *******/
/***************** ***************/
/*************************************************************************************************/

// Failsave settings
/* Failsafe check pulse on THROTTLE channel. If the pulse is OFF (on only THROTTLE or on all channels) the failsafe procedure is initiated.
After FAILSAVE_DELAY time of pulse absence, the level mode is on (if ACC or nunchuk is avaliable), PITCH, ROLL and YAW is centered
and THROTTLE is set to FAILSAVE_THR0TTLE value. You must set this value to descending about 1m/s or so for best results.
This value is depended from your configuration, AUW and some other params.
Next, afther FAILSAVE_OFF_DELAY the copter is disarmed, and motors is stopped.
If RC pulse coming back before reached FAILSAVE_OFF_DELAY time, after the small quard time the RC control is returned to normal.
(If you use serial sum PPM, the sum converter must completly turn off the PPM SUM pusles for this FailSafe functionality.)*/
#define FAILSAFE // uncomment to activate the failsafe function
#define FAILSAVE_DELAY 10 // Guard time for failsafe activation after signal lost. (1 step = 0.1sec)
#define FAILSAVE_OFF_DELAY 200 // Time for Landing before motors stop in 0.1sec. (1 step = 0.1sec)
#define FAILSAVE_THROTTLE (MINTHROTTLE + 200) // Throttle level used for landing - may be relative to MINTHROTTLE - as in this case

// GPS
/* Get your magnetic decliniation from here : http://magnetic-declination.com/
Convert the degree+minutes into decimal degree by ==> degree+minutes*(1/60)
Note the sign on declination it could be negative or positive (WEST or EAST) */
#define MAG_DECLINIATION 0.37f //Brugge - Belgi



/*************************************************************************************************/
/***************** ***************/
/**************** SECTION 7 - ESC AUTOMATIC CALLIBRATION **************/
/***************** ***************/
/*************************************************************************************************/
/* to calibrate all ESCs connected to MWii at the same time (useful to avoid unplugging/re-plugging each ESC)
Warning: this creates a special version of MultiWii Code
You cannot fly with this special version. It is only to be used for calibrating ESCs
Read How To at http://code.google.com/p/multiwii/wiki/ESCsCalibration */
#define ESC_CALIB_LOW MINCOMMAND
#define ESC_CALIB_HIGH 2000
//#define ESC_CALIB_CANNOT_FLY // uncomment to activate

// INFLIGHT ACC Calibration
/* This will activate the ACC-Inflight calibration if unchecked */
//#define INFLIGHT_ACC_CALIBRATION


/*************************************************************************************************/
/**** END OF PARAMETERS ****/
/*************************************************************************************************/




Pagina 184


/**************************************************************************************/
/*************** specific definitions ********************/
/**************************************************************************************/

// atmega328P (Promini) on HobbyKing MultiWii 328P

#define PROMINI

#if !defined(MONGOOSE1_0)
#define LEDPIN_PINMODE pinMode (13, OUTPUT);
#define LEDPIN_TOGGLE PINB |= 1<<5; //switch LEDPIN state (digital PIN 13)
#define LEDPIN_OFF PORTB &= ~(1<<5);
#define LEDPIN_ON PORTB |= (1<<5);
#endif

#if !defined(RCAUXPIN8)
#if !defined(MONGOOSE1_0)
#define BUZZERPIN_PINMODE pinMode (8, OUTPUT);
#define BUZZERPIN_ON PORTB |= 1;
#define BUZZERPIN_OFF PORTB &= ~1;
#endif
#else
#define BUZZERPIN_PINMODE ;
#define BUZZERPIN_ON ;
#define BUZZERPIN_OFF ;
#define RCAUXPIN
#endif

#if !defined(RCAUXPIN12) && !defined(DISABLE_POWER_PIN)
#define POWERPIN_PINMODE pinMode (12, OUTPUT);
#define POWERPIN_ON PORTB |= 1<<4;
#define POWERPIN_OFF PORTB &= ~(1<<4); //switch OFF WMP, digital PIN 12
#else
#define POWERPIN_PINMODE ;
#define POWERPIN_ON ;
#define POWERPIN_OFF ;
#endif

#if defined(RCAUXPIN12)
#define RCAUXPIN
#endif

#define I2C_PULLUPS_ENABLE PORTC |= 1<<4; PORTC |= 1<<5; // PIN A4&A5 (SDA&SCL)
#define I2C_PULLUPS_DISABLE PORTC &= ~(1<<4); PORTC &= ~(1<<5);






Pagina 185


#if !defined(MONGOOSE1_0)
#define PINMODE_LCD pinMode(0, OUTPUT);
#define LCDPIN_OFF PORTD &= ~1; //switch OFF digital PIN 0
#define LCDPIN_ON PORTD |= 1;
#define STABLEPIN_PINMODE ;
#define STABLEPIN_ON ;
#define STABLEPIN_OFF ;
#endif

#define PPM_PIN_INTERRUPT attachInterrupt(0, rxInt, RISING); //PIN 0
#define SPEK_SERIAL_VECT USART_RX_vect
#define SPEK_DATA_REG UDR0

//RX PIN assignment inside the port
#define THROTTLEPIN 2
#define ROLLPIN 4
#define PITCHPIN 5
#define YAWPIN 6
#define AUX1PIN 7
#define AUX2PIN 0 // optional PIN 8 or PIN 12 ; see AUX2 configuration
#define AUX3PIN 1 // unused
#define AUX4PIN 3 // unused

#define PCINT_PIN_COUNT 5
#define PCINT_RX_BITS (1<<2),(1<<4),(1<<5),(1<<6),(1<<7)
#define PCINT_RX_PORT PORTD
#define PCINT_RX_MASK PCMSK2
#define PCIR_PORT_BIT (1<<2)
#define RX_PC_INTERRUPT PCINT2_vect
#define RX_PCINT_PIN_PORT PIND
#define ISR_UART ISR(USART_UDRE_vect)
#define V_BATPIN A3 // Analog PIN 3
#define PSENSORPIN A2 // Analog PIN 2





Pagina 186


EEPROM
#include <avr/eeprom.h>

#define EEPROM_CONF_VERSION 161

void readEEPROM() {
uint8_t i;

eeprom_read_block((void*)&conf, (void*)0, sizeof(conf));
for(i=0;i<6;i++) {
lookupPitchRollRC[i] = (2500+conf.rcExpo8*(i*i-25))*i*(int32_t)conf.rcRate8/2500;
}
for(i=0;i<11;i++) {
int16_t tmp = 10*i-conf.thrMid8;
uint8_t y = 1;
if (tmp>0) y = 100-conf.thrMid8;
if (tmp<0) y = conf.thrMid8;
lookupThrottleRC[i] = 10*conf.thrMid8 + tmp*( 100-conf.thrExpo8+(int32_t)conf.thrExpo8*(tmp*tmp)/(y*y) )/10; // [0;1000]
lookupThrottleRC[i] = MINTHROTTLE + (int32_t)(MAXTHROTTLE-MINTHROTTLE)* lookupThrottleRC[i]/1000; // [0;1000] ->
[MINTHROTTLE;MAXTHROTTLE]
}

#if defined(POWERMETER)
pAlarm = (uint32_t) conf.powerTrigger1 * (uint32_t) PLEVELSCALE * (uint32_t) PLEVELDIV; // need to cast before multiplying
#endif
#ifdef FLYING_WING
#ifdef LCD_CONF
conf.wing_left_mid = constrain(conf.wing_left_mid, WING_LEFT_MIN, WING_LEFT_MAX); //LEFT
conf.wing_right_mid = constrain(conf.wing_right_mid, WING_RIGHT_MIN, WING_RIGHT_MAX); //RIGHT
#else // w.o LCD support user may not find this value stored in eeprom, so always use the define value
conf.wing_left_mid = WING_LEFT_MID;
conf.wing_right_mid = WING_RIGHT_MID;
#endif
#endif
#ifdef TRI
#ifdef LCD_CONF
conf.tri_yaw_middle = constrain(conf.tri_yaw_middle, TRI_YAW_CONSTRAINT_MIN, TRI_YAW_CONSTRAINT_MAX); //REAR
#else // w.o LCD support user may not find this value stored in eeprom, so always use the define value
conf.tri_yaw_middle = TRI_YAW_MIDDLE;
#endif
#endif
#if GPS
if (f.I2C_INIT_DONE) GPS_set_pids();
#endif
}






Pagina 187


void writeParams(uint8_t b) {
conf.checkNewConf = EEPROM_CONF_VERSION; // make sure we write the current version into eeprom
eeprom_write_block((const void*)&conf, (void*)0, sizeof(conf));
readEEPROM();
if (b == 1) blinkLED(15,20,1);
}

void checkFirstTime() {
if (EEPROM_CONF_VERSION == conf.checkNewConf) return;
conf.P8[ROLL] = 40; conf.I8[ROLL] = 30; conf.D8[ROLL] = 23;
conf.P8[PITCH] = 40; conf.I8[PITCH] = 30; conf.D8[PITCH] = 23;
conf.P8[YAW] = 85; conf.I8[YAW] = 45; conf.D8[YAW] = 0;
conf.P8[PIDALT] = 16; conf.I8[PIDALT] = 15; conf.D8[PIDALT] = 7;

conf.P8[PIDPOS] = POSHOLD_P * 100; conf.I8[PIDPOS] = POSHOLD_I * 100; conf.D8[PIDPOS] = 0;
conf.P8[PIDPOSR] = POSHOLD_RATE_P * 10; conf.I8[PIDPOSR] = POSHOLD_RATE_I * 100; conf.D8[PIDPOSR] = POSHOLD_RATE_D * 1000;
conf.P8[PIDNAVR] = NAV_P * 10; conf.I8[PIDNAVR] = NAV_I * 100; conf.D8[PIDNAVR] = NAV_D * 1000;

conf.P8[PIDLEVEL] = 70; conf.I8[PIDLEVEL] = 10; conf.D8[PIDLEVEL] = 100;
conf.P8[PIDMAG] = 40;

conf.P8[PIDVEL] = 0; conf.I8[PIDVEL] = 0; conf.D8[PIDVEL] = 0;

conf.rcRate8 = 90; conf.rcExpo8 = 65;
conf.rollPitchRate = 0;
conf.yawRate = 0;
conf.dynThrPID = 0;
conf.thrMid8 = 50; conf.thrExpo8 = 0;
for(uint8_t i=0;i<CHECKBOXITEMS;i++) {conf.activate[i] = 0;}
conf.angleTrim[0] = 0; conf.angleTrim[1] = 0;
conf.powerTrigger1 = 0;
#ifdef FLYING_WING
conf.wing_left_mid = WING_LEFT_MID;
conf.wing_right_mid = WING_RIGHT_MID;
#endif
#ifdef FIXEDWING
conf.dynThrPID = 50;
conf.rcExpo8 = 0;
#endif
#ifdef TRI
conf.tri_yaw_middle = TRI_YAW_MIDDLE;
#endif
#if defined HELICOPTER || defined(AIRPLANE)|| defined(SINGLECOPTER)|| defined(DUALCOPTER)
{
int16_t s[8] = SERVO_OFFSET;
for(uint8_t i=0;i<8;i++) conf.servoTrim[i] = s[i];
}
#endif





Pagina 188


#if defined(GYRO_SMOOTHING)
{
uint8_t s[3] = GYRO_SMOOTHING;
for(uint8_t i=0;i<3;i++) conf.Smoothing[i] = s[i];
}
#endif
writeParams(0); // this will also (p)reset checkNewConf with the current version number again.
}

IMU
void computeIMU () {
uint8_t axis;
static int16_t gyroADCprevious[3] = {0,0,0};
int16_t gyroADCp[3];
int16_t gyroADCinter[3];
static uint32_t timeInterleave = 0;

//we separate the 2 situations because reading gyro values with a gyro only setup can be acchieved at a higher rate
//gyro+nunchuk: we must wait for a quite high delay betwwen 2 reads to get both WM+ and Nunchuk data. It works with 3ms
//gyro only: the delay to read 2 consecutive values can be reduced to only 0.65ms
#if defined(NUNCHUCK)
annexCode();
while((micros()-timeInterleave)<INTERLEAVING_DELAY) ; //interleaving delay between 2 consecutive reads
timeInterleave=micros();
ACC_getADC();
getEstimatedAttitude(); // computation time must last less than one interleaving delay
while((micros()-timeInterleave)<INTERLEAVING_DELAY) ; //interleaving delay between 2 consecutive reads
timeInterleave=micros();
f.NUNCHUKDATA = 1;
while(f.NUNCHUKDATA) ACC_getADC(); // For this interleaving reading, we must have a gyro update at this point (less delay)

for (axis = 0; axis < 3; axis++) {
// empirical, we take a weighted value of the current and the previous values
// /4 is to average 4 values, note: overflow is not possible for WMP gyro here
gyroData[axis] = (gyroADC[axis]*3+gyroADCprevious[axis])/4;
gyroADCprevious[axis] = gyroADC[axis];
}
#else
#if ACC
ACC_getADC();
getEstimatedAttitude();
#endif
#if GYRO
Gyro_getADC();
#endif





Pagina 189


for (axis = 0; axis < 3; axis++)
gyroADCp[axis] = gyroADC[axis];
timeInterleave=micros();
annexCode();
if ((micros()-timeInterleave)>650) {
annex650_overrun_count++;
} else {
while((micros()-timeInterleave)<650) ; //empirical, interleaving delay between 2 consecutive reads
}
#if GYRO
Gyro_getADC();
#endif
for (axis = 0; axis < 3; axis++) {
gyroADCinter[axis] = gyroADC[axis]+gyroADCp[axis];
// empirical, we take a weighted value of the current and the previous values
gyroData[axis] = (gyroADCinter[axis]+gyroADCprevious[axis])/3;
gyroADCprevious[axis] = gyroADCinter[axis]/2;
if (!ACC) accADC[axis]=0;
}
#endif
#if defined(GYRO_SMOOTHING)
static int16_t gyroSmooth[3] = {0,0,0};
for (axis = 0; axis < 3; axis++) {
gyroData[axis] = (int16_t) ( ( (int32_t)((int32_t)gyroSmooth[axis] * (conf.Smoothing[axis]-1) )+gyroData[axis]+1 ) / conf.Smoothing[axis]);
gyroSmooth[axis] = gyroData[axis];
}
#elif defined(TRI)
static int16_t gyroYawSmooth = 0;
gyroData[YAW] = (gyroYawSmooth*2+gyroData[YAW])/3;
gyroYawSmooth = gyroData[YAW];
#endif
}






Pagina 190


//****** advanced users settings *******************
/* Set the Low Pass Filter factor for ACC */
/* Increasing this value would reduce ACC noise (visible in GUI), but would increase ACC lag time*/
/* Comment this if you do not want filter at all.*/
#ifndef ACC_LPF_FACTOR
#define ACC_LPF_FACTOR 100
#endif

/* Set the Low Pass Filter factor for Magnetometer */
/* Increasing this value would reduce Magnetometer noise (not visible in GUI), but would increase Magnetometer lag time*/
/* Comment this if you do not want filter at all.*/
#ifndef MG_LPF_FACTOR
//#define MG_LPF_FACTOR 4
#endif

/* Set the Gyro Weight for Gyro/Acc complementary filter */
/* Increasing this value would reduce and delay Acc influence on the output of the filter*/
#ifndef GYR_CMPF_FACTOR
#define GYR_CMPF_FACTOR 400.0f
#endif

/* Set the Gyro Weight for Gyro/Magnetometer complementary filter */
/* Increasing this value would reduce and delay Magnetometer influence on the output of the filter*/
#ifndef GYR_CMPFM_FACTOR
#define GYR_CMPFM_FACTOR 200.0f
#endif

//****** end of advanced users settings *************

#define INV_GYR_CMPF_FACTOR (1.0f / (GYR_CMPF_FACTOR + 1.0f))
#define INV_GYR_CMPFM_FACTOR (1.0f / (GYR_CMPFM_FACTOR + 1.0f))
#if GYRO
#define GYRO_SCALE ((2380 * PI)/((32767.0f / 4.0f ) * 180.0f * 1000000.0f)) //should be 2279.44 but 2380 gives better result
// +-2000/sec deg scale
//#define GYRO_SCALE ((200.0f * PI)/((32768.0f / 5.0f / 4.0f ) * 180.0f * 1000000.0f) * 1.5f)
// +- 200/sec deg scale
// 1.5 is emperical, not sure what it means
// should be in rad/sec
#else
#define GYRO_SCALE (1.0f/200e6f)
// empirical, depends on WMP on IDG datasheet, tied of deg/ms sensibility
// !!!!should be adjusted to the rad/sec
#endif





Pagina 191


// Small angle approximation
#define ssin(val) (val)
#define scos(val) 1.0f

typedef struct fp_vector {
float X;
float Y;
float Z;
} t_fp_vector_def;

typedef union {
float A[3];
t_fp_vector_def V;
} t_fp_vector;

int16_t _atan2(float y, float x){
#define fp_is_neg(val) ((((uint8_t*)&val)[3] & 0x80) != 0)
float z = y / x;
int16_t zi = abs(int16_t(z * 100));
int8_t y_neg = fp_is_neg(y);
if ( zi < 100 ){
if (zi > 10)
z = z / (1.0f + 0.28f * z * z);
if (fp_is_neg(x)) {
if (y_neg) z -= PI;
else z += PI;
}
} else {
z = (PI / 2.0f) - z / (z * z + 0.28f);
if (y_neg) z -= PI;
}
z *= (180.0f / PI * 10);
return z;
}






Pagina 192


// Rotate Estimated vector(s) with small angle approximation, according to the gyro data
void rotateV(struct fp_vector *v,float* delta) {
fp_vector v_tmp = *v;
v->Z -= delta[ROLL] * v_tmp.X + delta[PITCH] * v_tmp.Y;
v->X += delta[ROLL] * v_tmp.Z - delta[YAW] * v_tmp.Y;
v->Y += delta[PITCH] * v_tmp.Z + delta[YAW] * v_tmp.X;
}

void getEstimatedAttitude(){
uint8_t axis;
int32_t accMag = 0;
static t_fp_vector EstG;
#if MAG
static t_fp_vector EstM;
#endif
#if defined(MG_LPF_FACTOR)
static int16_t mgSmooth[3];
#endif
#if defined(ACC_LPF_FACTOR)
static float accLPF[3];
#endif
static uint16_t previousT;
uint16_t currentT = micros();
float scale, deltaGyroAngle[3];

scale = (currentT - previousT) * GYRO_SCALE;
previousT = currentT;

// Initialization
for (axis = 0; axis < 3; axis++) {
deltaGyroAngle[axis] = gyroADC[axis] * scale;
#if defined(ACC_LPF_FACTOR)
accLPF[axis] = accLPF[axis] * (1.0f - (1.0f/ACC_LPF_FACTOR)) + accADC[axis] * (1.0f/ACC_LPF_FACTOR);
accSmooth[axis] = accLPF[axis];
#define ACC_VALUE accSmooth[axis]
#else
accSmooth[axis] = accADC[axis];
#define ACC_VALUE accADC[axis]
#endif





Pagina 193


// accMag += (ACC_VALUE * 10 / (int16_t)acc_1G) * (ACC_VALUE * 10 / (int16_t)acc_1G);
accMag += (int32_t)ACC_VALUE*ACC_VALUE ;
#if MAG
#if defined(MG_LPF_FACTOR)
mgSmooth[axis] = (mgSmooth[axis] * (MG_LPF_FACTOR - 1) + magADC[axis]) / MG_LPF_FACTOR; // LPF for Magnetometer values
#define MAG_VALUE mgSmooth[axis]
#else
#define MAG_VALUE magADC[axis]
#endif
#endif
}
accMag = accMag*100/((int32_t)acc_1G*acc_1G);

rotateV(&EstG.V,deltaGyroAngle);
#if MAG
rotateV(&EstM.V,deltaGyroAngle);
#endif

if ( abs(accSmooth[ROLL])<acc_25deg && abs(accSmooth[PITCH])<acc_25deg && accSmooth[YAW]>0) {
f.SMALL_ANGLES_25 = 1;
} else {
f.SMALL_ANGLES_25 = 0;
}






Pagina 194


// Apply complimentary filter (Gyro drift correction)
// If accel magnitude >1.4G or <0.6G and ACC vector outside of the limit range => we neutralize the effect of accelerometers in the angle estimation.
// To do that, we just skip filter, as EstV already rotated by Gyro
if ( ( 36 < accMag && accMag < 196 ) || f.SMALL_ANGLES_25 )
for (axis = 0; axis < 3; axis++) {
int16_t acc = ACC_VALUE;
EstG.A[axis] = (EstG.A[axis] * GYR_CMPF_FACTOR + acc) * INV_GYR_CMPF_FACTOR;
}
#if MAG
for (axis = 0; axis < 3; axis++)
EstM.A[axis] = (EstM.A[axis] * GYR_CMPFM_FACTOR + MAG_VALUE) * INV_GYR_CMPFM_FACTOR;
#endif

// Attitude of the estimated vector
angle[ROLL] = _atan2(EstG.V.X , EstG.V.Z) ;
angle[PITCH] = _atan2(EstG.V.Y , EstG.V.Z) ;

#if MAG
// Attitude of the cross product vector GxM
heading = _atan2( EstG.V.X * EstM.V.Z - EstG.V.Z * EstM.V.X , EstG.V.Z * EstM.V.Y - EstG.V.Y * EstM.V.Z );
heading += MAG_DECLINIATION * 10; //add declination
heading = heading /10;
if ( heading > 180) heading = heading - 360;
else if (heading < -180) heading = heading + 360;
#endif
}

#define UPDATE_INTERVAL 25000 // 40hz update rate (20hz LPF on acc)
#define INIT_DELAY 4000000 // 4 sec initialization delay
#define BARO_TAB_SIZE 40

void getEstimatedAltitude(){
uint8_t index;
static uint32_t deadLine = INIT_DELAY;

static int16_t BaroHistTab[BARO_TAB_SIZE];
static int8_t BaroHistIdx;
static int32_t BaroHigh,BaroLow;
int32_t temp32;
int16_t last;

if (abs(currentTime - deadLine) < UPDATE_INTERVAL) return;
deadLine = currentTime;






Pagina 195


//**** Alt. Set Point stabilization PID ****
//calculate speed for D calculation
last = BaroHistTab[BaroHistIdx];
BaroHistTab[BaroHistIdx] = BaroAlt/10;
BaroHigh += BaroHistTab[BaroHistIdx];
index = (BaroHistIdx + (BARO_TAB_SIZE/2))%BARO_TAB_SIZE;
BaroHigh -= BaroHistTab[index];
BaroLow += BaroHistTab[index];
BaroLow -= last;

BaroHistIdx++;
if (BaroHistIdx == BARO_TAB_SIZE) BaroHistIdx = 0;

BaroPID = 0;
//D
temp32 = conf.D8[PIDALT]*(BaroHigh - BaroLow) / 40;
BaroPID-=temp32;

EstAlt = BaroHigh*10/(BARO_TAB_SIZE/2);

temp32 = AltHold - EstAlt;
if (abs(temp32) < 10 && abs(BaroPID) < 10) BaroPID = 0; //remove small D parametr to reduce noise near zero position

//P
BaroPID += conf.P8[PIDALT]*constrain(temp32,(-2)*conf.P8[PIDALT],2*conf.P8[PIDALT])/100;
BaroPID = constrain(BaroPID,-150,+150); //sum of P and D should be in range 150

//I
errorAltitudeI += temp32*conf.I8[PIDALT]/50;
errorAltitudeI = constrain(errorAltitudeI,-30000,30000);
temp32 = errorAltitudeI / 500; //I in range +/-60
BaroPID+=temp32;
}





Pagina 196


Output
/**************************************************************************************/
/*************** Motor Pin order ********************/
/**************************************************************************************/
// since we are uing the PWM generation in a direct way, the pin order is just to inizialie the right pins
// its not possible to change a PWM output pin just by changing the order
uint8_t PWM_PIN[8] = {9,10,11,3,6,5,A2,12}; //for a quadX: RR,FR,RL,FL

/**************************************************************************************/
/************ Writes the Motors values to the PWM compare register ******************/
/**************************************************************************************/
void writeMotors() { // [1000;2000] => [125;250]
/******** Specific PWM Timers & Registers for the atmega328P (Promini) ************/
#if (NUMBER_MOTOR > 0)
#ifndef EXT_MOTOR_RANGE
OCR1A = motor[0]>>3; // pin 9
#else
OCR1A = ((motor[0]>>2) - 250) + 2;
#endif
#endif
#if (NUMBER_MOTOR > 1)
#ifndef EXT_MOTOR_RANGE
OCR1B = motor[1]>>3; // pin 10
#else
OCR1B = ((motor[1]>>2) - 250) + 2;
#endif
#endif
#if (NUMBER_MOTOR > 2)
#ifndef EXT_MOTOR_RANGE
OCR2A = motor[2]>>3; // pin 11
#else
OCR2A = ((motor[2]>>2) - 250) + 2;
#endif
#endif
#if (NUMBER_MOTOR > 3)
#ifndef EXT_MOTOR_RANGE
OCR2B = motor[3]>>3; // pin 3
#else
OCR2B = ((motor[3]>>2) - 250) + 2;
#endif
#endif
}






Pagina 197


/**************************************************************************************/
/************ Writes the mincommand to all Motors ******************/
/**************************************************************************************/
void writeAllMotors(int16_t mc) { // Sends commands to all motors
for (uint8_t i =0;i<NUMBER_MOTOR;i++) {
motor[i]=mc;
}
writeMotors();
}

/**************************************************************************************/
/************ Initialize the PWM Timers and Registers ******************/
/**************************************************************************************/
void initOutput() {

/**************** mark all PWM pins as Output ******************/
for(uint8_t i=0;i<NUMBER_MOTOR;i++) {
pinMode(PWM_PIN[i],OUTPUT);
}

/******** Specific PWM Timers & Registers for the atmega328P (Promini) ************/

#if (NUMBER_MOTOR > 0)
TCCR1A |= _BV(COM1A1); // connect pin 9 to timer 1 channel A
#endif
#if (NUMBER_MOTOR > 1)
TCCR1A |= _BV(COM1B1); // connect pin 10 to timer 1 channel B
#endif
#if (NUMBER_MOTOR > 2)
TCCR2A |= _BV(COM2A1); // connect pin 11 to timer 2 channel A
#endif
#if (NUMBER_MOTOR > 3)
TCCR2A |= _BV(COM2B1); // connect pin 3 to timer 2 channel B
#endif
#if (NUMBER_MOTOR > 5) // PIN 5 & 6 or A0 & A1
initializeSoftPWM();
#if defined(A0_A1_PIN_HEX) || (NUMBER_MOTOR > 6)
pinMode(5,INPUT);pinMode(6,INPUT); // we reactivate the INPUT affectation for these two PINs
pinMode(A0,OUTPUT);pinMode(A1,OUTPUT);
#endif
#endif








Pagina 198


/**************************************************************************************/
/********** Mixes the Computed stabilize values to the Motors & Servos ***************/
/**************************************************************************************/
void mixTable() {
int16_t maxMotor;
uint8_t i;

#define PIDMIX(X,Y,Z) rcCommand[THROTTLE] + axisPID[ROLL]*X + axisPID[PITCH]*Y + YAW_DIRECTION * axisPID[YAW]*Z

#if NUMBER_MOTOR > 3
//prevent "yaw jump" during yaw correction
axisPID[YAW] = constrain(axisPID[YAW],-100-abs(rcCommand[YAW]),+100+abs(rcCommand[YAW]));
#endif

//QUAD x-mode:
motor[0] = PIDMIX(-1,+1,-1); //REAR_R
motor[1] = PIDMIX(-1,-1,+1); //FRONT_R
motor[2] = PIDMIX(+1,+1,+1); //REAR_L
motor[3] = PIDMIX(+1,-1,-1); //FRONT_L


/**************** Filter the Motors values ******************/
maxMotor=motor[0];
for(i=1;i< NUMBER_MOTOR;i++)
if (motor[i]>maxMotor) maxMotor=motor[i];
for (i = 0; i < NUMBER_MOTOR; i++) {
if (maxMotor > MAXTHROTTLE) // this is a way to still have good gyro corrections if at least one motor reaches its max.
motor[i] -= maxMotor - MAXTHROTTLE;
motor[i] = constrain(motor[i], MINTHROTTLE, MAXTHROTTLE);
if ((rcData[THROTTLE]) < MINCHECK)
#ifndef MOTOR_STOP
motor[i] = MINTHROTTLE;
#else
motor[i] = MINCOMMAND;
#endif
if (!f.ARMED)
motor[i] = MINCOMMAND;
}
}





Pagina 199


Receiver
/**************************************************************************************/
/*************** Global RX related variables ********************/
/**************************************************************************************/

//RAW RC values will be store here
#if defined(SBUS)
volatile uint16_t rcValue[18] = {1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502};
// interval [1000;2000]
#else
volatile uint16_t rcValue[8] = {1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502}; // interval [1000;2000]
#endif

#if defined(SERIAL_SUM_PPM) //Channel order for PPM SUM RX Configs
static uint8_t rcChannel[8] = {SERIAL_SUM_PPM};
#elif defined(SBUS) //Channel order for SBUS RX Configs
// for 16 + 2 Channels SBUS. The 10 extra channels 8->17 are not used by MultiWii, but it should be easy to integrate them.
static uint8_t rcChannel[18] = {PITCH,YAW,THROTTLE,ROLL,AUX1,AUX2,AUX3,AUX4,8,9,10,11,12,13,14,15,16,17};
static uint16_t sbusIndex=0;
#else // Standard Channel order
static uint8_t rcChannel[8] = {ROLLPIN, PITCHPIN, YAWPIN, THROTTLEPIN, AUX1PIN,AUX2PIN,AUX3PIN,AUX4PIN};
static uint8_t PCInt_RX_Pins[PCINT_PIN_COUNT] = {PCINT_RX_BITS}; // if this slowes the PCINT readings we can switch to a define for each pcint bit
#endif
#if defined(SPEKTRUM) // Spektrum Satellite Frame size
//Note: Defines are moved to def.h
volatile uint8_t spekFrame[SPEK_FRAME_SIZE];
#endif







Pagina 200


/**************************************************************************************/
/*************** RX Pin Setup ********************/
/**************************************************************************************/
void configureReceiver() {
/****************** Configure each rc pin for PCINT ***************************/
#if defined(STANDARD_RX)
// PCINT activation
for(uint8_t i = 0; i < PCINT_PIN_COUNT; i++){ // i think a for loop is ok for the init.
PCINT_RX_PORT |= PCInt_RX_Pins[i];
PCINT_RX_MASK |= PCInt_RX_Pins[i];
}
PCICR = PCIR_PORT_BIT;

/************************* Specific Aux2 Pin Setup *************************/
#if defined(RCAUXPIN)
PCICR |= (1 << 0) ; // PCINT activated also for PINS [D8-D13] on port B
#if defined(RCAUXPIN8)
PCMSK0 = (1 << 0);
#endif
#if defined(RCAUXPIN12)
PCMSK0 = (1 << 4);
#endif
#endif

/************************* Special RX Setup ********************************/
#endif
// Init PPM SUM RX
#if defined(SERIAL_SUM_PPM)
PPM_PIN_INTERRUPT;
#endif
// Init Sektrum Satellite RX
#if defined (SPEKTRUM)
SerialOpen(1,115200);
#endif
// Init SBUS RX
#if defined(SBUS)
SerialOpen(1,100000);
#endif
}






Pagina 201


/**************************************************************************************/
/*************** Standard RX Pins reading ********************/
/**************************************************************************************/
#if defined(STANDARD_RX)
// predefined PC pin block (thanks to lianj)
#define RX_PIN_CHECK(pin_pos, rc_value_pos) \
if (mask & PCInt_RX_Pins[pin_pos]) { \
if (!(pin & PCInt_RX_Pins[pin_pos])) { \
dTime = cTime-edgeTime[pin_pos]; if (900<dTime && dTime<2200) rcValue[rc_value_pos] = dTime; \
} else edgeTime[pin_pos] = cTime; \
}
// port change Interrupt
ISR(RX_PC_INTERRUPT) { //this ISR is common to every receiver channel, it is call everytime a change state occurs on a RX input pin
uint8_t mask;
uint8_t pin;
uint16_t cTime,dTime;
static uint16_t edgeTime[8];
static uint8_t PCintLast;

pin = RX_PCINT_PIN_PORT; // RX_PCINT_PIN_PORT indicates the state of each PIN for the arduino port dealing with Ports digital pins

mask = pin ^ PCintLast; // doing a ^ between the current interruption and the last one indicates wich pin changed
sei(); // re enable other interrupts at this point, the rest of this interrupt is not so time critical and can be interrupted
safely
PCintLast = pin; // we memorize the current state of all PINs [D0-D7]

cTime = micros(); // micros() return a uint32_t, but it is not usefull to keep the whole bits => we keep only 16 bits

#if (PCINT_PIN_COUNT > 0)
RX_PIN_CHECK(0,2);
#endif
#if (PCINT_PIN_COUNT > 1)
RX_PIN_CHECK(1,4);
#endif
#if (PCINT_PIN_COUNT > 2)
RX_PIN_CHECK(2,5);
#endif
#if (PCINT_PIN_COUNT > 3)
RX_PIN_CHECK(3,6);
#endif
#if (PCINT_PIN_COUNT > 4)
RX_PIN_CHECK(4,7);
#endif
#if (PCINT_PIN_COUNT > 5)
RX_PIN_CHECK(5,0);
#endif
#if (PCINT_PIN_COUNT > 6)
RX_PIN_CHECK(6,1);
#endif
#if (PCINT_PIN_COUNT > 7)




Pagina 202


RX_PIN_CHECK(7,3);
#endif

#if defined(FAILSAFE) && !defined(PROMICRO)
if (mask & 1<<THROTTLEPIN) { // If pulse present on THROTTLE pin (independent from ardu version), clear FailSafe counter - added by MIS
if(failsafeCnt > 20) failsafeCnt -= 20; else failsafeCnt = 0; }
#endif
}


/********************* atmega328P's Aux2 Pins *************************/
#if defined(PROMINI)
#if defined(RCAUXPIN)
/* this ISR is a simplification of the previous one for PROMINI on port D
it's simplier because we know the interruption deals only with one PIN:
bit 0 of PORT B, ie Arduino PIN 8
or bit 4 of PORTB, ie Arduino PIN 12
=> no need to check which PIN has changed */
ISR(PCINT0_vect) {
uint8_t pin;
uint16_t cTime,dTime;
static uint16_t edgeTime;

pin = PINB;
sei();
cTime = micros();
#if defined(RCAUXPIN8)
if (!(pin & 1<<0)) { //indicates if the bit 0 of the arduino port [B0-B7] is not at a high state (so that we match here only descending PPM
pulse)
#endif
#if defined(RCAUXPIN12)
if (!(pin & 1<<4)) { //indicates if the bit 4 of the arduino port [B0-B7] is not at a high state (so that we match here only descending PPM
pulse)
#endif
dTime = cTime-edgeTime; if (900<dTime && dTime<2200) rcValue[0] = dTime; // just a verification: the value must be in the range [1000;2000] +
some
margin
} else edgeTime = cTime; // if the bit 2 is at a high state (ascending PPM pulse), we memorize the time
}
#endif
#endif
#endif







Pagina 203


/**************************************************************************************/
/*************** combine and sort the RX Datas ********************/
/**************************************************************************************/
uint16_t readRawRC(uint8_t chan) {
uint16_t data;
uint8_t oldSREG;
oldSREG = SREG; cli(); // Let's disable interrupts
data = rcValue[rcChannel[chan]]; // Let's copy the data Atomically
#if defined(SPEKTRUM)
static uint32_t spekChannelData[SPEK_MAX_CHANNEL];
if (rcFrameComplete) {
for (uint8_t b = 3; b < SPEK_FRAME_SIZE; b += 2) {
uint8_t spekChannel = 0x0F & (spekFrame[b - 1] >> SPEK_CHAN_SHIFT);
if (spekChannel < SPEK_MAX_CHANNEL) spekChannelData[spekChannel] = ((uint32_t)(spekFrame[b - 1] & SPEK_CHAN_MASK) << 8) + spekFrame[b];
}
rcFrameComplete = 0;
}
#endif
SREG = oldSREG; sei();// Let's enable the interrupts
#if defined(SPEKTRUM)
static uint8_t spekRcChannelMap[SPEK_MAX_CHANNEL] = {1,2,3,0,4,5,6};
if (chan >= SPEK_MAX_CHANNEL) {
data = 1500;
} else {
#if (SPEKTRUM == 1024)
data = 988 + spekChannelData[spekRcChannelMap[chan]]; // 1024 mode
#endif
#if (SPEKTRUM == 2048)
data = 988 + (spekChannelData[spekRcChannelMap[chan]] >> 1); // 2048 mode
#endif
}
#endif
return data; // We return the value correctly copied when the IRQ's where disabled
}






Pagina 204


/**************************************************************************************/
/*************** compute and Filter the RX data ********************/
/**************************************************************************************/
void computeRC() {
static int16_t rcData4Values[8][4], rcDataMean[8];
static uint8_t rc4ValuesIndex = 0;
uint8_t chan,a;
#if !(defined(RCSERIAL) || defined(OPENLRSv2MULTI)) // dont know if this is right here
#if defined(SBUS)
readSBus();
#endif
rc4ValuesIndex++;
for (chan = 0; chan < 8; chan++) {
rcData4Values[chan][rc4ValuesIndex%4] = readRawRC(chan);
rcDataMean[chan] = 0;
for (a=0;a<4;a++) rcDataMean[chan] += rcData4Values[chan][a];
rcDataMean[chan]= (rcDataMean[chan]+2)/4;
if ( rcDataMean[chan] < rcData[chan] -3) rcData[chan] = rcDataMean[chan]+2;
if ( rcDataMean[chan] > rcData[chan] +3) rcData[chan] = rcDataMean[chan]-2;
}
#endif
}







Pagina 205


/**************************************************************************************/
/*************** OPENLRS ********************/
/**************************************************************************************/

//note: this dont feels right in RX.pde

#if defined(OPENLRSv2MULTI)
//######### TRANSMISSION VARIABLES ##########
#define CARRIER_FREQUENCY 435000 // 435Mhz startup frequency
#define FREQUENCY_HOPPING 1 // 1 = Enabled 0 = Disabled

//###### HOPPING CHANNELS #######
//Select the hopping channels between 0-255
// Default values are 13,54 and 23 for all transmitters and receivers, you should change it before your first flight for safety.
//Frequency = CARRIER_FREQUENCY + (StepSize(60khz)* Channel_Number)
static uint8_t hop_list[3] = {13,54,23};

//###### RF DEVICE ID HEADERS #######
// Change this 4 byte values for isolating your transmission, RF module accepts only data with same header
static uint8_t RF_Header[4] = {'O','L','R','S'};

//########## Variables #################

static uint32_t last_hopping_time;
static uint8_t RF_Rx_Buffer[17];
static uint16_t temp_int;
static uint16_t Servo_Buffer[10] = {3000,3000,3000,3000,3000,3000,3000,3000}; //servo position values from RF
static uint8_t hopping_channel = 1;

void initOpenLRS(void) {
pinMode(GREEN_LED_pin, OUTPUT);
pinMode(RED_LED_pin, OUTPUT);

//RF module pins
pinMode(SDO_pin, INPUT); //SDO
pinMode(SDI_pin, OUTPUT); //SDI
pinMode(SCLK_pin, OUTPUT); //SCLK
pinMode(IRQ_pin, INPUT); //IRQ
pinMode(nSel_pin, OUTPUT); //nSEL
checkPots(); // OpenLRS Multi board hardware pot check;
}






Pagina 206


void Config_OpenLRS() {
RF22B_init_parameter(); // Configure the RFM22B's registers
frequency_configurator(CARRIER_FREQUENCY); // Calibrate the RFM22B to this frequency, frequency hopping starts from here.
to_rx_mode();
#if (FREQUENCY_HOPPING==1)
Hopping(); //Hop to the next frequency
#endif
}

//############ MAIN LOOP ##############
void Read_OpenLRS_RC() {
uint8_t i,tx_data_length;
uint8_t first_data = 0;

if (_spi_read(0x0C)==0) {RF22B_init_parameter(); to_rx_mode(); }// detect the locked module and reboot
if ((currentTime-last_hopping_time > 25000)) {//automatic hopping for clear channel when rf link down for 25ms.
Red_LED_ON;
last_hopping_time = currentTime;
#if (FREQUENCY_HOPPING==1)
Hopping(); //Hop to the next frequency
#endif
}
if(nIRQ_0) { // RFM22B INT pin Enabled by received Data
Red_LED_ON;
send_read_address(0x7f); // Send the package read command
for(i = 0; i<17; i++) {//read all buffer
RF_Rx_Buffer[i] = read_8bit_data();
}
rx_reset();
if (RF_Rx_Buffer[0] == 'S') {// servo control data
for(i = 0; i<8; i++) {//Write into the Servo Buffer
temp_int = (256*RF_Rx_Buffer[1+(2*i)]) + RF_Rx_Buffer[2+(2*i)];
if ((temp_int>1500) && (temp_int<4500)) Servo_Buffer[i] = temp_int/2;
}
rcData[ROLL] = Servo_Buffer[0];
rcData[PITCH] = Servo_Buffer[1];
rcData[THROTTLE] = Servo_Buffer[2];
rcData[YAW] = Servo_Buffer[3];
rcData[AUX1] = Servo_Buffer[4];
rcData[AUX2] = Servo_Buffer[5];
rcData[AUX3] = Servo_Buffer[6];
rcData[AUX4] = Servo_Buffer[7];
}





Pagina 207


#if (FREQUENCY_HOPPING==1)
Hopping(); //Hop to the next frequency
#endif
delay(1);
last_hopping_time = currentTime;
Red_LED_OFF;
}
Red_LED_OFF;
}


//*****************************************************************************
//*****************************************************************************

//--------------------------------------------------------------
void Write0( void ) {
SCK_off;
NOP();
SDI_off;
NOP();
SCK_on;
NOP();
}
//--------------------------------------------------------------
void Write1( void ) {
SCK_off;
NOP();
SDI_on;
NOP();
SCK_on;
NOP();
}
//--------------------------------------------------------------
void Write8bitcommand(uint8_t command) { // keep sel to low
uint8_t n=8;
nSEL_on;
SCK_off;
nSEL_off;
while(n--) {
if(command&0x80)
Write1();
else
Write0();
command = command << 1;
}
SCK_off;
}

//--------------------------------------------------------------




Pagina 208


uint8_t _spi_read(uint8_t address) {
uint8_t result;
send_read_address(address);
result = read_8bit_data();
nSEL_on;
return(result);
}

//--------------------------------------------------------------
void _spi_write(uint8_t address, uint8_t data) {
address |= 0x80;
Write8bitcommand(address);
send_8bit_data(data);
nSEL_on;
}


//-------Defaults 38.400 baud----------------------------------------------
void RF22B_init_parameter(void) {
ItStatus1 = _spi_read(0x03); // read status, clear interrupt
ItStatus2 = _spi_read(0x04);
_spi_write(0x06, 0x00); // no wakeup up, lbd,
_spi_write(0x07, RF22B_PWRSTATE_READY); // disable lbd, wakeup timer, use internal 32768,xton = 1; in ready mode
_spi_write(0x09, 0x7f); // c = 12.5p
_spi_write(0x0a, 0x05);
_spi_write(0x0b, 0x12); // gpio0 TX State
_spi_write(0x0c, 0x15); // gpio1 RX State
_spi_write(0x0d, 0xfd); // gpio 2 micro-controller clk output
_spi_write(0x0e, 0x00); // gpio 0, 1,2 NO OTHER FUNCTION.
_spi_write(0x70, 0x00); // disable manchest






Pagina 209


// 57.6Kbps data rate
_spi_write(0x1c, 0x05); // case RATE_57.6K
_spi_write(0x20, 0x45);// 0x20 calculate from the datasheet= 500*(1+2*down3_bypass)/(2^ndec*RB*(1+enmanch))
_spi_write(0x21, 0x01); // 0x21 , rxosr[10--8] = 0; stalltr = (default), ccoff[19:16] = 0;
_spi_write(0x22, 0xD7); // 0x22 ncoff =5033 = 0x13a9
_spi_write(0x23, 0xDC); // 0x23
_spi_write(0x24, 0x03); // 0x24
_spi_write(0x25, 0xB8); // 0x25
_spi_write(0x2a, 0x1e);

_spi_write(0x6e, 0x0E); //case RATE_57.6K
_spi_write(0x6f, 0xBF); //case RATE_57.6K

_spi_write(0x30, 0x8c); // enable packet handler, msb first, enable crc,

_spi_write(0x32, 0xf3); // 0x32address enable for headere byte 0, 1,2,3, receive header check for byte 0, 1,2,3
_spi_write(0x33, 0x42); // header 3, 2, 1,0 used for head length, fixed packet length, synchronize word length 3, 2,
_spi_write(0x34, 0x07); // 7 default value or // 64 nibble = 32byte preamble
_spi_write(0x36, 0x2d); // synchronize word
_spi_write(0x37, 0xd4);
_spi_write(0x38, 0x00);
_spi_write(0x39, 0x00);
_spi_write(0x3a, RF_Header[0]); // tx header
_spi_write(0x3b, RF_Header[1]);
_spi_write(0x3c, RF_Header[2]);
_spi_write(0x3d, RF_Header[3]);
_spi_write(0x3e, 17); // total tx 17 byte

//RX HEADER
_spi_write(0x3f, RF_Header[0]); // check hearder
_spi_write(0x40, RF_Header[1]);
_spi_write(0x41, RF_Header[2]);
_spi_write(0x42, RF_Header[3]);
_spi_write(0x43, 0xff); // all the bit to be checked
_spi_write(0x44, 0xff); // all the bit to be checked
_spi_write(0x45, 0xff); // all the bit to be checked
_spi_write(0x46, 0xff); // all the bit to be checked

_spi_write(0x6d, 0x07); // 7 set power max power
_spi_write(0x79, 0x00); // no hopping
_spi_write(0x7a, 0x06); // 60khz step size (10khz x value) // no hopping

_spi_write(0x71, 0x23); // Gfsk, fd[8] =0, no invert for Tx/Rx data, fifo mode, txclk -->gpio
//_spi_write(0x72, 0x1F); // frequency deviation setting to 19.6khz (for 38.4kbps)
_spi_write(0x72, 0x2E); // frequency deviation setting to 28.8khz(for 57.6kbps)
_spi_write(0x73, 0x00);
_spi_write(0x74, 0x00); // no offset






Pagina 210


//band 435.000
_spi_write(0x75, 0x53);
_spi_write(0x76, 0x7D);
_spi_write(0x77, 0x00);
}

//--------------------------------------------------------------
void send_read_address(uint8_t i) {
i &= 0x7f;
Write8bitcommand(i);
}
//--------------------------------------------------------------
void send_8bit_data(uint8_t i) {
uint8_t n = 8;
SCK_off;
while(n--) {
if(i&0x80)
Write1();
else
Write0();
i = i << 1;
}
SCK_off;
}
//--------------------------------------------------------------

uint8_t read_8bit_data(void) {
uint8_t Result, i;

SCK_off;
Result=0;
for(i=0;i<8;i++) { //read fifo data byte
Result=Result<<1;
SCK_on;
NOP();
if(SDO_1) {
Result|=1;
}
SCK_off;
NOP();
}
return(Result);
}
//--------------------------------------------------------------






Pagina 211


//-----------------------------------------------------------------------
void rx_reset(void) {
_spi_write(0x07, RF22B_PWRSTATE_READY);
_spi_write(0x7e, 36); // threshold for rx almost full, interrupt when 1 byte received
_spi_write(0x08, 0x03); //clear fifo disable multi packet
_spi_write(0x08, 0x00); // clear fifo, disable multi packet
_spi_write(0x07,RF22B_PWRSTATE_RX ); // to rx mode
_spi_write(0x05, RF22B_Rx_packet_received_interrupt);
ItStatus1 = _spi_read(0x03); //read the Interrupt Status1 register
ItStatus2 = _spi_read(0x04);
}
//-----------------------------------------------------------------------

void to_rx_mode(void) {
to_ready_mode();
delay(50);
rx_reset();
NOP();
}


//--------------------------------------------------------------
void to_ready_mode(void) {
ItStatus1 = _spi_read(0x03);
ItStatus2 = _spi_read(0x04);
_spi_write(0x07, RF22B_PWRSTATE_READY);
}
//--------------------------------------------------------------
void to_sleep_mode(void) {
// TXEN = RXEN = 0;
//LED_RED = 0;
_spi_write(0x07, RF22B_PWRSTATE_READY);

ItStatus1 = _spi_read(0x03); //read the Interrupt Status1 register
ItStatus2 = _spi_read(0x04);
_spi_write(0x07, RF22B_PWRSTATE_POWERDOWN);
}





Pagina 212


//--------------------------------------------------------------

void frequency_configurator(uint32_t frequency) {
// frequency formulation from Si4432 chip's datasheet
// original formulation is working with mHz values and floating numbers, I replaced them with kHz values.
frequency = frequency / 10;
frequency = frequency - 24000;
frequency = frequency - 19000; // 19 for 430-439.9 MHz band from datasheet
frequency = frequency * 64; // this is the Nominal Carrier Frequency (fc) value for register setting

uint8_t byte0 = (uint8_t) frequency;
uint8_t byte1 = (uint8_t) (frequency >> 8);

_spi_write(0x76, byte1);
_spi_write(0x77, byte0);
}

//############# FREQUENCY HOPPING FUNCTIONS #################
#if (FREQUENCY_HOPPING==1)
void Hopping(void) {
hopping_channel++;
if (hopping_channel>2) hopping_channel = 0;
_spi_write(0x79, hop_list[hopping_channel]);
}
#endif

void checkPots() {
////Flytron OpenLRS Multi Pots
pot_P = analogRead(7);
pot_I = analogRead(6);

pot_P = pot_P - 512;
pot_I = pot_I - 512;

pot_P = pot_P / 25; //+-20
pot_I = pot_I / 25; //+-20
}
#endif





Pagina 213


Sensors
// ************************************************************************************************************
// board orientation and setup
// ************************************************************************************************************
//default board orientation
#if !defined(ACC_ORIENTATION)
#define ACC_ORIENTATION(X, Y, Z) {accADC[ROLL] = X; accADC[PITCH] = Y; accADC[YAW] = Z;}
#endif
#if !defined(GYRO_ORIENTATION)
#define GYRO_ORIENTATION(X, Y, Z) {gyroADC[ROLL] = X; gyroADC[PITCH] = Y; gyroADC[YAW] = Z;}
#endif
#if !defined(MAG_ORIENTATION)
#define MAG_ORIENTATION(X, Y, Z) {magADC[ROLL] = X; magADC[PITCH] = Y; magADC[YAW] = Z;}
#endif

/*** I2C address ***/
#if !defined(MMA7455_ADDRESS)
#define MMA7455_ADDRESS 0x1D
#endif

#if !defined(ADXL345_ADDRESS)
#define ADXL345_ADDRESS 0x1D
//#define ADXL345_ADDRESS 0x53 //WARNING: Conflicts with a Wii Motion plus!
#endif

#if !defined(BMA180_ADDRESS)
#define BMA180_ADDRESS 0x40
//#define BMA180_ADDRESS 0x41
#endif

#if !defined(ITG3200_ADDRESS)
#define ITG3200_ADDRESS 0X68
//#define ITG3200_ADDRESS 0X69
#endif

#if !defined(MPU6050_ADDRESS)
#define MPU6050_ADDRESS 0x68 // address pin AD0 low (GND), default for FreeIMU v0.4 and InvenSense evaluation board
//#define MPU6050_ADDRESS 0x69 // address pin AD0 high (VCC)
#endif

#if !defined(MS561101BA_ADDRESS)
#define MS561101BA_ADDRESS 0x77 //CBR=0 0xEE I2C address when pin CSB is connected to LOW (GND)
//#define MS561101BA_ADDRESS 0x76 //CBR=1 0xEC I2C address when pin CSB is connected to HIGH (VCC)
#endif






Pagina 214


//ITG3200 setting
#if defined(ITG3200_LPF_256HZ) || defined(ITG3200_LPF_188HZ) || defined(ITG3200_LPF_98HZ) || defined(ITG3200_LPF_42HZ) || defined(ITG3200_LPF_20HZ) ||
defined(ITG3200_LPF_10HZ)
#if defined(ITG3200_LPF_256HZ)
#define ITG3200_SMPLRT_DIV 0 //8000Hz
#define ITG3200_DLPF_CFG 0
#endif
#if defined(ITG3200_LPF_188HZ)
#define ITG3200_SMPLRT_DIV 0 //1000Hz
#define ITG3200_DLPF_CFG 1
#endif
#if defined(ITG3200_LPF_98HZ)
#define ITG3200_SMPLRT_DIV 0
#define ITG3200_DLPF_CFG 2
#endif
#if defined(ITG3200_LPF_42HZ)
#define ITG3200_SMPLRT_DIV 0
#define ITG3200_DLPF_CFG 3
#endif
#if defined(ITG3200_LPF_20HZ)
#define ITG3200_SMPLRT_DIV 0
#define ITG3200_DLPF_CFG 4
#endif
#if defined(ITG3200_LPF_10HZ)
#define ITG3200_SMPLRT_DIV 0
#define ITG3200_DLPF_CFG 5
#endif
#else
//Default settings LPF 256Hz/8000Hz sample
#define ITG3200_SMPLRT_DIV 0 //8000Hz
#define ITG3200_DLPF_CFG 0
#endif

uint8_t rawADC[6];
static uint32_t neutralizeTime = 0;






Pagina 215


// ************************************************************************************************************
// I2C general functions
// ************************************************************************************************************

void i2c_init(void) {
#if defined(INTERNAL_I2C_PULLUPS)
I2C_PULLUPS_ENABLE
#else
I2C_PULLUPS_DISABLE
#endif
TWSR = 0; // no prescaler => prescaler = 1
TWBR = ((F_CPU / I2C_SPEED) - 16) / 2; // change the I2C clock rate
TWCR = 1<<TWEN; // enable twi module, no interrupt
}

void i2c_rep_start(uint8_t address) {
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN) ; // send REPEAT START condition
waitTransmissionI2C(); // wait until transmission completed
TWDR = address; // send device address
TWCR = (1<<TWINT) | (1<<TWEN);
waitTransmissionI2C(); // wail until transmission completed
}

void i2c_stop(void) {
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
// while(TWCR & (1<<TWSTO)); // <- can produce a blocking state with some WMP clones
}

void i2c_write(uint8_t data ) {
TWDR = data; // send data to the previously addressed device
TWCR = (1<<TWINT) | (1<<TWEN);
waitTransmissionI2C();
}

uint8_t i2c_read(uint8_t ack) {
TWCR = (1<<TWINT) | (1<<TWEN) | (ack? (1<<TWEA) : 0);
waitTransmissionI2C();
uint8_t r = TWDR;
if (!ack) i2c_stop();
return r;
}

uint8_t i2c_readAck() {
return i2c_read(1);
}

uint8_t i2c_readNak(void) {
return i2c_read(0);
}




Pagina 216


void waitTransmissionI2C() {
uint16_t count = 255;
while (!(TWCR & (1<<TWINT))) {
count--;
if (count==0) { //we are in a blocking state => we don't insist
TWCR = 0; //and we force a reset on TWINT register
neutralizeTime = micros(); //we take a timestamp here to neutralize the value during a short delay
i2c_errors_count++;
break;
}
}
}

size_t i2c_read_to_buf(uint8_t add, void *buf, size_t size) {
i2c_rep_start((add<<1) | 1); // I2C read direction
size_t bytes_read = 0;
uint8_t *b = (uint8_t*)buf;
while (size--) {
/* acknowledge all but the final byte */
*b++ = i2c_read(size > 0);
/* TODO catch I2C errors here and abort */
bytes_read++;
}
return bytes_read;
}

size_t i2c_read_reg_to_buf(uint8_t add, uint8_t reg, void *buf, size_t size) {
i2c_rep_start(add<<1); // I2C write direction
i2c_write(reg); // register selection
return i2c_read_to_buf(add, buf, size);
}

/* transform a series of bytes from big endian to little
endian and vice versa. */
void swap_endianness(void *buf, size_t size) {
/* we swap in-place, so we only have to
* place _one_ element on a temporary tray
*/
uint8_t tray;
uint8_t *from;
uint8_t *to;
/* keep swapping until the pointers have assed each other */
for (from = (uint8_t*)buf, to = &from[size-1]; from < to; from++, to--) {
tray = *from;
*from = *to;
*to = tray;
}
}

void i2c_getSixRawADC(uint8_t add, uint8_t reg) {




Pagina 217


i2c_read_reg_to_buf(add, reg, &rawADC, 6);
}

void i2c_writeReg(uint8_t add, uint8_t reg, uint8_t val) {
i2c_rep_start(add<<1); // I2C write direction
i2c_write(reg); // register selection
i2c_write(val); // value to write in register
i2c_stop();
}

uint8_t i2c_readReg(uint8_t add, uint8_t reg) {
uint8_t val;
i2c_read_reg_to_buf(add, reg, &val, 1);
return val;
}

// ****************
// GYRO common part
// ****************
void GYRO_Common() {
static int16_t previousGyroADC[3] = {0,0,0};
static int32_t g[3];
uint8_t axis;

#if defined MMGYRO
// Moving Average Gyros by Magnetron1
//---------------------------------------------------
static int16_t mediaMobileGyroADC[3][MMGYROVECTORLENGHT];
static int32_t mediaMobileGyroADCSum[3];
static uint8_t mediaMobileGyroIDX;
//---------------------------------------------------
#endif
if (calibratingG>0) {
for (axis = 0; axis < 3; axis++) {
// Reset g[axis] at start of calibration
if (calibratingG == 400) g[axis]=0;
// Sum up 400 readings
g[axis] +=gyroADC[axis];
// Clear global variables for next reading
gyroADC[axis]=0;
gyroZero[axis]=0;
if (calibratingG == 1) {
gyroZero[axis]=g[axis]/400;
blinkLED(10,15,1);
}
}
calibratingG--;
}




Pagina 218


#ifdef MMGYRO
mediaMobileGyroIDX = ++mediaMobileGyroIDX % MMGYROVECTORLENGHT;
for (axis = 0; axis < 3; axis++) {
gyroADC[axis] -= gyroZero[axis];
mediaMobileGyroADCSum[axis] -= mediaMobileGyroADC[axis][mediaMobileGyroIDX];
//anti gyro glitch, limit the variation between two consecutive readings
mediaMobileGyroADC[axis][mediaMobileGyroIDX] = constrain(gyroADC[axis],previousGyroADC[axis]-800,previousGyroADC[axis]+800);
mediaMobileGyroADCSum[axis] += mediaMobileGyroADC[axis][mediaMobileGyroIDX];
gyroADC[axis] = mediaMobileGyroADCSum[axis] / MMGYROVECTORLENGHT;
#else
for (axis = 0; axis < 3; axis++) {
gyroADC[axis] -= gyroZero[axis];
//anti gyro glitch, limit the variation between two consecutive readings
gyroADC[axis] = constrain(gyroADC[axis],previousGyroADC[axis]-800,previousGyroADC[axis]+800);
#endif
previousGyroADC[axis] = gyroADC[axis];
}
}

// ****************
// ACC common part
// ****************
void ACC_Common() {
static int32_t a[3];

if (calibratingA>0) {
for (uint8_t axis = 0; axis < 3; axis++) {
// Reset a[axis] at start of calibration
if (calibratingA == 400) a[axis]=0;
// Sum up 400 readings
a[axis] +=accADC[axis];
// Clear global variables for next reading
accADC[axis]=0;
conf.accZero[axis]=0;
}
// Calculate average, shift Z down by acc_1G and store values in EEPROM at end of calibration
if (calibratingA == 1) {
conf.accZero[ROLL] = a[ROLL]/400;
conf.accZero[PITCH] = a[PITCH]/400;
conf.accZero[YAW] = a[YAW]/400-acc_1G; // for nunchuk 200=1G
conf.angleTrim[ROLL] = 0;
conf.angleTrim[PITCH] = 0;
writeParams(1); // write accZero in EEPROM
}
calibratingA--;
}
#if defined(INFLIGHT_ACC_CALIBRATION)
static int32_t b[3];
static int16_t accZero_saved[3] = {0,0,0};
static int16_t angleTrim_saved[2] = {0, 0};




Pagina 219


//Saving old zeropoints before measurement
if (InflightcalibratingA==50) {
accZero_saved[ROLL] = conf.accZero[ROLL] ;
accZero_saved[PITCH] = conf.accZero[PITCH];
accZero_saved[YAW] = conf.accZero[YAW] ;
angleTrim_saved[ROLL] = conf.angleTrim[ROLL] ;
angleTrim_saved[PITCH] = conf.angleTrim[PITCH] ;
}
if (InflightcalibratingA>0) {
for (uint8_t axis = 0; axis < 3; axis++) {
// Reset a[axis] at start of calibration
if (InflightcalibratingA == 50) b[axis]=0;
// Sum up 50 readings
b[axis] +=accADC[axis];
// Clear global variables for next reading
accADC[axis]=0;
conf.accZero[axis]=0;
}
//all values are measured
if (InflightcalibratingA == 1) {
AccInflightCalibrationActive = 0;
AccInflightCalibrationMeasurementDone = 1;
#if defined(BUZZER)
toggleBeep = 2; //buzzer for indicatiing the end of calibration
#endif
// recover saved values to maintain current flight behavior until new values are transferred
conf.accZero[ROLL] = accZero_saved[ROLL] ;
conf.accZero[PITCH] = accZero_saved[PITCH];
conf.accZero[YAW] = accZero_saved[YAW] ;
conf.angleTrim[ROLL] = angleTrim_saved[ROLL] ;
conf.angleTrim[PITCH] = angleTrim_saved[PITCH] ;
}
InflightcalibratingA--;
}
// Calculate average, shift Z down by acc_1G and store values in EEPROM at end of calibration
if (AccInflightCalibrationSavetoEEProm == 1){ //the copter is landed, disarmed and the combo has been done again
AccInflightCalibrationSavetoEEProm = 0;
conf.accZero[ROLL] = b[ROLL]/50;
conf.accZero[PITCH] = b[PITCH]/50;
conf.accZero[YAW] = b[YAW]/50-acc_1G; // for nunchuk 200=1G
conf.angleTrim[ROLL] = 0;
conf.angleTrim[PITCH] = 0;
writeParams(1); // write accZero in EEPROM
}
#endif
accADC[ROLL] -= conf.accZero[ROLL] ;
accADC[PITCH] -= conf.accZero[PITCH];
accADC[YAW] -= conf.accZero[YAW] ; }




Pagina 220


// ************************************************************************************************************
// I2C Barometer BOSCH BMP085
// ************************************************************************************************************
// I2C adress: 0x77 (7bit)
// principle:
// 1) read the calibration register (only once at the initialization)
// 2) read uncompensated temperature (not mandatory at every cycle)
// 3) read uncompensated pressure
// 4) raw temp + raw pressure => calculation of the adjusted pressure
// the following code uses the maximum precision setting (oversampling setting 3)
// ************************************************************************************************************

#if defined(BMP085)
#define BMP085_ADDRESS 0x77
static int32_t pressure;

static struct {
// sensor registers from the BOSCH BMP085 datasheet
int16_t ac1, ac2, ac3;
uint16_t ac4, ac5, ac6;
int16_t b1, b2, mb, mc, md;
union {uint16_t val; uint8_t raw[2]; } ut; //uncompensated T
union {uint32_t val; uint8_t raw[4]; } up; //uncompensated P
uint8_t state;
uint32_t deadline;
} bmp085_ctx;
#define OSS 2 //we can get more unique samples and get better precision using average

void i2c_BMP085_readCalibration(){
delay(10);
//read calibration data in one go
size_t s_bytes = (uint8_t*)&bmp085_ctx.md - (uint8_t*)&bmp085_ctx.ac1 + sizeof(bmp085_ctx.ac1);
i2c_read_reg_to_buf(BMP085_ADDRESS, 0xAA, &bmp085_ctx.ac1, s_bytes);
// now fix endianness
int16_t *p;
for (p = &bmp085_ctx.ac1; p <= &bmp085_ctx.md; p++) {
swap_endianness(p, sizeof(*p));
}
}

void Baro_init() {
delay(10);
i2c_BMP085_readCalibration();
i2c_BMP085_UT_Start();
delay(5);
i2c_BMP085_UT_Read();
}






Pagina 221


// read uncompensated temperature value: send command first
void i2c_BMP085_UT_Start() {
i2c_writeReg(BMP085_ADDRESS,0xf4,0x2e);
i2c_rep_start(BMP085_ADDRESS<<1);
i2c_write(0xF6);
i2c_stop();
}

// read uncompensated pressure value: send command first
void i2c_BMP085_UP_Start () {
i2c_writeReg(BMP085_ADDRESS,0xf4,0x34+(OSS<<6)); // control register value for oversampling setting 3
i2c_rep_start(BMP085_ADDRESS<<1); //I2C write direction => 0
i2c_write(0xF6);
i2c_stop();
}

// read uncompensated pressure value: read result bytes
// the datasheet suggests a delay of 25.5 ms (oversampling settings 3) after the send command
void i2c_BMP085_UP_Read () {
i2c_rep_start((BMP085_ADDRESS<<1) | 1);//I2C read direction => 1
bmp085_ctx.up.raw[2] = i2c_readAck();
bmp085_ctx.up.raw[1] = i2c_readAck();
bmp085_ctx.up.raw[0] = i2c_readNak();
}

// read uncompensated temperature value: read result bytes
// the datasheet suggests a delay of 4.5 ms after the send command
void i2c_BMP085_UT_Read() {
i2c_rep_start((BMP085_ADDRESS<<1) | 1);//I2C read direction => 1
bmp085_ctx.ut.raw[1] = i2c_readAck();
bmp085_ctx.ut.raw[0] = i2c_readNak();
}

void i2c_BMP085_Calculate() {
int32_t x1, x2, x3, b3, b5, b6, p, tmp;
uint32_t b4, b7;
// Temperature calculations
x1 = ((int32_t)bmp085_ctx.ut.val - bmp085_ctx.ac6) * bmp085_ctx.ac5 >> 15;
x2 = ((int32_t)bmp085_ctx.mc << 11) / (x1 + bmp085_ctx.md);
b5 = x1 + x2;






Pagina 222


// Pressure calculations
b6 = b5 - 4000;
x1 = (bmp085_ctx.b2 * (b6 * b6 >> 12)) >> 11;
x2 = bmp085_ctx.ac2 * b6 >> 11;
x3 = x1 + x2;
tmp = bmp085_ctx.ac1;
tmp = (tmp*4 + x3) << OSS;
b3 = (tmp+2)/4;
x1 = bmp085_ctx.ac3 * b6 >> 13;
x2 = (bmp085_ctx.b1 * (b6 * b6 >> 12)) >> 16;
x3 = ((x1 + x2) + 2) >> 2;
b4 = (bmp085_ctx.ac4 * (uint32_t)(x3 + 32768)) >> 15;
b7 = ((uint32_t) (bmp085_ctx.up.val >> (8-OSS)) - b3) * (50000 >> OSS);
p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;
x1 = (p >> 8) * (p >> 8);
x1 = (x1 * 3038) >> 16;
x2 = (-7357 * p) >> 16;
pressure = p + ((x1 + x2 + 3791) >> 4);
}

void Baro_update() {
if (currentTime < bmp085_ctx.deadline) return;
bmp085_ctx.deadline = currentTime;
TWBR = ((F_CPU / 400000L) - 16) / 2; // change the I2C clock rate to 400kHz, BMP085 is ok with this speed
switch (bmp085_ctx.state) {
case 0:
i2c_BMP085_UT_Start();
bmp085_ctx.state++; bmp085_ctx.deadline += 4600;
break;
case 1:
i2c_BMP085_UT_Read();
bmp085_ctx.state++;
break;
case 2:
i2c_BMP085_UP_Start();
bmp085_ctx.state++; bmp085_ctx.deadline += 14000;
break;
case 3:
i2c_BMP085_UP_Read();
i2c_BMP085_Calculate();
BaroAlt = (1.0f - pow(pressure/101325.0f, 0.190295f)) * 4433000.0f; //centimeter
bmp085_ctx.state = 0; bmp085_ctx.deadline += 5000;
break;
}
}
#endif






Pagina 223


// ************************************************************************************************************
// I2C Accelerometer BMA180
// ************************************************************************************************************
// I2C adress: 0x80 (8bit) 0x40 (7bit) (SDO connection to VCC)
// I2C adress: 0x82 (8bit) 0x41 (7bit) (SDO connection to VDDIO)
// Resolution: 14bit
// Control registers:
// 0x20 bw_tcs: | bw<3:0> | tcs<3:0> |
// | 150Hz | xxxxxxxx |
// 0x30 tco_z: | tco_z<5:0> | mode_config<1:0> |
// | xxxxxxxxxx | 00 |
// 0x35 offset_lsb1: | offset_x<3:0> | range<2:0> | smp_skip |
// | xxxxxxxxxxxxx | 8G: 101 | xxxxxxxx |
// ************************************************************************************************************
#if defined(BMA180)
void ACC_init () {
delay(10);
//default range 2G: 1G = 4096 unit.
i2c_writeReg(BMA180_ADDRESS,0x0D,1<<4); // register: ctrl_reg0 -- value: set bit ee_w to 1 to enable writing
delay(5);
uint8_t control = i2c_readReg(BMA180_ADDRESS, 0x20);
control = control & 0x0F; // save tcs register
control = control | (0x01 << 4); // register: bw_tcs reg: bits 4-7 to set bw -- value: set low pass filter to 20Hz
i2c_writeReg(BMA180_ADDRESS, 0x20, control);
delay(5);
control = i2c_readReg(BMA180_ADDRESS, 0x30);
control = control & 0xFC; // save tco_z register
control = control | 0x00; // set mode_config to 0
i2c_writeReg(BMA180_ADDRESS, 0x30, control);
delay(5);
control = i2c_readReg(BMA180_ADDRESS, 0x35);
control = control & 0xF1; // save offset_x and smp_skip register
control = control | (0x05 << 1); // set range to 8G
i2c_writeReg(BMA180_ADDRESS, 0x35, control);
delay(5);
acc_1G = 255;
}

void ACC_getADC () {
TWBR = ((F_CPU / 400000L) - 16) / 2; // Optional line. Sensor is good for it in the spec.
i2c_getSixRawADC(BMA180_ADDRESS,0x02);
//usefull info is on the 14 bits [2-15] bits /4 => [0-13] bits /4 => 12 bit resolution
ACC_ORIENTATION( ((rawADC[1]<<8) | rawADC[0])/16 ,
((rawADC[3]<<8) | rawADC[2])/16 ,
((rawADC[5]<<8) | rawADC[4])/16 );
ACC_Common();
}
#endif





Pagina 224


// ************************************************************************************************************
// I2C Gyroscope ITG3200
// ************************************************************************************************************
// I2C adress: 0xD2 (8bit) 0x69 (7bit)
// I2C adress: 0xD0 (8bit) 0x68 (7bit)
// principle:
// 1) VIO is connected to VDD
// 2) I2C adress is set to 0x69 (AD0 PIN connected to VDD)
// or 2) I2C adress is set to 0x68 (AD0 PIN connected to GND)
// 3) sample rate = 1000Hz ( 1kHz/(div+1) )
// ************************************************************************************************************
#if defined(ITG3200)
void Gyro_init() {
delay(100);
i2c_writeReg(ITG3200_ADDRESS, 0x3E, 0x80); //register: Power Management -- value: reset device
// delay(5);
// i2c_writeReg(ITG3200_ADDRESS, 0x15, ITG3200_SMPLRT_DIV); //register: Sample Rate Divider -- default value = 0: OK
delay(5);
i2c_writeReg(ITG3200_ADDRESS, 0x16, 0x18 + ITG3200_DLPF_CFG); //register: DLPF_CFG - low pass filter configuration
delay(5);
i2c_writeReg(ITG3200_ADDRESS, 0x3E, 0x03); //register: Power Management -- value: PLL with Z Gyro reference
delay(100);
}

void Gyro_getADC () {
TWBR = ((F_CPU / 400000L) - 16) / 2; // change the I2C clock rate to 400kHz
i2c_getSixRawADC(ITG3200_ADDRESS,0X1D);
GYRO_ORIENTATION( ((rawADC[0]<<8) | rawADC[1])/4 , // range: +/- 8192; +/- 2000 deg/sec
((rawADC[2]<<8) | rawADC[3])/4 ,
((rawADC[4]<<8) | rawADC[5])/4 );
GYRO_Common();
}
#endif






Pagina 225


// ************************************************************************************************************
// I2C Compass common function
// ************************************************************************************************************
#if MAG
static float magCal[3] = {1.0,1.0,1.0}; // gain for each axis, populated at sensor init
static uint8_t magInit = 0;
void Mag_getADC() {
static uint32_t t,tCal = 0;
static int16_t magZeroTempMin[3];
static int16_t magZeroTempMax[3];
uint8_t axis;
if ( currentTime < t ) return; //each read is spaced by 100ms
t = currentTime + 100000;
TWBR = ((F_CPU / 400000L) - 16) / 2; // change the I2C clock rate to 400kHz
Device_Mag_getADC();
magADC[ROLL] = magADC[ROLL] * magCal[ROLL];
magADC[PITCH] = magADC[PITCH] * magCal[PITCH];
magADC[YAW] = magADC[YAW] * magCal[YAW];
if (f.CALIBRATE_MAG) {
tCal = t;
for(axis=0;axis<3;axis++) {
conf.magZero[axis] = 0;
magZeroTempMin[axis] = magADC[axis];
magZeroTempMax[axis] = magADC[axis];
}
f.CALIBRATE_MAG = 0;
}
if (magInit) { // we apply offset only once mag calibration is done
magADC[ROLL] -= conf.magZero[ROLL];
magADC[PITCH] -= conf.magZero[PITCH];
magADC[YAW] -= conf.magZero[YAW];
}
if (tCal != 0) {
if ((t - tCal) < 30000000) { // 30s: you have 30s to turn the multi in all directions
LEDPIN_TOGGLE;
for(axis=0;axis<3;axis++) {
if (magADC[axis] < magZeroTempMin[axis]) magZeroTempMin[axis] = magADC[axis];
if (magADC[axis] > magZeroTempMax[axis]) magZeroTempMax[axis] = magADC[axis];
}
} else {
tCal = 0;
for(axis=0;axis<3;axis++)
conf.magZero[axis] = (magZeroTempMin[axis] + magZeroTempMax[axis])/2;
writeParams(1);
}
}
}
#endif





Pagina 226


// ************************************************************************************************************
// I2C Compass HMC5883
// ************************************************************************************************************
// I2C adress: 0x3C (8bit) 0x1E (7bit)
// ************************************************************************************************************
#if defined(HMC5843) || defined(HMC5883)
#define MAG_ADDRESS 0x1E
#define MAG_DATA_REGISTER 0x03

void Mag_init() {
delay(100);
// force positiveBias
i2c_writeReg(MAG_ADDRESS ,0x00 ,0x71 ); //Configuration Register A -- 0 11 100 01 num samples: 8 ; output rate: 15Hz ; positive bias
delay(50);
// set gains for calibration
i2c_writeReg(MAG_ADDRESS ,0x01 ,0x60 ); //Configuration Register B -- 011 00000 configuration gain 2.5Ga
i2c_writeReg(MAG_ADDRESS ,0x02 ,0x01 ); //Mode register -- 000000 01 single Conversion Mode

// read values from the compass - self test operation
// by placing the mode register into single-measurement mode (0x01), two data acquisition cycles will be made on each magnetic vector.
// The first acquisition values will be subtracted from the second acquisition, and the net measurement will be placed into the data output
registers
delay(100);
getADC();
delay(10);
#if defined(HMC5883)
magCal[ROLL] = 1160.0 / abs(magADC[ROLL]);
magCal[PITCH] = 1160.0 / abs(magADC[PITCH]);
magCal[YAW] = 1080.0 / abs(magADC[YAW]);
#else
magCal[ROLL] = 1000.0 / abs(magADC[ROLL]);
magCal[PITCH] = 1000.0 / abs(magADC[PITCH]);
magCal[YAW] = 1000.0 / abs(magADC[YAW]);
#endif

// leave test mode
i2c_writeReg(MAG_ADDRESS ,0x00 ,0x70 ); //Configuration Register A -- 0 11 100 00 num samples: 8 ; output rate: 15Hz ; normal measurement mode
i2c_writeReg(MAG_ADDRESS ,0x01 ,0x20 ); //Configuration Register B -- 001 00000 configuration gain 1.3Ga
i2c_writeReg(MAG_ADDRESS ,0x02 ,0x00 ); //Mode register -- 000000 00 continuous Conversion Mode

magInit = 1;
}






Pagina 227


void getADC() {
i2c_getSixRawADC(MAG_ADDRESS,MAG_DATA_REGISTER);
#if defined(HMC5843)
MAG_ORIENTATION( ((rawADC[0]<<8) | rawADC[1]) ,
((rawADC[2]<<8) | rawADC[3]) ,
((rawADC[4]<<8) | rawADC[5]) );
#endif
#if defined (HMC5883)
MAG_ORIENTATION( ((rawADC[0]<<8) | rawADC[1]) ,
((rawADC[4]<<8) | rawADC[5]) ,
((rawADC[2]<<8) | rawADC[3]) );
#endif
}

#if not defined(MPU6050_I2C_AUX_MASTER)
void Device_Mag_getADC() {
getADC();
}
#endif
#endif






Pagina 228


// ************************************************************************************************************
// I2C Sonar SRF08
// ************************************************************************************************************
// first contribution from guru_florida (02-25-2012)
//
// specs are here: http://www.meas-spec.com/downloads/MS5611-01BA03.pdf
// useful info on pages 7 -> 12
#if defined(SRF02) || defined(SRF08) || defined(SRF10) || defined(SRC235)

// the default address for any new sensor found on the bus
// the code will move new sonars to the next available sonar address in range of F0-FE so that another
// sonar sensor can be added again.
// Thus, add only 1 sonar sensor at a time, poweroff, then wire the next, power on, wait for flashing light and repeat
#if !defined(SRF08_DEFAULT_ADDRESS)
#define SRF08_DEFAULT_ADDRESS 0x70
#endif

#if !defined(SRF08_RANGE_WAIT)
#define SRF08_RANGE_WAIT 80000 // delay between Ping and Range Read commands
#endif

#if !defined(SRF08_RANGE_SLEEP)
#define SRF08_RANGE_SLEEP 35000 // sleep this long before starting another Ping
#endif

#if !defined(SRF08_SENSOR_FIRST)
#define SRF08_SENSOR_FIRST 0xF0 // the first sensor i2c address (after it has been moved)
#endif

#if !defined(SRF08_MAX_SENSORS)
#define SRF08_MAX_SENSORS 4 // maximum number of sensors we'll allow (can go up to 8)
#endif

#define SONAR_MULTICAST_PING

// registers of the device
#define SRF08_REV_COMMAND 0
#define SRF08_LIGHT_GAIN 1
#define SRF08_ECHO_RANGE 2







Pagina 229


static struct {
// sensor registers from the MS561101BA datasheet
int32_t range[SRF08_MAX_SENSORS];
int8_t sensors; // the number of sensors present
int8_t current; // the current sensor being read
uint8_t state;
uint32_t deadline;
} srf08_ctx;


// read uncompensated temperature value: send command first
void Sonar_init() {
memset(&srf08_ctx, 0, sizeof(srf08_ctx));
srf08_ctx.deadline = 4000000;
}

// this function works like readReg accept a failed read is a normal expectation
// use for testing the existence of sensors on the i2c bus
// a 0xffff code is returned if the read failed
uint16_t i2c_try_readReg(uint8_t add, uint8_t reg) {
uint16_t count = 255;
i2c_rep_start(add<<1); // I2C write direction
i2c_write(reg); // register selection
i2c_rep_start((add<<1)|1); // I2C read direction

TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT))) {
count--;
if (count==0) { //we are in a blocking state => we don't insist
TWCR = 0; //and we force a reset on TWINT register
return 0xffff; // return failure to read
}
}

uint8_t r = TWDR;
i2c_stop();
return r;
}

// read a 16bit unsigned int from the i2c bus
uint16_t i2c_readReg16(int8_t addr, int8_t reg) {
uint8_t b[2];
i2c_read_reg_to_buf(addr, reg, &b, sizeof(b));
return (b[0]<<8) | b[1];
}






Pagina 230


void i2c_srf08_change_addr(int8_t current, int8_t moveto) {
// to change a srf08 address, we must write the following sequence to the command register
// this sequence must occur as 4 seperate i2c transactions!!
// A0 AA A5 [addr]
i2c_writeReg(current, SRF08_REV_COMMAND, 0xA0); delay(30);
i2c_writeReg(current, SRF08_REV_COMMAND, 0xAA); delay(30);
i2c_writeReg(current, SRF08_REV_COMMAND, 0xA5); delay(30);
i2c_writeReg(current, SRF08_REV_COMMAND, moveto); delay(30); // now change i2c address
blinkLED(5,1,2);
}

// discover previously known sensors and any new sensor (move new sensors to assigned area)
void i2c_srf08_discover() {
uint8_t addr;
uint16_t x;

// determine how many sensors are plugged in
srf08_ctx.sensors=0;
addr = SRF08_SENSOR_FIRST;
for(int i=0; i<SRF08_MAX_SENSORS && x!=0xff; i++) {
// read the revision as a way to check if sensor exists at this location
x = i2c_try_readReg(addr, SRF08_REV_COMMAND);
if(x!=0xffff) {
// detected a sensor at this address
srf08_ctx.sensors++;
addr += 2;
}
}

// do not add sensors if we are already maxed
if(srf08_ctx.sensors < SRF08_MAX_SENSORS) {
// now determine if any sensor is on the 'new sensor' address (srf08 default address)
// we try to read the revision number
x = i2c_try_readReg(SRF08_DEFAULT_ADDRESS, SRF08_REV_COMMAND);
if(x!=0xffff) {
// new sensor detected at SRF08 default address
i2c_srf08_change_addr(SRF08_DEFAULT_ADDRESS, addr); // move sensor to the next address
srf08_ctx.sensors++;
}
}
}






Pagina 231


void Sonar_update() {
if (currentTime < srf08_ctx.deadline || (srf08_ctx.state==0 && f.ARMED)) return;
srf08_ctx.deadline = currentTime;
TWBR = ((F_CPU / 400000L) - 16) / 2; // change the I2C clock rate to 400kHz, SRF08 is ok with this speed
switch (srf08_ctx.state) {
case 0:
i2c_srf08_discover();
if(srf08_ctx.sensors>0)
srf08_ctx.state++;
else
srf08_ctx.deadline += 5000000; // wait 5 secs before trying search again
break;
case 1:
srf08_ctx.current=0;
srf08_ctx.state++;
srf08_ctx.deadline += SRF08_RANGE_SLEEP;
break;
#if defined(SONAR_MULTICAST_PING)
case 2:
// send a ping via the general broadcast address
i2c_writeReg(0, SRF08_REV_COMMAND, 0x51); // start ranging, result in centimeters
srf08_ctx.state++;
srf08_ctx.deadline += SRF08_RANGE_WAIT;
break;
case 3:
srf08_ctx.range[srf08_ctx.current] = i2c_readReg16( SRF08_SENSOR_FIRST+(srf08_ctx.current<<1), SRF08_ECHO_RANGE);
srf08_ctx.current++;
if(srf08_ctx.current >= srf08_ctx.sensors)
srf08_ctx.state=1;
break;
#else
case 2:
// send a ping to the current sensor
i2c_writeReg(SRF08_SENSOR_FIRST+(srf08_ctx.current<<1), SRF08_REV_COMMAND, 0x51); // start ranging, result in centimeters
srf08_ctx.state++;
srf08_ctx.deadline += SRF08_RANGE_WAIT;
break;
case 3:
srf08_ctx.range[srf08_ctx.current] = i2c_readReg16(SRF08_SENSOR_FIRST+(srf08_ctx.current<<1), SRF08_ECHO_RANGE);
srf08_ctx.current++;
if(srf08_ctx.current >= srf08_ctx.sensors)
srf08_ctx.state=1;
else
srf08_ctx.state=2;
break;
#endif
}





Pagina 232


sonarAlt = srf08_ctx.range[0]; //tmp
}
#elif defined(TINY_GPS_SONAR)
inline void Sonar_init() {}
void Sonar_update() {
/* do not query the module again if the GPS loop already did */
#if defined(TINY_GPS)
if (!GPS_Enable) {
#else
{
#endif
tinygps_query();
}
}
#else
inline void Sonar_init() {}
inline void Sonar_update() {}
#endif



void initSensors() {
delay(200);
POWERPIN_ON;
delay(100);
i2c_init();
delay(100);
if (GYRO) Gyro_init();
if (BARO) Baro_init();
if (MAG) Mag_init();
if (ACC) {ACC_init();acc_25deg = acc_1G * 0.423;}
if (SONAR) Sonar_init();
f.I2C_INIT_DONE = 1;
}







Pagina 233


Serial
#define UART_NUMBER 1
#define RX_BUFFER_SIZE 64
#define TX_BUFFER_SIZE 128
#define INBUF_SIZE 64

static volatile uint8_t serialHeadRX[UART_NUMBER],serialTailRX[UART_NUMBER];
static uint8_t serialBufferRX[RX_BUFFER_SIZE][UART_NUMBER];
static volatile uint8_t headTX,tailTX;
static uint8_t bufTX[TX_BUFFER_SIZE];
static uint8_t inBuf[INBUF_SIZE];

// Multiwii Serial Protocol 0
#define MSP_VERSION 0

#define MSP_IDENT 100 //out message multitype + multiwii version + protocol version + capability variable
#define MSP_STATUS 101 //out message cycletime & errors_count & sensor present & box activation
#define MSP_RAW_IMU 102 //out message 9 DOF
#define MSP_SERVO 103 //out message 8 servos
#define MSP_MOTOR 104 //out message 8 motors
#define MSP_RC 105 //out message 8 rc chan
#define MSP_RAW_GPS 106 //out message fix, numsat, lat, lon, alt, speed
#define MSP_COMP_GPS 107 //out message distance home, direction home
#define MSP_ATTITUDE 108 //out message 2 angles 1 heading
#define MSP_ALTITUDE 109 //out message 1 altitude
#define MSP_BAT 110 //out message vbat, powermetersum
#define MSP_RC_TUNING 111 //out message rc rate, rc expo, rollpitch rate, yaw rate, dyn throttle PID
#define MSP_PID 112 //out message up to 16 P I D (8 are used)
#define MSP_BOX 113 //out message up to 16 checkbox (11 are used)
#define MSP_MISC 114 //out message powermeter trig + 8 free for future use
#define MSP_MOTOR_PINS 115 //out message which pins are in use for motors & servos, for GUI
#define MSP_BOXNAMES 116 //out message the aux switch names
#define MSP_PIDNAMES 117 //out message the PID names
#define MSP_WP 118 //out message get a WP, WP# is in the payload, returns (WP#, lat, lon, alt, flags) WP#0-home, WP#16-
poshold

#define MSP_SET_RAW_RC 200 //in message 8 rc chan
#define MSP_SET_RAW_GPS 201 //in message fix, numsat, lat, lon, alt, speed
#define MSP_SET_PID 202 //in message up to 16 P I D (8 are used)
#define MSP_SET_BOX 203 //in message up to 16 checkbox (11 are used)
#define MSP_SET_RC_TUNING 204 //in message rc rate, rc expo, rollpitch rate, yaw rate, dyn throttle PID
#define MSP_ACC_CALIBRATION 205 //in message no param
#define MSP_MAG_CALIBRATION 206 //in message no param
#define MSP_SET_MISC 207 //in message powermeter trig + 8 free for future use
#define MSP_RESET_CONF 208 //in message no param
#define MSP_WP_SET 209 //in message sets a given WP (WP#,lat, lon, alt, flags)
#define MSP_EEPROM_WRITE 250 //in message no param
#define MSP_DEBUG 254 //out message debug1,debug2,debug3,debug4





Pagina 234


static uint8_t checksum;
static uint8_t indRX;
static uint8_t cmdMSP;

uint32_t read32() {
uint32_t t = read16();
t+= (uint32_t)read16()<<16;
return t;
}
uint16_t read16() {
uint16_t t = read8();
t+= (uint16_t)read8()<<8;
return t;
}
uint8_t read8() {
return inBuf[indRX++]&0xff;
}

void headSerialResponse(uint8_t err, uint8_t s) {
serialize8('$');
serialize8('M');
serialize8(err ? '!' : '>');
checksum = 0; // start calculating a new checksum
serialize8(s);
serialize8(cmdMSP);
}

void headSerialReply(uint8_t s) {
headSerialResponse(0, s);
}

void inline headSerialError(uint8_t s) {
headSerialResponse(1, s);
}

void tailSerialReply() {
serialize8(checksum);UartSendData();
}

void serializeNames(PGM_P s) {
for (PGM_P c = s; pgm_read_byte(c); c++) {
serialize8(pgm_read_byte(c));
}
}






Pagina 235


void serialCom() {
uint8_t c;
static uint8_t offset;
static uint8_t dataSize;
static enum _serial_state {
IDLE,
HEADER_START,
HEADER_M,
HEADER_ARROW,
HEADER_SIZE,
HEADER_CMD,
} c_state = IDLE;

while (SerialAvailable(0)) {
uint8_t bytesTXBuff = ((uint8_t)(headTX-tailTX))%TX_BUFFER_SIZE; // indicates the number of occupied bytes in TX buffer
if (bytesTXBuff > TX_BUFFER_SIZE - 40 ) return; // ensure there is enough free TX buffer to go further (40 bytes margin)
c = SerialRead(0);

if (c_state == IDLE) {
c_state = (c=='$') ? HEADER_START : IDLE;
if (c_state == IDLE) evaluateOtherData(c); // evaluate all other incoming serial data
} else if (c_state == HEADER_START) {
c_state = (c=='M') ? HEADER_M : IDLE;
} else if (c_state == HEADER_M) {
c_state = (c=='<') ? HEADER_ARROW : IDLE;
} else if (c_state == HEADER_ARROW) {
if (c > INBUF_SIZE) { // now we are expecting the payload size
c_state = IDLE;
continue;
}
dataSize = c;
offset = 0;
checksum = 0;
indRX = 0;
checksum ^= c;
c_state = HEADER_SIZE; // the command is to follow
} else if (c_state == HEADER_SIZE) {
cmdMSP = c;
checksum ^= c;
c_state = HEADER_CMD;
} else if (c_state == HEADER_CMD && offset < dataSize) {
checksum ^= c;
inBuf[offset++] = c;
} else if (c_state == HEADER_CMD && offset >= dataSize) {
if (checksum == c) { // compare calculated and transferred checksum
evaluateCommand(); // we got a valid packet, evaluate it
}
c_state = IDLE;
} } }




Pagina 236


void evaluateCommand() {
switch(cmdMSP) {
case MSP_SET_RAW_RC:
for(uint8_t i=0;i<8;i++) {
rcData[i] = read16();
}
headSerialReply(0);
break;
#if GPS
case MSP_SET_RAW_GPS:
f.GPS_FIX = read8();
GPS_numSat = read8();
GPS_coord[LAT] = read32();
GPS_coord[LON] = read32();
GPS_altitude = read16();
GPS_speed = read16();
GPS_update |= 2; // New data signalisation to GPS functions
headSerialReply(0);
break;
#endif
case MSP_SET_PID:
for(uint8_t i=0;i<PIDITEMS;i++) {
conf.P8[i]=read8();
conf.I8[i]=read8();
conf.D8[i]=read8();
}
headSerialReply(0);
break;
case MSP_SET_BOX:
for(uint8_t i=0;i<CHECKBOXITEMS;i++) {
conf.activate[i]=read16();
}
headSerialReply(0);
break;
case MSP_SET_RC_TUNING:
conf.rcRate8 = read8();
conf.rcExpo8 = read8();
conf.rollPitchRate = read8();
conf.yawRate = read8();
conf.dynThrPID = read8();
conf.thrMid8 = read8();
conf.thrExpo8 = read8();
headSerialReply(0);
break;





Pagina 237


case MSP_SET_MISC:
#if defined(POWERMETER)
conf.powerTrigger1 = read16() / PLEVELSCALE;
#endif
headSerialReply(0);
break;
case MSP_IDENT:
headSerialReply(7);
serialize8(VERSION); // multiwii version
serialize8(MULTITYPE); // type of multicopter
serialize8(MSP_VERSION); // MultiWii Serial Protocol Version
serialize32(0); // "capability"
break;
case MSP_STATUS:
headSerialReply(10);
serialize16(cycleTime);
serialize16(i2c_errors_count);
serialize16(ACC|BARO<<1|MAG<<2|GPS<<3|SONAR<<4);
serialize32(f.ACC_MODE<<BOXACC|f.BARO_MODE<<BOXBARO|f.MAG_MODE<<BOXMAG|f.ARMED<<BOXARM|
rcOptions[BOXCAMSTAB]<<BOXCAMSTAB | rcOptions[BOXCAMTRIG]<<BOXCAMTRIG |
f.GPS_HOME_MODE<<BOXGPSHOME|f.GPS_HOLD_MODE<<BOXGPSHOLD|f.HEADFREE_MODE<<BOXHEADFREE|
f.PASSTHRU_MODE<<BOXPASSTHRU|rcOptions[BOXBEEPERON]<<BOXBEEPERON|rcOptions[BOXLEDMAX]<<BOXLEDMAX|rcOptions[BOXLLIGHTS]<<BOXLLIGHTS|rcO
ptions[BOXHEADADJ]<<BOXHEADADJ);
break;
case MSP_RAW_IMU:
headSerialReply(18);
for(uint8_t i=0;i<3;i++) serialize16(accSmooth[i]);
for(uint8_t i=0;i<3;i++) serialize16(gyroData[i]);
for(uint8_t i=0;i<3;i++) serialize16(magADC[i]);
break;
case MSP_SERVO:
headSerialReply(16);
for(uint8_t i=0;i<8;i++)
#if defined(SERVO)
serialize16(servo[i]);
#else
serialize16(0);
#endif
break;
case MSP_MOTOR:
headSerialReply(16);
for(uint8_t i=0;i<8;i++) {
serialize16( (i < NUMBER_MOTOR) ? motor[i] : 0 );
}
break;





Pagina 238


case MSP_RC:
headSerialReply(16);
for(uint8_t i=0;i<8;i++) serialize16(rcData[i]);
break;
#if GPS
case MSP_RAW_GPS:
headSerialReply(14);
serialize8(f.GPS_FIX);
serialize8(GPS_numSat);
serialize32(GPS_coord[LAT]);
serialize32(GPS_coord[LON]);
serialize16(GPS_altitude);
serialize16(GPS_speed);
break;
case MSP_COMP_GPS:
headSerialReply(5);
serialize16(GPS_distanceToHome);
serialize16(GPS_directionToHome);
serialize8(GPS_update & 1);
break;
#endif
case MSP_ATTITUDE:
headSerialReply(8);
for(uint8_t i=0;i<2;i++) serialize16(angle[i]);
serialize16(heading);
serialize16(headFreeModeHold);
break;
case MSP_ALTITUDE:
headSerialReply(4);
serialize32(EstAlt);
break;
case MSP_BAT:
headSerialReply(3);
serialize8(vbat);
serialize16(intPowerMeterSum);
break;
case MSP_RC_TUNING:
headSerialReply(7);
serialize8(conf.rcRate8);
serialize8(conf.rcExpo8);
serialize8(conf.rollPitchRate);
serialize8(conf.yawRate);
serialize8(conf.dynThrPID);
serialize8(conf.thrMid8);
serialize8(conf.thrExpo8);
break;





Pagina 239


case MSP_PID:
headSerialReply(3*PIDITEMS);
for(uint8_t i=0;i<PIDITEMS;i++) {
serialize8(conf.P8[i]);
serialize8(conf.I8[i]);
serialize8(conf.D8[i]);
}
break;
case MSP_BOX:
headSerialReply(2*CHECKBOXITEMS);
for(uint8_t i=0;i<CHECKBOXITEMS;i++) {
serialize16(conf.activate[i]);
}
break;
case MSP_BOXNAMES:
headSerialReply(strlen_P(boxnames));
serializeNames(boxnames);
break;
case MSP_PIDNAMES:
headSerialReply(strlen_P(pidnames));
serializeNames(pidnames);
break;
case MSP_MISC:
headSerialReply(2);
serialize16(intPowerTrigger1);
break;
case MSP_MOTOR_PINS:
headSerialReply(8);
for(uint8_t i=0;i<8;i++) {
serialize8(PWM_PIN[i]);
}
break;






Pagina 240


#if defined(USE_MSP_WP)
case MSP_WP:
{
uint8_t wp_no = read8(); //get the wp number
headSerialReply(12);
if (wp_no == 0) {
serialize8(0); //wp0
serialize32(GPS_home[LAT]);
serialize32(GPS_home[LON]);
serialize16(0); //altitude will come here
serialize8(0); //nav flag will come here
} else if (wp_no == 16)
{
serialize8(16); //wp16
serialize32(GPS_hold[LAT]);
serialize32(GPS_hold[LON]);
serialize16(0); //altitude will come here
serialize8(0); //nav flag will come here
}
}
break;
#endif
case MSP_RESET_CONF:
conf.checkNewConf++;
checkFirstTime();
headSerialReply(0);
break;
case MSP_ACC_CALIBRATION:
calibratingA=400;
headSerialReply(0);
break;
case MSP_MAG_CALIBRATION:
f.CALIBRATE_MAG = 1;
headSerialReply(0);
break;
case MSP_EEPROM_WRITE:
writeParams(0);
headSerialReply(0);
break;
case MSP_DEBUG:
headSerialReply(8);
for(uint8_t i=0;i<4;i++) {
serialize16(debug[i]); // 4 variables are here for general monitoring purpose
}
break;
default: // we do not know how to handle the (valid) message, indicate error MSP $M!
headSerialError(0);
break;
}




Pagina 241


tailSerialReply();
}

// evaluate all other incoming serial data
void evaluateOtherData(uint8_t sr) {
switch (sr) {
// Note: we may receive weird characters here which could trigger unwanted features during flight.
// this could lead to a crash easily.
// Please use if (!f.ARMED) where neccessary
#ifdef LCD_CONF
case 's':
case 'S':
if (!f.ARMED) configurationLoop();
break;
#endif
#ifdef LCD_TELEMETRY
case 'A': // button A press
toggle_telemetry(1);
break;
case 'B': // button B press
toggle_telemetry(2);
break;
case 'C': // button C press
toggle_telemetry(3);
break;
case 'D': // button D press
toggle_telemetry(4);
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
#if defined(LOG_VALUES) && defined(DEBUG)
case 'R':
#endif
#ifdef DEBUG
case 'F':
#endif





Pagina 242


toggle_telemetry(sr);
break;
case 'a': // button A release
case 'b': // button B release
case 'c': // button C release
case 'd': // button D release
break;
#endif // LCD_TELEMETRY
}
}

// *******************************************************
// For Teensy 2.0, these function emulate the API used for ProMicro
// it cant have the same name as in the arduino API because it wont compile for the promini (eaven if it will be not compiled)
// *******************************************************
#if defined(TEENSY20)
unsigned char T_USB_Available(){
int n = Serial.available();
if (n > 255) n = 255;
return n;
}
#endif

// *******************************************************
// Interrupt driven UART transmitter - using a ring buffer
// *******************************************************

void serialize32(uint32_t a) {
serialize8((a ) & 0xFF);
serialize8((a>> 8) & 0xFF);
serialize8((a>>16) & 0xFF);
serialize8((a>>24) & 0xFF);
}

void serialize16(int16_t a) {
serialize8((a ) & 0xFF);
serialize8((a>>8) & 0xFF);
}

void serialize8(uint8_t a) {
uint8_t t = headTX;
if (++t >= TX_BUFFER_SIZE) t = 0;
bufTX[t] = a;
checksum ^= a;
headTX = t;
}






Pagina 243


#if !defined(PROMICRO)
ISR_UART {
uint8_t t = tailTX;
if (headTX != t) {
if (++t >= TX_BUFFER_SIZE) t = 0;
UDR0 = bufTX[t]; // Transmit next byte in the ring
tailTX = t;
}
if (t == headTX) UCSR0B &= ~(1<<UDRIE0); // Check if all data is transmitted . if yes disable transmitter UDRE interrupt
}
#endif

void UartSendData() {
#if defined(PROMICRO)
while(headTX != tailTX) {
if (++tailTX >= TX_BUFFER_SIZE) tailTX = 0;
uint8_t* p = bufTX+tailTX;
#if !defined(TEENSY20)
USB_Send(USB_CDC_TX,p,1);
#else
Serial.write(p,1);
#endif
}
#else
UCSR0B |= (1<<UDRIE0); // enable transmitter UDRE interrupt if deactivacted
#endif
}

static void inline SerialOpen(uint8_t port, uint32_t baud) {
uint8_t h = ((F_CPU / 4 / baud -1) / 2) >> 8;
uint8_t l = ((F_CPU / 4 / baud -1) / 2);
switch (port) {
#if !defined(PROMICRO)
case 0: UCSR0A = (1<<U2X0); UBRR0H = h; UBRR0L = l; UCSR0B |= (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0); break;
#else
#if (ARDUINO >= 100) && !defined(TEENSY20)
case 0: UDIEN &= ~(1<<SOFE); break;// disable the USB frame interrupt of arduino (it causes strong jitter and we dont need it)
#endif
#endif
#if defined(MEGA) || defined(PROMICRO)
case 1: UCSR1A = (1<<U2X1); UBRR1H = h; UBRR1L = l; UCSR1B |= (1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1); break;
#endif
#if defined(MEGA)
case 2: UCSR2A = (1<<U2X2); UBRR2H = h; UBRR2L = l; UCSR2B |= (1<<RXEN2)|(1<<TXEN2)|(1<<RXCIE2); break;
case 3: UCSR3A = (1<<U2X3); UBRR3H = h; UBRR3L = l; UCSR3B |= (1<<RXEN3)|(1<<TXEN3)|(1<<RXCIE3); break;
#endif
}
}





Pagina 244


static void inline SerialEnd(uint8_t port) {
switch (port) {
#if !defined(PROMICRO)
case 0: UCSR0B &= ~((1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<UDRIE0)); break;
#endif
#if defined(MEGA) || defined(PROMICRO)
case 1: UCSR1B &= ~((1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1)); break;
#endif
#if defined(MEGA)
case 2: UCSR2B &= ~((1<<RXEN2)|(1<<TXEN2)|(1<<RXCIE2)); break;
case 3: UCSR3B &= ~((1<<RXEN3)|(1<<TXEN3)|(1<<RXCIE3)); break;
#endif
}
}

static void inline store_uart_in_buf(uint8_t data, uint8_t portnum) {
uint8_t h = serialHeadRX[portnum];
if (++h >= RX_BUFFER_SIZE) h = 0;
if (h == serialTailRX[portnum]) return; // we did not bite our own tail?
serialBufferRX[serialHeadRX[portnum]][portnum] = data;
serialHeadRX[portnum] = h;
}

#if defined(PROMINI) && !(defined(SPEKTRUM))
ISR(USART_RX_vect) { store_uart_in_buf(UDR0, 0); }
#endif

#if (defined(MEGA) || defined(PROMICRO)) && !defined(SPEKTRUM)
ISR(USART1_RX_vect) { store_uart_in_buf(UDR1, 1); }
#endif
#if defined(MEGA)
ISR(USART0_RX_vect) { store_uart_in_buf(UDR0, 0); }
ISR(USART2_RX_vect) { store_uart_in_buf(UDR2, 2); }
ISR(USART3_RX_vect) { store_uart_in_buf(UDR3, 3); }
#endif






Pagina 245


uint8_t SerialRead(uint8_t port) {
#if defined(PROMICRO)
#if defined(TEENSY20)
if(port == 0) return Serial.read();
#else
#if (ARDUINO >= 100)
USB_Flush(USB_CDC_TX);
#endif
if(port == 0) return USB_Recv(USB_CDC_RX);
#endif
port = 0;
#endif
uint8_t t = serialTailRX[port];
uint8_t c = serialBufferRX[t][port];
if (serialHeadRX[port] != t) {
if (++t >= RX_BUFFER_SIZE) t = 0;
serialTailRX[port] = t;
}
return c;
}

uint8_t SerialAvailable(uint8_t port) {
#if defined(PROMICRO)
#if !defined(TEENSY20)
if(port == 0) return USB_Available(USB_CDC_RX);
#else
if(port == 0) return T_USB_Available();
#endif
port = 0;
#endif
return (serialHeadRX[port] != serialTailRX[port]);
}

void SerialWrite(uint8_t port,uint8_t c){
switch (port) {
case 0: serialize8(c);UartSendData(); break; // Serial0 TX is driven via a buffer and a background intterupt
#if defined(MEGA) || defined(PROMICRO)
case 1: while (!(UCSR1A & (1 << UDRE1))) ; UDR1 = c; break; // Serial1 Serial2 and Serial3 TX are not driven via interrupts
#endif
#if defined(MEGA)
case 2: while (!(UCSR2A & (1 << UDRE2))) ; UDR2 = c; break;
case 3: while (!(UCSR3A & (1 << UDRE3))) ; UDR3 = c; break;
#endif
}
}





Pagina 246


Calibrating ESCs
/******** special version of MultiWii to calibrate all attached ESCs ************/
#if defined(ESC_CALIB_CANNOT_FLY)
writeAllMotors(ESC_CALIB_HIGH);
delay(3000);
writeAllMotors(ESC_CALIB_LOW);
delay(500);
while (1) {
delay(5000);
blinkLED(2,20, 2);
}
exit; // statement never reached
#endif

writeAllMotors(MINCOMMAND);
delay(300);
#if defined(SERVO)
initializeServo();
#endif
}









Pagina 247


Lijst van figuren

fig. 1.1: De vier krachten op een vliegtuig
fig. 1.2: Een helikopter met zijn rotoren
fig. 1.3: Een helikopter die opstijgt
fig. 1.4: Doel van de staartrotor
fig. 1.5: Draairichting propellers op een quadrocopter
fig. 1.6: Vliegmodes van een quadrocopter
fig. 1.7: Een quadrocopter met een camera
fig. 1.8: Quadrocopters die een voorwerp verplaatsen
fig. 1.9: Quadrocopter die pakje zal verzenden
fig. 1.10: Voorbeelden van quadrocopters
fig. 1.11: Een quadrocopter die het best op onze quadrocopter gelijkt
fig. 1.12: Het KHBO te Brugge
fig. 1.13: Quadrocopter toegelaten in Belgi


fig. 2.1: Het afgewerkte frame
fig. 2.2: Een aluminium arm
fig. 2.3: Onbewerkte aluminium staaf
fig. 2.4a: De afgewerkte aluminium armen
fig. 2.4b: Zijkant van de afgewerkte armen
fig. 2.5: De carbon baseplates
fig. 2.6: De carbonstructuur
fig. 2.7: Zaag test
fig. 2.8: Afgewerkte baseplate (links) en deckplate (rechts)
fig. 2.9: Het maken van het kartonnen frame
fig. 2.10: Het kartonnen frame, schaal 1:1
fig. 2.11 a,b,c: Ons afgewerkt kartonnen frame
fig. 2.12: De 2 soorten stand-offs
fig. 2.13: De nylon stand-offs
fig. 2.14: Stand-offs gemonteerd op het frame
fig. 2.15: De aluminium stand-offs
fig. 2.16: Stand-offs gemonteerd op het frame
fig. 2.17: Deckplate
fig. 2.18: Inventor: hoe alles gemonteerd wordt
fig. 2.19a: Inventor: afgewerkte quadrocopter getekend (schuin zicht)
fig. 2.19b: Inventor: afgewerkte quadrocopter getekend (zijaanzicht)





Pagina 248


fig. 3.1: Schematische voorstelling van de elektronica
fig. 3.2: Onze 3S LiPo batterij
fig. 3.3: Schematische voorstelling van een 3S LiPo
fig. 3.4: Laadcurve van een LiPo batterij
fig. 3.5: Ontlaadcurve van een LiPo batterij
fig. 3.6: Ons powerboard
fig. 3.7: Connectors aan het powerboard solderen
fig. 3.8: Powerboard gemonteerd op het frame
fig. 3.9: De ESC (snelheidsregelaar
fig. 3.10: Brushless DC-motor
fig. 3.11: Schematische voorstelling DC-motor
fig. 3.12: Liftkracht
fig. 3.13: Liftkracht met reactiekrachten
fig. 3.14: Voorstelling invalshoek
fig. 3.15: Voorstelling drukverschil op een vleugel
fig. 3.16: Totale voorstelling werking van een vleugel
fig. 3.17: Karakteristiek van de liftcofficint
fig. 3.18: Voorstelling koorde of invalshoek
fig. 3.19: Draairichting propellers
fig. 3.20: De UBEC
fig. 3.21: De zender
fig. 3.22: De ontvanger
fig. 3.23: Het controllerbordje
fig. 3.24: Voltage level converter
fig. 3.25: Gyrometer
fig. 3.26: Voorstelling gyrometer
fig. 3.27: Accelerometer
fig. 3.28: Voorstelling accelerometer
fig. 3.29: Barometer
fig. 3.30: Magnetometer
fig. 3.31: Atmega 328P controller

fig. 4.1: Stick-inputs
fig. 4.2: Matrix van selecties (eigen voorkeur)
fig. 4.3: PID settings

fig. 5.1: Landingsgestel
fig. 5.2: Landingspoot
fig. 5.3: LED strips
fig. 5.4: Weegschaal met het totaal gewicht
fig. 5.5a: Zijaanzicht quadrocopter
fig. 5.5b: Zijaanzicht quadrocopter (met lichten aan)
fig. 5.6: Close-up van de elektronica
fig. 5.7: Bovenaanzicht

fig. 6.1: Logo Paola wedstrijd




Pagina 249


Literatuurlijst

Opdracht geschiedenis
Leonardo Da Vincis Inventions, internet, leonardodanvincisinventions.com,
(http://www.leonardodavincisinventions.com/inventions-for-flight/leonardo-
da-vinci-helicopter/).

Helicopters built between 1907 and 1935, internet, aviastar.org,
(http://www.aviastar.org/helicopters_eng/france.html).

Curtiss-Wright VZ-7, internet, aviastar.org,
(http://www.aviastar.org/helicopters_eng/curtiss_vz-7.php).

Convertawings Model A, internet, aviastar.org,
(http://www.aviastar.org/helicopters_eng/convertawings.php).

Quadcopter, internet, Wikipedia,
(http://en.wikipedia.org/wiki/Quadrocopter).


Hoofdstuk 1
ALEXANDER, Drones en de wetgeving, internet, Drone kopen.be,
(http://www.drone-kopen.be/wetgeving/drones-en-de-wetgeving/).

Helikopter vs quadcopter, internet, Diffen.com,
(http://quadrocopterpws.files.wordpress.com/2012/12/quadcopter-
profielwerkstuk-verslag.pdf).

Wet- en regelgeving voor drones, internet, Conrad.be,
(http://www.conrad.be/ce/nl/content/wet_en_regelgeving_drones/wet-en-
regelgeving-drones).

Circulaire Cir/GDF-01, internet, Mobilit.belgium.be, 29 juli 2013,
(http://mobilit.belgium.be/nl/binaries/gdf01_tcm466-229990.pdf).

Video zo gaat Amazon al vliegend pakjes bezorgen, internet, HLN.be, 2
december 2013,
(http://www.hln.be/hln/nl/959/Bizar/article/detail/1750634/2013/12/02/Video
-zo-gaat-Amazon-al-vliegend-pakjes-bezorgen.dhtml).






Pagina 250


Hoofdstuk 2
Aluminium, internet, Wikipedia, (http://nl.wikipedia.org/wiki/Aluminium).

Soortgelijke massa van vaste stoffen, internet, Wikipedia,
(http://nl.wikipedia.org/wiki/Soortelijke_massa_van_vaste_stoffen).

Staal vs Aluminium vs Carbon, internet, WordPress.com weblog,
27 januari 2010, (http://bodypegasus.wordpress.com/2010/01/27/staal-vs-
aluminium-vs-carbon/).

Carbon als framemateriaal, internet, Bongers Bikes,
(http://www.bongersbikes.nl/framebouw/carbon-als-framemateriaal).

Carbon molecule, internet, Math and Science Activity Center,
(http://www.edinformatics.com/math_science/carbon.htm).

Corrosiebestendige en slijtvaste oppervlaktelagen door oplassen en thermisch
spuiten, internet, Induteq.nl, (http://www.induteq.nl/metaal-
werktuigbouw/bestanden/VM108%20Corrosiebestendige%20en%20slijtvaste
%20opppervlaktelagen.pdf).


Hoofdstuk 3
Lithium-ion-polymeer-accu, internet, Wikipedia,
(http://nl.wikipedia.org/wiki/Lithium-ion-polymeer-accu).

Internet, Aerobertics.be,
(http://www.aerobertics.be/products.php?searchString=3s+2400+mAH&searc
h=Search).

Internet, Aerobertics.be,
(http://www.aerobertics.be/productDetail.php?prod=8953&cat=11&brand=25
).
PUTMAN, R., De 10 geboden van Lipo-accus, internet, Indoor Flyers
Roeselare, (https://sites.google.com/site/indoorflyersroeselareifr/techniek/de-
10-geboden-van-de-LiPo).

Internet, Media.conrad.nl, (http://media.conrad.nl/informatie/img/LiPo-Lilo-
accupack.jpg).

Alles over Lipo Accus, laden en gebruik, internet, pkracing.nl,
(http://www.pkracing.nl/akkuLiPomenu.jsp).





Pagina 251


Internet, Rcuniverse.com,
(http://www.rcuniverse.com/magazine/reviews/1183/AMPD14_DischargeCurv
e.jpg).

Internet, Aerobertics.be,
(http://www.aerobertics.be/productDetail.php?prod=9014&cat=14&brand=12
1).

Internet, Modelbouwforum.nl, 5 augustus 2008,
(http://www.modelbouwforum.nl/forums/model-elektronica/63080-verschil-
tussen-opto-en-bec-bij-esc.html).

Voordelen van een borstelloze DC Motor, internet, Micomdoor,
(http://www.micomdoor.be/Prod_MI50_nl.html).

Internet, Aerobertics.be,
(http://aerobertics.be/productDetail.php?prod=8802&cat=2&brand=44).

Internet, Aerobertics, be,
(http://aerobertics.be/productDetail.php?prod=8802&cat=2&brand=44).

Brushless Motor, internet, Modelbouw.nl,
(http://www.modelbouw.nl/wiki/brushless-motor#.UuFTI8IVGUk).

Borstelloze motoren en regelaars uitgelegd, internet, pkracing.nl,
(http://www.pkracing.nl/brushles_uitleg.jsp).

Wetenswaardigheden > Brushless motoren, Vermogen, Props, internet,
Vliegtuig Modelbouw Club Rheden, (http://www.vmcr.nl/wetens/index.htm).

File Angle of attack, internet, Wikimedia,
(http://commons.wikimedia.org/wiki/File:Angle_of_attack.png).

Vleugel (vliegtuig), internet, Wikipedia,
(http://nl.wikipedia.org/wiki/Vliegtuigvleugel#Invalshoek).

File Luchtstroom vliegtuigvleugel internet, Wikimedia,
(http://commons.wikimedia.org/wiki/File:Luchtstroom_vliegtuigvleugel.png).

Vleugel (vliegtuig), internet, Wikipedia,
(http://nl.wikipedia.org/wiki/Vliegtuigvleugel#De_aerodynamische_vorm).






Pagina 252


SCOTT, P., Wat is een BEC ? Wat is het verschil tussen een BEC en een UBEC
?, internet, translate. Google, 24 juli 2012,
(http://translate.google.be/translate?hl=nl&sl=en&u=http://flitetest.com/artic
les/What_is_a_BEC_What_is_the_difference_between_a_BEC_and_UBEC_&pr
ev=/search%3Fq%3Dverschil%2Btussen%2Bbec%2Ben%2Bubec%26biw%3D
1920%26bih%3D985).

Frequenties in Nederland, Belgi en wereldwijd, internet,
Modelbouwforum.nl, 25 mei 2011,
(http://www.modelbouwforum.nl/forums/%5Bfaq%5D-rc-techniek-en-
elektronica/21634-frequenties-nederland-belgi%EB-en-wereldwijd.html).

Internet, United Kingdom Radio Control Council,
(http://www.ukrcc.org/belgium.html).

Tips en info over modelbouw, internet, Thelittlewings.be,
(http://www.thelittlewings.be/Info/infopage.htm).


Hoofdstuk 4
Internet, api.ning.com, (http://api.ning.com/files/4*5ByqO6p6fl1A-
5uXSbAitAUuH5VGA*gezLVGDeZoWMvIacvHiGZ0VLlpK17Wb1RQRWiU3vRjX6e
sWFKwvvK1fzDjTgZXe-/Multiwii2.2stickconfigurationmode1.JPG).

Internet, Imageshack.us,
(http://img826.imageshack.us/img826/4347/og7v.jpg).

PID tuning theory and configuration guide for MultiWii, internet,
rcgroups.com,
(http://www.rcgroups.com/forums/showthread.php?t=1375728).

MultiWii Reflash, internet, Dans Website, 06 december 2012,
(http://logicalgenetics.com/multiwii-reflash/).


Hoofdstuk 5
Hoe installeer ik Led verlichting en hoe werkt het ?, internet, RJshop.nl,
(http://www.rjshop.nl/magazine/hoe-installeer-ik-led-verlichting-en-hoe-
werkt-het).
Internet, LEDSTRIPXL.nl, (https://www.ledstripxl.nl/product-informatie/5-
meter-RGB-LED-Strip-Compleet/LEDRGBW02/RGB-LED-Strip-60*led-5-meter-
Waterproof-inclusief-Adapter-en-Afstandsbediening-.html).
Internet, Quadrocoptershop.nl, (http://www.quadrocoptershop.nl/quadframe-
landingsgestel-155mm-v2).
Internet, Hobbyking.com,
(http://www.hobbyking.com/hobbyking/store/__6206__Carbon_Fiber_Landing
_Gear_120mm_1_Pair_.html).




Pagina 253


Hoofdstuk 6
Internet, Stichting Koningin Paola, (http://www.sk-fr-paola.be/nl).


Opdracht Engels
Internet, blog.oscarliang.net, (http://blog.oscarliang.net/build-a-quadcopter-
beginners-tutorial-1/).


Bijlagen
1. VAN BASTELAERE, L., Webwinkel Amazon test snelle bezorging
bestellingen, Het Laatste Nieuws, 03 december 2013.
2. STRAGIER, K., Vastgoedsite wil binnen de drie maanden onbemande
vliegtuigjes inzetten, Het Laatste Nieuws, 12 februari 2014.
3. KAV, Drone fotografeert elke woning voor vastgoedsite, Knack, 18
februari 2014.
4. Student krijgt dure drone cadeau, Metro, 08 mei 2014.
5. DELEPELEIRE, Y., Drones moeten peren redden van bacterievuur, De
Standaard, 21 maart 2014.
6. Rare dingen toch, die drones ?, Mobistar Newsletter, 14 april 2014.
7. Zo werkt onze drone, Het Nieuwsblad. Toepassing quadrocopter. De
Ronde van Vlaanderen volgen vanuit de lucht.
8. PEREZ, N., Gedachten laten quadrocopter opstijgen en rondvliegen,
Journal of Neural Engineering, 18 februari 2014.
9. KRAAIVANGER, C., Drone ontdekt 1000 jaar oud dorpje in Nieuw Mexico,
internet, scientias.nl, 13 mei 2014, (http://www.scientias.nl/drone-ontdekt-
1000-jaar-oud-dorpje-nieuw-mexico/100998).
16. SCHELDEMAN, L., (laurens.scheldeman@gmail.com), GIP Quadrocopter,
e-mail aan KRISTOF, (kristof@verbrugghemodelbouw.be),28 september 2013-
10 oktober 2013.
20. Circulaire CIR/GDF01, Federale Overheidsdienst Mobiliteit en Vervoer,
Directoraat-generaal Luchtvaart, 29 juli 2013.






Pagina 254


Nawoord

Dit jaar hebben we met ons project De quadrocopter veel bijgeleerd. Eerst
en vooral de voorbereiding. Er kwam echt veel opzoekwerk bij te pas. We
hebben gekeken op forums, internetsites en we zijn ook naar het KHBO te
Brugge gegaan. Van deze informatiebronnen zijn we veel wijzer geworden
over hoe een drone en een quadrocopter werken en in elkaar zitten.

Na het opzoekwerk zijn we begonnen met de technische tekeningen te
tekenen. We wisten ondertussen al ongeveer hoe groot we de drone wilden en
welke onderdelen we moesten tekenen. Op een paar boringen na zijn de
technische tekeningen nu nog altijd hetzelfde als in het begin.

Wanneer we de technische tekeningen gemaakt hadden besloten we om een
schaalmodel te maken in karton. Het zogenaamde kartonnen frame. Dit
hebben we zelf gemaakt omdat we zo visueel konden voorstellen hoe groot de
quadrocopter zou worden.

Nadien zijn we dan echt begonnen met de praktische realisatie. Hierbij hebben
we eerst en vooral carbon leren bewerken. Dit ging verassend goed ondanks
de vele voorspellingen van leerkrachten en kennissen. Die zijden ons dat
carbon een zeer moeilijk bewerkbaar materiaal is. De aluminium armen en
stand-offs hebben we op school laten maken. Wanneer het frame gemonteerd
was konden we over naar de volgende stap.

De volgende stap was het monteren van de onderdelen. Voordat we ze konden
monteren moesten we de juiste onderdelen uitkiezen. Omdat we nog geen
ervaring hadden met het maken van een drone zijn we naar Aerobertics
gegaan. Bert heeft ons daar goed geholpen door te helpen kiezen uit de juiste
onderdelen. Natuurlijk wisten we zelf ook al op voorhand wat we precies
allemaal nodig hadden. Door ons te wijzen op sommige kleine details zijn we
zeer tevreden over Aerobertics.

Na het aankopen hebben we de onderdelen op onze quadrocopter
gemonteerd. Dat ging zeer vlot. De motoren waren iets moeilijker te
bevestigen maar uiteindelijk kwam dit ook tot een goed einde na wat geduld.
Hierna kwam het programmeren. Ondanks dat we het programma niet zelf
geschreven hebben, maar een standaardprogramma voor multicopters hebben
gebruikt, hebben we toch veel tijd nodig gehad om het programma helemaal
op punt te zetten. Het open source porgram was niet perfect en kwam niet
helemaal overeen met ons geheugenbordje. De hoofdzakelijke problemen
zaten bij de orintatie van de sensoren en de verschillende manieren om de
sensoren hun waarden te laten inlezen. Na enige doorzetting zijn we er dan
toch nog in geslaagd om dit tot een goed einde te brengen.





Pagina 255


Wanneer het programma op het geheugenbordje stond hadden we een eerste
keer kortsluiting. Dit kwam doordat we hier een montagefout gemaakt
hadden. Daardoor hadden we het bordje aan twee kanten gevoed. Nadien
hadden we een tweede keer kortsluiting. Dit kwam doordat er een stekkertje
niet goed gesoleerd was. We dachten dat dit kwam wegens een voorgaande
testvlucht met een kleine crash tot gevolg. Hier waren er enkele propellers
kapot.

Als het programmeren gedaan was hadden we nog tijd voor enkele extras
want onze quadrocopter was dan in feite af. Zo hebben we nog een mooi
landingsgestel en enkele kleurrijke ledlampjes aangebracht. We hebben ons
ook ingeschreven voor de koningin Paola wedstrijd Focus Aarde. Hiermee
hopen we hoog te eindigen in de eindrondes.

Onze quadrocopter vliegt nu veiligheidshalve aan twee touwtjes. Na onze
lichte crash wouden we het niet riskeren om een zwaardere crash mee te
maken. Het geheugenbordje had een kapotte sensor. Dit komt door de tweede
kortsluiting. Wanneer we dan het derde bordje erop monteerde, zagen we dat
alles werkte zoals het hoort.

Naast dit praktische gedeelte is er natuurlijk ook een theoretisch deel. Ook
hieruit hebben we veel bijgeleerd. Zo weten we nu bijvoorbeeld hoe een Lipo
batterij en een DC motor werken. Ook over de liftkracht bij de propellers
weten we nu veel bij.

Dit project leerde ons niet alleen om een quadrocopter te maken en een GIP-
boek te schrijven. We hebben ook leren plannen, leren samenwerken en leren
geduld hebben op onderdelen die besteld zijn. Ook problemen efficint leren
aanpakken en oplossen behoren tot de dingen dat we hier hebben bijgeleerd.
We zijn er alle twee van overtuigd dat dit een toffe en leerrijke ervaring was
doorheen ons zesde jaar industrile wetenschappen. We raden dan ook
iedereen aan om in de toekomst zelf zo een drone te maken.

Tot slot willen we nog heel even iedereen bedanken die ons geholpen heeft
met dit project en we besluiten dan ook dat we allebei zeer tevreden zijn. We
hebben zeker geen spijt van onze keuze om een quadrocopter te bouwen.

You might also like