Skip to content

Instantly share code, notes, and snippets.

@philippe86220
Last active March 18, 2026 07:20
Show Gist options
  • Select an option

  • Save philippe86220/70dd20bac133e94a92507c2bbcfdefd5 to your computer and use it in GitHub Desktop.

Select an option

Save philippe86220/70dd20bac133e94a92507c2bbcfdefd5 to your computer and use it in GitHub Desktop.
Bridge de l’UNO‑Q

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)

Fiche de synthèse : communication MCU ↔ MPU sur UNO‑Q

1. Idée générale

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

2. Règle mentale fondamentale

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.


3. Bridge.provide()

Rôle

Bridge.provide("nom", fonction) enregistre une fonction pour qu’elle puisse être appelée depuis l’autre côté.

Exemple côté MCU

#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.

Exemple côté MPU (Python)

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.


4. Bridge.call()

Rôle

call() sert à appeler une fonction distante qui a été enregistrée avec provide(). C’est un appel de type requête / réponse.

Cas A : MCU appelle le MPU

Python expose une fonction

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)

MCU appelle cette fonction

#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) renvoie true si l’appel s’est bien terminé.

Cas B : MPU appelle le MCU

MCU expose une fonction

#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() {
}

Python appelle cette fonction

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.


5. RpcCall et result(...)

Ce que fait Bridge.call() côté MCU

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.

Forme correcte

RpcCall r = Bridge.call("get_temp");

int t;
if (r.result(t)) {
  Serial.println(t);
} else {
  Serial.println("RPC error");
}

Ce qu’il faut bien comprendre

Ici :

  • r représente l’appel RPC en cours
  • r.result(t) attend la réponse
  • si tout va bien, t reçoit la valeur renvoyée par la fonction distante
  • le bool renvoyé par result(t) indique succès / échec de la transaction RPC, pas la valeur métier.

6. Peut-on tester directement “1 si ça s’est bien passé” ?

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");
}

7. Bridge.notify()

Rôle

notify() envoie une requête sans attendre de réponse.

Exemple GPS : cas idéal pour notify()

MCU

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
  );
}

Python

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)

8. provide_safe()

Idée générale

provide_safe() est la version protégée de provide().

Intuition

Avec provide() : plusieurs appels peuvent arriver simultanément.
Avec provide_safe() :

un appel à la fois

Exemple conceptuel

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)

9. Résumé des directions possibles

MCU -> MPU

Le MCU peut :

  • call("nom", ...)
  • notify("nom", ...)

si le MPU a fait :

  • provide("nom", fonction)
  • ou provide_safe("nom", fonction)

MPU -> MCU

Le MPU peut :

  • call("nom", ...)

si le MCU a fait :

  • provide("nom", fonction)

10. Schéma global à retenir

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)


11. Tableau de synthèse

| É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          |


12. Exemples courts prêts à relire

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);

13. Phrase finale à retenir

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

Comments are disabled for this gist.