CAD de Hardware de Laboratorio
Diseñe hardware de investigación física como código fuente paramétrico en Python, exporte STEP como el artefacto autoritativo y verifique el resultado tanto numérica como visualmente antes de que se fabrique cualquier cosa.
La parte difícil del hardware de laboratorio casi nunca es la geometría. Es que la pieza debe acoplarse con equipos cuyas dimensiones están fijadas por un estándar publicado o un plano del proveedor. Un soporte que es 0.5 mm demasiado ancho no encaja en el lector de placas; un canal con la relación de aspecto incorrecta colapsa durante la unión; un soporte cuyo patrón de pernos es de 25.4 mm en lugar de 25.0 mm no alcanzará la mesa óptica. Esta skill existe para mantener esos números correctos y verificados.
Cuándo usarla
Úsela para cualquier solicitud de diseñar, modelar o fabricar una pieza física para un laboratorio: chip, molde, soporte, adaptador, portador, gradilla, abrazadera, carcasa, plantilla, accesorio, arena o laberinto. También úsala para inspeccionar o modificar un archivo STEP existente.
No la use para análisis de elementos finitos, dinámica de fluidos computacional, estructura molecular o trazado científico. Esas son habilidades diferentes.
Configuración
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 requiere Python >=3.10,<3.15 e incluye el kernel OpenCascade a través de
cadquery-ocp-novtk. El wheel es grande; instálelo una vez por proyecto y reutilícelo.
Todos los scripts empaquetados aceptan --help. check.py standards se ejecuta sin tener instalado build123d.
Los archivos de modelo se ejecutan, no se analizan. gen.py, check.py y snapshot.py importan un
*_model.py y llaman a su build(), que ejecuta Python arbitrario en el entorno actual. Eso
es inherente al CAD paramétrico: el código fuente es el diseño. Solo ejecute archivos de modelo creados en
esta sesión o suministrados por el usuario desde una ubicación confiable. Si un modelo provino de internet, una
unidad compartida o un colega no confiable, léalo antes de ejecutarlo y diga que lo hizo.
Flujo de trabajo obligatorio
Siga estos pasos en orden. Los pasos 5 y 6 no son opcionales, y el paso 6 no se omite porque el paso 5 se haya superado.
1. Enrutar a una familia de dispositivos
Lea la solicitud, clasifíquela y cargue exactamente una referencia de familia. No cargue las cuatro: son extensas y mezclar convenciones entre familias es una fuente común de errores.
| Si la pieza es | Cargue |
|---|---|
| Un chip, molde, red de canales, celda de flujo, junta o cualquier cosa con puertos de fluido | references/microfluidics.md |
| Un soporte, poste, adaptador de mesa óptica, pieza de sistema de jaula, portafiltros o portamuestras en una trayectoria de haz | references/optomechanics.md |
| Un adaptador, inserto, rack o soporte para placas, cubetas, tubos, portaobjetos o platos | references/labware-adapters.md |
| Una arena, laberinto, pieza de fijación de cabeza, boquilla, correa o carcasa montada en extrusión para trabajo animal | references/behavior-rigs.md |
Si la pieza abarca genuinamente dos familias — un chip microfluídico que se atornilla a una mesa óptica — cargue la familia que posee la interfaz crítica, luego lea solo la sección de interfaz de la segunda. Indique en su respuesta a qué familia enrutó.
2. Establecer las dimensiones de la interfaz antes de cualquier geometría
Cada pieza tiene al menos una interfaz de acoplamiento. Antes de escribir código, anote para cada interfaz:
- la fuente de la dimensión: un estándar publicado, un plano del proveedor o una medición del usuario;
- el valor nominal y la tolerancia;
- el juego o interferencia que pretende, y por qué.
Busque el número en assets/standards.json o en la referencia de la familia. Nunca escriba una dimensión
de interfaz de memoria. Si el número no está en el archivo de estándares o en la referencia, pídale al usuario
el plano del proveedor o la medición en lugar de adivinarlo. Una dimensión de interfaz adivinada es el
modo de fallo más costoso en esta habilidad.
Una característica que debe recibir un componente estandarizado se dimensiona con respecto al estado de material máximo de ese componente — nominal más su tolerancia positiva — y solo entonces se le otorga juego. Si se dimensiona a partir del nominal en su lugar, solo encaja en la mitad más pequeña de los componentes conformes.
python scripts/check.py standards --list
python scripts/check.py standards --show slas-microplate-footprint
Los IDs de estándares incluidos (cadenas exactas; no adivine 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 pieza no se acopla con nada en esta lista, eso es común y está bien: declare que no hay interfaces, y nombre cada dimensión de interfaz con su fuente (especificación del usuario, plano del proveedor, medición) como no verificada en el informe. Nunca declare contra un estándar no relacionado para llenar el vacío — una declaración inventada es peor que una declaración honesta de "nadie verificó esto".
3. Elegir el proceso antes de elegir la geometría
Lea references/fabrication-limits.md. El proceso determina el espesor mínimo de pared, la característica
mínima, la tolerancia alcanzable y si la pieza sobrevive al autoclave o al contacto con su disolvente.
FDM no puede mantener ±0.05 mm; la resina SLA generalmente no es segura para el contacto celular sin
post-curado y pruebas. Registre el proceso y el material en la docstring del modelo.
4. Crear un modelo paramétrico
Escriba <part>_model.py. El código fuente es el artefacto autoritativo — nunca edite manualmente un
archivo STEP exportado y nunca regenere a partir de una malla.
Requisitos:
- Cada dimensión que un usuario podría cambiar es una constante con nombre a nivel de módulo con unidades en el
nombre:
bore_d_mm,wall_t_mm,post_h_mm. Sin números desnudos en el cuerpo excepto 0, 1 y 2. - Exponga
build() -> Part.gen.pyla llama. - Agrupe los parámetros en un bloque
INTERFACE(dimensiones fijadas por un estándar, anotadas con el ID del estándar) y un bloqueDESIGN(dimensiones que usted es libre de elegir). - Derive cada dimensión calculada dentro de una función, nunca a nivel de módulo, para que las anulaciones
--paramrealmente la alcancen. - Declare una función
interfaces()que devuelva las dimensiones que la pieza debe encajar, cada una con su ID de estándar e intención. Esto es lo que hace que la interfaz sea verificable por máquina en el paso 5.intentes"envelope"cuando la característica debe aceptar cualquier pieza conforme (un bolsillo, agujero o ranura — verificado unilateralmente en el estado de material máximo más su juego) y"match"cuando esta pieza debe ser conforme (banda simétrica).clearancees el juego total previsto en mm y debe ser no negativo. Declare solo las dimensiones que restringen las características de acoplamiento de esta pieza — una propiedad del equipo de acoplamiento (el borde de una mesa, un espesor típico de placa) no es una interfaz suya. Si ningún estándar incluido se aplica, devuelva[]. - Declare una función
checks()de calibres pasa/no pasa medidos a partir del sólido construido: una regiónclearpara todo lo que debe pasar o caber (ejes de tornillos, corredores de haz, la pieza de acoplamiento en estado de material máximo cayendo en su bolsillo), una regiónmaterialpara todo lo que debe permanecer (una cresta, un borde, un asiento de tornillo) y unbbox_*límite para cada límite de tamaño que el usuario indicó. Asigne cada requisito geométrico en la solicitud a una entrada; estos detectan los errores queis_valid, la caja delimitadora y los números declarados no pueden ver.gen.pylos ejecuta en cada generación y falla la construcción cuando uno falla. Esquema y ejemplos resueltos:references/build123d-patterns.md. - Ponga el proceso, material y cada fuente de interfaz en la docstring del módulo.
"""Portador de microplaca SLAS para un inserto de escenario personalizado.
Proceso: FDM, PETG, 0.2 mm de capa. Presupuesto de tolerancia +/-0.3 mm.
Interfaces:
- Bolsillo de placa: ANSI/SLAS 1-2004 (R2012) huella 127.76 x 85.48 mm, +/-0.25.
- Pernos de escenario: medidos por el usuario, centros a 40.0 mm (dibujo en docs/stage.pdf).
"""
from build123d import *
# --- INTERFAZ (fijado por estándar; no ajustar) ---
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; el bolsillo se dimensiona al nominal + esto
# --- DISEÑO (libre) ---
pocket_clearance_mm = 0.40 # por lado; FDM, ver fabrication-limits.md
wall_t_mm = 3.0
floor_t_mm = 2.5
body_h_mm = 12.0
def pocket_mm() -> tuple[float, float]:
"""Bolsillo en el estado de material máximo de la placa más juego por lado.
Un bolsillo dimensionado a partir del nominal se atasca en aproximadamente la mitad de las placas conformes.
"""
growth = plate_tol_mm + 2 * pocket_clearance_mm
return plate_l_mm + growth, plate_w_mm + growth
def interfaces() -> list[dict]:
"""Lo que esta pieza debe ajustar. `check.py interfaces` verifica cada entrada."""
pocket_l, pocket_w = pocket_mm()
return [
{"feature": "longitud del bolsillo de la placa", "standard": "slas-microplate-footprint",
"dimension": "footprint_length", "value": pocket_l,
"intent": "envelope", "clearance": 2 * pocket_clearance_mm},
{"feature": "ancho del bolsillo de la placa", "standard": "slas-microplate-footprint",
"dimension": "footprint_width", "value": pocket_w,
"intent": "envelope", "clearance": 2 * pocket_clearance_mm},
]
def checks() -> list[dict]:
"""Calibres medidos a partir del sólido construido. Dimensionados a partir de los números del REQUISITO
(MMC de la placa, el límite de altura del usuario), no de los parámetros del bolsillo, para que un
parámetro incorrecto no pueda reducir el calibre para que coincida con una geometría incorrecta."""
depth = body_h_mm - floor_t_mm
return [
{"feature": "la placa en MMC cae en el bolsillo",
"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": "menos de 15 mm para el escenario", "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
Consulte references/build123d-patterns.md para la elección entre builder vs álgebra, el contrato de interfaces(),
dibujo, selectores, filetes y agujeros para insertos roscados.
5. Generar y ejecutar las comprobaciones
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 también evalúa los calibres checks() del modelo contra el sólido que acaba de construir, imprime
cada PASO/FALLO, los registra en el manifiesto y sale con código de error en caso de fallo, por lo que una pieza
que viola su propia geometría declarada nunca se convierte silenciosamente en un artefacto. check.py geometry
vuelve a ejecutar los mismos calibres contra el STEP exportado, que es el artefacto autoritativo.
out/ es una convención temporal, no un requisito. Cuando el usuario solicitó entregables en un lugar
específico, genere allí (--outdir .) o copie el STEP, el manifiesto y el DXF a ese lugar antes de
finalizar: un entregable que existe solo dentro de out/ no ha sido entregado.
gen.py escribe carrier.step (autoritativo), carrier.stl (vista previa de malla e impresión) y
carrier.manifest.json registrando el hash de la fuente, los parámetros resueltos, las interfaces declaradas,
las versiones de las bibliotecas y la caja delimitadora, el volumen y la validez medidos. El manifiesto es el
registro de procedencia: manténgalo con el artefacto.
check.py facts informa is_valid, caja delimitadora, volumen, área de superficie, centro de masa y
recuento de sólidos. Una pieza que informa is_valid: false tiene una geometría rota; corrija la fuente
antes de continuar.
check.py interfaces evalúa cada entrada que el modelo declaró contra la base de datos de estándares
y sale con código de error en caso de fallo. Sea claro sobre lo que verifica y lo que no verifica: verifica
los números declarados — detectando una dimensión mal transcrita, el estándar incorrecto y el
dimensionamiento nominal en lugar de MMC — pero nunca mide la geometría construida, y un valor calculado
a partir de las mismas constantes contra las que se verifica pasa con cero margen por construcción. No lo
cite como evidencia de que la geometría es correcta; facts y la instantánea son las comprobaciones de geometría.
Una lista de declaraciones vacía pasa: una pieza que no se acopla con nada en la base de datos incluida no tiene
nada que declarar, y sus dimensiones de interfaz se nombran como no verificadas en el informe.
Use interfaces en lugar de check.py fit para cualquier cosa interna: un bolsillo, agujero o ranura no
aparece en la caja delimitadora exterior de la pieza, que es lo que fit mide. Recurra a fit solo
para verificar un número manualmente (--value footprint_length=128.81), o cuando el contorno de la pieza
sea la interfaz, como una junta cortada a una huella de placa.
Para ensamblajes, verifique que las piezas no interfieran:
python scripts/check.py clearance out/carrier.step out/lid.step --min 0.3
6. Instantánea y mírela realmente
python scripts/snapshot.py out/carrier.step --out out/carrier.png
Luego lea el PNG. Este paso es obligatorio después de cada generación y cada modificación.
Que las comprobaciones deterministas se pasen no es una razón para omitirlo: is_valid y una caja delimitadora
correcta son ambas totalmente consistentes con un bolsillo cortado en la cara equivocada, un saliente colocado
fuera del cuerpo o un filete que se comió una característica. Esos errores son obvios en una imagen e invisibles
en los números.
Conozca también los límites de la representación. Una característica mucho más pequeña que el marco — una cresta de molde de 0.3 mm en una pieza de 40 mm, un paso de avellanado en una placa — puede no ser decidible a partir
de las vistas en absoluto. No informe haber visto algo que la imagen no puede resolver; eso es peor que no
mirar. Para tales características, la habilidad tiene instrumentos: check.py bores imprime cada cara
cilíndrica (diámetro, eje, posición, extensión, barrido) para que pueda conciliar...