識別力のあるDIYに敏感なArduinoIB金属探知機
コンポーネントと消耗品
> |
| × | 1 | |||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 2 | ||||
| × | 1 |
アプリとオンラインサービス
> |
|
このプロジェクトについて
今回は、鉄と非鉄の材料を区別できる高感度金属探知機の作り方を紹介します。比較的シンプルなデバイスなので、感度は十分です。
このプロジェクトはPCBgogoによって後援されています:
https://www.pcbgogo.com/promo/from_MirkoPavleskiMK
これは、2013年にArduinoCCフォーラムで発表されたDavidCrockerのプロジェクトの続きです。この金属探知機が誰かによって作成され、うまく機能しているという証拠(写真またはビデオ)が見つからなかったため、コードをテストすることにしました。
>最初に、GitHubに表示されたコードを使用して基本バージョンを作成し、デバイスの機能を確認しました。次に、コードをアップグレードして、信号が聞こえるようにし、16対2のLCDディスプレイにタイプに関する視覚情報を表示しました。検出されたオブジェクト(鉄または非鉄材料)および検出されたオブジェクトの近接度のLCD棒グラフ。
デバイスの構築は非常に簡単で、いくつかのコンポーネントのみで構成されています:
-ArduinoNanoマイクロコントローラー
-オペアンプ(私の場合はLT1677ですが、TL081または741を使用できます)
-抵抗とコンデンサはほとんどありません
-小さなトランジスタとスピーカー
-LCDディスプレイ
-3つのスイッチ
-ポテンショメータ
-バッテリー
-そしてサーチコイル
<図>これはVLF(超低周波)誘導バランス検出器技術であり、送信機コイルと受信機コイルの2つの同一のコイルが含まれています。すべての誘導バランス検出器と同様に、コイルバランスは非常に重要です。ポテンショメータは、信号の小さな90度の位相のずれた成分をゼロにするために使用されます。 (同相成分は、一般的なIB検出器スタイルでコイルの相対配置を調整することによって無効になります)。各コイルは、D字型の0.5mm ^ 2エナメル銅線を64ターン使用して、11cmの本体に巻かれ、テープを巻き付け、錫メッキされた銅線で結合されたアルミホイルを使用してふるいにかけられます(小さな隙間を残すように注意してください。画面は短い回転のようには動作しません)、プラスチックプレートにタイラップします。
<図>最初に、多くのオンライン計算機の1つを使用して、一次コイルコンデンサ回路の並列共振周波数を決定する必要があります。オシロスコープで測定しましたが、上記の寸法に従えば、正確に7.64 kHzになるので、コードで指定された値を直接入力できます。共振周波数の別の値の場合、キュー内のコードに適切な変更を加える必要があります。
#define TIMER1_TOP(249)//周波数を微調整する
ビデオで見ることができるように、結果は驚くほど良いです。金属がなくても、デバイスは完全に安定しています。範囲は比較的広く、例えば、直径15cmの金属カバーが30cm以上の距離で検出されます。 40〜50cmを超える距離では、より大きな金属物体が検出されます。空中で15cmの距離にある小さなコインを検出することができます。電源には直列に接続された2つのリチウム電池(7.4ボルト)を使用し、この電圧はArduinoのVin入力に接続されています。消費量は20mAを超えないので、バッテリーは非常に長持ちします。ビデオでは、デバイス全体の構造について詳しく説明しています。
これらは暫定的な結果にすぎません。 Txコイルを駆動するパワーMOSFETトランジスタを挿入することで感度を大幅に向上させる可能性がありますが、以下の動画でテストして紹介します。
コード
- Arduinoコード
- LcdBarGraphlib。
Arduinoコード Arduino
//誘導バランス金属探知機// CPUは16MHz、ADCクロックは1MHzで動作します。この速度では、ADCの分解能は8ビットに低下します。//タイマー1は、システムクロックを約256で除算して、62.5kHzの方形波を生成するために使用されます。 //これは、タイマー0を駆動し、ADC変換をトリガーするために使用されます。//タイマー0は、タイマー1の出力を8で除算するために使用され、送信コイルを駆動するための7.8125kHzの信号を生成します。//これにより、16個のADCが生成されます。各ADC変換のクロックサイクル(実際には13.5サイクルかかります)、およびコイル駆動電圧のサイクルごとに8つのサンプルを取得します。//ADCは45度間隔で4つの位相敏感検出器を実装します。 2の代わりに4を使用すると、//コイル周波数の3次高調波をキャンセルできます。//タイマー2は、イヤピースまたはヘッドセットのトーンを生成するために使用されます。//タイマー1の他の分割比は、約//配線://デジタルピン4(別名T0)をデジタルピン9に接続//デジタルピン5を抵抗を介して一次コイルとチューニングコンデンサに接続//受信アンプからの出力をアナログピン0に接続アンプはアナログ基準の約半分にバイアスする必要があります。//USB電源を使用する場合は、+ 5Vレールのノイズが多すぎて感度が良くないため、アナログ基準を3.3Vピンに変更します。#include#include #define max_ampAverage 200LiquidCrystal lcd(6、7、10、11、12、13); LcdBarGraph lbg(&lcd、16、0、1); #define TIMER1_TOP(259)//これを調整して周波数を微調整し、コイルを調整できます(上記を参照)#define USE_3V3_AREF(1)// USB電源を備えたArduinoで実行する場合は1に設定し、組み込みの場合は0に設定します3.3V電源が利用できないatmega28p //デジタルピンの定義//デジタルピン0は使用されていませんが、デバッグにシリアルポートを使用している場合は、シリアルinputconst int debugTxPin =1; //デバッグ用に予約された送信ピンconstintエンコーダボタンピン=2; //エンコーダボタン、スリープモードから復帰するためのIN0const int earpiecePin =3; //イヤピース、別名OCR2B(トーン生成用)const int T0InputPin =4; const intcoilDrivePin =5; const int LcdRsPin =6; const int LcdEnPin =7; const int LcdPowerPin =8; // LCD電源とバックライトenableconstint T0OutputPin =9; const int lcdD4Pin =10; const int lcdD5Pin =11; //ピン11〜13はICSPにも使用されますconst int LcdD6Pin =12; const int LcdD7Pin =13; //アナログピンの定義constint ReceiverInputPin =0; const int encodeAPin =A1; const int encodeBpin =A2; //アナログピン3-5未使用// ISRint16_t bins [4]でのみ使用される変数。 // ADC読み取り値を累積するために使用されるビン(4つのフェーズごとに1つ)suint16_t numSamples =0; const uint16_t numSamplesToAverage =1024; // ISRおよびその外部で使用される変数int16_taverages [4]; //ビンに十分な読み取り値が蓄積されると、ISRはそれらをここにコピーし、再び揮発性のuint32_t ticks =0を開始します。 //計時用のシステムティックカウンターvolatilebool sampleReady =false; //平均配列が更新されたことを示します// ISRint16_t calib [4]の外部でのみ使用される変数; //平均から減算する値(キャリブレーション中に設定)volatile uint8_t lastctr; volatile uint16_t misses =0; //これは、ISRの実行が遅すぎた回数をカウントします。すべてが正常に機能している場合は、ゼロのままにする必要があります。constdoublehalfRoot2 =sqrt(0.5); const double QuarterPi =3.1415927 / 4.0; const double radiansToDegrees =180.0 / 3.1415927; // ADCのサンプルとホールドは2つのADCクロックで発生します(=32システムクロック)タイマー1オーバーフローフラグが設定された後//これにより、わずかな位相エラーが発生し、計算で調整されます.const float phaseAdjust =(45.0 * 32.0)/(float)(TIMER1_TOP + 1); float threshold =5.0; //低い=感度が高い。 10は、バランスの取れたコイルでほぼ使用できます。 //ユーザーは、ポットまたはロータリーエンコーダーを介してこれを調整できます。voidsetup(){lcd.begin(16、2); // LCD 16X2 pinMode(encoderButtonPin、INPUT_PULLUP); digitalWrite(T0OutputPin、LOW); pinMode(T0OutputPin、OUTPUT); //タイマー0に供給するために使用されるタイマー1からのパルスピンdigitalWrite(coilDrivePin、LOW); pinMode(coilDrivePin、OUTPUT); //タイマー0出力、送信コイルを駆動する方形波cli(); // Arduinoコアによって設定されたタイマー0を停止しますTCCR0B =0; //タイマーを停止しますTIMSK0 =0; //割り込みを無効にするTIFR0 =0x07; //保留中の割り込みをクリアします//タイマー1でチャネル0をトリガーして読み取るようにADCを設定します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; //保留中の割り込みをクリアしますTIMSK1 =(1 < 15000)* p =15000; } else {* p- =val; if(* p <-15000)* p =-15000; } if(ctr ==7){++ numSamples; if(numSamples ==numSamplesToAverage){numSamples =0; if(!sampleReady)//前のサンプルが消費された場合{memcpy((void *)averages、bins、sizeof(averages)); sampleReady =true; } memset(bins、0、sizeof(bins)); }}} void loop(){while(!sampleReady){} uint32_t oldTicks =ticks; if(digitalRead(encoderButtonPin)==LOW){//押されたボタンを調整します。現在の位相検出器の出力を保存し、将来の結果からそれらを差し引きます。 //これにより、コイルのバランスがわずかにずれている場合に検出器を使用できます。 // 1つだけを取得するのではなく、複数のサンプルを活用する方がよいでしょう。 for(int i =0; i <4; ++ i){calib [i] =averages [i]; } sampleReady =false; Serial.print( "Calibrated:"); lcd.setCursor(0,0); lcd.print( "Calibrating ..."); 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( ""); } Serial.println(); } else {for(int i =0; i <4; ++ i){averages [i]-=calib [i]; } const double f =200.0; //結果をマッサージして3次高調波に対する感度を排除し、200で除算しますdouble bin0 =(averages [0] + halfRoot2 *(averages [1] --averages [3]))/ f; double bin1 =(averages [1] + halfRoot2 *(averages [0] + averages [2]))/ f; double bin2 =(averages [2] + halfRoot2 *(averages [1] + averages [3]))/ f; double bin3 =(averages [3] + halfRoot2 *(averages [2] --averages [0]))/ f; sampleReady =false; //平均の読み取りが終了したので、ISRはそれらを自由に上書きできますdouble amp1 =sqrt((bin0 * bin0)+(bin2 * bin2)); double amp2 =sqrt((bin1 * bin1)+(bin3 * bin3)); double ampAverage =(amp1 + amp2)/2.0; // ADCのサンプル/ホールドは、タイマーオーバーフローの2クロック後に発生しますdouble phase1 =atan2(bin0、bin2)* radiansToDegrees + 45.0; double phase2 =atan2(bin1、bin3)* radiansToDegrees; if(phase1> phase2){double temp =phase1;フェーズ1 =フェーズ2; phase2 =温度; } double phaseAverage =((phase1 + phase2)/2.0)-phaseAdjust; if(phase2-phase1> 180.0){if(phaseAverage <0.0){phaseAverage + =180.0; } else {phaseAverage- =180.0; }} //診断の目的で、個々のビンカウントと2つの独立して計算されたゲインとフェーズを出力しますSerial.print(misses); Serial.write( ''); if(bin0> =0.0)Serial.write( ''); Serial.print(bin0、2); Serial.write( ''); if(bin1> =0.0)Serial.write( ''); Serial.print(bin1、2); Serial.write( ''); if(bin2> =0.0)Serial.write( ''); Serial.print(bin2、2); Serial.write( ''); if(bin3> =0.0)Serial.write( ''); Serial.print(bin3、2); Serial.print( ""); Serial.print(amp1、2); Serial.write( ''); Serial.print(amp2、2); Serial.write( ''); if(phase1> =0.0)Serial.write( ''); Serial.print(phase1、2); Serial.write( ''); if(phase2> =0.0)Serial.write( ''); Serial.print(phase2、2); Serial.print( ""); //最終的な振幅と位相を出力します。これを使用して、(もしあれば)何を見つけたかを決定します)if(ampAverage> =0.0)Serial.write( ''); Serial.print(ampAverage、1); Serial.write( ''); 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); //見つけたものを決定し、次の場合にユーザーに通知します(ampAverage> =threshold){//コイルの中心に沿って保持すると://-非鉄金属は負の位相シフトを与えます。 -厚い銅またはアルミニウムの場合は90度、銅オリーブの場合は-30度、薄いアルミニウムの場合は-30度。 //鉄金属は、ゼロ位相シフトまたは小さな正の位相シフトを示します。 //したがって、位相シフトが-20度未満のものはすべて非鉄であると言えます。 if(phaseAverage <-20.0){Serial.print( "非鉄"); lcd.setCursor(0,0); lcd.print( "NonFerous"); } else {Serial.print( "Ferrous"); lcd.setCursor(0,0); lcd.print( "Ferrous"); } float temp =ampAverage; int thisPitch =map(temp、10、200、100、1500);トーン(3、thisPitch、120); while(temp> threshold){Serial.write( '!'); temp-=(threshold / 2); }} Serial.println(); } while(ticks-oldTicks <8000){}}
LcdBarGraphlib。 C / C ++
プレビューなし(ダウンロードのみ)。
回路図
製造プロセス
- RaspberryPiを使用した簡単なDIY赤ちゃん泣き検出器
- Arduinoを使用したDIYの最もシンプルなIV9Numitron時計
- MPU-6050を搭載したArduinoジャイロスコープゲーム
- DIYに敏感なADXL335地震検知器
- ArduinoとNokia5110ディスプレイを備えたDIY電圧計
- MobBob:Androidスマートフォンで制御されるDIY Arduino Robot
- ロータリーエンコーダー付きDIYシンプル測定ホイール
- Arduino、Yaler、IFTTTを使用したIoTゲージ
- シャープなGP2Y1010AU0Fセンサーを備えたDIY空気品質モニター
- ArduinoNanoを搭載したハンドヘルドガイガーカウンター
- WS2812LEDストリップを備えたDIYArduino1Dポンゲーム