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ä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> <a href=\"Auto_rechts\"><button><h2>Rechts</button></a></p>";
sResponse += "<p><a href=\"Auto_drehenli\"><center><button><h2>Drehen li</button></a> <a href=\"Auto_drehenre\"><button><h2>Drehen re</button></a></p>";
sResponse += "<p><a href=\"Auto_zurueck\"><center><button><h2>Zurü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> <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ä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();
}
}