Repository navigation
Home
Le projet FlashDrink vise à concevoir un distributeur de boissons connecté et autonome, pour des environnements comme les espaces de restauration en libre-service ou les espaces communs. Ce système propose une interface utilisateur simple etergonomique, qui permet à l'utilisateur de choisir sa quantité de boisson, évitant ainsi le gachis alimentaire.
L'utilisateur obtient un goblet connecté, qui peut être associé à son compte. Une fois son goblet associé, le système se charge de débiter automatiquement le compte de l'utilisateur en fonction de sa consommation.
- Description du projet
- Membres
- Problématique à résoudre
- Motivations
- Matériel utilisé
- Installation
- Conception
- Scénario d'utilisation
- Budget
- Bilan
- Pistes d'amélioration
- Liens
Maxence MATHIEU
Axel RILIEVO
Dans les espaces de restauration ou les lieux à forte affluence, plusieurs défis subsistent :
- Gestion des déchets : Favoriser l’utilisation d’un récipient unique et réutilisable pour réduire l’impact environnemental, et limiter le gachis de boisson.
- Personnalisation de la quantité : Permettre aux utilisateurs de sélectionner précisément la quantité de boisson désirée.
- Abstraction du paiement : Simplifier le processus de paiement grâce à une facturation automatique connectée.
- Gestion autonome et simple : Rendre l’utilisation fluide sans interventions complexes.
FlashDrink cherche à concevoir un distributeur de boissons connecté, autonome et écoresponsable, tout en offrant une expérience utilisateur fluide.
Ce projet s’inscrit principalement dans une volonté de réduire le gaspillage. Combien de fois êtes vous allé dans un fast-food, que le menu que vous aviez choisi vous force à prendre une boisson de 50cl, tout ça pour ne pas en boire la moitié ? FlashDrink a pour objectif de transformer cette situation en un mauvais souvenir.
À titre plus personnel, FlashDrink est l'occasion d'apprendre le fonctionnement de systèmes embarqués, de découvrir le monde de l'éléctronique, et de manipuler des composants uniques comme les lecteurs RFID. C'est aussi une opportunité de créer un système complet, robuste et documenté, avec une interface homme-machine intuitive.
-
Microcontrolleur : Raspberry Pi 3 Model B.
-
Connecteur récipient : Lecteur RFID MFRC522.
-
Afficheur : 7-Display TM1637.
-
Distribution du liquide : Pompe submergée.
-
Interaction utilisateur : Bouton classique d'arcade.
-
MOSFET : Pololu Power Switch.
-
Circuit : câblage électrique et tube étanche.
-
Impression 3D : 400 grammes de PLA.
On commence par se connecter à la machine qui va héberger le backend, par SSH ou par interface graphique.
Puis, dans un terminal, on se déplace dans le dossier backend du dépot github, et on exécute les étapes suivantes :
- Installez
UV
curl -LsSf https://astral.sh/uv/install.sh | sh
- Créez un environnement virtuel (venv)
uv venv
- Installez les dépendances
uv pip sync requirements.txt
- Exécutez le backend
source venv/bin/activate
gunicorn --workers 4 --bind 0.0.0.0:5000 app:app
- (Optionnel) Ajoutez le backend en tant que service Linux avec
systemctl
Placez ce qui suit (et modifiez-le si nécessaire) dans /etc/systemd/system/flask-drink-payment.service :
[Unit]
Description=Flash Drink Payment System
After=network.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/objetconnecte
ExecStart=/home/ubuntu/objetconnecte/venv/bin/gunicorn --workers 4 --bind 0.0.0.0:5000 app:app
Restart=always
Environment="PATH=/home/ubuntu/objetconnecte/venv/bin"
Environment="PYTHONUNBUFFERED=1"
[Install]
WantedBy=multi-user.target
Ensuite, redémarrez les services avec sudo systemctl enable flash-drink-payment et sudo systemctl daemon-reload
Pour accéder à l'application, rendez-vous sur http://localhost:5000. Si vous voulez y accéder depuis un autre appareil, il faut nécessairement ouvrir les ports de son réseau pour rediriger les requêtes du port 5000 vers la machine qui héberge ce script.
Pour exécuter le script sur le microcontrolleur du système embarqué, on utilise la même méthode que pour lancer le backend.
On commence par se connecter au microcontrolleur, par SSH ou par interface graphique.
Puis, dans un terminal, on se déplace dans le dossier raspberry du dépot github, et on exécute les étapes suivantes :
- Installez
UV
curl -LsSf https://astral.sh/uv/install.sh | sh
- Créez un environnement virtuel (venv)
uv venv
- Installez les dépendances
uv pip sync requirements.txt
- Exécutez le script
source venv/bin/activate
python main.py
- (Optionnel) Ajoutez le script en tant que service Linux avec
systemctl
Placez ce qui suit (et modifiez-le si nécessaire) dans /etc/systemd/system/flask-drink-embedded.service :
[Unit]
Description=Flash Drink Embedded System
After=network.target
[Service]
User=flashdrink
WorkingDirectory=/home/flashdrink/dev/FlashDrink/raspberry
ExecStart=/home/flashdrink/dev/FlashDrink/raspberry/venv/bin/python /home/flashdrink/dev/FlashDrink/raspberry/main.py
Restart=always
Environment="PATH=/home/flashdrink/dev/FlashDrink/raspberry/venv/bin"
Environment="PYTHONUNBUFFERED=1"
[Install]
WantedBy=multi-user.target
Ensuite, redémarrez les services avec sudo systemctl enable flask-drink-embedded et sudo systemctl daemon-reload
Le script se lancera au démarage du Raspberry Pi 3.
Pour brancher les composants, suivre le diagramme suivant :

Nous conseillons très fortement de simplement télécharger l'application, qui se trouve dans l'onglet release du git. Build l'application demande de nombreuses dépendances, beaucoup de configuration et des efforts de debug assez significatifs, parce que React Native est pas toujours très sympathique.
Si vous souhaitez tout de même build l'application vous même, alors suivez les instructions ci-dessous.
Dans un premier temps, on se place dans le dossier mobile-app du dépot github, puis :
- Installez les dépendances
Allez sur la documentation de React Native pour voir comment installer node, JDK, Android Studio, Android SDK, et comment les configurer
- Configurer l'application en mode Release
Allez sur cet article Medium qui explique comment générer les clés publiques et privées de l'application, et où les placer
- Build l'application
Exécutez le script build.sh, qui va générer l'APK app-release.apk à la racine du dossier mobile-app.
Le projet s'articule autour de 4 parties qui communiquent entre elles :
- Un goblet avec un tag RFID.
- Le backend, qui contient la base de donnée des utilisateur et l'API REST qui permet d'intéragir avec cette base de données.
- L'application mobile, qui permet à un utilisateur de s'inscrire, se connecter, ajouter des fonds à son compte et de synchroniser un goblet avec le compte.
- Le système embarqué, qui détecte le goblet, demande à au backend les fonds disponibles de l'utilisateur, et verse le liquide quand demandé, dans la limite des fonds disponibles.
Pour résumer ces intéractions, voici un schema :

L'API du Système de Paiement RFID Flask permet aux utilisateurs de :
- Enregistrer et authentifier les comptes utilisateurs.
- Associer des étiquettes RFID aux utilisateurs.
- Effectuer des transactions liées au solde, comme ajouter et retirer des fonds.
L'API communique avec une base de données SQLite pour stocker les informations des utilisateurs, les associations de tags RFID et les soldes.
La base de données est construit autour de 2 tables : users et tags. La première table doit contenir les informations sur les utilisateurs, comme leurs identifiants et leur solde. La seconde table est une table d'association qui indique quels tags sont associés à quels utilisateurs.
Voici un schéma de la base de données :
Et voici des informations plus détaillées sur chaque champs :
-
users : Stocke les informations des utilisateurs.
-
id: Identifiant unique pour l'utilisateur. -
username: Nom de l'utilisateur (unique). -
password: Mot de passe haché. -
balance: Solde du compte de l'utilisateur.
-
-
tags : Stocke les associations de tag RFID.
-
tag_id: Identifiant unique pour le tag RFID. -
user_id: ID de l'utilisateur associé au tag.
-
L'API REST est un script python qui utilise la librairie Flask pour facilement créer un serveur web qui réponds en JSON sur un total de 8 routes différentes.
Point de terminaison : /registerUser
Méthode : POST
Description : Enregistre un nouvel utilisateur avec un nom d'utilisateur et un mot de passe.
Corps de la requête :
{
"username": "string",
"password": "string"
}Réponses :
-
201: Utilisateur enregistré avec succès. -
400: Le nom d'utilisateur existe déjà ou des champs requis sont manquants.
Point de terminaison : /connectUser
Méthode : POST
Description : Authentifie un utilisateur avec un nom d'utilisateur et un mot de passe.
Corps de la requête :
{
"username": "string",
"password": "string"
}Réponses :
-
200: Utilisateur connecté avec succès avec l'ID de l'utilisateur. -
401: Nom d'utilisateur ou mot de passe invalide. -
400: Champs requis manquants.
Point de terminaison : /connectTagWithUser
Méthode : POST
Description : Lie un tag RFID à un utilisateur.
Corps de la requête :
{
"tag_id": "string",
"user_id": "integer"
}Réponses :
-
200: L'étiquette a été connectée à l'utilisateur avec succès. -
400: Champs requis manquants.
Point de terminaison : /disconnectTag
Méthode : POST
Description : Délie un tag RFID de tout utilisateur associé.
Corps de la requête :
{
"tag_id": "string"
}Réponses :
-
200: Le tag a été déconnectée avec succès. -
400: Champs requis manquants.
Point de terminaison : /addBalance
Méthode : POST
Description : Ajoute du solde au compte d'un utilisateur à l'aide d'un tag RFID.
Corps de la requête :
{
"tag_id": "string",
"amount": "float"
}Réponses :
-
200: La balance a été ajoutée avec succès. -
400: Champs requis manquants. -
404: Le tag n'est pas associée à un utilisateur.
Point de terminaison : /setBalance
Méthode : POST
Description : Définit le solude du compte d'un utilisateur à l'aide d'un tag RFID.
Corps de la requête :
{
"tag_id": "string",
"amount": "float"
}Réponses :
-
200: La balance a été définie avec succès. -
400: Champs requis manquants. -
404: Le tag n'est pas associée à un utilisateur.
Point de terminaison : /getBalance
Méthode : GET
Description : Récupère la balance d'un utilisateur.
Paramètres de requête :
-
user_id: ID de l'utilisateur.
Réponses :
-
200: Retourne la balance de l'utilisateur. -
400: Champs requis manquants. -
404: Utilisateur introuvable.
Point de terminaison : /getUserOfTag
Méthode : GET
Description : Récupère l'utilisateur associé à un tag.
Paramètres de requête :
-
tag_id: ID du tag.
Réponses :
-
200: Retourne l'utilisateur associé au tag. -
400: Champs requis manquants. -
404: Étiquette introuvable.
L'application mobile a pour objectif de pouvoir s’inscrire, se connecter, ajouter des fonds à son compte et de synchroniser un goblet avec le compte.
Pour créer cette application, on utilise le framework React Native, ce qui nous permet de coder l'application en TypeScript, et que celle-ci soit cross-platforme (iOS & Android).
La très grande majorité des fichiers sont les fichiers de base, nécessaires au fonctionnement d'une application React Native.
Les fichiers intéressants sont les suivants : App.tsx, screens/LoginScreen.tsx, screens/RegisterScreen.tsx et screens/ScanScreen.tsx.
App.tsx est le fichier racine qui contient le point d'entrée l'application.
Pour faire une analogie, on peut voir la fonction App comme la fonction main d'un programme.
Voici un extrait du code pour comprendre la logique de l'application :
const App: React.FC = () => {
const [userId, setUserId] = useState<number | null>(null);
const [isRegistering, setIsRegistering] = useState<boolean>(false);
if (userId) {
return <ScanScreen userId={userId} />;
}
return isRegistering ? (
<RegisterScreen onNavigateToLogin={() => setIsRegistering(false)} />
) : (
<LoginScreen
onLoginSuccess={setUserId}
onNavigateToRegister={() => setIsRegistering(true)}
/>
);
};On remarque que si userId est défini, l'utilisateur est connecté, et on affiche la vue ScanScreen.
Sinon on affiche la vue LoginScreen par défaut, et si l'utilisateur souhaite s'inscrire, on affiche la vue RegisterScreen.
Les 3 différentes vues vont ensuite faire des requêtes HTTP vers l'API en fonction des actions de l'utilisateur.
Voici un extrait de comment ces requêtes sont faites :
const handleLogin = async () => {
setLoading(true);
try {
const response = await fetch(`${BACKEND_URL}connectUser`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
const result = await response.json();
if (response.ok) {
onLoginSuccess(result.user_id);
} else {
Alert.alert('Login Failed', result.error || 'Invalid credentials');
}
} catch (error) {
Alert.alert('Error', 'Could not connect to the server');
} finally {
setLoading(false);
}
};On utilise une constante BACKEND_URL qui contient l'URL de l'API, et on utilise la fonction fetch pour envoyer une requête HTTP.
Le système embarqué dans le distributeur de boisson est constitué de 7 composants différents :
- Un raspberry pi 3
- Un lecteur RFID
- Un tag RFID
- Une pompe submergée
- Un bouton
- Un afficheur 7-Display
- Un composant "MOSFET"
Le bouton est le seul moyen pour l'utilisateur d'intéragir avec le distributeur directement, autre qu'avec l'application mobile.
L'afficheur 7-Display permet de voir la quantité de crédits restant sur le compte de l'utilisateur. Chaque crédit compte pour un centime d'euro.
Le lecteur RFID permet de scanner un tag RFID pour lier le goblet au compte de son utilisateur.
Le raspberry pi 3 est le composant central du distributeur. C'est celui qui possède tout le code, et qui interface avec les autre composants pour faire fonctionner le distributeur.
Plusieurs autres microcontrolleurs ont été essayés avant de passer au raspberry pi 3, comme l'Arduino Yun Mini, et le Raspberry Pi Zero. Cependant, le fonctionnement de la connexion sans fil de ces microcontrolleurs s'est avérée trop difficile à configurer. Le raspberry pi 3 a le bon goût d'avoir un port HDMI qui permet de facilement configurer la connexion sans fil avec l'interface graphique.
Le système d'exploitation utilisé sur la raspberry pi 3 est raspbian à la version du 2024-11-19. Cela permet d'avoir une version à jour de Debian, de python, et d'autres dépendances essentielles.
Le programme du distributeur est écrit en python pour plusieurs raisons :
- Simplicité d'utilisation, à la fois dans le code et dans l'installation des dépendances en une commande.
- Très large pannel de dépendances prêtes à l'emploi, comme celle du lecteur RFID et du 7-Display.
- Possibilité d'envoyer des requêtes HTTP vers l'API très simplement avec le package
requests.
Le code est divisé en plusieurs fichiers, un pour chaque composant ou fonctionalité du distributeur :
-
API.pypour les requêtes HTTP vers l'API. -
Button.pypour détecter si le bouton est appuyé ou non. -
Display.pypour configurer quoi afficher sur le 7-Display. -
Pump.pypour envoyer ou non du courant dans la pompe grâce au MOSFET -
RFID.pypour la détection et la lecture de tags par le lecteur RFID.
Et enfin, main.py contient le programme principal, qui utilise les méthodes des classes de ces différents composants pour faire fonctionner le distributeur.
Le programme principal fonctionne avec un automate d'états qui décrit les différents états dans lequel peut être le distributeur, et comment transitionner d'un état à l'autre.
Voici l'automate d'états :

Les différents composants sont reliés au raspberry pi 3 à travers les différents pins de celui-ci. Voici un résumé des rôles de chaque pin du raspberry pi 3 :

Voici comment les branchements des différents composants sont faits :
- Les fils oranges sont du courant de 3.3V ou 5V.
- Les fils noirs sont la masse
- Les fils violets sont des fils de GPIO en mode écoute
- Les fils vers sont des fils de GPIO en mode écriture

On remarque deux choses : premièrement, le bouton et le lecteur RFID sont des composants indépendants du reste du distributeur. Ces derniers lisent une entrée qui est envoyée sur un pin GPIO en mode écoute, qui peut ensuite être lu par le programme. Enfin, la pompe n'est pas alimentée directement. A la place, son courant vient d'un MOSFET qui ne laisse passer de courant que si le pin GPIO vert est allumé.
Un utilisateur lance l'application FlashDrink sur son smartphone. Il a le choix entre se connecter ou bien créer un compte. S'il possède déjà un compte, il peut se connecter avec ses identifiants
Si l'utilisateur n'a pas de compte, il peut cliquer sur le lien Don't have an account? Register. Cela le mène vers la page d'inscription, où il peut créer ses indentifiants
Une fois connecté sur l'applicaiton, l'utilisateur peut faire 2 actions : synchroniser son goblet à son compte, ou ajouter du solde à son compte.
Pour relier son goblet à son compte, il clique sur le bouton Scan a Tag qui fait passer l'application en mode "Scan de tag RFID".
Lorsque l'utilisateur place le goblet sur le scanneur RFID de son smartphone (souvent placé à l'arrière du smartphone), l'application l'informe que le tag a été scanné avec succès.
Il peut à présent choisir de déconnecter son compte du tag en cliquant sur le bouton Disconnect Tag
Si l'utilisateur clique sur ce bouton, l'application l'informe que le tag a bien été déconnecté
Pour ajouter du solde à son compte, l'utilisateur peut rentrer un nombre dans le champ textuel, puis appuyer sur le bouton Add Balance
Lorsque l'utilisateur clique sur ce bouton, l'applicaiton l'informe que le solde a bien été ajouté
L’utilisateur positionne son récipient sur le distributeur, se distribue lui-même la quantité souhaitée, et voit son solde restant s’afficher en temps réel.
demo_POC.mp4
-
Raspberry Pi 3 Model B : 40.00€.
-
Lecteur RFID MFRC522 : 7.00€.
-
7-Display TM1637 : 7.00€.
-
Pompe submergée : 3.80€.
-
Bouton classique d'arcade : 3.70€.
-
Pololu Power Switch : 3.95€.
-
câblage électrique et tube étanche : 4.00€.
-
400 grammes de PLA : 8.00€.
Le prix du matériel utilisé s'élève au total à 77.45€
Le temps de travail en présentiel au FabLab était de 15 heures. L'investissement en temps de travail personnel est estimé à 25 heures. On estime alors que le temps total de travail est de 40 heures
Avec un taux horraire de 11,65 €/heure/personne (salaire minimal en France), on arrive à un total de 932€ de salaire.
On arrive donc à un total de 1009.45€ pour le temps de travail et le prix du matériel.
En conclusion, le projet FlashDrink a permis de concevoir un distributeur de boissons autonome et connecté, répondant au problème gaspillage alimentaire.
Nous sommes assez fier d'avoir pu créer une solution complète qui est facile d'utilisation, qui simplifie les paiements, et qui pourrait être utilisé dans tous les environnements de restauration en libre-service. À travers une solution matérielle et logicielle intégrée, le système offre une gestion optimisée de la consommation des utilisateurs, tout en favorisant une démarche écoresponsable grâce à l’utilisation de récipients réutilisables et à la réduction des déchets alimentaires. Le travail réalisé a permis d'explorer de nombreux domaines technologiques, allant des systèmes embarqués avec le Raspberry Pi, à la création d'une application mobile avec React Native, sans oublier la mise en place d'un backend avec une API et une base de données.
Pour améliorer l’expérience utilisateur et rendre le système FlashDrink utilisable au public, plusieurs pistes peuvent être explorées :
-
Amélioration de la précision : Intégrer une pompe faite pour la mesure alimentaire, comme une pompe péristatique.
-
Personnalisation avancée : Offrir la possibilité de sélectionner la quantité de boisson directement depuis l’application avant l’utilisation, ainsi que de permettre la sélection parmi plusieurs boissons disponibles sur le distributeur.
-
Extension des transactions : Connecter le système à un vrai compte bancaire ou permettre le rechargement du compte utilisateur via des transactions sécurisées.
-
Amélioration de l’interface utilisateur : Remplacer l’actuelle interface limitée à 4 chiffres par une interface plus conviviale et intuitive, offrant plus d’informations et d’options.
-
Changer de MOSFET : Remplacer le MOSFET actuel et complexe par un MOFSET beaucoup plus simple, ce qui empêcherait la pompe de parfois s'allumer lors de l'allumage du microcontrolleur.