Multiple Servos using Servo.h library and ESP8266 (NodeMCU)

Hello,

Can anyone offer guidance or show me how to add additional servos to this project? I can’t seem to make any forward progress. And my googling hasn’t produced any useful information.

My sketch is working perfectly to control a single servo connected to pin D4 via a webpage.

I’m using a NodeMCU ESP-12 (ESP8266) and some legos.

I adopted a 12 week old puppy that requires medication midday.

My commute is 38 miles each way so giving him his meds remotely is ideal.

Unfortunately he also suffers from separation anxiety and I would like to be able to give him a treat and a toy during the day to help him with this. (That’s the reason for servo’s 3 and 4)

Any help would be greatly appreciated!

Johnny

I started with this code: Simplest-SmartThings-ESP8266-Blinds/ESP8266-Sketch.ino at master · hobbzey/Simplest-SmartThings-ESP8266-Blinds · GitHub

My working sketch:

/*
 *  Simple HTTP get webclient test
 */
 
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <Servo.h>

#define ssid      "ChangeME"
#define password  "Password"
 
ESP8266WebServer server(83);

Servo myservo;
int pos = 0;
int state = 0;
int prevstate = 0;
int dirc = 0;
int servoPin = D4;


String webPage = "";

void setup() {
  Serial.begin(115200);
  delay(100);
 
  // We start by connecting to a WiFi network
 
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
 
  WiFi.begin(ssid, password);
 
   // Set a static IP (optional)
  IPAddress ip(192, 168, 1, 71);
  IPAddress gateway(192, 168, 1, 1);
  IPAddress subnet(255, 255, 255, 0);
  WiFi.config(ip, gateway, subnet);
  // End of set a static IP (optional)
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
 
  Serial.println("");
  Serial.println("WiFi connected"); 
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  webPage += "<h1>Dog Rx Machine</h1><p>AM Medicine  <a href=\"deliver\"><button>Deliver</button></a>&nbsp;<a href=\"reset\"><button>Reset</button></a></p>";
  webPage += "<h2> </h1><p>PM Medicine  <a href=\"deliver\"><button>Deliver</button></a>&nbsp;<a href=\"reset\"><button>Reset</button></a></p>";
  webPage += "<h3> </h1><p>Treat  <a href=\"deliver\"><button>Deliver</button></a>&nbsp;<a href=\"reset\"><button>Reset</button></a></p>";
  webPage += "<h4> </h1><p>Kong Toy  <a href=\"deliver\"><button>Deliver</button></a>&nbsp;<a href=\"reset\"><button>Reset</button></a></p>";
   server.on("/", []() {
    server.send(200, "text/html", webPage);
   });
 
   server.on("/deliver", []() {
    server.send(200, "text/html", webPage);
    Serial.println("HTTP OPEN COMMAND RECEIVED");
    dirc = 0;  // direction for servo to run
    state = 2; // sets current state
  });
 
  server.on("/reset", []() {
    server.send(200, "text/html", webPage);
    Serial.println("HTTP CLOSE COMMAND RECEIVED");
    dirc = 180; // direction for servo to run
    state = 1;  // sets current state
  });

  server.begin();
  Serial.println("Server started");
}

void servo_move() {
  Serial.println("State Change. Rotating Servo");
  if ( dirc == 180) {
    myservo.attach(servoPin);              // energize servo
    delay(50);
    for (pos = 0; pos <= 180; pos += 1) {   // goes from 0 degrees to 90 degrees in steps of 1 degree CHANGE 90 TO MATCH ANGLE OF TILT DESIRED
      myservo.write(pos);                  // tell servo to go to position in variable 'pos'
      delay(10);                           // waits 30ms between each degree to slow rotation speed
    }
    delay(50);
    myservo.detach();                      // movement finished so detach servo to conserve power
  }
  else if (dirc == 0) {
    myservo.attach(servoPin);              // energize servo
    delay(50);
    for (pos = 90; pos >= 0; pos -= 1) {   // goes from 90 degrees to 0 degrees in steps of 1 degree CHANGE 90 TO MIRROR ANGLE OF TILT DESIRED ABOVE
      myservo.write(pos);                  // tell servo to go to position in variable 'pos'
      delay(10);                           // waits 30ms between each degree to slow rotation speed
    }
    delay(50);
    myservo.detach();                      // movement finished so detach servo to conserve power
  }

  Serial.println("Returning to main loop");
  return;
}
 
 
void loop() {
    if (state != prevstate) {
    Serial.println("State change!");
    servo_move();
  }
  prevstate = state;
  server.handleClient();
}

My working sketch:

But your question is about some non-working code. THAT is the code we need to see.

Your “working” code is NOT producing proper HTML output. You have open tags for h1, h2, h3, and h4, but close tags for h1, h1, and h1.

You have button objects that don’t appear to actually do anything. You appear to want to have several buttons that submit GET requests. Typically, that would be done using <input type=“submit” … > objects, with suitable names and values. The server then could distinguish what you want to deliver or reset.

I've implemented PPM decoding recently and came across a lot of PWM samples, Not sure if this will help: ESP8266 PWM revisited (and reimplemented) – May you live in interesting times

Paul,

I should say my working code is only working for a single servo. The 4 sets of web page buttons all do the same thing at the moment and only give a place holder for what I'm trying to accomplish in the end.

Any guidance adding servos to this sketch would be greatly appreciated. I can post my failed attempts at adding servos later today but I'm not sure it will be that useful.

Thanks,

Johnny

Heinduplessis,

Thank you for the link, unfortunately that information is way over my head.

Johnny

I'm not sure it will be that useful.

It will give us an idea of the approach you are using - right or wrong.

Where’s your code for multiple servos? The code you provided is for one servo.

The first step is to define more than 1 servo pins and create more than 1 moveServo() function and create more than 1 servo HTML interface.

Here is my attempt at adding additional servos.

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <Servo.h>

#define ssid      "ChangeME"
#define password  "Password"
 
ESP8266WebServer server(83);

Servo myservoa;
int pos = 0;
int state = 0;
int prevstate = 0;
int dirc = 0;
int servoPin = D4;

Servo myservob;
int pos = 0;
int state = 0;
int prevstate = 0;
int dirc = 0;
int servoPin = D5;

Servo myservoc;
int pos = 0;
int state = 0;
int prevstate = 0;
int dirc = 0;
int servoPin = D6;

Servo myservod;
int pos = 0;
int state = 0;
int prevstate = 0;
int dirc = 0;
int servoPin = D7;


String webPage = "";

void setup() {
  Serial.begin(115200);
  delay(100);
 
  // We start by connecting to a WiFi network
 
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
 
  WiFi.begin(ssid, password);
 
   // Set a static IP (optional)
  IPAddress ip(192, 168, 1, 71);
  IPAddress gateway(192, 168, 1, 1);
  IPAddress subnet(255, 255, 255, 0);
  WiFi.config(ip, gateway, subnet);
  // End of set a static IP (optional)
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
 
  Serial.println("");
  Serial.println("WiFi connected"); 
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  webPage += "<h1>Dog Rx Machine</h1><p>AM Medicine  <a href=\"deliver\"><button>Deliver</button></a>&nbsp;<a href=\"reset\"><button>Reset</button></a></p>";
  webPage += "<h2> </h1><p>PM Medicine  <a href=\"deliver\"><button>Deliver</button></a>&nbsp;<a href=\"reset\"><button>Reset</button></a></p>";
  webPage += "<h3> </h1><p>Treat  <a href=\"deliver\"><button>Deliver</button></a>&nbsp;<a href=\"reset\"><button>Reset</button></a></p>";
  webPage += "<h4> </h1><p>Kong Toy  <a href=\"deliver\"><button>Deliver</button></a>&nbsp;<a href=\"reset\"><button>Reset</button></a></p>";
   server.on("/", []() {
    server.send(200, "text/html", webPage);
   });
 
   server.on("/deliver", []() {
    server.send(200, "text/html", webPage);
    Serial.println("HTTP OPEN COMMAND RECEIVED");
    dirc = 0;  // direction for servo to run
    state = 2; // sets current state
  });
 
  server.on("/reset", []() {
    server.send(200, "text/html", webPage);
    Serial.println("HTTP CLOSE COMMAND RECEIVED");
    dirc = 180; // direction for servo to run
    state = 1;  // sets current state
  });

  server.begin();
  Serial.println("Server started");
}

void servo_move() {
  Serial.println("State Change. Rotating Servo");
  if ( dirc == 180) {
    myservoa.attach(servoPin);              // energize servo
    delay(50);
    for (pos = 0; pos <= 180; pos += 1) {   // goes from 0 degrees to 90 degrees in steps of 1 degree CHANGE 90 TO MATCH ANGLE OF TILT DESIRED
      myservoa.write(pos);                  // tell servo to go to position in variable 'pos'
      delay(10);                           // waits 30ms between each degree to slow rotation speed
    }
    delay(50);
    myservoa.detach();                      // movement finished so detach servo to conserve power
  }
  else if (dirc == 0) {
    myservoa.attach(servoPin);              // energize servo
    delay(50);
    for (pos = 90; pos >= 0; pos -= 1) {   // goes from 90 degrees to 0 degrees in steps of 1 degree CHANGE 90 TO MIRROR ANGLE OF TILT DESIRED ABOVE
      myservoa.write(pos);                  // tell servo to go to position in variable 'pos'
      delay(10);                           // waits 30ms between each degree to slow rotation speed
    }
    delay(50);
    myservoa.detach();                      // movement finished so detach servo to conserve power
  }

  Serial.println("Returning to main loop");
  return;
}
 
 
void loop() {
    if (state != prevstate) {
    Serial.println("State change!");
    servo_move();
  }
  prevstate = state;
  server.handleClient();
}

You're still controlling 1 servo. How are you controlling multiple servos?

Mistergreen,

I’m not controlling multiple servos. That’s one of the things I need assistance with.

Is this how I would add control for the 1st, 2nd, 3rd and 4th servos? myservoa.attach(servoPin); , myservob.attach(servoPin); , myservoc.attach(servoPin); , myservod.attach(servoPin);

I’m not sure how to join the webpage to the specific servo.

void servo_move() {
  Serial.println("State Change. Rotating Servo");
  if ( dirc == 180) {
    myservoa.attach(servoPin);              // energize servo
    delay(50);
    for (pos = 0; pos <= 180; pos += 1) {   // goes from 0 degrees to 90 degrees in steps of 1 degree CHANGE 90 TO MATCH ANGLE OF TILT DESIRED
      myservoa.write(pos);                  // tell servo to go to position in variable 'pos'
      delay(10);                           // waits 30ms between each degree to slow rotation speed
    }
    delay(50);
    myservoa.detach();                      // movement finished so detach servo to conserve power
  }
  else if (dirc == 0) {
    myservoa.attach(servoPin);              // energize servo
    delay(50);
    for (pos = 90; pos >= 0; pos -= 1) {   // goes from 90 degrees to 0 degrees in steps of 1 degree CHANGE 90 TO MIRROR ANGLE OF TILT DESIRED ABOVE
      myservoa.write(pos);                  // tell servo to go to position in variable 'pos'
      delay(10);                           // waits 30ms between each degree to slow rotation speed
    }
    delay(50);
    myservoa.detach();                      // movement finished so detach servo to conserve power
  }

  Serial.println("Returning to main loop");
  return;
}
 
 
void loop() {
    if (state != prevstate) {
    Serial.println("State change!");
    servo_move();
  }
  prevstate = state;
  server.handleClient();

void servo_move() {
  Serial.println("State Change. Rotating Servo");
  if ( dirc == 180) {
    myservob.attach(servoPin);              // energize servo
    delay(50);
    for (pos = 0; pos <= 180; pos += 1) {   // goes from 0 degrees to 90 degrees in steps of 1 degree CHANGE 90 TO MATCH ANGLE OF TILT DESIRED
      myservob.write(pos);                  // tell servo to go to position in variable 'pos'
      delay(10);                           // waits 30ms between each degree to slow rotation speed
    }
    delay(50);
    myservob.detach();                      // movement finished so detach servo to conserve power
  }
  else if (dirc == 0) {
    myservob.attach(servoPin);              // energize servo
    delay(50);
    for (pos = 90; pos >= 0; pos -= 1) {   // goes from 90 degrees to 0 degrees in steps of 1 degree CHANGE 90 TO MIRROR ANGLE OF TILT DESIRED ABOVE
      myservob.write(pos);                  // tell servo to go to position in variable 'pos'
      delay(10);                           // waits 30ms between each degree to slow rotation speed
    }
    delay(50);
    myservob.detach();                      // movement finished so detach servo to conserve power
  }

  Serial.println("Returning to main loop");
  return;
}
 
 
void loop() {
    if (state != prevstate) {
    Serial.println("State change!");
    servo_move();
  }
  prevstate = state;
  server.handleClient();

void servo_move() {
  Serial.println("State Change. Rotating Servo");
  if ( dirc == 180) {
    myservoc.attach(servoPin);              // energize servo
    delay(50);
    for (pos = 0; pos <= 180; pos += 1) {   // goes from 0 degrees to 90 degrees in steps of 1 degree CHANGE 90 TO MATCH ANGLE OF TILT DESIRED
      myservoc.write(pos);                  // tell servo to go to position in variable 'pos'
      delay(10);                           // waits 30ms between each degree to slow rotation speed
    }
    delay(50);
    myservoc.detach();                      // movement finished so detach servo to conserve power
  }
  else if (dirc == 0) {
    myservoa.attach(servoPin);              // energize servo
    delay(50);
    for (pos = 90; pos >= 0; pos -= 1) {   // goes from 90 degrees to 0 degrees in steps of 1 degree CHANGE 90 TO MIRROR ANGLE OF TILT DESIRED ABOVE
      myservoc.write(pos);                  // tell servo to go to position in variable 'pos'
      delay(10);                           // waits 30ms between each degree to slow rotation speed
    }
    delay(50);
    myservoc.detach();                      // movement finished so detach servo to conserve power
  }

  Serial.println("Returning to main loop");
  return;
}
 
 
void loop() {
    if (state != prevstate) {
    Serial.println("State change!");
    servo_move();
  }
  prevstate = state;
  server.handleClient();

void servo_move() {
  Serial.println("State Change. Rotating Servo");
  if ( dirc == 180) {
    myservod.attach(servoPin);              // energize servo
    delay(50);
    for (pos = 0; pos <= 180; pos += 1) {   // goes from 0 degrees to 90 degrees in steps of 1 degree CHANGE 90 TO MATCH ANGLE OF TILT DESIRED
      myservod.write(pos);                  // tell servo to go to position in variable 'pos'
      delay(10);                           // waits 30ms between each degree to slow rotation speed
    }
    delay(50);
    myservod.detach();                      // movement finished so detach servo to conserve power
  }
  else if (dirc == 0) {
    myservod.attach(servoPin);              // energize servo
    delay(50);
    for (pos = 90; pos >= 0; pos -= 1) {   // goes from 90 degrees to 0 degrees in steps of 1 degree CHANGE 90 TO MIRROR ANGLE OF TILT DESIRED ABOVE
      myservod.write(pos);                  // tell servo to go to position in variable 'pos'
      delay(10);                           // waits 30ms between each degree to slow rotation speed
    }
    delay(50);
    myservod.detach();                      // movement finished so detach servo to conserve power
  }

  Serial.println("Returning to main loop");
  return;
}
 
 
void loop() {
    if (state != prevstate) {
    Serial.println("State change!");
    servo_move();
  }
  prevstate = state;
  server.handleClient();

Any easier alternatives that would allow remote control of 4 servos?

Thanks for the help.

Johnny

Is this how I would add control for the 1st, 2nd, 3rd and 4th servos?

No. You can not attach multiple servos to the same pin.

I'm not sure how to join the webpage to the specific servo.

You have several problems here. First is having the web page have controls for multiple servos. Second is having server.on() lambdas for each of the deliverN and resetN methods that the buttons will trigger. Third is having the lamdas control the right servo.

The last one is the easiest to deal with.

Pauls,

Is this how to define each servo?

myservoa would be connected to pin D4 (This servo is working in my original sketch as myservo)
myservob would be connected to pin D5
myservoc would be connected to pin D6
myservod would be connected to pin D7

Servo myservoa;
int pos = 0;
int state = 0;
int prevstate = 0;
int dirc = 0;
int servoPin = D4;

Servo myservob;
int pos = 0;
int state = 0;
int prevstate = 0;
int dirc = 0;
int servoPin = D5;

Servo myservoc;
int pos = 0;
int state = 0;
int prevstate = 0;
int dirc = 0;
int servoPin = D6;

Servo myservod;
int pos = 0;
int state = 0;
int prevstate = 0;
int dirc = 0;
int servoPin = D7;

void servo_move() {
Serial.println(“State Change. Rotating Servo”);
if ( dirc == 180) {
myservoa.attach(servoPin); // energize servo
delay(50);
for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 90 degrees in steps of 1 degree CHANGE 90 TO MATCH ANGLE OF TILT DESIRED
myservoa.write(pos); // tell servo to go to position in variable ‘pos’
delay(10); // waits 30ms between each degree to slow rotation speed

Does myservoa.attach(servoPin); mean that it’s going to use pin D4?

I assumed the sketch works from the top down and I could address the web page portion when I got the compile errors fixed.

Thanks for the assistance.

Does myservoa.attach(servoPin); mean that it’s going to use pin D4?

Np, because the code you posted would not compile, even if it were complete. The code tries to declare the same variables over and over again with different values. This would not work.

int servoPin = D4;
int servoPin = D5;

UKHelibob,

Any idea how to define / call multiple servos in the same sketch?

I've been googling for several weeks without any luck.

Thanks

You write code for the second servo just like for the first, just give the variables different names.

Maybe instead of googling for code to copy for weeks you could spend a few minutes reading the documentation for the servo library on this site and the examples therein. Then instead of trying to guess how to adapt this code or that code you would know what the individual functions do and you could write your own code.

Delta_G,

Can you be more specific as to which variables I should be changing?

Is naming the servos "a" and "b" a viable approach?

Servo myservoa;
int pos = 0;
int state = 0;
int prevstate = 0;
int dirc = 0;
int servoPin = D4;

Servo myservob;
int pos = 0;
int state = 0;
int prevstate = 0;
int dirc = 0;
int servoPin = D5;

Thanks,

Johnny.

I turned to google after reading through the servo.h reference information and not understanding how to apply what I read to my situation.

This is my 1st attempt using Arduino hardware and software.

If it wasn't for a troubled dog I wouldn't have attempted this project.

Sure you can name the servos like that but look at all those other variables that have the same names. Compiler isn't going to like that. You should only use each name once. So how about servoPinA and servoPinB to match what you named the servos. Same with the rest.

int pos = 0;
int state = 0;
int prevstate = 0;
int dirc = 0;
int servoPin = D4;

int pos = 0;
int state = 0;
int prevstate = 0;
int dirc = 0;
int servoPin = D5;

You are reinitializing / reassigning the same variables over and over. Which one belongs to servoA, which to servoB?

try something like

int posA = 0;

int posB = 0;

As a beginner, you should start with that. As you gain more experience, there are other methods to organize members/variables.

Delta_G and mistergreen,

Thanks for the information!

I'll start making the changes this evening.

Johnny

You might consider creating a struct, to hold all the data related to one servo. Then, create an array of that type, with a size that matches the number of servos you have.