Automatiser Robot Structural Analysis avec Python et l'IA
Retour d'expérience : du plan de coffrage au modèle Robot calculé puis aux plans de ferraillage DXF, avec un script Python écrit par l'IA. Méthode, code de l'API, pièges et vérifications.
- Catégorie
- STRIA & Structures
- Publié
- Lecture
- 12 min
- Langue
- FR

Sommaire
Saisir un modèle dans Robot Structural Analysis, nœud par nœud et barre par barre, puis dessiner le ferraillage de chaque poteau et de chaque poutre : sur une villa, cela représente des journées de travail répétitif. Robot dispose pourtant d’une interface de programmation (API) qui permet de piloter tout le logiciel depuis Python.
Je ne suis pas programmeur. J’ai donc demandé à Claude d’écrire le script à ma place, puis je l’ai testé sur deux projets réels de bâtiments en béton armé. Cet article décrit la méthode, le code qui fonctionne réellement, et surtout ce qui ne fonctionne pas.
À retenir avant de commencer : ce script prépare un modèle et des plans à vérifier. Le choix du système porteur, les hypothèses et la validation des résultats restent le travail de l’ingénieur. Aucun résultat ne doit être signé sans les contrôles décrits plus bas.
Le principe : l’IA écrit, l’ingénieur exécute et valide
L’IA ne pilote pas Robot directement. La répartition des rôles est simple :
- Claude lit les plans, écrit le script Python et analyse les résultats exportés.
- J’exécute le script sur mon ordinateur, où Robot est installé.
- Le script construit le modèle, lance le calcul et exporte les efforts dans des fichiers CSV.
- Claude lit ces CSV, et le script produit les plans de ferraillage en DXF.
- Je vérifie chaque étape avant de passer à la suivante.
L’environnement utilisé :
| Élément | Version |
|---|---|
| Logiciel de calcul | Autodesk Robot Structural Analysis Professional 2014, en français |
| Langage | Python 3.13, éditeur IDLE |
| Connexion à Robot | bibliothèque pywin32 (pip install pywin32) |
| Lecture des plans DXF | AutoCAD |
Les commandes de l’API citées dans cet article proviennent d’un script utilisé sur Robot 2014 pour deux projets réels. Les extraits de code, eux, sont simplifiés pour la lecture et n’ont pas été exécutés tels quels. L’API COM existe toujours dans les versions récentes de Robot, mais certains comportements peuvent différer.
Le flux de travail en 7 étapes
- Entrées : plan de coffrage et plan d’architecture (DXF ou PDF) : axes, poteaux, poutres, niveaux.
- Lecture des plans et validation par l’ingénieur : axes, sections, planchers, charges, données de sol et de site.
- Saisie des données du projet dans le script : coordonnées des axes, liste des poteaux et des poutres, type de plancher.
- Modélisation et calcul dans Robot : nœuds, barres, appuis, charges, séisme, combinaisons.
- Contrôle d’équilibre : si l’écart entre les charges calculées et les réactions dépasse le seuil, retour à l’étape 3 pour corriger les entrées.
- Ferraillage, planchers et fondations, à partir des efforts exportés. Si un poteau n’a pas de solution raisonnable, on agrandit sa section et on relance tout le calcul.
- Revue des résultats avant signature : fichiers CSV, plans DXF ouverts dans AutoCAD, journal de calcul.
Point important : aucun ferraillage n’est calculé tant que le modèle n’est pas équilibré. C’est la règle qui évite de dessiner des plans à partir d’un modèle faux.
Un seul script, des sections bien séparées
Sur le premier projet, le travail s’est fait en plusieurs scripts, au fil de l’apprentissage. Sur le second, tout tient dans un seul fichier d’environ 880 lignes, qui s’exécute en une cinquantaine de secondes.
Ce fichier est organisé de façon à ce qu’un nouveau projet ne demande de modifier que les trois premières sections :
| Section | Contenu | À modifier ? |
|---|---|---|
| 1. Projet | Nom du projet, modèle vide de départ, étapes à exécuter | Oui |
| 2. Géométrie | Axes, poteaux, sections, niveaux, liste des poutres | Oui, d’après le coffrage |
| 3. Charges, séisme, sol | Finitions, planchers, acrotères, paramètres sismiques, contrainte du sol | Oui |
| 4 à 10 | Calcul des planchers, pilotage de Robot, ferraillage, fondations, dessin DXF | Non |
Cette séparation est ce qui rend le gain de temps réel : la partie « moteur » ne se réécrit pas à chaque projet.
Se connecter à Robot depuis Python
Voici les commandes de base de l’API. Un détail à retenir dès maintenant : l’API travaille toujours en newtons et en mètres, quelles que soient les unités affichées dans Robot.
Les commandes de l’API sont extraites, telles quelles, d’un script utilisé sur Robot 2014 pour deux projets réels. Les extraits qui les entourent sont simplifiés pour la lecture et n’ont pas été exécutés tels quels : ils se suivent, et les données de l’exemple (quatre poteaux, quatre poutres) sont à remplacer par celles de votre projet. Avant de les utiliser sur un projet, essayez-les sur un petit modèle (un seul poteau) et comparez les réactions d’appui avec un calcul à la main.
Connexion, ouverture et sauvegarde
import osimport win32com.clientfrom win32com.client import constants as C
DOSSIER = os.path.dirname(os.path.abspath(__file__))PROJET = "mon_projet"MODELE_VIDE = "MODEL.VIDE.rtd" # modèle vide préparé à la main : sections, matériaux, unités d'affichage
robot = win32com.client.gencache.EnsureDispatch("Robot.Application")robot.Visible = 1projet = robot.Project
# Ouvrir le modèle vide, puis l'enregistrer sous le nom du projetchemin = os.path.join(DOSSIER, MODELE_VIDE)projet.Open(chemin)projet.SaveAs(os.path.join(DOSSIER, PROJET + ".rtd"))st = projet.StructureNœuds, barres et sections
# Données d'exemple, même structure que la section 2 du script (m)AXES_X = {"A": 0.00, "B": 5.65}AXES_Y = {1: 0.00, 2: 3.90}POTEAUX = {"P1": ("A", 1), "P2": ("B", 1), "P3": ("A", 2), "P4": ("B", 2)}SECTION_POTEAU = {"defaut": "C30x30"}Z_ENCAST = -0.45H = 3.80POUTRES = [("A1", "P1", "P2", "B25x40", H), ("A2", "P3", "P4", "B25x40", H), ("A3", "P1", "P3", "B25x40", H), ("A4", "P2", "P4", "B25x40", H)]
# Géométrie dérivée (copiée du script)YMAX = max(AXES_Y.values())XY = {p: (AXES_X[a], YMAX - AXES_Y[r]) for p, (a, r) in POTEAUX.items()}POUTRE = {n: dict(nom=n, a=a, b=b, sec=s, z=z) for n, a, b, s, z in POUTRES}
def niveaux_poteau(p): zs = sorted({q["z"] for q in POUTRE.values() if p in (q["a"], q["b"])}) return zs or [H]
def sec_poteau(p): return SECTION_POTEAU.get(p, SECTION_POTEAU["defaut"])
# Nodes.Create(numéro, x, y, z) en m ; Bars.Create(numéro, nœud début, nœud fin)nid, n = {}, 0for p in POTEAUX: for z in [Z_ENCAST] + niveaux_poteau(p): n += 1; st.Nodes.Create(n, XY[p][0], XY[p][1], z); nid[(p, z)] = nbarres_pot, barres_pou, b = {}, {}, 0for p in POTEAUX: zs = [Z_ENCAST] + niveaux_poteau(p) for z0, z1 in zip(zs[:-1], zs[1:]): b += 1; st.Bars.Create(b, nid[(p, z0)], nid[(p, z1)]); barres_pot[b] = (p, z0, z1)for q in POUTRE.values(): b += 1; st.Bars.Create(b, nid[(q["a"], q["z"])], nid[(q["b"], q["z"])]); barres_pou[b] = q["nom"]
# Les sections doivent déjà exister dans le modèle vide (voir les pièges)for bb, (p, z0, z1) in barres_pot.items(): st.Bars.Get(bb).SetLabel(C.I_LT_BAR_SECTION, sec_poteau(p))for bb, nom in barres_pou.items(): st.Bars.Get(bb).SetLabel(C.I_LT_BAR_SECTION, POUTRE[nom]["sec"])Appuis encastrés
lab = st.Labels.Create(C.I_LT_SUPPORT, "ENCAST")d = lab.Data; d.UX = 1; d.UY = 1; d.UZ = 1; d.RX = 1; d.RY = 1; d.RZ = 1st.Labels.Store(lab)for p in POTEAUX: st.Nodes.Get(nid[(p, Z_ENCAST)]).SetLabel(C.I_LT_SUPPORT, "ENCAST")Cas de charge et combinaisons
COMBI_ELU, COMBI_ELS = 3, 4
# Cas permanent avec poids propre ; cas d'exploitation : la constante s'écrit bien « EXPLOATATION »cases = st.CasesG = cases.CreateSimple(1, "G", C.I_CN_PERMANENT, C.I_CAT_STATIC_LINEAR)Q = cases.CreateSimple(2, "Q", C.I_CN_EXPLOATATION, C.I_CAT_STATIC_LINEAR)r = G.Records.Get(G.Records.New(C.I_LRT_DEAD))r.SetValue(C.I_DRV_Z, -1); r.SetValue(C.I_DRV_ENTIRE_STRUCTURE, True)
# Charge répartie sur une poutre : valeur en kN/m, convertie en N/mdef uni(cas, bb, kN): if abs(kN) < 1e-6: return rr = cas.Records.Get(cas.Records.New(C.I_LRT_BAR_UNIFORM)) rr.SetValue(C.I_BURV_PZ, -1000.0 * kN); rr.Objects.FromText(str(bb))
# Exemple : 12 kN/m permanents sur chaque poutre (le script calcule ces charges à partir des planchers)for bb, nom in barres_pou.items(): uni(G, bb, 12.0) # 12 kN/m : uni() multiplie par 1000, l'API reçoit -12000 N/m
# Combinaisons ELU et ELScat = getattr(C, "I_CAT_COMB", None)if cat is None: cat = C.I_CAT_COMB_LINEARelu = cases.CreateCombination(COMBI_ELU, "ELU", C.I_CBT_ULS, C.I_CN_PERMANENT, cat)elu.CaseFactors.New(1, 1.35); elu.CaseFactors.New(2, 1.5)els = cases.CreateCombination(COMBI_ELS, "ELS", C.I_CBT_SLS, C.I_CN_PERMANENT, cat)els.CaseFactors.New(1, 1.0); els.CaseFactors.New(2, 1.0)Calcul et lecture des résultats
projet.CalcEngine.Calculate()res = st.Resultscombis = [COMBI_ELU, COMBI_ELS]
# Efforts : barre, combinaison, position sur la barre (0 à 1) ; l'API donne des N et N·mfor bb, nom in barres_pou.items(): for c in combis: for pos in (0.0, 0.25, 0.5, 0.75, 1.0): F = res.Bars.Forces.Value(bb, c, pos) print(nom, c, pos, round(F.FZ / 1000, 2), round(F.MY / 1000, 2)) # kN, kN·m
# Réactions : nœud, cas ; l'API donne des Nfor p in POTEAUX: for c in combis: R = res.Nodes.Reactions.Value(nid[(p, Z_ENCAST)], c) print(p, c, round(R.FZ / 1000, 2)) # kNCe qui ne fonctionne pas (dans Robot 2014)
C’est la partie qu’on ne trouve presque nulle part. Plusieurs fonctions de l’API semblent marcher, mais donnent un modèle inutilisable :
- Créer une section béton par le code : le nom de la section est bien créé, mais le calcul renvoie « Section non définie ». Solution : créer toutes les sections à la main dans le modèle vide, une fois pour toutes.
Labels.Exist: renvoie « absent » même pour une section qui existe. À ne pas utiliser.- Les bardages par le code : le contour est créé, mais sans la propriété de bardage, et la charge surfacique n’arrive pas aux poutres. Le bardage créé à la main fonctionne. Dans le script, les charges de plancher sont donc calculées en Python puis appliquées directement sur les poutres.
- Le module de ferraillage réel : il n’est pas automatisable. C’est pour cette raison que le ferraillage est calculé par le script lui-même, à partir des efforts exportés de Robot.
Les pièges qui font perdre le plus de temps
Avec le recul, la majorité du temps perdu ne venait pas du calcul, mais de ces détails :
| Symptôme | Cause | Solution |
|---|---|---|
| Le résultat est identique à l’ancienne version du script | La fenêtre du script était restée ouverte dans IDLE et a réécrit l’ancien code par-dessus le nouveau | Fermer la fenêtre sans enregistrer, la rouvrir, et vérifier une ligne caractéristique de la nouvelle version |
PermissionError | Un fichier CSV ou DXF est ouvert dans Excel ou AutoCAD | Fermer les fichiers avant de lancer le script |
| « Section non définie pour la barre n° … » | Section absente du modèle vide, ou nom différent (une espace de trop) | Ajouter la section à la main dans le modèle vide |
| « Le projet ouvert n’est pas vide » | Le modèle vide a été enregistré avec un modèle dedans | Recréer le modèle vide, et répondre « Non » quand Robot propose de l’enregistrer |
| Tous les résultats valent zéro | Le calcul a échoué sans que Robot le signale à Python | Ouvrir la fenêtre des messages de calcul dans Robot |
| Une valeur de 20 MPa pour le sol | Confusion d’unités : 2 bar = 0,20 MPa | Toute contrainte de sol de l’ordre de dizaines de MPa est une erreur |
Le dernier exemple est une erreur que j’ai faite moi-même, deux fois. L’IA l’a repérée parce que je lui avais demandé de signaler toute valeur incohérente.
Les vérifications obligatoires
Le script imprime la plupart de ces contrôles automatiquement. Aucun résultat n’est utilisé avant qu’ils soient tous passés :
- Équilibre vertical : sous G, le script compare la somme des réactions dans Robot à la charge calculée en Python. Si l’écart dépasse 5 %, il s’arrête avant le ferraillage. Sous Q, les deux valeurs sont seulement imprimées : la comparaison se fait à l’œil.
- Effort tranchant sismique à la base : la somme des réactions horizontales doit égaler l’effort sismique calculé, dans les quatre directions.
- Déplacements : les déplacements entre étages doivent respecter les limites du règlement parasismique.
- Contrôle manuel d’au moins un élément : par exemple, le moment en travée d’une poutre recalculé à la main.
- Cohérence entre le modèle et les plans : si un poteau a été agrandi pour le ferraillage, il doit l’être aussi dans le modèle, puis le calcul est relancé, car la rigidité modifie la répartition des efforts sismiques.
- Lecture de toutes les alertes du script : poteaux sans solution raisonnable, portées de plancher excessives, flèches importantes.
Un modèle équilibré n’est pas forcément un modèle juste
Les deux premiers contrôles ont une limite qu’il faut connaître : ils comparent Python et Robot, qui travaillent à partir de la même géométrie. Si un poteau a été placé sur le mauvais axe, ou si une portée a été mal recopiée depuis le plan, le modèle reste parfaitement équilibré, et pourtant faux.
Le vrai risque de ce flux de travail est donc la saisie des données, pas le calcul. Deux contrôles indépendants le couvrent :
- La superposition géométrique : exporter la géométrie du modèle (axes, poteaux, poutres avec leurs noms) en DXF, puis la superposer au plan de coffrage d’origine dans AutoCAD. Un écart se voit en quelques secondes.
- Une descente de charges manuelle sur un poteau, comparée à l’effort normal donné par Robot.
La méthode sismique a des conditions d’application
Le script applique la méthode statique équivalente du règlement parasismique. Cette méthode n’est valable que si le bâtiment respecte les conditions de régularité, en plan et en élévation. Un bâtiment avec des niveaux décalés, par exemple, demande une vérification explicite avant de l’utiliser. Sinon, une analyse modale spectrale est nécessaire. C’est une décision d’ingénieur, à prendre et à noter pour chaque projet.
Enfin, les plans DXF produits sont des brouillons d’ingénieur : je les reprends dans AutoCAD avant toute diffusion.
Une règle de chantier dans le code
Sur les chantiers où je travaille, on dépasse rarement le diamètre HA14 pour les poutres et les poteaux. J’ai donc imposé deux règles au script : pas de surferraillage, et pas de diamètre supérieur à HA14. Si un élément ne passe pas avec cette limite, le script ne baisse jamais les aciers sous le minimum requis : il le signale et propose une solution, comme une section plus grande ou deux lits d’armatures.
C’est un bon exemple de ce que l’ingénieur apporte : l’IA applique le règlement, mais elle ne connaît pas les pratiques du terrain si on ne les lui dit pas.
Le bilan
- Le gain de temps : le détail de ferraillage, qui me prenait une journée complète, me prend aujourd’hui environ deux heures, vérifications comprises.
- Ce qui reste manuel : la création des sections dans le modèle vide, les bardages, le module de ferraillage réel, et la mise en page finale des plans.
- Ce qui ne change pas : la responsabilité. Le script accélère la production, mais chaque hypothèse et chaque résultat restent validés par l’ingénieur.
Pour aller plus loin
Plusieurs améliorations restent à faire : l’export automatique de la géométrie pour la superposition avec le coffrage, le diaphragme rigide à chaque niveau, l’analyse modale spectrale directement dans Robot, les appuis élastiques, les escaliers et voiles, et les bâtiments à plusieurs étages. Je reviendrai sur ces points dans de prochains articles.
Si vous voulez essayer, commencez petit : un portique d’un seul niveau, un appui, une charge, et comparez les réactions avec un calcul à la main. C’est la meilleure façon de comprendre l’API avant de lui confier un vrai projet.
Article rédigé avec l’aide d’outils d’IA, puis relu et vérifié.