POCL Balise Mobilis : Différence entre versions

 
Ligne 3 : Ligne 3 :
 
|Licences=Attribution (CC-BY)
 
|Licences=Attribution (CC-BY)
 
|Description=Création d'un POCL sur les données en temps réels du trafic routier de Bordeaux métropole
 
|Description=Création d'un POCL sur les données en temps réels du trafic routier de Bordeaux métropole
|Disciplines scientifiques=Arduino, Mechanics
+
|Disciplines scientifiques=Computing, Mechanics
 
|Difficulty=Technical
 
|Difficulty=Technical
 
|Duration=2
 
|Duration=2
Ligne 73 : Ligne 73 :
 
}}
 
}}
 
{{Tuto Step
 
{{Tuto Step
|Step_Title=Codage
+
|Step_Title=Utiliser Thonny pour déposer les programmes sur l'ESP32
|Step_Content=from machine import Pin, PWM
+
|Step_Content=Télécharger le logiciel Thonny.
  
import network
+
Raccorder l'ESP 32 à un ordinateur.
 +
 
 +
Ouvrir Thonny et sélectionner l'ESP 32 avec son port si besoin.
 +
 
 +
Créer juste le fichier : main.py
 +
 
 +
Copier dedans les codes présents plus bas dans sources et ressources.
 +
 
 +
Modifier le fichier créé
 +
 
 +
> modifier le nom du wifi et son mot de passe (mettre un wifi accessible pour le POCL sans portail captif)
 +
 
 +
> modifier les coordonnées géographiques de votre station
 +
|Step_Picture_00=POCL_Balise_Mobilis_Capture_d_cran_2025-12-14_085655.png
 +
|Step_Picture_01=POCL_Balise_Mobilis_Capture_d_cran_2025-12-14_085923.png
 +
}}
 +
{{Tuto Step
 +
|Step_Title=Assemblage des éléments
 +
|Step_Content='''1. Assembler du  support du servomoteur au mat'''
 +
 
 +
Enclencher les 4 côtés verticaux (panneaux à encoches)
 +
 
 +
Coller pour rigidifier
 +
 
 +
Laisser un trou à la base pour faire passer le câble USB
 +
 
 +
'''2. Assembler du mat'''
 +
 
 +
Panneaux latéraux encastrés
 +
 
 +
Renforcer avec colle à bois
 +
 
 +
Faire passer les câbles des servos + alimentation à l’intérieur du tube
 +
 
 +
'''3. Assembler la tête semi-circulaire'''
 +
 
 +
Deux panneaux arrondis + une plateforme intérieure
 +
 
 +
Fixer le support du buzzer / HP à l’avant
 +
 
 +
Prévoir des trous pour les servos
 +
 
 +
'''4. Montage des tiges'''
 +
 
 +
Servos fixés en ligne
 +
 
 +
Tiges en bois reliées aux disques colorés
 +
 
 +
Vérifier le débattement (0° → 180°)
 +
 
 +
'''5. Installation des servomoteurs'''
 +
 
 +
- Fixer chaque servo dans une encoche prévue :
 +
 
 +
Servo 1 → Disque rouge
 +
 
 +
Servo 2 → Disque noir
 +
 
 +
Servo 3 → Disque jaune
 +
 
 +
Servo 4 → Disque bleu
 +
 
 +
- Passer les trois fils du servo dans la colonne :
 +
 
 +
Marron → GND
 +
 
 +
Rouge → 5V
 +
 
 +
Orange → GPIO (signal)
 +
 
 +
- Vérifier que les servos peuvent tourner sans forcer
 +
 
 +
Connexions servomoteurs → ESP32
 +
 
 +
Élément Fil servo ESP32
 +
 
 +
Servo 1 (rouge) Signal GPIO 14
  
import urequests
+
Servo 2 (noir) Signal GPIO 27
  
import time
+
Servo 3 (jaune) Signal GPIO 26
  
<nowiki>#</nowiki> === WIFI CONFIGURATION ===
+
Servo 4 (bleu) Signal GPIO 25
  
WIFI_SSID = "caroline"
+
Tous servos +5V Pin 5V
  
WIFI_PASS = "xPptucR33!"
+
Tous servos GND GND
  
<nowiki>#</nowiki> === REQUEST PARAMETERS ===
+
> Important : Tous les GND doivent pas être reliés ensemble.
  
latitude = 44.8378
+
Connexion du buzzer
  
longitude = -0.5792
+
Élément SP32
  
radius_m = 1000
+
+ du buzzer GPIO 4
  
<nowiki>#</nowiki> === Servo motors (4 servos) ===
+
– du buzzer GND
  
SERVO_PINS = [33, 13, 16, 4]
+
'''6- Fermeture et finition'''
  
servos = [PWM(Pin(pin), freq=50) for pin in SERVO_PINS]
+
- Installer la partie supérieure sur la colonne
  
def angle_to_duty_ns(angle):
+
- Faire sortir le câble USB par l’ouverture du bas
  
    min_ns = 500_000    # 0° → 0.5 ms
+
- Fixer les disques de couleur sur les tiges
  
    max_ns = 2_500_000  # 180° → 2.5 ms
+
- Tester les servos et ajuster les bras si besoin
  
    return int(min_ns + (angle / 180) * (max_ns - min_ns))
+
- Vernir ou peindre la structure si nécessaire
  
initial_angles = [130, 0, 30, 0]  # adapte la taille en fonction du nombre de servos
 
  
current_angles = initial_angles.copy()
 
  
def initiation_des_position():
+
<br />
 +
|Step_Picture_00=POCL_Balise_Mobilis_WhatsApp_Image_2025-12-12_at_12.15.45.jpeg
 +
|Step_Picture_01=POCL_Balise_Mobilis_a2d96700-21a7-4d3c-af39-f1e82a49df06.jpg
 +
|Step_Picture_02=POCL_Balise_Mobilis_c58bb05d-4338-4725-918d-e05970db4a55.jpg
 +
}}
 +
{{Tuto Step
 +
|Step_Title=Finition et test
 +
|Step_Content='''1-Inspection de la structure'''
  
   
+
Vérifie toutes les jonctions collées :
  
    for i, servo in enumerate(servos):
+
Appuie légèrement pour vérifier qu’aucune pièce ne bouge.
  
        angle = initial_angles[i]
+
Remplis éventuellement les petites fissures avec un léger filet de colle à bois.
  
        current_angles[i] = angle
+
'''2- Ponçage'''
  
        servo.duty_ns(angle_to_duty_ns(angle))
+
Utilise un papier de verre grain 180 → 240
  
       
+
pour enlever les traces de brûlure laser et adoucir les angles.
  
def reset_all_servos():
+
Peinture / Vernis
  
    for i, servo in enumerate(servos):
+
Tu peux appliquer :
  
        angle = initial_angles[i]
+
Vernis incolore → effet propre et lumineux
  
        current_angles[i] = angle
+
Peinture acrylique → personnalisable
  
        servo.duty_ns(angle_to_duty_ns(angle))
+
Ne peins pas les zones où les servomoteurs bougent pour éviter un frottement.
  
<nowiki>#</nowiki> === ACTIVATE ONLY ONE SERVO ===
+
Finition des disques
  
def activate_single_servo(state):
+
Vérifie que les disques colorés bougent bien.
  
    """
+
Renforce les bras avec un petit point de colle chaude si nécessaire.
  
    Active uniquement un servo selon la valeur :
+
'''3- Finition électronique (intérieur)'''
  
    1 → servo 0
+
-Gestion des câbles
  
    2 → servo 1
+
a. Regroupe les câbles par servo
  
    3 → servo 2
+
b. Utilise la colle ou du ruban adhésif pour éviter que ça tire sur les broches
  
    4 → servo 3
+
c. Monte entièrement l’ESP32 dans la base :
  
    Tous les autres reviennent à 0°
+
Collé sur une cale en bois
  
    """
+
Ou vissé sur une petite plaque
  
   
+
- Vérification des connexions
  
    if 1 <= state <= 4:
+
Teste la tension 5V avec un multimètre
  
        servo_index = state -1
+
Vérifie que tous les GND sont bien reliés
  
        new_angle = current_angles[servo_index] + 60
+
Vérifie que tu n’as aucun fil débranché ou qui touche un autre.
  
        servos[servo_index].duty_ns(angle_to_duty_ns(new_angle))  # Angle désiré
+
'''4- Tests progressifs (très important)'''
  
<nowiki>#</nowiki> === WIFI CONNECTION ===
+
Test 1 — Test alimentation
  
def connect_wifi():
+
1. Branche le câble USB
  
    wlan = network.WLAN(network.STA_IF)
+
2. Regarde si l’ESP32 s’allume
  
    wlan.active(True)
+
3. Vérifie que les servos ne tremblent pas
  
    reset_all_servos()
+
Si oui : problème d’alimentation → utiliser un 5V stable
 +
|Step_Picture_00=POCL_Balise_Mobilis_PHOTO_MAQUETTE.jpg
 +
|Step_Picture_01=POCL_Balise_Mobilis_59073af4-f4c0-406a-8292-457205e5e3b5.jpg
 +
|Step_Picture_02=POCL_Balise_Mobilis_d84b99ee-954f-4ea1-a5bd-28179530fed7.jpg
 +
}}
 +
{{Notes
 +
|Observations=Notre objet prend la forme d’une balise inspirée à la fois de balise navale mais aussi de cadran solaire, il contient un cercle central vide vers lequel un cercle plein va venir se placer dans un mouvement rotatif. En fonction de la densité du trafic, le cercle signal (au centre haut de l’objet) sera de plus en plus gros (accumulation de tous les bras).
 +
|Avertissement=- Distance des balises (maillage peu dense)
  
    initiation_des_position()
+
- Ne pas avoir accès à Internet
  
    if not wlan.isconnected():
+
- Mauvaise manipulation des câbles
  
        print("Connecting to Wi-Fi...")
+
- Fragilité des câbles
 +
|Explanations=Lorsqu'un usager de la route, (piéton, voiture, cycliste) sort de chez lui dans sa vie quotidienne que ce soit pour le travail ou loisir, sa mobilité peut avoir un réel impact sur l’environnement qui l’entoure tout au long de son trajet il pourra visualiser les différentes densité de trafic dans chaque zone et ainsi se rendre compte du trafic en fonction des horaires et de faire évoluer ses habitudes.
 +
|Applications=Cet objet pourrait être essentiel dans la vie de tous les jours grâce à plusieurs avantages :
  
        wlan.connect(WIFI_SSID, WIFI_PASS)
+
<br />
  
        while not wlan.isconnected():
+
* '''Simplicité''' : Il donne une visualisation rapide en un coup d’œil de la circulation dans un rayon définit.
 +
* '''Esthétique''' : Il s'intègre dans le décor urbain sous la forme d’une balise ou d’un panneau signalétique.  
 +
* '''Sensibilisation''' : Il informe en temps réel sur la densité du trafic et il encourage un comportement écoresponsable en rappelant l’impact de la voiture
 +
|Notes=Open Data Bordeaux Métropole - <u>https://opendata.bordeaux-metropole.fr/explore/dataset/dechetteries-en-temps-reel/information/</u>
  
            print(".", end="")
+
Télécharger Thony - [https://thonny.org/ Thonny, Python IDE for beginners]
  
            time.sleep(0.5)
+
Code source :
  
    print("\nConnected to Wi-Fi:", wlan.ifconfig())
 
  
<nowiki>#</nowiki> === API CALL ===
+
from machine import Pin, PWM
  
def call_api(lat, lon, radius_m):
+
import network
  
    url = f"<nowiki>https://hackathon.mathias-duprat.fr/api/liveTrafic?lat={lat}&long={lon}&radius={radius_m}</nowiki>"
+
import urequests
  
    print("\nCalling API:", url)
+
import time
  
    try:
 
  
        res = urequests.get(url)
+
<nowiki>#</nowiki> === WIFI CONFIGURATION ===
  
        print("HTTP Code:", res.status_code)
 
  
        data = res.json()
+
WIFI_SSID = "S22 Ultra de Ibrahim"
  
        res.close()
+
WIFI_PASS = "mec bien"
  
        return data
 
  
    except Exception as e:
+
<nowiki>#</nowiki> === REQUEST PARAMETERS ===
  
        print("Error:", e)
 
  
        return None
+
latitude = 44.8378
  
<nowiki>#</nowiki> === Speaker ===
+
longitude = -0.5792
  
BUZZER_PIN = 15
+
radius_m = 1000
  
last_state = None
 
  
def update_state(new_state):
+
<nowiki>#</nowiki> === Servo motors (4 servos) ===
  
    global last_state
 
  
    if new_state != last_state and last_state is not None:
+
SERVO_PINS = [33, 13, 16, 4]
  
        beep()  # beep uniquement si l'état a changé
+
servos = [PWM(Pin(pin), freq=50) for pin in SERVO_PINS]
  
    last_state = new_state
+
def angle_to_duty_ns(angle):
  
def beep(frequency=2000, duration=0.12):
+
min_ns = 500_000    # 0° → 0.5 ms
  
    buzzer = PWM(Pin(BUZZER_PIN))
+
max_ns = 2_500_000  # 180° → 2.5 ms
  
    buzzer.freq(frequency)
+
return int(min_ns + (angle / 180) * (max_ns - min_ns))
  
    buzzer.duty(512)
 
  
    time.sleep(duration)
+
<nowiki>#</nowiki> adapte la taille en fonction du nombre de servos
  
    buzzer.duty(0)
 
  
    buzzer.deinit()
+
initial_angles = [130, 0, 30, 0]
  
<nowiki>#</nowiki> === MAIN LOOP ===
+
current_angles = initial_angles.copy()
  
connect_wifi()
+
def initiation_des_position():
  
previous_value = None
 
  
try:
+
for i, servo in enumerate(servos):
  
    while True:
+
angle = initial_angles[i]
  
        beep()
+
current_angles[i] = angle
  
       
+
servo.duty_ns(angle_to_duty_ns(angle))
  
        data = call_api(latitude, longitude, radius_m)
 
  
        if data and 'moyenne_etat' in data:
+
def reset_all_servos():
  
            current_value = data['moyenne_etat']
+
for i, servo in enumerate(servos):
  
            beep(frequency=2000, duration=0.12)
+
angle = initial_angles[i]
  
            if previous_value is None:
+
current_angles[i] = angle
  
                # Première lecture
+
servo.duty_ns(angle_to_duty_ns(angle))
  
                previous_value = current_value
 
  
                print(f"Initial moyenne_etat = {current_value}")
+
<nowiki>#</nowiki> === ACTIVATE ONLY THE CONSERNE SERVO ===
  
                activate_single_servo(current_value)
 
  
                beep()
+
def activate_single_servo(state):
  
            elif current_value != previous_value:
+
"""
  
                # Changement d'état
+
Active uniquement un servo selon la valeur :
  
                print(f"Value changed from {previous_value} to {current_value}")
+
1 → servo 0
  
                activate_single_servo(current_value)
+
2 → servo 1
  
                previous_value = current_value
+
3 → servo 2
  
                beep()
+
4 → servo 3
  
                time.sleep(0.12)
+
Tous les autres reviennent à 0°
  
            else:
+
"""
  
                print(f"No change, current value = {current_value}")
 
  
        else:
+
if 1 <= state <= 4:
  
            print("'moyenne_etat' not found in API response")
+
servo_index = state -1
  
        print("Waiting 10 seconds before next call...\n")
+
new_angle = current_angles[servo_index] + 60
  
        time.sleep(10)
+
servos[servo_index].duty_ns(angle_to_duty_ns(new_angle)) # Angle désiré
  
except KeyboardInterrupt:
 
  
    # Remise à zéro des servos et fin propre du programme
+
<nowiki>#</nowiki> === WIFI CONNECTION ===
  
    reset_all_servos()
 
  
    for servo in servos:
+
def connect_wifi():
  
        servo.deinit()
+
wlan = network.WLAN(network.STA_IF)
  
    print("\nProgramme arrêté")
+
wlan.active(True)
}}
 
{{Tuto Step
 
|Step_Title=Assemblage des éléments
 
|Step_Content='''1. Assembler du  support du servomoteur au mat'''
 
  
Enclencher les 4 côtés verticaux (panneaux à encoches)
+
reset_all_servos()
  
Coller pour rigidifier
+
initiation_des_position()
  
Laisser un trou à la base pour faire passer le câble USB
+
if not wlan.isconnected():
  
'''2. Assembler du mat'''
+
print("Connecting to Wi-Fi...")
  
Panneaux latéraux encastrés
+
wlan.connect(WIFI_SSID, WIFI_PASS)
  
Renforcer avec colle à bois
+
while not wlan.isconnected():
  
Faire passer les câbles des servos + alimentation à l’intérieur du tube
+
print(".", end="")
  
'''3. Assembler la tête semi-circulaire'''
+
time.sleep(0.5)
  
Deux panneaux arrondis + une plateforme intérieure
+
print("\nConnected to Wi-Fi:", wlan.ifconfig())
  
Fixer le support du buzzer / HP à l’avant
 
  
Prévoir des trous pour les servos
+
<nowiki>#</nowiki> === API CALL ===
  
'''4. Montage des tiges'''
 
  
Servos fixés en ligne
+
def call_api(lat, lon, radius_m):
  
Tiges en bois reliées aux disques colorés
+
url = f"<nowiki>https://hackathon.mathias-duprat.fr/api/liveTrafic?lat={lat}&long={lon}&radius={radius_m}</nowiki>"
  
Vérifier le débattement (0° → 180°)
+
print("\nCalling API:", url)
  
'''5. Installation des servomoteurs'''
+
try:
  
- Fixer chaque servo dans une encoche prévue :
+
res = urequests.get(url)
  
Servo 1 → Disque rouge
+
print("HTTP Code:", res.status_code)
  
Servo 2 → Disque noir
+
data = res.json()
  
Servo 3 → Disque jaune
+
res.close()
  
Servo 4 → Disque bleu
+
return data
  
- Passer les trois fils du servo dans la colonne :
+
except Exception as e:
  
Marron → GND
+
print("Error:", e)
  
Rouge → 5V
+
return None
  
Orange → GPIO (signal)
 
  
- Vérifier que les servos peuvent tourner sans forcer
+
<nowiki>#</nowiki> === Speaker ===
  
Connexions servomoteurs → ESP32
 
  
Élément Fil servo ESP32
+
BUZZER_PIN = 15
  
Servo 1 (rouge) Signal GPIO 14
+
last_state = None
  
Servo 2 (noir) Signal GPIO 27
+
def update_state(new_state):
  
Servo 3 (jaune) Signal GPIO 26
+
global last_state
  
Servo 4 (bleu) Signal GPIO 25
+
if new_state != last_state and last_state is not None:
  
Tous servos +5V Pin 5V
+
beep()  # beep uniquement si l'état a changé
  
Tous servos GND GND
+
last_state = new_state
  
> Important : Tous les GND doivent pas être reliés ensemble.
+
def beep(frequency=2000, duration=0.12):
  
Connexion du buzzer
+
buzzer = PWM(Pin(BUZZER_PIN))
  
Élément SP32
+
buzzer.freq(frequency)
  
+ du buzzer GPIO 4
+
buzzer.duty(512)
  
– du buzzer GND
+
time.sleep(duration)
  
'''6- Fermeture et finition'''
+
buzzer.duty(0)
  
- Installer la partie supérieure sur la colonne
+
buzzer.deinit()
  
- Faire sortir le câble USB par l’ouverture du bas
 
  
- Fixer les disques de couleur sur les tiges
+
<nowiki>#</nowiki> === MAIN LOOP ===
  
- Tester les servos et ajuster les bras si besoin
 
  
- Vernir ou peindre la structure si nécessaire
+
connect_wifi()
  
 +
previous_value = None
  
 +
try:
  
<br />
+
while True:
|Step_Picture_00=POCL_Balise_Mobilis_WhatsApp_Image_2025-12-12_at_12.15.45.jpeg
 
|Step_Picture_01=POCL_Balise_Mobilis_a2d96700-21a7-4d3c-af39-f1e82a49df06.jpg
 
|Step_Picture_02=POCL_Balise_Mobilis_c58bb05d-4338-4725-918d-e05970db4a55.jpg
 
}}
 
{{Tuto Step
 
|Step_Title=Finition et test
 
|Step_Content='''1-Inspection de la structure'''
 
  
Vérifie toutes les jonctions collées :
+
beep()
  
Appuie légèrement pour vérifier qu’aucune pièce ne bouge.
 
  
Remplis éventuellement les petites fissures avec un léger filet de colle à bois.
+
data = call_api(latitude, longitude, radius_m)
  
'''2- Ponçage'''
+
if data and 'moyenne_etat' in data:
  
Utilise un papier de verre grain 180 → 240
+
current_value = data['moyenne_etat']
  
pour enlever les traces de brûlure laser et adoucir les angles.
+
beep(frequency=2000, duration=0.12)
  
Peinture / Vernis
+
if previous_value is None:
  
Tu peux appliquer :
 
  
Vernis incolore → effet propre et lumineux
+
<nowiki>#</nowiki> Première lecture
  
Peinture acrylique → personnalisable
+
previous_value = current_value
  
Ne peins pas les zones où les servomoteurs bougent pour éviter un frottement.
+
print(f"Initial moyenne_etat = {current_value}")
  
Finition des disques
+
activate_single_servo(current_value)
  
Vérifie que les disques colorés bougent bien.
+
beep()
  
Renforce les bras avec un petit point de colle chaude si nécessaire.
+
elif current_value != previous_value:
  
'''3- Finition électronique (intérieur)'''
 
  
-Gestion des câbles
+
<nowiki>#</nowiki> Changement d'état
  
a. Regroupe les câbles par servo
+
print(f"Value changed from {previous_value} to {current_value}")
  
b. Utilise la colle ou du ruban adhésif pour éviter que ça tire sur les broches
+
activate_single_servo(current_value)
  
c. Monte entièrement l’ESP32 dans la base :
+
previous_value = current_value
  
Collé sur une cale en bois
+
beep()
  
Ou vissé sur une petite plaque
+
time.sleep(0.12)
  
- Vérification des connexions
+
else:
  
Teste la tension 5V avec un multimètre
+
print(f"No change, current value = {current_value}")
  
Vérifie que tous les GND sont bien reliés
+
else:
  
Vérifie que tu n’as aucun fil débranché ou qui touche un autre.
+
print("'moyenne_etat' not found in API response")
  
'''4- Tests progressifs (très important)'''
+
print("Waiting 10 seconds before next call...\n")
  
Test 1 — Test alimentation
+
time.sleep(10)
  
1. Branche le câble USB
+
except KeyboardInterrupt:
  
2. Regarde si l’ESP32 s’allume
 
  
3. Vérifie que les servos ne tremblent pas
+
<nowiki>#</nowiki> Remise à zéro des servos et fin propre du programme
  
Si oui : problème d’alimentation → utiliser un 5V stable
+
reset_all_servos()
|Step_Picture_00=POCL_Balise_Mobilis_PHOTO_MAQUETTE.jpg
 
|Step_Picture_01=POCL_Balise_Mobilis_59073af4-f4c0-406a-8292-457205e5e3b5.jpg
 
|Step_Picture_02=POCL_Balise_Mobilis_d84b99ee-954f-4ea1-a5bd-28179530fed7.jpg
 
}}
 
{{Notes
 
|Observations=Notre objet prend la forme d’une balise inspirée à la fois de balise navale mais aussi de cadran solaire, il contient un cercle central vide vers lequel un cercle plein va venir se placer dans un mouvement rotatif. En fonction de la densité du trafic, le cercle signal (au centre haut de l’objet) sera de plus en plus gros (accumulation de tous les bras).
 
|Avertissement=- Distance des balises (maillage peu dense)
 
  
- Ne pas avoir accès à Internet
+
for servo in servos:
  
- Mauvaise manipulation des câbles
+
servo.deinit()
  
- Fragilité des câbles
+
print("\nProgramme arrêté")
|Explanations=Lorsqu'un usager de la route, (piéton, voiture, cycliste) sort de chez lui dans sa vie quotidienne que ce soit pour le travail ou loisir, sa mobilité peut avoir un réel impact sur l’environnement qui l’entoure tout au long de son trajet il pourra visualiser les différentes densité de trafic dans chaque zone et ainsi se rendre compte du trafic en fonction des horaires et de faire évoluer ses habitudes.
 
|Applications=Cet objet pourrait être essentiel dans la vie de tous les jours grâce à plusieurs avantages :
 
  
 
<br />
 
<br />
 
* '''Simplicité''' : Il donne une visualisation rapide en un coup d’œil de la circulation dans un rayon définit.
 
* '''Esthétique''' : Il s'intègre dans le décor urbain sous la forme d’une balise ou d’un panneau signalétique.
 
* '''Sensibilisation''' : Il informe en temps réel sur la densité du trafic et il encourage un comportement écoresponsable en rappelant l’impact de la voiture
 
|Notes=Open Data Bordeaux Métropole - <u>https://opendata.bordeaux-metropole.fr/explore/dataset/dechetteries-en-temps-reel/information/</u>
 
 
}}
 
}}
 
{{Tuto Status
 
{{Tuto Status
 
|Complete=Draft
 
|Complete=Draft
 
}}
 
}}

Version actuelle datée du 14 décembre 2025 à 10:05

Auteur avatarMathiasDuprat | Dernière modification 14/12/2025 par Mathiasduprat

POCL Balise Mobilis d84b99ee-954f-4ea1-a5bd-28179530fed7.jpg

Introduction

Balise Mobilis est un objet signal implanté dans l’espace public traduisant les datas mouvantes liées au flux et à la densité du trafic routier à Bordeaux. Inscrite dans une logique de service public, Balise Mobilis se déploie dans différents quartiers de la ville selon un maillage agissant tel un réseau reliant les quartiers entre eux. La portée du projet à court terme est de faire prendre conscience aux impacts des mobilités et à long terme, d’impulser un changement d’usage : tendre vers les mobilités douces.

Inspiré des balises signalétiques en mer et de la signalisation routière, l’objet reprend les codes formels et colorés des panneaux et de la route. Quatre cerveaux moteurs sont camouflés dans le mât de l’objet. Ils servent à contrôler quarte bras de manière individuelle, afin de matérialiser la densité du trafic routier de par leur taille et leur couleur.

Étape 1 - Conception et maquettage

- Conception du support à l'aide du logiciel Inscape

dimension du mat : 5x5x18 cm

parabole: demi cercle de 10cm

support des servo moteur : 20x13 cm

support du mat : 15x15 cm

tige 1 : 8x1 cm

tige 2 : 7x1 cm

tige 3 : 6x1 cm

tige 4 : 5x1 cm


Étape 2 - Fabrication et montage du support

- utilisation de la découpeuse laser pour matérialiser les plans du support sur une feuille de carton.
- assemblage du mat

- assemblage du toit

- fixation du mat + support du mat+ toit a l'aide de la colle.



Étape 3 - Utiliser Thonny pour déposer les programmes sur l'ESP32

Télécharger le logiciel Thonny.

Raccorder l'ESP 32 à un ordinateur.

Ouvrir Thonny et sélectionner l'ESP 32 avec son port si besoin.

Créer juste le fichier : main.py

Copier dedans les codes présents plus bas dans sources et ressources.

Modifier le fichier créé

> modifier le nom du wifi et son mot de passe (mettre un wifi accessible pour le POCL sans portail captif)

> modifier les coordonnées géographiques de votre station



Étape 4 - Assemblage des éléments

1. Assembler du support du servomoteur au mat

Enclencher les 4 côtés verticaux (panneaux à encoches)

Coller pour rigidifier

Laisser un trou à la base pour faire passer le câble USB

2. Assembler du mat

Panneaux latéraux encastrés

Renforcer avec colle à bois

Faire passer les câbles des servos + alimentation à l’intérieur du tube

3. Assembler la tête semi-circulaire

Deux panneaux arrondis + une plateforme intérieure

Fixer le support du buzzer / HP à l’avant

Prévoir des trous pour les servos

4. Montage des tiges

Servos fixés en ligne

Tiges en bois reliées aux disques colorés

Vérifier le débattement (0° → 180°)

5. Installation des servomoteurs

- Fixer chaque servo dans une encoche prévue :

Servo 1 → Disque rouge

Servo 2 → Disque noir

Servo 3 → Disque jaune

Servo 4 → Disque bleu

- Passer les trois fils du servo dans la colonne :

Marron → GND

Rouge → 5V

Orange → GPIO (signal)

- Vérifier que les servos peuvent tourner sans forcer

Connexions servomoteurs → ESP32

Élément Fil servo ESP32

Servo 1 (rouge) Signal GPIO 14

Servo 2 (noir) Signal GPIO 27

Servo 3 (jaune) Signal GPIO 26

Servo 4 (bleu) Signal GPIO 25

Tous servos +5V Pin 5V

Tous servos GND GND

> Important : Tous les GND doivent pas être reliés ensemble.

Connexion du buzzer

Élément SP32

+ du buzzer GPIO 4

– du buzzer GND

6- Fermeture et finition

- Installer la partie supérieure sur la colonne

- Faire sortir le câble USB par l’ouverture du bas

- Fixer les disques de couleur sur les tiges

- Tester les servos et ajuster les bras si besoin

- Vernir ou peindre la structure si nécessaire




Étape 5 - Finition et test

1-Inspection de la structure

Vérifie toutes les jonctions collées :

Appuie légèrement pour vérifier qu’aucune pièce ne bouge.

Remplis éventuellement les petites fissures avec un léger filet de colle à bois.

2- Ponçage

Utilise un papier de verre grain 180 → 240

pour enlever les traces de brûlure laser et adoucir les angles.

Peinture / Vernis

Tu peux appliquer :

Vernis incolore → effet propre et lumineux

Peinture acrylique → personnalisable

Ne peins pas les zones où les servomoteurs bougent pour éviter un frottement.

Finition des disques

Vérifie que les disques colorés bougent bien.

Renforce les bras avec un petit point de colle chaude si nécessaire.

3- Finition électronique (intérieur)

-Gestion des câbles

a. Regroupe les câbles par servo

b. Utilise la colle ou du ruban adhésif pour éviter que ça tire sur les broches

c. Monte entièrement l’ESP32 dans la base :

Collé sur une cale en bois

Ou vissé sur une petite plaque

- Vérification des connexions

Teste la tension 5V avec un multimètre

Vérifie que tous les GND sont bien reliés

Vérifie que tu n’as aucun fil débranché ou qui touche un autre.

4- Tests progressifs (très important)

Test 1 — Test alimentation

1. Branche le câble USB

2. Regarde si l’ESP32 s’allume

3. Vérifie que les servos ne tremblent pas

Si oui : problème d’alimentation → utiliser un 5V stable


Comment ça marche ?

Observations : que voit-on ?

Notre objet prend la forme d’une balise inspirée à la fois de balise navale mais aussi de cadran solaire, il contient un cercle central vide vers lequel un cercle plein va venir se placer dans un mouvement rotatif. En fonction de la densité du trafic, le cercle signal (au centre haut de l’objet) sera de plus en plus gros (accumulation de tous les bras).

Mise en garde : qu'est-ce qui pourrait faire rater l'expérience ?

- Distance des balises (maillage peu dense)

- Ne pas avoir accès à Internet

- Mauvaise manipulation des câbles

- Fragilité des câbles

Explications

Lorsqu'un usager de la route, (piéton, voiture, cycliste) sort de chez lui dans sa vie quotidienne que ce soit pour le travail ou loisir, sa mobilité peut avoir un réel impact sur l’environnement qui l’entoure tout au long de son trajet il pourra visualiser les différentes densité de trafic dans chaque zone et ainsi se rendre compte du trafic en fonction des horaires et de faire évoluer ses habitudes.

Applications : dans la vie de tous les jours

Cet objet pourrait être essentiel dans la vie de tous les jours grâce à plusieurs avantages :


  • Simplicité : Il donne une visualisation rapide en un coup d’œil de la circulation dans un rayon définit.
  • Esthétique : Il s'intègre dans le décor urbain sous la forme d’une balise ou d’un panneau signalétique.
  • Sensibilisation : Il informe en temps réel sur la densité du trafic et il encourage un comportement écoresponsable en rappelant l’impact de la voiture

Éléments pédagogiques


Sources et ressources

Open Data Bordeaux Métropole - https://opendata.bordeaux-metropole.fr/explore/dataset/dechetteries-en-temps-reel/information/

Télécharger Thony - Thonny, Python IDE for beginners

Code source :


from machine import Pin, PWM

import network

import urequests

import time


# === WIFI CONFIGURATION ===


WIFI_SSID = "S22 Ultra de Ibrahim"

WIFI_PASS = "mec bien"


# === REQUEST PARAMETERS ===


latitude = 44.8378

longitude = -0.5792

radius_m = 1000


# === Servo motors (4 servos) ===


SERVO_PINS = [33, 13, 16, 4]

servos = [PWM(Pin(pin), freq=50) for pin in SERVO_PINS]

def angle_to_duty_ns(angle):

min_ns = 500_000 # 0° → 0.5 ms

max_ns = 2_500_000 # 180° → 2.5 ms

return int(min_ns + (angle / 180) * (max_ns - min_ns))


# adapte la taille en fonction du nombre de servos


initial_angles = [130, 0, 30, 0]

current_angles = initial_angles.copy()

def initiation_des_position():


for i, servo in enumerate(servos):

angle = initial_angles[i]

current_angles[i] = angle

servo.duty_ns(angle_to_duty_ns(angle))


def reset_all_servos():

for i, servo in enumerate(servos):

angle = initial_angles[i]

current_angles[i] = angle

servo.duty_ns(angle_to_duty_ns(angle))


# === ACTIVATE ONLY THE CONSERNE SERVO ===


def activate_single_servo(state):

"""

Active uniquement un servo selon la valeur :

1 → servo 0

2 → servo 1

3 → servo 2

4 → servo 3

Tous les autres reviennent à 0°

"""


if 1 <= state <= 4:

servo_index = state -1

new_angle = current_angles[servo_index] + 60

servos[servo_index].duty_ns(angle_to_duty_ns(new_angle)) # Angle désiré


# === WIFI CONNECTION ===


def connect_wifi():

wlan = network.WLAN(network.STA_IF)

wlan.active(True)

reset_all_servos()

initiation_des_position()

if not wlan.isconnected():

print("Connecting to Wi-Fi...")

wlan.connect(WIFI_SSID, WIFI_PASS)

while not wlan.isconnected():

print(".", end="")

time.sleep(0.5)

print("\nConnected to Wi-Fi:", wlan.ifconfig())


# === API CALL ===


def call_api(lat, lon, radius_m):

url = f"https://hackathon.mathias-duprat.fr/api/liveTrafic?lat={lat}&long={lon}&radius={radius_m}"

print("\nCalling API:", url)

try:

res = urequests.get(url)

print("HTTP Code:", res.status_code)

data = res.json()

res.close()

return data

except Exception as e:

print("Error:", e)

return None


# === Speaker ===


BUZZER_PIN = 15

last_state = None

def update_state(new_state):

global last_state

if new_state != last_state and last_state is not None:

beep() # beep uniquement si l'état a changé

last_state = new_state

def beep(frequency=2000, duration=0.12):

buzzer = PWM(Pin(BUZZER_PIN))

buzzer.freq(frequency)

buzzer.duty(512)

time.sleep(duration)

buzzer.duty(0)

buzzer.deinit()


# === MAIN LOOP ===


connect_wifi()

previous_value = None

try:

while True:

beep()


data = call_api(latitude, longitude, radius_m)

if data and 'moyenne_etat' in data:

current_value = data['moyenne_etat']

beep(frequency=2000, duration=0.12)

if previous_value is None:


# Première lecture

previous_value = current_value

print(f"Initial moyenne_etat = {current_value}")

activate_single_servo(current_value)

beep()

elif current_value != previous_value:


# Changement d'état

print(f"Value changed from {previous_value} to {current_value}")

activate_single_servo(current_value)

previous_value = current_value

beep()

time.sleep(0.12)

else:

print(f"No change, current value = {current_value}")

else:

print("'moyenne_etat' not found in API response")

print("Waiting 10 seconds before next call...\n")

time.sleep(10)

except KeyboardInterrupt:


# Remise à zéro des servos et fin propre du programme

reset_all_servos()

for servo in servos:

servo.deinit()

print("\nProgramme arrêté")


Dernière modification 14/12/2025 par user:Mathiasduprat.

Commentaires

Draft