Que fait CAO pour Matériel de Laboratoire ?
Concevoir du matériel de recherche physique en tant que source Python paramétrique, exporter le STEP comme l'artefact de référence, et vérifier le résultat à la fois numériquement et visuellement avant toute fabrication.
La partie difficile du matériel de laboratoire n'est presque jamais la géométrie. C'est que la pièce doit s'adapter à un équipement dont les dimensions sont fixées par une norme publiée ou un dessin de fournisseur. Un support trop large de 0,5 mm ne tient pas dans le lecteur de plaques ; un canal avec un rapport d'aspect incorrect s'effondre lors du collage ; un support dont le motif de boulons est de 25,4 mm au lieu de 25,0 mm n'atteindra pas la table optique. Cette compétence existe pour que ces chiffres soient corrects et vérifiés.
Quand l'utiliser
À utiliser pour toute demande de conception, modélisation ou fabrication d'une pièce physique pour un laboratoire : puce, moule, montage, adaptateur, support, étagère, support, boîtier, gabarit, fixation, arène ou labyrinthe. Utilisez-la également pour inspecter ou modifier un fichier STEP existant.
N'utilisez pas pour l'analyse par éléments finis, la dynamique des fluides numérique, la structure moléculaire ou le traçage scientifique. Ce sont des compétences différentes.
Installation
uv venv --python 3.12 .venv-labcad
uv pip install --python .venv-labcad/bin/python "build123d==0.11.1" "matplotlib>=3.8"
build123d 0.11.1 nécessite Python >=3.10,<3.15 et importe le noyau OpenCascade via cadquery-ocp-novtk. La roue est volumineuse ; installez-la une fois par projet et réutilisez-la.
Tous les scripts fournis prennent --help. check.py standards s'exécute sans build123d installé.
Les fichiers de modèle sont exécutés, non analysés. gen.py, check.py et snapshot.py importent un *_model.py et appellent sa fonction build(), qui exécute du Python arbitraire dans l'environnement actuel. C'est inhérent à la CAO paramétrique — le code source est la conception. N'exécutez que les fichiers de modèle créés dans cette session ou fournis par l'utilisateur depuis un emplacement de confiance. Si un modèle provient d'Internet, d'un lecteur partagé ou d'un collègue non fiable, lisez-le avant de l'exécuter et dites que vous l'avez fait.
Workflow requis
Suivez ces étapes dans l'ordre. Les étapes 5 et 6 ne sont pas facultatives, et l'étape 6 n'est pas annulée par la réussite de l'étape 5.
1. Acheminer vers une famille de dispositifs
Lisez la demande, classez-la et chargez exactement une référence de famille. Ne chargez pas les quatre — elles sont longues, et mélanger les conventions entre les familles est une source fréquente d'erreur.
| Si la pièce est | Charger |
|---|---|
| Une puce, un moule, un réseau de canaux, une cellule de flux, un joint, ou tout ce qui a des ports fluidiques | references/microfluidics.md |
| Un montage, un poteau, un adaptateur de table à montage, une pièce de système à cage, un porte-filtre ou un porte-échantillon dans un chemin de faisceau | references/optomechanics.md |
| Un adaptateur, un insert, un rack ou un support pour plaques, cuves, tubes, lames ou boîtes | references/labware-adapters.md |
| Une arène, un labyrinthe, une pièce de fixation de tête, un bec, un lien ou un boîtier monté par extrusion pour le travail sur animaux | references/behavior-rigs.md |
Si la pièce couvre véritablement deux familles — une puce microfluidique qui se boulonne sur une table optique — chargez la famille qui possède l'interface critique, puis lisez uniquement la section d'interface de la seconde. Indiquez dans votre réponse à quelle famille vous avez acheminé.
2. Établir les dimensions d'interface avant toute géométrie
Chaque pièce a au moins une interface d'accouplement. Avant d'écrire du code, notez pour chaque interface :
- la source de la dimension : une norme publiée, un dessin de fournisseur ou une mesure de l'utilisateur ;
- la valeur nominale et la tolérance ;
- le jeu ou l'interférence que vous prévoyez, et pourquoi.
Recherchez le nombre dans assets/standards.json ou la référence de famille. N'écrivez jamais une dimension d'interface de mémoire. Si le nombre ne se trouve pas dans le fichier de normes ou la référence, demandez à l'utilisateur le dessin du fournisseur ou la mesure plutôt que de deviner. Une dimension d'interface devinée est le mode de défaillance le plus coûteux de cette compétence.
Une fonctionnalité qui doit recevoir un composant normalisé est dimensionnée par rapport à la condition de matière maximale de ce composant — nominal plus sa tolérance positive — et seulement ensuite on ajoute un jeu. Dimensionnée à partir du nominal, elle ne convient qu'à la moitié la plus petite des pièces conformes.
python scripts/check.py standards --list
python scripts/check.py standards --show slas-microplate-footprint
Les identifiants de normes fournis (chaînes exactes ; ne devinez pas de variantes) : slas-microplate-footprint, slas-microplate-height, slas-microplate-flange, slas-well-positions-96, slas-well-positions-384, slas-well-positions-1536, cuvette-standard-10mm, optical-breadboard-metric, optical-breadboard-imperial, cage-system-30mm, sm1-lens-tube-thread.
Si la pièce ne s'accouple avec rien dans cette liste, c'est courant et acceptable : déclarez sans interfaces, et nommez chaque dimension d'interface avec sa source (spécification utilisateur, dessin de fournisseur, mesure) comme non vérifiée dans le rapport. Ne déclarez jamais contre une norme non liée pour combler le vide — une déclaration fabriquée est pire qu'un honnête "personne n'a vérifié ça".
3. Choisir le procédé avant de choisir la géométrie
Lisez references/fabrication-limits.md. Le procédé détermine l'épaisseur minimale des parois, la taille minimale des détails, la tolérance réalisable et si la pièce survit à l'autoclave ou au contact avec votre solvant. Le FDM ne peut pas maintenir ±0,05 mm ; la résine SLA n'est généralement pas sûre pour le contact cellulaire sans post-traitement et tests. Enregistrez le procédé et le matériau dans la docstring du modèle.
4. Créer un modèle paramétrique
Écrivez <part>_model.py. Le code source est l'artefact de référence — ne modifiez jamais manuellement un fichier STEP exporté, et ne régénérez jamais à partir d'un maillage.
Exigences :
- Chaque dimension qu'un utilisateur pourrait modifier est une constante nommée au niveau du module avec les unités dans le nom :
bore_d_mm,wall_t_mm,post_h_mm. Pas de nombres nus dans le corps sauf 0, 1 et 2. - Exposez
build() -> Part.gen.pyl'appelle. - Regroupez les paramètres en un bloc
INTERFACE(dimensions fixées par une norme, annotées avec l'identifiant de la norme) et un blocDESIGN(dimensions que vous êtes libre de choisir). - Dérivez chaque dimension calculée à l'intérieur d'une fonction, jamais au niveau du module, afin que les surcharges
--paraml'atteignent réellement. - Déclarez une fonction
interfaces()retournant les dimensions que la pièce doit ajuster, chacune avec son identifiant de norme et son intention. C'est ce qui rend l'interface vérifiable par machine à l'étape 5.intentest"envelope"lorsque la fonctionnalité doit accepter toute pièce conforme (une poche, un alésage ou une fente — vérifiée unilatéralement à la condition de matière maximale plus votre jeu) et"match"lorsque cette pièce doit elle-même être conforme (bande symétrique).clearanceest le jeu total prévu en mm et doit être non négatif. Ne déclarez que les dimensions qui contraignent les fonctions d'accouplement de cette pièce — une propriété de l'équipement d'accouplement (le bord d'une table, une épaisseur typique de plaque) n'est pas une de vos interfaces. Si aucune norme fournie ne s'applique, retournez[]. - Déclarez une fonction
checks()de jauges passe/ne passe pas mesurées à partir du solide construit : une régionclearpour tout ce qui doit passer à travers ou s'insérer (tiges de vis, corridors de faisceau, la pièce d'accouplement à la condition de matière maximale tombant dans sa poche), une régionmaterialpour tout ce qui doit rester (une arête, un rebord, un siège de vis), et une limitebbox_*pour chaque limite de taille que l'utilisateur a énoncée. Associez chaque exigence géométrique de la demande à une entrée ; celles-ci détectent les erreurs queis_valid, la boîte englobante et les nombres déclarés ne peuvent pas voir.gen.pyles exécute à chaque génération et échoue la construction si l'une d'elles échoue. Schéma et exemples pratiques :references/build123d-patterns.md. - Mettez le procédé, le matériau et chaque source d'interface dans la docstring du module.
"""Support de microplaque SLAS pour un insert de scène personnalisé.
Procédé : FDM, PETG, 0,2 mm de couche. Budget de tolérance +/-0,3 mm.
Interfaces :
- Poche pour plaque : ANSI/SLAS 1-2004 (R2012) empreinte 127,76 x 85,48 mm, +/-0,25 mm.
- Boulons de scène : mesurés par l'utilisateur, 40,0 mm d'entraxe (dessin dans docs/stage.pdf).
"""
from build123d import *
# --- INTERFACE (fixé par norme ; ne pas ajuster) ---
plate_l_mm = 127.76 # ANSI/SLAS 1-2004 nominal
plate_w_mm = 85.48 # ANSI/SLAS 1-2004 nominal
plate_tol_mm = 0.25 # ANSI/SLAS 1-2004 ; la poche est dimensionnée au nominal + cela
# --- DESIGN (libre) ---
pocket_clearance_mm = 0.40 # par côté ; FDM, voir fabrication-limits.md
wall_t_mm = 3.0
floor_t_mm = 2.5
body_h_mm = 12.0
def pocket_mm() -> tuple[float, float]:
"""Poche à la condition de matière maximale de la plaque plus jeu par côté.
Une poche dimensionnée à partir du nominal coince environ la moitié des plaques conformes.
"""
growth = plate_tol_mm + 2 * pocket_clearance_mm
return plate_l_mm + growth, plate_w_mm + growth
def interfaces() -> list[dict]:
"""Ce que cette pièce doit ajuster. `check.py interfaces` vérifie chaque entrée."""
pocket_l, pocket_w = pocket_mm()
return [
{"feature": "longueur de la poche de la plaque", "standard": "slas-microplate-footprint",
"dimension": "footprint_length", "value": pocket_l,
"intent": "envelope", "clearance": 2 * pocket_clearance_mm},
{"feature": "largeur de la poche de la plaque", "standard": "slas-microplate-footprint",
"dimension": "footprint_width", "value": pocket_w,
"intent": "envelope", "clearance": 2 * pocket_clearance_mm},
]
def checks() -> list[dict]:
"""Jauges mesurées à partir du solide construit. Dimensionnées à partir des NOMBRES de l'EXIGENCE
(CMM de la plaque, limite de hauteur de l'utilisateur), pas des paramètres de la poche, donc un
mauvais paramètre ne peut pas réduire la jauge pour correspondre à la mauvaise géométrie."""
depth = body_h_mm - floor_t_mm
return [
{"feature": "la plaque à la CMM tombe dans la poche",
"clear": {"box": (plate_l_mm + plate_tol_mm, plate_w_mm + plate_tol_mm, depth),
"at": [(0.0, 0.0, floor_t_mm + depth / 2)]}},
{"feature": "moins de 15 mm pour la scène", "bbox_z": {"max": 15.0}},
]
def build() -> Part:
pocket_l, pocket_w = pocket_mm()
with BuildPart() as carrier:
Box(pocket_l + 2 * wall_t_mm, pocket_w + 2 * wall_t_mm, body_h_mm,
align=(Align.CENTER, Align.CENTER, Align.MIN))
with Locations((0, 0, floor_t_mm)):
Box(pocket_l, pocket_w, body_h_mm, mode=Mode.SUBTRACT,
align=(Align.CENTER, Align.CENTER, Align.MIN))
return carrier.part
Voir references/build123d-patterns.md pour le choix entre constructeur et algèbre, le contrat interfaces(), le dessin, les sélecteurs, les congés et les alésages pour inserts filetés.
5. Générer et exécuter les contrôles
python scripts/gen.py carrier_model.py --outdir out/
python scripts/check.py facts out/carrier.step
python scripts/check.py interfaces out/carrier.manifest.json
python scripts/check.py geometry out/carrier.step --model carrier_model.py
gen.py évalue également les jauges checks() du modèle par rapport au solide qu'il vient de construire, affiche chaque RÉUSSI/ÉCHEC, les enregistre dans le manifeste et se termine avec un code non nul en cas d'échec — de sorte qu'une pièce qui viole sa propre géométrie déclarée ne devienne jamais silencieusement un artefact. check.py geometry réexécute les mêmes jauges sur le STEP exporté, qui est l'artefact de référence.
out/ est une convention temporaire, pas une exigence. Lorsque l'utilisateur a demandé des livrables dans un endroit spécifique, générez-y (--outdir .) ou copiez-y le STEP, le manifeste et le DXF avant de terminer — un livrable qui n'existe que dans out/ n'a pas été livré.
gen.py écrit carrier.step (de référence), carrier.stl (aperçu du maillage et impression) et carrier.manifest.json enregistrant le hachage de la source, les paramètres résolus, les interfaces déclarées, les versions des bibliothèques et la boîte englobante, le volume et la validité mesurés. Le manifeste est le registre de provenance — conservez-le avec l'artefact.
check.py facts rapporte is_valid, la boîte englobante, le volume, la surface, le centre de masse et le nombre de solides. Une pièce qui indique is_valid : false est une géométrie cassée ; corrigez la source avant d'aller plus loin.
check.py interfaces évalue chaque entrée déclarée par le modèle par rapport à la base de données de normes et se termine avec un code non nul en cas d'échec. Soyez clair sur ce qu'elle vérifie et ne vérifie pas : elle vérifie les nombres déclarés — détectant une dimension mal recopiée, la mauvaise norme et un dimensionnement au nominal au lieu de la CMM — mais elle ne mesure jamais la géométrie construite, et une valeur calculée à partir des mêmes constantes avec lesquelles elle est vérifiée réussit par construction avec une marge nulle. Ne la citez pas comme preuve que la géométrie est correcte ; facts et la capture d'écran sont les vérifications de la géométrie. Une liste de déclaration vide réussit : une pièce qui ne s'accouple avec rien dans la base de données fournie n'a rien à déclarer, et ses dimensions d'interface sont nommées comme non vérifiées dans le rapport.
Utilisez interfaces plutôt que check.py fit pour tout ce qui est interne — une poche, un alésage ou une fente n'apparaît pas dans la boîte englobante extérieure de la pièce, ce que mesure fit. Utilisez fit uniquement pour vérifier un nombre à la main (--value footprint_length=128.81), ou lorsque le contour de la pièce lui-même est l'interface, comme un joint découpé selon l'empreinte d'une plaque.
Pour les assemblages, vérifiez que les pièces n'interfèrent pas :
python scripts/check.py clearance out/carrier.step out/lid.step --min 0.3
6. Prendre une capture d'écran et la regarder réellement
python scripts/snapshot.py out/carrier.step --out out/carrier.png
Ensuite, lisez le PNG. Cette étape est obligatoire après chaque génération et chaque modification. Le fait que les vérifications déterministes réussissent n'est pas une raison pour la sauter : is_valid et une boîte englobante correcte sont tous deux parfaitement compatibles avec une poche découpée sur la mauvaise face, un bossage placé à l'extérieur du corps ou un congé qui a mangé un détail. Ces erreurs sont évidentes dans une image et invisibles dans les chiffres.
Connaissez aussi les limites du rendu. Un détail beaucoup plus petit que le cadre — une arête de moule de 0,3 mm sur une pièce de 40 mm, un palier de lamage sur une plaque — peut ne pas être décidable à partir des vues du tout. Ne rapportez pas avoir vu quelque chose que l'image ne peut pas résoudre ; c'est pire que de ne pas regarder. Pour ces détails, la compétence dispose d'instruments : check.py bores affiche chaque surface cylindrique (diamètre, axe, position, portée, balayage) afin que vous puissiez les vérifier.