Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

Pilote automatique pour voiliers (système de pilotage automatique)

Composants et fournitures

Arduino UNO
× 1
Arduino Nano R3
× 1

À propos de ce projet

Préface :

J'aime naviguer seul car lorsqu'un homme est en mer avec son voilier, il a tout ce dont il a besoin pour évoluer à un niveau supérieur. Naviguer en mer crue avec du mauvais temps peut être très difficile mais s'il choisit des jours de beau temps avec du soleil et du vent agréable, le plaisir sera au maximum.

Le bonheur, c'est des horizons infinis, des techniques sportives parfaites, des choix optimaux, mais aussi des choses humaines comme une bonne boisson et un savoureux sandwich ! Exactement à ce moment-là vient l'aide du pilote automatique :il fonctionne à votre place pendant que vous avez votre thé et vos biscuits de 17h00 sur la mer. :-)

Ce que le pilote automatique peut faire pour vous :

Un voilier n'a pas de moteur et ne peut pas suivre un chemin programmé du port à la plage, puis au lieu de pêche, faire le tour du Phare et revenir, tout seul, il ne le peut pas.

Tout le travail est fait par le Marin, il faut le comprendre à ce stade :régler les voiles, maîtriser la météo et la source/vitesse du vent, durcir ou lâcher les cordages, faire attention à la circulation avec les autres bateaux, décider de la direction et du pilotage... Quand le Marin décide de faire une pause, disons 10 secondes ou quelques minutes (le fameux « tea time »), il enclenche le Pilote automatique. En quelques secondes, son GPS acquiert la position, la vitesse et la direction du bateau et est capable de maintenir la direction (itinéraire). Le système de direction, un manche relié au gouvernail, généralement déplacé par les mains expertes du marin, est désormais contrôlé par le pilote automatique via le moteur pas à pas qui lui est connecté par des poulies et des cordes.

Contrôler le gouvernail est un travail continu de réglage fin ou grossier. Plus petit (plus léger) est le bateau et plus grands seront les facteurs de changements de direction qui l'influencent :vagues de la mer, direction et pression du vent, déplacement du poids à bord par les mouvements des marins, courants marins. Mais le Sailor est toujours éveillé, même avec le pilote automatique activé, apportant des modifications à l'itinéraire réel au moyen de la télécommande :il y a 4 boutons dessus, étiquetés +1 -1 +10 -10, pour de petits ou grands changements de degrés, augmentant ou diminuant la valeur. Ces boutons sont présents sur le pilote automatique aussi, les vertes (à droite) et les rouges (à gauche). Le bouton bleu (au milieu) sert à activer ou désactiver le pilote automatique, la pause. C'est aussi un bouton noir pour configurer les paramètres en mémoire.

Le circuit :

Le traitement principal est effectué par MCU Arduino Uno . L'autre MCU, Arduino Nano , est le chien de garde :je sais qu'il existe une sorte de chien de garde à l'intérieur de l'Uno mais j'aimais le faire avec un microcontrôleur externe indépendant, c'est un rêve de toute une vie que j'ai couvert, je suis heureux maintenant ! Uno doit alimenter Nano via la broche 3 -> A0 en le mettant haut/bas, 5/0 volts, au moins une fois toutes les 2,5 secondes (feedingInterval); sinon, cela signifie que l'Uno est "en sommeil" ou "bloqué", et Nano réinitialise Uno... Cela ne s'est encore jamais produit, pouvez-vous croire ?

Il est utilisé un affichage populaire en conjonction avec un convertisseur de circuit i2c tous deux soudés ensemble, n'utilisant finalement que 4 fils pour épargner considérablement les broches numériques pour communiquer avec Uno. Également le moyen de connecter boutons et télécommande à est fait par des diviseurs de tension de résistance pour atteindre l'objectif d'utiliser le moins de ports MCU possible ; J'ai choisi des résistances de précision à 1%, les valeurs de comparaison analogiques doivent être comprises entre les valeurs que j'ai mises dans le code ; en cas de non-reconnaissance de certains boutons parce que vous choisissez d'autres types de résistances, apportez également quelques modifications aux constantes (modifiez le code dans "checkRfRC()" et "checkHWButtons()"). Le circuit de télécommande RF 433Mhz (RC) fonctionne bien; pour améliorer la couverture à distance et les chances de succès, j'ai ajouté une antenne bobine que vous pourriez fabriquer vous-même avec un morceau de fil de cuivre; Je l'ai testé à 10 mètres mais je pense qu'il peut fonctionner même à 20 mètres ou plus, plus que suffisant étant donné que le voilier cible que j'avais l'habitude de tester Autopilot n'avait que 4,20 mètres de long.

Pour l'unité GPS J'ai utilisé au début un bon EM406A mais malheureusement j'ai découvert qu'il souffrait de Week-Rollover-Bug, il était trop vieux, alors j'ai dû le changer avec un excellent et populaire Beitian BN-220T. Avec son logiciel de configuration, veuillez le régler pour "cracher" 2 fois par seconde (2 Hz) juste la phrase série NMEA "$ GNRMC" nécessaire. Le GPS envoie (TX) des données série à la broche 0 (RX) de Uno. Les données contiennent toutes les données de navigation utilisées pour calculer la correction à faire par le moteur :date, heure, position latitude et longitude, cap vrai, vitesse et validité du relevé des satellites. Étant donné que la programmation IDE d'Arduino utilise également le port pin 0 (RX), n'oubliez pas de déconnecter temporairement le GPS pendant cette opération...

Un autre de mes rêves était d'utiliser une EEPROM . L'IC 2404 est un magnifique circuit intégré i2c de 512 octets que j'ai utilisé pour lire/écrire dans cette puce mémoire quelques paramètres pour les mouvements du moteur pas à pas que j'expliquerai plus tard dans le paragraphe "Logiciel".

Liste des composants :

  • Arduino Uno en tant que MCU
  • Arduino Nano comme chien de garde
  • GPS Beitian BN-220T
  • Moteur pas à pas, modèle 23LM, 54 pas =1/4 de tour
  • Contrôleur Keyes L298 pour moteur
  • RF433Mhz RC XD-YK04 + télécommande 4 boutons + antenne bobine
  • 6 boutons normalement ouverts (2xRouge, 2xVert, 1xNoir et 1xBleu)
  • Interrupteur marche/arrêt (blanc)
  • Connecteurs ronds 6 broches femelle + mâle pour moteur pas à pas externe
  • Sonnerie
  • Affichage LCD1602 2x16 caractères + circuit convertisseur i2c
  • 3 LED (rouge, bleu et jaune))
  • IC 24c04 i2c eeprom
  • Multiplexeur IC 4051
  • Batterie LiPo 2s 7.4v 2600mA
  • Régulateur de tension IC 7805 + dissipateur de chaleur
  • Thermistance NTC MF52-103 10k
  • Fusible réarmable 2A
  • 6x 1N4148 diodes (D1-D6)
  • Résistances sur Power shield (R1-R4=10k, R5=100k)
  • Résistances sur le blindage du pilote automatique (R1=330, R2=1k, R3=2k, R4=5.1k, R5=1k, R6/R7/R14=330, R8-R13=10k, R15=10M)
  • Condensateurs (C1=470uF 16v, C2=100n)
  • Résistance 2W 0,22 Ohm (R6)
  • Épingles mâles
  • En-têtes femelles à broches longues
  • Boîtier transparent et "étanche"

Il y a quelques capteurs sur le circuit le tout connecté à Arduino Uno à l'aide du multiplexeur IC 4051 . C'est une Thermistance pour prendre sous contrôle la température du dissipateur de chauffage du régulateur de tension, une résistance de 2W et 4x10k comme diviseurs de tension pour calculer l'ampère comme consommation d'énergie de tout le circuit. Aussi la tension de la batterie est pris sous contrôle :les LiPo sont connus pour être critiques lorsque des éléments individuels sont déchargés en dessous de 3,3 v ; ce circuit a un LiPo à deux éléments (2S) dans un seul boîtier, en cas de basse tension (inférieure à 7.0v) le buzzer vous informera par de courts bips rapides. N'attendez pas trop longtemps pour éteindre, et rechargez vite ! Les Leds :un jaune clignotant à 1 Hz vous indique que le WatchDog fonctionne; le bleu est allumé lorsque le pilote automatique est activé, éteint s'il est en pause ; la led rouge clignote lorsque l'un des boutons de la télécommande est enfoncé.

Tout le circuit fonctionne à 5,0 v alimenté par une batterie LiPo 2S 7,4 v 2600 mA/h et un régulateur de tension IC 7805 . Le courant ne doit pas être supérieur à 800 mA, mais il est généralement d'environ 100 à 450 mA. Veuillez y mettre un dissipateur de chaleur . La thermistance est placée dessus et le buzzer émet un bip si la température dépasse 50°C.

Les circuits imprimés PCB et l'assemblage :

Est utilisé des PCB simple face pour cette raison, j'ai dû inclure quelques cavaliers (ceux en pointillés) pour résoudre les itinéraires pour des circuits entiers. Est montré ici les faces des composants mais ci-dessous vous avez tous les fichiers, composants et faces de soudure, en miroir, à télécharger et à imprimer au moyen d'une imprimante laser sur des feuilles "jaunes" ou "bleues". J'ai utilisé les jaunes mais ils disent que les bleus sont meilleurs (mais le prix est nettement plus élevé). Lors de l'impression, n'oubliez pas de désactiver les paramètres d'économie de toner, utilisez plutôt une résolution de 1200 dpi pour obtenir un résultat noir profond et réel. Le processus de transfert de toner des feuilles magiques aux circuits imprimés est effectué à l'aide d'un fer chaud... L'impression sur les deux faces, également sur la face des composants, permet de reconnaître facilement le positionnement des éléments et rend même le projet "professionnel".

Les deux PCB sont dimensionnés pour s'adapter l'un à l'autre Arduino Uno en tant que pile :d'abord l'unité de puissance puis l'unité de pilote automatique sur l'ensemble.

Mon choix a été de tout assembler, PCB, MCU, RC, circuit Motor Driver, batterie, GPS, boutons, interrupteur, fils, connecteurs, etc. pensant les réutiliser un jour :je ne les ai pas soudés ensemble, je utilisé en-têtes et câbles/connexions Dupont populaires plutôt. Il y a donc environ 200 connexions dessoudées, cela signifie que des dysfonctionnements inattendus et indésirables ou un comportement différent du circuit peuvent survenir de temps en temps, c'est normal. La suggestion est de tout souder pour un circuit plus stable !

Paramètres Configuration et affichage des valeurs des capteurs :

En appuyant sur le bouton noir sur le côté de la boîte, il entre en mode Configuration; cela peut être fait aussi pendant la navigation active, il n'est pas nécessaire d'entrer d'abord Pause. La 1ère page de l'écran affiche la tension de la batterie (V=7.83), la consommation électrique (mA=177) et la température du capteur à thermistance près du dissipateur (38°C) ; en appuyant encore et encore sur le bouton noir, vous entrez dans les pages suivantes ; les 2ème, 3ème, 4ème et 5ème pages montrent les paramètres listés ci-dessous et vous pouvez modifier ces valeurs à l'aide des boutons -1 et +1. La 6ème page affiche "Mise à jour..." si vous avez modifié quelque chose, les valeurs sont enregistrées dans la mémoire EEPROM.

  • Intervalle : c'est-à-dire 2000 mSec, c'est le temps entre un essai et un autre par le moteur pas à pas pour restaurer le cap "H" vers la route "R", en déplaçant le manche du gouvernail à droite ou à gauche ;
  • Minimum : c'est-à-dire 2°, est le nombre minimum de degrés hors route pour avoir une intervention du pilote automatique ; jusqu'à cette valeur, le gouvernail reste en position centrale stable ;
  • Max : c'est-à-dire 40°, est le changement de direction maximum à la fois par le moteur pas à pas ; si le calcul effectué est pour un changement de 50°, en réalité Stepper ne bougera que de 40° ;
  • Coeff. : c'est-à-dire 1,50 x °, est le coefficient de changement de direction à la fois ; si le calcul effectué est pour un changement de 40°, en réalité le moteur pas à pas se déplacera pour (40 x 1,50) =60° ;

Ces paramètres sont nécessaires au réglage fin du pilote automatique lorsqu'il est installé sur le voilier. La réactivité, la sensibilité et la douceur dépendent du diamètre des poulies, du nombre de poulies, du diamètre de la poulie principale du moteur pas à pas, de la sensibilité du gouvernail, de la longueur du manche du gouvernail, etc. Laissez tout installer et laissez essayer et faites de l'expérience à bord. Bien sûr, choisissez une belle journée ensoleillée avec un vent léger pour toutes les phases de test !

Comment ça marche "en direct" :

Vous naviguez sur la mer, sur le lac ou tout simplement autour du port. C'est l'heure du thé et votre coca et votre sandwich préféré vous attendent dans la poche. Nous y sommes :changer de pilote automatique sur et laissez-le prendre le GPS par satellite, vous devriez maintenant lire sur l'écran la vitesse réelle en nœuds, l'horloge et la direction du cap, c'est-à-dire H270° (R=route à suivre, H=cap réel) en degrés (rappelez-vous 180°=sud, 270° =ouest, 360° ou 0°=nord et 90°=est). Les valeurs R et H sont les mêmes en mode Pause (STOP est affiché). Connectez maintenant le câble de direction, du moteur pas à pas au manche de la gouverne de direction, et appuyez sur le bouton bleu pour démarrer le pilotage du pilote automatique; à ce stade, le pilote automatique maintient R=direction de la route et prend le contrôle de ce qui se passe avec H=cap. Le numéro d'en-tête change à coup sûr , lentement ou rapidement selon les conditions météo dont nous avons déjà parlé. Le pilote automatique essaie ensuite de restaurer la direction R=route en effectuant des corrections, c'est-à-dire -10°, +5°, etc. jusqu'à ce que la valeur H soit égale à la valeur R . Vous pouvez décider de certains changements sur l'itinéraire et vous pouvez modifier le numéro à l'aide des boutons rouges et verts de l'unité (-1 -10 +1 +10) ou par télécommande. Pour reprendre le contrôle de le direction il vous suffit d'appuyer sur le bouton bleu Pause, de déconnecter la corde du manche du gouvernail en continuant le travail par vos mains. Bravo.

Côté logiciel :

Le code est assez long mais j'espère qu'il est suffisamment clair pour être facilement compréhensible. En tout cas j'expliquerais comment ça se passe. L'esquisse utilise environ 65% du programme et environ 45% de la mémoire. Même en utilisant la classe String, principalement pour la manipulation de phrases Serial NMEA, l'ensemble du flux d'élaboration est stable et solide ; il utilise "serialEvent()" pour recevoir les données du GPS deux fois par seconde , puis appelle "nmeaExtractData()" et enfin, il vérifie le paquet de données avec "nmea0183_checksum() pour être sûr de l'intégrité des données. Si vous utilisez une autre marque et un autre modèle de GPS, assurez-vous que les phrases ont la même structure ou vous devez apporter des modifications ici . Par exemple, EM406A utilise l'ID de paquet "$GPRMC" , BT220 utilise "$GNRMC" à la place... juste un petit changement de nom... Un lien utile peut vous aider avec le test de la somme de contrôle :https://nmeachecksum.eqth.net - Voici un exemple de phrase NMEA complète, il contient :identifiant, heure, validité, latitude, longitude, vitesse, cap vrai, date, variation et somme de contrôle.

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

Pendant "Setup()" l'EEPROM est vérifié :si nouveau ou inconnu il est initialisé (formaté). Les paramètres en mémoire sont en lecture/écriture sous forme d'octets :0=0x29, 1=0x00, 2-3=intervalle, 4-5=min, 6-7=max, 8-11=coefficient (octet, octet, int, int, flotter). J'ai géré avec soin les opérations EEPROM r/w, peut-être trop défensives... Les capteurs sont vérifiés toutes les 10 secondes via "readMuxSensors()" par le multiplexeur et peut déclencher une alarme si la batterie est faible ou si la température est élevée. La résolution de la consommation électrique est faible, des pas d'environ 40mA. Boutons matériels et RC sont contrôlés en permanence ; ce qu'ils font dépend de la valeur booléenne "IsSetup" ainsi que l'affichage "RefreshDisplay()" fait . Le cœur du code est la section COMMANDE DE DIRECTION qui appelle la fonction "gomotor()" pour déplacer le moteur pas à pas; oui, il peut déplacer le gouvernail de 10° vers la droite et après la valeur de l'intervalle il revient à la position zéro du gouvernail, et ainsi de suite après un nouveau tour de calcul. Comme déjà dit, le travail de direction est également effectué pendant la configuration car il n'affecte que quelques boutons et le comportement de l'affichage. Nourriture Whatchdog est très simple mais important :il suffit d'activer/de désactiver son code PIN dès qu'il le peut.

Comment l'installer sur un voilier :

Comme le montre l'image ci-dessous, j'ai choisi de placer le pilote automatique et le moteur pas à pas sur la poupe, tous deux bien fixés avec des boulons, etc. ; une corde de 6 mm de diamètre part de la poulie principale du moteur et fait le tour de deux autres poulies placées des deux côtés. Ces deux poulies doivent être "fixées" au bateau par l'intermédiaire de deux anneaux d'élastique pour maintenir légèrement en tension la corde. À ce stade, enfin, vous devez décider comment connecter la corde au manche du gouvernail (connexion temporaire); il doit être connecté pendant que vous voulez que le pilote automatique soit en action, facile à connecter et facile à déconnecter. Gardez le système de pilote automatique à l'écart de l'eau ! :-)

Nouvelles et mises à jour :

  • 10.05.2020, ajouté pour le téléchargement des fichiers de projet .STEP 3D CAD pour la poulie pas à pas (par moi) et la plaque de montage (par Andrew Barney), et une image d'aperçu 3D d'entre eux.

Avis de non-responsabilité et avertissements :

Disons que c'est un jeu auquel nous jouons ici, rien à prenez au sérieux ! Il y a quelques années j'ai fait un long voyage, 16 mois, autour du monde sur un voilier. Nous avons beaucoup navigué avec un vrai pilote automatique (PAS CECI UN !) dans toutes les conditions météorologiques, même les mauvaises conditions météorologiques. Un vrai pilote automatique, c'est quelque chose très fort le matériel et les logiciels auxquels vous devez faire confiance beaucoup. Ce pilote automatique Arduino à la place est un jeu fantastique à jouer avec et vers passez du temps pour vous amuser.

Amusez-vous bien !

Marco Zonca

Code

  • Esquisse du pilote automatique (pour Uno)
  • Croquis WatchDog (pour Nano)
Esquisse du pilote automatique (pour Uno)Arduino
/* Ce sketch agit comme pilote automatique pour petits voiliers, par Marco Zonca, 2019 Arduino UNO comme CPU, Arduino Nano comme chien de garde, GPS BT-220 nmea, moteur pas à pas + contrôleur, rf433Mhz RC, 6 boutons, buzzer, i2c afficheur, 2 leds, eeprom i2c 24c04, Mux 4051 pour capteurs, lipo 2s 7.4v 2600mA, régulateur de tension 7805, Thermistance;*/#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/yyyy";String nm_routetofollow ="000";float nmf_route;tofollow non signé long précédentStearingMillis =0;non signé long currentStearingMillis =0;non signé long prevCheckSensorsMillis =0;non signé 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 prevSearing =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;// les paramètres suivants sont les valeurs par défaut mais sont en lecture/écriture eeprom// eeprom est initialisé si aux adresses 0 et 1 le contenu est différent adresse len type notes// 0-255 octets à 0x50 EEdisk, 256-512 octets à 0x51 (non utilisé) ---------- -------------------------------------------------- ---// 0 1B octet 01001001 (0x29 comme id de projet de pilote automatique1)// 1 1B octet 00000000 (0x00 " " id2)int StearingInterval =2000 ; // millis entre essai et retour 2 2B int StearingInterval 1000-5000 pas 100int StearingMinToMove =2; // compass_degrees 4 2B int StearingMinToMove 0-20 pas 1int StearingMaxMove =40; // compass_degrees 6 2B int StearingMaxMove 10-45 pas 1float StearingCoeffMove =1.5; // utilisé comme (compass_degrees * coeff) 8 4B float StearingCoeffMove 0.1-4 pas 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 ledpausePin =2;Bst int watch;DogPin =3 // 00=Vin 01=Vbatt 10=Tempconst int MuxSelBit1Pin =6; // const int motorsABenablePin =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 =201 const int RCright10button =204;const int HWleftbutton =101;const int HWrightbutton =102;const int HWpausebutton =103;const int HWsetupbutton =104;const int HWleft10button =105;const int HWright10button =106;const int motorStepsPerRevolution =200; // 200 pour le modèle 23LM, 54 pas =1/4 de révolutionLiquidCrystal_I2C lcd (0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIF);Moteur pas à pas (moteurPas Par Révolution, 9, 10, 11, 12 ); void setup() { Serial.begin (4800); lcd.begin (16,2); Fil.begin(); motor.setSpeed(60); inputString.reserve(200); pinMode(motorsABenablePin, OUTPUT); pinMode(MuxSelBit0Pin, SORTIE); pinMode(MuxSelBit1Pin, SORTIE); digitalWrite(motorsABenablePin, LOW); digitalWrite(MuxSelBit0Pin, LOW); digitalWrite(MuxSelBit1Pin, LOW); pinMode(ledpausePin, SORTIE); pinMode(watchDogPin, SORTIE); digitalWrite(ledpausePin, LOW); digitalWrite(watchDogPin, LOW); // lecture+vérification de l'EEPROM (formatage si nouveau (ou non identifié)) lcd.clear(); lcd.setCursor(0,0); lcd.print("Vérification de la mémoire..."); lcd.setCursor(0,1) ; for (s =0; s =CheckSensorsInterval) { readMuxSensors(); if ((SensorVBatt <=7.0) || (SensorTemp>
=50)) { lcd.clear(); lcd.setCursor(0,0); lcd.print("Capteurs d'alarme ! "); lcd.setCursor(1,1) ; lcd.print("V="); lcd.print(SensorVBatt); lcd.print(" "); lcd.print(int(SensorTemp)); lcd.write(0xDF); lcd.print("C"); NewTone (haut-parleurPin,10) ; retard(1000); noNewTone(); } prevCheckSensorsMillis =currCheckSensorsMillis; } // CONTRLE STEARING ---------------- currentSearingMillis =millis(); if (currentStearingMillis - previousStearingMillis>=StearingInterval) { if (isStearing ==false &&ispause ==false) { // va essayer (déplacer le 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((Searing * 216) / 360)); // 54 pas =1/4 de tour prevStearing =Stearing; isStearing =vrai; } } else { // revenir en arrière (déplacer le vol à la position "zéro") if (isStearing ==true) { Stearing =(prevStearing * -1); gomotor(int((Searing * 216) / 360)); // 54 pas =1/4 de tour Volant =0; prevStearing =0; isStearing =false; } } previousStearingMillis =currentStearingMillis; } // BOUTONS RF RF ------------------ rfRemoteControlValue =checkRfRC(); if (rfRemoteControlValue) { switch (rfRemoteControlValue) { case RCleftbutton :// Bouton RC gauche goleft(); Pause; case RCrightbutton :// Bouton RC droit goright(); Pause; case RCleft10button:// Bouton RC Left-10 goleft10(); Pause; case RCright10button:// Right+10 RC button goright10(); Pause; } } // BOUTONS ------------------------ HWButtonValue =checkHWButtons(); if (HWButtonValue) { switch (HWButtonValue) { case HWleftbutton:// Left(-1) HW button if (isSetup ==false) { goleft(); } else { setupMinus(); } Pause; case HWrightbutton :// Right(+1) HW button if (isSetup ==false) { goright(); } else { setupPlus(); } Pause; case HWpausebutton:// Suspendre le bouton HW gopause(); Pause; case HWsetupbutton:// Configurer le bouton HW gosetup(); Pause; case HWleft10button:// Left(-10) HW button goleft10(); Pause; case HWright10button:// Right (+10) HW button goright10(); Pause; } } // GPS NMEA ------------------ if (stringComplete ==true) { // phrase nmea reçue par le port série RX bool ret; ret =nmeaExtractData(); chaîne d'entrée ="" ; stringComplete =false; if (ret ==true) { RefreshDisplay(); } } // ALIMENTATION DU CHIEN DE GARDE ---------------- if (digitalRead(watchDogPin) ==LOW) { digitalWrite(watchDogPin, HIGH); } else { digitalWrite(watchDogPin, LOW); }}// lecture des capteurs sur multiplexervoid readMuxSensors() { float Vo =0; flottant n =0 ; flottant n1 =0 ; flottant v1ad =0 ; flottant v2ad =0 ; flotteur corr =0; flotteur R1 =10000 ; flottant logR2 =0 ; flotteur R2 =0 ; flotteur T =0 ; flottant c1 =1,009249522e-03 ; flotteur c2 =2.378405444e-04 ; flottant c3 =2.019202697e-07 ; digitalWrite(MuxSelBit0Pin, LOW); // 00=Vbatt digitalWrite(MuxSelBit1Pin, LOW); n =analogRead(MuxIOPin); v1ad=n; n1=(((10,00 * n) / 1023,00)); SensorVBatt=(n1 + ((n1 * 0.0) /100)); // correction arbitraire (non active =0.0%) digitalWrite(MuxSelBit0Pin, LOW); // 01=Vres digitalWrite(MuxSelBit1Pin, HIGH); n =analogRead(MuxIOPin); v2ad=n; n1=(((10,00 * n) / 1023,00)); SensorVRes=(n1 + ((n1 * 0.0) /100)); // correction arbitraire (non active =0.0%) digitalWrite(MuxSelBit0Pin, HIGH); // 10=NTC Temp digitalWrite(MuxSelBit1Pin, LOW); Vo =analogRead (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));}// extraire les données de nmea inputStringbool nmeaExtractData() { bool ret =false; //true if nmea phrase =$GNRMC et CHKSUM valide 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) { cas 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; Pause; cas 2 ://validité z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_validity=inputString.substring(y+1,y+1+1); } y=z; Pause; cas 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; Pause; cas 4://nord/sud z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_latitude=nm_latitude + inputString.substring(y+1,y+1+1); } y=z; Pause; cas 5 ://longitude 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; Pause; cas 6 ://est/ouest z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_longitude=nm_longitude + inputString.substring(y+1,y+1+1); } y=z; Pause; cas 7 ://vitesse des nœuds z=inputString.indexOf(",",y+1); if (z>(y+1)) { nmf_knots=inputString.substring(y+1,z).toFloat(); t=roundOneDec(nmf_knots); nm_knots=Chaîne(t,1)+"kn" ; } y=z; Pause; cas 8 ://vrai cours 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; Pause; cas 9 ://date 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; Pause; case 10 :// instructions break ; par défaut :// les instructions cassent ; } } if ((isfirstfix ==true) || (ispause ==true)) { nm_routetofollow=nm_truecourse; nmf_routetofollow=nmf_truecourse ; isfirstfix=false ; } ret=vrai; } renvoie ret;}// augmente (+) la valeur du paramètre pendant setupvoid setupPlus() { switch (SetupParameter) { case 2://interval StearingInterval =(StearingInterval + 100); if (StearingInterval> 5000) { StearingInterval =5000 ; } Pause; cas 3 ://min. pour déplacer StearingMinToMove =(StearingMinToMove + 1); if (StearingMinToMove> 20) { StearingMinToMove =20; } Pause; cas 4://max. déplacer StearingMaxMove =(StearingMaxMove + 1); if (StearingMaxMove> 45) { StearingMaxMove =45 ; } Pause; cas 5://coefficient StearingCoeffMove =(StearingCoeffMove + 0,1); if (StearingCoeffMove> 4) { StearingCoeffMove =4; } Pause; } délai (200); RefreshDisplay();}// diminuer (-) la valeur du paramètre pendant setupvoid setupMinus() { switch (SetupParameter) { case 2://interval StearingInterval =(StearingInterval - 100); if (StearingInterval <1000) { StearingInterval =1000; } Pause; cas 3 ://min. pour déplacer StearingMinToMove =(StearingMinToMove - 1); if (StearingMinToMove <0) { StearingMinToMove =0; } Pause; cas 4://max. déplacer StearingMaxMove =(StearingMaxMove - 1); if (StearingMaxMove <10) { StearingMaxMove =10 ; } Pause; cas 5://coefficient StearingCoeffMove =(StearingCoeffMove - 0,1); if (StearingCoeffMove <0,1) { StearingCoeffMove =0,1 ; } Pause; } délai (200); RefreshDisplay();}// contrôle moteur (+)=forward (-)=backwardsvoid gomotor(int stepsToMove) { digitalWrite(motorsABenablePin, HIGH); motor.step(stepsToMove); digitalWrite(motorsABenablePin, LOW);}// actualiser les données sur 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"); Pause; case 2://interval lcd.print("interval"); lcd.setCursor(7,1) ; lcd.print(StearingInterval); lcd.print(" mSec"); Pause; case 3://min. to move lcd.print("minimum"); lcd.setCursor(7,1) ; lcd.print(StearingMinToMove); lcd.write(0xDF); Pause; case 4://max. move lcd.print("max"); lcd.setCursor(7,1) ; lcd.print(StearingMaxMove); lcd.write(0xDF); Pause; case 5://coefficient lcd.print("coeffic."); lcd.setCursor(7,1) ; lcd.print(StearingCoeffMove); lcd.print(" x "); lcd.write(0xDF); Pause; } }}/* 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(); chaîne d'entrée +=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 je; // 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... "); retard(1000); goupdateEEPROM(); if (EEerr) { lcd.print("E="); lcd.print(EEerr); retard(1000); } prev_StearingInterval =StearingInterval; prev_StearingMinToMove =StearingMinToMove; prev_StearingMaxMove =StearingMaxMove; prev_StearingCoeffMove =StearingCoeffMove; } isSetup =false; } } NewTone (speakerPin,2000); retard (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); retard (200); noNewTone(); } else { NewTone (speakerPin,1000); retard (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); retard (200); noNewTone(); } else { NewTone (speakerPin,1000); retard (50); noNewTone(); } RefreshDisplay();}void gopause() { // pause button/RC if (ispause ==true) { ispause=false; digitalWrite(ledpausePin, HIGH); NewTone (speakerPin,50); retard (200); NewTone (speakerPin,200); delay(800); noNewTone(); } else { ispause=true; digitalWrite(ledpausePin, LOW); NewTone (speakerPin,200); retard (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); retard (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, SORTIE); 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); retard (500); digitalWrite(restartPin, LOW); //restart CLIENT tone(buzzerPin,1500); retard (500); digitalWrite(restartPin, HIGH); tone(buzzerPin,1500); delay(timeForClientStart); // let CLIENT time to restart... noTone(buzzerPin); currentMillis =millis(); previousFeedingState =LOW; previousFeedingMillis =currentMillis; previousLedMillis =currentMillis; }}

Pièces et boîtiers personnalisés

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

Schémas


Processus de fabrication

  1. Système de capteur de mouvement infrarouge DIY pour Raspberry Pi
  2. Créer un système de récupération de parachute balistique pour votre drone
  3. Un système de surveillance continue vous convient-il ?
  4. Changeurs d'outils automatiques pour robots
  5. Votre système est-il prêt pour l'IoT ?
  6. Fraises polygonales pour tours automatiques
  7. Tour automatique CNC pour pièces de précision
  8. Système de propulsion pour vol hypersonique
  9. Principe de fonctionnement du système de transmission manuelle et automatique