1. Introduction

Déjà durant l'Antiquité, les sportifs tels que les athlètes participant aux Jeux olympiques disposaient d'un entraînement sportif bien spécifique à leur discipline : ils avaient compris qu'une organisation rigoureuse était synonyme de victoire.

2500 ans plus tard, pendant la deuxième moitié du XXe siècle les sciences du sport se sont énormément développées, en même temps que les avancées techniques en médecine, biologie, physique, informatique, électronique et plus encore. A ce moment sont apparus les premiers appareils de mesure utilisés par les sportifs. L'objet de ce projet, un indicateur de vitesse, en fait partie.

En effet, le but de ce projet est la réalisation d'un artefact pouvant être disposé sur un vélo, et dont la fonction serait l'indication de la vitesse instantanée du vélo. Le cycliste pourra ainsi avoir une idée précise de la vitesse à laquelle il roule, et pourra s'entraîner plus efficacement. Afin de réaliser ce projet, un accéléromètre, un Raspberry Pi 3 et un écran LCD seront connectés ensemble et utilisés pour recueillir, transformer et diffuser des données.

2. Matériel et méthodes

2.1 Matériel

Comme pour tout problème, il y a plusieurs façons de mener à bien ce projet. Ci-dessous une liste de matériel constituant une solution.

2.1.1 Hardware
  • Raspberry Pi 3
  • câble ruban 40 pins
  • Pi Wedge 40-Pin
  • Breadboard
  • MPU-9150
  • écran LCD 16x2
  • fils de connexion M/M, F/M

Précisons que toute puce électronique ici mentionnée est supposée être brochée et connectable à la breadboard et au fils de connexion. Le MPU-9150 dispose d'un accéléromètre (pouvant comme son nom l'indique mesurer l'accélération instantanée). Il dispose aussi d'un magnétomètre et d'un gyroscope, cependant ils ne seront pas utiles pour ce projet.

2.1.2 Software

Afin de créer une interaction entre les trois parties que composent le Raspberry Pi, le MPU-9150, et l'écran LCD, deux librairies ont été importées (tous les travaux et informations ne provenant pas de moi sont référencés à la fin de cet article).

  • FaBo9Axis_MPU9250 pour le MPU-9150
  • RPLCD pour l'écran LCD

Puisque ce projet nécessite des programmes, il implique l'utilisation des logiciels de programmation, tels que IDLE (pratique car simple d'utilisation cependant très limité sur mac) ou encore WingPersonal (bien plus performant mais complexe).

Les programmes qui suivront sont tous écrits en Python dans sa version 2.7.

2.2 Méthode

2.2.1 Connectique

Après avoir connecté le Raspberry Pi à la breadboard en utilisant le câble ruban et le Pi Wedge 40-Pin, connectons le MPU-9150 à la breadboard. Sa place sur cette dernière importe peu, cependant il est judicieux de placer le MPU-9150 sur le coté droit pour aligner les broches connectées.

Le schéma ci-dessous indique les connexions à réaliser...

 schéma

...connexions reprises dans ces tableaux :

 connexions MPU  connexions LCD

2.2.2 Importation des librairies

Il faut maintenant importer les librairies relatives aux éléments utilisés. Pour ce faire, créez un clone du répertoire git sur le bureau Raspberry Pi. A partir d'un Terminal, sur le bureau du Pi, exécutez la commande suivante :

pip install [la_librairie]

Un processus de téléchargement se met en place, et se termine en indiquant que la librairie a bien été installée.

Le code qui suit nécessite également d'autres librairies :

  • time
  • sys
2.2.3 Programmation

Avant toute chose,

#!/usr/bin/python
# -*-coding:Utf-8 -*

Ce qui fait comprendre au système que le langage utilisé est Python, et que le système de caratère est Utf-8. Passons au code même. On importe premièrement les librairies :

import RPi.GPIO
import FaBo9Axis_MPU9250
import time
import sys
from RPLCD.gpio import CharLCD

Afin de simplifier l'écriture du code, on assigne un nouveau nom à deux fonctions. On indique aussi les pins utilisés pour l'écran :

lcd = CharLCD(pin_rs=18, pin_rw=37, pin_e=22, pins_data= [16, 12, 40, 38], numbering_mode=RPi.GPIO.BOARD)
mpu9250 = FaBo9Axis_MPU9250.MPU9250()
sleep = time.sleep

On déclare les paramètres :

tempo = 0.01
tempo = float(tempo)
g = 9.81
g = float(g)
iteration = 101

On insère un bloc "try" dans lequel deux boucles sont à l’œuvre :

try:
accel = mpu9250.readAccel()
i = 0
while i < int(iteration):
axi = (accel['x'])*g
axi = float(axi)
sleep(tempo)
i = i + 1
sumax = 0
i = 0
while i < int(iteration):
sumax = axi + float(sumax)
i += 1

Dans la première boucle, le Pi enregistre un nombre donné (le paramètre iteration) de fois la valeur de l'accélération sur l'axe x du MPU-9150 (dirigé vers l'avant de la puce), à une cadence précise (le paramètre tempo). Dans la deuxième, le Raspberry effectue la somme de ces valeurs, à mesure qu'il les enregistre. On doit maintenant calculer l'accélération moyenne, tout en assurant son type, un nombre flottant.

    moyax = (sumax/int(iteration))
moyax = float(moyax)

On déclare ainsi l'accélération (et son type) :

    a = moyax
a = float(a)

Sans oublier que tout instrument de mesure en soumis au bruit, on déclare un (petit) intervalle dans lequel l'accélération est considérée comme nulle :

    if a < 0.3 and a > -0.3:
a = 0
else:
a = a

Disposant à présent de la valeur de l'accélération moyenne ainsi que l'intervalle de temps dans laquelle elle à été déduite, on en vient au calcul de la vitesse, que l'on affiche, à l'aide de la formule v = a * t (en considérant que la vitesse initiale est nulle) :

    v = a * ((int(iteration) - 1)/tempo)
print("vitesse ="), (v)

Nous savons que ces calculs sont en lien étroit avec la deuxième loi de Newton (la somme des forces extérieures agissant sur un corps équivaut au produit de la masse de cet objet par l'accélération). Or, si la somme des forces est nulles, l'accélération l'est aussi. On insère alors une commande "break", stoppant la boucle, et une commande "continue", la redémarrant:

    if a == 0:
v = v_previous
break
else:
continue
v += v_previous

Ainsi, si l'accélération est nulle, puis non-nulle, on additionne la valeur de la vitesse précédente à celle actuelle pour obtenir la nouvelle vitesse. On réitère le code avec une fréquence de 1,5 secondes :

    sleep(1.5)

Afin de gérer les exceptions, on insère les lignes suivantes permettant de stopper le programme avec Ctrl +c, ou d'afficher un message d'erreur le cas échéant :

except KeyboardInterrupt:
pass
except Exception as error:
print error

Comme à la fin de tout code utilisant le port GPIO, on effectue un "cleanup", réinitialisant les pins, en terminant le programme :

finally:
GPIO.cleanup()

3. Résultats

Malheureusement l'écran LCD n'affiche rien, quand bien même il s'allume. Après quelques tests, j'en suis venu à la conclusion que c'était dans le programme du LCD que quelque chose n'allait pas, puisque le MPU9150 et le Raspberry arrivent à communiquer parfaitement, la valeur de la vitesse n'attend qu'à lue sur l'écran. De plus, il est à noter que la valeur calculée de la vitesse reste approximative: en effet j'ai effectué des tests avec le MPU seul, une batterie portable et un écran d'ordinateur (connecté en HDMI) dans la voiture, et les valeurs obtenues différaient de 25% à 30% de la vitesse réelle de la voiture (celle affichée sur le tableau de bord).

4. Discussion

Comme dit plus haut, la méthode ici utilisée n'est qu'une parmi plusieurs. Je l'ai choisie car le MPU-9150 était mis à disposition par le gymnase de Renens , et que l'aspect calculatoire m'a beaucoup plu. Si quelqu'un venait demain à reproduire ce projet, ses attentes feraient la différence quant au matériel utilisé. Par exemple, une balise GPS aurait probablement plus de précision, mais serait sujette à plus d'interférences (nuages, relief...). Une autre manière aurait été de mettre en place un système d'aimants autour de la roue pour déduire à partir du nombre de tours dans un intervalle de temps défini la vitesse du vélo. Cette dernière méthode me paraît être la plus fiable en termes de précision (cette technique est en fait utilisée sur les voitures pour le compteur de vitesse), néanmoins elle aurait nécessité un investissement financier bien plus étendu que ce que j'aurais pu me permettre.

Même si le code ici présenté est performant, il reste faillible à certains égards. En effet, on aura remarqué que sur trois axes, un seul est utilisé, celui pointant vers l'avant (l'axe x). La conséquence est que la valeur affichée de la vitesse sera la plus précise sur une trajectoire parfaitement horizontale et rectiligne. J'aurai pu utiliser le gyroscope (pour déduire un angle) et l'axe z (pointant vers le bas) pour calculer la vitesse dans une pente, cependant j'ai jugé que la marge d'erreur serait trop grande pour que le fruit de mon projet soit acceptable.

Finalement, on peut noter que l'artefact ainsi créer peut difficilement être placé sur un vélo. Il pourrait en effet être connecté à une batterie portable et tenir dans un panier à l'avant, cependant il faudrait s'assurer que le MPU-9150 pointe bien vers l'avant, et que la route empruntée soit plate.

5. Conclusion

En conclusion, je dirais n'avoir mené mon projet à bien que partiellement. Les calculs autant que les résultats sont approximatifs, et ne sont utilisables que dans des conditions difficiles à reproduire dans la réalité (encore moins avec un vélo). D'un autre côté, j'ai eu l'occasion de rencontrer des obstacles qui m'ont énormément fait progresser dans ma compréhension de l'informatique et de la programmation. Par exemple, avant ce projet, je ne savais pas ce qu'était une librairie. Plus encore, je ne connaissais pas le langage Python. Du côté matériel, j'ai appris à souder des composants avec d'autres (des broches sur l'écran LCD plus exactement), et ce non dans un but éducatif mais parce que cela m'aidait à atteindre un objectif bien défini. C'est pour cela que je suis content de ce que j'ai accompli pour réaliser ce projet, indépendamment du résultat immédiat. Parce que c'est le mien. Parce que je peux enfin dire :

Je l'ai fait.

Code entier

Ci-dessous est présenté le code décrit plus-haut, dans sa totalité.

#!/usr/bin/python
# coding: utf-8

# importation des librairies
import RPi.GPIO 
import FaBo9Axis_MPU9250
import time
import sys
from RPLCD.gpio import CharLCD

lcd = CharLCD(pin_rs=18, pin_rw=37, pin_e=22, pins_data=[16, 12, 40, 38], numbering_mode=RPi.GPIO.BOARD)

mpu9250 = FaBo9Axis_MPU9250.MPU9250()
sleep = time.sleep

# parametres
tempo = 0.01
tempo = float(tempo)
g = 9.81
g = float(g)
iteration = 100

try:
    while True:
        accel = mpu9250.readAccel()
        i = 0
        while i < int(iteration): #enregistrement des valeurs de l'acc. un nombre donné de fois
            axi = (accel['x'])*g
            axi = float(axi)
            sleep(tempo) #temps entre chaque enregistrement de valeurs
            i = i + 1

        sumax = 0
        i = 0
        while i < int(iteration): #somme de toutes le valeurs enregistrees selon l'axe x 
            sumax = axi + float(sumax)
            i += 1 

        moyax = (sumax/int(iteration)) #moyenne des valeurs selon les axes
        moyax = float(moyax)

        a = moyax 
        a = float(a)
        
        if a < 0.3 and a > -0.3:
            a = 0
        else:
            a = a
   
        v = a * ((int(iteration) - 1)/tempo)

        if a == 0: #acceleration nulle, vitesse constante (2eme loi de Newton)
            v = v_previous
            break
        else:
            continue
            v += v_previous

        lcd.write_string("vitesse = "), (v), ("m/s") #affichage de la vitesse
        
    sleep(1.5)

        
except KeyboardInterrupt:  # ctrl +c
    pass
  
except Exception as error: # error
    print error

finally:
    RPi.GPIO.cleanup()

Références

Librairies:

Divers: