Age : 44 Localisation : 67000 STRASBOURG Nombre de messages : 4563 Date d'inscription : 29/10/2015
Sujet: Les expérimentations de Sierramike Sam 23 Juil 2016 - 0:43
Bonjour à tous,
Pour ne pas polluer le post de mon réseau, ni celui de iChooChoo, j'ai choisi d'ouvrir un nouveau post dans lequel je publierai mes diverses expérimentations, n'hésitez pas à poser des questions !
En général, tout part de tutos trouvés sur Internet au sujet d'un composant particulier, que je modifie ensuite pour l'adapter à mes besoins ou simplement universaliser le résultat.
Mes petites expérimentations du jour : Arduino + Module ultra-sons HC-SR04 pour détecter le passage d'un train.
Ce module effectue une mesure de distance lorsqu'il reçoit une impulsion d'au moins 10 microsecondes sur sa broche "trigger". Le système est programmé pour effectuer les mesures sur les deux modules l'un après l'autre. La distance détectée est alors inscrite sur l'afficheur LCD. Le système effectue une mesure toutes les 250 millisecondes (4 mesures par seconde).
sierramike Membre
Age : 44 Localisation : 67000 STRASBOURG Nombre de messages : 4563 Date d'inscription : 29/10/2015
Sujet: Re: Les expérimentations de Sierramike Sam 23 Juil 2016 - 22:19
Suite des expérimentations : un module de traction automatique en analogique en utilisant la PWM.
Le sketch Arduino est conçu pour : 1) Surveiller la pression des 3 boutons Drive, Stop, Reverse 2) Configurer la FAST PWM sur la broche 9 3) Définir les vitesses de démarrage, maxi (dans chaque sens), arrêt 4) Ne pas autoriser de manoeuvre interdite (inversion de sens avant l'arrêt)
Dans un deuxième temps, le circuit de détection par ultra-son est programmé pour une sortie bas niveau (LED éteinte) en cas de détection. Cette sortie est simplement raccordée à l'entrée du bouton STOP. De cette manière, la détection du train par le module à ultra-sons va commander l'arrêt du train.
Le module de puissance LMD18200 est utilisé comme booster PWM. L'entrée PWM est raccordée à la sortie Digital 9 de l'Arduino, afin d'amplifier le signal PWM produit par l'Arduino. L'entrée "DIR" du module est connectée à la sortie Digital 7 de l'Arduino (choix arbitraire). Cette entrée permet de choisir la polarité du courant de sortie, donc le sens de circulation.
Sketch Arduino :
Code:
#define SPD_START 120 // Speed value when starting acceleration #define SPD_STOP 0 // Speed value when ending deceleration #define DUR_ACC 2000 // Acceleration speed (duration from START to MAX) #define DUR_DEC 2000 // Deceleration speed (duration from actual to STOP) #define SPD_MAX_D 200 // Maximum speed value in Drive direction #define SPD_MAX_R 150 // Maximum speed value in Reverse direction
#define PIN_PWM 9 // Pin connected to PWM input of LMD18200 module #define PIN_DIR 7 // Pin connected to Direction input of LMD18200 module
#define PIN_BTN_D 2 // Pin connected to "DRIVE" button (short to ground) #define PIN_BTN_S 3 // Pin connected to "STOP" button (short to ground) #define PIN_BTN_R 4 // Pin connected to "REVERSE" button (short to ground)
int _iActiveSpeed = 0; // Stores actual speed int _iTargetSpeed = 0; // Stores speed to be reached at end of acceleration/deceleration char _cStatus = '0'; // '0' = Steady, 'A' = Accelerate, 'D' = Decelerate char _cDirection = 'S'; // 'S' = Stop, 'D' = Drive, 'R' = Reverse long _lInterval = 0; // Interval duration in milliseconds (between each increment/decrement)
void loop() { // Following tests prevent being able to change direction if engine is still running
// If button "STOP" pressed, and status is NOT "Decelerate" and direction is NOT "STOP" if (digitalRead(PIN_BTN_S) == LOW) { delay(10); if (digitalRead(PIN_BTN_S) == LOW) if (_cStatus != 'D' && _cDirection != 'S') Stop(); } // If button "DRIVE" pressed, and direction is "STOP" else if (digitalRead(PIN_BTN_D) == LOW) { delay(10); if (digitalRead(PIN_BTN_D) == LOW) if (_cDirection == 'S') Drive(); } // If button "REVERSE" is pressed, and direction is "STOP" else if (digitalRead(PIN_BTN_R) == LOW) { delay(10); if (digitalRead(PIN_BTN_R) == LOW) if (_cDirection == 'S') Reverse(); }
// Update speed value on each loop Update(); }
long _lOldTimeStamp = 0;
void Update() { long l = millis(); // If interval length has been reached if (l > _lOldTimeStamp + _lInterval) { // Increment of decrement actual speed depending of status if (_cStatus == 'A') { _iActiveSpeed++; Serial.println(_iActiveSpeed); } else if (_cStatus == 'D') { _iActiveSpeed--; Serial.println(_iActiveSpeed); }
// If target speed is reached, stop acceleration or deceleration if (_iActiveSpeed == _iTargetSpeed) { _lInterval = 0; _cStatus = '0'; // If stop speed is reached, set full stop if (_iActiveSpeed == SPD_STOP) { _iActiveSpeed = 0; _cDirection = 'S'; } }
_lOldTimeStamp = l; }
// Update output pins if (_cDirection == 'D') digitalWrite(PIN_DIR, HIGH); else if (_cDirection == 'R') digitalWrite(PIN_DIR, LOW);
Dernière édition par sierramike le Sam 23 Juil 2016 - 22:40, édité 1 fois
sierramike Membre
Age : 44 Localisation : 67000 STRASBOURG Nombre de messages : 4563 Date d'inscription : 29/10/2015
Sujet: Re: Les expérimentations de Sierramike Sam 23 Juil 2016 - 22:21
Expérimentation suivante, très simple, la mise en oeuvre de la librairie CmdrArduino pour la génération d'un signal DCC, en application de l'excellent article sur Locoduino : http://www.locoduino.org/spip.php?article17
SavignyExpress Membre
Age : 61 Localisation : yyy Nombre de messages : 2043 Date d'inscription : 10/10/2010
Sujet: Re: Les expérimentations de Sierramike Dim 24 Juil 2016 - 11:28
Bonjour Sierramike,
C'est sympa de partager tes expérimentations avec nous.
Prévois-tu de poster les schémas ?
Tout bon dimanche et bel été.
sierramike Membre
Age : 44 Localisation : 67000 STRASBOURG Nombre de messages : 4563 Date d'inscription : 29/10/2015
Sujet: Re: Les expérimentations de Sierramike Lun 31 Oct 2016 - 0:55
Je vais essayer d'utiliser Fritzing pour faire un petit Schéma.
En attendant, l'expérimentation de ce soir, le pilotage de la plaque tournante Fleischmann, qui n'est pas un réel succès. (Voir le sujet ici) :
[/quote]
Boutons reliés aux pins suivantes (l'appui sur un bouton provoque la mise à la masse) : - Pin 2 : Sortie précédente - Pin 3 : Sortie suivante - Pin 4 : Go (lance le mouvement) - Pin 5 : Calibration
Sorties branchées comme telles : - Pin 9 : Entrée "DIR" du module LMD18200 - Pin 11 : Entrée "IN" d'un relais - Pin 7 : Entrée "PWM" du module LMD18200
12V continu branché en entrée du LDM18200 Fils jaune et rouge de la plaque tournante branchés en sortie du LMD18200 Fil jaune branché aussi en position centrale du relais Fil gris branché en contact "travail" du relais
Le relais permet de déclencher et maintenir le mouvement du pont tournant. La pin 7 reste à l'état haut pour activer la sortie permanente du LMD18200. La pin 9 détermine le sens de rotation du pont tournant en agissant sur la polarité du courant de sortie.
if (buttons.newPress(0)) // Button calibration, for calibration steps { Calibrate(); } else if (buttons.newPress(1)) // Button "Previous", move the desired position forwards { if (_ulMoveForwardDelay == 0) // If no calibration data present, do a single default move MoveNext(); else { _iBridgePosition--; ValidateBridgePosition(); #ifdef DEBUG Serial.print(F("Position requested : ")); Serial.println(_iBridgePosition); #endif } } else if (buttons.newPress(2)) // Button "Next", move the desired position backwards { if (_ulMoveBackwardDelay == 0) // If no calibration data present, do a single default move MovePrevious(); else { _iBridgePosition++; ValidateBridgePosition(); #ifdef DEBUG Serial.print(F("Position requested : ")); Serial.println(_iBridgePosition); #endif } } else if (buttons.newPress(3)) // Button "Go", starts moving the bridge { MoveBridge(); } }
// If desired position is outside bounds, put it back into the bounds void ValidateBridgePosition() { if (_iBridgePosition >= BRIDGEPOSITIONS) _iBridgePosition -= BRIDGEPOSITIONS; if (_iBridgePosition < 0) _iBridgePosition += BRIDGEPOSITIONS; }
// Calibration process : // 1) Press button : starts moving the bridge forwards // 2) Press button when bridge completes a full 360 : records the time needed for a forward move // 3) Press button : starts moving the bridge backwards // 4) Press button when bridge completes a full 360 : records the time needed for a backward move void Calibrate() { if (_iCalibrationStatus == 0) // Start calibration in forward way { #ifdef DEBUG Serial.println(F("Starting forward calibration.")); #endif _iCalibrationStatus = 1; _ulMoveForwardDelay = millis(); SetDirection(true); digitalWrite(PIN_BRIDGEMOVE, RELAY_ON); } else if (_iCalibrationStatus == 1) // End calibration in forward way (calculate delay) { #ifdef DEBUG Serial.println(F("End of forward calibration.")); #endif _iCalibrationStatus = 2; unsigned long ulTotal = millis() - _ulMoveForwardDelay; _ulMoveForwardDelay = ulTotal / BRIDGEPOSITIONS; SetDirection(true); digitalWrite(PIN_BRIDGEMOVE, RELAY_OFF); #ifdef DEBUG Serial.print(F("Forward delay (ms) : ")); Serial.println(_ulMoveForwardDelay); #endif } else if (_iCalibrationStatus == 2) // Start calibration in backard way { #ifdef DEBUG Serial.println(F("Starting backward calibration.")); #endif _iCalibrationStatus = 3; _ulMoveBackwardDelay = millis(); SetDirection(false); digitalWrite(PIN_BRIDGEMOVE, RELAY_ON); } else if (_iCalibrationStatus == 3) // End calibration in backward way (calculate delay) { #ifdef DEBUG Serial.println(F("End of backward calibration.")); #endif _iCalibrationStatus = 0; unsigned long ulTotal = millis() - _ulMoveBackwardDelay; _ulMoveBackwardDelay = ulTotal / BRIDGEPOSITIONS; SetDirection(false); digitalWrite(PIN_BRIDGEMOVE, RELAY_OFF); #ifdef DEBUG Serial.print(F("Backward delay (ms) : ")); Serial.println(_ulMoveBackwardDelay); #endif } }
// Starts moving the bridge void MoveBridge() { if (_iBridgePosition != _iBridgeActual) // Do nothing if the desired position is same as actual { #ifdef DEBUG Serial.print(F("Moving bridge from position ")); Serial.print(_iBridgeActual); Serial.print(F(" to position ")); Serial.println(_iBridgePosition); #endif
int iHalfOutputs = BRIDGEPOSITIONS / 2;
int iMove = _iBridgePosition - _iBridgeActual; bool bDirection = (iMove > 0); int iAbsMove = abs(iMove); if (iAbsMove > iHalfOutputs) // If move is more than half turn, then move the other direction { iAbsMove -= BRIDGEPOSITIONS; iAbsMove = abs(iAbsMove); bDirection = !bDirection; }
// Do the actual move SetDirection(bDirection); digitalWrite(PIN_BRIDGEMOVE, RELAY_ON); delay(ulDelay); digitalWrite(PIN_BRIDGEMOVE, RELAY_OFF); _iBridgeActual = _iBridgePosition; #ifdef DEBUG Serial.println(F("End of move.")); #endif } #ifdef DEBUG else Serial.println(F("No need to move.")); #endif }
// Do a single move forwards void MoveNext() { #ifdef DEBUG Serial.println(F("Single move forward.")); #endif SetDirection(true); digitalWrite(PIN_BRIDGEMOVE, RELAY_ON); delay(500); digitalWrite(PIN_BRIDGEMOVE, RELAY_OFF); }
// Do a single move backwards void MovePrevious() { #ifdef DEBUG Serial.println(F("Single move backward.")); #endif SetDirection(false); digitalWrite(PIN_BRIDGEMOVE, RELAY_ON); delay(500); digitalWrite(PIN_BRIDGEMOVE, RELAY_OFF); }
Age : 44 Localisation : 67000 STRASBOURG Nombre de messages : 4563 Date d'inscription : 29/10/2015
Sujet: Re: Les expérimentations de Sierramike Lun 31 Oct 2016 - 0:58
J'en profite pour publier le code source de ma petite librairie "ArduPress" qui permet de se simplifier la vie pour gérer jusqu'à 8 boutons sans avoir à gérer le dé-bounce à chaque fois dans le script :
ArduPress.h :
Code:
/******************************************************************** This is a simple buttons manager, designed to manage up to 8 buttons using 8 pins of the Arduino, while keeping the smallest footprint possible in memory. Unlike other libraries, this one uses a single byte in memory to keep track of 8 buttons status, and another single byte to store the 8 previous buttons status. The library handles debounce for you. The library uses internal Pull-up resistors. Buttons should switch inputs to ground.
Written by Stephane Moitry (aka 'sierramike'). http://stephane.moitry.fr
BSD license, check license.txt for more information. All text above must be included in any redistribution. ********************************************************************/
void ArduPress::init() { for (int i = 0; i < _quantity; i++) { pinMode(_pins[i], INPUT_PULLUP); digitalWrite(_pins[i], HIGH); //activate built-in pull-up resistor } }
void ArduPress::checkStatus() { _oldStatus = _status; for (byte i = 0; i < _quantity; i++) bitWrite(_firstStatus, i, !digitalRead(_pins[i])); delay(50); for (byte i = 0; i < _quantity; i++) { if (!bitRead(_firstStatus, i) == (!digitalRead(_pins[i]) == 1)) bitWrite(_status, i, !bitRead(_firstStatus, i)); } }
Age : 44 Localisation : 67000 STRASBOURG Nombre de messages : 4563 Date d'inscription : 29/10/2015
Sujet: Re: Les expérimentations de Sierramike Lun 31 Oct 2016 - 1:08
Deuxième expérimentation du jour : la génération du signal DCC.
Sur la même base que le test précédent de juillet, j'ai surtout trouvé pourquoi je n'arrivais plus à le faire marcher : j'avais branché l'entrée "PWM" sur une pin de l'Arduino pour la traction analogique, puis j'ai oublié de modifier le sketch DCC pour forcer cette pin à l'état haut ...
Bref, j'en ai profité pour revoir le sketch, et en faire une version à 4 boutons et virer le potentiomètre qui manque de précision.
Boutons reliés aux pins suivantes (l'appui sur un bouton provoque la mise à la masse) : - Pin 2 : Ralentir - Pin 3 : Accélérer - Pin 4 : Allumer/Éteindre les feux - Pin 5 : Stop/Changement de direction
Sorties branchées comme telles : - Pin 9 : Entrée "DIR" du module LMD18200 - Pin 7 : Entrée "PWM" du module LMD18200
12V continu branché en entrée du LDM18200 Sortie du LMD18200 reliée aux rails
La pin 7 reste à l'état haut pour activer la sortie permanente du LMD18200. La pin 9 génère le signal DCC qui consiste en un signal carré oscillant entre +12V et -12V, et dont la période détermine chaque bit 0 ou 1.
L'accélération et décélération fonctionne par pas de 10 jusqu'à la valeur maxi de 127. Le bouton stop force la valeur "MIN" de 1. (0 provoque l'arrêt d'urgence brutal). Lorsque la vitesse est à la valeur MIN (donc 1), chaque appui suivant inverse le sens de marche (donc on passe de 1 à -1 et vice versa. 1 ou -1 signifie l'arrêt, donc la locomotive n'avance pas, mais les feux correspondent au sens désiré).