Smooth servo doesn't work perfectly on wemos d1 mini

smooth servo doesn't work perfectly on wemos d1 mini, where is the error?

#include <Arduino.h>
#ifdef ESP32
#include <WiFi.h>
#include <AsyncTCP.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#endif
#include <ESPAsyncWebServer.h>
#include <FS.h>
#include <Servo.h>

/* Put your SSID & Password */
const char* ssid = "Car-ESP";  // Enter SSID here
const char* password = "12345678";  // Enter Password here

/* Put IP Address details */
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

int in1 = D6;
int in2 = D5;
// int motor_speed = 0;

const int servoPin = D1;

Servo servo;
int currentAngle = 90; // Initialize to 90 degrees

void setup(){
  // Serial port for debugging purposes
  // Serial.begin(115200);
  // Serial.println();

  servo.attach(servoPin);
  servo.write(currentAngle);

  if(SPIFFS.begin() == true) {
    // Serial.println("SPIFFS initialised OK");
  }

  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);

  WiFi.softAP(ssid, password);
  WiFi.softAPConfig(local_ip, gateway, subnet);
  delay(100);

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/index.html", "text/html");
  });
  server.on("/assets/css/foundation.css", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/assets/css/foundation.css", "text/css");
  });
  server.on("/assets/js/jquery.min.js", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/assets/js/jquery.min.js", "text/js");
  });
  server.on("/assets/img/up.png", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/assets/img/up.png", "image/png");
  });
  server.on("/assets/img/down.png", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/assets/img/down.png", "image/png");
  });

  server.on("/forward", HTTP_GET, [] (AsyncWebServerRequest *request) {
    digitalWrite(in1, HIGH);
    digitalWrite(in2, LOW);
    request->send(200, "text/plain", "ok");
  });
  server.on("/reverse", HTTP_GET, [] (AsyncWebServerRequest *request) {
    digitalWrite(in1, LOW);
    digitalWrite(in2, HIGH);
    request->send(200, "text/plain", "ok");
  });
  server.on("/off", HTTP_GET, [] (AsyncWebServerRequest *request) {
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
    request->send(200, "text/plain", "ok");
  });

  server.on("/angle", HTTP_POST, [](AsyncWebServerRequest *request) {
    String angle = request->arg("angle");
    int targetAngle = constrain(angle.toInt(), 0, 180);
    moveServoSmooth(currentAngle, targetAngle);
    currentAngle = targetAngle;
    request->send(200);
  });

  // Start server
  server.begin();
}

void loop() {}

// Function to move servo smoothly
void moveServoSmooth(int startAngle, int endAngle) {
  if (startAngle < endAngle) {
    for (int angle = startAngle; angle <= endAngle; angle++) {
      servo.write(angle);
      delay(20); // Adjust delay for smoothness
    }
  } else {
    for (int angle = startAngle; angle >= endAngle; angle--) {
      servo.write(angle);
      delay(20); // Adjust delay for smoothness
    }
  }
}

My guess would be that all the other stuff you've set up to be happening automatically is stealing attention that is needed by the smooth servo code if it wants to remain smooth.

Try a simple sketch that does nothing but attempt to smooth move the servo. Again guessing, but I bet it works fine when there's no distractions.

a7

1 Like

It may not be possible to completely avoid servo jitter with ESP8266. I suspect it is implemented in software using interrupts, but the WiFi functions may disable them or take higher priority at times, resulting in jitter.

If you can't get it as smooth as you want, you could consider using a pca9685 to drive the servo. Using a 16 channel servo driver may seem like overkill for 1 servo, but you could make use of the other outputs for additional digital outputs or for driving RGB LEDs, if that is useful.

It's possible that the wifi function disables it. It often happens when the servo movement cannot be smooth and suddenly esp8266 restarts

So we should have asked the first question when servos give trouble…

How are you providing power to the servo?

Nothing should make the esp8266 suddenly restart.

a7

1 Like

I just provide power using 1 18650 battery to the servo directly and it goes to the 3v pin on the wemos d1 mini

Soon enough that's less than 4 volts.

What do the specifications on the servo say about operating voltage and current?

Are you sure the 3.3 volt digital signal is sufficient?

a7

I can't test your code because I'm missing your additional files.

I guess it's the combination of the async webserver and your blocking code with delays to slow down the servo.

Make your function not blocking based on millis().
If that's not enough, replace the async webserver with the HTTPServer.

just a proposal:
https://werner.rothschopf.net/microcontroller/202207_millis_slow_servo.htm

try adding a slider control

Not enough for many rc servos.
Better check the specs.............. :upside_down_face:

I just modified your code a little so that it can be controlled using the web, it works perfectly. Thank you friend

// Import required libraries
#include <Arduino.h>
#ifdef ESP32
#include <WiFi.h>
#include <AsyncTCP.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#endif
#include <ESPAsyncWebServer.h>
#include <FS.h>
#include <Servo.h>
 
/* Put your SSID & Password */
const char* ssid = "Car-ESP";  // Enter SSID here
const char* password = "12345678";  // Enter Password here
 
/* Put IP Address details */
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);
 
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
 
int in1 = D6;
int in2 = D5;
 
const int servoPin = D1;

class SlowServo {
  protected:
    uint16_t target = 90;         // target angle
    uint16_t current = 90;        // current angle
    uint8_t interval = 15;        // delay time
    uint32_t previousMillis = 0;  // time management
  public:
    Servo servo;

    void begin(byte pin) {
      servo.attach(pin);
    }

    void setSpeed(uint8_t newSpeed) {
      interval = newSpeed;
    }

    void set(uint16_t newTarget) {
      target = newTarget;
    }

    void update() {
      if (millis() - previousMillis > interval) {
        previousMillis = millis();
        if (target < current) {
          current--;
          servo.write(current);
        }
        else if (target > current) {
          current++;
          servo.write(current);
        }
      }
    }
};
 
SlowServo myservo;
 
void setup(){
  // Serial port for debugging purposes
  // Serial.begin(115200);
  // Serial.println();
 
  myservo.begin(servoPin);
 
  if(SPIFFS.begin()==true) {
    // Serial.println("SPIFFS initialised OK");
  }
 
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
 
  WiFi.softAP(ssid, password);
  WiFi.softAPConfig(local_ip, gateway, subnet);
  delay(100);
 
  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/index.html", "text/html");
  });
  server.on("/assets/css/foundation.css", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/assets/css/foundation.css", "text/css");
  });
  server.on("/assets/js/jquery.min.js", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/assets/js/jquery.min.js", "text/js");
  });
  server.on("/assets/img/up.png", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/assets/img/up.png", "image/png");
  });
  server.on("/assets/img/down.png", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/assets/img/down.png", "image/png");
  });
 
  server.on("/forward", HTTP_GET, [] (AsyncWebServerRequest *request) {
    digitalWrite(in1, HIGH);
    digitalWrite(in2, LOW);
    request->send(200, "text/plain", "ok");
  });
  server.on("/reverse", HTTP_GET, [] (AsyncWebServerRequest *request) {
    digitalWrite(in1, LOW);
    digitalWrite(in2, HIGH);
    request->send(200, "text/plain", "ok");
  });
  server.on("/off", HTTP_GET, [] (AsyncWebServerRequest *request) {
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
    request->send(200, "text/plain", "ok");
  });
 
  server.on("/angle", HTTP_POST, [](AsyncWebServerRequest *request) {
    String angle = request->arg("angle");
    // Serial.println("Current Position: " + angle + "°");
    myservo.set(angle.toInt());
    request->send(200);
  });
  
  // Start server
  server.begin();
}
 
void loop(){
  myservo.update();
}
<!doctype html>
<html class="no-js" lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RC CAR</title>
    <link rel="stylesheet" href="assets/css/foundation.css">
    <script src="assets/js/jquery.min.js"></script>
  </head>
  <body>
    <div class="grid-container text-center">
      <div class="grid-x grid-padding-y">
        <div class="large-12 medium-12 small-12 cell">
          <h3>RC CAR</h3>
          <div class="large-12 medium-12 small-12 cell">
            <div class="grid-x grid-padding-y">
              <div class="large-12 medium-12 small-12 cell">
                <button type="button" class="button" onmousedown="toggleCheckbox('forward');" ontouchstart="toggleCheckbox('forward');" onmouseup="toggleCheckbox('off');" ontouchend="toggleCheckbox('off');"><img src="assets/img/up.png"></button>
              </div>
              <div class="large-12 medium-12 small-12 cell">
                <button type="button" class="button" onmousedown="toggleCheckbox('reverse');" ontouchstart="toggleCheckbox('reverse');" onmouseup="toggleCheckbox('off');" ontouchend="toggleCheckbox('off');"><img src="assets/img/down.png"></button>
              </div>
            </div>
          </div>
          <div class="large-12 medium-12 small-12 cell">
            <div class="grid-x grid-padding-y">
              <div class="large-12 medium-12 small-12 cell">
                <input type="range" name="angle" id="range" min="0" max="180" value="90">
                <p id="currentAngle" class="display-4">Current Value : 90°</p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <script>
      function toggleCheckbox(x) {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "/" + x, true);
        xhr.send();
      }
      $(document).ready(() => {
        $("#range").on("input", () => {
          $("#currentAngle").text("Current Value : " + $("#range").val() + "°");
          $.post("/angle", {
            angle: $("#range").val(),
          });
        });
      });
    </script>
  </body>
</html>

fine, if it was that easy.

Finally you can mark good answers with a like/heart.
One answer can be marked as solution.

forum_solution2

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.