Build an IoT Geiger-Müller Radiation Monitor with ESP32 & J305 Tube
Comprehensive step-by-step engineering guide for building an IoT ionizing radiation monitor and nuclear fallout alert node using ESP32 and a Geiger-Müller tube.
- Complete hardware pinout and wiring schematic mapping
- Production-tested Arduino C++ firmware with event-driven callbacks
- Electrical safety constraints, level-shifting & sensor calibration heuristics
2. Overview & Engineering Objectives
Natural background radiation (cosmic rays and terrestrial radon) exists everywhere at low levels (0.08–0.25 µSv/h). However, industrial radiotracer leaks, radiological accidents, or medical isotope spills require immediate warning. This project builds an automated, network-connected Geiger-Müller Radiation Monitor that translates ionizing particle discharge events into calibrated dose rates in micro-Sieverts per hour (µSv/h).
Core Engineering Capabilities:
Ionizing Avalanche Detection: Detects high-energy Gamma rays and Beta particles as they ionize low-pressure neon/halogen gas inside a 400V polarized Geiger tube.
RF Noise Rejection: Solves the notorious issue where ESP32 Wi-Fi transmission bursts induce false radiation counts on high-impedance detector circuits.
Calibrated Dosimetry Conversion: Applies empirical tube factors to convert instantaneous Counts Per Minute (CPM) into human biological equivalent dose rates (µSv/h).
Global Radiation Mapping: Broadcasts hourly radiation statistics to open-science networks (Safecast, RadMon) and sounds an immediate audible klaxon if radiation exceeds 0.50,µSv/h.
3. Bill of Materials (BOM)
Component
Quantity
Specification / Rating
Est. Cost (INR)
Sourcing / Affiliate Link
ESP32 DevKit V1 Board
1
30-Pin Dual-Core Xtensa LX6 (Wi-Fi + BLE)
₹380
Buy on Mentora Store
Geiger Counter Board Kit
1
Complete 400V inverter board with J305 / M4011 tube
₹2,850
Buy on Mentora Store
Active Piezo Buzzer
1
5V physical radiation click synthesizer
₹25
Buy on Mentora Store
SSD1306 0.96" I2C OLED
1
128x64 display for live CPM & dose rate gauge
₹220
Buy on Mentora Store
10kΩ Resistor & 100pF Cap
1 Set
Interrupt pull-up and RF snubber filter
₹8
Buy on Mentora Store
5V 2A Regulated Power Supply
1
Clean DC wall adapter (powers 400V boost stage)
₹180
Buy on Mentora Store
Aluminum Shielding Enclosure
1
Faradaic enclosure isolating 400V inverter
₹350
Buy on Mentora Store
Total Hardware Cost
~₹4,013
4. Hardware Engineering: The Wi-Fi RF Interference Fix
A Geiger tube generates a brief 100µs negative pulse whenever an ionizing particle triggers an electron avalanche.
The RF Noise Problem: The ESP32's 2.4GHz Wi-Fi transmitter emits up to +20dBm (100mW) of RF energy. The high-impedance pulse line on cheap Geiger kits acts like an antenna, picking up Wi-Fi packets and registering them as hundreds of false radiation counts per minute!
The Solution:
Add a 100pF ceramic capacitor in parallel with a 10kΩ pull-up resistor directly across the signal pin and GND at the ESP32 header (GPIO 13).
Implement software dead-time lockout in the ISR:
void IRAM_ATTR geigerPulseISR() {
unsigned long now = micros();
if (now - lastPulseMicros > 150) { // 150us dead-time filter
pulseCount++;
lastPulseMicros = now;
}
}
Keep the Geiger tube high-voltage inverter at least 10cm away from the ESP32 Wi-Fi antenna, ideally inside a grounded aluminum box.
5. Dosimetry Physics: CPM to µSv/h Conversion
A Geiger tube counts discrete ionization events, not total energy. Converting Counts Per Minute (CPM) to ambient dose equivalent rate (µSv/h) depends on tube geometry and gas volume:
Standard Conversion Factors for Gamma (^137Cs / ^60Co):
Russian J305 / M4011 Tube: $Dose Rate (µSv/h) = (CPM)/(153.8) = CPM × 0.0065$
Soviet SBM-20 Tube: $Dose Rate (µSv/h) = (CPM)/(175.43) = CPM × 0.0057$
Radiation Hazard Categories:
Normal Background: 0.08 to 0.25,µSv/h (Normal cosmic/terrestrial baseline)
Elevated Warning: 0.50 to 1.20,µSv/h (Abnormal - investigate source)
🚨 NUCLEAR HAZARD / FALLOUT: > 1.20,µSv/h (Emergency evacuation threshold)
6. Real-World Troubleshooting FAQs
Q1: Why does my multimeter read only 280V on the 400V Geiger tube?
Root Cause: Multimeter Loading Effect: Standard digital multimeters have a 10MΩ input impedance. Connecting a 10MΩ meter to a micro-power 400V inverter with high source resistance drags down the measured voltage! To measure true tube voltage, use a 1GΩ high-voltage probe.
Q2: Is the high-voltage circuit dangerous?
Safety Note: While the inverter generates 400V DC, the current is limited to a few microamps (µA). Touching the tube anode will give a harmless static snap, but always power down before handling.
7. Mentora Monetization & Student Support Hooks
🛒 Official Mentora Nuclear Radiation Monitor Kit: ESP32 DevKit, pre-assembled J305 tube inverter board, OLED display, active clicker buzzer, and shielded case for ₹4,499.
⚡ ₹49 Mentora Token Vault: Instantly unlock the Safecast API live streaming client, historical radiation dose rate chart generator, and audio geiger-click synthesizer code.
🛠️ ₹299 1-on-1 Mentora Live Video Debugging: 30-minute session with a nuclear instrumentation engineer to calibrate tube conversion factors, eliminate RF false triggers, and configure cloud emergency webhooks.
Hardware Pinout & Wiring Connections
Hardware Pinout & Wiring Connection Guide
Project 23: Geiger-Müller Radiation Level Monitor & Nuclear Fallout Alert Node
Microcontroller: ESP32 DevKit V1 (30-pin / 36-pin)Radiation Detector: Geiger-Müller Kit with 400V Inverter & J305 / M4011 / SBM-20 Glass TubeAcoustic Synthesizer: Active Piezo Buzzer (Audio Geiger Clicks & Hazard Alarm on GPIO 4)RF Noise Filter: 10kΩ Pull-Up Resistor + 100pF Ceramic Capacitor on Interrupt Line (GPIO 13)
1. Complete Fritzing Pin Connection Mapping Table
Table A: Geiger Counter Board & Audio Alert to ESP32
Component
Component Pin
ESP32 DevKit Pin
Wire Color
Bus Signal / Function
Operational Constraints & Notes
Geiger Board Power
5V / VCC
5V (VIN Rail)
Red (Thick)
High-Voltage Inverter Input
Powers internal 400V DC step-up boost converter.
Geiger Board Ground
GND
GND Rail
Black (Thick)
Power Ground
Common ground plane.
Geiger Pulse Output
VIN_INT / OUT
GPIO 13
Blue
Digital Discharge Pulse
Negative pulse (~100µs) triggered on ionizing event.
10kΩ Pull-Up
Lead 1 to Lead 2
Between 3V3 & GPIO 13
—
Line Pull-Up
Ensures positive return after pulse discharge.
100pF Capacitor
Lead 1 to Lead 2
Between GPIO 13 & GND
—
RF Noise Snubber
Shunts 2.4GHz Wi-Fi packet bursts to ground.
Active Buzzer
Positive (+)
GPIO 4
Orange
Acoustic Click Output
Pulsed for 2ms per ionizing count.
Active Buzzer
Negative (-)
GND Rail
Black
Ground Return
Common system ground.
Status LED
Onboard Pin
GPIO 2
—
Visual Alarm Indicator
Flashes on radiation pulse; solid on emergency.
2. Circuit Connection Schematic Diagram (ASCII Art)
+-------------------------------------------------------------+
| ESP32 DevKit V1 |
| |
| [ 5V ] [ 3V3 ] [ GND ] [GPIO 13] [GPIO 4] [GPIO 2] |
+----+-------+--------+----------+-----------+-----------+----+---+
| | | | | |+5V | +3.3V | GND | Geiger | Buzzer | Status |
Rail | Rail | Rail | Pulse | Click | LED |
=======+=======+========+==========+===========+===========+=====
| | | | || +--------+ [10k Pullup] || | | +---+---+ || | | | | || | | | +-----------+| | | | | || | | | [100pF Cap] || | | | | || | | | GND || | | | |+--+-------+--------+------+--+ |
| 5V 3V3 GND OUT | |
| GEIGER-MULLER KIT | || (400V Inverter + J305 Tube) | |
+-----------------------------+ |
|
+---------------------------------------+
|
+--+-------------+
| (+) (-)|
| ACTIVE PIEZO |
| BUZZER |
+----------------+
3. Golden High-Voltage & RF Engineering Rules
High-Voltage Anode Safety (400V DC):
The metal clip securing the anode side of the glass Geiger tube carries 400V DC. Never touch the tube anode contacts while powered. Always enclose the tube inside an insulated or grounded housing.
Wi-Fi RF Interference Snubber:
The 100pF ceramic capacitor in parallel with the 10kΩ pull-up resistor directly at the ESP32 GPIO 13 pin is strictly required. Without it, the high-gain pulse comparator on the Geiger board mistakes local Wi-Fi transmission bursts for nuclear radiation.
Fragile Glass Tube Enclosure:
The J305 / M4011 tube envelope is constructed from thin borosilicate glass. Protect the tube from mechanical shock by mounting the carrier board on rubber vibration isolators.
Complete Tested Arduino C++ Firmware
``cpp
/*
- ==============================================================================
- Project: Geiger-Müller Radiation Level Monitor & Nuclear Fallout Alert Node
- Microcontroller: ESP32 DevKit V1 (Xtensa 32-bit Dual-Core 240MHz)
- Author: Mentora Maker Lab (Spark Autonomous Content Intelligence)
- License: MIT
*
- Hardware Peripherals:
- - Geiger Counter Board Kit (400V Inverter + J305 / M4011 Tube):
- Pulse Signal Output -> GPIO 13 (Hardware Interrupt with Dead-Time Filter)
- (10k pullup resistor + 100pF RF capacitor installed at ESP32 pin)
- - Active Buzzer Clicker -> GPIO 4 (Synthesizes acoustic particle click)
- - Status / Alarm LED -> GPIO 2 (Flashes on particle strike / solid on alarm)
- ==============================================================================
*/
#include <WiFi.h>
#include <HTTPClient.h>
// -----------------------------------------------------------------------------
// USER CONFIGURATION (WIFI & TUBE CALIBRATION)
// -----------------------------------------------------------------------------
const char* WIFISSID = "YOURWIFI_SSID";
const char* WIFIPASSWORD = "YOURWIFI_PASSWORD";
const char* TELEMETRY_URL = "http://api.mentora.in/telemetry/radiation";
#define GEIGERPULSEPIN 13
#define BUZZER_PIN 4
#define STATUSLEDPIN 2
// J305 / M4011 Tube Conversion Factor (Gamma Co-60 / Cs-137)
// 153.8 CPM is approximately equal to 1.0 uSv/h
const float CONVERSIONFACTORCPMTOUSVH = 0.0065; // (1.0 / 153.8)
// Emergency Radiation Thresholds (uSv/h)
const float HAZARDALERTTHRESHOLD_USVH = 0.50; // Elevated warning
const float EMERGENCYFALLOUTTHRESHOLD = 1.20; // Severe fallout emergency
// Interrupt & Sampling State
volatile uint32_t pulseCount = 0;
volatile unsigned long lastPulseMicros = 0;
unsigned long lastCalcTimestamp = 0;
const unsigned long SAMPLEWINDOWMS = 5000; // Calculate moving CPM every 5 seconds
// Rolling 60-Second History Buffer (12 x 5-second bins)
const int BINS_COUNT = 12;
uint16t cpmBins[BINSCOUNT] = {0};
int currentBinIndex = 0;
float currentCPM = 0.0;
float currentDoseUSvH = 0.0;
// -----------------------------------------------------------------------------
// GEIGER PULSE INTERRUPT SERVICE ROUTINE (WITH DEAD-TIME REJECTION)
// -----------------------------------------------------------------------------
void IRAM_ATTR onGeigerPulse() {
unsigned long now = micros();
// 150us dead-time filter to reject Wi-Fi RF packet interference
if (now - lastPulseMicros > 150) {
pulseCount++;
lastPulseMicros = now;
}
}
// -----------------------------------------------------------------------------
// TELEMETRY CLOUD DISPATCHER
// -----------------------------------------------------------------------------
void uploadRadiationData(float cpm, float usvh, bool isHazard) {
if (WiFi.status() != WL_CONNECTED) return;
HTTPClient http;
http.begin(TELEMETRY_URL);
http.addHeader("Content-Type", "application/json");
String json = "{";
json += "\"node\":\"RADNODE01\",";
json += "\"cpm\":" + String(cpm, 1) + ",";
json += "\"doserateusvh\":" + String(usvh, 4) + ",";
json += "\"status\":\"" + String(isHazard ? "HAZARDEMERGENCY" : "NORMALBACKGROUND") + "\"";
json += "}";
int httpCode = http.POST(json);
Serial.printf("[HTTP] Telemetry uploaded. Response Code: %d\n", httpCode);
http.end();
}
// -----------------------------------------------------------------------------
// ARDUINO SETUP
// -----------------------------------------------------------------------------
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n========================================================");
Serial.println(" MENTORA ESP32 GEIGER-MULLER RADIATION TELEMETRY NODE ");
Serial.println("========================================================");
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW);
pinMode(STATUSLEDPIN, OUTPUT);
digitalWrite(STATUSLEDPIN, LOW);
// Configure Geiger Pulse Interrupt Pin
pinMode(GEIGERPULSEPIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(GEIGERPULSEPIN), onGeigerPulse, FALLING);
// Connect to Wi-Fi
Serial.printf("[WIFI] Connecting to SSID: %s\n", WIFI_SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFISSID, WIFIPASSWORD);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n[WIFI] Connected! Monitoring station IP: " + WiFi.localIP().toString());
} else {
Serial.println("\n[WARNING] Wi-Fi timed out. Operating in autonomous standalone mode.");
}
Serial.println("[SYSTEM] High-voltage 400V sensor monitoring active.\n");
lastCalcTimestamp = millis();
}
// -----------------------------------------------------------------------------
// ARDUINO MAIN LOOP
// -----------------------------------------------------------------------------
void loop() {
unsigned long now = millis();
// Evaluate Dosimetry every 5 seconds
if (now - lastCalcTimestamp >= SAMPLEWINDOWMS) {
lastCalcTimestamp = now;
// Grab atomic count and reset counter
noInterrupts();
uint32_t countsInWindow = pulseCount;
pulseCount = 0;
interrupts();
// Store in rolling bin
cpmBins[currentBinIndex] = countsInWindow;
currentBinIndex = (currentBinIndex + 1) % BINS_COUNT;
// Sum all 12 bins to get rolling 60-second CPM
uint32_t totalMinuteCounts = 0;
for (int i = 0; i < BINS_COUNT; i++) {
totalMinuteCounts += cpmBins[i];
}
currentCPM = (float)totalMinuteCounts;
currentDoseUSvH = currentCPM * CONVERSIONFACTORCPMTOUSVH;
bool isHazard = (currentDoseUSvH >= HAZARDALERTTHRESHOLD_USVH);
Serial.printf("[RADIATION] Counts: %3d | 60s CPM: %5.1f | Dose: %6.4f uSv/h | Status: %s\n",
countsInWindow, currentCPM, currentDoseUSvH,
isHazard ? "🚨 ELEVATED RADIATION ALERT" : "NORMAL BACKGROUND");
// Audible alarm & visual warning if hazard detected
if (isHazard) {
digitalWrite(STATUSLEDPIN, HIGH);
// Warning beep
digitalWrite(BUZZER_PIN, HIGH);
delay(80);
digitalWrite(BUZZER_PIN, LOW);
} else {
digitalWrite(STATUSLEDPIN, LOW);
// Acoustic Geiger Click synthesis if pulses occurred
if (countsInWindow > 0) {
digitalWrite(BUZZER_PIN, HIGH);
delayMicroseconds(2000); // 2ms short click
digitalWrite(BUZZER_PIN, LOW);
}
}
// Upload cloud telemetry every 30 seconds (every 6th window)
if (currentBinIndex % 6 == 0) {
uploadRadiationData(currentCPM, currentDoseUSvH, isHazard);
}
}
delay(20);
}
``
Build an IoT Geiger-Müller Radiation Monitor with ESP32 & J305 Tube Firmware & Schematics Vault
Download verified Arduino C++ firmware, pinout table, and BOM for Build an IoT Geiger-Müller Radiation Monitor with ESP32 & J305 Tube.
Free Tutorial vs. Project Vault: The tutorial and educational theory above are 100% free. The Project Vault contains downloadable production source files, complete Fritzing .fzz circuits, laser vector files, and 1-on-1 mentor debugging sessions.
#include<Adafruit_Sensor.h>
const int SAMPLING_RATE_HZ = 250;
// PID Calibrated loop variables initialized
void setup() { Wire.begin(21, 22); calibrateIMUGyroscope(); }
void loop() { float pitch = readSensorPitch(); float roll = readSensorRoll(); }
float calculatePID(float error, float kp, float ki, float kd) { ... }
void transmitTelemetryPackage(uint8_t *packet, size_t length) { ... }
1 Code Snippets & 0 Schematics Locked
Unlock immediate access to verified firmware files, Fritzing wiring diagrams, and laser-cut vectors for ₹49.
Includes circuit breadboard wiring, component pinouts, and laser cutting templates.
Screen-share or show your breadboard to M. F. Haque for 30 minutes of real-time debugging, circuit validation, and project guidance.
See What Mentora Makers Are Building
Real video walk-throughs, breadboard tests, and flight demonstrations submitted by students & parents.
Review This Build & Claim a Free ₹49 Token
Share your breadboard troubleshooting experience, code feedback, or video demo to earn a complimentary token voucher.
Have a Reward Voucher?
Enter your MAKER-TOKEN-XXXX reward code to unlock this project vault immediately.
Earn ₹50 Per Friend You Refer
Get your custom referral link. When friends book a free demo or unlock a project vault, you receive ₹50 via UPI!
Why does my multimeter read only 280V on the 400V Geiger tube?
Root Cause: Multimeter Loading Effect: Standard digital multimeters have a 10MΩ input impedance. Connecting a 10MΩ meter to a micro-power 400V inverter with high source resistance drags down the measured voltage! To measure true tube voltage, use a 1GΩ high-voltage probe.
Is the high-voltage circuit dangerous?
Safety Note: While the inverter generates 400V DC, the current is limited to a few microamps ($\mu\text{A}$). Touching the tube anode will give a harmless static snap, but always power down before handling.
Learn this in our Junior Tech: Game Design & Scratch
Master computational thinking, sprite animations, coordinate systems, and interactive 2D arcade games using drag-and-drop logic blocks.