Three-point-controller

Hello friends,

My goal: I want to control the pH value of my pool automaticly. For this i have a probe in my pool, that measues every x - interval the pH. Two pumps can dose a solution either to get the pH up or get the ph down, to a given setpoint. Long story short, fot this i coded myself a three-point-controller which will run on my esp32 in the loop.

i would realy appreciate if someone can control my function if there are some flaws, errors or nonsense. My first real-life testings seems positive. But since i dont wanna ruin my whole pool, i would prefer nor error.

Hopefully my code can help anyone for their applications=).

void threePointController(float hysteresis, float setpoint, int deadTime, int controlTime) {
  float measurement;

  // Depending on what sensor was chosen, it will use it as the source
  // Note: The switch-case block is commented out; consider removing it if not needed.
  // switch(mySettings.sensorSelect) {
  //   case 0:
  //     return;
  //   case 1:
  measurement = mySettings.sensor_3_int;
  //     break;
  // }

  if (mySettings.controllerOnOff == 0) {
    // If the controller is turned off, set relays off and update display
    digitalWrite(RELAY_DOWN, 0);
    digitalWrite(RELAY_UP, 0);
    myNex.writeStr("page1.q4.picc=0");
  }

  // Start the three-point controller
  if (mySettings.controllerOnOff == 1) {
    static bool relayStatus = 1; // Relay status: false = OFF, true = ON
    static int controlDirection = 0; // 0 = neutral, 1 = downward, 2 = upward
    float upperLimit = setpoint + hysteresis;
    float lowerLimit = setpoint - hysteresis;
    int pump_DOWN = RELAY_DOWN;
    int pump_UP = RELAY_UP;

    if (relayStatus == 1) { // If relay is ON (controller is active), check time
      if (millis() - Loop_Timer_tpc > controlTime) {
        // If time exceeds controlTime, turn off the controller
        myNex.writeStr("page1.q4.picc=0");
        relayStatus = 0; // Relay OFF
        digitalWrite(pump_UP, 0);
        digitalWrite(pump_DOWN, 0);
        Loop_Timer_tpc = millis();
      }
    } else if (relayStatus == 0) { // If relay is OFF (controller is inactive), check for deadTime
      if (millis() - Loop_Timer_tpc > deadTime) {
        if (measurement >= upperLimit) {
          // If "measurement" exceeds upper hysteresis, turn the relay ON (controller active)
          relayStatus = 1;
          digitalWrite(pump_UP, 0);
          digitalWrite(pump_DOWN, 1);
          controlDirection = 1;
          myNex.writeStr("page1.q4.picc=27");
          Loop_Timer_tpc = millis();
        } else if (measurement > setpoint && controlDirection == 1) {
          // If "measurement" is above setpoint and controlling downward, continue controlling downward
          relayStatus = 1;
          digitalWrite(pump_UP, 0);
          digitalWrite(pump_DOWN, 1);
          myNex.writeStr("page1.q4.picc=27");
          Loop_Timer_tpc = millis();
        } else if (measurement <= setpoint && controlDirection == 1) {
          // If "measurement" reaches setpoint while controlling downward, stop the controller
          relayStatus = 1;
          digitalWrite(pump_UP, 0);
          digitalWrite(pump_DOWN, 0);
          controlDirection = 0;
          myNex.writeStr("page1.q4.picc=0");
          Loop_Timer_tpc = millis();
        } else if (measurement <= lowerLimit) {
          // If "measurement" violates lower hysteresis, turn the relay ON (controller active)
          relayStatus = 1;
          digitalWrite(pump_UP, 1);
          digitalWrite(pump_DOWN, 0);
          controlDirection = 2;
          myNex.writeStr("page1.q4.picc=27");
          Loop_Timer_tpc = millis();
        } else if (measurement < setpoint && controlDirection == 2) {
          // If "measurement" is below setpoint and controlling upward, continue controlling upward
          relayStatus = 1;
          digitalWrite(pump_UP, 1);
          digitalWrite(pump_DOWN, 0);
          myNex.writeStr("page1.q4.picc=27");
          Loop_Timer_tpc = millis();
        } else if (measurement >= setpoint && controlDirection == 2) {
          // If "measurement" reaches setpoint while controlling upward, stop the controller
          relayStatus = 1;
          digitalWrite(pump_UP, 0);
          digitalWrite(pump_DOWN, 0);
          controlDirection = 0;
          myNex.writeStr("page1.q4.picc=0");
          Loop_Timer_tpc = millis();
        }
      }
    }
  }
}

Please post your whole sketch

It is a very good idea to test the code in a simulated environment. Often all you need to do is have sensor functions return made-up, but reasonable values. And, for example, the pump output can light an LED instead of turning on a pump.

1 Like

I build stuff alla time with the wokwi, and even for sensors that it does simulate often find that using a slide fader or other proxy is better, easier to use usually and gives a visual feedback of the"sensor" setting/

a7

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.