Inscription

Veuillez vous inscrire pour accéder à l'intégralité des sections du forum, aux images et interagir avec d'autres passionnés de la Ford Mustang.

Développement d'un Arduino comme controleur moteur gen 1

Démarré par filou96, 25 Juillet 2023 à 18:18:21

0 Membres et 1 Invité sur ce sujet

filou96

Voila je résume déja qques mois de développement , donc pavé  ;D
Ceci était sur le post du Fastback 65 , je fais ce post spécifique sur le développement d'un controleur pour mon moteur à base d'Arduino Mega 2560 : pour ceux qui ne connaissent pas mon moteur , je roule beaucoup et descend souvent en Camargue avec la Mustang et les canicules sont sévères , le but étant d'avoir une clim fonctionnelle ( chien dans la voiture ) par 40 - 45 °C à l'arret dans les bouchons .
Donc ne voulant pas trouer mon tablier et y mettre un gros radia , j'essaye d'autres voies .

Et je vous rassure , si c'est en panne , la voiture fonctionne normalement , juste ventilo moteur et pompe manuel ON/OFF LOL Je n'ai pas quitté la S5 pour me remmetre des ordis lol

Il y a à controler de manière active :

- Ventilo Spal brushless en primary fan controlé en PWM , régulation type PI ou PID sur capteur de tempé. ( actuellement controlé par un VSFM002 de Lingenfelter )

- Pompe à eau électrique brushless en ligne Stewart d'appoint ( celle des Funny cars , Dragster and co ) qui permet une circulation conséquente de LDR au ralenti ou même moteur stoppé afin de refroidir efficacement le moteur avec la pompe à eau méca au ralenti. (actuellement controlée par un thermostat Mishimoto ) Je l'ai essayée pour descendre chez @toine10 , bluffant.

- Clim passage en automatique plutot que manuel , actuellement manuel , par la suite Arduino

Le reste du role de l'Arduino c'est essentiellement du recueil d'infos et de paramètres.
Je précise que j'ai un carbu et déja un AFR avec sonde wideband et une pompe à vide Star Machine pour limiter le blowby ( pareil matos de funny cars ou de Dragsters )

Niveau paramètres à surveiller/datalogger par l'Arduino via écran TFT tactile :

- tempé LDR si possible au niveau de l'intake repiquage sur la sonde d'origine, assez facile à programmer une fois la courbe RΩ/T°F ou °C connue
- rpm en % du max du ventilo Spal, avec réglage sur écran tactile de la fenètre si modif necessaire, car celle ci sera controlée en PI ou PID, donc accès de bas niveau au Kp, Ki voir Kd sans remmètre l'Arduino sur l'ordi.
- pompe à eau d'appoint Stewart enclenchée ou non , avec réglage de la fenètre de tempé sur écran tactile, pas de PID là , c'est du ON/OFF
- tempé et pression d'huile moteur , facile.
- tempé huile boite C4, facile
- tempé int / ext voiture avec accès aux réglages de la clim, moins facile
- Vacuum level du bloc moteur vu la pompe à vide , je suis sur une régule à - 8 inches Hg pour un usage street, après 2000 km comme ça c'est parfait.
- voltage batterie , facile.

Ouf voila , le cahier des charges appelé à varier éventuellement.

Donc je programme ,  @geloche m'aide bien par ses conseils
Ca progresse , j'espère les premiers tests cet hiver.

Ci après résumé du développement qui était à la base sur la poste du Fastback

Donc tout ce qui est en dessous est un flashback ;)

_________________________________________________

Capteur de tempé , essai thermocouple K , afficheur , mesure de tension commande relai de puissance
C'est dur d'apprendre un langage qd on est vieux ;D
Il est dynamique l'affichage , mais j'ai pas fait de vidéo exprès pas la peine

traffic.gif

_______________________________________________

Hier me suis amusé avec le PWM sur une diode, bref j'apprends tout ce qui m'interesse comme modules pour controler les trucs dans la voiture, tu as des trucs sympas , style capteur de proximité qui t'envoie un SMS quand on ouvre le capot , tout ce que tu peux imaginer etc ... Bon un cadenas ça marche aussi LOL

traffic.gif

traffic.gif

_______________________________________________

Bon développement µcontroleur LOL

J'ai commandé un touch screen TFT capacitif 320X240 Adafruit 2.8"( matos conçu pour l'Arduino , c'est plug and play , ça aide )  pour me faire boutons et menus tactiles https://www.mouser.fr/datasheet/2/737/adafruit_2_8_tft_touch_shield_v2-1396541.pdf , seulement il me bouffe presque toutes les E/S du Uno , il ne me reste plus assez d'E/S analogiques ou digitales pour gérer mon bazard  sbhy LOL
De plus j'ai réussi à saturer la flash avec un tableau tournant 500X500 hier lol
Je change donc de carte je passe du L4 au V8 ;D , j'ai commandé un Arduino Mega, compatibilité complète des prog , l'écran se broche direct dessus et il me reste plusieurs 10zaines d'E/S libres et mémoire doublée , voila , c'est pas ruineux 35€ la carte ...
Ca avance mine de rien  bien1

Voila le tft sur le Uno , comme on peut le voir ...problème LOL

traffic.gif


Le voici sur le Mega , rien à voir , je garde plein de développement et d'E/S bien1

traffic.gif

_______________________________________________


Voila la simulation de régulation PI ou PID est prète

Ci dessous le moteur résistance de 1Ω 100 W , ça chauffe bien, ventilo de PC pour qu'elle se stabilise plus vite en refroidissement, un thermocouple et un relay MOSFET avec optocoupleur largement dimensionné 30V 160A !!! qui alimentera la résistance en PWM dont la variation est commandé par l'Arduino en fonction de la tempé de la résistance ;D

Le but stabiliser la tempé de la résistance à la consigne demandée 85 °C par variation du duty cycle du PWM de 122 Hz

2ème tof une alim stabilisée largement dimenssionnée ( aliexpress pas chère du tout, c'est fout ça coutait une blinde ces trucs avant, elle régule en courant constant aussi ) qui fournira le courant pour la résistance via le MOSFET et donc les variations de tempé à réguler

Ouf y a plus qu'à écrire les programmes , trouver le Kp , le Ki peut être le Kd , mais ça simule un moteur sur un bureau ( en gros ) l'alim faisant varier la puissance demandée au moteur , le PWM doit s'adapter tout seul pour que la résistance reste à 85°C

traffic.gif

traffic.gif

J'ai reçu et dompté le méga2560 , à peu près je recherche les adresses des Timers , y en a 5 ... en 8 et 16 bits , c'est un peu hard pour trouver la doc pour les modifs à bas niveau des timers, j'ai réussi pour le Timer 5 qui laisse les broches 44 à 46 compatibles PWM  libres avec l'écran en place. J'ai réussi à les passer à 122Hz pour le Spal bien1
Bon les prog du Uno tournent moyennant la rectification des E/S
J'ai réussi à le faire tourner à 122 Hz sur les 3 sorties dépendantes du timer 5, 44 - 46 ( y en a 100 des E/S ...) , mon prog PWM fonctionne sans pb, j'attend avec impatience l'écran tactile pour avancer , faire des lectures et des menus de commandes  :D

_______________________________________________


J'ai reçu le touch sreen capacitif TFT 320 X 240 , pas simple j'ai passé tout l'AM pour m'en sortir et finir par comprendre que les images , c'est du .bmp couleurs 16 bit c'est 65 536 couleurs.
Plus touts les pb de code "de base" pour faire tourner ce bazard, il y a une microSD card qui stocke les photos et donc les fonds d'écrans , jauges , boutons etc ... Qu'on s'est soit même dessiné, et oui , j'ai du reprendre une mise à jour pour mon vieux Graphic Converter LOL
Mais grand pas de fait !  :v:  suis bien content !
Du coup pas touché à la voiture hier !

Le pb ET le défaut de l'open source , c'est que il y a TOUT sur TOUT mais c'est réparti PARTOUT , on passe qques heures à la pèche au code !!!

traffic.gif

_______________________________________________


Bon ajd j'ai bossé ( boulot je veux dire ... ) mais ce soir j'ai gérer le touch , jusqu'à présent j'avais exploré l'affichage, mais les 2 vont être liés.
J'ai compris qu'il rafraichissait à 80 Hz , d'où les points, j'ai passé le doigt trop vite ;D , bon pas fait pour la vidéo LOL mais pour cliquer des touches ou régler des bargraph nickel
Très agréable l'écran capacitif, comme un smartphone , mais surement très fragile aussi le verre, va falloir trouver un boitier adapté ...

J'ai corrigé les couleurs 16 bit bmp c'est 65 536 couleurs, ça va ;D

traffic.gif


J'ai super progressé sur le touchscreen , je déssine les formes souhaitées , je mets des photos , et surtout je gère le touch en récupérant les coordonnées getPoint() pour les utiliser en variables , c'est la passerelle pour piloter ce que je veux en matos
il me reste l'écriture , pas trop compliqué , l'affichage m'a demandé bcp de temps pour comprendre , les lecteur SD aussi, purée la ligne code pour limiter l'ESP32 à 25 MHz , j'ai passé des h dessus , je ne savais pas que c'était l'origine de mon blocage lecture de SD card , je l'ai sortie des limbes de l'internet celle là , ça a débloqué la SD card , aucun risque pour que je l'oublie dans le code final LOL , le touch facile 3h cet AM
2 clips , traçage de ligne et récup des coordonnées , exportées sur le serial monitor en bas pour être visibles
C'est bête , mais c'est comme ça qu'on commande des pompes des tempé , des PWM etc ...

Va falloir que je pioche des beaux fonds de jauges sur internet

L'action




Et le résultat




bon, le but approche , la question est j'affiche quoi ??? je peux avoir plusieurs pages no pb et afficher 100 paramètres ce n'est pas le pb , il faut que ce soit ergonomique et informatif pour les données essentielles, après il y a la touche graphique pour faire beau mais , ça c'est pas dur , y a des milliers de jauges sur internet.

Voila , bravo à ceux qui sont arrivé au bout , désormais ça se passe ici le développement de l'Arduino

Vib

Bon, très interessant sujet mais il te manque le déverrouillage des portes avec une RFID et le démarrage de la Stang avec une reco biométrique 😀😀😀
👍👍👍
Vib
*GT2013 - Sterling Grey - Track Pack - Reccaro - Magnaflow Street ;-)

filou96

Tu rigoles , ça existe , capteur d'empreinte pour Arduino , ça coute rien et il y a pas mal Library de programmes pour les utiliser LOL

De même le détecteur de présence à ondes courtes, le RFID , GPS, GSM etc ... C'est pas le choix qui manque

filou96

Salut

J'ai commencé la régule PID cet AM , alors hyper facile , y a un mec qui s'appelle Brett Beauregard qui a fait une Library et des commandes ( https://github.com/br3ttb/Arduino-PID-Library ) , en 20 lignes de code c'est réglé  msk Y en a même une autre autotune PID qui calcule Kp Ki et Kd mais à priori je n'en aurais pas besoin.
Merci à lui.
J'ai aussi testé donc le PID et forcément un module MOSFET sur ma résistance 1 Ω 100 W , ça marche bien , il peut la réguler en PWM à 122 Hz sur le duty cycle le tempé de ma résistance qui est mesurée par un thermocouple K et transmise à l'Arduino. Suis monté à 12V 60 W sans pb sauf radiateur à monter sur le MOSFET. Le MOSFET n'est là que pour l'expérimentation, l'Arduino pourra piloter directement l'entrée PWM du Spal qui ne demande que qques mA, pratique .
En fait je me suis cassé les pieds à avoir une freq d'une horloge à 122 Hz en changeant les registres diviseurs , alors qu'il suffisait de travailler avec la commande millis() ( milisecondes ) pour fixer le cycle ... Je vais peut être faire cela.
Les briques du prog total se précisent.
Donc là j'ai toutes les options documentées , reste plus qu'à écrire le code initial et tester , ce sera en virtuel les premiers tests , c'est prévu cet hiver la version opérationnelle.
Va y avoir un gros débuggage je pense LOL
A suivre

filou96

Bon 2 jours de pluie et ma voiture étant terminée ( mais pas lavée ... )  = 2 jours de théorie Arduino ,  C++ , Python , j'ai la tête comme une citrouille  sroll
Opérateurs, variables, déclarations, fonctions , types de données, condition d'état, boucles etc .... j'ai au moins 40 pages de notes structurées.
Mais ce n'est pas en vain , très interessant et de toutes façons pour parler à un Arduino , il faut apprendre son langage , être poli et ne pas faire de faute ni de syntaxe , ni d'orthographe LOL
Toujours aussi top ce truc et quand un essai ou une amélioration fonctionne trop bien bien1

Hier j'ai réussi à controler une charge inductive via opto coupleur et MOSFET en duty cycle en fonction de la tempé mais pas en PID encore , charge courbe jaune , Arduino courbe bleue, pas mécontent :D

traffic.gif

filou96

Salut

Y a pas c'est vraiment le controle de l'écran qui demande le plus de boulot . Surtout l'affichage, le touch est assez simple à gérer. Par contre les couleurs , l'orientation etc ... pas simple mais en contre partie Powerfull bien1
J'ai bossé sur les pixels ajd, je sais bien qu'il y a des fonctions pour tracer des lignes, des cercles des rectangles, des boutons , pas grave, je voulais enchainer quadrillage sur 5 pixels et diagonales pareil , écran noir avant la dernière diagonale car les pixels sont déja en jaune  et ce uniquement avec la fonction drawPixel.
Ca oblige à programmer, j'ai du utiliser les boucles while et for pour y arriver plus les opérateurs boléens.
Succès mais j'y ai passé l'AM , je connais le code maintenant  :D
En fait après pleins de complications et de plantages, la solution est simple, toujours pareil le codage , simple et élégant , 20 lignes et c'est bon.
Je finis toujours mes prog par un écran noir pour ne pas marquer le TFT.
Demain , lignes, cercles , boutons , écriture etc ... ça avance



filou96

Salut

L'écran 2.8" est vraiment trop petit pour afficher suffisamment d'infos lisibles dans le secteur du cendrier ... j'ai bien progressé dans son maniement bien1

Je passe au 7" 800 X 480 toujours en touch screen ( taille livre de poche pour situer ) et son controleur , ça coute que dale ... toujours un cendrier chinois modifié en support, c'est parfait , pas de trous rien et démontable en 5 sec , par contre encore du code à apprendre , mais largement similaire entre les écrans , pas trop de pb.

Du coup l'Arduino lui même sera séparé de l'écran, seul le controleur sera pluggé dessus.

traffic.gif

traffic.gif

filou96

Salut , la journée dessus , nouevel écran 7" tft 800X480 et interface depuis ce matin  :v:

traffic.gif

Un peu ( beaucoup ) difficile pour la calibration du touch , j'ai utilisé un logiciel spécifique ( 350 lignes ... ) puis récupéré la matrice puis j'ai pu faire une formule simple pour tous mes sketchs  cool
Par contre , une fois les pb de pin résolus , dessins, boutons tout ça , ça roule super
Les points blancs c'est mon doigt qui a touché , et ils sont au bon endroit ,cool pour les boutons
Ce WE j'essayerais la carte SD avec + des pullup mais pas bcp d'espoir faudra un tri state buffer par ex : J'apprends le code en même temps et à corriger les conneries des ex pour les adapter à ma bête . Y a un truc ou je seche , je voudrais mettre la calib de mon écran en EEPROM, Je peux lire écrire mais je suis à la ramasse là ... pas bien grave j'ai 10 lignes pour recalibrer avant chaque sketch, m'enfin bon ... Il est sympa, ça c'est la voie à suivre pour les multichip select  https://www.pjrc.com/better-spi-bus-design-in-3-steps/
Mais si je n'y arrive pas il me reste la solution de 74HC125 tri-state buffer chip, controlled by the 2 chip selects.
Ca ca marche.
Voila une journée de boulot écran calibré et fonctionnel 🤣 c'est plus que ce que j'es espèrais

pas bien grave j'ai 10 lignes pour recalibrer avant chaque sketche, m'enfin bon ... en EEPROM c'est plus cool
J'ai la tête comme une citrouille, mais le l'ai pris en main clairement, il est sympa
@+ suis naze  sroll

filou96

J'ai beaucoup progressé sur l'arduino , j'en suis à éditer les fichier .h et .cpp pour arriver a ce que je veux avec du matos pas toujours conforme ...

J'en suis aux boutons : c'est réglé via new .h et .cpp , Library RA8875.h du controleur de mon écran pourrie mais c'est la seule qui gère les 800x480 , incapable de m'afficher les label des boutons ... Et pas de choix de polices ...
J'ai fini par trouver , via édition du fichier .h et .cpp pour faire appel a des polices externes et les centrer sur mes boutons msk ( c'est pour Geloche ça ...)

Photo useless juste que ça marche, 20 lignes de code pour ça :D juste 2 for(){}; Je ferais des boutons finaux conformes à mes souhaits.

En plus malgré mes modif du .h et .cpp, le textMode() de l'écran fonctionne toujours avec leur unique police ( pas la même que les boutons ) , cf le "Hello,World! " !!! trop cool LOL

traffic.gif

filou96

Salut , reprise du développement , ça avance , controle d'un Spal brushless 12" par l'Arduino Uno , en fait je dissocie , l'Uno s'occupe du refroidissement , pas besoin d'écran, je branche l'ordi en USB si modif et après il s'autogère.
Je garde le Mega pour un écran multiparamètres.
C'est super pratique , je mets les Spal en route à 50% si clim moteur froid, dès que le moteur est à 85°C c'est la régulation normale qui prend le relai. Pour la pompe Stewart , je vais me la faire de MOSFET aussi ,  un branchement sur le fil rpm moteur et conditions de mise en route rpm < 900 / mn et tempé > 100°C et basta :D
Tout ça pour moins de 50 € ( sans les Spal LOL )

Question @geloche si tu as un avis , je fais une relation linéaire rpm Spal 20% - 100% pour fenetre de tempé 80 - 100°C ??? Ou j'essaye un PI(D) , ça complique un peu le prog, pour le moment je ne maitrise pas , j'ai la Library qui va bien , le problème c'est de me faire un modèle expérimental pour essais plus sophistiqué que le Spal branché à l'arrache et je me demande si la solution simple , une fois qques adaptations faites n'irait pas très bien ?
Merci

L'arduino uno et le thermocouple, je fais un rafraichissement toutes les 2 secondes .... Je pourrais faire 10 - 30 sec sans pb , j'ai pu baisser la fréquence du pin 3 à 122 Hz compatible avec le PWM du Spal .

traffic.gif

Exemple de Duty cycle à 21,59 % , oui c'est un duty cycle négatif , car le MOSFET et l'optocoupleur me l'inversent et j'ai un DT positif en 12 V à la sortie MOSFET.

traffic.gif

Le relais MOSFET avec optocoupleur isole l'Arduino du Spal et du 12 V , alim pour le Spal derrière, vous constatez que sans précharge il consomme peu à 21 %

traffic.gif


Une petite vidéo en chauffant le thermocouple , les coupures du Spal et de l'oscillo c'est moi qui touche le thermocouple avec le pistolet de soudure pb de terre, pas assez de main ni d'yeux LOL




jojo28500

Ah j'ai compris tu veux mettre ca sous la Mustang  "Là où on va, on n'a pas besoin de route !"  smk  smk 


filou96

Voila j'ai trouvé un modèle expérimental pour le PID, le Spal refroidit le thermocouple chauffé par par le pistolet air chaud

Purée "yapuka" programmer ;D et intégrer la clim et le régime moteur , heureusement j'ai tout ce qu'il faut pour simuler ça :D

Je peux aussi faire un cas particulier , rpm >= 4000 ou 4500 durant X secondes ventilos direct 100%

J ai mis rafraichissement tt les 30 sec ça lisse bcp mieux



filou96

Voila régule Spal PID à 88°C ( expérimental ), c'est vraiment hypersimple avec la Library dédiée , juste les coef K à affiner mais à +/- 0.5°C c'est bon, là y a Kp = 2 , Ki = 5, Kd =1.


filou96

Salut le prog complet est quasi terminé avec un petit affichage plus simple pour les réglages. PID sur 88°C , controle PWM des 2 Spal, controle de la clim moteur froid, et de la pompe électrique au ralenti moteur au dessus de 100°C

C'est pas la mort 130 lignes de prog avec plein de commentaires, le "bug" des 2 C pour la tempé , c'est que le C de plus de 100°C persiste quand ça repasse à 2 chiffres ... ah ah ...réglé y en a plus qu'un.
Je vais mettre ça sur un nano ( même code et mêmes sorties ) monté sur un shield avec bornier à vis , puis tout dans une boite et voila.



filou96

Salut , après plusieurs jours de debuggage GPS intégré

En fait explication finale flooding du hardware serial port par trop de données , il marchait sur le Mega ou j'ai 4 hardware serial ports , mais un seul sur le uno et pareil sur le nano ( celui du boitier final ) , j'ai mis longtemps à trouver , comme j'utiliserais le nano dans le version définitive , je suis passé en software serial ports. Heureusement , pleins de possibilités.
Ca va enfin , le nano est plein à 75% mais je vais élaguer , j'ai plein de scripts de debuggage.
Vous saurez même où j'habite les plus adroits LOL

Je vais pouvoir intégrer la variable "speed" pour controler ventilo and co c'est cool et hyper utile :D Le reste du GPS peut aussi dévier sur alarme etc ...

17:23:23.231 -> Time: 15:23:23.000
17:23:23.264 -> Date: 25/9/2023
17:23:23.264 -> Fix: 1 quality: 2
17:23:23.264 -> Temperature = 25.25°C
17:23:23.296 -> Location: 4859.5107N, 208.4787E
17:23:23.296 -> Speed km/h : 0
17:23:23.296 -> Angle: 186.10
17:23:23.296 -> Altitude: 97.50
17:23:23.296 -> Satellites: 6
17:23:23.296 -> Antenna status: 2
17:23:23.296 -> $GPRMC,152323.000,A,4859.5106,N,00208.4787,E,0.03,186.10,250923$PCD,11,2*65
17:23:24.153 -> $GPGGA,152324.000,4859.5106,N,00208.4787,E,2,06,1.51,97.5,M,47.2,M,,*51
17:23:24.252 -> $GPRMC,152324.000,A,4859.5106,N,00208.4787,E,0.01,186.10,250923,,,D*6C
17:23:25.143 -> $PCD,11,2*65
17:23:25.143 -> $GPGGA,152325.000,4859.5106,N,00208.4787,E,2,06,1.51,97.5,M,47.2,M,,*50

traffic.gif

geloche

Je suis jaloux :)
Super boulot !
Oui les possibilités de ces jouets sont infinies, on n'arrive pas à s'arrêter.
Faut vraiment que je m'y mette un jour.

Vib

Citation de: geloche le 25 Septembre 2023 à 20:41:42Je suis jaloux :)
Super boulot !
Oui les possibilités de ces jouets sont infinies, on n'arrive pas à s'arrêter.
Faut vraiment que je m'y mette un jour.

Citation de: filou96 le 25 Septembre 2023 à 20:16:48Salut , après plusieurs jours de debuggage GPS intégré
j'ai plein de scripts de debuggage.
Vous saurez même où j'habite les plus adroits

C'est sur si tu nous file ta position GPS😀😀
En tout les cas chapeau bas !
Vib
*GT2013 - Sterling Grey - Track Pack - Reccaro - Magnaflow Street ;-)

filou96

Voila le schéma de principe , peut être avec encore qques conneries ... Sur ma breadboard ça marche bien1

Un piège , il faut savoir que une pin non connectée , n'est pas LOW en fait , il faut intégrer ce détail, elle est "flottante" pour ça qu'il faut parfois des ponts ou des résistances tout court pour avoir une masse si le 5 ou 12 v est coupé, on aura alors la condition LOW stable et donc les commandes qui en découlent effectuées.
J'ai intégré un refroidissement automatique du bloc moteur après coupure du contact si le LDR qui circule est > 80°C ( valeur au pif à voir à l'usage ) grace à la pompe à eau électrique et les ventilos, ça évite de se retrouver avec une montée de 85°C à 110°C dans le bloc à l'arrèt quand on a bien roulé.

Entouré en jaune dans la boite à gant
Entouré en bleu relais automobiles normaux
Entouré en rouge : éléments extérieurs

Tout le reste c'est dans une boite pas très grande 10 X 8 X 7 cm avec couvercle transparent pour l'écran. Cliquez sur l'image pour agrandir.

traffic.gif

filou96

Vla le code brut pour les connaisseurs , évolutif bien sur et adaptable, attentio il y a plein de commentaires et de sections de debuggage pour le Serial monitor.
Elles sont moins visibles et ne sont pas compliées : prédédées de soit // pour la ligne ou alors /* paragraphe et */ à la fin, tout ça blabla ou debuggabe ;)
A la fin y a 1/3 du code qui vire, là juste pour le développement .

/* programme final pour le controle des ventilos , pompe stewart et divers paramètres
selon tempé , vitesse, RPM etc , je limite le debuggage la *************************/

#include <Adafruit_GPS.h>
#include <SoftwareSerial.h> // pas assez de tx/rx sauf sur le Mega
#include "max6675.h"  // chargement de la library thermocouple et PID
#include <PID_v1.h>   // pour le PID
#include <LiquidCrystal_I2C.h>    //Library écran i2c, consommation ++++++++++++écran 45 mA++++++++++++


SoftwareSerial mySerial(12, 2);   //création de l'instance GPS l'ordre c'est mySerial(Rx, Tx) Rx GPS est connecté à Tx Serial et Tx GPS est connecté à Rx serial
Adafruit_GPS GPS(&mySerial);

// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
// Set to 'true' if you want to debug and listen to the raw GPS sentences
//in the car it will be on "false"
#define GPSECHO false

LiquidCrystal_I2C lcd(0x27,20,4);     //déclaration écran i2c 20 caractères, 4 lignes
                                      //SDA = A4 = D18 , SCL = A5 = D19

double Setpoint, temperature, PWMval, PWMval1;     //déclaration variables PID, double = X.00

double Kp = 2, Ki = 5, Kd = 1;      //j'ai pris les K de base de l'exemple
PID myPID(&temperature, &PWMval, &Setpoint, Kp, Ki, Kd, DIRECT);    //déclaration du PID

const uint8_t soPin = 4;                         // thermocouple serial out
const uint8_t csPin = 5;                         // chip select
const uint8_t sckPin = 6;                        // serial clock pin
MAX6675 Module(sckPin, csPin, soPin);  // create instance object of MAX6675 thermocouple

unsigned long pHigh, pLow;       //variables diverses , plus pratique et code plus lisible
uint16_t RPM;
bool clim, pompe, contact;
const uint8_t pinClim = 10;     //entrée via entrée via pont de résistances 100 k et 47 kΩ  mise en route clim
const uint8_t pinContact = 9;   // + 12 V contact entrée via pont de résistances 100 k et 47 kΩ
const uint8_t pinPWM = 3;       // pin de qortie de commande des Spal en PWM via MOSFET et optocoupleur
const uint8_t pinRPM = 8;       //entrée via entrée via pont de résistances 100 k et 47 kΩ  capture RPM
const uint8_t pinPompe = 7;     //sortie mise en route de la pompe par relais
const uint8_t pinBat = 14;      // ou A0 maintien de 12V après arret en différé
const uint8_t pin3V = 15;
const uint8_t pin7V = 16;
const uint8_t pin12V = 17;
double tens3V, tens7V, tens12V ;
uint8_t speed;  //normes GPS en knots
uint8_t dutyCycle;
uint8_t count;


// make a cute degree symbol en décimal matrice 5X8 et e accent = é correct
// faire en binaire matrice 5X8 facile , le [8] signifie tableau de 8 octets
  byte degree[8] = {
    B01100,
    B10010,
    B10010,
    B01100,
    B00000,
    B00000,
    B00000,
    B00000,
    };

    byte eaccent[8] = {
      B00010,
      B00100,
      B01110,
      B10001,
      B11111,
      B10000,
      B01110,
      B00000,
    };



void setup()
{
 

lcd.init();
lcd.backlight();
  lcd.createChar(1, degree);
  lcd.createChar(2, eaccent);

  pinMode(pinRPM, INPUT);      //entrée signal RPM

  pinMode(pinPompe, OUTPUT);     //sortie signal mise en route pompe stewart
  digitalWrite(pinPompe, LOW);   //mise à l'arret de base de la pompe

  pinMode(pinClim, INPUT);     //détection clim ou pas
  digitalWrite(pinClim, LOW);   //au cas où mais pont de résistances
  clim = false;

  pinMode(pinContact, INPUT);
  digitalWrite(pinContact, LOW);    //au cas où mais pont de résistances

  pinMode(pinBat, OUTPUT);
  digitalWrite(pinBat, HIGH);   //si il a démaré c'est que le contact est mis , donc j'actionne le relai

  pinMode(pin3V, INPUT);
  pinMode(pin7V, INPUT);
  pinMode(pin12V, INPUT);

  Setpoint = 88;          //déclaration température cible en °C sur la voiture 90°C
  myPID.SetOutputLimits(120, 220);    //déclaration des limites du PWM Spal sur la voiture 255 = arret du Spal , min speed 25% pour DT 10% = 229 max speed pour DT 90% = 25 donc je mets (0, 255)
  myPID.SetMode(AUTOMATIC);

   /*********************ATTENTION PIN 11 AUSSI A 122 Hz donc ne pas utiliser***************************/

  pinMode(pinPWM, OUTPUT);   // passage du pin3 ( et 11 ) à 122 Hz pour commande PWM des Spal en DT
  TCCR2B &= 0b11111000;     
  TCCR2B |= 0b00000110;

  count = 0;

  //comment all Serial on the car, uncomment for debug

  // connect at 115200 so we can read the GPS fast enough and echo without dropping chars
  // also spit it out
  Serial.begin(115200);
  delay(5000);
  //Serial.println("Adafruit GPS library basic parsing test!");

  // 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
  //I think keep these lines
  GPS.begin(9600);
  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  // uncomment this line to turn on only the "minimum recommended" data
  //GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  // For parsing data, we don't suggest using anything but either RMC only or RMC+GGA since
  // the parser doesn't care about other sentences at this time
  // Set the update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 1 Hz update rate
  // For the parsing code to work nicely and have time to sort thru the data, and
  // print it out we don't suggest using anything higher than 1 Hz

  // Request updates on antenna status, comment out to keep quiet comment on car
  GPS.sendCommand(PGCMD_ANTENNA);

  delay(1000);

  // Ask for firmware version, comment on car
  //mySerial.println(PMTK_Q_RELEASE);




}

  uint32_t timer = millis();
  uint32_t timer1 = millis();
 



void loop() // uncomment for GPS data serial read for debug
{
  // read data from the GPS in the 'main loop'
  char c = GPS.read();
  // if you want to debug, this is a good time to do it! on the car comment this
  //if ((c) && (GPSECHO))
    //Serial.write(c);

  // if a sentence is received, we can check the checksum, parse it...
  if (GPS.newNMEAreceived()) {
    // a tricky thing here is if we print the NMEA sentence, or data
    // we end up not listening and catching other sentences!
    // so be very wary if using OUTPUT_ALLDATA and trying to print out data
    //Serial.print(GPS.lastNMEA()); // this also sets the newNMEAreceived() flag to false
    if (!GPS.parse(GPS.lastNMEA())) // this also sets the newNMEAreceived() flag to false
      return; // we can fail to parse a sentence in which case we should just wait for another
  }

  // approximately every 2 seconds or so, print out the current stats, on the car comment all
  /*if (millis() - timer > 2000) {
    timer = millis(); // reset the timer

    Serial.print("\nTime: ");
    if (GPS.hour < 10) { Serial.print('0'); }
    Serial.print(GPS.hour, DEC); Serial.print(':');
    if (GPS.minute < 10) { Serial.print('0'); }
    Serial.print(GPS.minute, DEC); Serial.print(':');
    if (GPS.seconds < 10) { Serial.print('0'); }
    Serial.print(GPS.seconds, DEC); Serial.print('.');
    if (GPS.milliseconds < 10) {
      Serial.print("00");
    } else if (GPS.milliseconds > 9 && GPS.milliseconds < 100) {
      Serial.print("0");
    }
    Serial.println(GPS.milliseconds);
    Serial.print("Date: ");
    Serial.print(GPS.day, DEC); Serial.print('/');
    Serial.print(GPS.month, DEC); Serial.print("/20");
    Serial.println(GPS.year, DEC);
    Serial.print("Fix: "); Serial.print((int)GPS.fix);
    Serial.print(" quality: "); Serial.println((int)GPS.fixquality);
    Serial.print("Temperature = "); Serial.print(temperature); Serial.println("°C");
    if (GPS.fix) {
      Serial.print("Location: ");
      Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
      Serial.print(", ");
      Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
      Serial.print("Speed km/h : "); Serial.println(speed);
      Serial.print("Angle: "); Serial.println(GPS.angle);
      Serial.print("Altitude: "); Serial.println(GPS.altitude);
      Serial.print("Satellites: "); Serial.println((int)GPS.satellites);
      Serial.print("Antenna status: "); Serial.println((int)GPS.antenna);    //modifié : 2 antenne ext, 1 antenne interne , 0 dysfonctionnement
    }
  }*/

  if (millis() - timer1 > 5000) {           //obligé de faire le reste des controles toutes les 5 sec
                                            //sinon le GPS a pas le temps de se mettre à jour et de transmettre
  timer1 = millis();

  contact = digitalRead(pinContact);
 
  pompe = digitalRead(pinPompe);

  temperature = ((Module.readCelsius()) - 4);  //lecture tempé, sonde 4° trop haut, i can change timer on the car, no serial pb

  dutyCycle = round(((255-PWMval1)/255)*100);

  if (contact == true ) {

  digitalWrite(pinBat, HIGH);
     
  speed = round(GPS.speed*1.852);     //passage knots en km/h

  clim = digitalRead(pinClim);       //le + 12 V clim rentrera ici via pont de résistances 100k - 47kΩ pour l'amener à 5V et qques mA


if (GPS.fix == 1) {     /****************obligé de séparer GPS.fix ou pas pour speed et tunnels ou autres pb de GPS*****************/

/**********************PID et PWM , l'analog ne doit pas être connecté**************************************/
/********POUR OVERRIDE si panne il faut mettre le PWM à la masse et l'analogue au plus ********************/

    if ((( speed >= 60 ) || ( speed < 60 && temperature < 50 )) && (clim == false)) { PWMval1 = 255; analogWrite(pinPWM, PWMval1); }


    if ( speed < 60 && temperature >= 50 ) {                       //je commence à 50°C qu'il ai le temps
        myPID.Compute();                    //le PID fait son taf mais pas forcément répercuté sur le ventilo
          if ( PWMval>=200 && clim == true ) { PWMval1 = 200; analogWrite(pinPWM, PWMval1);}           //et il calcule le PWMval soit le PWM qui ne sera appliqué que si il est inf à 200 si clim ON
            else { analogWrite(pinPWM, PWMval); PWMval1 = PWMval; }
   
    }
     
     
 
/************************CLIMATISATION ou NON****************************/

  if ( speed < 60 && clim == true && temperature<50 ) { PWMval1 = 200; analogWrite(pinPWM, PWMval1); }      // mise du Spal à 50% soit 127 dans la voiture si speed < 50 km/h
 
      else { analogWrite(pinPWM, PWMval); PWMval1 = PWMval; }      // mise du Spal à la vitesse du PWM

}

else {        /****************si GPS.fix == 0 j'utilise les RPM *****************/

  if ((( RPM >= 1500 ) || ( RPM < 1500 && temperature < 50 )) && (clim == false)) { PWMval1 = 255; analogWrite(pinPWM, PWMval1); }


    if ( RPM < 1500 && temperature >= 50 ) {                       //je commence à 50°C qu'il ai le temps
        myPID.Compute();                    //le PID fait son taf mais pas forcément répercuté sur le ventilo
          if ( PWMval>=200 && clim == true ) { PWMval1 = 200; analogWrite(pinPWM, PWMval1);}           //et il calcule le PWMval soit le PWM qui ne sera appliqué que si il est inf à 200 si clim ON
            else { analogWrite(pinPWM, PWMval); PWMval1 = PWMval; }
   
    }
     
     
 
/************************CLIMATISATION ou NON****************************/

  if ( RPM < 1500 && clim == true && temperature<50 ) { PWMval1 = 200; analogWrite(pinPWM, PWMval1); }      // mise du Spal à 50% soit 127 dans la voiture si speed < 50 km/h
 
      else { analogWrite(pinPWM, PWMval); PWMval1 = PWMval; }      // mise du Spal à la vitesse du PWM


}

/************************POMPE STEWART*********************************/

  pHigh = pulseIn(pinRPM, HIGH);   //temps en µs du signal haut du RPM
  pLow = pulseIn(pinRPM, LOW);      //temps en µs du signal bas du RPM
  RPM = ((1000000/(pHigh+pLow))*2);   //calcul RPM
 
  if ( (temperature > 90) && ((speed < 10 && GPS.fix == 1)  || (RPM < 1000)  ))  { digitalWrite(pinPompe, HIGH); } else { digitalWrite(pinPompe, LOW); }    //conditions de mise en route de la pompe Stewart par le pin 7 moins de 1000 rpm et temp >= 100°C
 

 
 }          //fin du if (contact == true)

  /*******************calcul des voltages***************************************/

  tens3V = ((analogRead (pin3V)) * 0.0046);   //normalement 0.0049 v par unité de 0 à 1053 , en fait pas vraiment car on a plutot 4.67V
  tens7V = ((analogRead (pin7V)) * 0.0098);
  tens12V = ((analogRead (pin12V)) * 0.0153);

     /******************    écriture de l'écran  , une page par passage / 5 sec   ******************************/

  if (count <= 3) {
   

 if (count == 2) {
 
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Temp"); lcd.write(2); lcd.print("rature = ");
  lcd.print(round(temperature)); lcd.write(1); lcd.print("C ");
  lcd.setCursor(0,1);
  lcd.print("Duty cycle = "); lcd.print(dutyCycle); lcd.print(" %  ");
  lcd.setCursor(0,2);
  lcd.print("KM/H : "); lcd.print(speed);  lcd.print(" RPM "); lcd.print(RPM); lcd.print("   ");
  lcd.setCursor(0,3);
  lcd.print("Clim : "); lcd.print(clim); lcd.print(" Pompe : "); lcd.print(pompe);
 }

 if (count == 3) {

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Reg 3V = "); lcd.print(tens3V); lcd.print("V");
  lcd.setCursor(0,1);
  lcd.print("Reg 7V = "); lcd.print(tens7V); lcd.print("V");
  lcd.setCursor(0,2);
  lcd.print("Volts Batt = "); lcd.print(tens12V);  lcd.print("V");
  lcd.setCursor(0,3);
  lcd.print("Fix "); lcd.print(GPS.fix); lcd.print(" Sat "); lcd.print(GPS.satellites); lcd.print(" Ant "); lcd.print(GPS.antenna);
}

if (count == 1) {

    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Date: ");
    lcd.print(GPS.day); lcd.print('/');
    lcd.print(GPS.month); lcd.print("/20");
    lcd.print(GPS.year);
    lcd.setCursor(0,2);
    lcd.print("Time GMT  : ");
    if (GPS.hour < 10) { lcd.print('0'); }
    lcd.print(GPS.hour); lcd.print(':');
    if (GPS.minute < 10) { lcd.print('0'); }
    lcd.print(GPS.minute); lcd.print(':');
    if (GPS.seconds < 10) { lcd.print('0'); }
    lcd.print(GPS.seconds);
    lcd.setCursor(0,3);
    lcd.print("Time local: ");
    if ((GPS.hour+2) < 10) { lcd.print('0'); }
    lcd.print(GPS.hour+2); lcd.print(':');
    if (GPS.minute < 10) { lcd.print('0'); }
    lcd.print(GPS.minute); lcd.print(':');
    if (GPS.seconds < 10) { lcd.print('0'); }
    lcd.print(GPS.seconds);
   
   
}


}
else {count = 0;}
count++;
 
  }
 
   
    if ( (contact == false) && (temperature > 20)) {
     
      PWMval1 = 127; analogWrite(pinPWM, PWMval1);      //ventilos mi-régime
      digitalWrite(pinPompe, HIGH);                     //mise en route de la pompe

    }

    if ((contact == false) && (temperature <= 20)) {
      delay(5000);                   //vérif que ventilos OK et pompe OK penda t 5 sec
      digitalWrite(pinBat, LOW);     //coupure totale alim batterie arduino sauf pour le GPS en 3V
     
    }

 
}