ALT CTRL - Arduino <--> Godot #1 USB

Ce guide explique comment synchroniser un microcontrôleur avec Godot via USB, en mettant l'accent sur une communication simple et accessible.


Communication temps réel entre un microcontrôleur (Arduino/ESP32) et Godot via USB

À l'occasion d'une intervention auprès des étudiants de M1 à l'ENJMIN, j’ai rédigé quelques guides pour montrer comment faire communiquer un microcontrôleur avec Godot.

Dans la création d’installations interactives ou de contrôleurs alternatifs, il est souvent nécessaire de faire dialoguer du hardware (comme un Arduino ou un ESP32) avec un ordinateur. Ici, on s’intéresse à une communication simple et filaire via un câble USB. De plus cette exemple se limite à un micro controller, mais ça pourrais être utilisable avec de nombreux micro controlleurs.

Ce guide ne couvre pas les bases d’Arduino ou de Godot. De nombreux tutoriels existent déjà pour ça.

Communication Série

USB signifie Universal Serial Bus.

C’est un standard qui permet à des appareils comme un Arduino de communiquer avec un PC.

  • Universal : conçu pour remplacer plusieurs anciens types de connecteurs.
  • Serial : les données transitent bit par bit.
  • Bus : plusieurs appareils peuvent être branchés de manière partagée.

Dans notre cas, nous utiliserons un ESP32-S3 connecté via USB. Ce guide est aussi valable pour les Arduinos classiques.

💡
En USB classique, la communication est de type maître/esclave. Seul l’ordinateur (le maître) initie les échanges. Une seule entité peut écouter/envoyer à la fois.

Arduino --> Godot

On commence en envoyant un simple message série.

Nous allons incrémenter une variable de manière continue et envoyer sa valeur à chaque boucle en utilisant la fonction Serial.println(). Serial est la classe qui donne accès aux fonctions de communication via le port série. Les fonctions print() et println() permettent d’envoyer des chaînes de caractères (ou d'autres types) vers l’ordinateur via l’USB.

  • Serial.print() envoie un texte sans retour à la ligne.
  • Serial.println() ajoute un retour à la ligne.

Exemple :

Serial.print("Hello");
Serial.print("World");

Affiche : HelloWorld

Serial.println("Hello");
Serial.println("World");

Affiche :

Hello
World

Arduino

int i = 0;

void setup() {
 Serial.begin(115200);
}

void loop() {
 i++;
 Serial.println(String(i));
}

Ce code incrémente et envoie un nombre via USB à chaque boucle.

Après avoir téléversé le code, ouvrez le moniteur série de l’IDE Arduino : vous devriez voir défiler des nombres.

0:00
/0:02

Godot : réception des données

Godot ne prend pas en charge nativement la communication série. On va donc utiliser un add-on : GDSerial.

Installez GDSerial depuis l’AssetLib, ou téléchargez-le ici.

(si téléchargé) Placez le contenu dans un dossier addons à la racine du projet.

Allez dans :
Projet > Paramètres du projet > Plugins et activez GDSerial.

Grace à un script, nous allons pouvoir communiquer avec un port usb.

extends Node2D

var serial: GdSerial
var is_connected: bool = false

func _ready():
	serial = GdSerial.new()
	
	var ports = serial.list_ports()
	print("Available ports: ", ports) # affiche les ports disponible
	
	# Configuration et connexion unique
	serial.set_port("/dev/cu.usbmodem14301")  # Ajustez selon votre système
	serial.set_baud_rate(115200)
	
	# Ouvre la connexion une seule fois et la maintient ouverte
	if serial.open():
		is_connected = true
		print("Connecté")
	else:
		print("Échec de la connexion")

func _process(delta: float) -> void:
	if is_connected:
		monitor_serial()

func monitor_serial():
	# Vérifie si des données sont disponibles avant d'essayer de lire
	var bytes_count = serial.bytes_available()
	if bytes_count > 0:
		var data = serial.readline()
		if data != "":
			print("Monitor: ", data)
			# Traite vos données ici
    
	serial.clear_buffer()

func _exit_tree():
	# Nettoie les ressources à la fermeture
	if is_connected:
		serial.close()
💡
N’oubliez pas de changer la ligne avec serial.set_port(...) pour pointer vers le bon port !
  • sur Windows, ça peut ressembler à COM3.
  • Sur Mac/Linux : /dev/cu.usbmodemXXXX.
Liste des ports Arduino
Liste des ports dans la console de Godot
Utilisez la ligne print("Available ports: ", ports) pour voir quels ports sont disponibles après un premier Play dans Godot.
🚸
Le moniteur série dans l’IDE Arduino doit être fermé quand Godot se connecte. Sinon, l’accès au port sera bloqué.

Si tout fonctionne bien, vous verrez les nombres s’incrémenter dans la console de Godot.

⚠️
Attention à ce que le monituer serial côté arduino soit bien fermé ! SInon toute nouvelle connectionn au serial ne sera pas possible, même si vous utilisez le bon nom de port.

et si tout se passe bien, vous devriez avoir ce résultat, un nombre qui s'incrémente dans la console.

0:00
/0:06

Nous voici donc désormais capables de recevoir des interactions ou d'interpréter des données provenant d'un Arduino grâce à la variable 'data'. Bien qu'il existe une multitude de cas d'utilisation à considérer, le but premier de ce guide est de rester simple et accessible.

Godot --> Arduino

Et maintenant, on fait le chemin inverse : depuis Godot, on envoie des données à l’Arduino.

Code Godot pour envoyer les messages
extends Node2D

var serial: GdSerial
var is_connected: bool = false

func _ready():
	serial = GdSerial.new()
	
	var ports = serial.list_ports()
	print("Available ports: ", ports) # affiche les ports disponible
	
	# Configuration et connexion unique
	serial.set_port("/dev/cu.usbmodem14401")  # Ajustez selon votre système
	serial.set_baud_rate(115200)
	
	# Ouvre la connexion une seule fois et la maintient ouverte
	if serial.open():
		is_connected = true
		print("Connecté")
	else:
		print("Échec de la connexion")

func _process(delta: float) -> void:
	if is_connected:
		serial.writeline("ok cool");
		monitor_serial()

func monitor_serial():
	# Vérifie si des données sont disponibles avant d'essayer de lire
	var bytes_count = serial.bytes_available()
	if bytes_count > 0:
		var data = serial.readline()
		if data != "":
			#var datasStructured = JSON.parse_string(data)
			print("Monitor: ", data)
			# Traite vos données ici
	
	serial.clear_buffer()

func _exit_tree():
	# Nettoie les ressources à la fermeture
	if is_connected:
		serial.close()

Voici un code qui envoie via la fonction serial.writeline("ok cool"); une chaine de charactères.

Code Arduino pour recevoir les messages

#include <Adafruit_NeoPixel.h>

#define PIN 48
#define NUMPIXELS 1
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

String input = "";

int i = 0;
void setup() {
  Serial.begin(115200);
  pixels.begin();
}

void loop() {
  pixels.clear();

  // Lire tous les caractères disponibles
  while (Serial.available()) {
    char c = Serial.read();

    // Fin de ligne ? C'est la fin d'un message
    if (c == '\n') {
      input.trim();  // Nettoyage \r et espaces éventuels

      pixels.setPixelColor(0, pixels.Color(0, 255, 0));  // LED VERTE
      pixels.show();

      Serial.println("Reçu chaîne : " + input);
      input = "";  // Réinitialiser le buffer
      delay(500);
    } else {
      input += c;  // Ajouter chaque caractère reçu
    }
  }
  

  // Si rien n’est reçu : LED rouge
  if (input == "") {
    pixels.setPixelColor(0, pixels.Color(150, 0, 0));
  }

  pixels.show();
  delay(50);
}

Ce code change la couleur d'une LED sur l’ESP32 selon ce qui est reçu via USB.

Tout le code lié à Adafruit_NeoPixel pixels me permet de contrôler la LED intégrée à mon ESP32. Ce qui donne un retour visuel en plus de la console dans Godot.

0:00
/0:02

Si tout fonctionne correctement :

  • La LED devrait passer au vert quand un message est reçu.
  • Le message "Reçu chaîne : ..." devrait s’afficher côté Arduino.
  • Godot, lui, pourra afficher une confirmation dans sa console.

Ce guide reste volontairement simple. Il y a encore plein d’autres cas à explorer (parsing, JSON, synchronisation, retours d’état...), mais ce premier pas vous permet déjà de créer un lien basique entre Godot et un microcontrôleur.

La bise, Tchouss !

o(*^@^*)o