Schrittmotor mit Webinterface steuern

Hallo,
ich hoffe Ihr könnt mir helfen. Mein Ziel ist es, einen Schrittmotor mit einem Webinterface zu steuern, aber leider bekomme ich das nicht hin.
Hier ist mein Quelltext. Hat jemand einen Vorschlag

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
*********/

#include <AccelStepper.h>

const int DIR = 12;
const int STEP = 14;

#define motorInterfaceType 1
AccelStepper motor(motorInterfaceType, STEP, DIR);


// Load Wi-Fi library
#include <ESP8266WiFi.h>

// Replace with your network credentials
const char* ssid     = "";
const char* password = "";

// Set web server port number to 80
WiFiServer server(80);

// Variable to store the HTTP request
String header;

// Auxiliar variables to store the current output state
String output5State = "off";
String output4State = "off";

// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0; 
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;

void setup() 
{
  Serial.begin(9600);
  pinMode(Sensor,INPUT_PULLUP);
 motor.setMaxSpeed(1000);
  motor.setAcceleration(60);
  motor.setSpeed(1000);
  motor.moveTo(200000);  //richtung und drehungen einstellen

  Serial.begin(115200);

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {                             // If a new client connects,
    Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    currentTime = millis();
    previousTime = currentTime;
    while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
      currentTime = millis();         
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();
            
            // turns the GPIOs on and off
            if (header.indexOf("GET /5/on") >= 0) {
              Serial.println("GPIO 5 on");
              output5State = "on";
              (motor.run());
            } else if (header.indexOf("GET /5/off") >= 0) {
              Serial.println("GPIO 5 off");
              output5State = "off";
              (motor.stop());
            } else if (header.indexOf("GET /4/on") >= 0) {
              Serial.println("GPIO 4 on");
              output4State = "on";
              (motor.run());
            } else if (header.indexOf("GET /4/off") >= 0) {
              Serial.println("GPIO 4 off");
              output4State = "off";
              (motor.stop());
            }
            
            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            // CSS to style the on/off buttons 
            // Feel free to change the background-color and font-size attributes to fit your preferences
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
            client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            client.println(".button2 {background-color: #77878A;}</style></head>");
            
            // Web Page Heading
            client.println("<body><h1>ESP8266 Web Server</h1>");
            
            // Display current state, and ON/OFF buttons for GPIO 5  
            client.println("<p>GPIO 5 - State " + output5State + "</p>");
            // If the output5State is off, it displays the ON button       
            if (output5State=="off") {
              client.println("<p><a href=\"/5/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/5/off\"><button class=\"button button2\">OFF</button></a></p>");
            } 
               
            // Display current state, and ON/OFF buttons for GPIO 4  
            client.println("<p>GPIO 4 - State " + output4State + "</p>");
            // If the output4State is off, it displays the ON button       
            if (output4State=="off") {
              client.println("<p><a href=\"/4/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/4/off\"><button class=\"button button2\">OFF</button></a></p>");
            }
            client.println("</body></html>");
            
            // The HTTP response ends with another blank line
            client.println();
            // Break out of the while loop
            break;
          } else { // if you got a newline, then clear currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

Schonmal Danke in Voraus

Es ist sicher schön, das die ganze Welt jetzt weiss, was Du für eine Fritzbox hast und wie das WLAN-Passwort ist.

Hinweis: Lösche Deinen Beitrag, dann geht der Inhalt nach 24 Stunden aus dem Forum.
Wenn Du den Beitrag nur editierst, dann bleibt es für immer lesbar.

Nach dem löschen Deines Posts kannst Du einen neuen verfassen....

1 Like

... und nein

... auf einem ESP8266 schreibt man keinen HTTP header selber. Man nimmt die Beispiele vom ESP8266HTTPClient | BasicHttpclient

wenns mehr sein soll ein größeres Beispiel von mir:
https://werner.rothschopf.net/microcontroller/202108_esp_generic_webserver_en.htm

und Fipsok hat vermutlich auch was.

Dein Code zeigt den Zustand von zwei IO-pins an.
möchtest du mit dem Webinterface
a.) Richtungs-Eingang setzen
b.) durch ständiges Anklicken des Puls-Eingangs die einzelnen Pulse erzeugen?

Das kann man dann zutreffend auch mit "per Webinterface Schrittmotor ansteuern" beschreiben ist aber vermutlich nicht das was du haben willst weil du 400 mal klicken musst bis der Schrittmotor auch nur eine Umdrehung im Vollschrittmodus gemacht hat.

Du solltest mal genauer beschreiben was der Schrittmotor machen soll.

Es gibt dazu zwei Wege:
Weg 1: mit selbst HTML programmieren das ist Fips und Co.

Weg 2: ohne selbst HTML zu programmieren das geht mit
ESPUI

vgs

Hi, ich wollte es so haben, dass er sich mit jeweils einer Taste in eine andere Richtung bewegt.

Button links anklicken Schrittmotor dreht endlos gegen den Uhrzeigersinn
Button rechts anklicken Schrittmotor dreht endlos mit dem Uhrzeigersinn

Darfs es noch ein Button "Stop" geben oder machst du das über Stromversorgung ausschalten?

Kann man es einstellen, dass es eine bestimmte Anzahl an Umdrehungen macht?

Wenn man lange genug programmiert kann dir der Schrittmotor auch die aktuelle Hitparade vorsummen. (Das ist jetzt kein Scherz das geht wirklich)

Jetzt überlege mal in Ruhe zu Ende was du tatsächlich an Funktionen brauchst
oder noch besser beschreibe das ganze Projekt was du insgesamt machen willst.
vgs

Ich möchte gerne über ein Webinterface steuern, in welche Richtung sich der Schrittmotor drehen soll. Wie weit hätte ich gerne so, dass man es im Code einstellen kann.

Das ist keine Beschreibung des Endzwecks.
Willst du mit den Schrittmotoren an der James-Bond-Bar Martini rühren (und nicht schütteln) oder sollen die Schrittmotoren die Haare von der Oma auf die Lockenwickler drehen?

1 Like

Soll letztendlich sowas wie eine Rolladensteuerung ergeben.

Für Rolläden nimmt man keine Schrittmotoren sondern "klassische" Motoren mit Schneckenradantrieb weil selbsthemmend und viel größeres Drehmoment bezogen auf die Motorgröße.

Aber da du das eigentliche das wirkliche Projekt geheim halten willst kann man es nicht wirklich beurteilen.
Was für ein Gewicht hat der "Rolladen"?
Wie schnell soll der "Rolladen" über welche Strecke bewegt werden?
Wird der "Rolladen" senkrecht hochgezogen = das ganze Eigengewicht muss vom Motor bewegt werden oder ist das schräg oder waagerecht
Kannst du oben und unten Endschalter anbringen ja/nein?
Soll der "Rolladen" in jeder Zwischenposition angehalten werden können ja / nein?
Wenn ja mit welcher Genauigkeit soll die Zwischenposition eingehalten werden?

Man was ist so schwer daran das eigentliche Projekt zu beschreiben?
Ist das ein dermaßen ausgefallenes "Hobby" dass man es lieber geheim hält?

mach mal einen (kompilierbaren) Sketch mit deiner Servobewegung über zwei TASTER.
Auf / ab in zwei separaten Funktionen.

Und dann mach ein Mockup / Strichzeichnung wie die Oberfläche ca aussehen soll.

Vieleicht habe ich am Abend Zeit. Außer Stefan ist schneller, dann lass ich ihm den Vortritt.

Es ist halt ein kleines Bastelprojekt, es ist nicht für eine bestimmte Sache

Nein

Ich würde das Gewicht mal für Max. 1kg auslegen

Einen auf jeden Fall

Hier ist ein Demo-Code für ESPUI mit zwei Tabs.
Betrieb und Einstellungen.
Die Einstellungen werden im Flash gespeichert.

Die Buttons für den Betrieb stellen ein Servosignal auf verschiedene Werte
das könnten dann die Schrittmotorpositionen sein.

Wenn du da was anders haben willst dann kommst du nicht umhin mal eigene eigene Skizze zu erstellen wie das Webinterface aussehen soll.

#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);

#define dbgi(myFixedText, variableName,timeInterval) \
  do { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  } while (false);

#include <Preferences.h>     // add sourcecode file
Preferences myPrefInstance;  // create an instance of the object

#include <DNSServer.h>
#include <ESPUI.h>

const byte DNS_PORT = 53;
IPAddress apIP(192, 168, 4, 1);
DNSServer dnsServer;

#if defined(ESP32)
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif

unsigned long MyTestTimer = 0;                   // Timer-variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;
unsigned long SwitchStateTimer = 0;

int slider1Pos = 15;

const char *home_ssid     = "SSID";
const char *home_password = "password";

char ap_ssid[25];
const char* AP_password = "espui";
const char* AP_hostname = "espui";

uint16_t myTab1_ID;
uint16_t myTab2_ID;

uint16_t statusLabel_ID;

uint16_t button1_ID;
uint16_t button2_ID;
uint16_t button3_ID;

uint16_t ServoPos1_ID;
uint16_t ServoPos2_ID;
uint16_t ServoPos3_ID;
uint16_t buttonSave_ID;
uint16_t buttonSetDefault_ID;

#define myNameSpace "ServoPos"
const boolean ReadOnly  = true;
const boolean ReadWrite = !ReadOnly; // not-operator inverts the value

int servoPos1microS;
int servoPos2microS;
int servoPos3microS;


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void number1Callback(Control* sender, int eventType) {
  Serial.print(" ");
  Serial.print(sender->label);

  Serial.println(sender->value);
  servoPos1microS = atoi(sender->value.c_str());
  dbg("Pos1", servoPos1microS);
}

void number2Callback(Control* sender, int eventType) {
  Serial.print(" ");
  Serial.print(sender->label);

  Serial.println(sender->value);
  servoPos2microS = atoi(sender->value.c_str());
  dbg("Pos2", servoPos2microS);
}


void number3Callback(Control* sender, int eventType) {
  Serial.print(" ");
  Serial.print(sender->label);

  Serial.println(sender->value);
  servoPos3microS = atoi(sender->value.c_str());
  dbg("Pos3", servoPos3microS);
}


void buttonSetDefaultCallback(Control* sender, int eventType) {
  Serial.print("ID: ");
  Serial.print(sender->id);
  Serial.print(" ");
  Serial.println(sender->label);

  if (eventType == B_UP) {
    servoPos1microS = 1100;
    servoPos2microS = 1500;
    servoPos3microS = 1900;
    ESPUI.updateControlValue(ServoPos1_ID, String(servoPos1microS) );
    ESPUI.updateControlValue(ServoPos2_ID, String(servoPos2microS) );
    ESPUI.updateControlValue(ServoPos3_ID, String(servoPos3microS) );

    dbg("Default", servoPos1microS);
    dbg("Default", servoPos2microS);
    dbg("Default", servoPos3microS);
  }
}


void  buttonSaveCallback(Control* sender, int eventType) {
  Serial.print("ID: ");
  Serial.print(sender->id);
  Serial.print(" ");
  Serial.println(sender->label);
  if (eventType == B_UP) {
    SafePreferences();
  }
}


void button1Callback(Control* sender, int eventType) {

  Serial.print("ID: ");
  Serial.print(sender->id);
  Serial.print(" ");
  Serial.print(sender->label);
  dbg("Btn1", sender->id);
  dbg("Btn1", button1_ID);

  switch (eventType) {

    case B_DOWN:
      Serial.println("Button DOWN");
      break;

    case B_UP:
      Serial.println("Button UP");
      break;
  }
}


void button2Callback(Control* sender, int eventType) {
  Serial.print("ID: ");
  Serial.print(sender->id);
  Serial.print(" ");
  Serial.print(sender->label);

  switch (eventType) {

    case B_DOWN:
      Serial.println("Button DOWN");
      break;

    case B_UP:
      Serial.println("Button UP");
      break;
  }
}


void button3Callback(Control* sender, int eventType) {
  Serial.print("ID: ");
  Serial.print(sender->id);
  Serial.print(" ");
  Serial.print(sender->label);

  switch (eventType) {

    case B_DOWN:
      Serial.println("Button DOWN");
      break;

    case B_UP:
      Serial.println("Button UP");
      break;
  }
}


void ConnectToWiFi() {
  int myCount = 0;
#if defined(ESP32)
  WiFi.setHostname(AP_hostname); // xxy
#else
  WiFi.hostname(AP_hostname);
#endif

  // try to connect to existing network
  WiFi.begin(home_ssid, home_password);
  Serial.print("\n\nTry to connect to existing network");
  Serial.print(" named #");
  Serial.print(home_ssid);
  Serial.println("#");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED && myCount < 31) {
    yield(); // very important to execute yield to make it work
    BlinkHeartBeatLED(OnBoard_LED, 50); // blink LED fast during attempt to connect

    if ( TimePeriodIsOver(MyTestTimer, 500) ) { // once every 500 miliseconds
      Serial.print(".");                        // print a dot
      myCount++;

      if (myCount > 30) { // after 30 dots = 15 seconds restart
        Serial.println();
        Serial.print("not connected ");
      }
    }
  }

  if (WiFi.status() == WL_CONNECTED ) {
    Serial.println("");
    Serial.print("Connected to #");
    Serial.print(home_ssid);
    Serial.print("# IP address: ");
    Serial.println(WiFi.localIP());
  }
}

void createOwnAP() {
  // not connected -> create hotspot
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("\n\n no connection to SSID #");
    Serial.print(home_ssid);
    Serial.println("#\n Creating hotspot");

    WiFi.mode(WIFI_AP);
    delay(100);
    WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));

#if defined(ESP32)
    uint32_t chipid = 0;
    for (int i = 0; i < 17; i = i + 8) {
      chipid |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
    }
#else
    uint32_t chipid = ESP.getChipId();
#endif
    snprintf(ap_ssid, 26, "ESPUI-%08X", chipid);
    WiFi.softAP(ap_ssid);
    Serial.print("SSID #");
    Serial.print(ap_ssid);
    Serial.println("#");

    //dnsServer.start(DNS_PORT, "*", apIP);
  }
}

void printWiFiModeAndIP() {
  if (WiFi.getMode() == WIFI_AP) {
    Serial.print("ESP is its OWN accesspoint with SSID ");
    Serial.println(ap_ssid);
    Serial.print("IP address: ");
    Serial.println(WiFi.softAPIP() );
  }
  else {
    Serial.print("ESP connected to existing WLAN named ");
    Serial.println(home_ssid);
    Serial.print("IPAdress: ");
    Serial.println(WiFi.localIP() );
  }
}


void setup() {
  delay(1000);
  Serial.begin(115200);
  delay(1000);
  PrintFileNameDateTime();

#if defined(ESP32)
  WiFi.setHostname(AP_hostname);
#else
  WiFi.hostname(AP_hostname);
#endif

  ConnectToWiFi();
  if (WiFi.status() != WL_CONNECTED) {
    createOwnAP();
  }
  dnsServer.start(DNS_PORT, "*", apIP);
  printWiFiModeAndIP();

  defineUI();
  ESPUI.begin("I am the website created by the ESPUI-Demo");
  LoadPreferences();
}


void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 500);
  dnsServer.processNextRequest();

  if ( TimePeriodIsOver(MyTestTimer, 1000) ) {
  }

  if ( TimePeriodIsOver(SwitchStateTimer, 5000) ) {
  }
}


void defineUI() {
  // defining the website-tabs
  myTab1_ID = ESPUI.addControl(ControlType::Tab, "Operation", "Operation");
  myTab2_ID = ESPUI.addControl(ControlType::Tab, "Settings",  "Settings");

  // shown above all tabs
  statusLabel_ID = ESPUI.addControl(ControlType::Label, "Status:", "Last Action: none", ControlColor::Turquoise);

  // elements on myTab1_ID
  button1_ID = ESPUI.addControl(ControlType::Button, "Position 1", "Pos 1", ControlColor::Peterriver, myTab1_ID, &button1Callback);
  button2_ID = ESPUI.addControl(ControlType::Button, "Position 2", "Pos 2", ControlColor::Wetasphalt, myTab1_ID, &button2Callback);
  button3_ID = ESPUI.addControl(ControlType::Button, "Position 3", "Pos 3", ControlColor::Wetasphalt, myTab1_ID, &button3Callback);


  // elements on myTab2_ID
  ServoPos1_ID = ESPUI.addControl(ControlType::Number, "Servo position 1 (µseconds):", "1100",  ControlColor::Alizarin, myTab2_ID, &number1Callback);
  ESPUI.addControl(ControlType::Min, "Min-value", "1000", ControlColor::None, ServoPos1_ID);
  ESPUI.addControl(ControlType::Max, "Max-value", "2000", ControlColor::None, ServoPos1_ID);

  ServoPos2_ID = ESPUI.addControl(ControlType::Number, "Servo position 2 (µseconds):", "1500",  ControlColor::Alizarin, myTab2_ID, &number2Callback);
  ESPUI.addControl(ControlType::Min, "Min-value", "1000", ControlColor::None, ServoPos2_ID);
  ESPUI.addControl(ControlType::Max, "Max-value", "2000", ControlColor::None, ServoPos2_ID);

  ServoPos3_ID = ESPUI.addControl(ControlType::Number, "Servo position 3 (µseconds):", "1900",  ControlColor::Alizarin, myTab2_ID, &number3Callback);
  ESPUI.addControl(ControlType::Min, "Min-value", "1000", ControlColor::None, ServoPos3_ID);
  ESPUI.addControl(ControlType::Max, "Max-value", "2000", ControlColor::None, ServoPos3_ID);

  buttonSave_ID       = ESPUI.addControl(ControlType::Button, "Save to Flash ", "Save ",    ControlColor::Peterriver, myTab2_ID, &buttonSaveCallback);
  buttonSetDefault_ID = ESPUI.addControl(ControlType::Button, "Set Default ",   "Default ", ControlColor::Peterriver, myTab2_ID, &buttonSetDefaultCallback);
}


void LoadPreferences() {
  Serial.println("LoadPreferences");
  myPrefInstance.begin(myNameSpace, ReadOnly);

  servoPos1microS = myPrefInstance.getInt    ("ServoPos1"      , 1101);
  servoPos2microS = myPrefInstance.getInt    ("ServoPos2"      , 1501);
  servoPos3microS = myPrefInstance.getInt    ("ServoPos3"      , 1901);

  ESPUI.updateControlValue(ServoPos1_ID, String(servoPos1microS) );
  ESPUI.updateControlValue(ServoPos2_ID, String(servoPos2microS) );
  ESPUI.updateControlValue(ServoPos3_ID, String(servoPos3microS) );

  dbg("LP", servoPos1microS);
  dbg("LP", servoPos2microS);
  dbg("LP", servoPos3microS);
  myPrefInstance.end();
}

void SafePreferences() {
  Serial.println("SafePreferences");

  myPrefInstance.begin(myNameSpace, ReadWrite);
  //myPrefInstance.clear();

  myPrefInstance.putInt    ("ServoPos1"      , servoPos1microS);
  myPrefInstance.putInt    ("ServoPos2"      , servoPos2microS);
  myPrefInstance.putInt    ("ServoPos3"      , servoPos3microS);
  myPrefInstance.end();
  dbg("SP", servoPos1microS);
  dbg("SP", servoPos2microS);
  dbg("SP", servoPos3microS);
  LoadPreferences();
}

vgs

das Programm funktioniert bei mir nicht

Es gibt bei mir nur exit status 1 code, wenn ich das Programm hochladen möchte