Cercetari teoretice si aplicative privind realizarea unui quadcopter Coordonator stiintific : S.L. Dr. Ing. Besnea Daniel Absolvent Lupu Stefan -… [306184]
Universitatea POLITEHNICA din Bucuresti
Facultatea de Inginerie Mecanica si Mecatronica
Departamentul Mecanica de Precizie si Mecatronica
LUCRARE DE LICENTA
Cercetari teoretice si aplicative privind realizarea unui quadcopter
Coordonator stiintific : S.L. Dr. Ing. Besnea Daniel
Absolvent: [anonimizat]
2018-2019
Cap. 1 – [anonimizat] s-a dezvoltat considerabil pe plan mondial si i [anonimizat] a informatiilor din mediul extern.
Tema acestei lucrari se bazeaza pe o aplicatie de tip UAV ( unmanned aircraft vehicle ), [anonimizat] a sistemelor de supraveghere video de la sol .
[anonimizat], elementele constructive ale acesteia; se va realiza o tehnologie de executie cu calcule si se va proiecta aplicatia 3D pentru a se putea realiza simularea corespunzatoare inainte de introducerea in functiune a aplicatiei . In etapa finala o sa se construiasca aplicatia pe baza componentelor achizitionate si se va face o [anonimizat].
Scopul final al lucrarii este acela de a mentine platforma stabila in mediul aerian urmand sa poata efectua operatiile necesare proiectarii ei: detectarea, urmarirea, recuperarea si culegerea de informatii din mediul extern.
Cap. 2 – Stadiul actual al cunoasterii in domeniul sistemelor aeriene fara pilot uman
2.1 Generalitati
Drona este un dispozitiv de tip UAV (Unmanned Aerial Vehicle) capabil sa zboare fara sa fie pilotat de o persoana, care a fost folosit initial doar in scopuri militare pentru recunoasterea unor obiective si bombardarea unor tinte strategice.
La fel cum s-a [anonimizat] a [anonimizat], au ajuns sa fie produse si in scopuri comerciale. [anonimizat] a [anonimizat] o noua “jucarie” [anonimizat].
[anonimizat], [anonimizat] o gama diversificata de persoane.
Dronele civile sunt controlate wireless prin intermediul unei telecomenzi sau a [anonimizat], [anonimizat].
UAV-[anonimizat]:
Fotografie si inregistrari video;
Geomapping;
Agricultura;
Networking;
Monitorizarea schimbarilor climatice;
Constructii etc.
2.2 Evolutia sistemelor aeriene fara pilot uman
Pentru a [anonimizat], trebuie sa aruncam o privire asupra istoricului . [anonimizat] a [anonimizat] a fi si astazi. [anonimizat].
Inventia zborului fara pilot uman a fost utilizata incepand cu anul 1849 cand baloanele incarcate cu bombe au fost folosite de catre armata austriaca in timpul unui atac asupra Venetiei. Totusi, daca e sa ne rezumam la o abordare mai conventionala, prima lupta a unui aparat de zbor fara pilot uman nu dateaza mai devreme de perioada anilor 1890, cand Otto Lilienthal, un pionier al aviatiei germane a experimentat cu planoare fara echipaj uman pentru a testa modelele de zbor usoare, cu aripi fixe. Acesta dorea ca aparatele sale sa fie functionale pentru a se putea introduce in mediul aerian cu scopul evitarii accidentarii bravilor piloti. Rezultatul a fost unul pozitiv.
Pierpont Langley a experimentat aparate de zbor cu motor cu aburi. Interesant este faptul ca experimentele sale foloseau un sistem de catapultare. Aparatul lui Langley denumit “ Aerodrom ” a reusit sa zboare ceva mai putin de o mila de-a lungul raului Potomac in cadrul unui proiect mai larg privind un avion cu echipaj uman. Desi proiectul a fost ulterior abandonat, zborul de testare a ramas intiparit in istoria aviatiei, intrucat a fost primul zbor de succes pe distanta lunga folosindu-se un aparat de zbor autopropulsat. Evenimentul se intampla cu mai multi ani inaintea faimosului zbor al fratilor Wright.
Fig. 2.2.a: Aerodromul lui P.Langley care a intreprins cu success primul zbor din lume pe distanta lunga al unui aparat de zbor fara pilot actionat de un motor. A fost lansat prin catapultare in 1896 si a zburat aproape o mila peste raul Potomac,Virginia,SUA. A fost actionat de un motor cu aburi cu un singur cilindru care punea in miscare 2 elici propulsoare prin transmisie cu roti dintate.
Zborul istoric al fratilor Wright a aratat omenirii ca zborul controlat putea fi realizat utilizand aripi din panza intinsa pe o rama pentru a coordona ruliul (miscare alternativa de inclinare a unei nave sau a unei aeronave in jurul axei sale longitudinale ) aparatului de zbor, si aceasta realizare a avut un puternic impact in dezvoltarea tehnica din industria aviatica. Succesul fratilor Wright a constituit catalizatorul care a modelat stiinta aviatica in ceea ce este ea astazi.
Nu mult timp dupa aceea, Lawrence Sperry cunoscut ca si “ bunicul pilotului automat ” a folosit giroscopul pe care compania familiei sale il inventase pentru a construi primii piloti automati care sa ii ajute pe piloti sa isi controleze avioanele, reducand in mare masura munca pilotului uman.
Mai tarziu se remarca profesorul Archibald Low care a dezvoltat sistemele de ghidare prin radio pentru a controla avionele de la distanta, culminand cu controlul de la distanta al zborului Ruston Proctor AT ( tinta aeriana ) in 1917. Trebuie de asemenea notat ca Nikola Tesla demonstrase deja capacitatea de a controla de la distanta o ambarcatiune cu multi ani mai inainte, in 1898.
In anul 1922 este momentul in care primul aparat de zbor de tip quadcopter a zburat cu succes. Cunoscut sub denumirea de “ Elicopterul De Bothezat “, a folosit rotoare dispuse intr-o structura de forma X. S-au efectuat aproximativ 100 de zboruri si s-a atins o altitudine maxima de 5m. Totusi, proiectul nu a continuat, deoarece necesita complexitati mecanice.
Fig. 2.2.b: Elicopterul proiectat de Gheorghe De Bothezat, coborand pe campul McCook dupa ce a ramas in aer timp de 2 minute si 45 secunde
La scurt timp s-au adus imbunatatiri minore si s-au fabricat 12.000 de asemenea aparate. Chiar si in prezent, aceste constructii raman o utilizare militara majora fiind dezvoltate si mult mai autonome.
Exemple de drone precum TDR-1 sau faimosul B-17 au fost utilizate in Al Doilea Razboi Mondial pentru a putea livra bombe pe teritoriul inamic, aparatul de zbor fiind manevrat de la sol.
Aceste constructii se remarca si in anul 1960 cand Compania Ryan Aeronautics din California producea dronele-tinta aeriene, si care se fabrica si in prezent. Acestea au avut ca si scop supravegherea, recunoasterea si evaluarea distrugerilor rezultate in urma unei batalii.
In cele din urma se ajunge si in anul 2003 cand acestea incep sa fie construite si utilizate de civili in scopuri personale, urmand sa se aduca imbunatatiri pe partea hardware si a design-ului.
Putin mai tarziu, in anul 2009 a inceput proiectul de pilot automat ArduPilot al carui scop a fost sa faca drone mai accesibile maselor. Initial s-au bazat pe platforma electronica Arduino si au utilizat baterii termoelectrice pentru a mentine aparatul de zbor stabil, urmand ca mai apoi ArduPilot sa utilizeze senzori automati, cum ar fi accelerometer, giroscoape si intr-un final sa fie primii pe piata mondiala care sa controleze si sa distribuie toate vehiculele fara echipaj uman, fie ca sunt aparate de zbor cu aripi fixe, multirotori, barci sau vehicule de teren.
2.3 Echipamente existente
Dronele sunt categorisite fie dupa configuratie, fie dupa forma. Configuratia poate fi impartita in 2 grupe: aripi fixe, configuratie care este similara cu cea a aeroplanelor simple, unde ridicarea este produsa de miscarea aripilor inainte prin aer si autogir, configuratie in care aripile ( rotoarele ) se invart pentru a produce ridicarea, precum in cazul unui elicopter.
2.3.1 Aripi fixe
Aparatul de zbor cu aripi fixe foloseste o sursa de propulsie ( de regula un motor electric sau o elice ) pentru a genera o forta ascensionala pe aripi care sa permita realizarea zborului.
Cand un astfel de aparat zboara, unghiul sau ( altitudinea de zbor ) se poate schimba de-alungul a 3 axe:
axa de inclinare laterala ( tagaj Y-Y ), ceea ce presupune ca aparatul se misca in sus sau in jos;
axa verticala sau de viraj ( giratie Z-Z ), care se refera la schimbarea directiei aparatului de zbor ;
axa longitudinala ( ruliu X-X ), care implica balansarea aparatului de zbor la stanga si la dreapta.
Fig. 2.3.1.a: cele 3 axe ale unui aparat de zbor
Pentru a controla un aparat de zbor cu aripi fixe, aripile si sectiunea cozii dispun de niste arii mici ca niste flaps-uri, numite suprafete de control.
Exista 3 suprafete de control:
eleronii, care controleaza ruliul aparatului de zbor;
carma sau directia care controleaza deviatia de la drum;
profundorii care controleaza inclinarea longitudinala.
Fig. 2.3.1.b: cele 3 suprafete de control ale unui aparat de zbor
Indiferent de aranjamentul aripilor unui aparat de zbor, drone sau aripi fixe, un alt criteriu de clasificare a proiectului este locul de amplasare al motorului. Cel mai adesea, motoarele sunt localizate in partea stanga a aparatului de zbor, si astfel sunt clasificate dupa configuratie ca “ propulsori ” – motorul impinge aparatul de zbor inainte. Configuratiile motoarelor propulsoare sunt:
Configuratiile motoarelor care trag ( sau “ tractori ” ) au motorul montat cu elicea in fata de unde trage dupa sine aparatul de zbor inainte. Aceasta este o configuratie mai conventionala care poate fi mai eficienta decat cea cu propulsori, deoarece curentul de aer care loveste elicea nu este perturbat de corpul aparatului de zbor. Cu toate acestea, pentru ca elicea este de obicei montata in fata oricarei camere care se afla la bord, se poate crea o situatie neplacuta din cauza efectului “ rolling shutter ” ( distorsiune cauzata de metoda de fotografiere “ obturator oscilant ” ), care face ca imaginea sa apara in fotografie ca un model liniar ciudat. Cu toate acestea, pentru camerele orientate in jos ( ca cele de la UAV-urile folosite pentru cartografiere ), aceasta nu este o problema.
2.3.2 Aripi zburatoare
Aripile zburatoare ( avion tip “ numai aripa ” ) sunt platforme de drone destul de populare, deoarece ele au putine componente si sunt mai usor de transportat. Sunt de asemenea mai eficiente si pot inainta prin curentii de aer mai usor decat alte platforme de drone.
O aripa zburatoare are 2 suprafete de control, asa ca are nevoie de doar 2 servomecanisme, in comparatie cu aparatele de zbor mai conventionale care au nevoie de 4. Suprafetele de control de pe aripile zburatoare se numesc elevoini, deoarece combina atat functiile unui elevator ( inclina longitudinal aeroplanul in sus si in jos ) cat si pe cele ale unui eleron ( misca aparatul de zbor la stanga si la dreapta ).
Aparatul de control al zborului trebuie sa stie sa actioneze atat cat trebuie pentru ca fiecare suprafata de control sa se miste corespunzator pentru a indeplini actiunea dorita.
Aripile zburatoare sunt excelente pentru drone, deoarece ramane foarte mult spatiu pentru a monta tot echipamentul iar motoarele si elicile sunt amplasate in spate in afara campului de luat vederi al camerei.
Principalul lor defect este totusi faptul ca centrul de greutate este mai sensibil decat la alte configuratii si aparate de zbor.
Fig. 2.3.2: aparat de zbor cu aripi zburatoare ( Sursa imagine: Compania A.F.T Design S.R.L )
2.3.3 Aparate de zbor cu rotor
Termenul aparate de zbor cu rotor se utilizeaza pentru a defini aparatul de zbor prevazut cu un rotor care se invarte in aer si care genereaza suficienta forta de ascensiune pentru ca aparatul sa poata zbura.
Acestea se clasifica in doua categorii principale :
Elicoptere conventionale
Multicoptere
Multicopterele se clasifica in functie de numarul de motoare pe care le utilizeaza aparatul – de exemplu, in cadrul acestui proiect, quadcopterul care are 4 motoare.
Elicoptere conventionale
Acestea sunt capabile sa asigure controlul prin schimbarea inclinatiei longitudinale si a unghiului paletelor de rotor. La baza este un mecanism complex numit disc pendular. Majoritatea elicopterelor utilizeaza un singur disc pendular mare care creeaza un efort de torsiune in directia opusa rotatiei. De aceea rotorul de pe coada aparatului este necesar pentru a echilibra devierea de la directia de deplasare si a mentine elicopterul pe traiectoria corecta. Acest lucru este in consecinta considerat ca fiind un punct slab care face proiectul usor ineficient, deoarece o parte din energie este folosita pur si simplu pentru a mentine elicopterul pe aceeasi directie in loc sa contribuie la generarea ascensiunii.
Principalul dezavantaj al elicopterelor conventionale este acela ca sunt mai periculoase din cauza lamelelor rotoarelor mai largi si mai grele. Mai mult decat atat, complexitatea lor inseamna ca sunt de obicei mai fragile intr-un accident decat platformele dronelor obisnuite precum quadcopterele. Cu toate aceste au avantaje multiple cum ar fi gradul mare de stabilitate in conditiile de vant, comparativ cu multicopterele .
Fig. 2.3.3.a : elicopter conventional,aparat de zbor cu rotor
Multicoptere
Clasificare:
Tricopter
Quadcopter forma +
Quadcopter forma X
Hexacopter +
Hexacopter X
Y6 copter
X8 copter
In mod tipic, denumirea conventionala pentru copterele multirotor urmareste sistemul latin de numerotare astfel “ tri ” denota trei motoare, “ quad ” denota patru , “ hexa ” denota sase si asa mai departe urmand de sufixul “ –copter ”.
Tricopter
Tricopterul utilizeaza 3 motoare dispuse intr-o configuratie triunghiulara, cu unul in spate si doua in fata. Bratele unui elicopter sunt in mod tipic separate la 120°, ceea ce este un avantaj atunci cand folosim o camera montata la bord, deoarece acest unghi larg de separare inseamna ca bratele si elicele vor sta departe de campul de luat vederi al camerei.
Un alt beneficiu consta in faptul ca, deoarece tricopterele utilizeaza trei motoare sunt mai ieftin de construit, desi pentru a controla in totalitate elicopterul, motorul din spate trebuie sa se balanseze lateral pentru a roti aparatul la stanga si la dreapta ( viraj ). Acest lucru inseamna, de asemenea ca tricopterele pot schimba directia mult mai repede decat alte configuratii, cum ar fi quadcopterele.
Fig. 2.3.3.b: tricopter
Totusi, constructia tricopterelor se dovedeste a fi mai complexa, din cauza mecanismului de deviere a directiei de deplasare care trebuie sa balanseze motorul din spate, ceea ce are cel putin avantajul ca garanteaza un zbor lin, lucru benefic pentru situatiile in care utilizam drone pentru filmari.
Quadcopter
Quadcopterele, care sunt cel mai obisnuit tip de drone mulltirotor, au patru motoare aranjate simetric in configuratie “ + ” sau “ X ”. Intr-un aranjament +, partea din fata a quadcopterului este aliniata direct cu un motor. Intr-un aranjament X , partea din fata a quadcopterului este directionat intre cele doua motoare frontale. Aceasta ultima configuratie este mai utila si mai obisnuita, deoarece presupune ca bratele si elicele obtureaza mai putin campul vizual al unei camere de luat vederi de la bord care este orientata spre a lua vederi din fata.
Din cele patru motoare ale unui quadcopter, doua se invartesc in sensul acelor de ceas si celelalte doua se invartesc in sens opus acelor de ceas. Aceasta va compensa efortul de torsiune creat de motoare si va mentine quadcopterul cu fata catre directia corecta ( indeplineste astfel aceeasi functie ca rotorul de pe coada in cazul elicopterului traditional ).
Pentru a controla quadcopterul, vitezele motoarelor sunt variante – de exemplu, pentru a balansa quadcopterul inainte, cele doua motoare frontale incetinesc, in timpul in care cele doua motoare din spate accelereaza.
Principalul avantaj este acela ca sunt aparate usor de construit si de controlat.
Fig. 2.3.3.c: quadcopter
Hexacopter
In afara de faptul evident ca avand sase motoare pot ridica mai mult echipament , un beneficiu aditional este acela ca, datorita faptului ca motoarele sunt spatiate la o distanta mai mica in jurul centrului, daca un motor cedeaza, hexacopterul poate, de regula, sa ramana stabil, utilizand restul motoarelor si poate astfel sa aterizeze in siguranta. Daca un motor cedeaza la un tricopter sau quadcopter aterizarea se face in conditii eronate, deoarece fiecare motor este critic in mentinerea stabilitatii dronei. Din aceasta cauza, numeroase drone utilizate pentru fotografii aeriene profesionale au o configuratie fie de hexacopter, fie de octocopter, avand in vedere ca patru motoare ofera mai multa siguranta si pot transporta o greutate mai mare.
Fig. 2.3.3.d: hexacopter
Y6 copterele
Configuratia Y6 este un mix de tricopter si hexacopter. Are sase motoare pe trei brate, aranjate exact ca la tricopter, cu doua brate in fata spatiate intre ele la 120° si un singur brat in spate. Totusi, desi Y6 copterele au sase motoare in total, ele sunt considerate ca fiind hexacoptere. Fiecare brat are doua motoare montate pe el, unul cu fata in sus si celalalt cu fata in jos. Acest aranjament este cunoscut sub denumirea de aranjament coaxial de motoare. In mod tipic, fiecare motor se va roti intr-o directie opusa.
Ca si avantaje, acestea se ansambleaza si se realizeaza mai usor comparativ cu hexacopterele obisnuite. De asemenea, bratele au o greutate mai redusa iar motoarele prezinta o mare redundanta datorita modului in care au fost montate, fiecare pereche de motor actionand pe aceeasi axa de presiune. Daca se intampla ca un motor sa cedeze, configuratia Y6 abia daca va inregistra vreo diferenta, alta decat o usoara scadere de o sesame a fortei de presiune.
Singurul mic dezavantaj al cadrelor Y6 este ca exista o pierdere marginala de eficienta ( doar in jur de 5% ) din cauza motoarelor din partea de jos, care functioneaza in aerul turbulent ejectat in jos de catre motoarele de sus. Cu toate acestea, aceasta reducere de eficienta este compensata de catre greutatea mai mica a ramei ( doar trei brate in comparativ cu sase ), astfel ca acest efect se considera neglijabil.
Fig. 2.3.3.d: Y6 copter
Octocopter
Acesta este un aparat cu 8 motoare cu acelasi spatiu egal intre ele. Acestea sunt dintre cele mai mari multicoptere, un aparat de zbor tipic avand un diametru de 1m. Ca si in cazul hexacopterelor, cresterea numarului de motoare inseamna ca octocopterele pot purta sarcini utile mai grele si prezinta extra redundanta de motor. In timp ce un hexacopter poate de obicei doar sa supravietuiasca in urma cedarii unui singur motor ( sau probabil doua daca sunt asezate in parti opuse unul fata de celalalt ), un octocopter poate sa suporte mai multe cedari de motor fara sa se prabuseasca – in functie de sarcina utila si de care motor cedeaza.
Octocopterele sunt folosite de obicei, ca drone profesionale de filmat datorita capacitatii lor de a purta sarcina utila si datorita redundantei unghiului de deriva al motorului, deoarece unele camere profesionale pentru filmari costa mai mult decat majoritatea masinilor si sunt foarte grele.
X8 copter
Configuratia X8 este de fapt, o rama de quadcopter cu opt motoare, o combinatie de quadcopter si octocopter. Ramele X8 au patru brate cu doua motoare fiecare, unul fiind orientat in sus, iar celalalt in jos. Copterele X8 au aceleasi avantaje ca octocopterele, principala lor caracteristica fiind capacitatea de a ridica sarcini utile grele. Exact ca si configuratia Y6, X8 are de asemenea avantajul de a avea doua motoare plasate de-a lungul aceleasi axe de presiune, asa ca este chiar mai stabil in cazul in care un motor cedeaza in timpul zborului ( presupunand ca celelalte sapte produc suficienta forta de propulsie pentru a mentine dronele in aer ).
Fig.2.3.3.e: X8 copter
X8 copter – Unicopter
Acestea nu reprezinta o clasificare oficiala, dar exista foarte multe cazuri de coptere neobisnuite care au un singur motor. Acestea folosesc o singura elice care se roteste pentru a produce forta de propulsie si sunt controlate prin mici flapsuri aflate sub elicea care manipuleaza curentul de aer pentru a permite dronei sa se roteasca sau sa mearga inainte, etc. Aceste tipuri pot fi considerate asemanatoare cu elicopterele conventionale, deoarece folosesc un rotor principal pentru a genera ascensiunea.
Avantajul principal consta in aceea ca e mai simplu din punct de vedere mecanic, deoarece lamelele principalului rotor sunt fixe si micile flapsuri de sub lamela sunt folosite pentru a controla drona. Mai mult, deoarece paleta este de asemenea ingradita de un tub, elicele sunt putin mai eficiente in comparatie cu lamelele rotorului de aceeasi marime dintr-un elicopter ( deoarece tubul reduce pierderile de forta de propulsie la marginile lamelelor din motive aerodinamice ).
Un alt aspect important al tubului in termeni de siguranta, este ca impiedica lamelele, care se rotesc repede si care sunt astfel periculoase de a rani pe cineva; de asemenea, protejeaza impotriva prafului si mizeriei care pot patrunde inauntru. Cu toate acestea, tubul prezinta un mare inconvenient, si anume instabilitatea la conditiile de vant. Din cauza ariei lor frontale mari, dronele unicopter sunt foarte susceptibile de a fi impinse dintr-o parte in alta de rafale de vant, ceea ce inseamna ca nu pot fi folosite cand vantul e foarte puternic. De asemenea, deoarece motoarele/lamelele se afla in mijlocul dronei, acest lucru limiteaza spatial disponibil in care echipamentul poate fi montat.
X8 copter – Bicopter
Bicopterele au doua motoare si, desi nu sunt foarte folosite din cauza prolemelor de stabilitate, dar cu toate acestea, au un design placut ( asemanator cu aparatul de zbor Pandora Warrior din filmul avatar ).
Fig. 2.3.3.f: bicopter ( Sursa imagine Pandora Warrior : www.fpvguy.com )
Bicopterele sunt mai folosite pentru constructiile tip hybrid ( tiltrotor ) care se va transforma intr-un aparat de zbor cu aripi fixe si directive de deplasare in fata ( precum Boeing V22 Osprey care poate decola si ateriza ca un elicopter ), dar care pentru a zbura pe distante mai lungi, isi va bascula rotoarele inainte si se va transforma intr-un aparat de zbor cu aripi fixe.
Fig. 2.3.3.g: bicopter tip hybrid ( Sursa imagine Boeing V22 Osprey: wikipedia )
Aceste modele de drone sunt construite in special pentru misiuni militare.
X8 copter – Mai mult de opt motoare
Pe piata industriei exista si X8 copter cu 18 motoare ! Acestea sunt construite pentru a putea fi folosite la ridicarea unor greutati mari sau pur si simplu pentru proiecte distractive. Oricate motoare ar avea o astfel de drona, se va tine seama ca trebuie sa fie un numar par de motoare pentru o stabilitate cat mai buna.
2.4 Probleme privind stabilitatea sistemelor aeriene fara pilot uman
In cadrul temei abordate si conform simularilor efectuate, s-a depistat o prima problema privind stabilitatea quadcopter-ului in aer, si anume: calibrarea celor patru esc-uri ( reductoare de turatie ) din software-ul CLEANFLIGHT-Configurator bazat pe Arduino. O calibrare incorecta a condus la oprirea brusca a unuia dintre motoare in timpul zborului, efectul fiind acela de prabusire a sistemului aerian fara pilot uman.
O alta problema care are acelasi efect final ca si cel anterior, o reprezinta calibrarea incorecta a celor patru motoare fara perii. Rezultatul fiind oprirea brusca a motorului dupa cinci secunde de zbor sau functionarea intrerupta a acestuia.
Urmatoarea problema se refera la modul de pilotare care este destul de dificil, si anume: comanda de stanga efectuata de catre radio comanda este de fapt comanda de dreapta, iar dreapta este stanga. Indiferent de constructie, aceasta ordine este valabila pentru toate aparatele de zbor fara pilot uman, iar o manevrare neconforma duce la o stabilitate scazuta a aparatului in aer avand ca rezultat final, prabusirea sau lovirea de anumite obiecte contondente.
Datorita puterii unui singur motor, elicea poate atinge 8310 rot/min ceea ce inseamna un nivel mediu de pericol pentru persoanele din jur. Propulsoarele nu au o carcasa exterioara si tocmai de aceea este necesara montarea lor cu o foarte mare rigurozitate, altfel urmarile pot fii asemanatoare ca cele din fig. 2.4.a, sau mult mai grave.
Daca turatia este combinata si cu o anumita distanta, efectul poate fii unul destul de sever !
Fig. 2.4.a: rana cauzata de calibrarea incorecte a elicei
De asemenea, toate acestea nu pot fii posibile daca alimentarea nu se efectueaza. Prin urmare, trebuie sa se asigure alimentarea acumulatorului inainte de pornirea si punerea in functiune a aparatului de zbor. Nu trebuie neglijata aceasta etapa si in niciun caz nu este permisa incarcarea incompleta a acumulatorului, deoarece pot aparea probleme in timpul zborului si anume: oprirea brusca a alimentarii catre motoare mai devreme decat era prevazut, distribuirea energiei inegala catre cele patru motoare, aterizare neprevazuta, erori la bordul placutei de control, etc.
O alta problema substantiala este reprezentata de conectarea controller-ului de zbor la software-ul CLEANFLIGHT de configurare si calibrare. Pasii sunt destul de simpli:
Se conecteaza controllerul de zbor la calculator prin usb si micro-usb;
Apoi se instaleaza driver-ul controllerului de zbor;
Se instaleaza extensia CLEANFLIGHT din magazinul web chrome;
Dupa care urmeaza partea in care trebuie sa incarcam Firmware-ul si sa ii dam Flash ( exceptie de la regula pentru prima configurare, care nu necesita reset manual ).
Acesti pasi sunt descrisi in amanunt la capitolul 6 din acest proiect !
Iar aici intervine eroarea, deoarece controllerului de zbor trebuie sa ii dam un reset manual inainte de optiunea “flash” din programul de configurare “cleanflight” , si anume, trebuie sa utilizam o penseta pentru a face un scurt-circuit intre pinii de reset de pe controller, iar daca la final nu obtinem un rezultat pozitiv ( doar led-ul albastru ramane aprins ), trebuie sa repetam operatiunea de 2,3,4 … n ori pana reusim .
Fig. 2.4.b: pinii de reset ai placutei principale
O ultima problema este reprezentata de montarea si/sau configurarea incorecta a GPS-ului, deoarece fara acesta, quadcopterul nu isi poate calibra coordonatele pozitionarii in aer, iar rezultatul final este o manevrare mai dificila decat cea dorita.
Cap. 3 – Prezentarea solutiei proprii si modul de comanda
Principiul de functionare
Quadcopterul este alcatuit din doua tije perpendiculare la capatul carora se afla motoarele. In zona centrala este situata placa de baza impreuna cu restul componentelor electronice si bateria. Elicele, patru la numar sunt pozitionate fiecare deasupra celor patru motoare, iar rotirea acestora genereaza forta de impingere. In acelasi timp, aerul opune rezistenta acestei miscari de rotire, generand o forta in directia opusa directiei de rotatie a elicei. Motoarele aflate pe axe diferite se rotesc in directii opuse pentru a contracara acest efect. Urmarea este ca, daca vitezele de rotatie ale celor patru elice sunt egale, fortele aparute in urma frecarii cu aerul se anuleaza reciproc.
Configuratia quadcopterului din acest proiect este de forma literei X .
3.2 Alegerea cadrului
Cel mai important lucru in construirea unui aparat de zbor fara pilot uman este rama multimotor, unde ulterior pe aceasta vom atasa restul de componente. Aceasta rama avand in componenta ei bratele atasate, care reprezinta de fapt cadrul ce se poate confectiona din materiale plastice, poliamida, nylon sau diferite materiale usoare, dar totusi rezistente pentru a sustine greutatea componentelor ce urmeaza a fi atasate. Cadrul se poate realiza ori pe masini cu comanda numerica ( CNC ) utilizand operatia de frezare ori pe imprimante 3D.
Cadrul ales si folosit de mine este alcatuit din rama centrala din fibra de sticla si patru brate din nylon-poliamida. Operatia de confectionare a intreg cadrului a fost de frezare si finisare pe CNC cu 5 axe.
Fig. 3.2: cadrul Q450
3.3 Alegerea motoarelor brushless
Scopul motoarelor electrice este de a converti energia electrica in energie mecanica sub forma miscarii de rotatie. Aceste sisteme electromecanice sunt caracterizate de anumiti parametrii care ajuta la prezicerea performantelor motorului. Viteza in absenta sarcinii descrie viteza motorului cand nu este cuplul aplicat, iar viteza de mers in gol descrie momentul de cuplu maxim al motorului cand viteza acestuia este de 0 RPM ( rotatii pe minut ). Alti parametrii de interes sunt cuplul, curentul si tensiunea de alimentare a motorului. Modul de functionare al acestor motoare este simplu, cuplul fiind creat de forta de magnetism aparuta intre magnetii stationari si electromagnetii alimentati astfel incat, polaritatea dintre cele doua componente sa fie mereu inversa. Motoarele brushed, desi au avantajul unui pret mai mic, au electromagnetii plasati pe rotor si magnetii ficsi pe stator, de aceea sunt predispuse supraincalzirii, dar si uzuri din cauza comutatoarelor. La motoarele brushless, electromagnetii sunt plasati pe stator si magnetii stationari pe rotor. Polaritatea electromagnetilor este schimbata de data aceasta de un circuit de control care imbunatateste precizia motorului.
Fig.3.3.a: motor cu perii vs fara perii
Rpm= Kv * volt Factorul Kv este cel mai folosit pentru a descrie capacitatile unui motor. Dupa cum se observa, la aceeasi tensiune este proportional cu numarul de rotatii pe minut (RPM). Tipul de motor trebuie adaptat tipului de quadcopter dorit. O drona de mare performanta, acrobatica, va avea un motor de viteza mare. Pe de alta parte, un quadcopter folosit in zboruri lungi, trebuie sa consume cat mai putina energie, de aceea motoarele cu Rpm mic sunt de dorit in aceasta situatie.
Motorul cu perii are in rotor o bobina care este alimentata la o sursa de tensiune continua prin intermediul periilor de carbon. Statorul motorului contine un magnet permanent.
Motorul fara perii se mai numeste in industria de biciclete electrice si motor de curent continuu Brushless Trifazat.
Acest motor are bobinele din cupru plasate pe stator, iar rotorul sau contine o serie de magneti permanenti. Motorul este alimentat cu trei forme de unda diferite care genereaza in stator un camp magnetic.
Avantajele si dezavantajele motorului cu perii
Motorul cu perii disipa energie prin frecare si prin incalzire destul de mult;
Tot din cauza scanteilor de la perii se produce un factor de distorsiune a sistemului de alimentare prin reinjectarea de impulsuri parazite in sens invers ( de aceea mai cad controller-ele cu perii );
Pe deoparte este mai costisitor, pentru ca necesita intretinere ( schimbare perii ), pe de alta parte poate fi mai convenabil, pentru ca se poate prelungi viata lui prin aceasta intretinere;
Este mai avantajos de controlat, folosind doar doua fire, reglajul turatiei facandu-se in tensiune;
Viteza este limitata de forta de frecare ( cu cat avem viteza mai mare cu atat forta de frecare a periilor este mai mare ).
Avantajele si dezavantajele motorului fara perii
Lipsa de mentenanta constituie un avantaj;
Nu exista forta de frecare, ceea ce duce la obtinerea de cuplu si viteza mai mare, cat si o mai buna racire;
Un dezavantaj il constituie faptul ca, controlul lui se face intr-un mod mai complex, deci e nevoie de un controller neaparat;
Transmiterea semnalelor in bobine se face cu ajutorul senzorilor Hall care pot da erori daca se intrerup ( problema rezolvata cu ajutorul controllerelor universale );
Dimensiuni mai reduse si mai compacte, dar fara sa afecteze cuplul.
Datorita acestor avantaje si dezavantaje am ales patru motoare fara perii de la firma Turnigy de 1100KV ( rpm ), putere maxima 910W, curent maxim 50A, rezistenta interna 0.023Ohm, curent fara sarcina 3.1A, greutate 159g, diametru arbore 5mm.
Fig.3.3.b: turnigy motor D2836/8
Electronic speed control prescurtat si ESC ( reductoarele de turatie )
Un Electronic Speed Control ( ESC ) este un circuit ce indeplineste doua functii principale. Prima este de a actiona asemenea unui regulator de tensiune, reducand tensiunea furnizata de baterie pana la valoarea necesara functionarii motoarelor si microcontrollerelor. A doua functie este de a converti semnalul de la Hoverfly Open intr-un semnal de control pentru motorul brushless.
Spre deosebire de speed controllerele bazate pe rezistori, ESC-urile nu functioneaza aplicand motoarelor fractiuni din tensiunea de alimentare proportionale cu viteza pe care o dorim, ci aplicand intreaga tensiune, dar oprind-o si pornind-o extrem de rapid. In cazul celor aparute primele, diferenta de tensiune nefolosita pentru miscarea motorului ar fi fost irosita, fiind disipata sub forma de caldura. Variind raportul dintre timpii de „ON” ( tensiune maxima ) si „ OFF ” ( tensiune de 0V ), ESC-ul variaza de fapt tensiunea medie citita de motor. Cu alte cuvinte, la orice moment de timp, tensiunea de control este ori complet „ON” ori complet „OFF”. Aceasta face ca acest tip de control sa fie, cel putin teoretic, 100% eficient. In realitate totusi, ESC-urile sunt dispozitive imperfecte, eroarea acestora datorandu-se in principal timpului de comutare al tranzistoarelor folosite in circuit si rezistentelor interne. BEC ( Battery Eliminator Ciruit ) este circuitul ce reguleaza tensiunea furnizata de baterie. Este extrem de folositor in aplicatii de quadcopter, deoarece bateriile suplimentare ar creste greutatea dronei.
Fig.3.4.a: schema de principiu ESC
Am ales urmatoarele ESC-uri avand urmatoarele caracteristici principale si m-am asigurat sa fie compatibile cu motoarele alese la pasul anterior :
– Model: 20A XSC Micro Opto multi-rotor ESC
– Input Voltage: 3~4S (11.1~14.8V)
– Continuous Current: 20 amps
– Burst Current: 22 amps
– Cut Off Voltage: 9.9V (3S)/13.2V (4S)
– Frequency: 50Khz-5Mhz (CPU), signal 50hz
Fig.3.4.b: ESC dys – Motor Limit: 11000kv/rpm
ESC-urile nu functioneaza aplicand motoarelor fractiuni din tensiunea de alimentare proportionale cu viteza pe care o dorim, ci aplicand intreaga tensiune, dar oprind-o si pornind-o extrem de rapid. In cazul celor aparute primele, diferenta de tensiune nefolosita pentru miscarea motorului ar fi fost irosita, fiind disipata sub forma de caldura. Variind raportul dintre timpii de „ON” ( tensiune maxima ) si „OFF” ( tensiune de 0V ), ESC-ul variaza de fapt tensiunea medie citita de motor. Cu alte cuvinte, la orice moment de timp, tensiunea de control este ori complet „ON” ori complet „OFF”. Aceasta face ca acest tip de control sa fie, cel putin teoretic, 100% eficient. In realitate totusi, ESC-urile sunt dispozitive imperfecte, eroarea acestora datorandu-se in principal timpului de comutare al tranzistoarelor folosite in circuit si rezistentelor interne. BEC (Battery Eliminator Ciruit ) este circuitul ce reguleaza tensiunea furnizata de baterie. Este extrem de folositor in aplicatii de quadcopter, deoarece bateriile suplimentare ar creste greutatea dronei.
Alegerea controlerului de zbor
Am ales controlerul de zbor ”Flip32 All In One Pro v1.03” deoarece el contine un microcontroller puternic STM103 pentru procesare rapida, sursa de tensiune de 5V si 3A ce poate alimenta si ESC-urile de la motoare, ce suporta alimentare de pana la 6S, senzor de curent de maxim 90A ce poate monitoriza descarcarea acumulatorului, MinimOSD pentru a suprapune peste imaginea transmisa live, informatii despre datele de zbor, dar si un barometru MS5611 ce poate masura presiunea atmosferica si astfel sa mentina o altitudine constanta, cu o eroare cat mai mica.
Controller-ul de zbor este capabil sa se conecteze si la un GPS extern, astfel ca permite un zbor foarte stabil.
Fig.3.5: Flip32 All In One Pro v1.03
Caracteristici tehnice:
Microcontroller STM103 cu firmware Cleanflight
Numar maxim canale de iesire PWM: 8 – poate controla un octocopter
Barometru MS5611 ce ajuta la mentinerea altitudinii
Conexiune USB pentru configurare controller si OSD
Contine sursa de tensiune in comutatie de 5V, 3A (alimentare 2S – 6S)
Cerinte hardware compatibile cu MinimOSD/MWOSD/CC3D OSD
Senzor de curent (maxim 90A) si de tensiune (2S – 6S)
Chip pentru OSD cu consum mai redus de energie fata de variantele traditionale utilizate
Suporta SPPM si receptie seriala
Contina si o mica zona pentru distributia energiei
Masa: 17 grame .
Acest controler de zbor a fost realizat conform unui cod sursa scris in software-ul Arduino 1.8.8 si s-a anexat in detaliu la finalul acestui proiect la sectiunea “ ANEXA.Cod Sursa “ si de asemenea regasim la Cap.6 detaliile cu privire la configurarea setarilor acestei placute !
Alegerea bateriei LiPo – Turnigy 2200 mah
Bateriile LiPo ( prescurtare de la Litiu-Polimer ) sunt un tip de baterii reincarcabile ce au permis echipamentelor RC ( radio controlled ) sa prospere recent. Se poate considera ca aceste baterii sunt motivul pentru care zborul aparatelor electrice este o optiune viabila fata de modelele alimentate prin combustibili.
Motivele pentru care aceste baterii sunt atat de folosite sunt :
Greutatea mica si faptul pot avea orice forma sau marime;
Posibilitatea de a stoca multa energie intr-un pachet de mici dimensiuni;
Rata mare de descarcare pentru motoare electrice cu consum mare Bateriile LiPo nu folosesc o solutie electrolitica lichida ci un polimer electrolitic separator intre anodul si catodul bateriei, ce permite schimbul ionilor de litiu.
Am ales urmatorul tip de baterie:
Fig.3.6: acumulator turnigy 2.2
Caracteristici principale:
– Capacitate: 2200mAh
– Configuratie: 3S1P / 11.1v / 3Cell
Alegerea Gps-ului
• uBlox Neo-7M module
• 56-channel
• GPS L1 C/A, GLONASS L1 FDMA
• QZSS L1 C/A
• Galileo E1B/C
• SBAS: WAAS, EGNOS, MSAS
• 10Hz update rate
• 25x25x2 Ceramic patch antenna
• Rechargeable 3V Backup battery
• Low noise 3.3V regulator
• I2C EEPROM storage
• Power and fix LED’s
• Pedestal Mount/Case
• Pixhawk/PX4 compatible
• LNA MAX2659ELT+
• Pre-configured 38,400 Baud and prams
Fig.3.7: gps neo-7M
Alegerea propulsoarelor
Aceste propulsoare sunt proiectate special pentru a se potrivi cu motoarele DJI.
Diametrul elicei X :10.00 inch
Fig.3.8: propulsoare
Alegerea Radiocomenzii RC si a receptorului
Telecomanda entry-level cu 6 canale la o frecventa de 2.4GHz ce poate functiona si cu telemetrie. Telecomanda ideala pentru controlul multicopterelor. Din cele 6 canale, in mod normal 4 dintre ele vor fi folosite pentru comenzile referitoare la orientarea spatiala ( controlul inaltimii, controlul rotatiei fata de axa centrala si controlul pentru directionarea in planul dronei – inainte/inapoi, stanga/dreapta), iar restul de doua pot fi folosite pentru controlul modului de zbor (de exemplu, zbor simplu, asistat de GPS, Return-to-home, etc).\
Caracteristici tehnice:
Numar canale: 10 canale prin PPM sau 6 canale prin PWM;
Frecventa de transmisie: 2.408 ~ 2.475 GHz;
Latime de banda: 500 kHz;
Numar canale RF: 135;
Putere de transmisie: pana la 20dBm;
Sistem 2.4GHz AFHDS 2A;
Modulatie GFSK;
Rezolutie citire joystick-uri: 0 ~ 4095 (pe 12 biti);
Alarma pentru tensiune prea mica de alimentare (< 4.2V);
Port DSC MicroUSB sau PPM;
Tensiune de alimentare: 4.2V ~ 6V;
Lungime antena: 2 x 26 mm;
Certificate: CE0678, FCC ID: N4ZI6S00, RCM;
Functioneaza cu 4 baterii/acumulatori AA ce NU sunt incluse.
Fig.3.9.a: RadioComanda Turnigy tgy-i6S
Turnigy TGY-iA6C este un stil nou in receptoare. Se bazeaza pe fiabilitatea receptorului TGY-iA6B, dar este construit special pentru utilizarea cu configuratii PPM, i.BUS si S.BUS. Acesta este un plus excelent pentru transmitatoarele Turnigy TGY-i6, Turnigy Evolution sau Turnigy AFDHS 9x.
Antenele duale ofera iA6C o receptie fara precedent. Legaturile incorporate va permit sa utilizati senzorii optionali de telemetrie.
Un receptor excelent pentru telefoanele cu rotor multi-rotor, in timp ce se reduce la cablare si cu monitorizare integrata a bateriei.
Caracteristici:
Functie de semnal AFHDS 2A fiabila si fara interferente 2.4GHz
PPM, i.BUS, S.BUS
Design ultra-usor in greutate
Antene duale pentru cea mai fiabila functionare fara interferente
Porturi de conectare pentru utilizarea senzorilor telemetri optionali
Monitorizare baterie
Canal: 8
Frecventa: 2.4GHz ISM Gama de Frecventa
latime de banda: 500KHz
Band Cantitate: 135
Putere RF: <20dBm
Sistem: AFHDS2A
Date de iesire: PPM, i.BUS, S.BUS
Antena Lungime: 26mm
Putere: Actualizare wireless 4,0V ~ 6,5V: Da
Date canal: Pozitia centrului: 1500 ± 30us; Interval: 1000 ~ 2000 ± 30us
Intarziere canal: <15ms
Greutate neta: 7.9g
Dimensiuni: 41x25x10mm
Gama: > 300 metri
Certificare: CE0678, FCC ID: N4ZIA6C00, RCM
Fig.3.9.b: receptor tgy-IA6C
Cap. 4 – Memoriu Tehnic
4.1 Modelarea si Simularea motorului de curent continuu fara perii ( Brushless DC Motor )
Schema in impedanta pentru motorul de curent continuu:
Fig.4.1.a: schema in impedanta
Unde:
ZR=R
ZL=Ls
M=j*s*ω
Avem urmatoarele valori:
u= 0→12V
R=13,3 Ω
L=310μH
km=ke=11.4*10-3
J=0.67 g*cm2
MR=0.1197*10-3 N*m
C~0
Se cer: ω=?, i=?
Ecuatii:
u=zR*i+zL*i+ke*ω
Mm=km*i
Mm=M1+M2+MR
ω=M1*zj
ω=M2*zc
Schema de simulare in software-ul MatLab
Fig.4.1.b: schema de simulare in MatLab
Rezultatele obtinute sub forma grafica
Fig.4.1.c: Graficul lui omega
Fig.4.1.c: Graficul curentului
4.2 Dimensionarea lagarul cu rulment radial din interiorul statorului
In general lagarele cu rulmenti servesc la sustinerea arborilor, osiilor sau a altor organe de masini cu miscare de rotatie si sunt capabile sa preia fortele care actioneaza asupra acestora. Lagarele cu rulmenti sunt lagare cu frecare de rostogolire fiind realizate cu ajutorul rulmentilor. Rulmentii sunt ansambluri independente !
Avantajele lagarelor cu rulmenti constau in:
pierderi prin frecare reduse ( randament ridicat );
gabarit axial redus;
consum de lubrifiant mic;
intretinere usoara;
standardizarea pe scara internationala, prin care se asigura interschimbabilitatea acestora.
Dezavantajele lagarelor cu rulmenti constau in:
dimensiuni mari in directie radiala;
durata de functionare redusa in cazul vitezelor mari;
comportare nesatisfacatoare in cazul socurilor si vibratiilor;
necesitatea unei precizii de executie ridicate si a unor conditii severe de montaj.
Calcule in desfasurare !!!
4.3 Directia de rotatie al celor patru rotoare
Fig.4.1.d: Directia rotoarelor
Cand toate cele patru roatoare ating aceeasi viteza, momentul generat este zero ( Mom=0 ) iar quadcopter-ul isi mentine altitudinea. Cand viteza s-a stabilizat rotoarele ofera o forta de echilibru impotriva fortei gravitationale iar quadcopter-ul isi mentine altitudinea.
4.4 Ecuatii de miscare
4.4.1 Directia matriceala, matricea cosinusurilor
Rotatia vectorului in jurul axei “ x ” poate fi descrisa ca matrice:
In jurul axei “ y “ :
In jurul axei “ z ” :
Iar rotatia consecutiva in jurul axelor x,y,z poate fi scrisa astfel:
A = Rx Ry Rz =
Matricea A descrie coordonatele de transformare raportate la sol.
Primele ecuatii stabilite, descriu schimbarea pozitiei in functie de altitudinea quadcopter-ului :
-1 ·
4.4.2 Tranformarea vitezelor unghiulare
Transformarea vitezei unghilare raportate la cadrul fixat pe sol: ( conform cartii “ Flight Dynamics Principles – Michael V. Cook ” )
Unde:
Al doilea set de ecuatii de stare descriu schimbarea de altitudine in functie de rotatia corpului:
-1 ·
4.4.4 Acceleratia liniara
Acceleratia liniara a cadrului fixat la sol este data de a doua lege a lui Newton:
F = m ·
unde m este masa quadcopter-ului si este vectorul de viteza al cadrului. Iar vectorul o sa se deriveze total.
= m + m ·
Rescriem produsul incrucisat:
= m ·
Daca se neglijeaza fortele aerodinamice atunci intervin forte externe care actioneaza asupra aparatului de zbor, si anume: propulsoarele “ T “ si forta de greutate “ W “.
Forta de greutate este proiectata in functie de altitudinea quadcopter-ului iar propulsia actioneaza intotdeauna pe directia axei Z.
= m ·
Forta de greutate actioneaza intotdeauna pe directia axei z a cadrului aflat pe sol. Facand conversia cu matricea cosinusurilor, rezulta:
A · – = m ·
Rescriind organizat, rezulta:
= rv-qw-g sinθ
= pw-ru+g cosθsinɸ
= qu-pv+g cosɸcosθ –
4.4.5 Acceleratia unghiulara
Aplicarea unui cuplu extern va schimba acceleratia unghiulara a quadcopter-ului:
M=
Dar vectorul unghiular isi schimba directia si se aplica derivate totala a vectorului H:
M=+ω · H,
si H = I· ω,
unde, ω reprezinta schimbarea altitudinii, si I reprezinta momentul de inertie al quadcopter-ului.
Cand quadcopter-ul este simetric fata de planul xz si yz, iar axele de rotatie coincid cu axele principale, atunci momentul de inertie este:
Atunci,
M= I· + ω·I·ω
Dupa expansiune,
Mx= Ix+qr( Iz-Iy )
My= · Iy+pr( Ix-Iz )
Mz= · Iz +pq( Iy-Ix )
Si din cauza simetriei xz si yz,
Ix Iy
Iar ecuatiile pot fii scrise simplificat:
Mx= Ix+qr( Iz-Iy )
My= · Iy+pr( Ix-Iz )
Mz= · Iz
4.5 Momentele giroscopice ale propulsoarelor
Cap.5 – Proiectarea sistemului aerian de tip quadcopter in SolidWorks2016
Componentele Cadrului:
Cele patru suporturi ( picioare )
Fig.5.a: suport/picior cadru
Fig.5.a’: suport/picior cadru
Cele doua placute pe care vin montate restul componentelor
Fig.5.b: placa inferioara PCB
Fig.5.b’: placa superioara PCB
Surubul de asamblare cu cap de strangere imbus 2mm
Fig.5.c: surub cu cap imbus
Ansamblul final al cadrului
Fig.5.d: ansamblu final cadru
Bateria Turnigy
Fig.5.e: acumulator turnigy 2200mAh
Propulsoarele ( patru la numar )
Fig.5.f: propulsoare
Componentele motorului:
Stator + rulment radial
Fig.5.g: stator + rulment radial
Rotor
Fig.5.h: rotor
Surub
Fig.5.i: surub
Capac de sprijin
Fig.5.j: capac de sprijin
Axa fixa
Fig.5.k: axa fixa
Saiba
Fig.5.l: saiba
Capac stranger elice
Fig.5.m: capac strangere elice
Ansamblul final Motor – Elice
Fig.5.n: ansamblu motor-elice
Vedere din sectiune
Fig.5.n’: vederea din sectiune a ansamblului motor-elice
Componentele Gps-ului:
Capac spate
Fig.5.o: capac spate gps
Capac fata
Fig.5.o’: capac fata gps
Partea electronica, gps-ul propriu zis
Fig.5.p: partea electronica a gps-ului
Ansamblu Gps
Fig.5.p’: ansamblu gps
Fig.5.q: ansamblu gps
Suport gps
Fig.5.r: suport gps
Fig.5.s: statorul suportului gps
( 4x ) ESC-urile
Fig.5.t: ESC dys
Receptorul
Fig.5.u: receptor turnigy IA6C
Controlerul de zbor
Fig.5.v: Flip32 All In One Pro v1.03
Fig.5.v’: controllerul Flip32 All In One Pro v1.03 si suportul format din patru picioare
Ansamblul Final al Quadcopter-ului
Fig.5.w: ansamblu final quadcopter
Fig.5.w’: ansamblu final quadcopter
Cap. 6 – Configurarea, calibrarea si initializarea setarilor folosind extensia CLEANFLIGHT. Prezentarea programului utilizand Arduino pentru orientarea sistemului aerian
Controllerul de zbor “FLIP32 AIO Flight Controller Acro&Pro v1.03” este placa principala de control care da semnal componentelor si pe care o configuram astfel:
Primul pas este de a ne asigura ca am realizat conectivitatea componentelor pe Flight Controller asa cum ne-a fost indicat in manualul placii;
Fig.6.a: schema de principiu a conectivitatii pe placa de control
Al doilea pas constituie conectarea prin USB si Micro-USB la un calculator;
Fig.6.b: conectarea la calculator
Urmatoarea etapa este de a instala driver-ul placutei ( operatiune reusita si pe care o verificam intrand in My Computer – Management – Device Manager );
Fig.6.c: verificarea instalarii driver-ului in My Computer-Manager
Selectam din cipul de comanda de pe Flight Controller optiunea “ B ” ( FC Mode, CP2102 connected to FC );
Fig.6.d: cipul de comanda al placii principale de control
Dupa care instalam extensia CLEANFLIGHT din Magazinul Web Chrome ( sau o descarcam in calculator de pe site-ul oficial );
Inainte de a ne conecta, incarcam un Fireware si ii dam Flash ( operatiune care o sa aiba reusita la prima incercare, iar urmatoarele incercari vor necesita reset la placa de control cu ajutorul unei pensete si incercam sa facem un scurt-circuit intre pinii de reset asa cum se observa in Fig. 6.g );
Fig.6.e: conectarea placutei la extensia CLEANFLIGHT
Fig.6.f: comanda flash firmware finalizata
Fig.6.g: resetarea placutei utilizand o penseta
Daca conectarea s-a realizat cu succes, o sa apara meniul de configurari ca in Fig.6.h !
Fig.6.h: ecranul de comanda si de setare al configuratiilor
Ultimul pas consta in calibrarea esc-urilor, configurarea receptorului, configurarea radio comenzii, gps-ului si a motoarelor conform parametrilor din manualul placutei de control si a testarii in prealabil.
Controllerul de zbor “ FLIP32 AIO Flight Controller Acro&Pro v1.03” are la baza tehnologia ARDUINO prin care s-a scris codul sursa al firmware-ului ! In fig.6.i se poate observa interfata acestuia si meniul codurilor sursa scrise pe etape. Codul sursa final a fost atasat la sectiunea “ ANEXA. Cod Sursa “ de la finalul acestui proiect !
Fig.6.i: lista codurilor scrise in Arduino
Cap. 7 – Concluzii
In urma finalizarii etapelor teoretice si practice ale actualei lucrari prezentate, au fost indeplinite cu succes obiectivele propuse la inceputul proiectului, acelea de a se realiza un quadcopter, bazat pe calcule bine efectuate, care sa poata fii manevrabil de la sol prin intermediul unei radiocomenzi.
Existenta acestor aparate de zbor fara pilot uman ( denumite UAV ) difera de la o contructie la alta, de la un design la altul, asa cum s-a putut remarca mai sus, dar toate au un numitor comun si anume: siguranta sistemului de zbor construit. Orice functionare anormala a oricarei componente din ansamblul aparatului, poate conduce la urmari severe si tocmai de aceea este necesara verificarea starii de functionare a fiecarei piese.
Prezentul proiect s-a bazat pe consultarea multiplelor surse de informatie din documente de specialitate: carti, studii de caz, articole online,etc., avand ca scop informarea personala pentru a se putea realiza prezenta lucrare.
In vederea efectuarii probei practice, s-au ales componente eligibile pentru tipul aplicatiei prezentate tinandu-se cont si de raportul cost-performanta.
Alegerea controller-ului de zbor a insemnat un punct de mare importanta, deoarece acesta este placuta principala de control care preia semnalele si le distribuie mai departe pentru ca aplicatia sa poata functiona in conditii optime. Acesta avand bazele codului sursa scris in Arduino, a facut ca intreaga operatiune sa se bazeze pe un control sigur si fara erori de configurare.
Pe de alta parte, un alt punct destul de important a constat in alegerea reductoarelor de turatie care indeplinesc rolul de reglare si control al stabilitatii dinamice in zbor a aparatului construit. Acestea reduc si puterea motorului pana cand se recapata controlul dorit din radiocomanda.
Pentru efectuarea unui bun control de la sol prin intermediul radiocomenzii, s-au efectuat reglementari de software la baza placii principale de control care sa calibreze puterea motoarelor si a reductoarelor de turatie.
Testarea functionarii sistemului de zbor fara pilot uman s-a realizat intr-un spatiu deschis urmarindu-se miscarile de perturbatie si receptarea semnalelor pe o distanta de douazeci de metri.
Consideratii Perspective
Toate aplicatiile de tip UAV trebuie sa asigure un grad ridicat de siguranta atat pentru pilotul care controleaza aparatul de la sol, cat si pentru cetatenii din jur, tocmai de aceea s-au impus anumite prevederi legale de catre CAA ( Civil Aviation Authority ) pe care le regasim structurate sub forma de articole. Art.137 si Art.138 sunt generale si se refera la faptul ca o persoana nu trebuie sa actioneze in mod iresponsabil avand ca scop final punerea in pericol a aparatului de zbor si a persoanelor din jurul acestuia. Restul articolelor, cum ar fi Art.166 si Art.167 sunt reglementari impuse in exclusivitate pentru aparatele de zbor mici fara pilot uman, categorie in care se incadreaza si aparatul realizat in urma acestui proiect.
Pentru a se reusi o pilotare de la sol prin intermediul radiocomenzii cat mai usoara si sigura s-au creat aplicatii de simulare speciale, unele dintre ele fiind gratuite. Majoritatea acestor simulatoare includ un cablu USB care se conecteaza la un calculator si care face conexiunea cu radiocomanda.
Totusi, cel mai important aspect care trebuie mentionat este controlul de siguranta dinaintea zborului. Cu alte cuvinte, este necesara o verificare detaliata a quadcopter-ului inaintea fiecarei puneri in functiune.
Trebuie sa se verifice urmatoarele aspecte:
daca acumulatorul este incarcat;
mediul ambiant si cat de aglomerat este acesta;
echipamentul daca raspunde comenzilor dorite;
functionarea in conditii normale a motoarelor;
semnalul gps al aparatului;
calibrarea ESC-urilor;
directia/sensul propulsoarelor montate;
De asemenea, intotdeauna este necesar sa avem la noi o trusa de prim ajutor si pentru orice informatii putem apela la persoane in domeniu de pe www.dronetrest.com !
Dezvoltari Viitoare
Cu toate ca in decursul timpului s-au construit si perfectionat aceste aparate de zbor fara pilot uman, se pot gasi, totusi, noi imbunatatiri si dezvoltari. Pentru tema acestei lucrari abordate, propun urmatoarele etape spre o mai buna perfectionare:
Creearea unui controller de zbor mai stabil din punct de vedere software care sa nu necesite resetarea si update-ul firmware-ului odata la o anumita perioada;
Inlocuirea gps-ului cu o tehnologie mai stabila pentru un control de zbor mai usor;
Inlocuirea acumulatorului pentru o durata de zbor mai lunga;
Montarea unei camere video pentru supraveghere;
Realizarea unui cablaj mai solid pe o placa PCB externa si izolata.
Cap. 8 – B I B L I O G R A F I E
Multumiri Dl. S.l.dr.ing. Besnea Daniel pentru coordonare !
Multumiri Companiei Autonomous Flight Technologies S.R.L (A.F.T) pentru indrumare si permisiunea de realizare a imaginilor din cadrul companiei
S-a utilizat softul SolidWorks 2016 pentru realizarea desenului de executie
https://en.wikipedia.org/wiki/Langley_Aerodrome – Accesat la data de 07.10.2018
https://ro.wikipedia.org/wiki/George_de_Bothezat – Accesat la data de 07.10.2018
https://en.wikipedia.org/wiki/Flight_control_surfaces – Accesat la data de 12.10.2018
Book: Build Your Own Drone Manual-Alex Elliott-Editura Haynes – Accesata la data de 27.10.2018, 28.10.2018, 30.10.2018, 01.05.2019.
Book: Flight Dynamics Principles – Michael V. Cook – Accesata la data de 04.05.2019
www.fpvguy.com – Accesat la data de 20.11.2018
https://en.wikipedia.org/wiki/Bell_Boeing_V-22_Osprey – Accesat la data de 20.11.2018
https://blog.bimax.ro – Accesat la data de 28.11.2018
https://hobbyking.com – Accesat pentru comandarea pieselor la data de 02.01.2019
https://grabcad.com/tristan.newman-1/models – Accesat la data de 10.02.2019
https://nathan.vertile.com/blog/2015/11/09/rctimer-oze32-integrated-flight-controller-review-and-setup/#38e538cb2 – Accesat la 20.04.2019
ANEXA. Cod Sursa
#define MEMCHECK // to enable memory checking.
#if 1
__asm volatile ("nop");
#endif
#ifdef MEMCHECK
extern uint8_t _end; //end of program variables
extern uint8_t __stack; //start of stack (highest RAM address)
void PaintStack(void) __attribute__ ((naked)) __attribute__ ((section (".init1"))); //Make sure this is executed at the first time
void PaintStack(void)
{
//using asm since compiller could not be trusted here
__asm volatile (" ldi r30,lo8(_end)\n"
" ldi r31,hi8(_end)\n"
" ldi r24,lo8(0xa5)\n" /* Paint color = 0xa5 */
" ldi r25,hi8(__stack)\n"
" rjmp .cmp\n"
".loop:\n"
" st Z+,r24\n"
".cmp:\n"
" cpi r30,lo8(__stack)\n"
" cpc r31,r25\n"
" brlo .loop\n"
" breq .loop"::);
}
uint16_t UntouchedStack(void)
{
const uint8_t *ptr = &_end;
uint16_t count = 0;
while (*ptr == 0xa5 && ptr <= &__stack)
{
ptr++; count++;
}
return count;
}
#endif
// Frequently used expressions
#define PGMSTR(p) (char *)pgm_read_word(p)
//––––––––––––––––––––––––
#define MWVERS "MW-OSD – R1.9.1.1"
//#define MWVERS "MW-OSD – R1.9"
#define MWOSDVERSION 1911 // 1660=1.6.6.0 for GUI
#define EEPROMVER 17 // for eeprom layout verification
#include <avr/pgmspace.h>
#undef PROGMEM
#define PROGMEM __attribute__(( section(".progmem.data") )) // Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734
#include <EEPROM.h>
#include <util/atomic.h> // For ATOMIC_BLOCK
#include "Config.h"
#include "Def.h"
#include "symbols.h"
#include "GlobalVariables.h"
#include "math.h"
#if defined LOADFONT_LARGE
#include "fontL.h"
#elif defined LOADFONT_DEFAULT
#include "fontD.h"
#elif defined LOADFONT_BOLD
#include "fontB.h"
#endif
#ifdef I2C_UB_SUPPORT
#include "WireUB.h"
#endif
#ifdef I2C_SUPPORT
#include <Wire.h>
#endif
#if defined USEMS5837
#include "MS5837.h"
MS5837 MS5837sensor;
#endif //USEMS5837
#if defined PROTOCOL_SKYTRACK
#include "SKYTRACK.h"
#endif
//––––––––––––––––––––––––
void setup()
{
#ifdef HARDRESET
MCUSR &= (0xFF & (0 << WDRF));
WDTCSR |= (1 << WDCE) | (1 << WDE) | (0 << WDIE);
WDTCSR = (0 << WDE) | (0 << WDIE);
#endif
Serial.begin(BAUDRATE);
#ifndef PROTOCOL_MAVLINK //use double speed asynch mode (multiwii compatible)
uint8_t h = ((F_CPU / 4 / (BAUDRATE) – 1) / 2) >> 8;
uint8_t l = ((F_CPU / 4 / (BAUDRATE) – 1) / 2);
UCSR0A |= (1 << U2X0); UBRR0H = h; UBRR0L = l;
#endif
#ifdef I2C_UB_SUPPORT
// I2C initialization
WireUB.begin(I2C_UB_ADDR, -1);
TWBR = 2; // Probably has no effect.
// Compute rx queue timeout in microseconds
// = 3 character time at current bps (10bits/char)
WireUB.setWriteTimo((1000000UL) / (I2C_UB_BREQUIV / 10) * 3);
#endif
MAX7456SETHARDWAREPORTS
ATMEGASETHARDWAREPORTS
LEDINIT
#if defined EEPROM_CLEAR
EEPROM_clear();
#endif
checkEEPROM();
readEEPROM();
#ifndef STARTUPDELAY
#define STARTUPDELAY 1000
#endif
#ifndef INTRO_DELAY
#define INTRO_DELAY 6
#endif
delay(STARTUPDELAY);
#ifdef VTX_RTC6705
vtx_init();
#ifdef IMPULSERC_HELIX
vtx_flash_led(5);
# endif
#endif
MAX7456Setup();
#if defined GPSOSD
timer.GPS_initdelay = INTRO_DELAY;
#else
#endif
#if defined FORECSENSORACC
MwSensorPresent |= ACCELEROMETER;
#endif
#if defined FORCESENSORS
MwSensorPresent |= GPSSENSOR;
MwSensorPresent |= BAROMETER;
MwSensorPresent |= MAGNETOMETER;
MwSensorPresent |= ACCELEROMETER;
#endif
setMspRequests();
#ifdef ALWAYSARMED
armed = 1;
#endif //ALWAYSARMED
#ifdef KKAUDIOVARIO
Wire.begin();
setupSensor();
pressure = getPressure();
lowpassFast = lowpassSlow = pressure;
#endif //KKAUDIOVARIO
#if defined USEMS5837
Wire.begin();
MS5837sensor.init();
MS5837sensor.setFluidDensity(FLUID_DENSITY); // kg/m^3
#endif // USE MS_5837
GPS_time=946684801; // Set to Y2K as default.
datetime.unixtime = GPS_time;
Serial.flush();
for (uint8_t i = 0; i < (1+16); i++) {
MwRcData[i]=1500;
}
}
//––––––––––––––––––––––––
#if defined LOADFONT_DEFAULT || defined LOADFONT_LARGE || defined LOADFONT_BOLD
void loop()
{
switch (fontStatus) {
case 0:
MAX7456_WriteString_P(messageF0, 32);
MAX7456_DrawScreen();
delay(3000);
displayFont();
MAX7456_WriteString_P(messageF1, 32);
MAX7456_DrawScreen();
fontStatus++;
delay(3000);
break;
case 1:
updateFont();
MAX7456Setup();
MAX7456_WriteString_P(messageF2, 32);
displayFont();
MAX7456_DrawScreen();
fontStatus++;
break;
}
LEDOFF
}
#elif defined DISPLAYFONTS
void loop()
{
MAX7456Setup();
displayFont();
MAX7456_DrawScreen();
}
#else
// ampAlarming returns true if the total consumed mAh is greater than
// the configured alarm value (which is stored as 100s of amps)
bool ampAlarming() {
int used = pMeterSum > 0 ? pMeterSum : (amperagesum / 360);
return used > (Settings[S_AMPER_HOUR_ALARM] * 100);
}
//––––––––––––––––––––––––
void loop()
{
#if defined TX_GUI_CONTROL //PITCH,YAW,THROTTLE,ROLL order controlled by GUI for GPSOSD and MAVLINK
switch (Settings[S_TX_TYPE]) {
case 1: //RPTY
tx_roll = 1;
tx_pitch = 2;
tx_yaw = 4;
tx_throttle = 3;
break;
case 2: //TRPY
tx_roll = 2;
tx_pitch = 3;
tx_yaw = 4;
tx_throttle = 1;
break;
default: //RPYT – default xxxflight FC
tx_roll = 1;
tx_pitch = 2;
tx_yaw = 3;
tx_throttle = 4;
break;
}
#endif // TX_GUI_CONTROL //PITCH,YAW,THROTTLE,ROLL order controlled by GUI
alarms.active = 0;
timer.loopcount++;
if (flags.reset) {
resetFunc();
}
#if defined (KISS)
if (Kvar.mode == 1)
screenlayout = 1;
else
screenlayout = 0;
#elif defined (OSD_SWITCH)
if (MwSensorActive & mode.osd_switch)
screenlayout = 1;
else
screenlayout = 0;
#elif defined (OSD_SWITCH_RC)
rcswitch_ch = Settings[S_RCWSWITCH_CH];
screenlayout = 0;
if (Settings[S_RCWSWITCH] == 1) {
if (MwRcData[rcswitch_ch] > TX_CHAN_HIGH) {
screenlayout = 2;
}
else if (MwRcData[rcswitch_ch] > TX_CHAN_MID) {
screenlayout = 1;
}
}
else {
if (MwSensorActive & mode.osd_switch)
screenlayout = 1;
}
#else
screenlayout = 0;
#endif
if (screenlayout != oldscreenlayout) {
readEEPROM();
}
oldscreenlayout = screenlayout;
// Blink Basic Sanity Test Led at 0.5hz
if (timer.Blink2hz)
LEDON
else
LEDOFF
//––––– Start Timed Service Routines –––––––––––––
unsigned long currentMillis = millis();
#ifdef IMPULSERC_HELIX
vtx_process_state(currentMillis, vtxBand, vtxChannel);
#endif //IMPULSERC_HELIX
#ifdef KKAUDIOVARIO
if (millis() > timer.audiolooptimer) {
timer.audiolooptimer += 20;
AudioVarioUpdate();
}
#endif //KKAUDIOVARIO
#ifdef MSP_SPEED_HIGH
if ((currentMillis – previous_millis_sync) >= sync_speed_cycle) // (Executed > NTSC/PAL hz 33ms)
{
previous_millis_sync = previous_millis_sync + sync_speed_cycle;
#ifdef CANVAS_SUPPORT
if (!fontMode && !canvasMode)
#else
if (!fontMode)
#endif
{
#ifdef PROTOCOL_MSP
if (timer.GUI_active == 0) {
mspWriteRequest(MSP_ATTITUDE, 0);
}
#endif
}
}
#endif //MSP_SPEED_HIGH
if ((currentMillis – previous_millis_low) >= lo_speed_cycle) // 10 Hz (Executed every 100ms)
{
previous_millis_low = previous_millis_low + lo_speed_cycle;
timer.tenthSec++;
timer.halfSec++;
timer.Blink10hz = !timer.Blink10hz;
#ifdef USEMS5837
MS5837sensor.read();
#endif //USEMS5837
if (GPS_fix && armed) {
if (Settings[S_UNITSYSTEM])
tripSum += GPS_speed * 0.0032808; // 100/(100*1000)*3.2808=0.0016404 cm/sec –> ft/50msec
else
tripSum += GPS_speed * 0.0010; // 100/(100*1000)=0.0005 cm/sec –> mt/50msec (trip var is float)
trip = (uint32_t) tripSum;
}
#if defined (GPSOSD)
handleRawRC();
#endif
#ifndef KISS
amperagesum += amperage;
#else
if (!Settings[S_MWAMPERAGE])
amperagesum += amperage;
#endif // KISS
#ifndef GPSOSD
#ifdef MSP_SPEED_MED
#ifdef CANVAS_SUPPORT
if (!fontMode && !canvasMode)
#else
if (!fontMode)
#endif
{
#ifdef PROTOCOL_MSP
if (timer.GUI_active == 0) {
mspWriteRequest(MSP_ATTITUDE, 0);
}
#endif // KISS
}
#endif //MSP_SPEED_MED
#endif //GPSOSD
} // End of slow Timed Service Routine (100ms loop)
if ((currentMillis – previous_millis_high) >= hi_speed_cycle) // 33 Hz or 100hz in MSP high mode.
{
previous_millis_high = previous_millis_high + hi_speed_cycle;
uint16_t MSPcmdsend = 0;
if (queuedMSPRequests == 0)
queuedMSPRequests = modeMSPRequests;
uint32_t req = queuedMSPRequests & -queuedMSPRequests;
queuedMSPRequests &= ~req;
switch (req) {
case REQ_MSP_STATUS:
MSPcmdsend = MSP_STATUS;
break;
#ifdef INTRO_FC
case REQ_MSP_FC_VERSION:
MSPcmdsend = MSP_FC_VERSION;
break;
#endif
case REQ_MSP_RC:
MSPcmdsend = MSP_RC;
break;
case REQ_MSP_RAW_GPS:
MSPcmdsend = MSP_RAW_GPS;
break;
case REQ_MSP_COMP_GPS:
MSPcmdsend = MSP_COMP_GPS;
break;
case REQ_MSP_ATTITUDE:
MSPcmdsend = MSP_ATTITUDE;
break;
case REQ_MSP_ALTITUDE:
MSPcmdsend = MSP_ALTITUDE;
break;
case REQ_MSP_ANALOG:
MSPcmdsend = MSP_ANALOG;
break;
case REQ_MSP_MISC:
MSPcmdsend = MSP_MISC;
break;
case REQ_MSP_RC_TUNING:
MSPcmdsend = MSP_RC_TUNING;
break;
case REQ_MSP_PID_CONTROLLER:
MSPcmdsend = MSP_PID_CONTROLLER;
break;
case REQ_MSP_PID:
MSPcmdsend = MSP_PID;
break;
#ifdef MENU_SERVO
case REQ_MSP_SERVO_CONF:
MSPcmdsend = MSP_SERVO_CONF;
break;
#endif
#ifdef USE_MSP_PIDNAMES
case REQ_MSP_PIDNAMES:
MSPcmdsend = MSP_PIDNAMES;
break;
#endif
#ifdef CORRECTLOOPTIME
case REQ_MSP_LOOP_TIME:
MSPcmdsend = MSP_LOOP_TIME;
break;
#endif
case REQ_MSP_BOX:
#ifdef BOXNAMES
MSPcmdsend = MSP_BOXNAMES;
#else
MSPcmdsend = MSP_BOXIDS;
#endif
break;
case REQ_MSP_FONT:
MSPcmdsend = MSP_OSD;
break;
#if defined DEBUGMW
case REQ_MSP_DEBUG:
MSPcmdsend = MSP_DEBUG;
break;
#endif
#if defined SPORT
case REQ_MSP_CELLS:
MSPcmdsend = MSP_CELLS;
break;
#endif
#ifdef MULTIWII_V24
case REQ_MSP_NAV_STATUS:
if (MwSensorActive & mode.gpsmission)
MSPcmdsend = MSP_NAV_STATUS;
break;
#endif
#ifdef CORRECT_MSP_BF1
case REQ_MSP_CONFIG:
MSPcmdsend = MSP_CONFIG;
break;
#endif
#ifdef MENU_FIXEDWING
case REQ_MSP_FW_CONFIG:
MSPcmdsend = MSP_FW_CONFIG;
break;
#endif
#ifdef HAS_ALARMS
case REQ_MSP_ALARMS:
MSPcmdsend = MSP_ALARMS;
break;
#endif
#ifdef MSP_RTC_SUPPORT
case REQ_MSP_RTC:
MSPcmdsend = MSP_RTC;
break;
#endif
case REQ_MSP_VOLTAGE_METER_CONFIG:
MSPcmdsend = MSP_VOLTAGE_METER_CONFIG;
break;
#ifdef MSPV2
case REQ_MSP2_INAV_AIR_SPEED:
MSPcmdsend = MSP2_INAV_AIR_SPEED;
break;
#endif
}
if (!fontMode) {
#ifdef KISS
Serial.write(0x20);
#elif defined SKYTRACK
DrawSkytrack();
#elif defined PROTOCOL_MSP
#ifdef CANVAS_SUPPORT
if (!canvasMode)
#endif
{
if (MSPcmdsend != 0) {
#ifdef MSPV2
if (MSPcmdsend > 254) {
mspV2WriteRequest(MSPcmdsend, 0);
}
else
#endif
{
mspWriteRequest(MSPcmdsend & 0xff, 0);
}
}
}
#endif // KISS
MAX7456_DrawScreen();
}
ProcessSensors(); // using analogue sensors
if ( allSec < INTRO_DELAY ) {
displayIntro();
timer.lastCallSign = onTime – CALLSIGNINTERVAL;
}
else
{
if (armed) {
previousarmedstatus = 1;
timer.disarmed = OSDSUMMARY;
if (configMode == 1)
configExit();
}
#ifndef HIDESUMMARY
if (previousarmedstatus && !armed) {
configPage = 0;
ROW = 10;
COL = 1;
configMode = 1;
setMspRequests();
}
#else
if (previousarmedstatus && !armed) {
previousarmedstatus = 0;
configMode = 0;
}
#endif //HIDESUMMARY
if (configMode)
{
displayConfigScreen();
}
#ifdef CANVAS_SUPPORT
else if (canvasMode)
{
// In canvas mode, we don't actively write the screen; just listen to MSP stream.
if (lastCanvas + CANVAS_TIMO < currentMillis) {
MAX7456_ClearScreen();
canvasMode = false;
}
}
#endif
else
{
setMspRequests();
#if defined USE_AIRSPEED_SENSOR
useairspeed();
#endif //USE_AIRSPEED_SENSOR
displayHorizon(MwAngle[0], MwAngle[1]);
#if defined FORCECROSSHAIR
displayForcedCrosshair();
#endif //FORCECROSSHAIR
displayVoltage();
displayVidVoltage();
if ((rssi > Settings[S_RSSI_ALARM]) || (timer.Blink2hz))
displayRSSI();
if (((amperage / 10) < Settings[S_AMPERAGE_ALARM]) || (timer.Blink2hz))
displayAmperage();
if (((!ampAlarming()) || timer.Blink2hz))
displaypMeterSum();
#ifdef DISPLAYEFFICIENCYTIME
displayRemainingTime();
#endif
displayFlightTime();
#if defined (DISPLAYWATTS)
displayWatt();
#endif //DISPLAYWATTS
#if defined (DISPLAYEFFICIENCY)
displayEfficiency();
#endif //DISPLAYEFFICIENCY
#if defined (DISPLAYAVGEFFICIENCY)
displayAverageEfficiency();
#endif //DISPLAYAVGEFFICIENCY
#ifdef SHOW_TEMPERATURE
displayTemperature();
#endif
#ifdef VIRTUAL_NOSE
displayVirtualNose();
#endif
displayArmed();
displayCurrentThrottle();
#ifdef FREETEXTLLIGHTS
if (MwSensorActive & mode.llights) displayCallsign(getPosition(callSignPosition));
#elif FREETEXTGIMBAL
if (MwSensorActive & mode.camstab) displayCallsign(getPosition(callSignPosition));
#else
if (fieldIsVisible(callSignPosition)) {
#ifdef PILOTICON
if (Settings[S_CALLSIGN_ALWAYS] == 3) {
displayIcon(getPosition(callSignPosition));
}
else if (Settings[S_CALLSIGN_ALWAYS] == 2) {
if ( (onTime > (timer.lastCallSign + CALLSIGNINTERVAL))) { // Displays 4 sec every 60 secs
if ( onTime > (timer.lastCallSign + CALLSIGNINTERVAL + CALLSIGNDURATION))
timer.lastCallSign = onTime;
displayCallsign(getPosition(callSignPosition));
}
}
else if (Settings[S_CALLSIGN_ALWAYS] == 1) {
displayCallsign(getPosition(callSignPosition));
}
#else
if (Settings[S_CALLSIGN_ALWAYS] == 2) {
if ( (onTime > (timer.lastCallSign + CALLSIGNINTERVAL))) { // Displays 4 sec every 60 secs
if ( onTime > (timer.lastCallSign + CALLSIGNINTERVAL + CALLSIGNDURATION))
timer.lastCallSign = onTime;
displayCallsign(getPosition(callSignPosition));
}
}
else if (Settings[S_CALLSIGN_ALWAYS] == 1) {
displayCallsign(getPosition(callSignPosition));
}
#endif
}
#endif
displayHeadingGraph();
displayHeading();
#if defined SUBMERSIBLE
#if defined USEMS5837
MwAltitude = (float)100 * MS5837sensor.depth();
#endif //USEMS5837
if (millis() > timer.fwAltitudeTimer) { // To make vario from Submersible altitude
timer.fwAltitudeTimer += 1000;
MwVario = MwAltitude – previousfwaltitude;
previousfwaltitude = MwAltitude;
}
#endif // SUBMERSIBLE
displayAltitude(((int32_t)GPS_altitude*10),MwGPSAltPosition,SYM_GPS_ALT);
displayAltitude(MwAltitude/10,MwAltitudePosition,SYM_ALT);
displayClimbRate();
displayVario();
displayNumberOfSat();
displayDirectionToHome();
displayDistanceToHome();
displayDistanceTotal();
displayDistanceMax();
displayAngleToHome();
displayGPSdop();
// displayfwglidescope(); //note hook for this is in display horizon function
if (!armed)
GPS_speed = 0;
display_speed(GPS_speed, GPS_speedPosition, SYM_SPEED_GPS);
display_speed(AIR_speed, AIR_speedPosition, SYM_SPEED_AIR);
displayWindSpeed(); // also windspeed if available
displayItem(MAX_speedPosition, speedMAX, SYM_MAX, speedUnitAdd[Settings[S_UNITSYSTEM]], 0 );
displayGPSPosition();
#ifdef GPSTIME
if (fieldIsVisible(GPS_timePosition))
displayDateTime();
#endif
#ifdef MAPMODE
mapmode();
#endif
displayMode();
#ifdef I2CERROR
displayI2CError();
#endif
#ifdef SPORT
if (MwSensorPresent)
displayCells();
#endif
#ifdef DEBUG
displayDebug();
#endif
#ifdef HAS_ALARMS
displayAlarms();
#endif
#ifdef MAV_STATUS
displayMAVstatustext();
#endif
}
}
} // End of fast Timed Service Routine (50ms loop)
if (timer.halfSec >= 5) {
timer.halfSec = 0;
timer.Blink2hz = ! timer.Blink2hz;
#if 0
// XXX What is this for? On-Arm power setting?
// XXX May be "Power up at minimum power, then goto stored power on-arming."for stick based blind operation or something similar
// XXX Leave commented out until intension is known.
#ifdef VTX_RTC6705
vtx_set_power(armed ? vtxPower : 0);
#endif // VTX_RTC6705
#endif
}
if (millis() > timer.seconds + 1000) // this execute 1 time a second
{
#if defined (GPSTIME) && !defined (UBLOX)
datetime.unixtime++;
updateDateTime(datetime.unixtime);
#endif //GPSTIME
if (timer.armedstatus > 0)
timer.armedstatus–;
timer.seconds += 1000;
timer.tenthSec = 0;
#ifdef MAV_STATUS
if (timer.MAVstatustext > 0)
timer.MAVstatustext–;
#endif
#ifdef DEBUGDPOSLOOP
framerate = timer.loopcount;
timer.loopcount = 0;
#endif
#ifdef DEBUGDPOSPACKET
packetrate = timer.packetcount;
timer.packetcount = 0;
#endif
#ifdef DEBUGDPOSRX
serialrxrate = timer.serialrxrate;
timer.serialrxrate = 0;
#endif
onTime++;
#if defined(AUTOCAM) || defined(MAXSTALLDETECT)
if (!fontMode)
MAX7456CheckStatus();
#endif
#ifdef ALARM_GPS
if (timer.GPS_active == 0) {
GPS_numSat = 0;
}
else {
timer.GPS_active–;
}
#endif // ALARM_GPS
if (timer.disarmed > 0) {
timer.disarmed–;
}
if (timer.MSP_active > 0) {
timer.MSP_active–;
}
if (timer.GUI_active > 0) {
timer.GUI_active–;
#if defined GPSOSD
timer.GPS_initdelay = 2;
#endif
}
#if defined(GPSOSD) && !defined(NAZA)
if (timer.GPS_initdelay == 1) {
GPS_SerialInit();
}
if (timer.GPS_initdelay > 0) {
timer.GPS_initdelay–;
}
#endif
if (!armed) {
#ifndef MAPMODENORTH
armedangle = MwHeading;
#endif
}
else {
flyTime++;
flyingTime++;
configMode = 0;
setMspRequests();
}
allSec++;
/*
if((timer.accCalibrationTimer==1)&&(configMode)) {
mspWriteRequest(MSP_ACC_CALIBRATION,0);
timer.accCalibrationTimer=0;
}
*/
#ifdef PROTOCOL_MSP
if ((timer.magCalibrationTimer == 1) && (configMode)) {
mspWriteRequest(MSP_MAG_CALIBRATION, 0);
timer.magCalibrationTimer = 0;
}
if (timer.magCalibrationTimer > 0) timer.magCalibrationTimer–;
#endif
if (timer.rssiTimer > 0) timer.rssiTimer–;
}
// setMspRequests();
serialMSPreceive(1);
#ifdef FIXEDLOOP
delay(1);
#endif
} // End of main loop
#endif //main loop
//––––––––––––––––––––––––
//FONT management
uint8_t safeMode() {
return 1; // XXX
}
// Font upload queue implementation.
// Implement a window for curr + the previous 6 requests.
// First-chance to retransmit at curr-3 (retransmitQueue & 0x10)
// First-chance retransmit marked as used at retransmitQueue |= 0x01
// 2 to N-chance retransmit marked at curr-6 (retransmitQueue & 0x02)
void initFontMode() {
if (armed || configMode || fontMode || !safeMode())
return;
// queue first char for transmition.
retransmitQueue = 0x80;
fontMode = 1;
// setMspRequests();
}
void fontCharacterReceived(uint8_t cindex) {
if (!fontMode)
return;
uint8_t bit = (0x80 >> (nextCharToRequest – cindex));
// Just received a char..
if (retransmitQueue & bit) {
// this char war requested and now received for the first time
retransmitQueue &= ~bit; // mark as already received
write_NVM(cindex); // Write to MVRam
}
}
int16_t getNextCharToRequest() {
if (nextCharToRequest != lastCharToRequest) { // Not at last char
if (retransmitQueue & 0x02) { // Missed char at curr-6. Need retransmit!
return nextCharToRequest – 6;
}
if ((retransmitQueue & 0x11) == 0x10) { // Missed char at curr-3. First chance retransmit
retransmitQueue |= 0x01; // Mark first chance as used
return nextCharToRequest – 3;
}
retransmitQueue = (retransmitQueue >> 1) | 0x80; // Add next to queue
return nextCharToRequest++; // Notice post-increment!
}
uint8_t temp1 = retransmitQueue & ~0x01;
uint8_t temp2 = nextCharToRequest – 6;
if (temp1 == 0) {
fontMode = 0; // Exit font mode
// setMspRequests();
return -1;
}
// Already at last char… check for missed characters.
while (!(temp1 & 0x03)) {
temp1 >>= 1;
temp2++;
}
return temp2;
}
//––––––––––––––––––––––––
// MISC
void resetFunc(void)
{
#ifdef I2C_UB_SUPPORT
WireUB.end();
#endif
#if defined HARDRESET
MCUSR &= ~(1 << WDRF);
WDTCSR |= (1 << WDCE) | (1 << WDE) | (1 << WDIE);
WDTCSR = (1 << WDIE) | (0 << WDE) | (0 << WDP3) | (0 << WDP2) | (0 << WDP1) | (1 << WDP0);
while (1);
#elif defined BOOTRESET
asm volatile (" jmp 0x3800");
#else
asm volatile (" jmp 0");
#endif
}
void setMspRequests() {
if (fontMode) {
modeMSPRequests = REQ_MSP_FONT;
}
else if (configMode) {
modeMSPRequests =
REQ_MSP_STATUS |
REQ_MSP_RAW_GPS |
REQ_MSP_ATTITUDE |
REQ_MSP_RAW_IMU |
REQ_MSP_ALTITUDE |
REQ_MSP_RC_TUNING |
REQ_MSP_PID_CONTROLLER |
REQ_MSP_ANALOG |
#ifdef USE_MSP_PIDNAMES
REQ_MSP_PIDNAMES |
#endif
REQ_MSP_PID |
#ifdef CORRECTLOOPTIME
REQ_MSP_LOOP_TIME |
#endif
#ifdef CORRECT_MSP_BF1
REQ_MSP_CONFIG |
#endif
#ifdef DEBUGMW
REQ_MSP_DEBUG |
#endif
#ifdef SPORT
REQ_MSP_CELLS |
#endif
#ifdef HAS_ALARMS
REQ_MSP_ALARMS |
#endif
#ifdef MENU_SERVO
REQ_MSP_SERVO_CONF |
#endif
#ifdef MENU_FIXEDWING
REQ_MSP_FW_CONFIG |
#endif
#ifdef USE_FC_VOLTS_CONFIG
#if defined(CLEANFLIGHT) || defined(BETAFLIGHT)
REQ_MSP_VOLTAGE_METER_CONFIG |
#else
REQ_MSP_MISC |
#endif
#endif
REQ_MSP_RC;
}
else {
modeMSPRequests =
REQ_MSP_STATUS |
#ifdef DEBUGMW
REQ_MSP_DEBUG |
#endif
#ifdef SPORT
REQ_MSP_CELLS |
#endif
#ifdef MSP_USE_GPS
REQ_MSP_RAW_GPS |
REQ_MSP_COMP_GPS |
#endif //MSP_USE_GPS
#ifdef MSP_USE_BARO
REQ_MSP_ALTITUDE |
#endif //MSP_USE_BARO
#ifdef HAS_ALARMS
REQ_MSP_ALARMS |
#endif
#ifdef MSP_SPEED_LOW
REQ_MSP_ATTITUDE |
#endif
#ifdef MSP_USE_ANALOG
REQ_MSP_ANALOG |
#endif //MSP_USE_ANALOG
#ifdef MSPV2
REQ_MSP2_INAV_AIR_SPEED |
#endif
REQ_MSP_RC;
if (!armed) {
modeMSPRequests |=
REQ_MSP_BOX |
#if defined INTRO_FC && defined PROTOCOL_MSP
REQ_MSP_FC_VERSION |
#endif // INTRO_FC && defined PROTOCOL_MSP
#ifdef USE_FC_VOLTS_CONFIG
#if defined(CLEANFLIGHT) || defined(BETAFLIGHT)
REQ_MSP_VOLTAGE_METER_CONFIG |
#else
REQ_MSP_MISC |
#endif // defined(CLEANFLIGHT) || defined(BETAFLIGHT)
#endif // USE_FC_VOLTS_CONFIG
#ifdef MSP_RTC_SUPPORT
REQ_MSP_RTC |
#endif // MSP_RTC_SUPPORT
0;
}
#if defined MULTIWII_V24
if (MwSensorActive & mode.gpsmission)
modeMSPRequests |= REQ_MSP_NAV_STATUS;
#endif
}
if (timer.GUI_active != 0) {
modeMSPRequests = 0;
queuedMSPRequests = 0;
}
queuedMSPRequests &= modeMSPRequests; // so we do not send requests that are not needed.
}
void writeEEPROM(void) // OSD will only change 8 bit values. GUI changes directly
{
for (uint8_t en = 0; en < EEPROM_SETTINGS; en++) {
EEPROM.write(en, Settings[en]);
}
for (uint8_t en = 0; en < EEPROM16_SETTINGS; en++) {
uint16_t pos = EEPROM_SETTINGS + (en * 2);
uint16_t data = Settings16[en];
write16EEPROM(pos, data);
}
EEPROM.write(0, EEPROMVER);
}
void readEEPROM(void)
{
for (uint8_t en = 0; en < EEPROM_SETTINGS; en++) {
Settings[en] = EEPROM.read(en);
}
// config dependant – set up interrupts
#if defined INTC3
if (Settings[S_MWRSSI] == 1) {
DDRC &= ~(1 << DDC3); // PORTC |= (1 << PORTC3);
//DDRC &=B11110111;
#ifndef INTD5
Settings[S_PWM_PPM] = 0;
#endif
}
#endif
#if defined INTD5
DDRD &= ~(1 << DDD5); // PORTD |= (1 << PORTD5);
#endif
cli();
#if defined INTC3
if (Settings[S_MWRSSI] == 1) {
if ((PCMSK1 & (1 << PCINT11)) == 0) {
PCICR |= (1 << PCIE1);
PCMSK1 |= (1 << PCINT11);
}
}
#endif
#if defined INTD5
if ((PCMSK2 & (1 << PCINT21)) == 0) {
PCICR |= (1 << PCIE2);
PCMSK2 |= (1 << PCINT21);
}
#endif
sei();
// config dependant – voltage reference
#ifdef IMPULSERC_HELIX
//Ignore setting because this is critical to making sure we can detect the
//VTX power jumper being installed. If we aren't using 5V ref there is
//the chance we will power up on wrong frequency.
Settings[S_VREFERENCE] = 1;
#endif //IMPULSERC_HELIX
if (Settings[S_VREFERENCE])
analogReference(DEFAULT);
else
analogReference(INTERNAL);
for (uint8_t en = 0; en < EEPROM16_SETTINGS; en++) {
uint16_t pos = (en * 2) + EEPROM_SETTINGS;
Settings16[en] = EEPROM.read(pos);
uint16_t xx = EEPROM.read(pos + 1);
Settings16[en] = Settings16[en] + (xx << 8);
}
// Read screen layouts
uint16_t EEPROMscreenoffset = EEPROM_SETTINGS + (EEPROM16_SETTINGS * 2) + (screenlayout * POSITIONS_SETTINGS * 2);
for (uint8_t en = 0; en < POSITIONS_SETTINGS; en++) {
uint16_t pos = (en * 2) + EEPROMscreenoffset;
screenPosition[en] = EEPROM.read(pos);
uint16_t xx = (uint16_t)EEPROM.read(pos + 1) << 8;
screenPosition[en] = screenPosition[en] + xx;
if (flags.signaltype == 1) {
uint16_t x = screenPosition[en] & 0x1FF;
if (x > LINE06) screenPosition[en] = screenPosition[en] + LINE;
if (x > LINE09) screenPosition[en] = screenPosition[en] + LINE;
}
}
}
void checkEEPROM(void)
{
uint8_t EEPROM_Loaded = EEPROM.read(0);
if (EEPROM_Loaded != EEPROMVER) {
for (uint8_t en = 0; en < EEPROM_SETTINGS; en++) {
EEPROM.write(en, pgm_read_byte(&EEPROM_DEFAULT[en]));
}
for (uint8_t en = 0; en < EEPROM16_SETTINGS; en++) {
uint16_t pos = EEPROM_SETTINGS + (en * 2);
uint16_t data = pgm_read_word(&EEPROM16_DEFAULT[en]);
write16EEPROM(pos, data);
}
uint16_t base = EEPROM_SETTINGS + (EEPROM16_SETTINGS * 2);
for (uint8_t ilayout = 0; ilayout < 3; ilayout++) {
for (uint8_t en = 0; en < POSITIONS_SETTINGS * 2; en++) {
uint16_t pos = base + (en * 2);
uint16_t data = pgm_read_word(&SCREENLAYOUT_DEFAULT[en]);
write16EEPROM(pos, data);
}
base += POSITIONS_SETTINGS * 2;
}
}
}
void write16EEPROM(uint16_t pos, uint16_t data)
{
EEPROM.write(pos , data & 0xff);
EEPROM.write(pos + 1, data >> 8 );
}
void gpsdistancefix(void) {
int8_t speedband;
static int8_t oldspeedband;
static int8_t speedcorrection = 0;
if (GPS_distanceToHome < 10000) speedband = 0;
else if (GPS_distanceToHome > 50000) speedband = 2;
else {
speedband = 1;
oldspeedband = speedband;
}
if (speedband == oldspeedband) {
if (oldspeedband == 0) speedcorrection–;
if (oldspeedband == 2) speedcorrection++;
oldspeedband = speedband;
}
GPS_distanceToHome = (speedcorrection * 65535) + GPS_distanceToHome;
}
void ProcessSensors(void) {
/*
special note about filter: last row of array = averaged reading
*/
//––––– ADC sensor / PWM RSSI / FC data read into filter array
static uint8_t sensorindex;
uint16_t sensortemp;
for (uint8_t sensor = 0; sensor < SENSORTOTAL; sensor++) {
sensortemp = analogRead(sensorpinarray[sensor]);
//– override with FC voltage data if enabled
if (sensor == 0) {
if (Settings[S_MAINVOLTAGE_VBAT]) {
sensortemp = MwVBat;
}
}
#ifdef MAV_VBAT2
// assume vbat2 on FC if vbat1 is
if (sensor == 1) {
if (Settings[S_MAINVOLTAGE_VBAT]) {
sensortemp = MwVBat2;
}
}
#endif
//– override with PWM, FC RC CH or FC RSSI data if enabled
if (sensor == 4) {
if (Settings[S_MWRSSI] == 3) { // RSSI from a TX channel
sensortemp = MwRcData[Settings[S_RSSI_CH]] >> 1;
}
else if (Settings[S_MWRSSI] == 2) { // RSSI from Flight controller
sensortemp = MwRssi;
}
else if (Settings[S_MWRSSI] == 1) { // RSSI from direct OSD – PWM
sensortemp = pwmRSSI >> 1;
if (sensortemp == 0) { // timed out – use previous
sensortemp = sensorfilter[sensor][sensorindex];
}
}
else { // RSSI from direct OSD – Analog
}
}
//– Apply filtering
#if defined FILTER_HYSTERYSIS // Hysteris incremental averaged change
static uint16_t shfilter[SENSORTOTAL];
int16_t diff = (sensortemp << FILTER_HYSTERYSIS) – shfilter[sensor];
if (abs(diff) > (FHBANDWIDTH << FILTER_HYSTERYSIS)) {
shfilter[sensor] = sensortemp << FILTER_HYSTERYSIS;
}
else if (diff > 0) {
shfilter[sensor]++;
}
else if (diff < 0) {
shfilter[sensor]–;
}
sensorfilter[sensor][SENSORFILTERSIZE] = (shfilter[sensor] >> FILTER_HYSTERYSIS << 3);
#elif defined FILTER_AVG // Use averaged change
sensorfilter[sensor][SENSORFILTERSIZE] = sensorfilter[sensor][SENSORFILTERSIZE] – sensorfilter[sensor][sensorindex];
sensorfilter[sensor][sensorindex] = (sensorfilter[sensor][sensorindex] + sensortemp) >> 1;
sensorfilter[sensor][SENSORFILTERSIZE] = sensorfilter[sensor][SENSORFILTERSIZE] + sensorfilter[sensor][sensorindex];
#else // No filtering
sensorfilter[sensor][SENSORFILTERSIZE] = sensortemp << 3;
#endif
}
//––––– Voltage
if (!Settings[S_MAINVOLTAGE_VBAT]) { // not MWII
uint16_t voltageRaw = sensorfilter[0][SENSORFILTERSIZE];
if (!Settings[S_VREFERENCE]) {
voltage = float(voltageRaw) * Settings[S_DIVIDERRATIO] * (DIVIDER1v1);
}
else {
voltage = float(voltageRaw) * Settings[S_DIVIDERRATIO] * (DIVIDER5v);
}
}
else {
voltage = sensorfilter[0][SENSORFILTERSIZE] >> 3;
}
vidvoltageWarning = Settings[S_VIDVOLTAGEMIN];
uint16_t vidvoltageRaw = sensorfilter[1][SENSORFILTERSIZE];
if (!Settings[S_VREFERENCE]) {
vidvoltage = float(vidvoltageRaw) * Settings[S_VIDDIVIDERRATIO] * (DIVIDER1v1);
}
else {
vidvoltage = float(vidvoltageRaw) * Settings[S_VIDDIVIDERRATIO] * (DIVIDER5v);
}
//––––– Temperature
#ifdef SHOW_TEMPERATURE
#if defined USEMS5837
temperature = (float)(10 * MS5837sensor.temperature());
#elif defined PROTOCOL_MAVLINK && !defined USE_TEMPERATURE_SENSOR
#else
temperature = (sensorfilter[3][SENSORFILTERSIZE] >> 3);
temperature = map (temperature, Settings16[S16_AUX_ZERO_CAL], Settings16[S16_AUX_CAL], 0 , 100);
#endif
#endif
//––––– Current
if (Settings[S_MWAMPERAGE] == 2) { // Virtual
uint32_t Vthrottle = map(MwRcData[THROTTLESTICK], LowT, HighT, 0, 100);
Vthrottle = constrain(Vthrottle, 0, 100);
amperage = (Vthrottle + (Vthrottle * Vthrottle * 0.02)) * Settings16[S16_AMPDIVIDERRATIO] * 0.01;
if (armed)
amperage += Settings16[S16_AMPZERO];
else
amperage = Settings16[S16_AMPZERO];
}
else if (Settings[S_MWAMPERAGE] == 1) { // from FC
if (MWAmperage < 0)
amperage = (MWAmperage – AMPERAGE_DIV / 2) / AMPERAGE_DIV;
else
amperage = (MWAmperage + AMPERAGE_DIV / 2) / AMPERAGE_DIV;
}
else { // Analog
amperage = sensorfilter[2][SENSORFILTERSIZE] >> 3;
amperage = map(amperage, Settings16[S16_AMPZERO], AMPCALHIGH, AMPCALLOW, Settings16[S16_AMPDIVIDERRATIO]);
if (amperage < 0) amperage = 0;
}
//––––– RSSI
rssi = sensorfilter[4][SENSORFILTERSIZE] >> 3; // filter and remain 16 bit
if (configMode) {
if ((timer.rssiTimer == 15)) {
Settings16[S16_RSSIMAX] = rssi; // tx on
}
if ((timer.rssiTimer == 1)) {
Settings16[S16_RSSIMIN] = rssi; // tx off
timer.rssiTimer = 0;
}
}
rssi = map(rssi, Settings16[S16_RSSIMIN], Settings16[S16_RSSIMAX], 0, 100);
rssi = constrain(rssi, 0, 100);
//––––– For filter support
sensorindex++;
if (sensorindex >= SENSORFILTERSIZE)
sensorindex = 0;
}
#if defined INTD5
ISR(PCINT1_vect) { // Default Arduino A3 Atmega C3
#define PWMPIN1 DDC3
static uint16_t s_LastRising = 0;
uint16_t l_PulseDuration;
uint16_t l_CurrentTime = micros();
uint8_t l_pinstatus = PINC;
sei();
l_PulseDuration = l_CurrentTime – s_LastRising;
if ((l_pinstatus & (1 << PWMPIN1))) { // transitioned to high
s_LastRising = l_CurrentTime;
if ((l_PulseDuration) > 3000) { //assume this is PPM gap so exit
return;
}
}
else{ // // transitioned to low
if ((900 < l_PulseDuration) && (l_PulseDuration < 2200)) {
#if defined DEBUG
pwmval1 = l_PulseDuration;
#endif
pwmRSSI = l_PulseDuration;
}
}
}
#else // INTD5
ISR(PCINT1_vect) { // Default Arduino A3 Atmega C3
#define PWMPIN1 DDC3
static uint8_t s_RCchan = 1;
static uint16_t s_LastRising = 0;
static uint16_t s_LastFalling = 0;
uint16_t l_PulseDuration;
uint16_t l_CurrentTime = micros();
uint8_t l_pinstatus = PINC;
sei();
l_PulseDuration = l_CurrentTime – s_LastRising;
if ((l_pinstatus & (1 << PWMPIN1))) { // transitioned to high
s_LastRising = l_CurrentTime;
if ((l_PulseDuration) > 3000) { //assume this is PPM gap so exit
s_RCchan = 1;
return;
}
if (Settings[S_PWM_PPM]) {//ppm
if (s_RCchan <= TX_CHANNELS) { // avoid array overflow if > standard ch PPM
MwRcData[s_RCchan] = l_PulseDuration; // Val updated
}
if (s_RCchan == 4){
#if defined DEBUG
pwmval1 = l_PulseDuration;
#endif
#if defined TX_GUI_CONTROL
reverseChannels();
#endif // TX_GUI_CONTROL
}
s_RCchan++;
}
}
else{ // // transitioned to low
s_LastFalling = l_CurrentTime;
if (!Settings[S_PWM_PPM]) {//pwm
if ((900 < l_PulseDuration) && (l_PulseDuration < 2250)) {
#if defined DEBUG
pwmval1 = l_PulseDuration;
#endif
#ifdef NAZA
Naza.mode = 0;
if (l_PulseDuration > NAZA_PMW_HIGH) {
Naza.mode = NAZA_MODE_HIGH;
}
else if (l_PulseDuration > NAZA_PMW_MED) {
Naza.mode = NAZA_MODE_MED;
}
else if (l_PulseDuration > NAZA_PWM_LOW) {
Naza.mode = NAZA_MODE_LOW;
}
#endif
#ifdef PWM_OSD_SWITCH
MwRcData[rcswitch_ch] = l_PulseDuration;
#elif defined PWM_THROTTLE
MwRcData[THROTTLESTICK] = l_PulseDuration;
#else
pwmRSSI = l_PulseDuration;
#endif
}
}
}
}
#endif // INTD5
#if defined INTD5
ISR(PCINT2_vect) { // // Secondary Arduino D5 Atmega D5
#define PWMPIN2 DDD5
static uint8_t s_RCchan = 1;
static uint16_t s_LastRising = 0;
static uint16_t s_LastFalling = 0;
uint16_t l_PulseDuration;
uint16_t l_CurrentTime = micros();
uint8_t l_pinstatus = PIND;
sei();
l_PulseDuration = l_CurrentTime – s_LastRising;
if ((l_pinstatus & (1 << PWMPIN2))) { // transitioned to high
s_LastRising = l_CurrentTime;
if ((l_PulseDuration) > 3000) { //assume this is PPM gap so exit
s_RCchan = 1;
return;
}
if (Settings[S_PWM_PPM]) {//ppm
if (s_RCchan <= TX_CHANNELS) { // avoid array overflow if > standard ch PPM
MwRcData[s_RCchan] = l_PulseDuration; // Val updated
}
if (s_RCchan == 4){
#if defined DEBUG
pwmval2 = l_PulseDuration;
#endif
#if defined TX_GUI_CONTROL
reverseChannels();
#endif // TX_GUI_CONTROL
}
s_RCchan++;
}
}
else{ // // transitioned to low
s_LastFalling = l_CurrentTime;
if (!Settings[S_PWM_PPM]) {//pwm
if ((950 < l_PulseDuration) && (l_PulseDuration < 2150)) {
pwmval2 = l_PulseDuration;
#ifdef NAZA
Naza.mode = 0;
if (l_PulseDuration > NAZA_PMW_HIGH) {
Naza.mode = NAZA_MODE_HIGH;
}
else if (l_PulseDuration > NAZA_PMW_MED) {
Naza.mode = NAZA_MODE_MED;
}
else if (l_PulseDuration > NAZA_PWM_LOW) {
Naza.mode = NAZA_MODE_LOW;
}
#endif
#ifdef PWM_OSD_SWITCH
MwRcData[rcswitch_ch] = l_PulseDuration;
#else
MwRcData[THROTTLESTICK] = l_PulseDuration;
#endif
}
}
}
}
#endif // INTD5
void EEPROM_clear() {
for (int i = 0; i < 512; i++)
EEPROM.write(i, 0);
}
int16_t filter16( int16_t filtered, int16_t raw, const byte k) {
filtered = filtered + (raw – filtered) / k; // note extreme values may overrun. 32 it if required.
return filtered;
}
int32_t filter32( int32_t filtered, int32_t raw, const byte k) {
filtered = filtered + (raw – filtered) / k; // note extreme values may overrun. 32 it if required.
return filtered;
}
int32_t filter32F( float filtered, float raw, const byte k) {
filtered = filtered + (raw – filtered) / k; // note extreme values may overrun. 32 it if required.
return (int32_t) filtered;
}
#if defined USE_AIRSPEED_SENSOR
void useairspeed() {
#define AIRDENSITY 1.225 // Density of air kg/m3
int16_t pressuresensor = (int16_t)(sensorfilter[3][SENSORFILTERSIZE] >> 3) – Settings16[S16_AUX_ZERO_CAL];
if (pressuresensor < 0) {
pressuresensor = 0;
}
pressuresensor = ((int32_t)pressuresensor * Settings16[S16_AUX_CAL]) / 500;
constrain(pressuresensor, -410, 410);
int16_t Pa = map(pressuresensor, -410, 410, -2000, 2000); // Pressure – actual pascals
AIR_speed = (int32_t)100 * sqrt((2 * Pa) / AIRDENSITY); // Speed required in cm/s
}
#endif //USE_AIRSPEED_SENSOR
void reverseChannels(void) { //ifdef (TX_REVERSE)
for (uint8_t i = 1; i <= 4; i++) {
if (Settings[S_TX_CH_REVERSE] & (1 << i))
MwRcData[i] = 3000 – MwRcData[i];
}}
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Cercetari teoretice si aplicative privind realizarea unui quadcopter Coordonator stiintific : S.L. Dr. Ing. Besnea Daniel Absolvent Lupu Stefan -… [306184] (ID: 306184)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
