Une station de test, plusieurs produits : configurez votre test OpenHTF pour détecter le SKU au moment de l'exécution, charger les limites et phases spécifiques au SKU depuis un fichier de configuration, et laisser TofuPilot suivre le rendement par numéro de pièce automatiquement.
Pourquoi les stations multi-SKU sont importantes
Exécuter des stations séparées par SKU gaspille de l'espace au sol et des fixtures. Une seule station qui gère une famille de produits réduit :
- Le nombre de fixtures (lit de clous ou carte à sondes partagés)
- La formation des opérateurs (un seul flux de travail, pas cinq)
- La surface de maintenance (une seule station à calibrer)
Méthodes de détection du SKU
| Méthode | Quand l'utiliser | Fiabilité |
|---|---|---|
| Scan code-barres | Étiquette scannée par l'opérateur, pas de contact électrique nécessaire | Élevée |
| Résistance d'identification | Le PCB possède un diviseur résistif codant le SKU | Moyenne |
| EEPROM I2C | Le PCB stocke le numéro de pièce dans une mémoire embarquée | Élevée |
Scan code-barres
import openhtf as htf
class BarcodePlug(htf.plugs.BasePlug):
"""Lit le SKU depuis le scan de code-barres de l'opérateur."""
def setUp(self):
pass
def scan(self) -> str:
raw = input("Scanner le code-barres : ").strip()
if not raw:
raise ValueError("Scan de code-barres vide")
return raw
def tearDown(self):
passRésistance d'identification
import openhtf as htf
_VOLTAGE_MAP = {
(0.0, 0.4): "SKU-A",
(0.4, 0.8): "SKU-B",
(0.8, 1.2): "SKU-C",
(1.2, 1.6): "SKU-D",
}
class ResistorIdPlug(htf.plugs.BasePlug):
"""Identifie le SKU depuis la tension du diviseur résistif."""
def setUp(self):
pass
def read_sku(self, adc_voltage: float) -> str:
for (low, high), sku in _VOLTAGE_MAP.items():
if low <= adc_voltage < high:
return sku
raise ValueError(f"Tension non reconnue : {adc_voltage:.3f} V")
def tearDown(self):
passSélection de test pilotée par configuration
Stockez les définitions de SKU dans un fichier YAML. Cela sépare les limites de la logique de test.
SKU-A:
part_number: "PCB-001-A"
description: "Variante standard 5 V"
phases:
- power_on
- voltage_check
- current_check
limits:
supply_voltage:
min: 4.85
max: 5.15
supply_current:
min: 0.080
max: 0.120
SKU-B:
part_number: "PCB-001-B"
description: "Variante basse consommation 3,3 V"
phases:
- power_on
- voltage_check
- current_check
- sleep_current_check
limits:
supply_voltage:
min: 3.2
max: 3.4
supply_current:
min: 0.030
max: 0.060
sleep_current:
min: 0
max: 0.000050Chargez la configuration au démarrage de la station :
from pathlib import Path
import yaml
def load_sku_config(path: str = "station/config/skus.yaml") -> dict:
config_path = Path(path)
if not config_path.exists():
raise FileNotFoundError(f"Configuration SKU introuvable : {config_path}")
with config_path.open() as f:
return yaml.safe_load(f)Limites de mesure spécifiques au SKU avec OpenHTF
Utilisez une phase factory pour intégrer les limites spécifiques au SKU dans les mesures OpenHTF :
import openhtf as htf
from openhtf.util import units
def make_voltage_phase(min_v: float, max_v: float):
"""Retourne une phase de tension avec des limites intégrées."""
@htf.measures(
htf.Measurement("supply_voltage")
.in_range(minimum=min_v, maximum=max_v)
.with_units(units.VOLT),
)
def voltage_check(test):
test.measurements.supply_voltage = read_voltage()
return voltage_check
def make_current_phase(min_a: float, max_a: float):
"""Retourne une phase de courant avec des limites intégrées."""
@htf.measures(
htf.Measurement("supply_current")
.in_range(minimum=min_a, maximum=max_a)
.with_units(units.AMPERE),
)
def current_check(test):
test.measurements.supply_current = read_current()
return current_checkExemple complet fonctionnel
import openhtf as htf
from tofupilot.openhtf import TofuPilot
from station.config.loader import load_sku_config
from station.phases.factory import make_voltage_phase, make_current_phase
SKU_CONFIG = load_sku_config()
def power_on(test):
"""Met le DUT sous tension et attend la stabilisation."""
import time
time.sleep(0.5)
def run_station():
# 1. Détecter le SKU
sku_id = input("Scanner le code-barres : ").strip()
if sku_id not in SKU_CONFIG:
raise ValueError(f"SKU inconnu '{sku_id}'. Disponibles : {list(SKU_CONFIG)}")
sku = SKU_CONFIG[sku_id]
limits = sku["limits"]
part_number = sku["part_number"]
# 2. Composer les phases depuis la configuration
phases = [power_on]
if "supply_voltage" in limits:
lim = limits["supply_voltage"]
phases.append(make_voltage_phase(lim["min"], lim["max"]))
if "supply_current" in limits:
lim = limits["supply_current"]
phases.append(make_current_phase(lim["min"], lim["max"]))
# 3. Construire et exécuter le test
test = htf.Test(*phases, test_name=f"Station ({sku_id})")
with TofuPilot(test):
test.execute(test_start=lambda: input("Scanner le numéro de série : "))
if __name__ == "__main__":
run_station()Suivi du rendement par SKU dans TofuPilot
TofuPilot regroupe les statistiques de rendement par numéro de pièce. Chaque SKU obtient son propre graphique de rendement sans configuration supplémentaire.
| Numéro de pièce | SKU | Exécutions | Taux de réussite |
|---|---|---|---|
| PCB-001-A | SKU-A | 240 | 97,5 % |
| PCB-001-B | SKU-B | 180 | 94,4 % |
Filtrez par numéro de pièce dans le tableau de bord TofuPilot pour comparer les tendances des SKU côte à côte.