Éclairer ses bâtiments aléatoirement avec Arduino

Lorsque l’on représente des villages au sein d’un décor ferroviaire, arrive le jour où se pose la question de l’éclairage et de l’ajout des poteaux qui éclairent la rue (ou les maisons). Ajouter de l’éclairage à ces villages apporte un plus et un certain charme au rendu de la maquette.

Généralement ce type d’éclairage est commandé par un interrupteur et allume toute la série de poteaux de la ruelle en une seule action. De ce constat est partie l’idée d’ajouter un peu plus de réalisme avec une séquence d’éclairage aléatoire.

Ainsi nous réaliserons ici une séquence d’allumage de plusieurs leds, qui s’allumeront les unes après les autres de façon aléatoire. Le tout pour donner de la vie à la maquette !

Arduino pour commander des Leds

Lorsque l’on débute en Arduino, les premiers programmes « découverte » nous amènent à tester l’affichage d’une LED, la faire clignoter et généralement la commander avec un bouton poussoir.

Dans notre cas, une dizaine de leds seront reliées à l’Arduino et s’allumeront les unes après les autres de façon aléatoire de manière à créer une séquence. Cette séquence sera initiée (phase d’allumage ou d’éteinte des leds) par le bouton poussoir.

 
 
 
 

Quelques notions d’Arduino

Ce montage permet également d’appréhender quelques notions de base en Arduino qui pourront servir pour d’autres programmes.

Pulse With Modulation (PWM)

Cela consiste à mettre la sortie à l’état haut (+5V) pendant une durée puis à l’état bas (masse) un certain temps afin de créer une tension moyenne sur cette sortie. En jouant sur les durées des états, on augmente ou l’on diminue la tension moyenne en sortie. Certaines broches de l’Arduino sont natives PWM. Comme ici nous avons besoins qu’elles le soient toutes, alors le mode PWM est réalisé de façon logicielle (et non de façon matérielle en utilisant les fonctionnalités natives.)

Résistance de Pull-UP

Lorsque l’on utilise un bouton poussoir relié à l’état haut (+5V) et à l’état bas (masse), il en résulte un court circuit lorsque l’on enfonce le bouton. Pour éviter cela on utilise une résistance ce pull-up (ou résistance de rappel/tirage).Arduino permet cependant de s’affranchir de cette résistance dès lors que la broche est déclarée en « PULL-UP ». L’on utilise ici une fonction native de la carte.

Générateur de nombre aléatoire

Doit être initialisé pour permettre de générer des nombres pseudo-aléatoires.

Tri à « bulles

Nom donné à un algorithme de tri (rapide). Ici cette méthode est dérivée pour rendre le tableau aléatoire.

Vidéo de présentation

Schéma de câblage

Le schéma ne pose pas trop de problème ici. Chaque sortie étant reliée à une à une seule Led, elle même reliée à une résistance de 560Ω. Le bouton poussoir est relié à une des broches de l’Arduino.

Sketch réalisé avec Tinkercad.

Dans cet exemple, toutes les broches ne sont pas utilisées ce qui permettra encore d’étendre les possibilités d’éclairages en ajouter des Leds supplémentaires.

Programme

Le programme est largement commenté pour permettre de l’appréhender et éventuellement ajuster quelques variables, comme par exemple la durée de fondu ou espacer le temps d’éclairage entre 2 leds.

On pourra également rendre ce délai entre 2 leds aléatoire également pour rendre la séquence toujours plus réaliste.

/*
 *
 * Commande LEDS pour éclairage aléatoire
 * Auteur: Seine Modèle Club Ferroviaire 
 * Site: https://www.modelisme-ferroviaire-rouen.fr/
 *
 * Juillet 2022
 */
// Variables ajustables
unsigned int tao = 300; 			// Durée d'un cycle
bool affichageProgressif = true;	// Affichage progressif 
int delay2Leds = 500;				// Délai allumer/éteindre entre 2 Leds
// Attribution et définition des ports utilisés
// Toutes les sorties LEDS sont renseignées dans un tableau
const int BOUTON = A0;
int tab_pins_leds [] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
int ledTemoin = 13;
int nbLeds = sizeof (tab_pins_leds) / sizeof(int); // Compte le
// Variables pour le fonctionnement du programme
// Ne pas modifier
byte del = 0; // duty cycle
int boutonDernierEtat = HIGH; 	// Mémoriser me dernier état du bouton
int boutonEtatCourant;    		// Mémoriser l'état courant u bouton
int etatsLeds = 0;				// Mémorise si la dernière séquence est d'éteindre ou d'allumer les leds
/*
 * Fonction qui permet de mélanger
 * toutes les valeurs d'un tableau aléatoirement
 */
void tabAleatoire(int *list, int elem) {
	for (int a = elem - 1; a > 0; a--) {
		int r = random(a + 1);
		if (r != a) {
			int temp = list[a];
			list[a] = list[r];
			list[r] = temp;
		}
	}
}
/*
 * Éxécute la méthode d'affichage
 * Selon le choix Progressif / Non progressif
 * (selon variable affichageProgressif)
 */
void execSequence () {
  if (affichageProgressif == true) seq_AllumerEteindrePWM(); else seq_AllumerEteindre();
}
/*
 * Méthode d'affichage non progressive
 * ------------------------------------------------------------
 * Fonction qui permet d'allumer (ou d'éteindre) les leds
 * Cette méthode est utilisée si la variable
 * affichageProgressif = false
 */
void seq_AllumerEteindre () {
	digitalWrite(ledTemoin, HIGH);
	if (etatsLeds == 0) etatsLeds = 1; else etatsLeds = 0;
	tabAleatoire(tab_pins_leds, nbLeds);
	for (int ii = 0; ii < nbLeds; ii++) {
		digitalWrite(tab_pins_leds[ii], etatsLeds);
		delay(delay2Leds); // Wait for xxx millisecond(s)
	}
	digitalWrite(ledTemoin, LOW);
}
/*
 * Méthode d'affichage PWM = progressive
 * ------------------------------------------------------------
 * Fonction qui permet d'allumer (ou d'éteindre) les leds
 * Cette méthode est utilisée si la variable
 * affichageProgressif = true
 */
void seq_AllumerEteindrePWM () {
	digitalWrite(ledTemoin, HIGH);
	tabAleatoire(tab_pins_leds, nbLeds);
	// start with fading IN the LEDs brightness
	if (etatsLeds == 0) {
		etatsLeds = 1;
		for (int ii = 0; ii < nbLeds; ii++) {
			for (int i = 0; i < 60; i++) {
				digitalWrite(tab_pins_leds[ii], HIGH);
				for (unsigned int j = 0; j < 20; j++) { // set duty cycle
					if (j == del) {
						digitalWrite(tab_pins_leds[ii], LOW);
					}
					delayMicroseconds(tao);
				}
				if ((i) % 3 == 0) del++; // every third cycle duty cycle is raised by 5%
			}
			// set LED to HIGH and wait few seconds
			digitalWrite(tab_pins_leds[ii], HIGH);
			del = 0; // needs to be set to zero
			delay(delay2Leds); // Wait for entre 2 leds
		}
    } else {
		etatsLeds = 0;
		// start with fading OUT the LEDs brightness
		for (int ii = 0; ii < nbLeds; ii++) {
			for (int i = 0; i < 60; i++) {
				for (unsigned int j = 0; j < 20; j++) { // set duty cycle
					if (j == del) {
						digitalWrite(tab_pins_leds[ii], HIGH);
					}
					delayMicroseconds(tao);
				}
				if ((i) % 3 == 0) del++; // every third cycle duty cycle is lowered by 5%
				digitalWrite(tab_pins_leds[ii], LOW);
			}
			// set LED to LOW and wait few seconds
			digitalWrite(tab_pins_leds[ii], LOW);
			del = 0; // needs to be set to zero
			delay(delay2Leds); // Wait for entre 2 leds
		} // end for loop leds
	} // end if etatLeds
	digitalWrite(ledTemoin, LOW);
}
/*
 * Intialisation du programme
 */
void setup() {
	// initialise le générateur de nombres aléatoires
  	// en lisant 1 broche analogique
	int noise = analogRead(A0);
	randomSeed(noise);
  
  
	// Définition de l'entrée liée au bouton poussoir
	pinMode(BOUTON, INPUT_PULLUP);
	// Définition de toutes les pins des LEDS en sorties
	for (int ii = 0; ii < nbLeds; ii++) pinMode(tab_pins_leds[ii], OUTPUT);
	
  	// Définition de la sortie de la led témoin située sur la carte
  	pinMode(ledTemoin, OUTPUT);
  
  	// Éxécute la séquence d'allumage (au démarrage de la carte)
	execSequence ();
}
/*
 * Intialisation du programme
 */
void loop() {
	// Lit l'état du boutton
	boutonEtatCourant = digitalRead(BOUTON);
	if (boutonDernierEtat == LOW && boutonEtatCourant == HIGH) execSequence ();
		
	// Mémorise l'état du boutton
	boutonDernierEtat = boutonEtatCourant;
}

N'hésitez pas à partager sur les réseaux sociaux, si vous avez trouvé ce tutoriel utile et pourquoi pas faire parvenir des photos de vos réalisations que je nous pourrons publier sur le site.

Partager sur les réseaux sociaux en un clic.