Мягкий сброс wdt — ESP8266/NodeMCU с использованием шагового двигателя

Я запускаю очень простой код, и время ожидания моего ESP8266 истекло во время работы шагового двигателя. Я получаю программный сброс wdt примерно через 1600 мс при вызове функции myStepper.step. Программа работает для MyStepper.setSpeed, равного 38, но не для 37. Это происходит на двух из двух плат, которые я пробовал. Есть ли способ обойти эту проблему? Я использую программное обеспечение для программирования Arduino, код ниже.

#include <Stepper.h>

const int stepsPerRevolution = 200;  
unsigned long startT;

// initialize the stepper library:
Stepper myStepper(stepsPerRevolution, 14, 12, 13, 15); //D5, D6, D7 & D8

void setup() {
  // set the speed at in rpm:
  myStepper.setSpeed(37); //38 good (~1571 ms), 37 bad (~1614 ms)
  
  // initialize the serial port:
  Serial.begin(9600);
  Serial.println("Started stepper_oneRevolution_mk-------------------------");
}

void loop() {
  startT=millis();
  // step one revolution  in one direction:
  Serial.print("clockwise took: ");
  myStepper.step(stepsPerRevolution);
  Serial.println(millis()-startT);
  delay(1000);
  
}

person Matt    schedule 05.11.2020    source источник


Ответы (2)


Сторожевой таймер жалуется, что вы слишком долго загружаете процессор.

myStepper.step() блокируется, поэтому другие процессы не могут использовать процессор, пока двигатель не закончит движение.

В это время такие процессы, как связь по Wi-Fi и управление стеком TCP/IP, также не могут работать, и в таких случаях существует сторожевой таймер для сброса ESP8266.

Этого можно избежать, заставив шаговый двигатель двигаться всего на несколько шагов за цикл и при необходимости добавить yield(); или увеличить скорость, чтобы он сделал полный оборот до того, как сторожевой таймер разозлится.

Вы можете попробовать быстрый и грязный способ, выполнив 20 шагов, затем короткий delay() или yield(), и сделать это 10 раз в своем собственном цикле for. Вам придется поэкспериментировать, чтобы получить что-то, что не запускает сторожевой таймер, и компенсировать измерения времени, которые вы делаете.

Или используйте Arduino или ESP с дополнительным ядром, выделенным для WiFi, или найдите неблокирующую библиотеку шаговых двигателей.

person ocrdu    schedule 05.11.2020
comment
Фу! Это не то, что я надеялся услышать. Это обходной путь, который сделает код более неуклюжим. - person Matt; 05.11.2020
comment
Такова жизнь с ESP8266. Я обновил ответ, кстати. - person ocrdu; 05.11.2020
comment
Спасибо, я надеялся найти неблокирующий вызов шагового двигателя. Запуск нескольких циклов может повлиять на звук и плавность движения. - person Matt; 05.11.2020
comment
Возможно, есть другая библиотека степперов, которая делает что-то по-другому. Я помню, что видел AccelStepper и Unistep2, но не могу вспомнить, блокируются они или нет. - person ocrdu; 05.11.2020
comment
Не забудьте принять ответ (если вы принимаете ответ), чтобы вопрос не оставался открытым. - person ocrdu; 01.12.2020

Вот как я решил эту проблему.

  • Я мог включить двигатель один раз за период времени, разрешенный сторожевым таймером.
  • So instead of telling the motor to step 30 times
    • myStepper.step(stepsPerRevolution * 30);
  • I tell it to step 1 revolution, 30 times. :)
    • The key here is calling yield() between each revolution

упрощенный

int steps = 30;
while(stepsTaken < steps){
    yield(); // Let other things run
    myStepper.step(-stepsPerRevolution * 1);
    stepsTaken++;
}

Уступка для ESP8266 (sparkfun)

Более полный пример. В нем отсутствуют все биты Wi-Fi и mqtt, но вы должны понять суть.

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
// D1 and D2 is set by the Board selection
// It will error as not defined if you have the wrong board 
// specified in the Arduino ID
#include <Stepper.h>

// I need to be able to complete this before watchdog runs
const int stepsPerRevolution = 800; 

// First Pin is Step
// Sec Pin is Dir
Stepper myStepper(stepsPerRevolution,D1,D2);


// you need to define your mqtt client, wifi ect.


// This is the callback you define for your mqtt client
// client.setCallback(callback);
void callback(char* topic, byte* message, unsigned int length) {
StaticJsonDocument<256> messageTemp;
deserializeJson(messageTemp, message, length);

if (String(topic) == "esp32/output") {
    const char* dir = messageTemp["dir"];
    int steps = messageTemp["steps"];
    int stepsTaken = 0;
    while(stepsTaken < steps){
      yield();
      if(String(dir) == "up"){
        Serial.println("up");
        myStepper.step(stepsPerRevolution * 1);
      }
      else if(String(dir) == "down"){
        Serial.println("down");
        myStepper.step(-stepsPerRevolution * 1);
      }
      stepsTaken++;
    }
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(D1,OUTPUT); 
  pinMode(D2,OUTPUT);
  // set the speed at 60 rpm:
  myStepper.setSpeed(60);

  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

}

person styks    schedule 10.01.2021