Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

DIY gevoelige Arduino IB metaaldetector met discriminatie

Componenten en benodigdheden

Arduino Nano R3
× 1
Adafruit Standaard LCD - 16x2 Wit op Blauw
× 1
TL081 operationele versterker-IC
× 1
Luidspreker:0,25 W, 8 ohm
× 1
Transistor-NPN voor algemeen gebruik
× 1
Zoekspoelen
× 2
Weerstanden, condensatoren
× 1

Apps en online services

Arduino IDE

Over dit project

Deze keer laat ik je zien hoe je een gevoelige metaaldetector maakt die ook onderscheid kan maken tussen ferro en non-ferro materialen. De gevoeligheid is bevredigend, aangezien het een relatief eenvoudig apparaat is.

Dit project wordt gesponsord door PCBgogo:

https://www.pcbgogo.com/promo/from_MirkoPavleskiMK

Dit is een voortzetting van het project van David Crocker, gepresenteerd op het Arduino CC Forum in 2013. Ik besloot de code te testen omdat ik geen enkel bewijs (foto of video) kon vinden dat deze metaaldetector door iemand is gemaakt en goed werkt.

Eerst heb ik een basisversie gemaakt met de code gepresenteerd op GitHub, om zeker te zijn van de functionaliteit van het apparaat en vervolgens heb ik de code geüpgraded zodat deze een hoorbaar signaal heeft, en op een 16 op 2 LCD-scherm visuele informatie over het type van object gedetecteerd (ferro- of non-ferromateriaal) en LCD-staafdiagram voor de nabijheid van gedetecteerde objecten.

Het apparaat is heel eenvoudig te bouwen en bestaat uit slechts een paar componenten:

- Arduino Nano-microcontroller

- Operationele versterker (in mijn geval LT1677, maar je kunt TL081 of 741) gebruiken

- Weinig weerstanden en condensatoren

- Kleine transistor en luidspreker

- LCD-scherm

- 3 schakelaars

- Potentiometer

- Batterij

- En zoekspoelen

Dit is een VLF (zeer lage frequentie) Inductie Balance-detectortechnologie en bevat twee identieke spoelen:zender- en ontvangerspoel. Zoals bij alle inductie-balansdetectoren, is de spoelbalans erg kritisch. De potentiometer wordt gebruikt om de kleine 90 graden uit-fase component van het signaal op nul te zetten. (de in-fase component wordt opgeheven door de relatieve plaatsing van de spoelen in de typische IB-detectorstijl aan te passen). Elk van de spoelen is op een lichaam van 11 cm gewikkeld met behulp van 64 windingen van 0,5 mm^2 geëmailleerd koperdraad in een D-vorm, wikkelde er tape omheen, schermde ze af met aluminiumfolie gebonden met vertind koperdraad (zorg ervoor dat er een kleine opening overblijft zodat het scherm gedraagt ​​zich niet als een kortgesloten bocht), en bond ze vast op een plastic plaat.

We moeten eerst de parallelle resonantiefrequentie van het primaire spoel-condensatorcircuit bepalen met behulp van een van de vele online rekenmachines. Ik heb het gemeten met een oscilloscoop, maar als je je aan de bovenstaande afmetingen houdt, is het precies 7,64 kHz, dus je kunt direct de waarde invoeren die in de code staat. In het geval van een andere waarde van de resonantiefrequentie, moeten we een passende wijziging aanbrengen in de code in de wachtrij:

#define TIMER1_TOP (249) // fijnafstemming van de frequentie

Zoals je in de video kunt zien, zijn de resultaten verrassend goed. Zonder de aanwezigheid van een metaal is het apparaat perfect stabiel. Het bereik is relatief groot en bijvoorbeeld een metalen deksel met een diameter van 15 cm wordt gedetecteerd op een afstand van meer dan 30 cm. Grotere metalen voorwerpen worden gedetecteerd op een afstand van meer dan 40-50 cm. We kunnen een kleine munt op een afstand van 15 cm in de lucht detecteren. Voor de voeding gebruik ik twee lithium batterijen die in serie geschakeld zijn (7,4 volt) en deze spanning wordt aangesloten op de Vin ingang van de Arduino. Het verbruik is niet hoger dan 20mA, dus batterijen gaan erg lang mee. De video beschrijft in detail de constructie van het hele apparaat.

Dit zijn slechts voorlopige resultaten. Er is een mogelijkheid om de gevoeligheid aanzienlijk te verbeteren door een vermogens-MOSFET-transistor in te voegen voor het aansturen van de Tx-spoel, maar ik zal het testen en presenteren in een van de volgende video's.

Code

  • Arduino-code
  • LcdBarGraph lib.
Arduino-codeArduino
// Inductie balans metaaldetector// We draaien de CPU op 16MHz en de ADC klok op 1MHz. De ADC-resolutie wordt bij deze snelheid teruggebracht tot 8 bits.// Timer 1 wordt gebruikt om de systeemklok te delen door ongeveer 256 om een ​​blokgolf van 62,5 kHz te produceren. // Dit wordt gebruikt om timer 0 aan te sturen en ook om ADC-conversies te activeren.// Timer 0 wordt gebruikt om de output van timer 1 te delen door 8, wat een 7.8125kHz-signaal oplevert voor het aansturen van de zendspoel.// Dit geeft ons 16 ADC klokcycli voor elke ADC-conversie (het duurt eigenlijk 13,5 cycli), en we nemen 8 monsters per cyclus van de spoelaandrijfspanning.// De ADC implementeert vier fasegevoelige detectoren met intervallen van 45 graden. Door 4 in plaats van slechts 2 te gebruiken, kunnen we de derde harmonische van de// spoelfrequentie annuleren.// Timer 2 wordt gebruikt om een ​​toon voor het oorstuk of de headset te genereren.// Andere verdelingsverhoudingen voor timer 1 zijn mogelijk, vanaf ongeveer 235 naar boven.// Bedrading:// Sluit digitale pin 4 (alias T0) aan op digitale pin 9// Sluit digitale pin 5 via weerstand aan op primaire spoel en afstemcondensator// Sluit uitgang van ontvangstversterker aan op analoge pin 0. Uitgang van ontvangst versterker moet worden beïnvloed tot ongeveer de helft van de analoge referentie.// Als u USB-voeding gebruikt, wijzigt u de analoge referentie naar de 3,3V-pin, omdat er te veel ruis op de +5V-rail is om een ​​goede gevoeligheid te krijgen. #include  #include #define max_ampAverage 200LiquidCrystal lcd(6, 7, 10, 11, 12, 13);LcdBarGraph lbg(&lcd, 16, 0, 1); #define TIMER1_TOP (259) // kan dit aanpassen om de frequentie fijn af te stemmen om de spoel af te stemmen (zie hierboven) #define USE_3V3_AREF (1) // ingesteld op 1 van draaien op een Arduino met USB-voeding, 0 voor een embedded atmega28p zonder 3.3V-voeding beschikbaar// Digitale pindefinities// Digitale pin 0 niet gebruikt, maar als we de seriële poort gebruiken voor foutopsporing, dan is het seriële invoerconst int debugTxPin =1; // zendpin gereserveerd voor debuggingconst int encoderButtonPin =2; // encoderknop, ook IN0 voor het ontwaken uit de slaapmodusconst int earpiecePin =3; // oortelefoon, ook bekend als OCR2B voor toongeneratieconst int T0InputPin =4;const int coilDrivePin =5;const int LcdRsPin =6;const int LcdEnPin =7;const int LcdPowerPin =8; // LCD-voeding en achtergrondverlichting inschakelenconst int T0OutputPin =9;const int lcdD4Pin =10;const int lcdD5Pin =11; // pinnen 11-13 ook gebruikt voor ICSPconst int LcdD6Pin =12;const int LcdD7Pin =13;// Analoge pindefinitiesconst int receiverInputPin =0;const int encoderAPin =A1;const int encoderBpin =A2;// Analoge pinnen 3-5 niet gebruikt// Variabelen die alleen worden gebruikt door de ISRint16_t bins[4]; // bins die worden gebruikt om ADC-metingen te accumuleren, één voor elk van de 4 fasensuint16_t numSamples =0;const uint16_t numSamplesToAverage =1024;// Variabelen gebruikt door de ISR en daarbuiten vluchtige int16_t gemiddelden [4]; // als we genoeg metingen in de bakken hebben verzameld, kopieert de ISR ze naar hier en begint opnieuw vluchtig uint32_t ticks =0; // systeemtick-teller voor tijdwaarnemingvluchtige bool sampleReady =false; // geeft aan dat de array met gemiddelden is bijgewerkt// Variabelen die alleen buiten de ISRint16_t calib[4] worden gebruikt; // waarden (ingesteld tijdens kalibratie) die we aftrekken van de gemiddeldenvluchtige uint8_t lastctr;vluchtige uint16_t misses =0; // dit telt hoe vaak de ISR te laat is uitgevoerd. Moet op nul blijven als alles goed werkt.const double halfRoot2 =sqrt(0.5);const double quarterPi =3.1415927/4.0;const double radiansToDegrees =180,0/3.1415927;// De ADC-sample en hold vindt plaats 2 ADC-klokken (=32 systeem klokken) nadat de overloopvlag van timer 1 is ingesteld.// Dit introduceert een kleine fasefout, waarvoor we corrigeren in de berekeningen.const float phaseAdjust =(45,0 * 32,0)/(float)(TIMER1_TOP + 1);floatdrempel =5,0; // lager =grotere gevoeligheid. 10 is zo goed als bruikbaar met een goed uitgebalanceerde spoel. // De gebruiker kan dit aanpassen via een pot of roterende encoder.void setup(){ lcd.begin(16, 2);// LCD 16X2 pinMode(encoderButtonPin, INPUT_PULLUP); digitalWrite (T0OutputPin, LAAG); pinMode (T0OutputPin, OUTPUT); // pulspen van timer 1 gebruikt om timer 0 digitalWrite (coilDrivePin, LOW) te voeden; pinMode (spoelDrivePin, UITGANG); // timer 0-uitgang, blokgolf om zendspoel cli (); // Stop timer 0 die is ingesteld door de Arduino-kern TCCR0B =0; // stop de timer TIMSK0 =0; // uitschakelen interrupt TIFR0 =0x07; // wis alle wachtende interrupts // Stel ADC in om kanaal 0 te activeren en te lezen op timer 1 overflow #if USE_3V3_AREF ADMUX =(1 <> 8); OCR1AL =(TIMER1_TOP/2 &0xFF); ICR1H =(TIMER1_TOP>> 8); ICR1L =(TIMER1_TOP &0xFF); TCNT1H =0; TCNT1L =0; TIFR1 =0x07; // wis alle wachtende interrupt TIMSK1 =(1 <
 15000) *p =15000; } anders { *p -=val; als (*p <-15000) *p =-15000; } if (ctr ==7) { ++numSamples; if (numSamples ==numSamplesToAverage) { numSamples =0; if (!sampleReady) // als het vorige voorbeeld is verbruikt { memcpy((void*)averages, bins, sizeof(averages)); sampleReady =waar; } memset(bins, 0, sizeof(bins)); } }}void loop(){ while (!sampleReady) {} uint32_t oldTicks =ticks; if (digitalRead (encoderButtonPin) ==LAAG) { // Kalibreerknop ingedrukt. We slaan de huidige fasedetectoruitgangen op en trekken ze af van toekomstige resultaten. // Hierdoor kunnen we de detector gebruiken als de spoel enigszins uit balans is. // Het zou beter zijn om meerdere monsters te nemen in plaats van er maar één te nemen. for (int i =0; i <4; ++i) { calib[i] =gemiddelden[i]; } sampleReady =onwaar; Serial.print("Gekalibreerd:"); lcd.setCursor(0,0); lcd.print("Kalibratie... "); for (int i =0; i <4; ++i) { Serial.write(' '); Serial.print(calib[i]); lcd.setCursor(0,1); lcd.print(' '); lcd.print(calib[4]); lcd.print(" "); } Serieel.println(); } else { for (int i =0; i <4; ++i) { gemiddelden[i] -=calib[i]; } const dubbel f ​​=200,0; // Masseer de resultaten om de gevoeligheid voor de 3e harmonische te elimineren en deel door 200 dubbele bin0 =(gemiddelden[0] + halfRoot2 * (gemiddelden[1] - gemiddelden[3]))/f; dubbele bin1 =(gemiddelden[1] + halfRoot2 * (gemiddelden[0] + gemiddelden[2]))/f; dubbele bin2 =(gemiddelden[2] + halfRoot2 * (gemiddelden[1] + gemiddelden[3]))/f; dubbele bin3 =(gemiddelden[3] + halfRoot2 * (gemiddelden[2] - gemiddelden[0]))/f; sampleReady =onwaar; // we zijn klaar met het lezen van de gemiddelden, dus de ISR is vrij om ze opnieuw te overschrijven double amp1 =sqrt((bin0 * bin0) + (bin2 * bin2)); dubbele amp2 =sqrt((bin1 * bin1) + (bin3 * bin3)); dubbel ampAverage =(amp1 + amp2)/2.0; // De ADC-sample/hold vindt plaats 2 klokken na de timeroverloop dubbele fase1 =atan2(bin0, bin2) * radialenToDegrees + 45.0; dubbele fase2 =atan2(bin1, bin3) * radialenToDegrees; if (fase1> fase2) { dubbele temp =fase1; fase1 =fase2; fase2 =temperatuur; } dubbele phaseAverage =((phase1 + phase2)/2.0) - phaseAdjust; if (phase2 - phase1> 180,0) { if (phaseAverage <0.0) { phaseAverage +=180,0; } else { phaseAverage -=180.0; } } // Druk voor diagnostische doeleinden de individuele baktellingen en de 2 onafhankelijk berekende winsten en fasen af ​​Serial.print(misses); Serieel.schrijven(' '); if (bin0>=0.0) Serial.write(' '); Serial.print(bin0, 2); Serieel.schrijven(' '); if (bin1>=0.0) Serial.write(' '); Serial.print(bak1, 2); Serieel.schrijven(' '); if (bin2>=0.0) Serial.write(' '); Serial.print(bak2, 2); Serieel.schrijven(' '); if (bin3>=0.0) Serial.write(' '); Serial.print(bin3, 2); Serieel.print(" "); Serial.print(amp1, 2); Serieel.schrijven(' '); Serial.print(amp2, 2); Serieel.schrijven(' '); if (fase1>=0.0) Serial.write(' '); Serial.print(fase1, 2); Serieel.schrijven(' '); if (fase2>=0.0) Serial.write(' '); Serial.print(fase2, 2); Serieel.print(" "); // Druk de uiteindelijke amplitude en fase af, die we gebruiken om te beslissen wat (als er iets is) we hebben gevonden) if (ampAverage>=0.0) Serial.write(' '); Serial.print(ampAverage, 1); Serieel.schrijven(' '); lcd.setCursor(0,0); lcd.print(" "); lcd.print(ampAverage); lcd.setCursor(0,1); lbg.drawValue(ampAverage, max_ampAverage); if (phaseAverage>=0.0) Serial.write(' '); Serial.print((int)phaseAverage); // Bepaal wat we hebben gevonden en vertel de gebruiker if (ampAverage>=threshold) { // Indien in lijn gehouden met het midden van de spoel:// - non-ferrometalen geven een negatieve faseverschuiving, b.v. -90deg voor dik koper of aluminium, een koperen olijf, -30deg voor dun aluminium. // Ferrometalen geven nul faseverschuiving of een kleine positieve faseverschuiving. // Dus we zeggen dat alles met een faseverschuiving onder -20deg non-ferro is. if (phaseAverage <-20.0) { Serial.print(" Non-ferro"); lcd.setCursor(0,0); lcd.print("Non-Fereuze"); } else { Serial.print("Ijzerhoudend"); lcd.setCursor(0,0); lcd.print("Ijzerhoudend"); } float temp =ampAverage; int thisPitch =kaart (temp, 10, 200, 100, 1500); toon(3, thisPitch,120); while (temp>
 drempel) { Serial.write('!'); temp -=(drempel/2); } } Serieel.println(); } while (ticks - oldTicks <8000) { } }
LcdBarGraph lib.C/C++
Geen voorbeeld (alleen downloaden).

Schema's


Productieproces

  1. Eenvoudige doe-het-zelf huilende babydetector met Raspberry Pi
  2. DIY eenvoudigste IV9 Numitron-klok met Arduino
  3. Arduino-gyroscoopspel met MPU-6050
  4. DIY Gevoelige ADXL335 Aardbevingsdetector
  5. DIY voltmeter met Arduino en een Nokia 5110-display
  6. MobBob:doe-het-zelf Arduino-robot bestuurd door Android-smartphone
  7. DIY eenvoudig meetwiel met roterende encoder
  8. IoT-meter met Arduino, Yaler en IFTTT
  9. DIY-luchtkwaliteitsmonitor met Sharp GP2Y1010AU0F-sensor
  10. Handheld geigerteller met Arduino Nano
  11. DIY Arduino 1D Pong-spel met WS2812 LED-strip