Les exercices de l'Atelier des Outils Pour le Numérique

Les balises cardinales nautiques

L'objectif de cet exercice est de simuler le fonctionnement des balises cardinales nautiques qui permettent aux bateaux d'éviter certains obstacles.

Cet exemple, très progressif est le fil conducteur du cours d'introduction. Il permet d'aborder graduellement les notions de programmation standard et également de s'initier aux techniques de l'Arduino. Merci à Philippe Jaillon de l'avoir proposé, rédigé, expliqué.

Ce qui est proposé ici est une synthèse de toutes les séances, il n'y a donc pas le déroulé des étapes. Une fois les séances de cours terminées, vous serez capable de lire et de comprendre le code présenté en bas de page.

Documents

Ci-dessous une image explicative du fonctionnement des balises.

Montage associé

Pour cet exercice vous devez disposer du matériel ci-dessous.

TypeQuantité
Platine Arduino1
Plaque à essais1
Fil de câblage9
Résistance de 330 Ω1
LED (couleur indiférente)1
Potentiomètre1
Switch On-On1

Le montage à réaliser est le suivant :

Une insoupsonnée balise nautique (n'oubliez pas les flotteurs avant de la mettre en conditions réelles).

Les balises

Le sujet est en cours de rédaction (pour les années à venir), mais vous pouvez trouver une proposition de correction et les commentaires associés dans la section suivante.

Correction et commentaires

int balise ;
boolean vitesseClignotement ;

#define LED 6
#define SWITCH 8

void setup()
{
  int val ;

  Serial.begin(9600) ;
  
  Serial.println("Initialisation...") ;

  pinMode(LED,OUTPUT) ;
  digitalWrite(LED,LOW) ;
  pinMode(SWITCH,INPUT) ;

  Serial.print("Configuration pour une balise ") ;
  val = analogRead(A0) ;
  if ( val < 256 ) {  
    balise = 0 ;
    Serial.print("Nord") ;
  } else if ( val < 512 ) {
    balise = 1 ;
    Serial.print("Est") ;
  } else if ( val < 758 ) {
    balise = 2 ;
    Serial.print("Sud") ;
  } else {
    balise = 3 ;
    Serial.print("Ouest") ;
  }
  Serial.print(" (") ;
  Serial.print(val) ;
  Serial.println(")") ;
  
  Serial.print("Clignotement ") ;
  if ( digitalRead(SWITCH) == HIGH ) {
    vitesseClignotement = true ;
    Serial.println("long") ;
  } else {
    vitesseClignotement = false ;
    Serial.println("court") ;
  }
}

void scintille(int port, int attente)
{
  digitalWrite(port,HIGH) ;
  delay(attente) ;
  digitalWrite(port,LOW) ;
  delay(attente) ;
}

/* le parametre type permet de demander
 * une balise type Q -- longue (type=true)
 * ou une balise de type VQ -- courte (type=false).
 */
void baliseNord(boolean type)
{
  int clignotement ;
  if ( type == true ) { // clignotements longs
    clignotement = 400 ;
  } else {              // clignotements courts
    clignotement = 200 ;
  }

  scintille(LED,clignotement) ;
}

void baliseEst(boolean type)
{
  int clignotement ;
  int tempsTotal ;
  int i ;
  if ( type == true ) { // clignotements longs
    clignotement = 400 ;
    tempsTotal = 10 ;
  } else {              // clignotements courts
    clignotement = 200 ;
    tempsTotal = 5 ;
  }

  for (i=0 ; i<3 ; i=i+1) scintille(LED,clignotement) ;

  delay(tempsTotal*1000 - 3*clignotement*2) ;
}

void baliseSud(boolean type)
{
  int clignotement ;
  int tempsTotal ;
  int tempsEclat ;
  int i ;
  if ( type == true ) { // clignotements longs
    clignotement = 400 ;
    tempsTotal = 15 ;
  } else {              // clignotements courts
    clignotement = 200 ;
    tempsTotal = 10 ;
  }

  /* L'eclat long dure deux fois la duree totale d'un
   * scintillement, donc 4 clignotements.
   */
  tempsEclat = 4*clignotement ;
  for (i=0 ; i<6 ; i=i+1) scintille(LED,clignotement) ;
  scintille(LED,tempsEclat) ;

  delay(tempsTotal*1000 - 6*clignotement*2 - tempsEclat*2) ;
}

void baliseOuest(boolean type)
{
  int clignotement ;
  int tempsTotal ;
  int i ;
  if ( type == true ) { // clignotements longs
    clignotement = 400 ;
    tempsTotal = 15 ;
  } else {              // clignotements courts
    clignotement = 200 ;
    tempsTotal = 10 ;
  }

  for (i=0 ; i<9 ; i=i+1) scintille(LED,clignotement) ;

  delay(tempsTotal*1000 - 9*clignotement*2) ;
}


void loop()
{
  if ( balise == 0 ) baliseNord(vitesseClignotement) ;
  else if ( balise == 1 ) baliseEst(vitesseClignotement) ;
  else if ( balise == 2 ) baliseSud(vitesseClignotement) ; 
  else baliseOuest(vitesseClignotement) ;
}
				
Exemple de code pour réaliser les balises.

Dans cet exemple de code, il faut distinguer plusieurs ensembles similaires, en plus des parties classiques que sont les fonctions setup() et loop().

Fonctions loop() et setup()

Dans la fonction setup(), nous procédons aux classiques initialisations (le port sur lequel est branché la LED est positionné en sortie et celui sur lequel est branché l'interrupteur en entrée). C'est là également que nous allons définir quel sera le type de la balise simulée par le montage. En effet, nous lisons les valeurs de l'interrupteur et du potentiomètre. Le premier nous renseigne sur le fait que nous allons simuler une balise à éclat long ou à éclat court et le dernier sur le type de la balise (Nord, Est, Sud, Ouest).

Les valeurs lues sont envoyées sur la ligne série pour être récupérées par le moniteur série de l'IDE Arduino et être affichées. Ceci n'est pas nécessaire, mais permet une mise au point plus facile.

La fonction loop() de son côté ne fait qu'appeler la fonction correspondant à la balise sélectonnée. Tout le travail se fait justement dans ces fonctions.

Fonctions de balise

Chaque fonction de balise (baliseNord(), baliseEst(), baliseSud(), baliseOuest()) prend un unique argument de type booléen (vrai ou faux) qui va déterminer le type du scintillement (long ou court).

Dans chacune de ces fonctions, pour éviter de répéter des tests, nous définissons une ou plusieurs variables de type int qui vont représenter la durée de chaque clignotement et la période totale de la balise, en millisecondes.

Ayant défini la durée d'un scintillement et la période de chaque balise, il ne reste plus qu'à appeler la fonction scintille() le bon nombre de fois et avec les bons argument.

Enfin, il faut attendre le temps nécessaire pour atteindre la fin de la période. Il se calcule simplement en déduisant du temps total pour la période, le temps passé dans chacune des appels à la fonction scintille().

Fonction scintille()

L'objet de cette fonction est de décrire une fois pour toutes la façon dont une LED doit clignoter pour notre application.

Comme nous prévoyons de, soit pouvoir brancher plusieurs LED en même temps, soit pouvoir brancher une LED sur des ports différents, nous passons un premier argument à cette fonction qui est le numéro du port sur lequel la LED est branchée. Nous passons également un second argument qui est la durée de la demi-période de scintillement. Cette dernière valeur est exprimée en millisecondes, pour être donnée à la fonction delay().

Grâce à cet exemple, vous avez pu mettre en œuvre les principes suivants :

Remarque

Dans le cas d'une mise en œuvre réelle de cet exemple, nous n'aurions sans doute pas utilisé un potentiomètre pour déterminer le type de la balise. Nous aurions plutôt utilisé un couple d'interrupteurs qui, en simulant chacun 1 bit, nous permettait de coder 4 valeurs. Ça aurait donc fait un total de trois interrupteurs que nous trouvons dans le commerce sous la forme de dip switch, idéal dans ce type d'application.

Malheuresement, vous ne disposez pas d'un tel composant dans vos kits, ni d'interrupteurs en quantité suffisante, c'est pourquoi nous utilisons le potentiomètre.