Need some help with 4 servos on NodeMCU (esp8266) + Arduino IDE

Hello there! I’m trying to control 4 MG90S servos with a NodeMcu 8266 and RoboRemo App via wifi. I can make it work with 1 servo but not with all 4. I’m stuck. Please i need some help here (not much of a coder). Need at least one servo controlled with accelerometer:

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

const char *ssid = "TEAM_UNAVAILABLE";  // Telefonul se va conecta la acest Access Point
const char *pw = "nopassword"; // asta este parola retelei wifi
IPAddress ip(192, 168, 0, 1); // adresa IP de conectare
IPAddress netmask(255, 255, 255, 0);
const int port = 9876; // port de conectare
WiFiServer server(port);
WiFiClient client;

const int chCount = 4; // 4 channels, you can add more if you have GPIOs :)
Servo servoCh[chCount]; // will generate 4 servo PWM signals
int chPin[] = {4, 5, 12, 14}; // ESP pins: GPIO 4,5,12,14
int chVal[] = {1500, 1500, 1500, 1500}; // default value (middle)
int usMin = 700; // min pulse width
int usMax = 2300; // max pulse width


char cmd[100];
int cmdIndex;
unsigned long lastCmdTime = 60000;
unsigned long aliveSentTime = 0;

boolean cmdStartsWith(const char *st) { // checks if cmd starts with st
  for(int i=0; ; i++) {
    if(st[i]==0) return true;
    if(cmd[i]==0) return false;
    if(cmd[i]!=st[i]) return false;;
  }
  return false;
}

void exeCmd() { 

  lastCmdTime = millis();

  // example: set RoboRemo slider id to "ch0", set min 1000 and set max 2000
  
  if( cmdStartsWith("ch") ) {
    int ch = cmd[2] - '0';
    if(ch>=0 && ch<=9 && cmd[3]==' ') {
      chVal[ch] = (int)atof(cmd+4);
      if(!servoCh[ch].attached()) {
        servoCh[ch].attach(chPin[ch], usMin, usMax);
      }   
      servoCh[ch].writeMicroseconds(chVal[ch]);
    }
  }
  
  // invert channel:
  // example: set RoboRemo slider id to "ci0", set min -2000 and set max -1000
  
  if( cmdStartsWith("ci") ) {
    int ch = cmd[2] - '0';
    if(ch>=0 && ch<=9 && cmd[3]==' ') {
      chVal[ch] = -(int)atof(cmd+4);
      if(!servoCh[ch].attached()) {
        servoCh[ch].attach(chPin[ch], usMin, usMax);
      }   
      servoCh[ch].writeMicroseconds(chVal[ch]);
    }
  }
  
  // use accelerometer:
  // example: set RoboRemo acc y id to "ca1"
  
  if( cmdStartsWith("ca") ) {
    int ch = cmd[2] - '0';
    if(ch>=0 && ch<=9 && cmd[3]==' ') {
      chVal[ch] = (usMax+usMin)/2 + (int)( atof(cmd+4)*51 ); // 9.8*51 = 500 => 1000 .. 2000
      if(!servoCh[ch].attached()) {
        servoCh[ch].attach(chPin[ch], usMin, usMax);
      }   
      servoCh[ch].writeMicroseconds(chVal[ch]);
    }
  }
  
  // invert accelerometer:
  // example: set RoboRemo acc y id to "cb1"
  
  if( cmdStartsWith("cb") ) {
    int ch = cmd[2] - '0';
    if(ch>=0 && ch<=9 && cmd[3]==' ') {
      chVal[ch] = (usMax+usMin)/2 - (int)( atof(cmd+4)*51 ); // 9.8*51 = 500 => 1000 .. 2000
      if(!servoCh[ch].attached()) {
        servoCh[ch].attach(chPin[ch], usMin, usMax);
      }   
      servoCh[ch].writeMicroseconds(chVal[ch]);
    }
  }
  
}

      
void setup() {

  delay(1000); // intarziere pentru pornire wifi

  Serial.begin(115200);

 for(int i=0; i<chCount; i++) {
    // attach channels to pins
    servoCh[i].attach(chPin[i], usMin, usMax);
    // initial value = middle
    chVal[i] = (usMin + usMax)/2;
    // update
    servoCh[i].writeMicroseconds( chVal[i] );
  }
  
  
  cmdIndex = 0;


  WiFi.softAPConfig(ip, ip, netmask); // configurare adresa ip pentru AP-Wifi
  WiFi.softAP(ssid, pw); // configurare ssid si parola wifi

  server.begin(); // porneste serverul TCP

  Serial.println("ESP8266 receptor Wifi masinuta RC -TEAM-UNAVAILABLE ");
  Serial.println((String)"SSID: " + ssid + "  PASS: " + pw);
  Serial.println((String)"Aplicatia Android se va conecta la " + ip.toString() + ":" + port);

}



void loop() {

  
   // if contact lost for more than half second
  if(millis() - lastCmdTime > 500) {  
    for(int i=0; i<chCount; i++) {
      // set all values to middle
      servoCh[i].writeMicroseconds( (usMin + usMax)/2 );
      servoCh[i].detach(); // stop PWM signals
    }
  }

  

  if(!client.connected()) {
    client = server.available();
    return;
  }

  // here we have a connected client

  if(client.available()) {
    char c = (char)client.read(); // read char from client (RoboRemo app)

    if(c=='\n') { // if it is command ending
      cmd[cmdIndex] = 0;
      exeCmd();  // execute the command
      cmdIndex = 0; // reset the cmdIndex
    } else {      
      cmd[cmdIndex] = c; // add to the cmd buffer
      if(cmdIndex<99) cmdIndex++;
    }
  } 

  if(millis() - aliveSentTime > 500) { // every 500ms
    client.write("alive 1\n");
    // send the alibe signal, so the "connected" LED in RoboRemo will stay ON
    // (the LED must have the id set to "alive")
    
    aliveSentTime = millis();
    // if the connection is lost, the RoboRemo will not receive the alive signal anymore,
    // and the LED will turn off (because it has the "on timeout" set to 700 (ms) )
  }

}

Explain “not working”. Give an example of a command and describe how your system is currently execute that command (not how you expect it should do).

How are you powering the servos? This is the #1 problem with servos used by newer forum members like yourself.

A single, unladen, small servo might be able to be powered from the arduino 5v pin most of the time. But if you put on multiples, or load the servos up by attaching things to them, then you are out of luck and you (best case) brown out the arduino and it resets.

Servos require a separate power supply (with a common ground).

(deleted)

I have 4 servos connected to the nodemcu with 4,5,12,14 pins ( tried with 1,3,4,5 as well). The servos get power from a power suply (5 volts) as well as nodemcu. ( max 15A). Via the code above ony one servo works on pin 5 (gpio5) te rest do not get any command from the nodemcu. The servo on pin 5 is getting command over roboremo via accelerometer or a slide button with id "ca1" and "cb1".( wierd as it should work with just one of these on pin 5). The rest of id's (ch0, ci0) are not assigned to any of nodemcu pins. I've tested all the nodemcu pwm pins with a test code, and all work. Thx for your support guys!

This part of the program should generate 4 pwm signals over 4 different nodemcu pins . (with id's ca1,cb1,ch0,ci0)

const int chCount = 4; // 4 channels, you can add more if you have GPIOs :) Servo servoCh[chCount]; // will generate 4 servo PWM signals int chPin[] = {4, 5, 12, 14}; // ESP pins: GPIO 4,5,12,14

It seems it does not work as it should

My project is a robotic arm with 4 servos (one at base with 180 degree rotation) 2 for arm movements and one for gripper. I'd like to control all of them with accelerometer but it's not smooth. So only the base will be by accelerometer and the rest with slides within roboremo app.

This morning I made a new try, this time without using servo library. Made this with analogWrite on each pin and 8 variables ("sv and svold for each servo). Now i get for each servo, commands simultaneously on the designated pins, but the pwm signal it’s out of range ( one servo almost broke). I don’t know how to adjust in the program for pulse width and delays. This code it’s a brut force method, i know it’s not suitable for servos. That’s why i want to make the first code (in the first page) work.

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

// configurare retea acces telefon (microcontroler wi-fi ESP8266-esp12E->Acces Point)

const char *ssid = "TEAM_UNAVAILABLE";  // Telefonul se va conecta la acest Access Point
const char *pw = "nopassword"; // asta este parola retelei wifi
IPAddress ip(192, 168, 0, 1); // adresa IP de conectare
IPAddress netmask(255, 255, 255, 0);
const int port = 9876; // port de conectare
WiFiServer server(port);
WiFiClient client;

int servo1 = 1;
int servo2 = 3;
int servo3 = 4;
int servo4 = 5;

int usMin = 700; // min pulse width |not used
int usMax = 2300; // max pulse width |not used

//declarare variabile folosite pentru controlul servo
char cmd[100];
int cmdIndex;
int sv1 = 0, sv2 = 0, sv3 = 0, sv4 = 0;
int sv1Old, sv2Old, sv3Old, sv4Old;

unsigned long aliveSentTime = 0;

boolean cmdStartsWith(const char *st) { // checks if cmd starts with st
  for (int i = 0; ; i++) {
    if (st[i] == 0) return true;
    if (cmd[i] == 0) return false;
    if (cmd[i] != st[i]) return false;;
  }
  return false;
}

void onConnectionLost() {

  // inactivitate -->  ,toate comenzile vor intra in inactivitate/OFF/oprit !

  analogWrite(servo1, 0);

  analogWrite(servo2, 0);

  analogWrite(servo3, 0);
 
  analogWrite(servo4, 0);
  
}
unsigned long lastCmdTime = 0;
//parametri pentru comanda motoarelor

void exeCmd() {
  lastCmdTime = millis();


  if ( cmdStartsWith("s1 ") ) {
    sv1Old = sv1;
    sv1 = atoi(cmd + 3);
    if (sv1 > 0) {
      if (sv1Old < 0) {
        analogWrite (servo1, 0);
      }
      analogWrite (servo1, sv1);
    }
    if (sv1 < 0) {
      if (sv1Old > 0) {
        analogWrite (servo1, 0);
      }
      analogWrite (servo1, -sv1);
      if (sv1 == 0) {
        analogWrite(servo1, 0);
      }
    }
  }

  if ( cmdStartsWith("s2 ") ) {
    sv2Old = sv2;
    sv2 = atoi(cmd + 3);
    if (sv2 > 0) {
      if (sv2Old < 0) {
        analogWrite (servo2, 0);
      }
      analogWrite (servo2, sv2);
    }
    if (sv2 < 0) {
      if (sv2Old > 0) {
        analogWrite (servo2, 0);
      }
      analogWrite (servo2, -sv2);
      if (sv2 == 0) {
        analogWrite(servo2, 0);
      }
    }
  }

  if ( cmdStartsWith("s3 ") ) {
    sv3Old = sv3;
    sv3 = atoi(cmd + 3);
    if (sv3 > 0) {
      if (sv3Old < 0) {
        analogWrite (servo3, 0);
      }
      analogWrite (servo3, sv3);
    }
    if (sv3 < 0) {
      if (sv3Old > 0) {
        analogWrite (servo3, 0);
      }
      analogWrite (servo3, -sv3);
      if (sv3 == 0) {
        analogWrite(servo3, 0);
      }
    }
  }
  if ( cmdStartsWith("s4") ) {
    sv4Old = sv4;
    sv4 = atoi(cmd + 3);
    if (sv4 > 0) {
      if (sv4Old < 0) {
        analogWrite (servo4, 0);
      }
      analogWrite (servo4, sv4);
    }
    if (sv4 < 0) {
      if (sv4Old > 0) {
        analogWrite (servo4, 0);
      }
      analogWrite (servo4, -sv4);
      if (sv4 == 0) {
        analogWrite(servo4, 0);
      }
    }
  }

}


void setup() {

  delay(1000); // intarziere pentru pornire wifi

  pinMode(servo1, OUTPUT);
  analogWrite(servo1, 0);
  pinMode(servo2, OUTPUT);
  analogWrite(servo2, 0);
  pinMode(servo3, OUTPUT);
  analogWrite(servo3, 0);
  pinMode(servo4, OUTPUT);
  analogWrite(servo2, 0);


  cmdIndex = 0;
  Serial.begin(115200);

  WiFi.softAPConfig(ip, ip, netmask); // configurare adresa ip pentru AP-Wifi
  WiFi.softAP(ssid, pw); // configurare ssid si parola wifi

  server.begin(); // porneste serverul TCP

  Serial.println("ESP8266 receptor Wifi  -TEAM-UNAVAILABLE ");
  Serial.println((String)"SSID: " + ssid + "  PASS: " + pw);
  Serial.println((String)"Aplicatia Android se va conecta la " + ip.toString() + ":" + port);

}



void loop() {

  // daca nimic nu este receptionat(de catre Microcontroloer ESP8266) timp de 500ms
  if ( millis() - lastCmdTime > 500) {
    onConnectionLost();

  }


  if (!client.connected()) {
    client = server.available();
    return;
  }

  // Avem aplicatia conecatata aici

  if (client.available()) {
    char c = (char)client.read(); // citeste char de la aplicatia Android

    if (c == '\n') { // daca este sfarsit de comanda
      cmd[cmdIndex] = 0;
      exeCmd();  // executa comanda
      cmdIndex = 0; // reseteaza cmdIndex
    } else {
      cmd[cmdIndex] = c; // adauga la cmd buffer
      if (cmdIndex < 99) cmdIndex++;
    }
  }

  if (millis() - aliveSentTime > 500) { // la fiecare 500ms
    client.write("alive 1\n");
    // trimite semnal ca,conectat, astfel LED-ul de conexiune din aplicatia Android va sta aprins
    // (id-ul ledului din aplicatie trebuie sa fie "alive")

    aliveSentTime = millis();
    // daca conexiunea este pierduta, aplicatia android nu va mai primi semnal de conexiune cu microcontrolerul,
    // si astfel ledul se va opri (pentru ca are setat "on timeout" la 700 (ms) )
  }

}

AdyCrv: This morning I made a new try, this time without using servo library. Made this with analogWrite on each pin

analogWrite() is not intended for servos. It is for controlling the speed of a DC motor or the brightness of an LED.

You could write bit-bang code to emulate the output of the Servo library but it would not use analogWrite()

And, sorry, I have no experience of using the Servo library on an ESP8266. I suspect the Atmega328 servo library would not work but I don't know if there is an ESP8266 specific alternative.

Maybe this is a case where the simplest thing would be to use an Atmega 328 in conjunction with the Nodemcu

...R

I'm afraid i can't do that. Don't need the extra complexity and i don't have enough time to order new parts. My projects is due in 2 days! I know it can be done with the microcontroller i have, i just don't have the coding skill to do it without help.

(deleted)

spycatcher2k: It's YOUR project, but you expected us to do YOUR work.

When was this project assigned? Who assigned it to YOU? Is this a joint project, or is it just YOU? Who choose the parts? Why were they chosen?

Very helpful! First I'm not asking anyone to do my work. I asked for some help, an ideea or someone to correct me on my mistakes. I'm not experienced with programming/ micro-programming, so i'm a beginner. Second i'm on my own, no help from anyone , that's why is so fricking frustrating. Third I chose those components , including servos(on a budget), microcontroler (i like eps8266/ep32 cause it's cheap and powerful + integrated wifi) and i'm doing all the parts for the physical robotic arm. Anything else? wanna know my name , phone number, adresse? Most of the code you see is reused from a different project i did (in a team) a year ago with an rc car using the same esp8266. That time was easy to code for using 1 dc motor and 1 kinda like servo using only analogWrite.

AdyCrv: Third I chose those components ... microcontroler (i like eps8266/ep32 cause it's cheap and powerful + integrated wifi)

But did you check that it can control 4 servos?

...R

(deleted)

A little bit of Googling leads me to believe there should be no trouble controlling multiple servos. For example this Thread

Have you tried a simple program that does nothing but sweep your servos back and forth?

...R

Robin2: A little bit of Googling leads me to believe there should be no trouble controlling multiple servos. For example this Thread

Have you tried a simple program that does nothing but sweep your servos back and forth?

...R

Yes i did. Also i wrote a simple servo code and tested that servo on multiple pins, just to be safe in case the nodemcu was DOA.

spycatcher2k: I'm trying to point out :

Planning & research!

What do you want your project to do? Can you find examples to do parts of the project? What physical parts do you need for your project? Will these work with the selected controller you choose? Do you understand what and how to implement the code you have found in your research?

Well now, that's just being cheeky now!

'AdyCrv' - just been added to the "don't help this person under ANY circumstances" list.

and all you had to do was answer the questions, and I could of given you the FULL code to do this project.

I think you misunderstood me big time. I'm not here to ask for a complete code so i can just copy paste it. I'm messing with this project i took so i can learn things, not to get a good grade at school. I had a choice between making a paper work on some old shit pneumatic laboratory robot from 1992, or make something on my own( free pass on deciding whatever i want). Guess wich one i chose ? !

AdyCrv: Yes i did. Also i wrote a simple servo code and tested that servo on multiple pins, just to be safe in case the nodemcu was DOA.

But did you try multiple servos? Isn't that where your problem lies?

...R

Robin2: But did you try multiple servos? Isn't that where your problem lies?

...R

Yes i did try the nodemcu with 4 sevos connected. I used the second program posted by me on first page, but that program is using analogwrite and is not suitable for servo. Al 4 servo work (kinda') ,but the pwm signal is out of range for them, basically i can't control the position. My problem lies in the code.

AdyCrv: Yes i did try the nodemcu with 4 sevos connected. I used the second program posted by me on first page,

Systematic problem solving does not seem to be your forte - but we will get you there, don't worry.

Let's just just focus on the servo-sweep program that you say you tried successfully with one servo attached at different times to 4 different I/O pins.

Modify that program so that it can control all 4 servos and if it does not work then post the program. There is no point worrying about WiFi until you are sure the servos can work with the simplest possible program.

...R