alvesoaj / eFLL

eFLL (Embedded Fuzzy Logic Library) is a standard library for Embedded Systems
MIT License
211 stars 91 forks source link

Help with fuzzy hydroponics #15

Closed servetcoskun closed 3 years ago

servetcoskun commented 5 years ago

Hi! Loving this library so far! I am trying to recreate the Fuzzy controller seen in the picture here https://imgur.com/a/Rk4qOhe, but I have just started using the library but never implemented a fuzzy controller before, I am pretty sure my outputs are not correct as of now. Here are the membership functions I am trying to recreate https://imgur.com/a/Q20vhaK

I have tried covering the cases in the "The first rules" -> "Acid High" but I am not seeing a proper output. The optimal ph should be 5.5 and the optimal ec range should be 550-600. I was expecting to see something from the output1 and output2 variables, but they are constantly 0. Can you help? Thank you!

#include <Arduino.h>

#include <Fuzzy.h>

// Instantiating a Fuzzy object
Fuzzy *fuzzy = new Fuzzy();

//FuzzyInput
FuzzyInput *ph = new FuzzyInput(1);
//FuzzySet *phacid = new FuzzySet(0, 0, 5.5, 6.0);
//FuzzySet *phbase = new FuzzySet(5.5, 6.0, 14.0, 14.0);
FuzzySet *phACIDIC = new FuzzySet(0, 0, 5.5, 6.0);
FuzzySet *phALKALINE = new FuzzySet(5.5, 6.0, 14.0, 14.0);

FuzzyInput *ec = new FuzzyInput(2);
FuzzySet *ecLOW = (0, 0, 500, 550);
FuzzySet *ecOPTIMAL = (500, 550, 600, 650);
FuzzySet *ecHIGH = (600, 650, 700, 700);

//FuzzyOutput
FuzzyOutput *ph_pumpaction = new FuzzyOutput(1);
FuzzySet *ph_pumpoff = new FuzzySet(0, 0, 0, 0);
FuzzySet *ph_pumpon = new FuzzySet(0, 1, 1, 1);

FuzzyOutput *ec_pumpaction = new FuzzyOutput(2);
FuzzySet *ec_pumpoff = new FuzzySet(0, 0, 0, 0);
FuzzySet *ec_pumpon = new FuzzySet(0, 1, 1, 1);

void setup()
{
  // Set the Serial output
  Serial.begin(9600);
  // Set a random seed
  randomSeed(analogRead(0));

  ph->addFuzzySet(phACIDIC);
  ph->addFuzzySet(phALKALINE);
  fuzzy->addFuzzyInput(ph);

  ec->addFuzzySet(ecLOW);
  ec->addFuzzySet(ecOPTIMAL);
  ec->addFuzzySet(ecHIGH);
  fuzzy->addFuzzyInput(ec);

  ph_pumpaction->addFuzzySet(ph_pumpoff);
  ph_pumpaction->addFuzzySet(ph_pumpon);
  fuzzy->addFuzzyOutput(ph_pumpaction);

  ec_pumpaction->addFuzzySet(ec_pumpoff);
  ec_pumpaction->addFuzzySet(ec_pumpon);
  fuzzy->addFuzzyOutput(ec_pumpaction);

  //building fuzzy rule for ph AND ec
  // ACIDIC FIRST RULE

  // if ph acidic AND eclow THEN ph pump OFF AND ec pump ON
  FuzzyRuleAntecedent *phAcidicAndEcLow = new FuzzyRuleAntecedent();
  phAcidicAndEcLow->joinWithAND(ecLOW, ec_pumpon);
  FuzzyRuleConsequent *thenPhPumpOffAndEcPumpOn = new FuzzyRuleConsequent();
  thenPhPumpOffAndEcPumpOn->addOutput(ph_pumpoff);
  thenPhPumpOffAndEcPumpOn->addOutput(ec_pumpon);
  FuzzyRule *fuzzyRule1 = new FuzzyRule(1, phAcidicAndEcLow, thenPhPumpOffAndEcPumpOn);
  fuzzy->addFuzzyRule(fuzzyRule1);

  // if ph acidic AND ecOPTIMAL THEN ph pump OFF and ec pump OFF
  FuzzyRuleAntecedent *phAcidicAndEcOptimal = new FuzzyRuleAntecedent();
  phAcidicAndEcOptimal->joinWithAND(ecOPTIMAL, ec_pumpoff);
  FuzzyRuleConsequent *thenPhPumpOffAndEcPumpOff = new FuzzyRuleConsequent();
  thenPhPumpOffAndEcPumpOff->addOutput(ph_pumpoff);
  thenPhPumpOffAndEcPumpOff->addOutput(ec_pumpoff);
  FuzzyRule *fuzzyRule2 = new FuzzyRule(2, phAcidicAndEcOptimal, thenPhPumpOffAndEcPumpOff);
  fuzzy->addFuzzyRule(fuzzyRule2);

  // if ph acidic AND ecHIGH then ph pump OFF and ec pump OFF
  FuzzyRuleAntecedent *phAcidicAndEcHigh = new FuzzyRuleAntecedent();
  phAcidicAndEcHigh->joinWithAND(ecHIGH, ec_pumpoff);
  FuzzyRuleConsequent *thenPhPumpOffAndEcPumpOff2 = new FuzzyRuleConsequent();
  thenPhPumpOffAndEcPumpOff2->addOutput(ph_pumpoff);
  thenPhPumpOffAndEcPumpOff2->addOutput(ec_pumpoff);
  FuzzyRule *fuzzyRule3 = new FuzzyRule(3, phAcidicAndEcHigh, thenPhPumpOffAndEcPumpOff2);
  fuzzy->addFuzzyRule(fuzzyRule3);

}

void loop()
{
  float input1 = 5.7;
  float input2 = 400;
  fuzzy->setInput(1, input1);
  fuzzy->setInput(2, input2);
  fuzzy->fuzzify();
  // Running the Defuzzification
  float output1 = fuzzy->defuzzify(1);
  float output2 = fuzzy->defuzzify(2);
  // Printing something
  Serial.print("\nInput [input1, input2]: ");
  Serial.print("\t[");
  Serial.print(input1);
  Serial.print("\t");
  Serial.print(input2);
  Serial.print("]");
  Serial.print("\nOutput pertinence: ");
  Serial.print("\t\t");
  Serial.print(ph_pumpoff->getPertinence());
  Serial.print("\t");
  Serial.print(ph_pumpon->getPertinence());
  Serial.print("\t");
  Serial.print(ec_pumpoff->getPertinence());
  Serial.print("\t");
  Serial.print(ec_pumpon->getPertinence());
  Serial.println();
  Serial.print("Output ph pump [0=off, 1.0=on]:");
  Serial.print("\t");
  Serial.print(output1);
  Serial.println();
  Serial.print("Output ec pump [0=off, 1.0=on]:");
  Serial.print(output2);
  Serial.println();
  Serial.print("\nInput pertinence [acid, base, eclow, ecoptimal, echigh]");
  Serial.print("\n[");
  Serial.print(phACIDIC->getPertinence());
  Serial.print("\t");
  Serial.print(phALKALINE->getPertinence());
  Serial.print("\t");
  Serial.print(ecLOW->getPertinence());
  Serial.print("\t");
  Serial.print(ecOPTIMAL->getPertinence());
  Serial.print("\t");
  Serial.print(ecHIGH->getPertinence());
  Serial.print("]");
  Serial.print("\n");

  // wait 12 seconds
  delay(12000);
}

Serial output


Input [input1, input2]:             [5.70   400.00]
Output pertinence:      0.00    0.00    0.00    0.00
Output ph pump [0=off, 1.0=on]: 0.00
Output ec pump [0=off, 1.0=on]:   0.00

Input pertinence [acid, base, eclow, ecoptimal, echigh]
[0.60 1.00 0.00 0.00 0.00]
alvesoaj commented 5 years ago

Hello, I found some errors in your code when you was building the FuzzyAntecedent objects, take a look in this correction:

#include <Arduino.h>

#include <Fuzzy.h>

// Instantiating a Fuzzy object
Fuzzy *fuzzy = new Fuzzy();

//FuzzyInput
FuzzyInput *ph = new FuzzyInput(1);
//FuzzySet *phacid = new FuzzySet(0, 0, 5.5, 6.0);
//FuzzySet *phbase = new FuzzySet(5.5, 6.0, 14.0, 14.0);
FuzzySet *phACIDIC = new FuzzySet(0, 0, 5.5, 6.0);
FuzzySet *phALKALINE = new FuzzySet(5.5, 6.0, 14.0, 14.0);

FuzzyInput *ec = new FuzzyInput(2);
FuzzySet *ecLOW = new FuzzySet(0, 0, 500, 550);
FuzzySet *ecOPTIMAL = new FuzzySet(500, 550, 600, 650);
FuzzySet *ecHIGH = new FuzzySet(600, 650, 700, 700);

//FuzzyOutput
FuzzyOutput *ph_pumpaction = new FuzzyOutput(1);
FuzzySet *ph_pumpoff = new FuzzySet(0, 0, 0, 0);
FuzzySet *ph_pumpon = new FuzzySet(0, 1, 1, 1);

FuzzyOutput *ec_pumpaction = new FuzzyOutput(2);
FuzzySet *ec_pumpoff = new FuzzySet(0, 0, 0, 0);
FuzzySet *ec_pumpon = new FuzzySet(0, 1, 1, 1);

void setup()
{
  // Set the Serial output
  Serial.begin(9600);
  // Set a random seed
  randomSeed(analogRead(0));

  ph->addFuzzySet(phACIDIC);
  ph->addFuzzySet(phALKALINE);
  fuzzy->addFuzzyInput(ph);

  ec->addFuzzySet(ecLOW);
  ec->addFuzzySet(ecOPTIMAL);
  ec->addFuzzySet(ecHIGH);
  fuzzy->addFuzzyInput(ec);

  ph_pumpaction->addFuzzySet(ph_pumpoff);
  ph_pumpaction->addFuzzySet(ph_pumpon);
  fuzzy->addFuzzyOutput(ph_pumpaction);

  ec_pumpaction->addFuzzySet(ec_pumpoff);
  ec_pumpaction->addFuzzySet(ec_pumpon);
  fuzzy->addFuzzyOutput(ec_pumpaction);

  //building fuzzy rule for ph AND ec
  // ACIDIC FIRST RULE

  // if ph acidic AND eclow THEN ph pump OFF AND ec pump ON
  FuzzyRuleAntecedent *phAcidicAndEcLow = new FuzzyRuleAntecedent();
  phAcidicAndEcLow->joinWithAND(phACIDIC, ecLOW);
  FuzzyRuleConsequent *thenPhPumpOffAndEcPumpOn = new FuzzyRuleConsequent();
  thenPhPumpOffAndEcPumpOn->addOutput(ph_pumpoff);
  thenPhPumpOffAndEcPumpOn->addOutput(ec_pumpon);
  FuzzyRule *fuzzyRule1 = new FuzzyRule(1, phAcidicAndEcLow, thenPhPumpOffAndEcPumpOn);
  fuzzy->addFuzzyRule(fuzzyRule1);

  // if ph acidic AND ecOPTIMAL THEN ph pump OFF and ec pump OFF
  FuzzyRuleAntecedent *phAcidicAndEcOptimal = new FuzzyRuleAntecedent();
  phAcidicAndEcOptimal->joinWithAND(phACIDIC, ecOPTIMAL);
  FuzzyRuleConsequent *thenPhPumpOffAndEcPumpOff = new FuzzyRuleConsequent();
  thenPhPumpOffAndEcPumpOff->addOutput(ph_pumpoff);
  thenPhPumpOffAndEcPumpOff->addOutput(ec_pumpoff);
  FuzzyRule *fuzzyRule2 = new FuzzyRule(2, phAcidicAndEcOptimal, thenPhPumpOffAndEcPumpOff);
  fuzzy->addFuzzyRule(fuzzyRule2);

  // if ph acidic AND ecHIGH then ph pump OFF and ec pump OFF
  FuzzyRuleAntecedent *phAcidicAndEcHigh = new FuzzyRuleAntecedent();
  phAcidicAndEcHigh->joinWithAND(phACIDIC, ecHIGH);
  FuzzyRuleConsequent *thenPhPumpOffAndEcPumpOff2 = new FuzzyRuleConsequent();
  thenPhPumpOffAndEcPumpOff2->addOutput(ph_pumpoff);
  thenPhPumpOffAndEcPumpOff2->addOutput(ec_pumpoff);
  FuzzyRule *fuzzyRule3 = new FuzzyRule(3, phAcidicAndEcHigh, thenPhPumpOffAndEcPumpOff2);
  fuzzy->addFuzzyRule(fuzzyRule3);
}

void loop()
{
  float input1 = 5.7;
  float input2 = 400;
  fuzzy->setInput(1, input1);
  fuzzy->setInput(2, input2);
  fuzzy->fuzzify();
  // Running the Defuzzification
  float output1 = fuzzy->defuzzify(1);
  float output2 = fuzzy->defuzzify(2);
  // Printing something
  Serial.print("\n\n\n\n\n\nInput [input1, input2]: ");
  Serial.print("\t[");
  Serial.print(input1);
  Serial.print("\t");
  Serial.print(input2);
  Serial.print("]");
  Serial.print("\nOutput pertinence: ");
  Serial.print("\t\t");
  Serial.print(ph_pumpoff->getPertinence());
  Serial.print("\t");
  Serial.print(ph_pumpon->getPertinence());
  Serial.print("\t");
  Serial.print(ec_pumpoff->getPertinence());
  Serial.print("\t");
  Serial.print(ec_pumpon->getPertinence());
  Serial.println();
  Serial.print("Output ph pump [0=off, 1.0=on]: ");
  Serial.print(output1);
  Serial.println();
  Serial.print("Output ec pump [0=off, 1.0=on]: ");
  Serial.print(output2);
  Serial.println();
  Serial.print("\nInput pertinence [acid, alkaline, eclow, ecoptimal, echigh]");
  Serial.print("\n[");
  Serial.print(phACIDIC->getPertinence());
  Serial.print("\t");
  Serial.print(phALKALINE->getPertinence());
  Serial.print("\t");
  Serial.print(ecLOW->getPertinence());
  Serial.print("\t");
  Serial.print(ecOPTIMAL->getPertinence());
  Serial.print("\t");
  Serial.print(ecHIGH->getPertinence());
  Serial.print("]");
  Serial.print("\n");

  // wait 12 seconds
  delay(12000);
}

And the output:

Input [input1, input2]:     [5.70   400.00]
Output pertinence:      0.60    0.00    0.00    0.60
Output ph pump [0=off, 1.0=on]: 0.00
Output ec pump [0=off, 1.0=on]: 0.63

Input pertinence [acid, alkaline, eclow, ecoptimal, echigh]
[0.60   0.40    1.00    0.00    0.00]

But looking your example, I see that something is strange (I guess we found a bug)!

I will check it deeply.

servetcoskun commented 5 years ago

Thank you for helping! It works a lot more as expected now. I have ignored the "PH Alkaline" functions from https://imgur.com/a/Q20vhaK. So I end up with "The first rules" from https://imgur.com/a/Rk4qOhe, I have included the code below, but have removed the serial code for readability, I have instead included the serial monitor output. It looks a lot better! I am gonna run a couple of more tests and report back. The pump values are 0.67 as long as the pH and EC values are from the optimal values (in this case pHdesired: 5.5 and ECdesired: 550.0 < ec > 600.0).

...
  // if ph acidic AND eclow THEN ph pump OFF AND ec pump ON
  FuzzyRuleAntecedent *phAcidicAndEcLow = new FuzzyRuleAntecedent();
  phAcidicAndEcLow->joinWithAND(phACIDIC, ecLOW);
  FuzzyRuleConsequent *thenPhPumpOffAndEcPumpOn = new FuzzyRuleConsequent();
  thenPhPumpOffAndEcPumpOn->addOutput(ph_pumpoff);
  thenPhPumpOffAndEcPumpOn->addOutput(ec_pumpon);
  FuzzyRule *fuzzyRule1 = new FuzzyRule(1, phAcidicAndEcLow, thenPhPumpOffAndEcPumpOn);
  fuzzy->addFuzzyRule(fuzzyRule1);

  // if ph acidic AND ecOPTIMAL THEN ph pump OFF and ec pump OFF
  FuzzyRuleAntecedent *phAcidicAndEcOptimal = new FuzzyRuleAntecedent();
  phAcidicAndEcOptimal->joinWithAND(phACIDIC, ecOPTIMAL);
  FuzzyRuleConsequent *thenPhPumpOffAndEcPumpOff = new FuzzyRuleConsequent();
  thenPhPumpOffAndEcPumpOff->addOutput(ph_pumpoff);
  thenPhPumpOffAndEcPumpOff->addOutput(ec_pumpoff);
  FuzzyRule *fuzzyRule2 = new FuzzyRule(2, phAcidicAndEcOptimal, thenPhPumpOffAndEcPumpOff);
  fuzzy->addFuzzyRule(fuzzyRule2);

  // if ph acidic AND ecHIGH then ph pump OFF and ec pump OFF
  FuzzyRuleAntecedent *phAcidicAndEcHigh = new FuzzyRuleAntecedent();
  phAcidicAndEcHigh->joinWithAND(phACIDIC, ecHIGH);
  FuzzyRuleConsequent *thenPhPumpOffAndEcPumpOff2 = new FuzzyRuleConsequent();
  thenPhPumpOffAndEcPumpOff2->addOutput(ph_pumpoff);
  thenPhPumpOffAndEcPumpOff2->addOutput(ec_pumpoff);
  FuzzyRule *fuzzyRule3 = new FuzzyRule(3, phAcidicAndEcHigh, thenPhPumpOffAndEcPumpOff2);
  fuzzy->addFuzzyRule(fuzzyRule3);

  // if ph alkaline AND ecHIGH then ph pump ON and ec pump OFF
  FuzzyRuleAntecedent *phAlkalineAndEcHigh = new FuzzyRuleAntecedent();
  phAlkalineAndEcHigh->joinWithAND(phALKALINE, ecHIGH);
  FuzzyRuleConsequent *thenPhPumpOnAndEcPumpOff = new FuzzyRuleConsequent();
  thenPhPumpOnAndEcPumpOff->addOutput(ph_pumpon);
  thenPhPumpOnAndEcPumpOff->addOutput(ec_pumpoff);
  FuzzyRule *fuzzyRule4 = new FuzzyRule(4, phAlkalineAndEcHigh, thenPhPumpOnAndEcPumpOff);
  fuzzy->addFuzzyRule(fuzzyRule4);

  // if ph alkaline AND ecOPTIMAL then ph pump ON and ec pump OFF
  FuzzyRuleAntecedent *phAlkalineAndEcOptimal = new FuzzyRuleAntecedent();
  phAlkalineAndEcOptimal->joinWithAND(phALKALINE, ecOPTIMAL);
  FuzzyRuleConsequent *thenPhPumpOnAndEcPumpOff2 = new FuzzyRuleConsequent();
  thenPhPumpOnAndEcPumpOff2->addOutput(ph_pumpon);
  thenPhPumpOnAndEcPumpOff2->addOutput(ec_pumpoff);
  FuzzyRule *fuzzyRule5 = new FuzzyRule(5, phAlkalineAndEcOptimal, thenPhPumpOnAndEcPumpOff2);
  fuzzy->addFuzzyRule(fuzzyRule5);

  // if ph alkaline AND ecLOW then ph pump ON and ec pump ON
  FuzzyRuleAntecedent *phAlkalineAndEcLow = new FuzzyRuleAntecedent();
  phAlkalineAndEcLow->joinWithAND(phALKALINE, ecLOW);
  FuzzyRuleConsequent *thenPhPumpOnAndEcPumpOn = new FuzzyRuleConsequent();
  thenPhPumpOnAndEcPumpOn->addOutput(ph_pumpon);
  thenPhPumpOnAndEcPumpOn->addOutput(ec_pumpon);
  FuzzyRule *fuzzyRule6 = new FuzzyRule(6, phAlkalineAndEcLow, thenPhPumpOnAndEcPumpOn);
  fuzzy->addFuzzyRule(fuzzyRule6);
...
Input [input1, input2]:     [7.18   368.40]
Output pertinence:      0.00    1.00    0.00    1.00
Output ph pump [0=off, 1.0=on]: 0.67
Output ec pump [0=off, 1.0=on]: 0.67
Input pertinence [acid, alkaline, eclow, ecoptimal, echigh]
[0.00   1.00    1.00    0.00    0.00]

Input [input1, input2]:     [4.91   76.03]
Output pertinence:      1.00    0.00    0.00    1.00
Output ph pump [0=off, 1.0=on]: 0.00
Output ec pump [0=off, 1.0=on]: 0.67
Input pertinence [acid, alkaline, eclow, ecoptimal, echigh]
[1.00   0.00    1.00    0.00    0.00]

Input [input1, input2]:     [6.07   567.40]
Output pertinence:      0.00    1.00    1.00    0.00
Output ph pump [0=off, 1.0=on]: 0.67
Output ec pump [0=off, 1.0=on]: 0.00
Input pertinence [acid, alkaline, eclow, ecoptimal, echigh]
[0.00   1.00    0.00    1.00    0.00]

Input [input1, input2]:     [1.62   62.45]
Output pertinence:      1.00    0.00    0.00    1.00
Output ph pump [0=off, 1.0=on]: 0.00
Output ec pump [0=off, 1.0=on]: 0.67
Input pertinence [acid, alkaline, eclow, ecoptimal, echigh]
[1.00   0.00    1.00    0.00    0.00]

Input [input1, input2]:     [5.17   26.88]
Output pertinence:      1.00    0.00    0.00    1.00
Output ph pump [0=off, 1.0=on]: 0.00
Output ec pump [0=off, 1.0=on]: 0.67
Input pertinence [acid, alkaline, eclow, ecoptimal, echigh]
[1.00   0.00    1.00    0.00    0.00]

Input [input1, input2]:     [2.69   377.09]
Output pertinence:      1.00    0.00    0.00    1.00
Output ph pump [0=off, 1.0=on]: 0.00
Output ec pump [0=off, 1.0=on]: 0.67
Input pertinence [acid, alkaline, eclow, ecoptimal, echigh]
[1.00   0.00    1.00    0.00    0.00]

Input [input1, input2]:     [2.03   574.29]
Output pertinence:      1.00    0.00    1.00    0.00
Output ph pump [0=off, 1.0=on]: 0.00
Output ec pump [0=off, 1.0=on]: 0.00
Input pertinence [acid, alkaline, eclow, ecoptimal, echigh]
[1.00   0.00    0.00    1.00    0.00]

Input [input1, input2]:     [9.26   345.49]
Output pertinence:      0.00    1.00    0.00    1.00
Output ph pump [0=off, 1.0=on]: 0.67
Output ec pump [0=off, 1.0=on]: 0.67
Input pertinence [acid, alkaline, eclow, ecoptimal, echigh]
[0.00   1.00    1.00    0.00    0.00]

Input [input1, input2]:     [4.49   526.31]
Output pertinence:      0.53    0.00    0.53    0.47
Output ph pump [0=off, 1.0=on]: 0.00
Output ec pump [0=off, 1.0=on]: 0.25
Input pertinence [acid, alkaline, eclow, ecoptimal, echigh]
[1.00   0.00    0.47    0.53    0.00]
servetcoskun commented 5 years ago

I think it works fine now. Do you want me to keep it open or close it @zerokol ?

alvesoaj commented 5 years ago

Great. Keep the issue open a bit more, until I finish one test.