Un contact intermittent mesure normalement au repos et ne s'ouvre que lorsque la pièce bouge. Ce guide montre comment le détecter en production en mesurant la résistance en continu pendant que la liaison est fléchie, en enregistrant le résultat comme une mesure temporelle dans TofuPilot, et en validant la dispersion des lectures, pas seulement leur moyenne.
Pourquoi une mesure statique ne suffit pas
Une soudure fissurée, un sertissage qui n'a pas capturé tous les brins ou un contact de connecteur à force de contact trop faible peuvent tous conduire parfaitement tant que rien ne bouge. Les faces de la fissure se touchent, ou les brins appuient contre le fût, et une lecture de résistance unique tombe dans les limites. Sous vibration ou traction sur le fil, la surface de contact change d'un instant à l'autre et la résistance saute.
Lectures d'exemple sur une soudure de fil de forte section d'un ESC, en 4 fils, courant de test de 4 A :
| Soudure | Lecture statique | Sous flexion : min | Sous flexion : max | Sous flexion : moyenne |
|---|---|---|---|---|
| Bonne | 0,50 mΩ | 0,49 mΩ | 0,52 mΩ | 0,50 mΩ |
| Fissurée | 0,62 mΩ | 0,60 mΩ | 3,80 mΩ | 0,75 mΩ |
Ces valeurs sont illustratives. C'est le schéma qui compte : la soudure fissurée passe une limite statique de 0,8 mΩ et passe aussi une limite sur la moyenne sous flexion, parce que les lectures élevées sont brèves. Seuls le maximum et la dispersion (max moins min) la distinguent de la bonne soudure.
La méthode s'applique à tout contact qui transporte du courant à travers une interface mécanique :
| Contact | Comment le solliciter pendant la mesure |
|---|---|
| Soudure fil sur pastille | Fléchir le fil d'un angle fixe à la sortie de la soudure |
| Sertissage | Fléchir le fil à l'arrière du fût de sertissage |
| Connecteur | Basculer le connecteur accouplé, ou faire vibrer l'ensemble |
| Soudure traversante sur un composant lourd | Tapoter ou faire vibrer la carte |
Principe de la mesure
Le gabarit fait trois choses simultanément pendant une durée fixe :
- Il impose un courant constant dans le contact par des contacts de force Kelvin.
- Il sollicite le contact avec un actionneur : un bras de servomoteur, un solénoïde ou un petit pot vibrant, à amplitude et fréquence fixes.
- Il échantillonne la tension de mesure et le courant réel à intervalle fixe.
Chaque échantillon donne une résistance R = V / I. Avec la tension en microvolts et le courant en milliampères, le rapport est directement en milliohms. La série d'échantillons est enregistrée comme une seule mesure multidimensionnelle : le temps en abscisse, la résistance en ordonnée.
L'actionneur doit solliciter la pièce de la même façon sur chaque unité. Un technicien qui fléchit un fil à la main applique une force différente à chaque fois, et le résultat ne peut pas être comparé d'une unité à l'autre ni entre opérateurs.
Prérequis
- Le CLI TofuPilot installé sur le poste de test
- Un gabarit Kelvin tel que décrit dans Contrôler les soudures sans les détruire, complété d'un actionneur
- Un firmware de gabarit qui capture une rafale d'échantillons pendant l'actionnement et les renvoie en une seule réponse
Étape 1 : définir la commande de capture
Dans cet exemple, le microcontrôleur du gabarit accepte une commande par capture :
FLEX <channel> <amps> <samples> <period_ms> <flex_hz>Le firmware sélectionne le canal, mesure l'offset à courant nul, active le courant, démarre l'actionneur, prend samples lectures toutes les period_ms, arrête l'actionneur et le courant, puis répond par une ligne JSON :
{"sense_uv": [2010.4, 2012.1, 2009.8], "current_ma": [4001.2, 4000.8, 4001.0]}L'offset est déjà soustrait de sense_uv. La temporisation reste dans le firmware, parce qu'un microcontrôleur échantillonne à intervalle régulier, ce que ne fait pas une boucle Python qui envoie une requête série par échantillon.
Étape 2 : écrire le plug du gabarit
plugs/flex_fixture.py21 lines
import jsonimport serialclass FlexFixture: def __init__(self, port, baudrate=115200): self._ser = serial.Serial(port, baudrate, timeout=10) def capture_under_flex(self, channel, amps, samples, period_ms, flex_hz): command = f"FLEX {channel} {amps:.3f} {samples} {period_ms} {flex_hz:.2f}" self._ser.write(command.encode()) reply = self._ser.readline().decode().strip() if not reply or reply.startswith("ERR"): raise RuntimeError(f"Flex capture on channel {channel} failed: {reply!r}") # Des listes de flottants traversent la frontière du plug, qui n'accepte que du JSON. return json.loads(reply) def __del__(self): self._ser.close()Le timeout série couvre toute la capture : 500 échantillons à 2 ms prennent 1 s, plus le démarrage et l'arrêt de l'actionneur.
Étape 3 : écrire la phase de mesure
phases/flex.py49 lines
import csvimport io# Enregistré à la place d'un échantillon où le courant s'est effondré (contact ouvert).R_CEILING_MOHM = 100.0def measure_under_flex( flex_fixture, measurements, attach, log, channel, current_a=4.0, samples=500, period_ms=2, flex_hz=5.0,): capture = flex_fixture.capture_under_flex(channel, current_a, samples, period_ms, flex_hz) times_ms = [i * period_ms for i in range(len(capture["sense_uv"]))] resistance = [] open_samples = 0 for uv, ma in zip(capture["sense_uv"], capture["current_ma"]): # Un courant très inférieur à la consigne signifie que la source a atteint # sa tension de compliance : le contact était ouvert pendant cet échantillon. if ma < 0.5 * current_a * 1000: open_samples += 1 resistance.append(R_CEILING_MOHM) else: resistance.append(uv / ma) # µV / mA = mΩ m = measurements.flex_resistance m.x_axis = times_ms m.y_axis.resistance = resistance aggs = m.y_axis.resistance.aggregations aggs.mean = sum(resistance) / len(resistance) aggs.max = max(resistance) aggs.spread = max(resistance) - min(resistance) aggs.open_samples = open_samples buf = io.StringIO() writer = csv.writer(buf) writer.writerow(["time_ms", "sense_uv", "current_ma", "resistance_mohm"]) writer.writerows(zip(times_ms, capture["sense_uv"], capture["current_ma"], resistance)) attach.data(buf.getvalue().encode(), f"flex_channel_{channel}.csv") log.info(f"Channel {channel}: spread {aggs.spread:.3f} mΩ, {open_samples} open samples")Le graphique du run montre la courbe, les agrégations portent la décision bon/mauvais, et le CSV conserve la tension et le courant bruts pour l'analyse des défaillances.
Étape 4 : déclarer la mesure et ses limites
Les validateurs d'axe d'une mesure multidimensionnelle n'acceptent que == et != contre un tableau complet, les limites de plage se placent donc sur des agrégations. Le type d'une agrégation est une chaîne libre, ce qui permet spread et open_samples à côté de mean et max.
procedure.yaml49 lines
name: ESC Power Joint Flex Screeningversion: 1.0.0execution: workers: 1plugs: - name: Flex Fixture key: flex_fixture python: plugs.flex_fixture:FlexFixture scope: station with: port: "COM5"main: - name: Battery Positive Joint Under Flex key: flex_bat_pos python: phases.flex:measure_under_flex with: channel: 0 measurements: - name: Resistance Under Flex key: flex_resistance title: Battery positive joint, 5 Hz flex x_axis: legend: Time key: time unit: ms y_axis: - legend: Resistance key: resistance unit: mΩ aggregations: - type: mean validators: - operator: "<=" expected_value: 0.8 - type: max validators: - operator: "<=" expected_value: 1.2 - type: spread validators: - operator: "<=" expected_value: 0.3 - type: open_samples validators: - operator: "==" expected_value: 0Les limites sont des exemples pour une soudure de fil de forte section à 4 A. Dérivez les vôtres d'unités réputées bonnes, comme pour la mesure statique : mesurez la dispersion sur 30 unités saines ou plus sous le même actionnement, et placez la limite au-dessus de cette population avec une marge pour le bruit du gabarit. Une étude R&R sur la dispersion indique si le bruit du gabarit est assez faible pour la limite visée.
| Agrégation | Ce qu'elle détecte |
|---|---|
mean | Une soudure résistive en permanence, déjà visible en statique |
max | De brefs pics de résistance pendant l'ouverture de la fissure |
spread | Un contact dont la résistance suit l'actionneur |
open_samples | Des échantillons où le contact s'est complètement ouvert |
Étape 5 : choisir la cadence et la durée
Deux paramètres déterminent ce que la mesure peut voir :
- Intervalle d'échantillonnage. Une ouverture plus courte que l'intervalle entre deux échantillons peut passer entre eux. À 2 ms par échantillon, une ouverture de 0,5 ms n'est détectée que si un échantillon tombe dedans. Des intervalles plus courts réduisent le moyennage par échantillon et augmentent le bruit, la limite de dispersion doit en tenir compte. Il existe des détecteurs d'événements dédiés aux discontinuités inférieures à la milliseconde sur les connecteurs ; une mesure de résistance échantillonnée ne les remplace pas.
- Durée et cycles de flexion. Enregistrez plusieurs cycles complets d'actionneur : 500 échantillons à 2 ms couvrent 1 s, soit 5 cycles à 5 Hz. Un seul cycle peut ne pas atteindre la position où la fissure s'ouvre.
Gardez un nombre de points modéré par mesure : de quelques centaines à quelques milliers. La pièce jointe CSV contient la capture complète si une acquisition plus longue est nécessaire pour l'analyse.
Étape 6 : analyser les résultats
Dans le dashboard TofuPilot, chaque run affiche le graphique de résistance de chaque soudure à côté de ses agrégations. Sur l'ensemble des runs :
| Vue | Usage |
|---|---|
| Pareto des défaillances par mesure | Montre la soudure ou le connecteur qui échoue le plus souvent sous flexion |
| Carte de contrôle et Cpk de chaque agrégation | Montre une dispersion qui augmente sur plusieurs semaines, souvent un actionneur ou un gabarit usé |
| Rendement par opérateur et par poste | Désigne l'étape de montage ou le poste de test en cause |
Pour les causes de procédé des soudures fissurées et les actions correctives, voir Pourquoi les soudures d'ESC cèdent en vol.
Pièges courants
Valider uniquement la moyenne. Une fissure ouverte quelques pour cent du temps déplace à peine la moyenne. Mettez des limites sur max, spread et open_samples.
Fléchir à la main. La force et l'angle changent avec chaque opérateur. Utilisez un actionneur à amplitude et fréquence fixes.
Échantillonner depuis une boucle Python sur la liaison série. L'intervalle varie avec la latence USB et celle du système d'exploitation. Laissez le firmware cadencer les échantillons et renvoyer la rafale.
Calculer la résistance avec la consigne de courant. Pendant une ouverture, la source ne peut pas maintenir son courant. Utilisez le courant mesuré à chaque échantillon, et comptez ceux où il s'est effondré.
Mesurer en 2 fils. Les contacts des pointes bougent aussi sous flexion, et leur résistance varie. Les contacts Kelvin les retirent de la lecture.
Oublier workers: 1. Les phases sans depends_on démarrent en parallèle. Deux phases qui pilotent en même temps un seul actionneur et un seul multiplexeur produisent des données sans signification.
Fléchir trop fort. Le test doit révéler les défauts, pas les créer. Réglez l'amplitude bien en dessous de ce que la soudure subit en service, et vérifiez sur des unités saines que des tests répétés ne modifient pas leurs lectures.
Points clés
- Un contact intermittent passe une mesure de résistance statique et ne s'ouvre qu'en mouvement.
- Mesurez la résistance en continu pendant qu'un actionneur à amplitude fixe fléchit la soudure, le sertissage ou le connecteur.
- Enregistrez la série comme une mesure multidimensionnelle, la résistance en milliohms en fonction du temps.
- Validez les agrégations
max,spreadetopen_samples, pas seulement la moyenne. - Laissez le firmware du gabarit cadencer les échantillons, et joignez la capture brute en CSV.
- Fixez les limites à partir d'unités saines sous le même actionnement, et vérifiez le bruit du gabarit par une étude R&R.
