Skip to content

Latest commit

 

History

History
167 lines (138 loc) · 5.23 KB

File metadata and controls

167 lines (138 loc) · 5.23 KB
title Firmware Dev - The Core Logic
project Solar-Doctor
phase 08 - Firmware Development
status CODING
tags
CPP
Arduino
ESP32
RTOS
Firmware
aliases
Phase 8 Firmware
Core Firmware
date 2025-11-22
owner mr.princetheprogrammerbtw

PHASE 8: FIRMWARE DEV - THE CORE LOGIC

Breathing Life into Silicon: The C++ Firmware.

8.1 The Logic Structure

To ensure responsive and non-blocking operation, the firmware will leverage the ESP32's dual-core architecture using FreeRTOS tasks.

  • Task 1 (Core 1): High-speed sensor sampling (e.g., reads sensors every 50ms).
  • Task 2 (Core 0): Handles network communication (Wi-Fi, ESP-NOW) and cloud reporting (runs every 5 seconds).
  • Task 3 (Core 1): Executes the fault detection and decision logic.

8.2 Calibration Constants

Define hardware-specific values and pin assignments at the beginning of the code for easy tuning.

#define VOLT_PIN 35
#define CURR_PIN 34
#define RELAY_PIN 26

// Resistor values for the voltage divider
const float R1 = 150000.0; // 150kΩ
const float R2 = 10000.0;  // 10kΩ

// Reference voltage for ADC calculations
const float V_REF = 3.3;

// Sensitivity for the ACS712-20A current sensor
const float ACS712_SENSITIVITY = 0.100; // 100mV per Amp

8.3 The Code Skeleton

This C++ code for the Arduino IDE provides a basic, single-threaded framework for initial testing.

#include <Arduino.h>

// Pin definitions
const int voltagePin = 35;
const int currentPin = 34;
const int relayPin = 26;

// Global state variables
float voltage = 0.0;
float current = 0.0;
bool isFaulty = false;

// Forward function declarations
float readVoltage();
float readCurrent();
void triggerBypass();
void disableBypass();

void setup() {
  Serial.begin(115200);
  pinMode(relayPin, OUTPUT);
  // Default to Normal Operation (Bypass OFF). Note the inverted logic from Phase 7.
  digitalWrite(relayPin, LOW); 

  Serial.println("Solar-Doctor System Initialized...");
}

void loop() {
  // 1. Read sensor values
  voltage = readVoltage();
  current = readCurrent();

  // 2. Print data for debugging
  Serial.print("V: "); Serial.print(voltage);
  Serial.print(" V | I: "); Serial.print(current);
  Serial.println(" A");

  // 3. Simple threshold logic (pre-AI)
  // If voltage drops below 20V but is above 2V (to avoid night triggers)
  if (voltage < 20.0 && voltage > 2.0) {
    triggerBypass();
  } else {
    disableBypass();
  }

  delay(500); // Main loop delay for testing
}

/**
 * @brief Reads and averages voltage from the sensor.
 * @return The calculated real voltage.
 */
float readVoltage() {
  float adc_value = 0.0;
  for(int i = 0; i < 10; i++) { // Average 10 samples to reduce noise
    adc_value += analogRead(voltagePin);
    delay(5);
  }
  adc_value /= 10.0;
  
  // Convert ADC value to voltage at the pin
  float pinVoltage = (adc_value / 4095.0) * V_REF;
  // Scale pin voltage to the actual panel voltage
  float realVoltage = pinVoltage * ((R1 + R2) / R2);
  return realVoltage;
}

/**
 * @brief Reads and calculates current, correcting for zero-offset.
 * @return The absolute current value.
 */
float readCurrent() {
  float adc_value = analogRead(currentPin);
  float pinVoltage = (adc_value / 4095.0) * V_REF;
  // ACS712 zero-current offset is typically VCC/2 (3.3V/2 = 1.65V)
  float current = (pinVoltage - 1.65) / ACS712_SENSITIVITY;
  return abs(current); // Use absolute value to ignore current direction
}

/**
 * @brief Activates the bypass mechanism if not already active.
 */
void triggerBypass() {
  if (!isFaulty) {
    digitalWrite(relayPin, HIGH); // Activate bypass
    isFaulty = true;
    Serial.println(">>> FAULT DETECTED! BYPASS ACTIVE <<<");
  }
}

/**
 * @brief Deactivates the bypass mechanism if it is currently active.
 */
void disableBypass() {
  if (isFaulty) {
    digitalWrite(relayPin, LOW); // Deactivate bypass
    isFaulty = false;
    Serial.println(">>> SYSTEM NORMAL <<<");
  }
}

8.4 Testing the Firmware

  1. Upload the code to the ESP32.
  2. Open the Arduino IDE's Serial Monitor at 115200 baud.
  3. Test Normal Operation: Apply 30V. The serial output should show V: 30.1 V and the bypass should be OFF.
  4. Test Fault Condition: Lower the input voltage to 15V. The serial output should show FAULT DETECTED! and the bypass mechanism should activate.
  5. Test Night Condition: Turn off the power supply (0V). The bypass should remain OFF due to the > 2.0 check.

8.5 Refinement: Debouncing

  • Problem: If the voltage flickers around the 20V threshold (e.g., 20.1V → 19.9V → 20.1V), the relay will rapidly switch on and off ("chatter"), causing wear.
  • Fix: A debounce mechanism is required. A simple fix is to only trigger the bypass if the voltage remains below the threshold for a set duration (e.g., 5 seconds). This logic will be implemented in the next phase with the TinyML model.

Phase 8 Checklist

  • Wrote basic sensor reading functions for voltage and current.
  • Implemented signal averaging (10 samples) to reduce noise.
  • Implemented a basic threshold-based fault detection logic.
  • Added a check to prevent false triggers during nighttime.
  • Verified the core logic and output on the Serial Monitor.

The core firmware is alive. It can perceive its environment and react.

[[09_Edge_AI]]