Raspberry & Arduino sous surveillance

À l'occasion de la refonte de la carte de chauffage, je me suis donné comme contrainte que celle-ci devait pouvoir fonctionner en toutes circonstances.
- 1/ elle devait se relancer après crash
- 2/ elle devait se passer du Rasperry Pi, si celui-ci disparaissait.
- 3/ les programmes sous Rasperry devaient pouvoir être relancer automatiquement.#

En un mot, la carte doit être opérationnelle en permanence, sauf panne d'alimentation, les pannes électroniques sont rares et considérées comme négligeables. ++ Les solutions envisagées :++

  1. un "watchdog" pour surveiller l'ATmega
  2. un "heartbit" pour surveiller le Raspberry Pi
  3. un programme de surveillance des applications Python.

1. Le "watchdog"

Il s'agit de détecter si l'ATmega fonctionne correctement. Il ne peut être que matériel, car aucun logiciel ne surveille l'ATmega.

J'ai donc opté pour un circuit 74LS4060, qui est constitué d'une horloge à base de R/C pour déterminer un période d'horloge d'environ 0,2ms(50KHz), et d'une cascade de compteurs binaires allant jusqu'à 2^14=16384. Ce qui permet de compter un peu plus de 3" au maximum.
La sortie "Q14" du 4060 va donc à travers un transistor inverseur, appliquer un "reset" sur l'ATmega. Pour empêcher se RAZ, l'ATmega doit impérativement remettre les compteurs à 0 avant les 3" fatidiques.
Pour appliquer un "reset" de l'ATmega volontairement, il suffit de ne plus "resetter" le 4060, c'est le rôle de la variable "rstATm" qui est activée par la séquence [bouton2]+[bouton1].

le circuit :

circuit_watchdog.png Vous remarquerez le RC (47K-0,1µF) qui est nécessaire à la génération d'un signal de reset du 4060 à la mise sous tension, ce qui permet à l'ATmega de démarrer et commencer les RAZ du "watchdog".

le code (code IDE Arduino):

void raz() {               // reset du Watch Dog
   if (!rstATm) {         // reset de l'ATmega non demandé (si demandé, le W.D. n'est pas "reseté" et va "reseté" l'ATmega)
      digitalWrite(razWD,HIGH);
      delay(1);
      digitalWrite(razWD,LOW); }
}

2. Le "heartbit"

Le "heartbit" est un signal périodique (comme un battement de cœur !) qui va permettre de déterminer si le Raspberry Pi est bien vivant. En cas de perte de communication avec le Pi, l'ATmega va exécuter un code autonome spécifique.
La seule détection d'un niveau "haut" ou "bas" sur une broche ne suffit pas, car le Pi peut planter et laisser la broche en l'état. Un signal alternatif est plus sûr, mais plus compliqué à détecter.
L'idée est de détecter un changement d'état sur la broche du Pi et de lancer un compteur à ce moment là. Si le compteur dépasse une certaine valeur, le Pi n'a pas changé d'état et est donc HS.
Il n'y a pas de matériel ad hoc, si ce n'est juste une liaison entre une broche du Pi et une broche de l'ATmega, juste un code côté Raspberry et côté ATmega... Voyons ça :

côté Raspberry Pi (python):

# création du signal du heartbit (cette fonctionn doit être exécutéd ttes les 1" max)
def heartbit():
    GPIO.output(HeartBit,not GPIO.input(HeartBit))
    GPIO.output(dpc,     not GPIO.input(dpc))

côté ATmega (IDE Arduino):

void lecHeartBit() {                    // surveillance de la vie du Raspberry Pi
  bool HB=digitalRead(HeartBit);                     // témoin de présence du heartbit
  if (HB != lastHB) { cptHB=0; lastHB=HB; }  // raz du compteur sur changement d'état & mémo état, pour prochain test
  if (cptHB > 499) {                                                // valeur déterminé par essais successifs
    digitalWrite(led2, HIGH);
    etatPI=false;                                                        // le Rpi ne répond plus
  } else { if (etatBouton0 && etatBouton1) {digitalWrite(led2, HB);}
           etatPI=true;                                                  // le Pi est là
           }
  if (cptHB < 500 ) {cptHB=(cptHB+1); }           // incrément du compteur
}

3. Surveillance des applications

Il s'agit maintenant de s'assurer que les programmes principaux fonctionnent sur le Pi.
Le programme le plus fragile est celui qui établi une commuication entre le Raspberry et l'ATmega. Il arrive que l'ATmega plante sur une réception de données, dû à une interuption de celui-ci au mauvais moment. Le programme Python va à son tour planter.
La solution consiste à faire tourner un script BASH qui surveille les PID des tâches en cours. Ce script est lancé par "crontab" au  boot du Pi.

code :

#!/bin/bash
sleep 5
echo 1 > /run/lock/cpt            # comptage des plantage
while true
  do
    sleep 5
    if [ -e /run/lock/test ]                        # 1er lancement
      then
        pidtest=$(cat /run/lock/test)            # récupération du PID du prg "test"
      else
        python /home/pi/carte-chauffage.py &    # exécution du programme principal
        echo ${!} > /run/lock/test                # enregistrement du PID 
    fi
    if [ ! -e /proc/$pidtest ]                    # vérification de la présence du prg vivant 
      then
        python /home/pi/carte-chauffage.py & # exécution du programme principal
        echo ${!} > /run/lock/test                # enregistrement du PID
    cpt=$(cat /run/lock/cpt)                        # incrément du nb de plantage
    cpt=$(( $cpt+1 ))
    echo $cpt > /run/lock/cpt
    fi
  done
exit
 

Conclusion

Voilà les outils mis en place pour surveiller le couple Raspberry Pi / ATmega.
J'espère qu'ils suffiront à éviter de se retrouver sans chauffage en plein hiver.
Ils n'empêcheront pas d'éviter les coupures secteurs. Heureusement il reste la cheminée.