Translate

Kendali Suhu Menggunakan FUZZY LOGIC MAMDANI dengan Library eFLL

Kendali Suhu Menggunakan FUZZY LOGIC MAMDANI dengan Library eFLL


          Pada kesempatan kali ini saya akan menjelaskan mengenai bagaimana cara membuat sebuah alat yang dapat digunakan untuk mengendalikan suhu pemanas sehingga suhunya sesuai setpoint atau fuzzy rule yang telah dibuat / diinginkan. alat ini menggunakan pemanas berupa peltier 5v dan sensor suhu Ds18b20 sebanyak 2 buah serta untuk pemprosesan datanya menggunakan Arduino Uno. untuk lebih jelasnya berikut adalah koding dan komponennya. untuk library eFLL bisa didownload pada link berikut.



1. Komponenya dan Skema

    a. Arduino Uno
    b. Sensor Suhu Ds18b20
    c. Transistor TIP3055
    d. Peltier 5v
    e. Resistor 330 ohm dan 4k7 ohm




2. Fuzzy Logic Mamdani

a. Membership Function





b. Fuzzy Rule



c. Defuzzyfikasi




d. Program Arduino IDE

#include <Fuzzy.h>
#include <Wire.h>
#include <DallasTemperature.h>
#include <OneWire.h>
#define ONE_WIRE_BUS 2  

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

float tempobject;
float temppeltier;

Fuzzy *fuzzy = new Fuzzy();

// FuzzyInput
FuzzySet *dingin = new FuzzySet(0, 0, 35, 36);
FuzzySet *normal = new FuzzySet(35, 36, 36, 37);
FuzzySet *panas = new FuzzySet(36, 37, 100, 100);

// FuzzyInput
FuzzySet *rendah = new FuzzySet(0, 0, 30, 40);
FuzzySet *sedang = new FuzzySet(30, 40, 40, 50);
FuzzySet *tinggi = new FuzzySet(40, 50, 100, 100);

// FuzzyOutput
FuzzySet *minimum = new FuzzySet(0, 0, 1, 2);
FuzzySet *average = new FuzzySet(2, 50, 50, 100);
FuzzySet *maximum = new FuzzySet(100, 200, 255, 255);

void setup()
{

  Serial.begin(9600);
  pinMode(9,OUTPUT);
  
  // FuzzyInput suhuobject
  FuzzyInput *suhuobject = new FuzzyInput(1);

  suhuobject->addFuzzySet(dingin);
  suhuobject->addFuzzySet(normal);
  suhuobject->addFuzzySet(panas);
  fuzzy->addFuzzyInput(suhuobject);

  // FuzzyInput suhupeltier
  FuzzyInput *suhupeltier = new FuzzyInput(2);

  suhupeltier->addFuzzySet(rendah);
  suhupeltier->addFuzzySet(sedang);
  suhupeltier->addFuzzySet(tinggi);
  fuzzy->addFuzzyInput(suhupeltier);

  // FuzzyOutput pwm
  FuzzyOutput *pwmout = new FuzzyOutput(1);

  pwmout->addFuzzySet(minimum);
  pwmout->addFuzzySet(average);
  pwmout->addFuzzySet(maximum);
  fuzzy->addFuzzyOutput(pwmout);

  // Building FuzzyRule 1
  FuzzyRuleAntecedent *ifsuhuobjectDinginAndsuhupeltierRendah = new FuzzyRuleAntecedent();
  ifsuhuobjectDinginAndsuhupeltierRendah->joinWithAND(dingin, rendah); 
  FuzzyRuleConsequent *thenPwmoutMaximum= new FuzzyRuleConsequent();
  thenPwmoutMaximum->addOutput(maximum);
  FuzzyRule *fuzzyRule1 = new FuzzyRule(1, ifsuhuobjectDinginAndsuhupeltierRendah, thenPwmoutMaximum);
  fuzzy->addFuzzyRule(fuzzyRule1);

  // Building FuzzyRule 2
  FuzzyRuleAntecedent *ifsuhuobjectDinginAndsuhupeltierSedang = new FuzzyRuleAntecedent();
  ifsuhuobjectDinginAndsuhupeltierSedang->joinWithAND(dingin, sedang); 
  //FuzzyRuleConsequent *thenPwmoutMaximum= new FuzzyRuleConsequent();
  thenPwmoutMaximum->addOutput(maximum);
  FuzzyRule *fuzzyRule2 = new FuzzyRule(2, ifsuhuobjectDinginAndsuhupeltierSedang, thenPwmoutMaximum);
  fuzzy->addFuzzyRule(fuzzyRule2);

  // Building FuzzyRule 3
  FuzzyRuleAntecedent *ifsuhuobjectDinginAndsuhupeltierTinggi = new FuzzyRuleAntecedent();
  ifsuhuobjectDinginAndsuhupeltierTinggi->joinWithAND(dingin, tinggi); 
  //FuzzyRuleConsequent *thenPwmoutMaximum= new FuzzyRuleConsequent();
  thenPwmoutMaximum->addOutput(maximum);
  FuzzyRule *fuzzyRule3 = new FuzzyRule(3, ifsuhuobjectDinginAndsuhupeltierTinggi, thenPwmoutMaximum);
  fuzzy->addFuzzyRule(fuzzyRule3);

  // Building FuzzyRule 4
  FuzzyRuleAntecedent *ifsuhuobjectNormalAndsuhupeltierRendah= new FuzzyRuleAntecedent();
  ifsuhuobjectNormalAndsuhupeltierRendah->joinWithAND(normal, rendah); 
  FuzzyRuleConsequent *thenPwmoutAverage= new FuzzyRuleConsequent();
  thenPwmoutAverage->addOutput(average);
  FuzzyRule *fuzzyRule4 = new FuzzyRule(4, ifsuhuobjectNormalAndsuhupeltierRendah, thenPwmoutAverage);
  fuzzy->addFuzzyRule(fuzzyRule4);

  // Building FuzzyRule 5
  FuzzyRuleAntecedent *ifsuhuobjectNormalAndsuhupeltierSedang= new FuzzyRuleAntecedent();
  ifsuhuobjectNormalAndsuhupeltierSedang->joinWithAND(normal, sedang); 
  //FuzzyRuleConsequent *thenPwmoutAverage= new FuzzyRuleConsequent();
  thenPwmoutAverage->addOutput(average);
  FuzzyRule *fuzzyRule5 = new FuzzyRule(5, ifsuhuobjectNormalAndsuhupeltierSedang, thenPwmoutAverage);
  fuzzy->addFuzzyRule(fuzzyRule5);

  // Building FuzzyRule 6
  FuzzyRuleAntecedent *ifsuhuobjectNormalAndsuhupeltierTinggi= new FuzzyRuleAntecedent();
  ifsuhuobjectNormalAndsuhupeltierTinggi->joinWithAND(normal, tinggi); 
  //FuzzyRuleConsequent *thenPwmoutAverage= new FuzzyRuleConsequent();
  thenPwmoutAverage->addOutput(average);
  FuzzyRule *fuzzyRule6 = new FuzzyRule(6, ifsuhuobjectNormalAndsuhupeltierTinggi, thenPwmoutAverage);
  fuzzy->addFuzzyRule(fuzzyRule6);

  // Building FuzzyRule 7
  FuzzyRuleAntecedent *ifsuhuobjectPanasAndsuhupeltierRendah= new FuzzyRuleAntecedent();
  ifsuhuobjectPanasAndsuhupeltierRendah->joinWithAND(panas, rendah); 
  FuzzyRuleConsequent *thenPwmoutMinimum= new FuzzyRuleConsequent();
  thenPwmoutMinimum->addOutput(minimum);
  FuzzyRule *fuzzyRule7 = new FuzzyRule(7, ifsuhuobjectPanasAndsuhupeltierRendah, thenPwmoutMinimum);
  fuzzy->addFuzzyRule(fuzzyRule7);

  // Building FuzzyRule 8
  FuzzyRuleAntecedent *ifsuhuobjectPanasAndsuhupeltierSedang= new FuzzyRuleAntecedent();
  ifsuhuobjectPanasAndsuhupeltierSedang->joinWithAND(panas, sedang); 
  //FuzzyRuleConsequent *thenPwmoutMinimum= new FuzzyRuleConsequent();
  thenPwmoutMinimum->addOutput(minimum);
  FuzzyRule *fuzzyRule8 = new FuzzyRule(8, ifsuhuobjectPanasAndsuhupeltierSedang, thenPwmoutMinimum);
  fuzzy->addFuzzyRule(fuzzyRule8);

  // Building FuzzyRule 9
  FuzzyRuleAntecedent *ifsuhuobjectPanasAndsuhupeltierTinggi= new FuzzyRuleAntecedent();
  ifsuhuobjectPanasAndsuhupeltierTinggi->joinWithAND(panas, tinggi); 
  //FuzzyRuleConsequent *thenPwmoutMinimum= new FuzzyRuleConsequent();
  thenPwmoutMinimum->addOutput(minimum);
  FuzzyRule *fuzzyRule9 = new FuzzyRule(9, ifsuhuobjectPanasAndsuhupeltierTinggi, thenPwmoutMinimum);
  fuzzy->addFuzzyRule(fuzzyRule9);
  
}

void loop()
{

  sensors.requestTemperatures();
  tempobject = sensors.getTempCByIndex(0);
  temppeltier = sensors.getTempCByIndex(1);

  Serial.print("Suhu Object: ");
  Serial.print(tempobject);
  Serial.print("|| Suhu Peltier: ");
  Serial.println(temppeltier);

  fuzzy->setInput(1, tempobject);
  fuzzy->setInput(2, temppeltier);

  fuzzy->fuzzify();

  Serial.print("Suhu Object: Dingin-> ");
  Serial.print(dingin->getPertinence());
  Serial.print(", Normal-> ");
  Serial.print(normal->getPertinence());
  Serial.print(", Panas-> ");
  Serial.println(panas->getPertinence());

  Serial.print("Suhu Peltier: Rendah-> ");
  Serial.print(rendah->getPertinence());
  Serial.print(",  Sedang-> ");
  Serial.print(sedang->getPertinence());
  Serial.print(",  Tinggi-> ");
  Serial.print(tinggi->getPertinence());

  float output1 = fuzzy->defuzzify(1);

  Serial.println("Output: ");
  Serial.print("PWMOUT: Minimum-> ");
  Serial.print(minimum->getPertinence());
  Serial.print(", Average-> ");
  Serial.print(average->getPertinence());
  Serial.print(", Maximum-> ");
  Serial.println(maximum->getPertinence());

  Serial.print("HASIL: ");
  Serial.print("PWM: ");
  Serial.println(output1);
  analogWrite(9,output1);
  
  delay(1000);
}





e. VIDEO HASILNYA








Alat Pakan Ikan Otomatis dan Monitor PH, Turbidity, Amoniak, Suhu Air Kolam Ikan dan Setting Batas Setpoint

Alat Pakan Ikan Otomatis dan Monitor PH, Turbidity, Amoniak, Suhu Air Kolam Ikan dan Setting Batas Setpoint


        Pada kesempatan kali ini saya akan menjelaskan mengenai bagaimana cara membuat sebuah alat yang dapat memonitor PH,TDS/NTU,Amoniak,Suhu dan juga dapat memberikan pakan ikan otomatis pada jam-jam tertentu tergantung dari setting waktu pakannya. alat ini juga dilengkapi dengan EEPROM sehingga ketika lampu padam maka setting batasnya tidaklah menjadi 0 namun sesuai setting yang kita inputkan. untuk lebih jelasnya berikut adalah koding dan komponennya.


1. Komponennya:

    a. Arduino Uno
    b. Sensor PH
    c. Turbidity Sensor
    d. Sensor Ds18b20
    e. Sensor HC-SRF04
    f. Nodemcu ESP8266
    g. Modul Relay 3 Channel
    h. Mini Servo
    i. LCD 20x4 + I2C
    j. Push Button




2. Program Arduino IDE 

#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal_I2C.h>
#include <DS3231.h>
#include <EEPROM.h>
#define ONE_WIRE_BUS 8  
#include <Servo.h>

#define trigPin1 6
#define echoPin1 5
#define trigPin2 4
#define echoPin2 3

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

LiquidCrystal_I2C lcd(0x27,20,4);
DS3231  rtc(SDA, SCL);
Servo myservo;

int addr1 = 0;
int addr2 = 1;
int addr3 = 2;
int addr4 = 3;
int addr5 = 4;

Time  t;
int jampagi,jamsiang,jamsore;
float TempC;
float pHValue;
int tds;
int adctds;
int adcPH;
int TempCx;
int pHValuex;
int ntux;
float ntufix;
long duration1, distance1;
long duration2, distance2;  
int btset = 2;
int btup = 10;
int btdown = 11;
int btok = 12;
int btsetx;
int btupx;
int btdownx;
int btokx;
float batasamo;
float batasph;
float amoniak;
int relayout = A3;
int relayin = A2;
int relayaerator = 7;
int tanda = 0;
int kolam;
int tinggipakan;


void setup(){  
  
jampagi = EEPROM.read(addr1);
jamsiang = EEPROM.read(addr2);
jamsore = EEPROM.read(addr3);
batasamo = EEPROM.read(addr4);
batasph = EEPROM.read(addr5);

pinMode(relayout,OUTPUT);
pinMode(relayin,OUTPUT);
pinMode(relayaerator,OUTPUT);
digitalWrite(relayout,LOW);
digitalWrite(relayin,LOW);
digitalWrite(relayaerator,LOW);

pinMode(btset,INPUT_PULLUP);
pinMode(btup,INPUT_PULLUP);
pinMode(btdown,INPUT_PULLUP);
pinMode(btok,INPUT_PULLUP);

pinMode(trigPin1, OUTPUT);
pinMode(echoPin1, INPUT);
pinMode(trigPin2, OUTPUT);
pinMode(echoPin2, INPUT);  

Wire.begin();  
sensors.begin();
Serial.begin(9600);
lcd.begin();  
lcd.clear(); 

rtc.begin();
//rtc.setDOW(WEDNESDAY);     // Set Day-of-Week to SUNDAmy
//rtc.setTime(13, 15, 0);     // Set the time to 12:00:00 (24hr format)
//rtc.setDate(1, 1, 2014);   // Set the date to January 1st, 2014

myservo.attach(9);
myservo.write(100);
}

void loop(){

btsetx = digitalRead(btset);
btupx = digitalRead(btup);
btdownx = digitalRead(btdown);
btokx = digitalRead(btok);

if(btsetx == 0){
delay(1000);
lcd.clear();
setjampagi();
setjamsiang();
setjamsore();
setbatasamo();
setbatasph();
}
  
 t = rtc.getTime();

  //ketinggian air kolam 
  digitalWrite(trigPin1, LOW);  // Added this line
  delayMicroseconds(2); // Added this line
  digitalWrite(trigPin1, HIGH);
  delayMicroseconds(10); // Added this line
  digitalWrite(trigPin1, LOW);
  duration1 = pulseIn(echoPin1, HIGH);
  distance1 = (duration1/2) / 29.1;

  //ketinggian pakan ikan
  digitalWrite(trigPin2, LOW);  // Added this line
  delayMicroseconds(2); // Added this line
  digitalWrite(trigPin2, HIGH);
  delayMicroseconds(10); // Added this line
  digitalWrite(trigPin2, LOW);
  duration2 = pulseIn(echoPin2, HIGH);
  distance2 = (duration2/2) / 29.1;
  
  if(distance1 > 35){
    distance1 = 35;
  }

  if(distance2 > 30){
    distance2 = 30;
  }
  
  kolam = 35 - distance1; 
  tinggipakan = map(distance2, 5,30,100,0);

if((kolam >= 29)&&(kolam <= 31)){
  digitalWrite(relayin,LOW);
  digitalWrite(relayout,LOW);  
  }

if(kolam < 29){
  digitalWrite(relayin,HIGH);
  digitalWrite(relayout,LOW);
  }

if(kolam > 31){
  digitalWrite(relayin,LOW);
  digitalWrite(relayout,HIGH);
  }
     
 adcPH = analogRead(A0); //menggunakan pin A0 untuk membaca output sensor pH
 pHValue = (adcPH - 906.84) / -37.283;

 adctds = analogRead(A1);             
 tds = map(adctds, 855, 1, 0, 100);
 
 pHValuex = pHValue * 100.0;
 
  sensors.requestTemperatures();
  TempC = sensors.getTempCByIndex(0); // Celcius
  TempCx =  TempC * 100.0;

if(pHValue < 6.5){
  amoniak = (pHValue / TempC) * 0.202; 
}

if(pHValue == 7.0){
  amoniak = (pHValue / TempC) * 1.131; 
}

if(pHValue > 7.0){
  amoniak = (pHValue / TempC) * 3.306; 
}


if(amoniak > batasamo){
  digitalWrite(relayaerator,HIGH);
  }

if(amoniak <= batasamo){
  digitalWrite(relayaerator,LOW);
  }

  
if((t.hour == jampagi)&&(jampagi > 0)&&(tanda == 0)){
  myservo.write(150);
  delay(5000);
  myservo.write(100);
  tanda = 1;
}

if((t.hour == jamsiang)&&(jamsiang > 0)&&(tanda == 1)){
  myservo.write(150);
  delay(5000);
  myservo.write(100);
  tanda = 2;
}

if((t.hour == jamsore)&&(jamsore > 0)&&(tanda == 2)){
  myservo.write(150);
  delay(5000);
  myservo.write(100);
  tanda = 0;
}

  
  lcd.setCursor(0,0);
  lcd.print("TDS:");
  lcd.print(tds);
  lcd.print("% ");
 
  lcd.print("PH:");
  lcd.print(pHValue);
  lcd.print("  ");

  lcd.setCursor(0,1);
  lcd.print("T:");
  lcd.print(TempC,1);
  lcd.print("c ");
  
  lcd.print(batasamo);
  lcd.print("/");
  lcd.print(batasph);
  lcd.print(" ");

  lcd.setCursor(0,2);
  lcd.print(t.hour, DEC);
  lcd.print(":");
  lcd.print(t.min, DEC);
  lcd.print(":");
  lcd.print(t.sec, DEC);
  lcd.print("  ");
  lcd.print(jampagi);
  lcd.print("/");
  lcd.print(jamsiang);
  lcd.print("/");
  lcd.print(jamsore);
  lcd.print("  ");

  lcd.setCursor(0,3);
  lcd.print("S=");
  lcd.print(kolam);
  lcd.print("/");
  lcd.print(tinggipakan);
  lcd.print("  ");

  lcd.setCursor(10,3);
  lcd.print("Mg/l:");
  lcd.print(amoniak);
  lcd.print(" ");

  Serial.print("*");
  Serial.print(pHValue * 100.0);
  Serial.print(",");
  Serial.print(tds);
  Serial.print(",");
  Serial.print(amoniak * 100.0);
  Serial.print(",");
  Serial.print(TempC * 100.0);
  Serial.println("#");
  
  delay(1000);
}


void setjampagi(){
  
btsetx = digitalRead(btset);
btupx = digitalRead(btup);
btdownx = digitalRead(btdown);
btokx = digitalRead(btok);  

  lcd.setCursor(0,0);
  lcd.print("Waktu Pakan Pagi");
  lcd.setCursor(0,1);
  lcd.print("Jam: ");
  lcd.print(jampagi);
  lcd.print("   ");

if(btupx == 0){
  delay(200);
  jampagi++; 
}

if(btdownx == 0){
  delay(200);
  jampagi--; 
}

if(jampagi > 23){
jampagi = 0;  
}

if(btokx == 0){
  lcd.clear();
  delay(2000);
  EEPROM.write(addr1, jampagi);
  return; 
}

setjampagi();  
}


void setjamsiang(){
  
btsetx = digitalRead(btset);
btupx = digitalRead(btup);
btdownx = digitalRead(btdown);
btokx = digitalRead(btok);  

  lcd.setCursor(0,0);
  lcd.print("Waktu Pakan Siang  ");
  lcd.setCursor(0,1);
  lcd.print("Jam: ");
  lcd.print(jamsiang);
  lcd.print("   ");

if(btupx == 0){
  delay(200);
  jamsiang++; 
}

if(btdownx == 0){
  delay(200);
  jamsiang--; 
}

if(jamsiang > 23){
jamsiang = 0;  
}

if(btokx == 0){
  lcd.clear();
  delay(2000);
  EEPROM.write(addr2, jamsiang);
  return; 
}

setjamsiang();  
}


void setjamsore(){
  
btsetx = digitalRead(btset);
btupx = digitalRead(btup);
btdownx = digitalRead(btdown);
btokx = digitalRead(btok);  

  lcd.setCursor(0,0);
  lcd.print("Waktu Pakan Sore  ");
  lcd.setCursor(0,1);
  lcd.print("Jam: ");
  lcd.print(jamsore);
  lcd.print("   ");

if(btupx == 0){
  delay(200);
  jamsore++; 
}

if(btdownx == 0){
  delay(200);
  jamsore--; 
}

if(jamsore > 23){
jamsore = 0;  
}

if(btokx == 0){
  lcd.clear();
  delay(2000);
  EEPROM.write(addr3, jamsore);
  return; 
}

setjamsore();  
}


void setbatasamo(){
  
btsetx = digitalRead(btset);
btupx = digitalRead(btup);
btdownx = digitalRead(btdown);
btokx = digitalRead(btok);  

  lcd.setCursor(0,0);
  lcd.print("BATAS AMONIAK  ");
  lcd.setCursor(0,1);
  lcd.print("mg/l: ");
  lcd.print(batasamo);
  lcd.print("   ");

if(btupx == 0){
  delay(200);
  batasamo = batasamo + 0.1; 
}

if(btdownx == 0){
  delay(200);
  batasamo = batasamo - 0.1; 
}

if(batasamo > 100.0){
batasamo = 0;  
}

if(btokx == 0){
  lcd.clear();
  delay(2000);
  EEPROM.write(addr4, batasamo);
  return; 
}

setbatasamo();  
}



void setbatasph(){
  
btsetx = digitalRead(btset);
btupx = digitalRead(btup);
btdownx = digitalRead(btdown);
btokx = digitalRead(btok);  

  lcd.setCursor(0,0);
  lcd.print("BATAS PH  ");
  lcd.setCursor(0,1);
  lcd.print("PH: ");
  lcd.print(batasph);
  lcd.print("   ");

if(btupx == 0){
  delay(200);
  batasph = batasph + 0.1; 
}

if(btdownx == 0){
  delay(200);
  batasph = batasph - 0.1; 
}

if(batasph > 100.0){
batasph = 0;  
}

if(btokx == 0){
  lcd.clear();
  delay(2000);
  EEPROM.write(addr5, batasph);
  return; 
}

setbatasph();  
}



3. Program Nodemcu ESP8266

#include <ESP8266WiFi.h>
#include <ThingSpeak.h>
#include <WiFiClient.h>

int temp;
int x = 5;
int y;

int value1;
int value2;
int value3;
int value4;

float ph;
int tds;
float amoniak;
float suhu;

int datain1;
int datain2;
int datain3;
int datain4;

String dataIn;
String dt[10];
int i;
boolean parsing = false;

String apiKey = "UYGFUY87JKJGJ6HKS";     //  Enter your Write API key from ThingSpeak
const char* resource = "/update?api_key=";

const char* ssid =  "hotspothpku";     // replace with your wifi ssid and wpa2 key
const char* pass =  "123456789";
const char* server = "api.thingspeak.com";

WiFiClient  client;

void setup()
{
 
  dataIn="";
  Serial.begin(9600);
  delay(10);

  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

      while (WiFi.status() != WL_CONNECTED)
     {
            delay(500);
            Serial.print(".");
     }
      Serial.println("");
      Serial.println("WiFi connected");

}

void loop()
{

while(Serial.available()>0) {
//   dataIn="";
    char inChar = (char)Serial.read();
    dataIn += inChar;
    if (inChar == '\n') {
    parsing = true;
  }
}

if(parsing){
    parsingData();
       
  if (client.connect(server,80))   //   "184.106.153.149" or api.thingspeak.com
                      {
                           
                             String postStr = apiKey;
                             postStr +="&field1=";
                             postStr += String(ph);
                             postStr += "\r\n\r\n";

                             client.print(String("GET ") + resource + apiKey + "&field1=" + ph + "&field2=" + tds + "&field3=" + amoniak + "&field4=" + suhu + " HTTP/1.1\r\n" + "Host: " + server + "\r\n" + "Connection: close\r\n\r\n");
                                       
                             client.print("Host: api.thingspeak.com\n");
                             client.print("Connection: close\n");
                             client.print("X-THINGSPEAKAPIKEY: "+apiKey+"\n");
                             client.print("Content-Type: application/x-www-form-urlencoded\n");
                             client.print("Content-Length: ");
                             client.print(postStr.length());
                             client.print("\n\n");
                             client.print(postStr);
                           
                          
                             Serial.println(". Send to Thingspeak.");
                        }
                       
          client.stop();

          //Serial.println("Waiting...");

  delay(10000);
 
 }
}

void parsingData(){
int j=0;

//kirim data yang telah diterima sebelumnya
//Serial.print("data masuk : ");
//Serial.print(dataIn);
//Serial.print("\n");

//inisialisasi variabel, (reset isi variabel)
dt[j]="";
//proses parsing data
for(i=1;i<dataIn.length();i++){
//pengecekan tiap karakter dengan karakter (#) dan (,)
if ((dataIn[i] == '#') || (dataIn[i] == ','))
{
//increment variabel j, digunakan untuk merubah index array penampung
j++;
dt[j]="";       //inisialisasi variabel array dt[j]
}
else
{
//proses tampung data saat pengecekan karakter selesai.
dt[j] = dt[j] + dataIn[i];
}
}

 datain1 = dt[0].toInt();
 datain2 = dt[1].toInt();
 datain3 = dt[2].toInt();
 datain4 = dt[3].toInt();

//kirim data hasil parsing
Serial.print("data 1 : ");
Serial.print(datain1);
Serial.print("\n");
Serial.print("data 2 : ");
Serial.print(datain2);
Serial.print("\n");
Serial.print("data 3 : ");
Serial.print(datain3);

 ph = datain1 / 100.0;
 tds = datain2 / 1;
 amoniak = datain3 / 100.0;
 suhu = datain4 / 100.0;
 
}



4. VIDEO HASILNYA




PELATIHAN ROBOT UNTUK PEMULA (BISA KURSUS ONLINE / OFFLINE)


PELATIHAN ROBOT UNTUK PEMULA 

        Kabar gembira untuk pelajar wilayah kediri jawa timur dan sekitarnya karena kami telah membuka jasa pelatihan robotika untuk pemula yaitu untuk level SD - SMP - SMA, materi pelatihan robotika dari kami sangat sederhana namun bisa diaplikasikan langsung ke robot karena kami menyediakan beberapa item untuk peserta pelatihan seperti keterangan diawah ini dan juga materi pelatihan yang memudahkan siswa untuk mempelajari robot secara mendalam. berikut adalah materi pelatihan dan item yang didapat peserta. 


1. Item yang didapat peserta
    a. Modul Pembelajaran (Hardcopy)
    b. Robot Pelatihan
    c. Komponen dan Sensor yang dipakai
 
 
2. Materi pelatihan
    a. Cara memasang komponen dan sensor pada robot
    b. Cara memprogram robot agar sesuai yang diinginkan
    c. Cara menjalankan robot sesuai skema dan koding yang dibuat
    d. Improvisasi robot oleh peserta didik / siswa
 
 
3. Level pelatihan:
    a. Dasar : SD - SMP - SMA
    b. Menengah : Mahasiwa / Pekerja (Segala Usia)
    c. Lanjut (Advance) : Mahasiwa / Pekerja (Segala Usia)


4. Waktu Pelatihan dan Biaya:
    a. Waktu pelatihan 1-2 jam tergantung tingkat pemahaman peserta
    b. Jumlah pertemuan maksimal 3 atau 4 kali pertemuan 
    c. Biaya pelatihan tergantung pada levelnya.
    d. Biaya level dasar : Rp. 800.000,-  
    e. Biaya level menengah : Rp. 1.000.000,-
    f. Biaya Level Lanjut (Advance) : Rp. 1.500.000,- (Tergantung tingkat kesulitan)


5, Materi Pelatihan Ada 6 Jenis Robot (Peserta memilih salah satu) yaitu:
    a. Robot Line Follower
    b. Robot Wall Avoider
    c. Robot Lengan
    d. Robot Remot Control
    e. Robot Kendali Joystick
    f. Robot Kendali HP


6. VIDEO REVIEW ROBOT




Membuat ECG / EKG Electrocardiograph

Membuat ECG / EKG Electrocardiograph  

        Pada kesempatan kali ini saya akan menjelaskan mengenai bagaimana cara membuat sebuah alat yang dapat mendeteksi sinyal yang biasa disebut ECG atau EKG yang mana komponenya bisa didapat mudah dipasaran seperti ICTL084, ICLM358, untuk lebih jelasnya berikut adalah skema dan hasilnya.


a. Skema Rangkaian



b. Power Supply



c. Board Sudah Jadi




d. Video Hasilnya





Monitor Tegangan dan Arus DC (INA219) Thingspeak

Monitor Tegangan dan Arus DC (INA219) Thingspeak 

         Pada kesempatan kali ini saya akan menjelaskan mengenai bagaimana cara membuat sebuah alat yang dapat memonitor tegangan dan arus DC dengan sensor INA219 dan VDC modul. alat ini menggunakan mikrokontroller Nodemcu ESP8266 dan menggunakan server Thingspeak untuk monitor onlinenya.  untuk lebih jelasnya berikut adalah koding dan skemanya.


a. Skema 



b. Program Arduino IDE

#include <Wire.h>
#include <ESP8266WiFi.h>
#include <Adafruit_INA219.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);

float busVoltage = 0;
float arusac = 0; // Measure in milli amps
float dayaac = 0;
float vac;
float arusdc;
float dayadc;
float vdc;
int adcteg;
float tegangan;
float k = 1.2;
float resistansi;
int cacah;
float Vdcaverage;
float Idcaverage;
float resivitas;

Adafruit_INA219 sensor219; // Declare and instance of INA219


WiFiClient client;
// ThingSpeak Settings
String apiKey = "87K76FHGFJKV4VVH";
const char *ssid = "hotspothpku";
const char *pass = "123456789";
const char* server = "api.thingspeak.com";
const char* resource = "/update?api_key=";

 
void setup() {
  Serial.begin(9600);
  sensor219.begin();
  lcd.clear();
  lcd.begin();
  lcd.noCursor();
  
  //setting ke online
  Serial.println("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED){\
    delay(200);
    Serial.println(".");
    }
  Serial.println("");
  Serial.println("WiFi connected");

}
 
void loop() {

cacah++;
 
    sensor219.begin();
    busVoltage = sensor219.getBusVoltage_V();
    arusdc = sensor219.getCurrent_mA();
    arusdc = (arusdc / 10.0) * -1;
    
    adcteg = analogRead(A0);
    tegangan = (adcteg * (5.0 / 1023.0) * 4.8) - 3.1;

    Idcaverage = arusdc + Idcaverage;
    Vdcaverage = tegangan + Vdcaverage;
    
    if(cacah > 5){
    cacah = 0;  
    Idcaverage = (Idcaverage / 5.0) - 0.13 ;
    Vdcaverage = Vdcaverage / 5.0;
    resistansi = Vdcaverage / Idcaverage;
    resivitas = k * resistansi;
    
    lcd.setCursor(0,0);
    lcd.print("V= ");
    lcd.print(Vdcaverage);
    lcd.print("  ");
    lcd.setCursor(0,1);
    lcd.print("I= ");
    lcd.print(Idcaverage);
    lcd.print("  ");
    lcd.setCursor(0,2);
    lcd.print("Resiv= ");
    lcd.print(resivitas);
    lcd.print("  ");
    lcd.setCursor(0,3);
    lcd.print("Resis= ");
    lcd.print(resistansi);
    lcd.print("  ");
    
    kirim();
    
    Idcaverage = 0;
    Vdcaverage = 0;
    }

 
delay(200);   
}


void kirim(){
  
 if (client.connect(server,80))   //   "184.106.153.149" or api.thingspeak.com
 
                      {
                           
                             String postStr = apiKey;
                             postStr +="&field1=";
                             postStr += String(Vdcaverage);
                             postStr += "\r\n\r\n";

                             client.print(String("GET ") + resource + apiKey + "&field1=" + Vdcaverage + "&field2=" + Idcaverage + "&field3=" + resistansi + "&field4=" + resivitas + " HTTP/1.1\r\n" + "Host: " + server + "\r\n" + "Connection: close\r\n\r\n");
                                       
                             client.print("Host: api.thingspeak.com\n");
                             client.print("Connection: close\n");
                             client.print("X-THINGSPEAKAPIKEY: "+apiKey+"\n");
                             client.print("Content-Type: application/x-www-form-urlencoded\n");
                             client.print("Content-Length: ");
                             client.print(postStr.length());
                             client.print("\n\n");
                             client.print(postStr);
                         
                             Serial.println(". Send to Thingspeak.");
                        }
                       
          client.stop();

          Serial.println("Waiting...");
 
  // thingspeak needs minimum 15 sec delay between updates, i've set it to 30 seconds
  delay(10000);
    
}



c. VIDEO HASILNYA




Komunikasi Antar ESP32 / ESP8266 Menggunakan WIFI dan IP LOCAL

Komunikasi Antar ESP32 / ESP8266 Menggunakan WIFI dan IP LOCAL


       Pada kesempatan kali ini saya akan menjelaskan mengenai bagaimana cara membuat sebuah alat yang menggunakan komunikasi wifi, jadi terdapat 2 board ESP32 yang mengirimkan data suhu kepada board ESP32 Receiver, kemudian dari board ESP32 receiver data di tampilkan ke web browser dengan menggunakan IP Local. untuk lebih jelasnya berikut adalah koding dan skemanya.



1. ESP32 Transmitter




2. ESP32 Receiver




3. Setelah dipasang sensor DS18b20 ke ESP32 kemudian lakukan pembacaan MAC ADDRESS ESP32 Receiver dahulu dengan menggunakan koding berikut, maka akan tampil di serial monitor seperti gambar dibawah, jangan lupa tekan dulu tombol EN di board ESP32

#ifdef ESP32
  #include <WiFi.h>
#else
  #include <ESP8266WiFi.h>
#endif

void setup(){
  Serial.begin(115200);
  Serial.println();
  Serial.print("ESP Board MAC Address:  ");
  Serial.println(WiFi.macAddress());
}
 
void loop(){

}






4. Setelah dapat MAC Address Receiver ESP32 kemudian upload koding transmitter berikut ke Board ESP32 sebagai Transmitter dan ubah MAC Address sesuai dengan MAC Address Receiver

#include <esp_now.h>
#include <esp_wifi.h>
#include <WiFi.h>
#include <Wire.h>
#include <DallasTemperature.h>
#include <OneWire.h>
#include <SPI.h>
#define ONE_WIRE_BUS 17  //D3 pin of nodemcu

// Set your Board ID (ESP32 Sender #1 = BOARD_ID 1, ESP32 Sender #2 = BOARD_ID 2, etc)
#define BOARD_ID 1

// Digital pin connected to the DHT sensor
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
float t;
 
//MAC Address of the receiver 
uint8_t broadcastAddress[] = {0x94, 0x3C, 0xC6, 0x33, 0x81, 0xD0}; 

//Structure example to send data
//Must match the receiver structure
typedef struct struct_message {
    int id;
    float temp;
    int readingId;
} struct_message;

//Create a struct_message called myData
struct_message myData;

unsigned long previousMillis = 0;   // Stores last time temperature was published
const long interval = 10000;        // Interval at which to publish sensor readings

unsigned int readingId = 0;

// Insert your SSID
constexpr char WIFI_SSID[] = "Mipad";

int32_t getWiFiChannel(const char *ssid) {
  if (int32_t n = WiFi.scanNetworks()) {
      for (uint8_t i=0; i<n; i++) {
          if (!strcmp(ssid, WiFi.SSID(i).c_str())) {
              return WiFi.channel(i);
          }
      }
  }
  return 0;
}

float readDSTemperature() {
  sensors.requestTemperatures();
  t = sensors.getTempCByIndex(0);

    if (isnan(t)) {    
    Serial.println("Failed to read from DS sensor!");
    return 0;
  }
  else {
    Serial.println(t);
    return t;
  }
  
}


// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
 
void setup() {
  //Init Serial Monitor
  Serial.begin(115200);

  sensors.begin();
 
  // Set device as a Wi-Fi Station and set channel
  WiFi.mode(WIFI_STA);

  int32_t channel = getWiFiChannel(WIFI_SSID);

  WiFi.printDiag(Serial); // Uncomment to verify channel number before
  esp_wifi_set_promiscuous(true);
  esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
  esp_wifi_set_promiscuous(false);
  WiFi.printDiag(Serial); // Uncomment to verify channel change after

  //Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);
  
  //Register peer
  esp_now_peer_info_t peerInfo;
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.encrypt = false;
  
  //Add peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
}
 
void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    // Save the last time a new reading was published
    previousMillis = currentMillis;
    //Set values to send
    myData.id = BOARD_ID;
    myData.temp = readDSTemperature();
    myData.readingId = readingId++;
     
    //Send message via ESP-NOW
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    if (result == ESP_OK) {
      Serial.println("Sent with success");
    }
    else {
      Serial.println("Error sending the data");
    }
  }
}



5. Kemudian Upload koding ESP32 Receiver berikut.

#include <esp_now.h>
#include <WiFi.h>
#include "ESPAsyncWebServer.h"
#include <Arduino_JSON.h>

// Replace with your network credentials (STATION)
const char* ssid = "Mipad";
const char* password = "123456789";

// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {
  int id;
  float temp;
  float hum;
  unsigned int readingId;
} struct_message;

struct_message incomingReadings;

JSONVar board;

AsyncWebServer server(80);
AsyncEventSource events("/events");

// callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac_addr, const uint8_t *incomingData, int len) { 
  // Copies the sender mac address to a string
  char macStr[18];
  Serial.print("Packet received from: ");
  snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
  Serial.println(macStr);
  memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
  
  board["id"] = incomingReadings.id;
  board["temperature"] = incomingReadings.temp;
  board["humidity"] = incomingReadings.hum;
  board["readingId"] = String(incomingReadings.readingId);
  String jsonString = JSON.stringify(board);
  events.send(jsonString.c_str(), "new_readings", millis());
  
  Serial.printf("Board ID %u: %u bytes\n", incomingReadings.id, len);
  Serial.printf("t value: %4.2f \n", incomingReadings.temp);
  Serial.printf("h value: %4.2f \n", incomingReadings.hum);
  Serial.printf("readingID value: %d \n", incomingReadings.readingId);
  Serial.println();
}

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>ESP-NOW DASHBOARD</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
  <link rel="icon" href="data:,">
  <style>
    html {font-family: Arial; display: inline-block; text-align: center;}
    p {  font-size: 1.2rem;}
    body {  margin: 0;}
    .topnav { overflow: hidden; background-color: #2f4468; color: white; font-size: 1.7rem; }
    .content { padding: 20px; }
    .card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }
    .cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
    .reading { font-size: 2.8rem; }
    .packet { color: #bebebe; }
    .card.temperature { color: #fd7e14; }
    .card.humidity { color: #1b78e2; }
  </style>
</head>
<body>
  <div class="topnav">
    <h3>MONITOR SUHU</h3>
  </div>
  <div class="content">
    <div class="cards">
      <div class="card temperature">
        <h4><i class="fas fa-thermometer-half"></i> BOARD #1 - TEMPERATURE</h4><p><span class="reading"><span id="t1"></span> &deg;C</span></p><p class="packet">Reading ID: <span id="rt1"></span></p>
      </div>
      <div class="card temperature">
        <h4><i class="fas fa-thermometer-half"></i> BOARD #2 - TEMPERATURE</h4><p><span class="reading"><span id="t2"></span> &deg;C</span></p><p class="packet">Reading ID: <span id="rt2"></span></p>
      </div>
    </div>
  </div>
<script>
if (!!window.EventSource) {
 var source = new EventSource('/events');
 
 source.addEventListener('open', function(e) {
  console.log("Events Connected");
 }, false);
 source.addEventListener('error', function(e) {
  if (e.target.readyState != EventSource.OPEN) {
    console.log("Events Disconnected");
  }
 }, false);
 
 source.addEventListener('message', function(e) {
  console.log("message", e.data);
 }, false);
 
 source.addEventListener('new_readings', function(e) {
  console.log("new_readings", e.data);
  var obj = JSON.parse(e.data);
  document.getElementById("t"+obj.id).innerHTML = obj.temperature.toFixed(2);
  document.getElementById("h"+obj.id).innerHTML = obj.humidity.toFixed(2);
  document.getElementById("rt"+obj.id).innerHTML = obj.readingId;
  document.getElementById("rh"+obj.id).innerHTML = obj.readingId;
 }, false);
}
</script>
</body>
</html>)rawliteral";

void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);

  // Set the device as a Station and Soft Access Point simultaneously
  WiFi.mode(WIFI_AP_STA);
  
  // Set device as a Wi-Fi Station
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Setting as a Wi-Fi Station..");
  }
  Serial.print("Station IP Address: ");
  Serial.println(WiFi.localIP());
  Serial.print("Wi-Fi Channel: ");
  Serial.println(WiFi.channel());

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_register_recv_cb(OnDataRecv);

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html);
  });
   
  events.onConnect([](AsyncEventSourceClient *client){
    if(client->lastId()){
      Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
    }
    // send event with message "hello!", id current millis
    // and set reconnect delay to 1 second
    client->send("hello!", NULL, millis(), 10000);
  });
  server.addHandler(&events);
  server.begin();
}
 
void loop() {
  static unsigned long lastEventTime = millis();
  static const unsigned long EVENT_INTERVAL_MS = 5000;
  if ((millis() - lastEventTime) > EVENT_INTERVAL_MS) {
    events.send("ping",NULL,millis());
    lastEventTime = millis();
  }
}



6. Setelah itu buka serial monitor lalu tekan EN pada board ESP32 Receiver maka akan tampil IP Address, kemudian ketikkan IP tersebut pada web browser maka tampilannya akan seperti beriku ini.






7. VIDEO HASILNYA




Link sumber referensi:
https://randomnerdtutorials.com/esp32-esp-now-wi-fi-web-server/