Transformer une simple carte micro:bit en manche à balai pour piloter l’attitude d’une navette spatiale 3D en temps réel dans votre navigateur, c’est le défi technique que je vous propose de relever aujourd’hui sur le Raspberry Pi 400. De l’acquisition brute des inclinaisons par liaison série jusqu’au rendu WebGL fluide sous Three.js, en passant par un pont Python asynchrone chargé de lisser les commandes et de contrer le Gimbal Lock, ce banc d’essai explore une intégration système de bout en bout. Un projet concret qui démontre qu’en maîtrisant les protocoles ouverts (UART, WebSocket), on peut s’affranchir de l’obsolescence des écosystèmes propriétaires.
Au sommaire :
- 1 Piloter un modèle 3D dans le navigateur avec Micro:bit et Raspberry Pi 400
- 1.1 Comment ça marche sous le capot ?
- 1.2 Le modèle 3D : Récupérer les ressources de la NASA
- 1.3 La source matérielle : Programmer la micro:bit
- 1.4 Le Calculateur de Vol : Mise en place du pont Python
- 1.5 L’Interface 3D : Affichage et Serveur Web
- 1.6 Le Grand Décollage : Mise en service du système
- 1.7 Automatisation : Un clic pour tout lancer
- 1.8 Installation et mise en route
- 1.9 Vidéo
- 1.10 Conclusion : Une architecture ouverte et réactive
- 1.11 Sources
Comment ça marche sous le capot ?
Si on se contente de brancher la micro:bit en USB pour essayer de faire bouger un objet 3D directement dans le navigateur, on se rend vite compte que ça saccade ou que la connexion finit par figer. Pour que notre manche à balai réagisse au quart de tour, sans latence et de manière fluide, il faut soigner un peu la tuyauterie logicielle.
L’idée de ce montage sur le Raspberry Pi 400, c’est de faire dialoguer le matériel et la page web en temps réel. Pour y parvenir proprement, j’ai découpé le problème en trois briques :
- À la source (la micro:bit) : on crache les trames brutes de l’accéléromètre en continu sur le port série (UART). C’est du bas niveau, mais c’est d’une fiabilité absolue.
- Au milieu (la moulinette Python) : un script tourne en tâche de fond sur le Pi pour intercepter ces trames. C’est lui qui fait le vrai travail : il calcule les angles, filtre les tremblements du capteur pour lisser le mouvement, évite qu’on parte en vrille à 80° à cause du Gimbal Lock (blocage de cardan), et pousse le résultat propre sur un canal WebSocket local.
- À l’affichage (HTML / Three.js) : la page web se contente d’écouter ce flux en direct et d’incliner la maquette 3D dès qu’un message arrive. On ne fait porter aucune charge de calcul lourde au navigateur.
C’est une approche de maker : on sépare les tâches, on utilise des protocoles standards et robustes, et surtout, tout reste en local sur la machine.
Le modèle 3D : Récupérer les ressources de la NASA
Pour l’affichage, inutile de réinventer la roue. La NASA met à disposition une quantité impressionnante de modèles 3D de ses missions historiques. C’est une mine d’or pour nous, les makers.
Le dépôt GitHub officiel de la NASA regroupe les fichiers pour le LEM, Apollo, Hubble et bien d’autres. C’est là que j’ai récupéré la base de travail :
NASA-3D-Resources sur GitHub. Allez sur 3Dmodels et choisissez Space Shuttle (D)
Préparation du fichier
Dans ce dossier GitHub, vous trouverez des modèles dans divers formats (souvent du .obj ou .3ds). Pour mon projet, j’ai choisi de convertir et de renommer le modèle de la navette pour plus de simplicité :
- Nom du fichier : https://github.com/nasa/NASA-3D-Resources/tree/master/3D%20Models/Space%20Shuttle%20(D)
- Poids : 2,47 Mo (format binaire optimisé pour le web).
- Installation : Placez-le directement à la racine de votre dossier de travail
dev_navette.
Le format .glb est particulièrement efficace sur le Raspberry Pi 400 car il charge les textures et le maillage d’un seul bloc, ce qui évite de multiplier les appels réseau ou les erreurs de liens vers les images de texture.
Optimisation pour le Raspberry Pi 400
La rigueur impose de surveiller ses ressources. Pour garantir un rendu fluide à ~60 images par seconde sur le Pi 400, j’ai sélectionné un modèle optimisé.
Voici ses caractéristiques techniques :
- Fichier utilisé : Space Shuttle (D).glb que j ai renommé shuttle.glb
- Poids : 2,47 Mo (un excellent compromis entre détails visuels et performance GPU).
- Format :
.glb(le « JPEG de la 3D », incluant maillage et textures). - Emplacement : Le fichier doit être placé à la racine de votre dossier
dev_navette, au même niveau que votre fichierindex.html.
Le modèle a été centré sur ses axes de rotation (centre de gravité) pour que les commandes de tangage et de roulis envoyées par la micro:bit s’appliquent naturellement sans créer de décentrement visuel.
La source matérielle : Programmer la micro:bit
Pour commencer, nous devons transformer notre carte micro:bit en capteur d’inclinaison bavard. Son rôle est simple : lire en boucle l’état de son accéléromètre embarqué et envoyer les valeurs brutes des axes X, Y et Z sur son port USB (qui se comporte comme une liaison série UART).
Voici le code MicroPython à flasher sur la carte. Je l’ai largement commenté pour que vous puissiez comprendre chaque étape du traitement :
La minute aéronautique : Qu’est-ce qu’une CDVE ?
Dans ce projet, j’emploie le terme CDVE pour Commandes de Vol Électriques (le fameux Fly-by-wire). Sur une navette spatiale ou un avion moderne, le manche à balai n’a plus aucun lien mécanique (câbles, poulies) avec les gouvernes.
Le pilote donne une consigne via un manche électronique (notre micro:bit). Cette consigne brute est envoyée à un ordinateur de bord (notre script Python sur le Raspberry Pi) qui va filtrer les tremblements et vérifier que l’ordre ne met pas l’aéronef en danger (comme notre blocage mathématique à 80°), avant d’envoyer l’ordre corrigé aux gouvernes (notre affichage 3D). Nous avons reproduit fidèlement l’architecture informatique d’un véritable simulateur de vol !
# ==============================================================================
# Programme : capteur_cdve.py (MicroPython pour micro:bit)
# Rôle : Acquisition et envoi continu des vecteurs de gravité via UART
# Auteur : framboise314.fr
# ==============================================================================
# Ce script extrait les accélérations brutes (en milli-g) mesurées par la carte
# et les transmet sous forme de chaîne de caractères (X,Y,Z) sur le port série.
# ==============================================================================
from microbit import *
# ------------------------------------------------------------------------------
# INITIALISATION
# ------------------------------------------------------------------------------
# On configure explicitement la vitesse de la liaison série à 115200 bauds.
# C'est indispensable pour assurer un débit rapide et éviter la latence.
uart.init(baudrate=115200)
# ------------------------------------------------------------------------------
# BOUCLE PRINCIPALE (Acquisition temps réel)
# ------------------------------------------------------------------------------
while True:
# 1. Lecture des capteurs
# On récupère l'accélération sur les 3 axes. Au repos, la gravité
# terrestre (1g) se répartit sur X, Y et Z en fonction de l'inclinaison.
x = accelerometer.get_x()
y = accelerometer.get_y()
z = accelerometer.get_z()
# 2. Formatage de la trame CSV
# On assemble les trois valeurs séparées par une simple virgule.
# C'est ce format brut ultra-léger que le script Python décodera plus tard.
trame = str(x) + "," + str(y) + "," + str(z)
# 3. Transmission
# print() envoie automatiquement la trame CSV sur l'UART, suivie d'un
# caractère de fin de ligne (\r\n), indispensable pour synchroniser la lecture.
print(trame)
# 4. Temporisation
# Une pause de 20 millisecondes limite le flux à 50 trames par seconde (50 Hz).
# C'est largement suffisant pour une animation 3D fluide sans saturer le Pi400.
sleep(20)
La preuve par l’image : Test du flux avec Screen
Pour vérifier que ma micro:bit « cause » correctement avec le Raspberry Pi 400, j’ai utilisé l’utilitaire screen. C’est un outil simple et efficace pour ouvrir une console série en une ligne de commande (installez le s’il n’est pas sur votre système).
Une fois la carte branchée, j’ai lancé la commande suivante dans le terminal :
screen /dev/ttyACM0 115200
Le résultat est immédiat. On voit défiler les trames de télémétrie brute sous forme de triplets de données (X, Y, Z). Chaque ligne représente une capture de l’accéléromètre envoyée vers le Pi400 :

Capture du flux série : les données arrivent en temps réel sur le Raspberry Pi.
Le terminal confirme que la liaison fonctionne\ ou : relance le defilé de data . Les données sont prêtes à être traitées par notre calculateur Python.
Note pratique : Pour quitter screen et reprendre la main, la méthode la plus simple sur le Raspberry Pi 400 consiste tout bêtement à fermer la fenêtre de votre terminal (en cliquant sur la croix). Cela tuera automatiquement le processus et libérera le port série pour l’étape suivante.
Le Calculateur de Vol : Mise en place du pont Python
Une fois que vous avez vérifié que les données arrivent bien avec screen, une étape cruciale consiste à libérer proprement le port série. Sur le Raspberry Pi, fermer la fenêtre du terminal ne suffit pas toujours : le processus screen peut rester actif en arrière-plan et « verrouiller » l’accès à la micro:bit, empêchant notre futur script Python de se connecter.
Libérer le port série
Pour être certain que la voie est libre, ouvrez un terminal et exécutez la commande suivante pour mettre fin à toute session screen résiduelle :
pkill screen
Préparation de l’environnement de travail
Nous allons maintenant créer un espace propre pour notre projet. Je vous suggère de créer un dossier dédié afin d’y regrouper le calculateur et, plus tard, la page web de rendu 3D :
mkdir dev_navette
cd dev_navette
Créez ensuite un fichier nommé bridge.py (par exemple avec l’éditeur nano ou Thonny) et insérez-y le code suivant. C’est ce script qui va transformer la télémétrie brute en ordres de commande exploitables.
Le code du pont (bridge.py)
Ce script utilise la bibliothèque asyncio pour gérer simultanément la lecture du port série et la diffusion réseau via WebSocket. Comme précédemment, j’ai ajouté des commentaires détaillés pour expliciter le programme..
# ==============================================================================
# Programme : bridge.py
# Rôle : Pont de télémétrie UART -> WebSocket avec filtrage CDVE
# Auteur : framboise314.fr
# ==============================================================================
import asyncio
import websockets
import serial
import math
import json
# --- CONFIGURATION ET ETAT ---
pitch = 0.0
roll = 0.0
# Constante du filtre passe-bas (0.0 à 1.0)
# 0.15 = amortissement important pour une inertie "navette".
ALPHA = 0.15
async def read_serial():
"""Tâche de fond : Lecture du port série et calcul de l'attitude"""
global pitch, roll
try:
# Ouverture de la liaison avec la micro:bit
ser = serial.Serial('/dev/ttyACM0', 115200, timeout=1)
print("Liaison série établie. Calculateur en attente de données...")
while True:
if ser.in_waiting > 0:
try:
# Lecture et décodage de la trame "X,Y,Z"
line = ser.readline().decode('utf-8').strip()
parts = line.split(',')
if len(parts) == 3:
x = float(parts[0])
y = float(parts[1])
z = float(parts[2])
# --- 1. CALCUL TRIGONOMÉTRIQUE (Angles d'Euler) ---
# On calcule l'inclinaison physique à partir des mg
tangage_physique = math.atan2(y, math.sqrt(x*x + z*z))
# Sécurité anti-Gimbal Lock (blocage de cardan)
# Au-delà de 80° (1.4 rad), on fige le roulis
if abs(tangage_physique) > 1.4:
roulis_physique = 0.0
else:
roulis_physique = math.atan2(x, -z)
# --- 2. TRANSPOSITION DES COMMANDES ---
commande_roulis = -roulis_physique
commande_tangage = tangage_physique
# --- 3. FILTRAGE PASSE-BAS (Lissage du signal) ---
# On mélange une fraction de la nouvelle valeur (ALPHA)
# avec l'ancienne position pour éviter les saccades.
pitch = (ALPHA * commande_roulis) + ((1.0 - ALPHA) * pitch)
roll = (ALPHA * commande_tangage) + ((1.0 - ALPHA) * roll)
except (ValueError, UnicodeDecodeError):
# Ignorer les trames incomplètes ou corrompues
pass
# Temporisation pour libérer le processeur (10ms)
await asyncio.sleep(0.01)
except Exception as e:
print(f"Erreur critique port série : {e}")
async def send_data(websocket):
"""Serveur WebSocket : Diffusion de l'attitude au format JSON"""
global pitch, roll
while True:
# Préparation du paquet de données pour le client JavaScript
data = json.dumps({"pitch": pitch, "roll": roll})
try:
await websocket.send(data)
# Rafraîchissement de l'affichage (20 Hz)
await asyncio.sleep(0.05)
except websockets.exceptions.ConnectionClosed:
break
async def main():
"""Point d'entrée du programme"""
print("Serveur WebSocket lancé sur ws://localhost:8765")
# Lancement de la lecture série en tâche asynchrone
asyncio.create_task(read_serial())
# Démarrage du serveur de diffusion
async with websockets.serve(send_data, "localhost", 8765):
await asyncio.Future() # Maintien du service actif
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\nArrêt du calculateur.")
Ce script garantit le bon fonctionnement du système. En utilisant des protocoles standards comme le JSON et les WebSockets, on crée une architecture découplée. Si demain le moteur de rendu 3D change, ce calculateur Python restera opérationnel, sans aucune modification.
Focus technique : La trame de télémétrie CSV
Le protocole de communication que j’ai choisi est le CSV (Comma-Separated Values). C’est le format le plus simple et le plus universel pour échanger des données structurées.
Chaque message envoyé par la micro:bit ressemble à ceci :
24, -16, -1012
| Composante | Valeur brute (mg) | Interprétation physique |
|---|---|---|
| X | 24 | Inclinaison latérale (Roulis) |
| Y | -16 | Inclinaison avant/arrière (Tangage) |
| Z | -1012 | Force de gravité (Verticale) |
Pourquoi ce format ?
- Légèreté : Pas de fioritures, on ne transmet que l’essentiel pour garantir une latence minimale.
- Lisibilité : Comme vous l’avez vu avec l’outil screen, n’importe quel terminal peut afficher et comprendre ces données.
- Facilité de traitement : En Python, une simple commande
line.split(',')suffit à isoler chaque valeur pour le calculateur.
Note : Chaque trame se termine par un caractère de fin de ligne (\n), ce qui permet au script bridge.py de savoir exactement quand une mesure est complète.
L’Interface 3D : Affichage et Serveur Web
Maintenant que notre « Calculateur de Vol » (le script Python) est prêt à diffuser ses données, il nous faut un écran pour voir notre navette bouger. Pour cela, nous allons utiliser une page Web et la bibliothèque Three.js.
Zoom sur Three.js : Le moteur de rendu
Si WebGL (la technologie de base du navigateur) est une boîte à outils complexe où il faut tout programmer à la main, Three.js est le chef de chantier qui simplifie tout. C’est la bibliothèque JavaScript de référence pour afficher de la 3D sur le Web.
Pour comprendre comment ça marche, imaginez une pièce de théâtre :
- La Scène (Scene) : C’est votre plateau. Rien n’existe tant qu’on ne le place pas dessus. C’est l’espace en 3D où évoluent les objets.
- La Caméra (Camera) : C’est l’œil du spectateur. On peut la déplacer, changer son zoom ou son angle de vue.
- Le Rendu (Renderer) : C’est le projecteur. C’est lui qui prend la scène et la caméra pour dessiner l’image finale sur votre écran.
- Le Maillage (Mesh) : C’est l’acteur. Dans notre cas, c’est notre fichier
shuttle.glbqui contient la forme et les textures de la navette.
Pourquoi est-ce indispensable ici ?
Sans Three.js, faire pivoter la navette en fonction des données de la micro:bit demanderait des centaines de lignes de calculs matriciels indigestes. Ici, il nous suffit de dire à l’objet de tourner de quelques degrés, et la bibliothèque s’occupe de tout le calcul mathématique en arrière-plan.
Pour aller plus loin : La documentation officielle est une mine d’or remplie d’exemples interactifs :
Consulter la doc de Three.js
Pourquoi un serveur Web local ?
Vous pourriez être tenté de simplement double-cliquer sur votre fichier index.html pour l’ouvrir dans Chromium. Mauvaise idée ! Les navigateurs modernes bloquent le chargement des fichiers 3D (le .glb) depuis le disque local pour des raisons de sécurité (politique CORS).
Pour que la navette s’affiche, il faut « servir » la page via un protocole HTTP. Pas besoin d’installer une usine à gaz comme Apache ou Nginx, Python dispose d’un petit serveur intégré parfait pour le développement. Dans votre dossier dev_navette, lancez cette commande (dans un autre terminal que celui où vous exécutez bridge.py) :
python3 -m http.server 8000
Votre Raspberry Pi 400 devient alors un mini serveur web. Il vous suffit d’ouvrir Chromium et de taper l’adresse : http://localhost:8000.
Le code de l’interface (index.html)
Voici le contenu du fichier index.html. Je l’ai encore largement commenté pour que vous puissiez comprendre comment on récupère les données de la WebSocket pour faire pivoter la navette sur ses axes de tangage et de roulis.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>NASA Shuttle - Contrôle Temps Réel</title>
<style>
/* --- STYLE VISUEL --- */
body { margin: 0; overflow: hidden; background-color: #020202; color: #fff; font-family: monospace; }
#ui {
position: absolute; top: 20px; left: 20px; padding: 15px;
background: rgba(0, 0, 0, 0.8); border: 1px solid #00ff00;
border-radius: 4px; pointer-events: none; z-index: 10;
}
.status { color: #00ff00; }
#data { color: #ffae00; margin-top: 10px; font-size: 0.9em; }
</style>
</head>
<body>
<!-- Petit panneau de contrôle en haut à gauche -->
<div id="ui">
[ SYSTÈME : <span class="status" id="ws-status">DÉCONNECTÉ</span> ]<br><br>
FLUX : MICRO:BIT via PYTHON<br>
<div id="data">Attente du chargement...</div>
</div>
<!-- Chargement des bibliothèques Three.js -->
<script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.156.1/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.156.1/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
let scene, camera, renderer, shuttle, gimbal;
let pitch = 0, roll = 0;
function init() {
// Création de la scène et de la caméra
scene = new THREE.Scene();
scene.background = new THREE.Color(0x050505);
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
// Moteur de rendu WebGL
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.outputColorSpace = THREE.SRGBColorSpace;
document.body.appendChild(renderer.domElement);
// Lumières (Ambiante + Directionnelle pour le relief)
scene.add(new THREE.AmbientLight(0xffffff, 1.2));
const sun = new THREE.DirectionalLight(0xffffff, 2.0);
sun.position.set(50, 100, 50);
scene.add(sun);
// CRÉATION DU CARDAN (Gimbal)
// On crée un groupe vide qui servira de pivot pour la navette.
gimbal = new THREE.Group();
scene.add(gimbal);
// CHARGEMENT DU MODÈLE SHUTTLE.GLB
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.6/');
const loader = new GLTFLoader();
loader.setDRACOLoader(dracoLoader);
loader.load('shuttle.glb', (gltf) => {
shuttle = gltf.scene;
// Centrage automatique du modèle
const box = new THREE.Box3().setFromObject(shuttle);
const size = box.getSize(new THREE.Vector3());
const center = box.getCenter(new THREE.Vector3());
shuttle.position.x += (shuttle.position.x - center.x);
shuttle.position.y += (shuttle.position.y - center.y);
shuttle.position.z += (shuttle.position.z - center.z);
// Correction de l'orientation initiale (on la redresse)
shuttle.rotation.set(-Math.PI / 2, 0, 0);
// Réglage de la caméra en fonction de la taille de l'objet
const maxDim = Math.max(size.x, size.y, size.z);
camera.position.set(0, maxDim * 0.5, maxDim * 1.25);
camera.lookAt(0, 0, 0);
gimbal.add(shuttle);
initWebSocket(); // On ne se connecte qu'une fois le modèle chargé
});
window.addEventListener('resize', onWindowResize);
}
// CONNEXION AU PONT PYTHON
function initWebSocket() {
const ws = new WebSocket('ws://localhost:8765');
ws.onopen = () => document.getElementById('ws-status').innerText = "CONNECTÉ";
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
pitch = msg.pitch;
roll = msg.roll;
document.getElementById('data').innerText =
`Pitch: ${(pitch * 180 / Math.PI).toFixed(1)}° | Roll: ${(roll * 180 / Math.PI).toFixed(1)}°`;
};
ws.onclose = () => {
document.getElementById('ws-status').innerText = "COUPÉ";
setTimeout(initWebSocket, 2000); // Reconnexion auto
};
}
// BOUCLE D'ANIMATION (60 fois par seconde)
function animate() {
requestAnimationFrame(animate);
if (gimbal) {
// On applique les angles reçus au pivot (cardan)
gimbal.rotation.x = pitch;
gimbal.rotation.z = -roll;
}
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
init();
animate();
<script>
<body>
<html>
Le Grand Décollage : Mise en service du système
Maintenant que tous nos fichiers sont prêts dans le dossier dev_navette, il est temps de passer à l’action. Pour que la magie opère, nous allons devoir lancer deux services en même temps.
Démarrage manuel (La méthode « pas à pas »)
Pour bien comprendre comment les briques communiquent entre elles, nous allons ouvrir deux terminaux séparés. C’est indispensable car chaque programme doit rester « vivant » pour que le simulateur fonctionne.
- Terminal 1 – Le Serveur Web : Ce terminal va gérer l’affichage de la page dans votre navigateur.
cd ~/dev_navette python3 -m http.server 8000 - Terminal 2 – Le Calculateur (Bridge) : Ce terminal va gérer la liaison entre la micro:bit et le réseau.
cd ~/dev_navette python3 bridge.py
Une fois ces deux services lancés, ouvrez Chromium et tapez l’adresse suivante : http://localhost:8000.
Vérifier que tout fonctionne
Dès que la page s’affiche, jetez un œil au panneau de télémétrie en haut à gauche :
- Statut : Il doit passer de « DÉCONNECTÉ » à « CONNECTÉ » en vert.
- Données : Les valeurs de Tangage et Roulis doivent s’agiter dès que vous manipulez la micro:bit.
- Visuel : La navette doit s’incliner de façon fluide. Si vous inclinez la carte vers l’avant, le nez de la navette doit piquer vers le bas.
Automatisation : Un clic pour tout lancer
C’est ici qu’on passe du bricolage à l’application finie. Nous allons créer un script de démarrage et une icône sur le bureau pour éviter de retaper les commandes à chaque fois.
Ce script va nettoyer les anciennes instances et lancer nos deux serveurs automatiquement. Voici le contenu du fichier demarrage_navette.sh :
#!/bin/bash
cd ~/dev_navette
# On tue les anciennes instances pour libérer les ports
pkill -f "python3 -m http.server 8000"
pkill -f "python3 bridge.py"
# Lancement des services en tâche de fond
python3 -m http.server 8000 &
python3 bridge.py &
# On attend que les serveurs se lancent
sleep 2
# On ouvre Chromium sur la bonne page
xdg-open http://localhost:8000
Vous remarquerez un
& à la fin des lignes de commande. En langage Linux, cela signifie que l’on exécute le programme en tâche de fond (background). Sans ce symbole, le script s’arrêterait à la première ligne en attendant que le serveur se ferme. Grâce au &, le programme est chargé en mémoire et s’exécute « dans son coin », permettant au script de passer immédiatement à la ligne suivante.L’icône sur le Bureau avec votre visuel
Télécharger l’icône navette.png
Pour finir proprement, j’ai préparé un fichier navette.png qui servira d’icône. Placez-le dans le dossier dev_navette. Ensuite, créez un fichier Banc_Navette.desktop dans le dossier ~/Desktop (votre Bureau) avec ce contenu :
[Desktop Entry]
Name=Banc Navette
Comment=Visualisation 3D Navette via Micro:bit
Exec=/home/pi/dev_navette/demarrage_navette.sh
Icon=/home/pi/dev_navette/navette.png
Terminal=true
Type=Application
Categories=Development;
Name[fr_FR]=Banc Navette
Dernière étape cruciale : les permissions
Pour que ces fichiers soient utilisables, il faut donner au système le droit de les exécuter. Tapez ceci une dernière fois dans un terminal :
chmod +x ~/dev_navette/demarrage_navette.sh
chmod +x ~/Desktop/Banc_Navette.desktop
Installation et mise en route
Pour déployer ce projet sur votre Raspberry Pi, suivez ces étapes de configuration :
- Téléchargez l’archive fichiers_navette.zip et décompressez-la.
- Répartissez les fichiers dans le dossier
/home/pi/dev_navette/comme illustré sur l’image ci-dessus (bridge.py,demarrage_navette.sh,index.htmletnavette.png). Notez que le modèle 3Dshuttle.glbdoit également se trouver dans ce répertoire. - Placez le fichier
Banc_Navette.desktopdirectement sur votre Bureau (Desktop). - Rendez les scripts exécutables en saisissant ces deux commandes dans un terminal :
chmod +x ~/dev_navette/demarrage_navette.sh chmod +x ~/Desktop/Banc_Navette.desktop - Il ne vous reste plus qu’à double-cliquer sur le lanceur Banc Navette pour démarrer automatiquement les serveurs et l’interface de pilotage.
Vidéo
Conclusion : Une architecture ouverte et réactive
Ce projet illustre parfaitement ce qu’on peut obtenir en combinant des briques matérielles simples et des protocoles logiciels standards. Plutôt que de subir une solution « boîte noire » propriétaire, vous avez ici le contrôle total sur chaque étape de la chaîne de traitement.
Pour résumer le fonctionnement de ce manche à balai spatial, voici le chemin parcouru par l’information :
➔ Accéléromètre (Valeurs brutes en mg)
➔ Liaison UART/USB (Trame CSV)
➔ Calculateur bridge.py (Trigonométrie + Filtre Passe-Bas)
➔ Paquet JSON (Données formatées)
➔ Serveur WebSocket (Diffusion temps réel)
➔ Three.js (Mise à jour de la scène WebGL)
➔ Rendu 3D (La navette s’incline à l’écran)
En séparant ainsi l’acquisition (Micro:bit), le calcul (Python) et le rendu (JavaScript), je m’assure une souplesse totale. C’est une méthode de travail que je privilégie systématiquement : utiliser des standards ouverts permet de s’affranchir de l’obsolescence programmée et garantit que ce montage fonctionnera encore dans plusieurs années, peu importe l’évolution des navigateurs ou des systèmes d’exploitation.
Vous pouvez télécharger l’ensemble des fichiers de ce tutoriel en cliquant sur ce lien.
Remerciements et coulisses de l’article :
Je tiens à remercier chaleureusement Kubii qui a fourni les cartes micro:bit en prévision du Nantes Maker Campus 2026. J’aurai le plaisir de vous y retrouver si vous passez nous voir sur le stand !
Pour la réalisation de ce dossier, j’ai également mis l’intelligence artificielle Gemini à contribution. Elle m’a épaulé sur certaines parties du développement et, surtout, sur la finalisation et la vérification rigoureuse des commentaires. Dans un projet de cette nature, la clarté du code et des explications me semble indispensable pour que vous puissiez vous approprier ces outils et les faire évoluer.
Acheter la carte micro:bit v2 chez Kubii
Sources
Ressources Micro:bit
-
Site Officiel : https://microbit.org/fr/
-
Le point d’entrée pour les débutants et la présentation générale du projet éducatif de la BBC.
-
-
Documentation Technique (Developer) : https://tech.microbit.org/
-
C’est ici qu’on trouve les détails sur le processeur nRF52833, le brochage (pinout) et les spécifications matérielles précises.
-
-
MicroPython pour micro:bit : https://microbit-micropython.readthedocs.io/
-
La référence absolue pour comprendre comment on interroge l’accéléromètre ou la liaison série (UART) en Python.
-
https://science.nasa.gov/3d-resources/space-shuttle-b/https://github.com/nasa/NASA-3D-Resources/tree/master/3D%20Models







Impressionnant, ludique, génial.
Si avec ça nos têtes blondes ne relèvent pas la tête de leurs écrans, je ne comprends plus !