Introduction: How to Build a DIY Walkthrough Detector Using Arduino UNO
This project demonstrates a low-cost and sensitive walkthrough metal detector using the FG-3+ fluxgate magnetometer sensor paired with the Arduino UNO R4 WiFi. The device detects the presence of metal objects based on perturbations in the ambient magnetic field, a matrix display shows an exclamation mark "!" whenever a metal object is detected near the walkthrough detector.
Supplies
Step 1: About Fluxgate Magnetometers
Fluxgate magnetometers like the FG-3+ sensor offer high sensitivity and low noise level for detecting minute changes in magnetic fields. They are commonly used in geophysics and in security applications such as metal detection because they can precisely sense the magnetic disturbances caused by metallic objects.
The FG-3+ sensor by www.fgsensors.com provides stable and accurate magnetic field measurements and is well-suited for embedded platforms like Arduino, enabling development of compact, portable detection systems.
Step 2: Hardware Setup
- Position the FG-3+ sensor near the detector's walkthrough frame to sense metallic objects passing through.
- Connect the FG-3+ sensor signals to Arduino UNO R4 WiFi
Step 3: Firmware Functionality
Sensor Reading:
The sensor outputs a frequency proportional to the local magnetic field (typically from 40 kHz to 120 kHz). This frequency is measured using interrupt-driven counting logic.
Signal Filtering:
A moving average baseline is maintained to track ambient field conditions and smooth sensor output to avoid false triggers.
Metal Detection:
Sudden deviations beyond a configurable threshold relative to the baseline indicate a metal object presence.
Visual Alert:
The LED matrix displays "!" during detection events.
Step 4: Code
#include <Arduino_LED_Matrix.h>
const int sensorDig = 2; // Digital pin 2 for sensor input (interrupt pin)
unsigned int updateRate = 100; // Sensor update rate in ms
unsigned int measureTime = 100; // Sensor measure time in ms
volatile unsigned int intEnable = 0; // Interrupt counter enable flag
volatile unsigned long sensorDigCnt = 0; // Count of sensor signal changes
unsigned long prevMillis = 0; // For timing updates
float base_line = 0.0; // Moving average baseline
const float alpha = 0.1; // Smoothing factor for baseline
const float base_line_change = 10.0; // Threshold for significant change
const int N = 10; // Number of samples for peak event duration
int peakSamplesCount = 0; // Samples counted during peak event
bool inPeakEvent = false; // Flag: tracking a peak event?
float peakValue = 0.0; // Maximum deviation recorded during peak event
int state = 0; // State machine variable
// LED matrix setup
ArduinoLEDMatrix matrix;
const int matrixWidth = 12;
const int matrixHeight = 8;
// Alert sign bitmap 10x7 pixels (largest fitting design)
// A large exclamation mark ! with border
const uint8_t alertWidth = 10;
const uint8_t alertHeight = 7;
const uint8_t alertBitmap[alertHeight] = {
0b0000110000, // border top
0b0000110000, // | ! |
0b0000110000, // | ! |
0b0000110000, // | ! |
0b0000000000, // | ! |
0b0000110000, // | ! |
0b0000110000 // border bottom
};
uint8_t frame[matrixHeight][matrixWidth];
void clearFrame() {
for (int y = 0; y < matrixHeight; y++) {
for (int x = 0; x < matrixWidth; x++) {
frame[y][x] = 0;
}
}
}
void drawAlert(int xPos, int yPos) {
clearFrame();
for (int row = 0; row < alertHeight; row++) {
for (int col = 0; col < alertWidth; col++) {
bool pixelOn = alertBitmap[row] & (1 << (alertWidth - 1 - col));
int x = xPos + col;
int y = yPos + row;
if (pixelOn && x >= 0 && x < matrixWidth && y >= 0 && y < matrixHeight) {
frame[y][x] = 1;
}
}
}
matrix.renderBitmap(frame, matrixHeight, matrixWidth);
}
void setup() {
Serial.begin(115200);
pinMode(sensorDig, INPUT);
attachInterrupt(digitalPinToInterrupt(sensorDig), sensorDigHandler, RISING);
matrix.begin();
matrix.clear();
// Initialize baseline with first measurement
sensorDigCnt = 0;
intEnable = 1;
delay(measureTime);
intEnable = 0;
base_line = sensorDigCnt;
Serial.print("Initial baseline: ");
Serial.println(base_line);
prevMillis = millis();
}
void loop() {
unsigned long currMillis = millis();
switch (state) {
case 1:
// Update baseline (moving average)
base_line = alpha * sensorDigCnt + (1.0 - alpha) * base_line;
// Calculate deviation from baseline
float diff = sensorDigCnt - base_line;
if (!inPeakEvent) {
// Not currently tracking a peak event
if (abs(diff) > base_line_change) {
inPeakEvent = true;
peakSamplesCount = 1;
peakValue = diff;
}
} else {
// Tracking peak event
peakSamplesCount++;
if (abs(diff) > abs(peakValue)) {
peakValue = diff;
}
// End peak detection when signal returns near baseline or max samples reached
if (abs(diff) <= base_line_change || peakSamplesCount > N) {
Serial.print("Peak detected: ");
Serial.println(peakValue);
inPeakEvent = false;
peakSamplesCount = 0;
peakValue = 0.0;
// Display alert sign centered on the matrix
drawAlert((matrixWidth - alertWidth) / 2, (matrixHeight - alertHeight) / 2);
delay(2000); // Display alert for 2 seconds
matrix.clear();
}
}
Serial.print("Sensor= ");
Serial.print(sensorDigCnt);
Serial.print(" Baseline= ");
Serial.println(base_line);
state = 0;
break;
}
if (currMillis - prevMillis >= updateRate) {
sensorDigCnt = 0;
prevMillis = currMillis;
intEnable = 1;
delay(measureTime);
intEnable = 0;
state = 1;
}
}
// Interrupt handler increments counter on rising edge
void sensorDigHandler() {
if (intEnable == 1) {
sensorDigCnt++;
}
}
Attachments
Step 5: How the Code Works
Interrupt Counting:
Each rising edge on the sensor output increments a counter during a fixed measurement window.
Baseline Tracking:
The system establishes a baseline frequency count during startup representing no metal present. This baseline is continuously updated slowly to adapt to environmental changes.
Peak Detection:
When sensor readings deviate beyond a threshold for a sustained period, a detection event is flagged.
Display Update:
On detection, the exclamation mark is shown on the matrix display to alert users.
Parameter Recommendations
Step 6: Testing the Detector
Test by moving a metal object (like keys) near the sensor. The exclamation mark should appear on the matrix indicating detection.
Note: The FG-3+ sensor is highly sensitive and may respond to electromagnetic interference in your environment, so calibrate thresholds carefully.
Step 7: Suggested Improvements - Multi-Sensor Array Using AI
- Deploy several FG-3+ sensors spaced across the walkthrough frame.
- Use their comparative outputs to detect and localize metal objects precisely.
- Combine readings to filter out false positives caused by environmental EMI (which may only affect some sensors non-simultaneously).
- This approach enhances sensitivity, positional awareness, and reduces false alarms.
- Use AI to identify different objects
Step 8: Applications
- Security checkpoints for metal detection without bulky equipment.
- Museum exhibits to monitor access or protect sensitive artifacts.
- Industrial safety where metal detection is needed in restricted zones
Step 9: Conclusion
This walkthrough metal detector design harnesses the precision of FG-3+ fluxgate magnetometers and the versatile Arduino UNO R4 WiFi to create a cost-effective and cloud-enabled metal detection system suitable for diverse security and monitoring needs.




