Allez, un premier essai pour variateur en mode crawler (freinage drag brake) On a : - feu stop au neutre pendant 5sec + feu stop 1seconde en cas de décélération brusque - feu de recul en marche arrière (pas pu vérifier, je crois que j'ai grillé ma led ) - warning sur volant maintenu à gauche au neutre des gaz pendant 5sec (fonction impulsionnelle) - phares sur volant maintenu à droite au neutre des gaz pendant 5sec (fonction impulsionnelle) - sortie D4 en mode feu stop simple fonction - sortie D5 en mode feu arriere double fonction stop/position par PWM Câblage absolument identique à précédemment Tout ça sans utiliser un éventuel CH3. ça laisse donc la possibilité de réserver CH3 a un treuil par exemple (c'est mon cas). Mais ça peut aussi du coup focntioner sur des tx basiques à 2canaux #include <Servo.h> const byte ch2Pin = 2; const byte ch1Pin = 3; const byte outputD4 = 4; const byte outputD5 = 5; const byte outputD6 = 6; const byte D7_TOGGLE = 7; const byte outputD9 = 9; // =============================== // SEUILS CH2 // =============================== const int NEUTRE_MIN = 1300; const int NEUTRE_MAX = 1600; // Hysteresis autour du neutre const int SORTIE_NEUTRE_ARRIERE = 1250; const int SORTIE_NEUTRE_AVANT = 1650; // Variation nécessaire pour déclencher un freinage rapide const int VARIATION_FREIN = 100; // Variation nécessaire pour réarmer le frein const int REMISE_GAZ = 50; // =============================== // TEMPORISATIONS // =============================== const unsigned long DUREE_FREIN_RAPIDE = 1000; const unsigned long DUREE_FREIN_NEUTRE = 5000; const unsigned long DUREE_MAINTIEN_TOGGLE = 5000; const unsigned long DUREE_CLIGNOTEMENT = 500; // =============================== // SEUILS CH1 // =============================== const int CH1_GAUCHE = 1500; const int CH1_DROITE = 1300; // =============================== // PWM D5 // =============================== const int PWM_D5_VEILLEUSE = 60; const int PWM_D5_STOP = 255; // =============================== // VARIABLES CH1 / CH2 // =============================== int ch1 = 1500; int ch2 = 1500; int ch2Precedent = 1500; int referenceGaz = 1500; // =============================== // VARIABLES FREIN // =============================== bool freinActif = false; bool freinRapideActif = false; unsigned long debutFrein = 0; unsigned long debutNeutre = 0; bool etaitAuNeutre = false; bool freinArme = true; // =============================== // VARIABLES D6 WARNING // =============================== bool clignotementD6 = false; bool etatD6 = false; unsigned long debutMaintienD6 = 0; bool toggleD6DejaEffectue = false; unsigned long dernierChangementD6 = 0; // =============================== // VARIABLES D7 // =============================== bool etatD7 = false; unsigned long debutMaintienD7 = 0; bool toggleD7DejaEffectue = false; // =============================== // GESTION D5 // =============================== void mettreAJourD5() { if (freinActif) { // D4 ON = STOP // D5 à la puissance STOP analogWrite(outputD5, PWM_D5_STOP); } else if (etatD7) { // D7 ON sans frein // D5 en mode VEILLEUSE analogWrite(outputD5, PWM_D5_VEILLEUSE); } else { // D7 OFF et D4 OFF // D5 éteint analogWrite(outputD5, 0); } } // =============================== // ALLUMAGE FREIN // =============================== void allumerFrein() { digitalWrite(outputD4, HIGH); freinActif = true; mettreAJourD5(); } // =============================== // EXTINCTION FREIN // =============================== void eteindreFrein() { digitalWrite(outputD4, LOW); freinActif = false; mettreAJourD5(); } // =============================== // GESTION TOGGLE D6 // CH1 GAUCHE + CH2 NEUTRE // MAINTIEN 5 SECONDES // =============================== void gererToggleD6(unsigned long maintenant, bool neutre) { bool ch1Gauche = (ch1 >= CH1_GAUCHE); if (ch1Gauche && neutre) { if (debutMaintienD6 == 0) { debutMaintienD6 = maintenant; Serial.println(); Serial.println("D6 : CH1 GAUCHE + CH2 NEUTRE"); Serial.println("MAINTIEN 5 SECONDES..."); } if (!toggleD6DejaEffectue && maintenant - debutMaintienD6 >= DUREE_MAINTIEN_TOGGLE) { toggleD6DejaEffectue = true; clignotementD6 = !clignotementD6; if (clignotementD6) { etatD6 = true; digitalWrite(outputD6, HIGH); dernierChangementD6 = maintenant; Serial.println("D6 : CLIGNOTEMENT ON"); } else { etatD6 = false; digitalWrite(outputD6, LOW); Serial.println("D6 : CLIGNOTEMENT OFF"); } } } else { debutMaintienD6 = 0; toggleD6DejaEffectue = false; } } // =============================== // CLIGNOTEMENT D6 // =============================== void gererClignotementD6(unsigned long maintenant) { if (!clignotementD6) { digitalWrite(outputD6, LOW); etatD6 = false; return; } if (maintenant - dernierChangementD6 >= DUREE_CLIGNOTEMENT) { dernierChangementD6 = maintenant; etatD6 = !etatD6; digitalWrite(outputD6, etatD6 ? HIGH : LOW); } } // =============================== // GESTION TOGGLE D7 // CH1 DROITE + CH2 NEUTRE // MAINTIEN 5 SECONDES // =============================== void gererToggleD7(unsigned long maintenant, bool neutre) { bool ch1Droite = (ch1 <= CH1_DROITE); if (ch1Droite && neutre) { if (debutMaintienD7 == 0) { debutMaintienD7 = maintenant; Serial.println(); Serial.println("D7 : CH1 DROITE + CH2 NEUTRE"); Serial.println("MAINTIEN 5 SECONDES..."); } if (!toggleD7DejaEffectue && maintenant - debutMaintienD7 >= DUREE_MAINTIEN_TOGGLE) { toggleD7DejaEffectue = true; etatD7 = !etatD7; digitalWrite(D7_TOGGLE, etatD7 ? HIGH : LOW); mettreAJourD5(); if (etatD7) { Serial.println("D7 : ON"); } else { Serial.println("D7 : OFF"); } } } else { debutMaintienD7 = 0; toggleD7DejaEffectue = false; } } // =============================== // SETUP // =============================== void setup() { pinMode(ch2Pin, INPUT); pinMode(ch1Pin, INPUT); pinMode(outputD4, OUTPUT); pinMode(outputD5, OUTPUT); pinMode(outputD6, OUTPUT); pinMode(D7_TOGGLE, OUTPUT); pinMode(outputD9, OUTPUT); digitalWrite(outputD4, LOW); analogWrite(outputD5, 0); digitalWrite(outputD6, LOW); digitalWrite(D7_TOGGLE, LOW); digitalWrite(outputD9, LOW); Serial.begin(9600); Serial.println(); Serial.println("================================="); Serial.println("FEUX STOP CRAWLER"); Serial.println("TEST CH1 / CH2"); Serial.println("================================="); } // =============================== // LOOP PRINCIPALE // =============================== void loop() { unsigned long maintenant = millis(); // ============================= // LECTURE CH2 // ============================= ch2 = pulseIn(ch2Pin, HIGH, 25000); if (ch2 == 0) { ch2 = ch2Precedent; } // ============================= // LECTURE CH1 // ============================= ch1 = pulseIn(ch1Pin, HIGH, 25000); if (ch1 == 0) { ch1 = 1500; } // ============================= // MONITEUR SERIE // ============================= Serial.print("CH1 = "); Serial.print(ch1); Serial.print(" CH2 = "); Serial.println(ch2); // ============================= // DETECTION NEUTRE // ============================= bool neutre = (ch2 >= NEUTRE_MIN && ch2 <= NEUTRE_MAX); // ============================= // FEUX DE RECUL D9 // CH2 < 1300 // ============================= if (ch2 < NEUTRE_MIN) { digitalWrite(outputD9, HIGH); } else { digitalWrite(outputD9, LOW); } // ============================= // TOGGLE D6 // ============================= gererToggleD6(maintenant, neutre); // ============================= // CLIGNOTEMENT D6 // ============================= gererClignotementD6(maintenant); // ============================= // TOGGLE D7 // ============================= gererToggleD7(maintenant, neutre); // ============================= // GESTION DU NEUTRE // ============================= if (neutre) { if (!etaitAuNeutre) { etaitAuNeutre = true; debutNeutre = maintenant; allumerFrein(); Serial.println("ENTREE AU NEUTRE : FREIN"); } // Après 5 secondes au neutre, // extinction du frein if (maintenant - debutNeutre >= DUREE_FREIN_NEUTRE) { eteindreFrein(); } ch2Precedent = ch2; delay(20); return; } // ============================= // HYSTERESIS AUTOUR DU NEUTRE // ============================= bool zoneHysteresis = (ch2 >= SORTIE_NEUTRE_ARRIERE && ch2 <= SORTIE_NEUTRE_AVANT); if (etaitAuNeutre) { if (zoneHysteresis) { ch2Precedent = ch2; delay(20); return; } etaitAuNeutre = false; eteindreFrein(); Serial.println("SORTIE REELLE DU NEUTRE"); } // ============================= // DIRECTION // ============================= bool marcheAvant = (ch2 > NEUTRE_MAX); bool marcheArriere = (ch2 < NEUTRE_MIN); // ============================= // FREINAGE RAPIDE // ============================= if (freinArme) { // Freinage rapide en marche avant if (marcheAvant) { if (ch2Precedent - ch2 >= VARIATION_FREIN) { allumerFrein(); freinRapideActif = true; debutFrein = maintenant; freinArme = false; Serial.println("FREINAGE RAPIDE AVANT"); } } // Freinage rapide en marche arrière if (marcheArriere) { if (ch2 - ch2Precedent >= VARIATION_FREIN) { allumerFrein(); freinRapideActif = true; debutFrein = maintenant; freinArme = false; Serial.println("FREINAGE RAPIDE ARRIERE"); } } } // ============================= // FIN DU FREINAGE RAPIDE // ============================= if (freinRapideActif) { if (maintenant - debutFrein >= DUREE_FREIN_RAPIDE) { eteindreFrein(); freinRapideActif = false; Serial.println("FIN FREINAGE RAPIDE"); } } // ============================= // REARMEMENT DU FREIN // ============================= if (!freinArme && !freinRapideActif) { if (marcheAvant) { if (ch2 >= referenceGaz + REMISE_GAZ) { freinArme = true; referenceGaz = ch2; Serial.println("FREIN REARME AVANT"); } } if (marcheArriere) { if (ch2 <= referenceGaz - REMISE_GAZ) { freinArme = true; referenceGaz = ch2; Serial.println("FREIN REARME ARRIERE"); } } } // ============================= // MEMORISATION CH2 // ============================= ch2Precedent = ch2; delay(20); }