sketch48_autofahren_hupen_greifer_ueber_ESPsoftAP   (ESP8266 NodeMCU)

sketch48_autofahren_hupen_greifer_ueber_ESPsoftAP
  /*---------------------------------------------------------------------------------------
  Der ESP arbeitet als Access Point mit Webserver.
  Computer oder Smartphone sind ueber WLAN als Client verbunden.
  Es erfolgt keine Kommunikation ueber das Internet, nur intern im Heimnetz (local network).
  
  In einem Browser kann das Auto mit Buttons in alle Richtungen gesteuert werden.
  Zusaetzliche Buttons sind fuer Hupen (gleichzeitig Stopp)und Greifer.
  Der Fahrzustand wird sowohl im "title" als auch auf der Webseite angezeigt.
  Ausserdem wird die Anzahl der Schalthandlungen gezaehlt (Anzeige "Zaehler").
  
  In einem Browser (Computer oder Smartphone) muss die IP-Adresse des ESP aufgerufen werden:
  http://192.168.4.1   wenn nicht mit WiFiConfig geaendert wurde.
  
  Achtung: Der Abschnitt "form the html page" darf nicht zu umfangreich werden, sonst 
  treten sporadisch Fehler in der Darstellung der Webseite auf.
  Der Webserver ist stabil, Fehler oder ein Absturz der Webseite kann durch Aktualisieren
  (refresh) wieder repariert werden. 
  
  Dieser Sketch wurde angepasst: LED schalten by Stefan Thesen 08/2015 - free for anyone.
  https://blog.thesen.eu/http-1-1-webserver-fuer-esp8266-als-accesspoint/
  Does HTTP 1.1 with defined connection closing.
  Handles empty requests in a defined manner.
  Handles requests for non-existing pages correctly.
  -----------------------------------------------------------------------------------------*/
  #include "Greifer.h"
  #include "Hupen.h"
  #include "Fahrablaufmodule.h"
  #include <ESP8266WiFi.h>
  
  const char* ssid = "ESPsoftAP";
  const char* password = "password55";              // wenn mit Passwort, dann mind 8 Zeichen notwendig
  unsigned long ulReqcount;
  
  // Create an instance of the server on Port 80
  WiFiServer server(80);
  
  void setup() 
  {
    // setup globals
    ulReqcount=0; 
    
    // prepare GPIO 
    /*Programmiere ESP Pins D1...8 als Ausgang (beachte Bezeichnung mit "D", sonst werden die GPIO-Nummern angesprochen)*/  
    pinMode(D1, OUTPUT);                          //Motoren rechts - Bruecke
    pinMode(D2, OUTPUT);                          //Motoren rechts - Bruecke
    pinMode(D5, OUTPUT);                          //Motoren rechts - PWM
    pinMode(D3, OUTPUT);                          //Motoren links - Bruecke
    pinMode(D4, OUTPUT);                          //Motoren links - Bruecke
    pinMode(D6, OUTPUT);                          //Motoren links - PWM
    pinMode(D7, OUTPUT);                          //Hupe (Buzzer)                    
    pinMode(D8, OUTPUT);                          //Greifer  
    
    // start serial
    delay (2000);                                 //Bis Programmstart 2 Sek warten, fuer sichtbare Anzeige im Serial Monitor
    Serial.begin(115600);                         //Serial Monitor muss ebenfalls auf 115600 eingestellt sein!
    Serial.println(); 
    Serial.print("Server IP address: "); 
    Serial.println(WiFi.softAPIP());              //Der Serial Monitor zeigt die IP-Adresse des ESP an 
    delay(1);                                   
      
    // AP mode
    WiFi.mode(WIFI_AP);
    WiFi.softAP(ssid, password);
    server.begin();
    Serial.println("Server wurde gestartet"); 
  }
  
  void loop() 
  { 
    // Check if a client has connected
    WiFiClient client = server.available();
    if (!client) 
    {
      return;
    }
    
    // Wait until the client sends some data
    Serial.println("new client");
    unsigned long ultimeout = millis()+250;
    while(!client.available() && (millis()<ultimeout) )
    {
      delay(1);
    }
    if(millis()>ultimeout) 
    { 
      Serial.println("client connection time-out!");
      return; 
    }
    
    // Read the first line of the request
    String sRequest = client.readStringUntil('\r');
    //Serial.println(sRequest);
    client.flush();
    
    // stop client, if request is empty
    if(sRequest=="")
    {
      Serial.println("empty request! - stopping client");
      client.stop();
      return;
    }
    
    // get path; end of path is either space or ?
    // Syntax is e.g. GET /?pin=MOTOR1STOP HTTP/1.1
    String sPath="",sParam="", sCmd="";
    String sGetstart="GET ";
    int iStart,iEndSpace,iEndQuest;
    iStart = sRequest.indexOf(sGetstart);
    if (iStart>=0)
    {
      iStart+=+sGetstart.length();
      iEndSpace = sRequest.indexOf(" ",iStart);
      iEndQuest = sRequest.indexOf("A",iStart);       
      
      // are there parameters?
      if(iEndSpace>0)
      {
        if(iEndQuest>0)
        {
          // there are parameters
          sPath  = sRequest.substring(iStart,iEndQuest);
          sParam = sRequest.substring(iEndQuest,iEndSpace);
        }
        else
        {
          // NO parameters
          sPath  = sRequest.substring(iStart,iEndSpace);
        }
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    // output parameters to serial, you may connect e.g. an Arduino and react on it
    ///////////////////////////////////////////////////////////////////////////////
    if(sParam.length()>0)
    {
      int iEqu=sParam.indexOf("Auto");                   //geaendert gegenueber Original
      if(iEqu>=0)
      {
        sCmd = sParam.substring(iEqu,sParam.length());   //geaendert gegenueber Original
        Serial.println(sCmd);
      }
    }
     
    ///////////////////////////
    // format the html response
    ///////////////////////////
    String sResponse,sHeader;
    
    ////////////////////////////
    // 404 for non-matching path
    ////////////////////////////
    if(sPath!="/")
    {
      sResponse="<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL was not found on this server.</p></body></html>";
      
      sHeader  = "HTTP/1.1 404 Not found\r\n";
      sHeader += "Content-Length: ";
      sHeader += sResponse.length();
      sHeader += "\r\n";
      sHeader += "Content-Type: text/html\r\n";
      sHeader += "Connection: close\r\n";
      sHeader += "\r\n";
    }
    ///////////////////////
    // format the html page
    ///////////////////////
    else
    {
      ulReqcount++;
      sResponse  = "<html><head><title>Auto fahren</title></head><body>";
      sResponse += "<font color=\"black\"><body bgcolor=\"lightblue\">";
      sResponse += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">";
      sResponse += "<center><h2>ESP Auto fahren</h2>";
      sResponse += "<br>";
      /* Alle Subpages muessen mit "Auto" beginnen, auch wenn der Greifer angesprochen werden soll. 
         Das ist wichtig fuer den Befehl in Zeile 137: int iEqu=sParam.indexOf("Auto"); */
      sResponse += "<p><a href=\"Auto_stopp\"><center><button><h2>Stopp</button></a></p>";
      sResponse += "<p><a href=\"Auto_vorwaerts\"><center><button><h2>Vorw&auml;rts</button></a></p>";
      /* siehe:  https://www.adfreak.de/2018/11/25/html-umlaute-und-sonderzeichen */
      sResponse += "<p><a href=\"Auto_links\"><center><button><h2>Links</button></a>&ensp;<a href=\"Auto_rechts\"><button><h2>Rechts</button></a></p>";
      sResponse += "<p><a href=\"Auto_drehenli\"><center><button><h2>Drehen li</button></a>&ensp;<a href=\"Auto_drehenre\"><button><h2>Drehen re</button></a></p>";
      sResponse += "<p><a href=\"Auto_zurueck\"><center><button><h2>Zur&uuml;ck</button></a></p>";
      sResponse += "<p><a href=\"Auto_hupen\"><center><button><h2>Hupen</button></a></p>";
      sResponse += "<p><a href=\"Auto_auf\"><center><button><h2>Auf</button></a>&ensp;<a href=\"Auto_zu\"><button><h2>Zu</button></a></p>";
           
      //////////////////////
      // react on parameters
      //////////////////////
      if (sCmd.length()>0)
      {
        // write received command to html page("Auto_stopp" bzw... wird auf Webseite geschrieben)
        sResponse += sCmd + "<BR>";
        
        // switch GPIO
        if(sCmd.indexOf("Auto_stopp")>=0)
        {
        stopp();
        }
        else if(sCmd.indexOf("Auto_vorwaerts")>=0)
        {
        vorwaerts();
        }
        else if(sCmd.indexOf("Auto_links")>=0)
        {
        links();
        }
        else if(sCmd.indexOf("Auto_rechts")>=0)
        {
        rechts();
        }
        else if(sCmd.indexOf("Auto_zurueck")>=0)
        {
        zurueck();
        }
        else if(sCmd.indexOf("Auto_drehenli")>=0)
        {
        drehenli();
        }
        else if(sCmd.indexOf("Auto_drehenre")>=0)
        {
        drehenre();      
        }
        else if(sCmd.indexOf("Auto_hupen")>=0)
        {
        stopp();
        hupen();
        }
        else if(sCmd.indexOf("Auto_auf")>=0)
        {
        stopp();
        auf();
        }
        else if(sCmd.indexOf("Auto_zu")>=0)
        {
        stopp();
        zu();
        }
      }
      
      sResponse += "<BR>Z&auml;hler="; 
      sResponse += ulReqcount;
      sResponse += "<BR>";
      sResponse += "</body></html>";
      
      sHeader  = "HTTP/1.1 200 OK\r\n";
      sHeader += "Content-Length: ";
      sHeader += sResponse.length();
      sHeader += "\r\n";
      sHeader += "Content-Type: text/html\r\n";
      sHeader += "Connection: close\r\n";
      sHeader += "\r\n";
    }
    
    // Send the response to the client
    client.print(sHeader);
    client.print(sResponse);
    
    // and stop the client
    client.stop();
    Serial.println("Client disconnected");
  }
Fahrablaufmodule.h
  void stopp()                         //Achtung: "stop" funktioniert nicht, es ist ein reservierter Befehl
  {
    digitalWrite(D1, LOW);             // Schalte alle Motoren aus
    digitalWrite(D2, LOW);  
    digitalWrite(D3, LOW); 
    digitalWrite(D4, LOW);  
  }
  
  void vorwaerts()
  {   
    digitalWrite(D1, HIGH);            // Schalte Motoren RECHTS ein 
    digitalWrite(D2, LOW);                                                      
    analogWrite (D5, 220);             // Setze die Geschwindigkeit (zwischen 0...1024)
    digitalWrite(D3, HIGH);            // Schalte Motoren LINKS ein 
    digitalWrite(D4, LOW);                                
    analogWrite (D6, 220);             // Setze die Geschwindigkeit (zwischen 0...1024)
  }
  
   void links()
  {   
    digitalWrite(D1, HIGH);            // Schalte Motoren RECHTS ein 
    digitalWrite(D2, LOW);                                                      
    analogWrite (D5, 220);             // Setze die Geschwindigkeit (zwischen 0...1024)
    digitalWrite(D3, HIGH);            // Schalte Motoren LINKS ein 
    digitalWrite(D4, LOW);                                
    analogWrite (D6, 50);             // Setze die Geschwindigkeit (zwischen 0...1024)
  }
  
  void rechts()
  {   
    digitalWrite(D1, HIGH);             // Schalte Motoren RECHTS ein 
    digitalWrite(D2, LOW);                                                      
    analogWrite (D5, 50);             // Setze die Geschwindigkeit (zwischen 0...1024)
    digitalWrite(D3, HIGH);            // Schalte Motoren LINKS ein 
    digitalWrite(D4, LOW);                                
    analogWrite (D6, 220);             // Setze die Geschwindigkeit (zwischen 0...1024)
  }
  
  void zurueck()
  {   
    digitalWrite(D1, LOW);             // Schalte Motoren RECHTS ein 
    digitalWrite(D2, HIGH);                                                      
    analogWrite (D5, 220);             // Setze die Geschwindigkeit (zwischen 0...1024)
    digitalWrite(D3, LOW);             // Schalte Motoren LINKS ein 
    digitalWrite(D4, HIGH);                                
    analogWrite (D6, 220);             // Setze die Geschwindigkeit (zwischen 0...1024)
  }
  
  void drehenli()
  {   
    digitalWrite(D1, HIGH);            // Schalte Motoren RECHTS ein 
    digitalWrite(D2, LOW);                                                      
    analogWrite (D5, 220);             // Setze die Geschwindigkeit (zwischen 0...1024)
    digitalWrite(D3, LOW);             // Schalte Motoren LINKS ein 
    digitalWrite(D4, HIGH);                                
    analogWrite (D6, 220);             // Setze die Geschwindigkeit (zwischen 0...1024)
  }
  
  void drehenre()
  {   
    digitalWrite(D1, LOW);             // Schalte Motoren RECHTS ein 
    digitalWrite(D2, HIGH);                                                      
    analogWrite (D5, 220);             // Setze die Geschwindigkeit (zwischen 0...1024)
    digitalWrite(D3, HIGH);            // Schalte Motoren LINKS ein 
    digitalWrite(D4, LOW);                                
    analogWrite (D6, 220);             // Setze die Geschwindigkeit (zwischen 0...1024)
  }
Greifer.h
  /*Dieser Sketch oeffnet und schliesst den Greifer-Servo.   
    Die "for"-Schleife sorgt dafuer, dass der Servo so lange aktiviert bleibt, bis er seine Zielstellung erreicht hat.
    Pin D11 ist vor Beendigung auf LOW gesetzt, deshalb laesst sich der Servo per Hand verdrehen.
    Die Ansteuerung des Servos wird beendet, er wird stromlos, es wirkt nur noch die Selbsthaltung es Getriebes.
    Aufgrund des Spiels kann ein gegriffener Gegenstand wieder rausrutschen.
    Wenn die Ansteuerung aber nicht beendet wird, drueckt der Greifer weiterhin zu bei hohem Stromwert.   
    Achtung: void open bzw void close nicht moeglich, da reservierte Begriffe im Compiler (faerbt sich rot).
    
    Achtung: Servo sollte eine eigene Spannungsversorgung erhalten, z.B.mit Modul LM2596.
    Eingangsspannung vom Akku - Einstellung Ausgangsspannung ca. 6V.
    Die Spannungsversorgung durch die 5V aus dem Treiber LN298, die auch den ESP versorgt, kann zu Fehlfunktion des 
    ESP fuehren (kurzzeitige Spannungseinbrueche).*/
     
  void auf()
   {
    for (int i=0; i<=60 ; i++)         //Der Servo bekommt 60 mal 20ms= 1,2s Zeit, seine Zielstellung zu erreichen
    {
    digitalWrite(D8,HIGH);
    delayMicroseconds(2100);           //Bei dieser Einstellung oeffnet der Greifer weit genug
    digitalWrite(D8,LOW);
    delay(20);                         //Ergaenzung auf Zykluszeit 20ms
    }
    Serial.println("AUF");
   }
  
   void zu() 
   {
    for (int i=0; i<=60 ; i++)         //Der Servo bekommt 60 mal 20ms= 1,2s Zeit, seine Zielstellung zu erreichen
    {
    digitalWrite(D8,HIGH);
    delayMicroseconds(1500);           //Bei dieser Einstellung schliesst der Greifer eng genug
    digitalWrite(D8,LOW);
    delay(20);                         //Ergaenzung auf Zykluszeit 20ms
    } 
    Serial.println("ZU");
   }
Hupen.h
  /*Dieser Sketch erzeugt einen Ton mit einem Passive Buzzer (Piezo-Summer).
  Die Tonhoehe (Frequenz) und Tondauer kann programmiert werden.
  Achtung: 
  Hier laeuft das Programm laengere Zeit.
  Da sich der ESP-Chip im Hintergrund immer auch um das WLAN kuemmern muss, darf 
  der ESP-Chip durch eigene Programme nie laenger als 20 ms blockiert werden. 
  Sonst muss ein yield oder delay Befehl eingefuegt werden. 
  */ 
   void hupen()
   {
   for (int i =0; i<200; i++)
    {
    digitalWrite(D7, HIGH); 
    delay (3);
    digitalWrite(D7, LOW);
    delay (3);
    yield();
    }    
  }