Il arrive que certains nos clients, pas très à l'aise en programmation, nous demandent de l'aide pour programmer une application qui utilise nos modules. Par exemple, on nous a demandé une application qui puisse surveiller la tension du secteur à une fréquence variable. Pourquoi pas? ça fait un moment qu'on n'a pas eu l'occasion de montrer la simplicité de notre API...
Le problème
L'énoncé du problème est simple: le client veut contrôler la tension du secteur et l'enregistrer dans un fichier CSV. En temps normal l'échantillonnage se fait une fois toutes les 10 secondes, mais quand un événement se produit (signalé par un contact qui se ferme), l'échantillonnage doit se faire 10 fois par seconde.
Le matériel
On a donc besoin d'un Yocto-Volt pour mesurer la tension du secteur et d'un Yocto-Knob pour mesurer l'état du bouton de commande.
Un Yocto-Volt et un Yocto-Knob
Le client désire faire tourner son application depuis un Raspberry PI, on a donc choisi le langage Python: il est livré en standard dans toutes les distributions Linux. Il ne faudra pas oublier de configurer le PI pour qu'il fonctionne à peu près correctement avec les périphériques USB 1.1.
Le cablage
On va commencer par configurer le Yocto-Volt et le Yocto-Knob à l'aide du Virtual Hub. On va donner le nom logique ACinput à la fonction voltage2 du Yocto-Volt, et on va donner le nom logique FreqCmd au canal 1 du Yocto-Knob. On pourrait se passer de cette étape, mais le code serait alors un peu plus complexe.
Pour simplifier le code, on donne un nom logique à l'entrée AC du voltmètre
La programmation
Assurons-nous d'abord d'avoir téléchargé puis installé la librairie Yoctopuce pour Python, la procédure à suivre est décrite dans la doc de tous modules Yoctopuce.
Il faut maintenant commencer notre programme en incluant les librairies Yoctopuce nécessaires
from yocto_voltage import *
from yocto_anbutton import *
Puis il faut initialiser l'API Yoctopuce:
errmsg=YRefParam()
if YAPI.RegisterHub("usb", errmsg)!= YAPI.SUCCESS:
sys.exit("init error"+errmsg.value)
Il nous faut maintenant retrouver les objets correspondant à l'entrée AC du Yocto-Volt et a au canal 1 du Yocto-Knob. Et pour cela on va utiliser les noms logiques que l'on a définis auparavant dans les modules.
sensorAC = YVoltage.FindVoltage('ACinput')
if not(sensorAC.isOnline()):
sys.exit('No ACsensor Voltage function found')
# look for the anButton called FreqCmd
button = YAnButton.FindAnButton('FreqCmd')
if not(button.isOnline()):
sys.exit('No FreqCmd AnButton Function found')
Pour contrôler la fréquence d'échantillonnage, on va mettre en place un callback qui sera appelé à chaque fois que l'état du bouton de contrôle aura changé de manière significative,
button.registerValueCallback(buttonChange);
Le callback, se contente de vérifier si le canal qui a déclenché le callback a détecté un bouton appuyé ou relâché, et met à jour une variable globale qui contrôle la fréquence d'échantillonnage.
global SampleFrequency
if button.get_isPressed():
SampleFrequency=10
else:
SampleFrequency=0.1
Il ne reste plus qu'à coder la boucle principale qui se contente de lire le voltage:
... et de l'écrire à la fin d'un fichier au format CSV.
logfile.write(str(sampleTime.day)+'/')
logfile.write(str(sampleTime.month)+'/')
logfile.write(str(sampleTime.year)+' ')
logfile.write(str(sampleTime.hour)+':')
logfile.write(str(sampleTime.minute)+':')
logfile.write(str(sampleTime.second)+'.')
logfile.write(("%03d" % (sampleTime.microsecond/1000))+' , ')
logfile.write(str(voltage)+'\n')
logfile.close()
Reste à attendre jusqu'au prochain échantillonnage. Comme on ne connaît pas à l'avance le temps qu'il faut attendre (puisque la fréquence d'échantillonnage peut changer à tout moment), on doit être un peu subtil. La boucle est donc construite de manière à vérifier en permanence que le temps écoulé depuis le dernier échantillonnage n'est pas plus grand que la période courante. C'est probablement le bout de code le plus complexe de tout le programme.
while mustwait:
YAPI.Sleep(10)
delta = datetime.datetime.now()-sampleTime;
if (delta.seconds*1000 + delta.microseconds/1000) > 1000 / SampleFrequency:
mustwait=False
C'est fini, on a fait le tour de la question. Voici le code source complet du programme:
import datetime
from yocto_api import *
from yocto_voltage import *
from yocto_anbutton import *
SampleFrequency = 0.1;
def buttonChange(button,value):
global SampleFrequency
if button.get_isPressed():
SampleFrequency=10
else:
SampleFrequency=0.1
# Setup the API to use local USB devices
errmsg=YRefParam()
if YAPI.RegisterHub("usb", errmsg)!= YAPI.SUCCESS:
sys.exit("init error"+errmsg.value)
# look for the Voltage Sensor called ACinput
sensorAC = YVoltage.FindVoltage('ACinput')
if not(sensorAC.isOnline()):
sys.exit('No ACsensor Voltage function found')
# look for the anButton called FreqCmd
button = YAnButton.FindAnButton('FreqCmd')
if not(button.isOnline()):
sys.exit('No FreqCmd AnButton Function found')
# register button callback
button.registerValueCallback(buttonChange);
print("Running")
while True:
# make sure the Sensor is still connected
sys.stdout.write(".")
sys.stdout.flush()
if (sensorAC.isOnline()):
sampleTime = datetime.datetime.now();
voltage = sensorAC.get_currentValue();
# write to log file
logfile = open("voltagelog.csv", "a");
logfile.write(str(sampleTime.day)+'/')
logfile.write(str(sampleTime.month)+'/')
logfile.write(str(sampleTime.year)+' ')
logfile.write(str(sampleTime.hour)+':')
logfile.write(str(sampleTime.minute)+':')
logfile.write(str(sampleTime.second)+'.')
logfile.write(("%03d" % (sampleTime.microsecond/1000))+' , ')
logfile.write(str(voltage)+'\n')
logfile.close()
else:
print("Yocto-Volt is offline")
# wait until for next sample
mustwait = True;
while mustwait:
YAPI.Sleep(10)
delta = datetime.datetime.now()-sampleTime;
if (delta.seconds*1000 + delta.microseconds/1000) > 1000/SampleFrequency:
mustwait=False
Trop facile ;-)