Migrating from Legacy Systems

Reconvertir un développeur LabVIEW à Python

Comment un développeur LabVIEW passe à Python en six semaines : carte des concepts, plan d'étude, code de plug et de phase, et les pièges à prévoir.

JJulien Buteau
intermediate11 min de lecture23 septembre 2026

Un développeur LabVIEW possède déjà la partie difficile du métier d'ingénieur de test Python : il connaît les instruments, les montages, les limites et l'allure d'un DUT marginal sur le banc. Seul le langage change, et c'est la plus petite des deux choses à apprendre. Six semaines d'étude à temps partiel avec le TofuPilot Framework transforment un VI de driver en plug, une machine d'états en fichier procedure.yaml et un dossier TDMS en tableau de bord.

Pourquoi ça marche

La partie rare d'un ingénieur de test, c'est la connaissance du domaine, pas la syntaxe. Votre développeur LabVIEW sait quel pogo pin se soulève sur le montage 3, pourquoi le rail 5 V lit haut pendant les 200 premières ms, et quelle requête SCPI l'ancien DMM renvoie avec un retour à la ligne en trop. Rien de cela n'est dans un examen de certification et tout cela se transfère.

Ce qui ne se transfère pas, c'est la couche propre à G : le séquenceur qu'il a construit, la face-avant, le fil d'erreur, les VI de rapport. Sur le TofuPilot Framework, ces quatre choses sont fournies. Le séquenceur est procedure.yaml, les limites sont des validateurs dans le même fichier, l'interface opérateur est déclarée et les résultats arrivent dans TofuPilot. Le développeur doit apprendre Python, et seulement Python.

Les six semaines ci-dessous supposent un développeur LabVIEW en activité, avec quelques heures par semaine et aucune expérience Python. Un CLD avec un diplôme d'informatique finira en trois.

Pour le manager, c'est l'option la moins chère sur la table. Le développeur garde son salaire et sa connaissance des montages, l'usine garde la personne qui sait pourquoi le poste 3 a besoin de 200 ms de stabilisation, et personne ne passe un trimestre à recruter dans un vivier qui penche vers les seniors et les profils chers. Le coût, c'est quelques heures par semaine pendant six semaines et un instrument de banc qu'il peut casser sans conséquence.

Carte des concepts

Chaque concept LabVIEW a un équivalent Python ou framework. La plupart sont plus simples.

LabVIEW / TestStandPython + TofuPilot FrameworkCe qui change
VIFonctionUn def avec des paramètres. Pas de face-avant, pas de panneau de connecteurs
SubVIModuleUn fichier .py que vous importez. La réutilisation, c'est import plugs.dmm
Face-avantInterface opérateur déclaréeChamps texte, checklists, images et barres de progression se déclarent dans procedure.yaml
Cluster d'erreurExceptionsraise au lieu de câbler. Le framework enregistre l'erreur et fait échouer la phase
Machine d'étatsSéquence de la procedureLa liste main: dans procedure.yaml, avec depends_on pour les branches parallèles
Cluster typedefDataclass ou dict@dataclass pour la structure, dict pour tout ce qui ressemble à du JSON
Fichier TDMSRun TofuPilotLes mesures remontent. FPY, Cpk et histogrammes sont déjà des graphiques
DAQmxnidaqmxMême driver, binding Python
VI de driver NI-VISAPlug PyVISAUne classe avec __init__, des méthodes et close()
Séquence TestStandprocedure.yamlLes étapes deviennent des phases, les limites des validateurs
Projet (.lvproj)Dépôt GitFichiers texte, comparables, relisibles

Le guide de migration LabVIEW détaille les neuf premières lignes. Si l'usine fait tourner TestStand par-dessus, le guide de migration TestStand couvre le fichier de séquence et les callbacks.

Deux habitudes LabVIEW n'ont pas de ligne parce qu'elles n'ont pas d'équivalent. L'exécution en surbrillance et les sondes deviennent des appels log.info() et un terminal, ce qui ressemble à une perte pendant une semaine, puis plus du tout. La flèche d'exécution devient une commande. Les deux sont couvertes dans la table des pièges plus bas.

Un parcours d'auto-formation en six semaines

Deux à quatre heures par semaine, sur un vrai instrument du banc, pas un tutoriel. Chaque exercice produit un fichier que le développeur garde, et dès la semaine 3 ces fichiers sont le début d'un vrai poste.

SemaineObjectifExerciceTerminé quand
1Les bases de Python sur le bancInstaller Python, pip install pyvisa pyvisa-py, envoyer *IDN? au DMM du banc depuis un scriptLe DMM répond depuis un fichier .py
2Un plug à la place d'un VI de driverEnvelopper le DMM dans une classe avec read_voltage() et close()La classe remplace un VI de driver sur un poste
3Une phase avec des limitesÉcrire procedure.yaml avec une phase et deux validateurs, l'exécuter avec tofupilot runLe pass et le fail s'affichent tous deux correctement dans le terminal
4Séquence et interface opérateurAjouter trois phases, depends_on et une checklist pour l'opérateurLa séquence correspond à l'ancienne machine d'états étape par étape
5Un vrai templateCloner un template TofuPilot, l'exécuter avec des plugs mock, remplacer un plug par l'instrument du bancLe template tourne sur du vrai matériel
6Remonter et lire les résultatstofupilot login, tofupilot link, exécuter avec --upload, lire le Cpk dans le tableau de bordLe Cpk d'une mesure est visible sans tableur

Chaque ligne s'appuie sur la précédente. Dès la semaine 4, le développeur a un dossier de poste qu'il pourrait confier à n'importe qui dans l'équipe.

Associez-le à la personne qui écrit du Python dans l'équipe, même un ingénieur firmware, trente minutes par semaine. Les questions des semaines 1 et 2 portent sur le langage et prennent une minute à résoudre en personne et une heure seul. À partir de la semaine 3, les questions portent sur le framework, et la documentation Python plus tofupilot run en couvrent la plupart.

Semaines 1 à 2 : un plug à la place d'un VI de driver

Un VI de driver LabVIEW, c'est une face-avant, un fil de session VISA et un cluster d'erreur. En Python, c'est une classe. Le framework appelle __init__ au setup, injecte l'instance dans toute phase qui la nomme et appelle close() au teardown. La documentation PyVISA couvre le resource manager et le backend @py.

plugs/dmm.py
# Remplace "DMM Read Voltage.vi" : une session VISA, un canal de mux, une requête, une fermetureimport pyvisaclass Multimeter:    def __init__(self, address="TCPIP::192.168.1.100::INSTR"):        rm = pyvisa.ResourceManager("@py")        self.inst = rm.open_resource(address)        self.inst.timeout = 5000        self.inst.write("*RST")    def read_voltage(self, channel):        self.inst.write(f"ROUT:CLOS (@{channel})")        return float(self.inst.query(":MEAS:VOLT:DC?"))    def close(self):        self.inst.close()

L'adresse vient de procedure.yaml via config, donc le même plug sert trois postes avec trois DMM. C'est la réutilisation de SubVI qu'un développeur LabVIEW attend déjà, sans le panneau de connecteurs. Le float() est la leçon de la semaine 2 : tout ce que VISA renvoie est une chaîne, et la conversion a sa place dans le plug.

Semaines 3 à 4 : une phase et ses limites

En LabVIEW, la limite vit dans un nœud de comparaison à côté de la mesure, ou dans une table de limites que la face-avant charge. Dans le framework, elle vit dans procedure.yaml, et la phase ne fait qu'assigner la valeur.

procedure.yaml
34 lines
# Deux rails avec limites ; l'adresse du plug est de la config, pas du codename: Controller Board FCTversion: 1.0.0unit:  serial_number:    default_value: "SN-0001"  part_number:    default_value: "CTRL-100"plugs:  - name: dmm    python: plugs.dmm:Multimeter    config:      address: "TCPIP::192.168.1.100::INSTR"main:  - name: Power Rails    python: phases.power_rails    measurements:      - name: rail_3v3        unit: V        validators:          - operator: ">="            expected_value: 3.2          - operator: "<="            expected_value: 3.4      - name: rail_5v        unit: V        validators:          - operator: ">="            expected_value: 4.8          - operator: "<="            expected_value: 5.2
phases/power_rails.py
# Pas de nœud de comparaison : les validateurs de procedure.yaml décident du pass ou du faildef power_rails(measurements, dmm, log):    rail_3v3 = dmm.read_voltage(101)    rail_5v = dmm.read_voltage(102)    log.info(f"3V3 {rail_3v3:.3f} V, 5V {rail_5v:.3f} V")    measurements.rail_3v3 = rail_3v3    measurements.rail_5v = rail_5v

Exécutez-le avec tofupilot run ./procedure.yaml. Puis resserrez un validateur jusqu'à ce qu'il échoue et relancez. Voir les deux résultats dans le terminal est le test de sortie de la semaine 3.

La semaine 4 ajoute le reste de l'ancienne machine d'états. Les branches parallèles après la mise sous tension, c'est depends_on, et la checklist de la face-avant devient un composant déclaré sans code derrière.

procedure.yaml
23 lines
# Semaine 4 : branches parallèles après la mise sous tension, plus une checklist opérateur sans Python derrièremain:  - name: Power Rails    key: power_rails    python: phases.power_rails  - name: Firmware Handshake    key: firmware    python: phases.firmware    depends_on: [power_rails]  - name: Visual Check    key: visual    depends_on: [power_rails]    ui:      components:        - key: visual_checks          type: checklist          label: "Visual inspection"          required: true          options:            - label: "Status LED lit"              value: "led"            - label: "No solder bridges on J3"              value: "bridges"

Semaines 5 à 6 : exécuter un template, remonter, lire le Cpk

La semaine 5 part d'un poste qui fonctionne plutôt que d'un fichier vide. Le template de calibration thermique IMU convient bien à un ingénieur calibration ; le template de montage FCT à une ligne PCBA.

week5.sh
# Un poste complet avec des instruments mock, qui tourne en quelques minutescurl -fsSL https://www.tofupilot.app/install | shgit clone https://github.com/tofupilot/template-framework-imu-thermal-calibrationcd template-framework-imu-thermal-calibrationtofupilot run ./procedure.yaml

Lisez procedure.yaml de haut en bas, puis remplacez un plug mock par la classe de la semaine 2. Les phases ne changent pas. C'est le moment où la plupart des développeurs LabVIEW cessent de s'inquiéter du langage.

La semaine 6 connecte le poste au tableau de bord et fait passer vingt unités.

week6.sh
# Lier le dossier à une procedure du tableau de bord, puis remonter chaque runtofupilot logintofupilot linktofupilot run ./procedure.yaml --upload

Ouvrez la procedure dans TofuPilot et trouvez le Cpk et l'histogramme d'une mesure. Ne calculez pas le Cpk en Python. Le tableau de bord le fait déjà, et c'est le but de la semaine 6 : le développeur regarde ses mesures devenir les chiffres de rendement de l'usine sans écrire un VI de rapport.

Le test de sortie de la semaine 6 est une passation. Donnez le dossier du poste à un collègue qui ne l'a jamais vu, et faites-lui passer vingt unités avec --upload en utilisant seulement le README. S'il y arrive, le développeur a appris la partie de Python qui compte pour un poste de test, et le poste a cessé d'être un point de défaillance unique. Sinon, l'écart est généralement une dépendance manquante dans pyproject.toml ou une adresse d'instrument codée en dur dans un plug au lieu de config.

Pièges courants

PiègeCe que le développeur voitSolution
IndentationIndentationError sur une ligne qui a l'air correcteDes espaces seulement, quatre par niveau. Réglez l'éditeur pour afficher les espaces
Exceptions contre fil d'erreurUn appel de plug qui échoue arrête la phase avec une tracebackC'est le fil d'erreur. Attrapez avec try et except seulement là où vous auriez traité le cluster, sinon laissez propager
Pas de flèche d'exécution« Comment je lance ça ? »tofupilot run ./procedure.yaml pour le poste, python -c pour un plug seul
Environnements virtuelsModuleNotFoundError: pyvisa juste après l'avoir installéLe framework construit un venv depuis pyproject.toml. Ajoutez la dépendance là, pas avec un pip install global
Parallélisme impliciteS'attend à ce que deux nœuds non câblés s'exécutent en même tempsPython s'exécute de haut en bas. Utilisez depends_on dans procedure.yaml pour les branches parallèles
Tout est une chaîneTypeError en comparant une réponse VISA à une limiteConvertissez avec float() à la frontière du plug, jamais dans la phase
Références mutablesUne liste passée à une fonction change à l'extérieurPython passe des références. Copiez avec list(x) là où vous auriez dérivé un fil

Le piège qui n'est pas dans la table, c'est la lecture. Un développeur LabVIEW a l'habitude de voir toute la séquence comme un diagramme, et un dossier de fichiers .py ressemble d'abord à moins d'information. C'est la même information sous une autre forme, et elle vient avec quelque chose que le diagramme n'a jamais eu : un diff. Après un mois de git log sur son propre poste, la plupart des développeurs cessent de demander l'image.

La liste complète de ce qu'un ingénieur de test Python devrait savoir faire est dans la Checklist des compétences Python pour ingénieurs de test. Utilisez-la comme entretien de sortie de la semaine 6.

Commencez par un poste

Choisissez le poste au plus fort volume, ou celui qu'une seule personne sait ouvrir. Reconstruisez-le en Python avec le TofuPilot Framework et faites-le tourner en parallèle de la version LabVIEW sur les mêmes unités pendant deux semaines. Comparez les deux jeux de résultats dans TofuPilot avant de retirer quoi que ce soit.

install-and-run.sh
curl -fsSL https://www.tofupilot.app/install | shtofupilot run ./procedure.yaml

Le pas à pas est dans Migrer de LabVIEW vers Python, et le framework est sur https://tofupilot.com/products/framework. L'offre Lab est gratuite, et tofupilot run fonctionne sans compte.

Plus de guides

Mettez ce guide en pratique