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.

Convertisseur analogique-numérique MCP3008

Convertisseur analogique-numérique 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.

Nous avons un tutoriel sur la connexion et l’utilisation du MCP3008, avec des exemples pratiques et le code source requis.

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é :

MCP3008 et pont diviseur

MCP3008 et pont diviseur

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 :

MCP3008 et pont diviseur avec régulateur de tension

MCP3008 et pont diviseur avec régulateur de tension

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 :

test d'autonomie via le script mesurant la tension

test d’autonomie via le script mesurant la tension

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.

 

Réseaux sociaux