Voici une fiche de synthèse complète en français sur le Bridge de l’UNO‑Q, avec les exemples de code. Les points clés viennent de la doc UNO Q et de la bibliothèque Arduino_RouterBridge : le Bridge peut être utilisé comme client RPC et comme serveur RPC, call() côté MCU renvoie un objet RpcCall asynchrone, result(...) est bloquant et renvoie true si l’appel s’est terminé sans erreur, et notify() sert aux appels sans réponse. (github.com)
L’UNO‑Q contient deux mondes qui coopèrent :
- MCU : microcontrôleur, code C++/Arduino
- MPU : Linux, code Python
La communication entre les deux passe par le Bridge, qui repose sur un routeur RPC central. Ce n’est donc pas une liaison “à sens unique” : chaque côté peut exposer une fonction et chaque côté peut appeler une fonction distante.
Schéma mental simple :
MCU <---- Bridge / Router RPC ----> MPU
C++ Python
Il faut retenir ceci :
- provide = j’expose une fonction à l’autre côté (MPU ou MCU)
- provide_safe = j’expose une fonction, mais protégée / sérialisée (MCU uniquement)
- call = j’appelle une fonction distante avec réponse (MPU ou MCU)
- notify = j’envoie une notification sans réponse (MPU ou MCU)
- result(...) = je récupère la réponse d’un call côté MCU uniquement
C’est la clef pour comprendre toute l’architecture.
Bridge.provide("nom", fonction) enregistre une fonction pour qu’elle puisse être appelée depuis l’autre côté.
#include <Arduino.h>
#include <Arduino_RouterBridge.h>
void set_led(bool state) {
digitalWrite(LED_BUILTIN, state ? HIGH : LOW);
}
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Bridge.begin();
Bridge.provide("set_led", set_led);
}
void loop() {
}Ici, le MCU expose la fonction set_led.
from arduino.app_utils import App, Bridge
def update_gps(lat, lon):
print("lat =", lat, "lon =", lon)
Bridge.provide("update_gps", update_gps)
def loop():
pass
App.run(user_loop=loop)Ici, le MPU expose la fonction update_gps.
Conclusion importante : provide() n’est pas réservé au MPU. On peut l’utiliser des deux côtés.
call() sert à appeler une fonction distante qui a été enregistrée avec provide(). C’est un appel de type requête / réponse.
from arduino.app_utils import App, Bridge
def get_temp():
return 25
Bridge.provide("get_temp", get_temp)
def loop():
pass
App.run(user_loop=loop)#include <Arduino.h>
#include <Arduino_RouterBridge.h>
void setup() {
Serial.begin(115200);
Bridge.begin();
RpcCall r = Bridge.call("get_temp");
int t;
if (r.result(t)) {
Serial.print("Temperature = ");
Serial.println(t);
} else {
Serial.println("RPC error");
}
}
void loop() {
}Ici :
- le MCU envoie l’appel
get_temp - le MPU exécute
get_temp() - la valeur de retour est récupérée dans
t r.result(t)renvoietruesi l’appel s’est bien terminé.
#include <Arduino.h>
#include <Arduino_RouterBridge.h>
void set_led(bool state) {
digitalWrite(LED_BUILTIN, state ? HIGH : LOW);
}
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Bridge.begin();
Bridge.provide("set_led", set_led);
}
void loop() {
}from arduino.app_utils import App, Bridge
import time
def loop():
Bridge.call("set_led", True)
time.sleep(1)
Bridge.call("set_led", False)
time.sleep(1)
App.run(user_loop=loop)Conclusion importante : call() n’est pas réservé au MCU. On peut l’utiliser des deux côtés.
La bibliothèque Arduino_RouterBridge indique que Bridge.call() côté C++ est non bloquant et retourne un objet RpcCall. La méthode result(...) de RpcCall est bloquante : elle attend la réponse RPC.
RpcCall r = Bridge.call("get_temp");
int t;
if (r.result(t)) {
Serial.println(t);
} else {
Serial.println("RPC error");
}Ici :
rreprésente l’appel RPC en coursr.result(t)attend la réponse- si tout va bien,
treçoit la valeur renvoyée par la fonction distante - le
boolrenvoyé parresult(t)indique succès / échec de la transaction RPC, pas la valeur métier.
Oui, mais ce 1 n’est pas la donnée renvoyée par la fonction.
C’est simplement le succès de la transaction RPC.
Exemple :
RpcCall r = Bridge.call("get_temp");
int t;
if (r.result(t)) {
Serial.println("Transaction OK");
Serial.println(t);
} else {
Serial.println("Transaction KO");
}notify() envoie une requête sans attendre de réponse.
if (gps.extrait() && gps.estValide()) {
Bridge.notify(
"update_gps",
gps.latitude,
gps.longitude,
gps.jour,
gps.mois,
gps.annee + 2000,
(gps.heure) % 24,
gps.minute,
gps.seconde,
gps.numSat,
gps.altitude
);
}from arduino.app_utils import App, Bridge
import threading
_lock = threading.Lock()
_state = {}
def update_gps(lat, lon, jour, mois, annee, heure, minute, seconde, numsat, altitude):
with _lock:
_state["lat"] = float(lat)
_state["lon"] = float(lon)
_state["jour"] = int(jour)
_state["mois"] = int(mois)
_state["annee"] = int(annee)
_state["heure"] = int(heure)
_state["minute"] = int(minute)
_state["seconde"] = int(seconde)
_state["numsat"] = int(numsat)
_state["altitude"] = float(altitude)
Bridge.provide("update_gps", update_gps)
def loop():
pass
App.run(user_loop=loop)provide_safe() est la version protégée de provide().
Avec provide() : plusieurs appels peuvent arriver simultanément.
Avec provide_safe() :
un appel à la fois
from arduino.app_utils import App, Bridge
counter = 0
def increment():
global counter
counter += 1
return counter
Bridge.provide_safe("increment", increment)
def loop():
pass
App.run(user_loop=loop)Le MCU peut :
call("nom", ...)notify("nom", ...)
si le MPU a fait :
provide("nom", fonction)- ou
provide_safe("nom", fonction)
Le MPU peut :
call("nom", ...)
si le MCU a fait :
provide("nom", fonction)
MCU expose une fonction :
Bridge.provide("f", ...).
MPU appelle cette fonction :
Bridge.call("f", ...).
MPU expose une fonction :
Bridge.provide("g", ...).
MCU appelle cette fonction :
RpcCall r = Bridge.call("g", ...).
r.result(valeur)
| Élément | Rôle | Réponse attendue ? | Côté concerné |
| ----------------------- | ------------------------------------- | -----------------: | ---------------------------------------- |
| `Bridge.provide()` | expose une fonction | non | MCU ou MPU |
| `Bridge.provide_safe()` | expose une fonction de façon protégée | non | MCU |
| `Bridge.call()` | appelle une fonction distante | oui | MCU ou MPU |
| `RpcCall` | représente un appel RPC asynchrone | oui | MCU |
| `result(...)` | attend et récupère la réponse | oui | MCU |
| `Bridge.notify()` | envoie une notification | non | MCU/Bridge selon API disponible |
Exposer une fonction côté MCU
void led_on() {
digitalWrite(LED_BUILTIN, HIGH);
}
Bridge.provide("led_on", led_on);Appeler cette fonction depuis Python
Bridge.call("led_on")Exposer une fonction côté Python
def get_temp():
return 25
Bridge.provide("get_temp", get_temp)Appeler cette fonction depuis le MCU
RpcCall r = Bridge.call("get_temp");
int t;
if (r.result(t)) {
Serial.println(t);
}Envoyer un événement sans réponse
Bridge.notify("update_gps", lat, lon, jour, mois, annee, heure, minute, seconde);provide = j’ouvre une porte
call = je frappe et j’attends une réponse
notify = j’envoie un message et je continue
result = je récupère la réponse du call côté MCU