Suite à mes premiers tests sur un Raspberry pi mobile utilisant une batterie lipo qui a permis plus de 40 heures d’autonomie, je poursuis les expérimentations dans le domaine. Nous reprendrons le même montage, mais nous ajouterons un convertisseur analogique vers numérique afin de pouvoir mesurer la tension de la batterie. Nous ajouterons également une charge activable sur commande pour représenter une activité plus lourde, et nous établirons des profils de consommation, et chercherons une méthode d’estimation de l’autonomie restante en fonction de la tension mesurée de la batterie.
Ajout du convertisseur analogique-numérique : le MCP3008.
Nous ne reviendrons pas en profondeur sur l’utilisation de ce composant, qui permet de convertir des entrées analogiques (un signal codé en tension, c’est à dire qu’une lecture de 3V ne signifie pas la même chose qu’une lecture de 2V), alors que le Raspberry pi ne dispose que d’entrées numériques (elles valent 0 ou 1 : si la tension récupérée sur l’entrée est 0v, c’est un 0, si c’est 3.3V, c’est un 1. Il y a un seuil qui sépare les deux, par exemple, 2.5V sera considéré comme 1 quand même, et 0.5V sera quand même un 0 logique).
Le MCP3008 nous permettra, en utilisant le bus SPI d’ajouter 8 entrées analogiques, afin de lire des capteurs de ce type, ce qui sera utile notamment pour lire la tension de la batterie.
Mesure de la tension de la batterie avec un pont diviseur de tension
Le pont diviseur de tension
Pour mesurer une tension, il nous faut un convertisseur ADC. Nous avons le MCP3008 pour remplir ce rôle. Puisque nous l’alimentons en 3.3V, nous pourrons mesurer des tensions de 0 à 3.3V. Nous souhaitons mesurer la tension d’une batterie dont la tension peut atteindre 4.2V au maximum, ce qui dépasse le maximum acceptable.
Pour remédier à cela, nous allons utiliser un pont diviseur de tension. Nous nous baserons sur les valeurs expliquées et définies dans notre tutoriel sur les ponts diviseurs de tension pour définir celui ci. Si vous souhaitez adapter le montage à votre cas pratique, n’hésitez pas à consulter le tutoriel pour voir la méthode de calcul.
Ici, nous ferons simple, en utilisant deux résistances de 2.2Koms, qui restent en dessous de la résistance d’entrée maximale du MCP3008, tout en limitant le courant à 4.2/4400= 0.000954A, soit environ 1mA. La puissance dissipée sera au maximum de 4.2*4.2/4400 = 4 milliwatts.
Cela est relativement faible par rapport à la consommation totale du système, et c’est donc très acceptable.
Montage
Voici un montage simplifié :
Par rapport à notre montage réel, les batteries n’alimentent pas le Raspberry pi via le convertisseur de tension. Je présente toutefois le schéma ainsi pour plus de lisibilité. Voici toutefois le schéma complet :
Quoi qu’il en soit, le montage est le suivant : le + de la batterie arrive à la première résistance. Celle ci est connectée à la seconde résistance, et au point de connexion, un câble part vers la première entrée du MCP3008. la seconde résistance repart quand à elle à la masse de la batterie.
N’oubliez surtout pas de connecter la masse des batteries à la masse du circuit, sous peine d’avoir des mesures totalement incohérentes.
code source
Nous reprenons le programme utilisé pour les exemples sur le MCP3008, mais avec quelques petits ajustements pour afficher la valeur réelle de la tension de la batterie plutôt qu’une fraction de celle ci (à cause du pont diviseur). J’ai constaté une certaine incertitude de mesure, et de ce fait, j’ai rajouté une boucle permettant de faire de multiples mesures à la suite et d’en faire la moyenne. La dispersion est nettement plus faible dans ce contexte, et les mesures moyennées restent très proches, avec une dispersion inférieure à 1% (environ 0.5%). Nous pourrons donc sans problème effectuer des mesures avec deux chiffres significatifs après la virgule (4.11v, par exemple). Le chiffre des millivolts en revanche est bruité, donc nous ne l’exploiterons pas.
Le code est le suivant :
#!/usr/bin/env python import time import os import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) #fonction lisant les donnees SPI de la puce MCP3008, parmi 8 entrees, de 0 a 7 def readadc(adcnum, clockpin, mosipin, misopin, cspin): if ((adcnum > 7) or (adcnum < 0)): return -1 GPIO.output(cspin, True) GPIO.output(clockpin, False) # start clock low GPIO.output(cspin, False) # bring CS low commandout = adcnum commandout |= 0x18 # start bit + single-ended bit commandout <<= 3 # we only need to send 5 bits here for i in range(5): if (commandout & 0x80): GPIO.output(mosipin, True) else: GPIO.output(mosipin, False) commandout <<= 1 GPIO.output(clockpin, True) GPIO.output(clockpin, False) adcout = 0 # read in one empty bit, one null bit and 10 ADC bits for i in range(12): GPIO.output(clockpin, True) GPIO.output(clockpin, False) adcout <<= 1 if (GPIO.input(misopin)): adcout |= 0x1 GPIO.output(cspin, True) adcout /= 2 # first bit is 'null' so drop it return adcout SPICLK = 18 SPIMISO = 23 SPIMOSI = 24 SPICS = 25 # definition de l'interface SPI GPIO.setup(SPIMOSI, GPIO.OUT) GPIO.setup(SPIMISO, GPIO.IN) GPIO.setup(SPICLK, GPIO.OUT) GPIO.setup(SPICS, GPIO.OUT) adcnum = 0 # Lecture de la valeur brute du capteur read_adc0 = readadc(adcnum, SPICLK, SPIMOSI, SPIMISO, SPICS) # conversion de la valeur brute lue en milivolts = ADC * ( 3300 / 1024 ) millivolts = read_adc0 * ( 3300.0 / 1024.0) vBatt = millivolts*2/1000 sum_vbatt=0 print "\tvaleur brute : %s" % read_adc0 print "\ttension lue : %s millivolts" % millivolts print "\ttension de la batterie : %s volts" % vBatt for x in range(0, 100): read_adc0 = readadc(adcnum, SPICLK, SPIMOSI, SPIMISO, SPICS) vBatt=read_adc0 * ( 3300.0 / 1024.0)*2/1000 sum_vbatt=sum_vbatt+vBatt time.sleep (0.01) avg_vBatt=sum_vbatt/100; print "\ttension moyenne mesuree de la batterie : %s volts" % avg_vBatt
Programme de mesures
Pour pouvoir tester l’autonomie, nous ferons tourner le système sur batterie, en mesurant le temps écoulé depuis le lancement du script. Pour chaque mesure, nous noterons également la tension de la batterie, ce qui nous permettra alors de tracer une courbe sur l’autonomie en fonction de la tension de la batterie.
Pour cela, nous utiliserons deux scripts. Le premier est une version modifiée du précédent, qui n’affiche que la tension, avec deux décimales uniquement. Le code est le suivant :
#!/usr/bin/env python import time import os import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) #fonction lisant les donnees SPI de la puce MCP3008, parmi 8 entrees, de 0 a 7 def readadc(adcnum, clockpin, mosipin, misopin, cspin): if ((adcnum > 7) or (adcnum < 0)): return -1 GPIO.output(cspin, True) GPIO.output(clockpin, False) # start clock low GPIO.output(cspin, False) # bring CS low commandout = adcnum commandout |= 0x18 # start bit + single-ended bit commandout <<= 3 # we only need to send 5 bits here for i in range(5): if (commandout & 0x80): GPIO.output(mosipin, True) else: GPIO.output(mosipin, False) commandout <<= 1 GPIO.output(clockpin, True) GPIO.output(clockpin, False) adcout = 0 # read in one empty bit, one null bit and 10 ADC bits for i in range(12): GPIO.output(clockpin, True) GPIO.output(clockpin, False) adcout <<= 1 if (GPIO.input(misopin)): adcout |= 0x1 GPIO.output(cspin, True) adcout /= 2 # first bit is 'null' so drop it return adcout SPICLK = 18 SPIMISO = 23 SPIMOSI = 24 SPICS = 25 # definition de l'interface SPI GPIO.setup(SPIMOSI, GPIO.OUT) GPIO.setup(SPIMISO, GPIO.IN) GPIO.setup(SPICLK, GPIO.OUT) GPIO.setup(SPICS, GPIO.OUT) adcnum = 0 # Lecture de la valeur brute du capteur read_adc0 = readadc(adcnum, SPICLK, SPIMOSI, SPIMISO, SPICS) # conversion de la valeur brute lue en milivolts = ADC * ( 3300 / 1024 ) millivolts = read_adc0 * ( 3300.0 / 1024.0) vBatt = millivolts*2/1000 sum_vbatt=0 iterations_count=100 for x in range(0, iterations_count): read_adc0 = readadc(adcnum, SPICLK, SPIMOSI, SPIMISO, SPICS) vBatt=read_adc0 * ( 3300.0 / 1024.0)*2/1000 sum_vbatt=sum_vbatt+vBatt time.sleep (0.01) avg_vBatt=sum_vbatt/iterations_count; #print "%.2f" % round(avg_vBatt,2) print("{0:.2f}".format(round(avg_vBatt,2)))
N’oubliez pas qu’il faut exécuter ce code avec sudo :
sudo python avgVBatt.py
Le second script est celui que nous avons utilisé pour les précédents tests d’autonomie, mais légèrement modifié afin d’enregistrer également la tension mesurée grâce au script précédent. Le code est le suivant :
start=`date +%s` while [ 0 ] do sleep 1 end=`date +%s` vBatt=`python avgVBatt.py` runtime=$((end-start)) echo "$runtime;$vBatt" echo "$runtime;$vBatt" >> log done
Cela donne le résultat suivant à l’écran :
La colonne de gauche donne le temps écoulé en secondes depuis le début de l’exécution, et la colonne de droite la tension de la batterie.
Le script enregistre également ces données dans un fichier, de sorte que lorsque le Raspberry pi cessera de fonctionner pour cause de batterie vide, les données seront préservées.
Conclusions
Nous avons pu mettre en place une installation permettant au système de connaitre la tension de la batterie avec une dérivation bien inférieure à 0.01 volts. Dans ce contexte, si nous considérons un courant consommé constant, nous pourrons à partir des données collectées calculer l’autonomie restante.
Cependant, en pratique, celle ci dépendra de la consommation du circuit, qui peut ne pas être constante. Je pensais faire un billet rapidement sur la mesure de la consommation du Raspberry pi, mais il semble que les composants dont je dispose ne soient pas adaptés. On poursuivra donc en utilisant des valeurs théoriques pour la consommation.
On notera qu’il sera possible d’utiliser le même système que celui présenté ici pour mesurer la tension fournie par un panneau solaire, une éolienne, ou toute autre source de courant.
La prochaine étape sera de mener une série d’expériences pour mesurer l’autonomie du système dans des cas concrets, et nous présenterons les résultats détaillés avec des courbes et un modèle d’estimation de la charge restante de la batterie.
[…] Raspberry pi mobile – mesure de la tension de la batterie […]
parfait
par contre c’est une carte arduino pour la connectique A200-26 donc fais gaffe la prochaine fois
ps: j’ai saigné du nez 3 fois en voyant sa merci de me rembourser l’hopital je vais porter plainte fais pas le con
moi j’ai saigné du nez en voyant “sa”
bonjour
pourquoi le branchement du MCP3008 est inversé ?
(correct sur http://nagashur.com/blog/2013/01/13/lire-des-entrees-analogiques-sur-un-raspberry-avec-un-circuit-adc-le-mcp3008/)
bonjour
pourquoi le branchement du MCP3008 est inversé ?
(correct sur http://nagashur.com/blog/2013/01/13/lire-des-entrees-analogiques-sur-un-raspberry-avec-un-circuit-adc-le-mcp3008/)