Preiswerter induktiver Näherungssensor im Eigenbau

Wozu?

Der hier beschriebene induktive Näherungssensor wurde von mir im Rahmen einer Modellbahn-Steuerung selbst gebaut und eingesetzt. Bis zu sieben Messstellen können an einem Mikrocontroller betrieben werden. Die einzelnen Sensoren sind klein und kommen mit wenigen preiswerten Bauteilen aus. Die Einsatzmöglichkeiten beschränken sich nicht nur auf den Modellbahn-Bereich. Überall da, wo die Anhäherung bzw. der Bewegungsablauf von leitfähigen Teilen erfasst werden soll, kann der Sensor gute Dienste leisten. Die Auswertesoftware im Microcontroller entscheidet darüber, ob letztendlich nur ein binäres Signal erzeugt wird oder ob der Grad der Annäherung ausgewertet wird.

Wie funktioniert's?

Unten stehendes Bild 1 zeigt den Sensor, der aus einer Induktivität plus einem Kondensator, also einem Schwingkreis, besteht. Über ein verdrilltes Adernpaar ist der Schwingkreis an die Auswerteelektronik (Mikrocontroller) angeschlossen. Die maximal mögliche Länge der Leitung habe ich nicht ausprobiert. Bei o.g., gut funktionierender Modellbahn-Anwendung gibt es Leitungslängen von 80 cm.

Sensor
Bild 1: Sensor mit Induktivität kleinster ∅

Mit kurzen Impulsen aus dem Microcontroller wird die Schaltung zum Schwingen angeregt. Da der Schwingkreis eine hohe Güte besitzt, kann man nach einmalger Anregung ein Ausschwingen über mehrere Dutzend Perioden beobachten und durch den Microcontroller auszählen lassen. An der Stirnseite der tonnenförmigen ungeschirmten Induktivität tritt dabei das Wechsel-Magnetfeld in die Umgebung aus. Bringt man nun Metall (muss nicht ferromagnetisch sein) in die Nähe, so werden darin energiezehrende Wirbelströme induziert, die die Güte des Schwingkreises und damit die Anzahl der zählbaren Ausschwingperioden reduzieren. Dieser Effekt ist deutlich und ist gut auswertbar. Die Schwingfrequenz ändert sich dagegen kaum.

Testaufbau
Bild 2: Testaufbau mit Induktivität ∅ 9,5 mm


Sensor
Bild 3: Dämpfung der Schwingungen über Abstand der Probe

Mit dem Sensor des Testaufbaus ergaben sich mit einem dicken Stück Aluminium die in neben stehendem Diagramm gezeigten Empfindlichkeiten bei verschiedenen Abständen.


Wie schaut die Hardware aus?

Die beiden Komponenten des Schwingkreises müssen folgende Voraussetzungen erfüllen:
  • Die Induktivität muss einen möglichst geringen Serienwiderstand haben (am besten < 0,05 Ω). Man muss deshalb eine Ausführung wählen, die einen Nennstrom von mehreren Ampere hat (für Leistungsanwendungen), obwohl bei vorliegender Anwendung nur Ströme im mA-Bereich fließen. Die Induktivität muss zudem ungeschirmt und am besten tonnenförmig und radial bedrahtet sein. Der tolerierbare Durchmesser richtet sich nach der Anwendung. Für die eingangs erwähnte Modellbahn-Steuerung musste der Sensor in ein Spur N -Gleis passen. Deshalb wurde die kleinste verfügbare Bauform mit 6 mm Durchmesser gewählt ( z.B. bei Conrad-Electronic). Größere Bauformen (z.B. ∅ 9,5 mm) (z.B. bei Conrad-Electronic) haben einen noch etwas geringeren Serienwiderstand (≤ 0,03 Ω), wodurch der Messeffekt, d.h. die Güteminderung durch leitende Gegenstände im Magnetfeld, im Verhältnis noch deutlicher ausfällt.
  • Die Kapazität muss temperaturstabil sein. Dafür eignet sich ein Keramikkondensator mit X7R-Dielektrikum ( z.B. bei Conrad-Electronic). Der Kondensator sollte auch einen möglichst kleinen Serienwiderstand haben (wird leider nicht immer angegeben).
  • Das Produkt aus Induktivitäts- und Kapazitätswert darf nicht zu klein sein, da die Resonanzfrequenz sich zu , ergibt, also bei kleinem LC hoch liegt. Für die Werte, wie sie in Bild 4 zu finden sind , nämlich (6,8 μH und 47 nF), sind das ca. 280 kHz. Das lässt sich mit einem 16 MHz ATmega-Prozessor per Interrupt noch gut auszählen. Viel höher sollte die Frequenz aber nicht liegen. Natürlich gibt es auch ein Verhältnis zwischen Induktivitäts- und Kapazitätswert, bei dem die Anregung per Impuls und das lange Ausklingen am besten funktioniert. Die verwendeten Werte wurden durch Schaltungssimulation unter Berücksichtigung der jeweilgen Serienwiderstände der käuflichen Bauteilwerte ermittelt. Mit diesem Schaltungsmodell könnt Ihr in LTspice selbst experimentieren.

Der schon mehrfach erwähnte Mikrocontroller spielt eine entscheidende Rolle. Wie auch bei anderen Projekten verwende ich dafür das Mikrocontroller-Board Pro Mini (Arduino bzw. kompatible) in der 5V/16MHz-Ausführung. Falls Ihr mit dieser Technik noch nicht vertraut seid, findet Ihr auf meiner speziellen Seite nähere Anleitungen. Der dort verbaute ATmega-Prozessor bietet alles was man bei vorliegender Anwendung braucht, um mit wenig externen Bauteilen auszukommen: nämlich Tri-State-Aus-/Eingänge, Analog-Multiplexer und Analog-Komparator.

Es braucht keine spezielle, schwer durchschaubare Oszillatorschaltung, die u.U. nicht zuverlässig anschwingt. Vor allem lassen sich bis zu sieben Sensoren anschließen, wobei als zusätzliches Bauteil je Anschluss lediglich ein Widerstand benötigt wird. Unten stehendes Bild 4 zeigt die verwendete Beschaltung.

Schaltplan
Bild 4: Schaltung

Die Sensor-Schaltungen sind auf der einen Seite jeweils mit den Analog-Eingängen A0, A1 ... verbunden und hängen auf der anderen Seite gemeinsam an einer festen mittleren Bezugsspannung, die durch einem Spannungsteiler (2 x 1kΩ) plus Elko (4,7 μF) erzeugt wird. Diese Spannung ist zudem auf den positiven Eingang AIN0 des Anlalog-Komparators geführt. Per integriertem Mulitplexer kann der Prozessor die Eingänge A0 bis A6 (nicht A7) intern auf den AIN1-Pin, also den negativen Komparatoreingang durchschalten. Zudem lassen sich alle Pins, und eben auch A0 bis A6, beliebig als Ausgang (zieht Strom nach Masse bzw. nach VCC) oder als Eingang (hochohmig) schalten. Anregung, anschließendes Auszählen der Schwingungen und Verarbeitung der Zählwerte ist damit nur noch eine Sache der Software.

Was macht die Software?

Das Microcontroller-Programm (Arduino-Sketch) muss folgende Kernfunktionen für jede Messung ausführen:
  • Start der Messung, d.h. Impulse zum Anregen des jeweiligen Schwingkreises erzeugen,
  • Zählen der Nulldurchgänge und
  • Abschluss der Messung, d.h. Filtern und Abspeichern des jeweilgen Zählergebnisses.
Ich habe diese Funktionen timergesteuert und vollständig in Interrupt-Serviceroutinen (ISR) realisiert. Das Hauptprogramm (loop()) ist damit für übergeordnete Aufgaben frei. Start und Abschluss der Messungen erfolgen in der „Output Compare Match“-Interrupt-Serviceroutine des Timers 2A, das Zählen der Schwingungen in der Komparator-Interrupt-Serviceroutine. Nachstehende Scroll-Box zeigt auszugsweise diese Programmteile zur Erläuterung:
--- Auszug Arduino-Sketch (Interrupt-Routinen) ---

ISR(TIMER2_COMPA_vect, ISR_NOBLOCK) {  // Timer-Interrupt-Serviceroutine

uint8_t bitmask, channel;

  channel = ((measuring_count++) % SAMPLE_INTERVAL);

  /* terminate and save the measurement started for the previous channel */
  if (measurement_in_progress) {
    channel--; // the previous channel
    ACSR &= ~(1<<ACIE);  // disable interrupt of analog comparator, result is in "comparator_count"
    measurement_in_progress = false;

    measurement[channel] = comparator_count;  // save measurement

    // filtering may be done here

    channel++;  // increment again to the current channel
  } // saving of previous measurement completed

  /* if still a channel to serve */
  if (channel < NR_SENSORS) {
    measurement_in_progress = true;
    ADMUX = channel & ((1<<MUX2)|(1<<MUX1)|(1<<MUX0)); // MUX2 bis MUX0 Bits im ADMUX Register
    bitmask = (1<<channel);  // for selecting pin PC0...7
    /******** start measuring sequence ********/
    cli();
    /* pull down pulse */
    PORTC &= ~bitmask;  // sets PC0...7, i.e. pin 14... to LOW
    DDRC |= bitmask;  // sets PC0...7 (ADC0...7), i.e. pin 14... as output (i.e. pull down)
    TEN_TIMES_NOP; TEN_TIMES_NOP;  // 1.25 uS pulse duration
    DDRC &= ~bitmask;  // sets  PC0...7 (ADC0...7), i.e. pin 14... as input (i.e. tri-state)

    TEN_TIMES_NOP;  // 0.625 uS pause

    /* pull up pulse */
    PORTC |= bitmask;  // sets PC0...7, i.e. pin 14... to HIGH
    DDRC |= bitmask;  // sets PC0...7 (ADC0...7), i.e. pin 14... as output (i.e. pull up)
    TEN_TIMES_NOP; TEN_TIMES_NOP;  // 1.25 uS counter pulse duration
    DDRC &= ~bitmask;  // sets  PC0...7 (ADC0...7), i.e. pin 14... as input (i.e. tri-state)

    /* start counting */
    comparator_count = 0;

    sei();
    ACSR |= (1<<ACIE) | (1<<ACI);  // enable interrupt for analog comparator and delete possible comparator flag
  }  // for current channel
}

ISR(ANALOG_COMP_vect) {  //Komparator-Interrupt-Serviceroutine

  comparator_count++;  // counting the oscillations
}

In der Interrupt-Serviceroutine des Timers „ISR(TIMER2_COMPA_vect, ISR_NOBLOCK)“ kommt der Abschluss für die ggf. zuvor gestartete Messung im Programmablauf zuerst. Dann folgt der Start einer neuen Messung, indem der Schwingkreis durch einen negativen (pull down) und einen positiven (pull up) Impuls „angezupt“ wird. Das Auszählen geschieht in „ISR(ANALOG_COMP_vect)“. „TEN_TIMES_NOP“ ist ein Makro, das zehn leere Takte (6,25 μs bei 16MHz Takt) einschiebt. „comparator_count“, „measuring_count“ und „measurement_in_progress“ sind globale Variablen.

Den vollständigen Arduino-Sketch, der als Einstieg für Eure Anwendung gedacht ist, könnt Ihr hier herunterladen. Die Abtastfrequenz ist dort über die Konstanten „INTERRUPT_INTERVAL“ („Output Compare“-Wert des Timers), „SAMPLE_INTERVAL“ (Software-Teiler) und den Prescaler des Timers (32) auf 100Hz eingestellt. Das Zeitfenster je Sensor für das Auszählen der Schwingungen beträgt ca. 0,3 ms. Bei den oben erwähnten 280 kHz haben da ca. 80 Perioden Platz. Nicht mehr als 60 werden typischerweise gebraucht.

Es ist auch noch eine einfache Filterung des Messergebnisses implementiert (siehe „measurement_filtered[]“). Die dort vorkommende Konstante „ZERO_MEASUREMENT“ gibt die Anzahl der gezählten Schwingungen ohne Beeinflussung (kein Metall in der Nähe) an. Diese müsst Ihr an Eure Verhältnisse anpassen. Bei meiner Anwendung im Modellbahn-Gleis haben sich 32 ergeben. Bei der Testschaltung mit der größeren Induktivität und ohne Metall in der Nähe waren es 59. Je nach Güte der verwendeten Bauteile und der Nähe von Metallteilen im eingebauten Zustand, habt Ihr da wahrscheinlich andere Werte.

Die Programmteile, die durch den Compiler-Switch „SAMPLING“ aktiviert werden, geben Euch eine Messreihe von 512 Werten auf der seriellen Schnittstelle aus, die Ihr mit dem Seriellen Monitor oder dem Seriellen Plotter der Arduino-IDE anschauen könnt.

Ich habe übrigens erfreulicherweise nur eine geringe Temperaturempfindlichkeit feststellen können. Beim Testen der Schaltung zwischen 4 und 22 °C ergab sich bei ausreichend langer Temperaturanpassung aller Komponenten keine Veränderung der Zählwerte. Schnelle Temperaturwechsel führen vorübergehend (10-20 Minuten) zu Verschiebungen um bis zu vier Zähler.

Worauf ich Euch noch hinweisen möchte:

  • Wenn Ihr das Programm mit den Teilen für Eure spezielle Anwendung erweitert, müsst Ihr beachten, dass Timer 2 und der Komparator belegt sind. Bei der Verwendung von Bibliotheken müsst Ihr sicherstellen, dass diese Resourcen dort nicht auch verwendet werden.
  • Ihr dürft keine Funktionen verwenden, die länger als für wenige Mikrosekunden andere Interrupts (speziell den Komparator-Interrupt) sperren. Der standardmäßig implementierte Systemzähler, der den Timer 0 benutzt und die Funktionen delay(), millis() etc. versorgt, ist gerade noch tolerierbar. Er verursacht alle paar Messungen ein „Verschlucken“ eines einzelnen Komparator-Interrupts. Der Zählwert ist dann also eins niedriger als er sein sollte. Wenn Ihr diesen kleinen zusätzlichen Jitter vermeiden wollt, müsst Ihr bei Beginn einer Messung (measurement_in_progress = true;) den Timer0-Interrupt sperren (TIMSK0 sichern und dann zu Null setzen) und nach Ende einer Messung (measurement_in_progress = false;) wieder zulassen (TIMSK0 wieder herstellen). Die Funktionen delay() etc. sind dann wahrscheinlich nicht mehr so genau.
    Auch die Funktionen für die serielle Schnittstelle hauen mit ihren Interrupts wahrscheinlich dazwischen. Am besten erzeugt Ihr seriellen I/O nur dann, wenn Ihr die Messungen gerade nicht braucht.
  • Die Anordnung entspricht wahrscheinlich nicht den gesetzlichen EMV-Anforderungen. Wenn man mit einem UKW-Radio bis auf ca. 30 cm rangeht und die Antenne maximal günstig zum Einkoppeln der Störung ausrichtet, fängt es im Lautsprecher zu prasseln an. Eine Störung von Bluetooth, WLAN, DECT oder Mobiltelefon konnte ich nicht feststellen.
  • Der Sensor bzw. seine Leitung fangen ggf. auch Störungen von außen ein. Dies kann in den Zählungen zu Ausreissern nach oben führen. Eine probate Methode der Störunterdrückung ist hier das Abschneiden des Zählwertes auf den maximal vorkommenden Wert (siehe „ZERO_MEASUREMENT“ im Sketch).

Viel Erfolg bei der Verwendung des Sensors!

Wollt Ihr einen Kommentar loswerden oder habt Ihr eine Frage? Schickt mir eine Mail