亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

DIY 灵敏的 Arduino IB 金属探测器,具有辨别力

组件和用品

Arduino Nano R3
× 1
Adafruit 标准 LCD - 16x2 蓝底白字
× 1
TL081 运算放大器 IC
× 1
扬声器:0.25W,8 ohms
× 1
通用晶体管 NPN
× 1
搜索线圈
× 2
电阻、电容
× 1

应用和在线服务

Arduino IDE

关于这个项目

这次我将向您展示如何制作一个灵敏的金属探测器,同时还能区分黑色金属和有色金属材料。灵敏度是令人满意的,因为它是一个相对简单的设备。

该项目由PCBgogo赞助:

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

这是 David Crocker 于 2013 年在 Arduino CC 论坛上展示的项目的延续。我决定测试它的代码,因为我没有找到任何证据(图片或视频)表明这个金属探测器是由任何人制造的并且运行良好。

首先,我使用 GitHub 上提供的代码制作了一个基本版本,以确保设备的功能,然后我升级了代码,使其具有声音信号,并在 16 合 2 LCD 上显示有关设备类型的视觉信息检测到的物体(黑色金属或有色金属)和检测物体接近度的 LCD 条形图。

该设备的构建非常简单,仅由几个组件组成:

- Arduino Nano 微控制器

- 运算放大器(在我的情况下是 LT1677,但您可以使用 TL081 或 741)

- 很少的电阻和电容

- 小晶体管和扬声器

- 液晶显示

- 3个开关

- 电位器

- 电池

- 和搜索线圈

这是一种 VLF(极低频)感应平衡检测器技术,包含两个相同的线圈:发射器和接收器线圈。与所有感应平衡探测器一样,线圈平衡非常关键。电位计用于将信号的小 90 度异相分量归零。 (在典型的 IB 检测器样式中,通过调整线圈的相对位置可以使同相分量为零)。每个线圈用 64 匝 0.5mm^2 漆包铜线 D 形缠绕在 11cm 的主体上,用胶带缠绕它们,用镀锡铜线包裹的铝箔屏蔽它们(注意留出小间隙,以便屏幕不会像短路一样),并将它们绑在塑料板上。

我们首先需要使用许多在线计算器之一来确定初级线圈电容器电路的并联谐振频率。我用示波器测量了它,但如果你遵守上面给出的尺寸,它将正好是 7.64 kHz,所以你可以直接输入代码中给出的值。在谐振频率为另一个值的情况下,我们需要在队列中的代码中做一个适当的改变:

#define TIMER1_TOP (249) // 微调频率

正如您在视频中看到的,结果出奇的好。没有金属的存在,设备非常稳定。范围比较大,比如直径15cm的金属盖在30cm以上的距离被检测到。在大于 40-50 厘米的距离处检测到较大的金属物体。我们可以在空气中 15 厘米的距离内检测到一枚小硬币。我使用两个串联的锂电池作为电源(7.4 伏),这个电压连接到 Arduino 的 Vin 输入端。消耗不超过 20mA,因此电池可以使用很长时间。视频详细介绍了整个装置的构造。

这些只是初步结果。有可能通过插入一个功率 MOSFET 晶体管来驱动 Tx 线圈来显着提高灵敏度,但我将在以下视频之一中进行测试和展示。

代码

  • Arduino 代码
  • LcdBarGraph 库。
Arduino 代码Arduino
// 感应平衡金属探测器// 我们以 16MHz 的频率运行 CPU,以 1MHz 的频率运行 ADC 时钟。在此速度下,ADC 分辨率降低到 8 位。// 定时器 1 用于将系统时钟除以约 256 以产生 62.5kHz 方波。 // 这用于驱动定时器 0 并触发 ADC 转换。// 定时器 0 用于将定时器 1 的输出除以 8,从而提供 7.8125kHz 信号来驱动发射线圈。// 这为我们提供了 16 个 ADC每个 ADC 转换的时钟周期(实际上需要 13.5 个周期),我们对线圈驱动电压的每个周期进行 8 个采样。// ADC 以 45 度的间隔实现四个相敏检测器。使用 4 而不仅仅是 2 允许我们取消 // 线圈频率的三次谐波。// 定时器 2 将用于为听筒或耳机生成音调。// 定时器 1 的其他分频比是可能的,从大约235向上。//接线://将数字引脚4(别名T0)连接到数字引脚9//将数字引脚5通过电阻连接到初级线圈和调谐电容器//将接收放大器的输出连接到模拟引脚0。接收输出放大器应该偏置到模拟参考的一半左右。//使用USB电源时,将模拟参考更改为3.3V引脚,因为+5V轨上的噪声太多以获得良好的灵敏度。#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) // 设置为 1 表示在带 USB 电源的 Arduino 上运行,0 表示嵌入式atmega28p 没有可用的 3.3V 电源// 数字引脚定义// 未使用数字引脚 0,但是如果我们使用串行端口进行调试,那么它是串行输入常量 int debugTxPin =1; // 传输引脚保留用于调试const int encoderButtonPin =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 电源和背光使能const int T0OutputPin =9;const int lcdD4Pin =10;const int lcdD5Pin =11; // 引脚 11-13 也用于 ICSPconst int LcdD6Pin =12;const int LcdD7Pin =13;// 模拟引脚定义const int receiverInputPin =0;const int encoderAPin =A1;const int encoderBpin =A2;// 模拟引脚 3-5未使用// 仅由 ISRint16_t bins[4] 使用的变量; // 用于累积 ADC 读数的 bin,4 个 phasesuint16_t numSamples =0 中的每一个对应一个 bin;const uint16_t numSamplesToAverage =1024;// ISR 和外部使用的变量 volatile int16_t averages[4]; // 当我们在 bin 中积累了足够的读数时,ISR 将它们复制到这里并再次启动 volatile uint32_t ticks =0; // 用于计时的系统滴答计数器 volatile bool sampleReady =false; // 表示平均值数组已更新// 仅在 ISRint16_t calib[4] 之外使用的变量; // 我们从平均值中减去的值(在校准期间设置)volatile uint8_t lastctr;volatile uint16_t misses =0; // 这会计算 ISR 执行太晚的次数。如果一切正常,则应保持为零。const double halfRoot2 =sqrt(0.5);const double quadquad =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 几乎可以与平衡良好的线圈一起使用。 // 用户可以通过电位器或旋转编码器进行调整。void setup(){ lcd.begin(16, 2);// LCD 16X2 pinMode(encoderButtonPin, INPUT_PULLUP);数字写入(T0OutputPin,低); pinMode(T0OutputPin, OUTPUT); // 来自定时器 1 的脉冲引脚用于馈送定时器 0 digitalWrite(coilDrivePin, LOW); pinMode(coilDrivePin, OUTPUT); //定时器0输出,方波驱动发射线圈cli(); // 停止由 Arduino 内核设置的定时器 0 TCCR0B =0; // 停止定时器 TIMSK0 =0; // 禁用中断 TIFR0 =0x07; // 清除任何挂起的中断 // 设置 ADC 以在定时器 1 溢出时触发和读取通道 0#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;如果 (*p <-15000) *p =-15000; } if (ctr ==7) { ++numSamples;如果(numSamples ==numSamplesToAverage){ numSamples =0; if (!sampleReady) // 如果之前的样本已经被消耗 { memcpy((void*)averages, bins, sizeof(averages));样品就绪 =真; } memset(bins, 0, sizeof(bins)); } }}void loop(){ while (!sampleReady) {} uint32_t oldTicks =ticks; if (digitalRead(encoderButtonPin) ==LOW) { // 校准按钮按下。我们保存当前的相位检测器输出并从未来的结果中减去它们。 // 如果线圈稍微不平衡,这让我们可以使用检测器。 // 最好是多次采样而不是只取一个。 for (int i =0; i <4; ++i) { calib[i] =averages[i];样品就绪 =假; Serial.print("校准:"); lcd.setCursor(0,0); lcd.print("校准中..."); for (int i =0; i <4; ++i) { Serial.write(' '); Serial.print(calib[i]); lcd.setCursor(0,1);液晶打印(''); lcd.print(calib[4]);液晶打印(“”); Serial.println(); } else { for (int i =0; i <4; ++i) { averages[i] -=calib[i];常量双 f =200.0; // 按摩结果以消除对三次谐波的敏感性,并除以 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;样品准备=假; // 我们已经读完了平均值,所以 ISR 可以自由地再次覆盖它们 double amp1 =sqrt((bin0 * bin0) + (bin2 * bin2));双 amp2 =sqrt((bin1 * bin1) + (bin3 * bin3));双 ampAverage =(amp1 + amp2)/2.0; // ADC 采样/保持发生在定时器溢出后 2 个时钟周期 double phase1 =atan2(bin0, bin2) * radiansToDegrees + 45.0;双相 2 =atan2(bin1, bin3) * radiansToDegrees;如果(阶段 1> 阶段 2){ 双温度 =阶段 1;阶段 1 =阶段 2;阶段 2 =温度; } double phaseAverage =((phase1 + phase2)/2.0) - phaseAdjust; if (phase2 - phase1> 180.0) { if (phaseAverage <0.0) { phaseAverage +=180.0; } else { phaseAverage -=180.0; } } // 出于诊断目的,打印单个 bin 计数和 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);液晶打印(“”);液晶打印(ampAverage); lcd.setCursor(0,1); lbg.drawValue(ampAverage, max_ampAverage); if (phaseAverage>=0.0) Serial.write(' '); Serial.print((int)phaseAverage); // 确定我们发现了什么并告诉用户 if (ampAverage>=threshold) { // 当与线圈中心保持一致时: // - 有色金属产生负相移,例如-90deg 适用于厚铜或铝,橄榄铜,-30deg 适用于薄铝。 //黑色金属产生零相移或小的正相移。 // 所以我们会说相移低于 -20 度的任何东西都是有色金属。如果(phaseAverage <-20.0){ Serial.print(“有色金属”); lcd.setCursor(0,0); lcd.print("有色金属"); } else { Serial.print("亚铁"); lcd.setCursor(0,0); lcd.print("黑色金属"); } 浮动温度 =ampAverage; int thisPitch =map (temp, 10, 200, 100, 1500);音调(3,这个音高,120);而(温度> 阈值){ Serial.write('!');温度-=(阈值/2); Serial.println(); } while (ticks - oldTicks <8000) { } }
LcdBarGraph lib.C/C++
无预览(仅限下载)。

示意图


制造工艺

  1. 使用 Raspberry Pi 的简单 DIY 婴儿哭闹检测器
  2. DIY 最简单的 IV9 Numitron 时钟与 Arduino
  3. Arduino Gyroscope Game with MPU-6050
  4. DIY 灵敏 ADXL335 地震探测器
  5. DIY 电压表与 Arduino 和诺基亚 5110 显示器
  6. MobBob:由 Android 智能手机控制的 DIY Arduino 机器人
  7. 带旋转编码器的DIY简易测量轮
  8. 带有 Arduino、Yaler 和 IFTTT 的物联网仪表
  9. 带夏普 GP2Y1010AU0F 传感器的 DIY 空气质量监测仪
  10. 带有 Arduino Nano 的手持盖革计数器
  11. 带 WS2812 LED 灯条的 DIY Arduino 1D 乒乓球游戏
  12. 带有 DSM501A 传感器的 Arduino 空气质量监测器