Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Autopilot voor zeilboten (automatisch stuursysteem)

Componenten en benodigdheden

Arduino UNO
× 1
Arduino Nano R3
× 1

Over dit project

Voorwoord:

Ik hou van alleen zeilen, want als een man met zijn zeilboot op zee is, heeft hij alles wat hij nodig heeft om naar een hoger niveau te evolueren. Zeilen in ruwe zee met slecht weer kan erg moeilijk zijn, maar als hij goede weerdagen met zon en mooie wind kiest, zal het genieten maximaal zijn.

Geluk betekent oneindige horizonten, perfecte sporttechnieken, optimale keuzes, maar ook menselijke dingen als een lekker drankje en een lekker broodje! Precies in deze tijd komt hulp Autopilot:het werkt in plaats van jij ondertussen heb je 17.00 uur thee &koekjes op zee. :-)

Wat Autopilot voor u kan doen:

Een zeilboot heeft geen motor en kan niet langs een geprogrammeerd pad gaan van de haven naar het strand, dan naar de visplek, om de vuurtoren draaien en terug, helemaal zelf, dat kan het niet.

Het hele werk wordt gedaan door de matroos, we moeten het op dit punt begrijpen:zeilen trimmen, het weer en de windbron/snelheid onder controle krijgen, touwen hard maken of loslaten, op het verkeer met andere boten letten, richting bepalen en sturen... Wanneer de Zeeman besluit voor een pauze, laten we zeggen slechts 10 seconden of een paar minuten (de beroemde "theetijd"), hij zet Autopilot aan. In een kopje seconden bepaalt zijn GPS positie, snelheid en richting van de boot en is in staat om de richting (route) vast te houden. Het stuursysteem, een stok die is verbonden met het roer, wordt meestal bewogen door de deskundige zeemanshanden, maar wordt nu bestuurd door Autopilot via de stappenmotor die ermee is verbonden door katrollen en touwen.

Bedien het roer is een continu werk van fijne of grove afstemming. Kleiner (lichter) is de boot en groter zullen de richtingsveranderingen zijn die er invloed op hebben:zeegolven, richting en druk van de wind, verschuiving van het gewicht aan boord door zeemansbewegingen, zeestromingen. Maar de Sailor is altijd wakker, zelfs met de automatische piloot aan, en brengt wijzigingen aan in de werkelijke route via de afstandsbediening :er zitten 4 knoppen op, gelabeld +1 -1 +10 -10, voor kleine of grote veranderingen in graden, het verhogen of verlagen van de waarde. Deze knoppen zijn aanwezig op de stuurautomaat ook de groene (rechts) en de rode (links). De blauwe knop (midden) is voor het activeren of deactiveren van de Autopilot, de pauze. Het is ook een zwarte knop voor het instellen van parameters in het geheugen.

Het circuit:

De belangrijkste verwerking wordt gedaan door MCU Arduino Uno . De andere MCU, Arduino Nano , is de waakhond:ik weet dat er een soort waakhond in de Uno bestaat, maar ik deed het graag met een onafhankelijke externe microcontroller, het is een levenslange droom die ik heb gedekt, ik ben nu gelukkig! Uno moet Nano voeden via pin 3 -> A0 hoog/laag, 5/0 volt, minstens één keer per 2,5 seconden (feedingInterval); zo niet, dan betekent dit dat de Uno "slaapt" of "geblokkeerd" is, en Nano reset Uno... Het is nog nooit gebeurd, kun je geloven?

Het wordt gebruikt als een populair scherm in combinatie met een i2c-circuitconverter beide aan elkaar gesoldeerd, uiteindelijk met slechts 4 draden om digitale pinnen aanzienlijk te sparen om met Uno te communiceren. Ook de manier om knoppen en afstandsbediening aan te sluiten wordt gedaan door weerstandsspanningsdelers om het doel te bereiken om zo min mogelijk MCU-poorten te gebruiken; Ik heb gekozen voor 1% precisieweerstanden, de analoge vergelijkingswaarden moeten tussen de waarden liggen die ik in de code heb ingevoerd; in het geval dat sommige knoppen niet worden herkend omdat je een ander soort weerstand kiest, breng dan ook wat wijzigingen aan in constanten (wijzig de code bij "checkRfRC()" en "checkHWButtons()"). Het RF 433Mhz Remote Control (RC) circuit werkt goed; om de afstandsdekking en de kansen op succes te verbeteren, heb ik een spoelantenne toegevoegd die je zelf zou kunnen maken met een stuk koperdraad; Ik heb het op 10 meter afstand getest, maar ik denk dat het zelfs op 20 meter of meer kan werken, meer dan genoeg gezien de doelzeilboot die ik gebruikte om Autopilot te testen, slechts 4,20 meter lang was.

Voor de GPS-eenheid Ik gebruikte in het begin een goede EM406A maar helaas ontdekte ik dat hij last had van Week-Rollover-Bug, hij was te oud, toen moest ik hem vervangen door een uitstekende en populaire Beitian BN-220T. Stel het met zijn configuratiesoftware in om 2 keer per seconde (2Hz) uit te "spugen", alleen de noodzakelijke "$GNRMC" NMEA seriële zin. De GPS stuurt (TX) seriële data naar pin 0 (RX) van Uno. De gegevens bevatten alle navigatiegegevens die worden gebruikt om de door de motor uit te voeren correctie te berekenen:datum, tijd, positie breedte- en lengtegraad, ware koers, snelheid en geldigheid van satellieten. Omdat Arduino's IDE-programmering ook pin 0 (RX)-poort gebruikt, vergeet niet om de GPS tijdelijk los te koppelen tijdens deze bewerking...

Een andere droom van mij was een EEPROM gebruiken . De IC 2404 is een prachtige 512 bytes i2c geïntegreerde schakeling die ik heb gebruikt om in deze geheugenchip enkele parameters voor stappenmotorbewegingen te lezen/schrijven die ik later in de paragraaf "Software" zal uitleggen.

Onderdelenlijst:

  • Arduino Uno als MCU
  • Arduino Nano als WatchDog
  • Beitian BN-220T GPS
  • Stappenmotor, model 23LM, 54 stappen =1/4 omwenteling
  • Controller Keyes L298 voor motor
  • RF433Mhz RC XD-YK04 + 4 knoppen afstandsbediening + spoelantenne
  • 6 Knoppen normaal open (2xRood, 2xGroen, 1xZwart en 1xBlauw)
  • Schakelaar voor aan/uit (wit)
  • Vrouwelijke + mannelijke 6-pins ronde connectoren voor externe stappenmotor
  • Zoemer
  • Display LCD1602 2x16 tekens + i2c-convertercircuit
  • 3 LEDS (rood, blauw en geel))
  • IC 24c04 i2c eeprom
  • IC 4051-multiplexer
  • Batterij LiPo 2s 7.4v 2600mA
  • IC 7805 spanningsregelaar + warmteafvoer
  • Thermistor NTC MF52-103 10k
  • Resetbare zekering 2A
  • 6x 1N4148 diodes (D1-D6)
  • Weerstanden op vermogensafscherming (R1-R4=10k, R5=100k)
  • Weerstanden op stuurautomaat schild (R1=330, R2=1k, R3=2k, R4=5.1k, R5=1k, R6/R7/R14=330, R8-R13=10k, R15=10M)
  • condensatoren (C1=470uF 16v, C2=100n)
  • 2W 0.22 Ohm weerstand (R6)
  • Mannelijke pinnen
  • Vrouwelijke long-pins headers
  • Behuizing transparant en "waterdicht"

Er zijn een paar sensoren op het circuit allemaal verbonden met Arduino Uno met behulp van IC 4051 multiplexer . Het is een Thermistor om de temperatuur van de verwarmingsdissipator van de spanningsregelaar onder controle te houden, een 2W-weerstand en 4x10k als spanningsdelers om Ampere te berekenen als stroomverbruik van het hele circuit. Ook de accuspanning wordt onder controle genomen:het is bekend dat LiPo van cruciaal belang is wanneer afzonderlijke elementen worden ontladen onder 3,3 V; deze schakeling heeft een LiPo met twee elementen (2S) in één pakket, bij lage spanning (onder 7.0v) de zoemer zal u informeren met korte snelle piepjes. Wacht niet te lang met uitschakelen, en laad snel weer op! De Leds :gele knippert met 1 Hz om u te laten weten dat de WatchDog werkt; de blauwe is aan als Autopilot aan staat, uit als hij is gepauzeerd; de rode led knippert wanneer een van de knoppen op de afstandsbediening wordt ingedrukt.

Alle circuits werken op 5.0v geleverd door LiPo 2S 7.4v 2600mA/h batterij en IC 7805 spanningsregelaar . De stroom mag niet groter zijn dan 800mA, maar is meestal rond de 100-450mA. Zet er een verwarmer op . De thermistor wordt erop geplaatst en de zoemer piept als de temperatuur boven de 50°C komt.

De PCB-printplaten en montage:

Wordt gebruikt enkelzijdige PCB's om die reden moest ik een paar draadjumpers (de stippellijnen) toevoegen om routes voor hele circuits op te lossen. Hier ziet u de componenten gezichten maar hieronder heb je alle bestanden, componenten en soldeer gezichten, gespiegeld, om te downloaden en af ​​te drukken door middel van een laserprinter op "gele" of "blauwe" vellen. Ik heb de gele gebruikt, maar ze zeggen dat de blauwe beter zijn (maar de prijs is aanzienlijk hoger). Denk er bij het afdrukken aan de tonerbesparingsinstellingen uit te schakelen, maar gebruik in plaats daarvan een resolutie van 1200 dpi voor een diep, echt zwart resultaat. Het toneroverdrachtsproces van magische vellen naar PCB's wordt gemaakt door het gebruik van een heet strijkijzer... Afdrukken op beide zijden, ook op het oppervlak van de componenten, maakt het gemakkelijk om de positionering van items te herkennen en maakt het project zelfs "professioneel".

Beide PCB's zijn zo groot dat ze de ene over de andere Arduino Uno passen als een stapel :eerst Power unit dan Autopilot unit over alles.

Mijn keuze was om alle dingen samen te voegen, PCB's, MCU's, RC, Motor Driver-circuit, batterij, GPS, knoppen, schakelaar, draden, connectoren, enz. Ik dacht ze op een dag opnieuw te gebruiken:ik heb ze niet aan elkaar gesoldeerd, ik gebruikt kopteksten en populaire Dupont-draden/-verbindingen in plaats van. Er zijn dan ongeveer 200 ongesoldeerde verbindingen, dit betekent dat er van tijd tot tijd onverwachte en ongewenste storingen of ander gedrag van het circuit kan optreden, het is normaal. Suggestie is om alles te solderen voor een stabieler circuit!

Parameters Sensorwaarden instellen en weergeven:

Op de zwarte knop . drukken aan de zijkant van de doos gaat naar de configuratiemodus; dit kan ook tijdens actieve navigatie, het is niet nodig om eerst Pauze in te voeren. De 1e pagina van het display toont batterijspanning (V=7,83), stroomverbruik (mA=177) en temperatuur van de thermistorsensor nabij dissipator (38°C); door steeds opnieuw op de zwarte knop te drukken, gaat u naar de volgende pagina's; de 2e, 3e, 4e en 5e pagina tonen de onderstaande parameters en u kunt deze waarden wijzigen door middel van de -1 en +1 knoppen. Op de 6e pagina staat "Updating..." als u iets heeft gewijzigd, worden de waarden opgeslagen in het EEPROM-geheugen.

  • Interval: d.w.z. 2000 mSec, is de tijd tussen de ene poging en de andere door de stappenmotor om "H" op weg naar de "R"-route te herstellen, door de roerstok naar rechts of links te bewegen;
  • Minimaal: d.w.z. 2°, is het minimum aantal graden buiten de route om de automatische piloot te laten ingrijpen; tot deze waarde blijft het roer stabiel in het midden;
  • Max: d.w.z. 40° is de maximale stuurverandering per keer door de stappenmotor; als de gemaakte berekening voor 50° verandering is, zal Stepper in werkelijkheid slechts 40° bewegen;
  • Coëffic.: d.w.z. 1,50 x °, is de coëfficiënt voor stuurverandering per keer; als de gemaakte berekening voor een verandering van 40 ° is, zal de stappenmotor in werkelijkheid bewegen voor (40 x 1,50) =60 °;

Deze parameters zijn nodig voor het finetunen van Autopilot wanneer geïnstalleerd op de zeilboot. Responsiviteit, gevoeligheid en soepelheid hangen af ​​van de diameter van de katrollen, het aantal katrollen, de diameter van de hoofdkatrol op de stappenmotor, de gevoeligheid van het roer, hoe lang de roerstok erop is aangesloten, enzovoort. Laat alles installeren en laat proberen ervaring op te doen aan boord. Kies natuurlijk een zonnige mooie dag met lichte wind voor alle testfase!

Hoe het "live" werkt:

U vaart op zee, op het meer of gewoon rond de haven. Het is Tea Time en je cola en je favoriete broodje wachten in de zak. Hier zijn we:schakel Autopilot aan en laat het satelliet GPS-fix nemen, u zou nu op het display de werkelijke snelheid in knopen, klok en koersrichting moeten aflezen, dwz H270° (R=te volgen route, H=werkelijke koers) in graden (onthoud 180°=zuiden, 270° =west, 360° of 0°=noord en 90°=oost). R- en H-waarden zijn hetzelfde in de pauzemodus (STOP wordt weergegeven). Verbind nu het stuurkoord, van de stappenmotor naar de roerstok, en druk op de blauwe knop om het sturen van de stuurautomaat te starten; op dit punt houdt Autopilot R=routerichting vast en neemt het onder controle wat er gebeurt met H=heading. Kopnummer verandert zeker , langzaam of snel, afhankelijk van de weersomstandigheden waar we het al over hadden. Stuurautomaat probeert dan te herstellen naar R=routerichting correcties makend, bijv. -10°, +5°, etc. totdat H-waarde gelijk is aan R-waarde . U kunt bepaalde wijzigingen op de route doorvoeren en u kunt het nummer wijzigen met de rode en groene knoppen op het apparaat (-1 -10 +1 +10) of met de afstandsbediening. Om de controle terug te nemen van de besturing je hoeft alleen maar op de blauwe knop Pauze te drukken, het touw los te koppelen van de roerstok en het werk met je handen voort te zetten. Goed gedaan.

Softwarekant:

De code is vrij lang, maar ik hoop dat het duidelijk genoeg is om gemakkelijk te begrijpen. Ik zou in ieder geval uitleggen hoe het ervoor staat. De schets gebruikt ongeveer 65% van het programma en ongeveer 45% van het geheugen. Zelfs bij het gebruik van String-klasse, meestal voor het manipuleren van seriële NMEA-zinnen, is de hele uitwerkingsstroom stabiel en solide; het gebruikt "serialEvent()" om twee keer per seconde gegevens van GPS te ontvangen , roept dan "nmeaExtractData()" aan en tot slot controleert het het datapakket met "nmea0183_checksum() om zeker te zijn van de gegevensintegriteit. Als u een ander merk en model GPS gebruikt, zorg er dan voor dat de zinnen dezelfde structuur hebben of u moet hier enkele wijzigingen aanbrengen Bijvoorbeeld EM406A gebruikt "$GPRMC" pakket-ID , BT220 gebruikt in plaats daarvan "$GNRMC"... slechts een kleine naamswijziging... Een handige link kan u helpen bij de checksum-test:https://nmeachecksum.eqth.net - Hier een voorbeeld van een volledige NMEA-zin, deze bevat :id, tijd, geldigheid, breedtegraad, lengtegraad, snelheid, ware koers, datum, variatie en controlesom.

$GPRMC, 095836.000, A, 4551.9676, N, 01328.7118, E, 2.09, 341.84, 280519,, *08

Tijdens "Setup()" wordt de EEPROM gecontroleerd :indien nieuw of onbekend wordt het geïnitialiseerd (geformatteerd). Parameters in het geheugen zijn lezen/schrijven als bytes:0=0x29, 1=0x00, 2-3=interval, 4-5=min, 6-7=max, 8-11=coëfficiënt (byte, byte, int, int, vlot). Ik ben voorzichtig omgegaan met EEPROM r/w operaties, misschien te defensief... Sensoren worden elke 10 seconden gecontroleerd via "readMuxSensors()" door multiplexer en kan een alarm veroorzaken als de batterij bijna leeg is of de temperatuur hoog is. De resolutie van het stroomverbruik is laag, stappen van ongeveer 40mA. Hardware- en RC-knoppen worden continu gecontroleerd; wat ze doen hangt af van de "IsSetup"-booleaanse waarde en het scherm dat "RefreshDisplay()" doet . De kern van de code is de STEERING CONTROL-sectie die de "gomotor()"-functie aanroept om de Stepper heen en weer te bewegen; ja, hij mag het roer 10° naar rechts verplaatsen en na intervalwaarde gaat hij terug naar nul roerstand, enzovoort na een nieuwe rekenronde. Zoals gezegd, wordt er ook tijdens Setup gestuurd, omdat het slechts een paar knoppen en weergavegedrag beïnvloedt. Whatchdog voeren is heel eenvoudig maar belangrijk:zet de pin zo snel mogelijk aan/uit.

Hoe te installeren op een zeilboot:

Zoals op onderstaande foto te zien is heb ik ervoor gekozen om de Autopilot en de Stappenmotor op het achterschip te plaatsen, beide goed vastgezet met bouten etc.; een touw met een diameter van 6 mm begint bij de katrol van de hoofdmotor en gaat rond twee andere katrollen die aan beide zijden zijn geplaatst. Deze twee katrollen moeten aan de boot worden "vastgemaakt" door middel van twee ringen van bungee om het touw lichtjes op spanning te houden. Op dit punt moet u tenslotte beslissen hoe u het touw aan de roerstok bevestigt (tijdelijke verbinding); het moet worden aangesloten terwijl u wilt. Autopilot is in actie, eenvoudig aan te sluiten en los te koppelen. Houd het Autopilot-systeem uit de buurt van water! :-)

Nieuws en updates:

  • 10.05.2020, toegevoegd voor het downloaden van .STEP 3D CAD-projectbestanden voor stepper-poelie (door mij) en montageplaat (door Andrew Barney), en een 3D-voorbeeldafbeelding ervan.

Disclaimer en waarschuwingen:

Laten we zeggen dat dit een spel is dat we hier spelen, niets naar serieus nemen! Een paar jaar geleden ging ik voor een lange reis, 16 maanden, rond de wereld op een zeilboot. We hebben uitgebreid genavigeerd met een echte stuurautomaat (NIET DIT EEN!) in alle weersomstandigheden, zelfs in slechte weersomstandigheden. Een echte stuurautomaat is iets zeer sterk zowel hardware als software waarop u moet vertrouwen veel. Deze Arduino Autopilot in plaats daarvan is een fantastisch spel om te spelen met en om tijd voor plezier besteden.

Veel plezier!

Marco Zonca

Code

  • Schets stuurautomaat (voor Uno)
  • WatchDog-schets (voor Nano)
Schets stuurautomaat (voor Uno)Arduino
/* Deze schets fungeert als stuurautomaat voor kleine zeilboten, door Marco Zonca, 2019 Arduino UNO als CPU, Arduino Nano als waakhond, GPS BT-220 nmea, stappenmotor + controller, rf433Mhz RC, 6 knoppen, zoemer, i2c display, 2 leds, i2c 24c04 eeprom, Mux 4051 voor sensoren, lipo 2s 7.4v 2600mA, 7805 spanningsregelaar, thermistor;*/#include #include #include # include String inputString ="";String nm_time ="00:00:00";String nm_validity ="V";String nm_latitude ="ddmm.mmmm'N";String nm_longitude ="dddmm.mmmm'E ";String nm_knots ="0.0kn";float nmf_knots =0.0;String nm_truecourse ="360";float nmf_truecourse =360;String nm_date ="dd/mm/jjjj";String nm_routetofollow ="000";float nmf_routetofollow =0; unsigned long previousStearingMillis =0; unsigned long currentStearingMillis =0; unsigned long prevCheckSensorsMillis =0; unsigned long currCheckSensorsMillis =0;int CheckSensorsInterval =10000;bool stringComplete =false;bool isfirstfix =true;bool ispause =true;bool isStearing =false;bool isSetup =false;int s=0;int y=0;int z=0;int d=0;int rfRemoteControlValue =0;int HWButtonValue =0;int SetupParameter =0;float calcmove =0;float cm =0;float Stearing =0;float prevStearing =0;float t =0;int EEdisk =0x50;int EEid1 =0x29;int EEid2 =0x00;unsigned int EEaddress =0;unsigned int EEbytes =12;byte EEdata[12];byte EEbytedata;int EEerr =0;float SensorVBatt=0;float SensorVRes=0;float SensorTemp=0;float SensormAmp=0;// volgende parameters zijn de standaardwaarden, maar zijn lezen/schrijven in eeprom// eeprom wordt geïnitialiseerd als op adressen 0 en 1 de inhoud verschillend is adrestype opmerkingen// 0-255 bytes bij 0x50 EEdisk, 256-512 bytes bij 0x51 (niet gebruikt) ---------- -------------------------------------------------- ---// 0 1B byte 01001001 (0x29 als stuurautomaatproject id1)// 1 1B byte 00000000 (0x00 " " id2)int StearingInterval =2000; // millis tussen proberen en terug 2 2B int StearingInterval 1000-5000 stappen 100int StearingMinToMove =2; // compass_degrees 4 2B int StearingMinToMove 0-20 stappen 1int StearingMaxMove =40; // compass_degrees 6 2B int StearingMaxMove 10-45 stappen 1float StearingCoeffMove =1.5; // gebruikt als (compass_degrees * coeff) 8 4B float StearingCoeffMove 0.1-4 stappen 0.1// 12 free//byte bStearingInterval[sizeof(int)];byte bStearingMinToMove[sizeof(int)];byte bStearingMaxMove[sizeof(int)];byte bStearingCoeffMove[sizeof(float)];int prev_StearingInterval=0;int prev_StearingMinToMove=0;int prev_StearingMaxMove=0;float prev_StearingCoeffMove=0;const int ledpause 7Pin =2;const int =2;const int =// 00=Vin 01=Vbatt 10=Tempconst int MuxSelBit1Pin =6; // const int motorenABenablePin =13;const int MuxIOPin =14;const int ButtonsPin =15;const int rfRemoteControlPin =16;const int speakerPin =17;const int RCleftbutton =201;const int RCrightbutton =202;const int RCleft10button =203; const int RCright10knop =204;const int HWlinksknop =101;const int HWrightknop =102;const int HWpauzeknop =103;const int HWsetupknop =104;const int HWleft10knop =105;const int HWright10knop =106;const intRevolution motorSteps; // 200 voor model 23LM, 54 stappen =1/4 van omwenteling LiquidCrystal_I2C lcd (0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIEF); Stappenmotor (motorStepsPerRevolution, 9, 10, 11, 12 ); ongeldige setup () { Serial.begin (4800); lcd.begin(16,2); Draad.begin(); motor.setSpeed(60); inputString.reserve(200); pinMode (motorenABenablePin, OUTPUT); pinMode (MuxSelBit0Pin, UITGANG); pinMode (MuxSelBit1Pin, UITGANG); digitalWrite (motorenABenablePin, LAAG); digitalWrite (MuxSelBit0Pin, LAAG); digitalWrite (MuxSelBit1Pin, LAAG); pinMode (ledpauzePin, UITGANG); pinMode (watchDogPin, OUTPUT); digitalWrite(ledpausePin, LAAG); digitalWrite (watchDogPin, LAAG); // read+check EEPROM (formatteren indien nieuw (of niet geïdentificeerd)) lcd.clear(); lcd.setCursor(0,0); lcd.print("Geheugencontrole..."); lcd.setCursor(0,1); voor (s =0; s =CheckSensorsInterval) { readMuxSensors(); if ((SensorVBatt <=7.0) || (SensorTemp>
=50)) { lcd.clear(); lcd.setCursor(0,0); lcd.print("Alarmsensoren! "); lcd.setCursor(1,1); lcd.print("V="); lcd.print (SensorVBatt); lcd.print(" "); lcd.print(int(SensorTemp)); lcd.schrijven (0xDF); lcd.print("C"); NewTone (speakerPin,10); vertraging (1000); geenNieuweTone(); } prevCheckSensorsMillis =currCheckSensorsMillis; } // STUURBEDIENING ---------------- currentStearingMillis =millis(); if (currentStearingMillis - previousStearingMillis>=StearingInterval) {if (isStearing ==false &&ispause ==false) { // probeer (verplaats stearing) calcmove =nmf_routetofollow - nmf_truecourse; if (calcmove <(-180)) { calcmove =calcmove + 360; } else { if (calcmove> (+180)) { calcmove =calcmove - 360; } } if (abs(calcmove)>=StearingMinToMove) { if (abs(calcmove)>=StearingMaxMove) { if (calcmove <0) { cm =(StearingMaxMove * -1); calcmove =cm; } else { cm =(StearingMaxMove * 1); calcmove =cm; } } Stearing =(calcmove * StearingCoeffMove); gomotor(int((Stuur * 216) / 360)); // 54 stappen =1/4 van omwenteling prevStearing =Sturen; isStearing =waar; } } else { // ga terug (verplaats stearing naar "nul" positie) if (isStearing ==true) { Stearing =(prevStearing * -1); gomotor(int((Stuur * 216) / 360)); // 54 stappen =1/4 van omwenteling Sturen =0; prevStearing =0; isStearing =onwaar; } } previousStearingMillis =currentStearingMillis; } // RC RF-KNOPPEN ------------------ rfRemoteControlValue =checkRfRC(); if (rfRemoteControlValue) { switch (rfRemoteControlValue) { case RCleftbutton:// Linker RC-knop goleft (); pauze; case RCrightbutton:// Rechter RC-knop goright(); pauze; behuizing RCleft10button:// Left-10 RC-knop goleft10(); pauze; behuizing RCright10button:// Rechts+10 RC-knop goright10(); pauze; } } // KNOPPEN ------------------------ HWButtonValue =checkHWButtons(); if (HWButtonValue) { switch (HWButtonValue) { case HWleftbutton:// Left (-1) HW-knop if (isSetup ==false) { goleft (); } else { setupMinus(); } pauze; case HWrightbutton:// Rechts(+1) HW-knop if (isSetup ==false) { goright(); } else { setupPlus(); } pauze; case HWpauzeknop:// Pauzeer HW-knop gopause(); pauze; case HWsetup-knop:// Setup HW-knop gosetup(); pauze; behuizing HWleft10button:// Links(-10) HW-knop goleft10(); pauze; behuizing HWright10button:// Rechts (+10) HW-knop goright10(); pauze; } } // GPS NMEA ------------------ if (stringComplete ==true) { // NMEA-zin ontvangen via seriële poort RX bool ret; ret =nmeaExtractData(); invoerString =""; stringComplete =onwaar; if (ret ==true) { RefreshDisplay(); } } // WATCHDOG FEEDING ---------------- if (digitalRead (watchDogPin) ==LAAG) {digitalWrite (watchDogPin, HIGH); } else {digitalWrite(watchDogPin, LOW); }}// lees sensoren op multiplexervoid readMuxSensors () { float Vo =0; vlotter n =0; vlotter n1 =0; float v1ad =0; float v2ad =0; vlotter corr =0; vlotter R1 =10000; float logR2 =0; vlotter R2 =0; vlotter T =0; vlotter c1 =1.09249522e-03; vlotter c2 =2.378405444e-04; vlotter c3 =2.019202697e-07; digitalWrite (MuxSelBit0Pin, LAAG); // 00=Vbatt digitalWrite (MuxSelBit1Pin, LAAG); n =analoog lezen (MuxIOPin); v1ad=n; n1=(((10.00 * n) / 1023,00)); SensorVBatt=(n1 + ((n1 * 0,0) /100)); // willekeurige correctie (niet actief =0,0%), digitalWrite (MuxSelBit0Pin, LOW); // 01=Vres digitalWrite (MuxSelBit1Pin, HOOG); n =analoog lezen (MuxIOPin); v2ad=n; n1=(((10.00 * n) / 1023,00)); SensorVRes=(n1 + ((n1 * 0,0) /100)); // willekeurige correctie (niet actief =0,0%), digitalWrite (MuxSelBit0Pin, HIGH); // 10=NTC Temp digitalWrite (MuxSelBit1Pin, LAAG); Vo =analoog lezen (MuxIOPin); R2 =R1 * (1023,0 / Vo - 1,0); logR2 =log(R2); T =(1,0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2)); SensorTemp =T - 273.15; // Celsius n =(v1ad - v2ad); n1 =(n / 0,22) * 1000,00; SensormAmp =(((10.00 * n1) / 1023.00));}// gegevens extraheren uit nmea inputStringbool nmeaExtractData () { bool ret =false; //true if nmea zin =$GNRMC en geldige CHKSUM if ((inputString.substring(0,6) =="$GNRMC") &&(inputString.substring(inputString.length()-4,inputString.length()- 2) ==nmea0183_checksum(inputString))) { y=0; for (s =1; s <11; s ++) { y=inputString.indexOf(",",y); switch (s) { case 1://time z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_time=inputString.substring(y+1,y+2+1)+":"+inputString.substring(y+1+2,y+4+1)+" :"+inputString.substring(y+1+4,y+6+1); } y=z; pauze; geval 2://geldigheid z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_validity=inputString.substring(y+1,y+1+1); } y=z; pauze; geval 3://latitude z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_latitude=inputString.substring(y+1,y+2+1)+""+inputString.substring(y+1+2,y+10+1)+"' "; } y=z; pauze; geval 4://noord/zuid z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_latitude=nm_latitude + inputString.substring(y+1,y+1+1); } y=z; pauze; geval 5:// lengtegraad z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_longitude=inputString.substring(y+1,y+3+1)+""+inputString.substring(y+1+3,y+11+1)+"' "; } y=z; pauze; geval 6://east/west z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_longitude=nm_longitude + inputString.substring(y+1,y+1+1); } y=z; pauze; geval 7://snelheidsknopen z=inputString.indexOf(",",y+1); if (z>(y+1)) { nmf_knots=inputString.substring(y+1,z).toFloat(); t=roundOneDec(nmf_knots); nm_knots=String(t,1)+"kn"; } y=z; pauze; geval 8://true course z=inputString.indexOf(",",y+1); if (z>(y+1)) { nmf_truecourse=inputString.substring(y+1,z).toFloat(); d=nmf_truecourse; nm_truecourse=d; } y=z; pauze; geval 9:// datum z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_date=inputString.substring(y+1,y+2+1)+"/"+inputString.substring(y+1+2,y+4+1)+" /20"+inputString.substring(y+1+4,y+6+1); } y=z; pauze; geval 10:// uitspraken breken; standaard:// instructies breken; } } if ((isfirstfix ==true) || (ispause ==true)) { nm_routetofollow=nm_truecourse; nmf_routetofollow=nmf_truecourse; isfirstfix=false; } ret=waar; } return ret;}// verhoging (+) parameterwaarde tijdens setupvoid setupPlus () { switch (SetupParameter) { case 2:// interval StearingInterval =(StearingInterval + 100); if (StearingInterval> 5000) { StearingInterval =5000; } pauze; geval 3://min. om te bewegen StearingMinToMove =(StearingMinToMove + 1); if (StearingMinToMove> 20) { StearingMinToMove =20; } pauze; geval 4://max. move StearingMaxMove =(StearingMaxMove + 1); if (StearingMaxMove> 45) { StearingMaxMove =45; } pauze; geval 5://coëfficiënt StearingCoeffMove =(StearingCoeffMove + 0,1); if (StearingCoeffMove> 4) { StearingCoeffMove =4; } pauze; } vertraging (200); RefreshDisplay ();}// afname (-) parameterwaarde tijdens setupvoid setupMinus () { switch (SetupParameter) { geval 2:// interval StearingInterval =(StearingInterval - 100); if (StearingInterval <1000) { StearingInterval =1000; } pauze; geval 3://min. om te verplaatsen StearingMinToMove =(StearingMinToMove - 1); if (StearingMinToMove <0) { StearingMinToMove =0; } pauze; geval 4://max. move StearingMaxMove =(StearingMaxMove - 1); if (StearingMaxMove <10) { StearingMaxMove =10; } pauze; geval 5://coëfficiënt StearingCoeffMove =(StearingCoeffMove - 0,1); if (StearingCoeffMove <0,1) { StearingCoeffMove =0,1; } pauze; } vertraging (200); RefreshDisplay();}// motor control (+)=forward (-)=backwardsvoid gomotor(int stepsToMove) {digitalWrite(motorenABenablePin, HIGH); motor.stap(stappenToMove); digitalWrite(motorsABenablePin, LOW);}// refresh data on displayvoid RefreshDisplay() { if (isSetup ==false) { //---------normal lcd.clear(); lcd.setCursor(0,0); lcd.print("R"+nm_routetofollow); lcd.write(0xDF); lcd.print(" H"+nm_truecourse); lcd.write(0xDF); if (ispause ==true) { lcd.print(" STOP"); } else { if (Stearing> 0) { lcd.print(" +"); } if (Stearing ==0) { lcd.print(" "); } if (Stearing <0) { lcd.print(" "); } lcd.print(int(Stearing)); } lcd.setCursor(0,1); lcd.print(nm_time+" "+nm_knots); } if (isSetup ==true) { //-----------setup lcd.clear(); lcd.setCursor(0,0); lcd.print("setup:"); switch (SetupParameter) { case 1://display sensors readMuxSensors(); lcd.print("V="); lcd.print(SensorVBatt); lcd.setCursor(1,1); lcd.print("mA="); lcd.print(int(SensormAmp)); lcd.print(" "); lcd.print(int(SensorTemp)); lcd.write(0xDF); lcd.print("C"); break; case 2://interval lcd.print("interval"); lcd.setCursor(7,1); lcd.print(StearingInterval); lcd.print(" mSec"); break; case 3://min. to move lcd.print("minimum"); lcd.setCursor(7,1); lcd.print(StearingMinToMove); lcd.write(0xDF); break; case 4://max. move lcd.print("max"); lcd.setCursor(7,1); lcd.print(StearingMaxMove); lcd.write(0xDF); break; case 5://coefficient lcd.print("coeffic."); lcd.setCursor(7,1); lcd.print(StearingCoeffMove); lcd.print(" x "); lcd.write(0xDF); break; } }}/* SerialEvent occurs whenever a new data comes in the hardware serial RX. This routine is run between each time loop() runs, so using delay inside loop can delay response. Multiple bytes of data may be available.*/void serialEvent() { while (Serial.available()) { char inChar =(char)Serial.read(); inputString +=inChar; // if the incoming character is a newline, set a flag so the main loop can // do something about it if (inChar =='\n') { stringComplete =true; } } }//calculate checksum of nmea sentenceString nmea0183_checksum(String nmea_data) { int crc =0; String chSumString =""; int ik; // ignore the first $ sign, checksum in sentence for (i =1; i <(nmea_data.length()-5); i ++) { // remove the - 5 if no "*" + cksum + cr + lf are present crc ^=nmea_data[i]; } chSumString =String(crc,HEX); if (chSumString.length()==1) { chSumString="0"+chSumString.substring(0,1); } chSumString.toUpperCase(); return chSumString;}//check RC which button is pressedint checkRfRC() { int n =0; int res =0; n =analogRead(rfRemoteControlPin); if ((n>350) and (n<460)) { // button A res =RCleftbutton; } if ((n> 90) and (n<190)) { // button B res =RCrightbutton; } if ((n>540) and (n<640)) { // button C res =RCleft10button; } if ((n>225) and (n<325)) { // button D res =RCright10button; } return res; }//check HW which button is pressedint checkHWButtons() { int n =0; int res =0; n =analogRead(ButtonsPin); //Serial.println(n); if ((n>465) and (n<565)) { // button left res =HWleftbutton; } if ((n>290) and (n<390)) { // button right res =HWrightbutton; } if ((n>130) and (n<220)) { // button pause res =HWpausebutton; } if ((n>625) and (n<725)) { // button setup res =HWsetupbutton; } if ((n>975) and (n<1075)) { // button left-10 res =HWleft10button; } if ((n>800) and (n<900)) { // button right+10 res =HWright10button; } return res; }void gosetup() { // setup button if (isSetup ==false) { SetupParameter =1; isSetup =true; } else { if (SetupParameter <5) { SetupParameter ++; } else { if (prev_StearingInterval !=StearingInterval || prev_StearingMinToMove !=StearingMinToMove || prev_StearingMaxMove !=StearingMaxMove || prev_StearingCoeffMove !=StearingCoeffMove) { lcd.clear(); lcd.setCursor(0,0); lcd.print("updating... "); vertraging (1000); goupdateEEPROM(); if (EEerr) { lcd.print("E="); lcd.print(EEerr); vertraging (1000); } prev_StearingInterval =StearingInterval; prev_StearingMinToMove =StearingMinToMove; prev_StearingMaxMove =StearingMaxMove; prev_StearingCoeffMove =StearingCoeffMove; } isSetup =false; } } NewTone (speakerPin,2000); delay(200); noNewTone(); RefreshDisplay();}void goupdateEEPROM() { EEaddress =0; //id1 EEdata[0] =EEid1; EEbytedata =EEid1; writeEEPROM (EEdisk, EEaddress, EEbytedata); EEaddress =1; //id2 EEdata[1] =EEid2; EEbytedata =EEid2; writeEEPROM (EEdisk, EEaddress, EEbytedata); memcpy(bStearingInterval, &StearingInterval, sizeof(int)); memcpy(bStearingMinToMove, &StearingMinToMove, sizeof(int)); memcpy(bStearingMaxMove, &StearingMaxMove, sizeof(int)); memcpy(bStearingCoeffMove, &StearingCoeffMove, sizeof(float)); memcpy(EEdata+2,bStearingInterval,sizeof(int)); memcpy(EEdata+4,bStearingMinToMove,sizeof(int)); memcpy(EEdata+6,bStearingMaxMove,sizeof(int)); memcpy(EEdata+8,bStearingCoeffMove,sizeof(float)); for (s =2; s  360) { nmf_routetofollow =1; } d=nmf_routetofollow; nmf_routetofollow=d; nm_routetofollow=d; NewTone (speakerPin,800); delay(200); noNewTone(); } else { NewTone (speakerPin,1000); delay(50); noNewTone(); } RefreshDisplay();}void goright10() { // right 10x button/RC if (ispause ==false) { for (s =1; s <11; s ++) { nmf_routetofollow ++; if (nmf_routetofollow> 360) { nmf_routetofollow =1; } } d=nmf_routetofollow; nmf_routetofollow=d; nm_routetofollow=d; NewTone (speakerPin,800); delay(200); noNewTone(); } else { NewTone (speakerPin,1000); delay(50); noNewTone(); } RefreshDisplay();}void gopause() { // pause button/RC if (ispause ==true) { ispause=false; digitalWrite(ledpausePin, HIGH); NewTone (speakerPin,50); delay(200); NewTone (speakerPin,200); delay(800); noNewTone(); } else { ispause=true; digitalWrite(ledpausePin, LOW); NewTone (speakerPin,200); delay(200); NewTone (speakerPin,50); delay(800); noNewTone(); } RefreshDisplay();}// reading eeprombyte readEEPROM (int diskaddress, unsigned int memaddress) { byte rdata =0x00; Wire.beginTransmission (diskaddress); Wire.write (memaddress); if (Wire.endTransmission () ==0) { Wire.requestFrom (diskaddress,1); if (Wire.available()) { rdata =Wire.read(); } else { EEerr =1; //"READ no data available" } } else { EEerr =2; //"READ eTX error" } Wire.endTransmission (true); return rdata;}// writing eepromvoid writeEEPROM (int diskaddress, unsigned int memaddress, byte bytedata) { Wire.beginTransmission (diskaddress); Wire.write (memaddress); Wire.write (bytedata); if (Wire.endTransmission () !=0) { EEerr =3; //"WRITING eTX error" } Wire.endTransmission (true); delay(5); }// round zero decimalfloat roundZeroDec(float f) { float y, d; y =f*1; d =y - (int)y; y =(float)(int)(f*1)/1; if (d>=0.5) { y +=1; } else { if (d <-0.5) { y -=1; } } return y;}// round one decimalfloat roundOneDec(float f) { float y, d; y =f*10; d =y - (int)y; y =(float)(int)(f*10)/10; if (d>=0.5) { y +=0.1; } else { if (d <-0.5) { y -=0.1; } } return y;}// round two decimalfloat roundTwoDec(float f) { float y, d; y =f*100; d =y - (int)y; y =(float)(int)(f*100)/100; if (d>=0.5) { y +=0.01; } else { if (d <-0.5) { y -=0.01; } } return y;}
WatchDog sketch (for Nano)Arduino
/* * This sketch is a Watchdog to keep CLIENT under control, on Arduino NANO 3.0 by Marco Zonca * CLIENT must feed Whatcdog sooner then feedingInterval otherwise will be forced to restart * */const int feedingPin =14;const int ledPin =15;const int restartPin =16;const int buzzerPin =17;const long ledInterval =1000;const long feedingInterval =2500;const long timeForClientStart =16000;int ledState =LOW;int previousFeedingState =LOW;int feedingState =LOW;unsigned long previousLedMillis =0;unsigned long previousFeedingMillis =0;void setup() { digitalWrite(restartPin, HIGH); // LOW will force CLIENT to restart pinMode(ledPin, OUTPUT); pinMode(buzzerPin, OUTPUT); pinMode(restartPin, OUTPUT); pinMode(feedingPin, INPUT); delay(timeForClientStart); // let time to CLIENT to start...}void loop() { unsigned long currentMillis =millis(); // BLINK LED ------------------- if (currentMillis - previousLedMillis>=ledInterval) { previousLedMillis =currentMillis; if (ledState ==LOW) { ledState =HIGH; } else { ledState =LOW; } digitalWrite(ledPin, ledState); } // CHECK THE FEEDING ------------------- feedingState =digitalRead(feedingPin); // CLIENT must set pin HIGH -> LOW frequently to prove it's alive if (feedingState ==HIGH) { if (previousFeedingState ==LOW) { previousFeedingMillis =currentMillis; } previousFeedingState =HIGH; } else { previousFeedingState =LOW; } if (currentMillis - previousFeedingMillis> feedingInterval) { // CLIENT is sleeping ledState =HIGH; digitalWrite(ledPin, ledState); tone(buzzerPin,1500); delay(500); digitalWrite(restartPin, LOW); //restart CLIENT tone(buzzerPin,1500); delay(500); digitalWrite(restartPin, HIGH); tone(buzzerPin,1500); delay(timeForClientStart); // let CLIENT time to restart... noTone(buzzerPin); currentMillis =millis(); previousFeedingState =LOW; previousFeedingMillis =currentMillis; previousLedMillis =currentMillis; }}

Aangepaste onderdelen en behuizingen

23lm-stepper-plate-v2_PlvJaff9Hl.step 23lm-stepper-pulley-56_UhsbaWbiBt.step

Schema's


Productieproces

  1. DIY infrarood bewegingssensorsysteem voor Raspberry Pi
  2. Bouw een ballistisch parachuteherstelsysteem voor uw drone
  3. Is een continu monitoringsysteem geschikt voor u?
  4. Automatische gereedschapswisselaars voor robots
  5. Is uw systeem klaar voor IoT?
  6. Veelhoeksnijders voor automatische draaibanken
  7. CNC automatische draaibank voor precisieonderdelen
  8. Aandrijvingssysteem voor hypersonische vlucht
  9. Werkingsprincipe van handmatig en automatisch transmissiesysteem:
  10. Automatisch transmissiesysteem begrijpen
  11. Automatisch smeersysteem begrijpen