Une erreur Lua non gérée termine le programme du robot, immédiatement : la cellule s'arrête, la pièce reste coincée dans le préhenseur et l'équipe appelle la maintenance. Lua fournit pourtant un outil qui empêche exactement cela : pcall. À travers des exemples DobotStudio, cet article montre comment protéger les commandes de mouvement, réessayer les erreurs de façon délibérée, définir des objets d'erreur personnalisés et rendre les défauts visibles de manière centralisée, pour qu'une erreur d'exécution ne devienne pas un arrêt de production.
Pourquoi la gestion des erreurs fonctionne autrement dans un programme robot
Dans une application de bureau, un processus qui plante est agaçant. Dans une cellule robotisée, cela signifie : le programme s'interrompt en plein cycle, les axes s'arrêtent dans une position indéfinie, la pièce et le préhenseur sont dans un état que personne n'a prévu. Le redémarrage ne coûte pas que des minutes, il faut souvent une personne pour dégager le robot à la main.
Sources d'erreur typiques au quotidien avec un Dobot : une pièce posée de travers et le mouvement bute sur un fin de course, une connexion TCP vers le système de caméra se coupe, un fichier sur la carte SD ne s'ouvre pas, un capteur renvoie une valeur inattendue. Rien de tout cela ne doit terminer le programme si l'erreur est interceptée au bon endroit.
pcall en 60 secondes
pcall signifie « protected call » : la fonction transmise est exécutée, mais une erreur en son sein ne termine pas le programme. À la place, pcall renvoie deux valeurs : un indicateur de succès et, en cas d'échec, le message d'erreur.
-- Schéma de base : appel protégé
local ok, err = pcall(function()
fonction_risquee()
end)
if not ok then
print("Erreur interceptée : " .. tostring(err))
-- le programme continue, c'est nous qui décidons de la suite
end
Protéger les commandes de mouvement
Le point d'entrée le plus pratique est un wrapper autour des commandes de mouvement. Au lieu d'appeler MovJ et MovL directement, encapsulez-les dans une fonction qui intercepte les erreurs, les journalise et ramène la cellule dans un état défini :
-- Global.lua : mouvement protégé avec journal
function mouvement_sur(nom, mouvement)
local ok, err = pcall(mouvement)
if not ok then
log_local("ERROR", "Mouvement '" .. nom .. "' échoué : " .. tostring(err))
DO(PREHENSEUR, OFF) -- déposer la pièce de façon contrôlée
Sync()
return false
end
return true
end
-- Utilisation dans le cycle
if not mouvement_sur("Approche dépôt", function() MovJ(P_DEPOT) end) then
return -- terminer le cycle proprement au lieu d'interrompre en plein mouvement
end
Réessayer avec mesure : des réessais bornés
Toute erreur n'est pas définitive. Une connexion réseau coupée vers le système de caméra ou un capteur qui rebondit brièvement revient souvent une seconde plus tard. Ces cas justifient un réessai, mais toujours avec une borne supérieure et un temps d'attente, sinon le programme martèle sans retenue en cas d'échec :
-- Réessai borné : 3 tentatives max., 1 s de pause
function avec_reessai(nom, tentatives, pause_ms, fn)
for tentative = 1, tentatives do
local ok, err = pcall(fn)
if ok then return true end
log_local("WARN", nom .. " tentative " .. tentative .. "/" .. tentatives
.. " échouée : " .. tostring(err))
Wait(pause_ms)
end
log_local("ERROR", nom .. " définitivement échoué après " .. tentatives .. " tentatives")
return false
end
-- Exemple : déclenchement caméra via TCP, tolère les coupures brèves
local ok = avec_reessai("Déclenchement caméra", 3, 1000, function()
local socket = TCPCreate(false, CAMERA_IP, CAMERA_PORT)
TCPStart(socket, 0)
TCPWrite(socket, "TRIGGER")
TCPDestroy(socket)
end)
Utiliser error() à bon escient : des objets d'erreur personnalisés
pcall n'intercepte pas seulement les erreurs d'exécution, mais aussi tout ce que vous levez vous-même avec error(). Cela rend les contrôles de plausibilité élégants : le contrôle lève, le gestionnaire central décide. Une table est admise comme valeur d'erreur ; l'erreur transporte alors une information structurée au lieu d'un simple texte :
-- Le contrôle lève un objet d'erreur structuré
function controle_piece()
if DI(CAPTEUR_PIECE) ~= ON then
error({ code = "PAS_DE_PIECE", text = "Aucune pièce en position" })
end
end
local ok, err = pcall(controle_piece)
if not ok then
if type(err) == "table" and err.code == "PAS_DE_PIECE" then
-- cas attendu : alimentation vide, attendre le réapprovisionnement
log_local("WARN", err.text)
attendre_reapprovisionnement()
else
-- tout le reste est une vraie erreur
log_local("ERROR", tostring(type(err) == "table" and err.text or err))
retour_position_initiale()
end
end
Rendre les erreurs visibles : journalisation centrale avec Leif
Les erreurs interceptées qui n'atterrissent que sur la console du robot, personne ne les voit. Seule la journalisation centrale transforme la gestion des erreurs en système d'alerte précoce : si les réessais s'accumulent sur un poste, un problème mécanique s'annonce bien avant l'arrêt réel de la cellule. L'article Journalisation avec Dobot Lua montre pas à pas comment étendre la fonction log_local de ces exemples pour envoyer les messages vers Leif. Dans Leif, vous voyez alors en direct tous les messages WARN et ERROR de vos robots, avec alertes vers Microsoft Teams, et la chronologie des incidents rejoue pour chaque message l'image caméra et la ligne de programme.
Liste de contrôle pour des programmes Dobot robustes
- Faire passer chaque commande de mouvement par un wrapper pcall, jamais à nu dans le cycle
- En cas d'erreur, amener d'abord préhenseur et pièce dans un état défini
- Des réessais toujours bornés avec temps d'attente, puis passage ordonné à l'état sûr
- Séparer les états attendus (alimentation vide, porte ouverte) des vraies erreurs avec des objets error()
- Journaliser chaque erreur interceptée, WARN pour les réessayables, ERROR pour les définitives
- Collecter les messages de façon centralisée pour repérer les accumulations avant l'arrêt de la cellule
Questions fréquentes
Que fait exactement pcall en Lua ?
pcall exécute une fonction en mode protégé. Si une erreur s'y produit, le programme ne s'interrompt pas ; pcall renvoie false et le message d'erreur. Sans erreur, il renvoie true ainsi que les valeurs de retour de la fonction.
Quand utiliser xpcall plutôt que pcall ?
xpcall accepte en plus votre propre gestionnaire d'erreur, qui s'exécute au moment même de l'erreur et peut par exemple capturer une trace d'appels avec debug.traceback. Pour la plupart des programmes robots, pcall suffit ; xpcall vaut la peine quand vous voulez savoir exactement où cela a cassé.
pcall ralentit-il le programme du robot ?
Le surcoût d'un appel pcall est négligeable face à un mouvement de robot de l'ordre de la milliseconde. Dans des boucles serrées sans mouvements, n'enveloppez pas chaque micro-opération individuellement ; enveloppez des blocs cohérents.