Why Most Electrical Engineering Project Ideas Fail on the Bench

Searching for "electrical engineering project ideas" usually yields a graveyard of blinking LEDs, basic DC motor controllers, and Arduino weather stations. While those are fine for learning syntax, real electrical engineering requires dealing with messy AC waveforms, phase shifts, non-linear loads, and signal conditioning. If you want a project that bridges embedded firmware with hardcore AC circuit theory, you need to measure True RMS and Power Factor.

Before we wire up the bench, use this decision path to select the right project for your current skill level. We are terminating on the most rigorous option.

Your Primary Goal Project Pick Core Theory Tested
Learn basic GPIO and relay switching Arduino Nano 120V Timer DC control of AC magnetic coils
Learn IoT telemetry and MQTT ESP8266 BME280 Weather Station I2C bus capacitance and pull-ups
Master AC power theory & DSP ESP32 True RMS Power Meter (Default Pick) RMS integration, phase angle, ADC sampling

We are building the default pick. This build forces you to confront the ESP32’s notoriously non-linear ADC, design analog biasing networks, and write firmware that calculates instantaneous power without blocking the watchdog timer.

Spec Sheet & Parts List: The True RMS Power Meter

Difficulty Rating: Advanced (Requires mains AC wiring and analog signal conditioning)
Estimated Cost: $25 - $35 USD
Time to Build: 3-4 hours (including calibration)

Do not substitute the current transformer. The internal burden resistor changes the math entirely.

Component Exact Variant / Model Why This Specific Part?
Microcontroller ESP32-WROOM-32 DevKit V1 (30-pin) Dual-core 240MHz allows simultaneous WiFi and high-speed ADC sampling without watchdog resets.
Current Sensor YHDC SCT-013-000 (100A / 50mA) The "-000" variant has NO internal burden resistor, allowing us to optimize the burden for the ESP32's 3.3V ADC range.
Voltage Sensor ZMPT101B Active Module Includes onboard op-amp circuitry to step down 120V/240V AC and add a DC bias offset.
Burden Resistor 33Ω 1/4W Metal Film Converts the 50mA CT secondary current into a ~1.65V peak signal (3.3V peak-to-peak).
Bias Network 2x 10kΩ, 1x 10µF Cap Creates a stable 1.65V virtual ground to center the AC waveform in the ESP32's 0-3.3V ADC window.

Safety Callout & Pin Mapping

⚠️ HIGH VOLTAGE WARNING: The ZMPT101B primary side connects directly to mains voltage (120V/240V AC). De-energize the circuit, lock out the breaker, and verify dead with a CAT III multimeter before making connections. If you are not comfortable with mains wiring, use a 12V AC wall transformer for bench testing.

The ESP32 ADC is strictly 0V to 3.3V. Feeding it a raw AC signal will destroy the silicon. The bias network shifts the AC waveform up by 1.65V so the negative peaks read as ~0V and positive peaks read as ~3.3V.

ESP32 Pin Destination Function
GPIO 34 (ADC1_CH6) ZMPT101B Analog Out Voltage waveform sampling (Input only, no internal pull-up)
GPIO 35 (ADC1_CH7) SCT-013 Burden/Bias Node Current waveform sampling (Input only)
3V3 Sensor VCC / Bias Divider Reference voltage for the 1.65V bias network
GND Sensor GND / Bias Divider Common ground reference

The Theory: True RMS and Power Factor Math

Cheap multimeters and basic microcontroller projects measure the average rectified value of a waveform and multiply it by 1.11 (the form factor of a pure sine wave) to guess the RMS value. This works for resistive loads like incandescent bulbs or space heaters. It fails catastrophically on non-linear loads like LED drivers, PC power supplies, and VFDs.

According to Fluke's engineering guidelines on True RMS, non-linear loads draw current in sharp spikes rather than smooth sine waves. To find the actual heating value (True RMS), we must sample the waveform and integrate the squares:

True RMS Formula:
V_RMS = √( 1/T ∫₀ᵀ v(t)² dt )

Discrete Microcontroller Approximation:
V_RMS = √( (1/N) * Σ(v_i - v_offset)² )

Numeric Example: A PC power supply draws 8A peak but only 3A True RMS due to a high crest factor. An average-responding meter reads the average current (e.g., 2.5A) and multiplies by 1.11, displaying 2.77A. A True RMS meter correctly calculates the square root of the mean squares and displays 3.00A. If you size a breaker or wire based on the average meter's reading, you risk thermal overload.

Power Factor (PF) is the ratio of Real Power (Watts) to Apparent Power (Volt-Amps). In our firmware, we calculate instantaneous power (p = v * i) at every sample, average those to get Real Power, and divide by (V_RMS * I_RMS).

Complete ESP32 Firmware (Arduino IDE)

Target Board: ESP32 Dev Module (ESP32-WROOM-32 30-pin).
IDE Setup: Arduino IDE 2.x, ESP32 Core v2.0.x or v3.0.x by Espressif. No external DSP libraries required; we use raw ADC polling for maximum transparency.

#include <Arduino.h>

// --- PIN DEFINITIONS ---
const int V_PIN = 34; // ZMPT101B Analog Out
const int I_PIN = 35; // SCT-013 Burden/Bias Node

// --- CALIBRATION CONSTANTS ---
// Adjust these based on your multimeter readings
const float V_CAL = 135.0; // Voltage calibration factor
const float I_CAL = 28.5;  // Current calibration factor

// --- SAMPLING PARAMETERS ---
const int NUM_SAMPLES = 1000; // Samples per calculation cycle

void setup() {
  Serial.begin(115200);
  
  // Configure ESP32 ADC for 0-3.3V range (11dB attenuation)
  // Reference: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc_oneshot.html
  analogSetAttenuation(ADC_11db);
  analogReadResolution(12); // 12-bit (0-4095)
  
  // Prime the ADC to clear initial noise
  for(int i=0; i<50; i++) {
    analogRead(V_PIN);
    analogRead(I_PIN);
  }
  Serial.println("ESP32 True RMS Power Meter Initialized.");
}

void loop() {
  unsigned long startMicros = micros();
  
  double sumV = 0, sumI = 0, sumP = 0;
  double offsetV = 2048.0; // Initial guess for 1.65V bias (approx 2048 on 12-bit)
  double offsetI = 2048.0;
  
  int rawV, rawI;
  double instV, instI, instP;
  
  // Error Handling: Check for ADC saturation or disconnected sensors
  int clipCountV = 0, clipCountI = 0;

  for (int n = 0; n < NUM_SAMPLES; n++) {
    rawV = analogRead(V_PIN);
    rawI = analogRead(I_PIN);
    
    // Track ADC clipping (ESP32 ADC saturates near 0 and 4095)
    if (rawV < 50 || rawV > 4000) clipCountV++;
    if (rawI < 50 || rawI > 4000) clipCountI++;
    
    // Digital low-pass filter to track the DC bias offset dynamically
    offsetV = offsetV + ((rawV - offsetV) / 1024.0);
    offsetI = offsetI + ((rawI - offsetI) / 1024.0);
    
    // Remove DC bias to get pure AC component
    instV = rawV - offsetV;
    instI = rawI - offsetI;
    
    // Accumulate squares for RMS calculation
    sumV += instV * instV;
    sumI += instI * instI;
    
    // Accumulate instantaneous power for Real Power calculation
    instP = instV * instI;
    sumP += instP;
    
    // Yield to prevent Watchdog Timer (WDT) resets on Core 1
    if (n % 100 == 0) yield(); 
  }
  
  // Calculate RMS values
  double V_RMS = V_CAL * sqrt(sumV / NUM_SAMPLES);
  double I_RMS = I_CAL * sqrt(sumI / NUM_SAMPLES);
  double P_REAL = V_CAL * I_CAL * (sumP / NUM_SAMPLES);
  
  // Calculate Apparent Power and Power Factor
  double S_APPARENT = V_RMS * I_RMS;
  double PF = 0.0;
  
  // Error Handling: Prevent division by zero when load is disconnected
  if (S_APPARENT > 1.0) {
    PF = P_REAL / S_APPARENT;
  }
  
  // Output telemetry
  Serial.print("V_RMS: "); Serial.print(V_RMS, 1);
  Serial.print("V | I_RMS: "); Serial.print(I_RMS, 2);
  Serial.print("A | P_Real: "); Serial.print(P_REAL, 1);
  Serial.print("W | PF: "); Serial.print(PF, 3);
  
  // Alert on ADC Clipping
  if (clipCountV > 10 || clipCountI > 10) {
    Serial.println(" [WARNING: ADC CLIPPING DETECTED - REDUCE GAIN]");
  } else {
    Serial.println();
  }
  
  // Pace the loop to update roughly once per second
  delay(800);
}

Debugging: First 3 Things to Check When It Fails

When moving from AVR Arduinos to the ESP32, the ADC behavior and RTOS environment will break your assumptions. Here is the exact decision path for the three most common failures.

  1. Error String: Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1)
    • Cause: The ESP32 runs FreeRTOS. If your for loop samples the ADC 1000 times without yielding, the Idle Task on Core 1 starves, and the Watchdog Timer resets the chip.
    • Fix: Ensure the if (n % 100 == 0) yield(); line is present inside the sampling loop. If you increase NUM_SAMPLES to 5000, decrease the modulo threshold to 50.
  2. Symptom: Readings are stuck at 0.00 or max out erratically, and Serial prints [WARNING: ADC CLIPPING DETECTED].
    • Cause: Your DC bias network is failing. The ESP32 ADC cannot read negative voltages. If the 1.65V offset drifts to 0.2V, the negative half of the AC sine wave hits the 0V rail and clips, destroying the RMS math. Furthermore, the OpenEnergyMonitor CT sensor guide notes that op-amp bias circuits require a stable reference.
    • Fix: Measure the voltage at GPIO 34 and 35 with a DC multimeter while the AC load is OFF. It must read exactly 1.65V (±0.05V). If it reads 0V or 3.3V, check your 10kΩ voltage divider and 10µF smoothing capacitor.
  3. Symptom: Power Factor (PF) reads > 1.0 or < -1.0.
    • Cause: Phase shift introduced by the ZMPT101B op-amp or the SCT-013 inductor, combined with floating-point noise when the load is very small (e.g., a 5W LED bulb).
    • Fix: The firmware already includes a threshold (S_APPARENT > 1.0) to prevent division by zero. To fix phase-shift errors on larger loads, you must add a software phase-calibration delay in the sampling loop (shifting the current array index relative to the voltage array index by 2-4 samples).

Extending or Simplifying the Build

Do not leave this project as a bare Serial print. Decide how to scale it based on your end goal.

To Simplify (The "Good Enough" DC Route):
If AC theory is overwhelming and you just need to monitor a 12V/24V solar battery bank, drop the ZMPT101B and SCT-013 entirely. Buy an INA219 I2C DC Current/Power Sensor ($3). It handles the shunt voltage amplification and I2C handshaking in hardware. You will lose True RMS AC capabilities, but you gain bulletproof DC telemetry with three lines of code using the Adafruit_INA219 library.

To Extend (The Smart Home Route):
Keep the AC sensors but add an SSD1306 128x64 I2C OLED for local readouts, and integrate the PubSubClient library to push the V_RMS, I_RMS, and PF variables to a Home Assistant MQTT broker every 5 seconds. This transforms a bench experiment into a permanent, code-compliant sub-panel monitor.

Mastering the ESP32 ADC and AC signal conditioning separates hobbyists who copy-paste library code from engineers who understand the physics of the grid. Build the bias network, flash the firmware, and verify the math against a Fluke 87V.