Servo effectue un premier mouvement puis semble se détacher

Bonjour,

J'essaie de me fabriquer un petit bras robot controlé via arduino et avec une interface web (quelques sliders, quelques boutons).
Je me heurte actuellement à un problème, mais je n'arrive pas à comprendre d'où il vient.

J'ai deux versions de mon code qui diffèrent sur la gestion des mouvements des servos. La première demande aux servos de bouger d'un coup (d'une position 0 à 90 en un seul mouvement) mais je trouvais cela très brutale et je ne pense pas que ce soit la meilleure façon de faire. Ce qui m'amène à ma deuxième version, celle ci utilise la logique de l'exemple Servo/Sweep, donc on passe d'une position A à B dans une boucle donnant une position intermédiaire à chaque tour (A --> A+1 --> A+2 ... --> A+n --> B).

Et c'est là que j'ai mon problème, lorsque je teste une nouvelle position via ce code, le servo se déplace jusqu'à sa position une seule fois puis il réagit comme s'il ne recevait plus de commande/courant (servo.detach() en gros) jusqu'à ce que je redémarre la carte. Le reste de l'appli continue de fonctionner, juste le servo est comme mort.

Erreur que je n'ai pas dans la première version de mon code.

Avez-vous une idée d'où ça peut venir ? Ou au moins des pistes de recherche ?
Il y a quelque chose d'obvious que je ne vois pas ?

Via des tests empiriques avec Serial et du délai cela semble se produire pendant le chargement de la page web.
Les servos utilisés sont des MG995 et la carte est une ESP32 et sont branchés sur une alim externe.
J'ai testé le code sur des servos avec et sans charge, je me retrouve toujours avec la même erreur.

Pour une raison que j'ignore, j'avais ces erreurs mais ne les retrouve plus dans mes logs :

Socket is not connected
Connection reset by peer

Le code V1 :

#include <WiFi.h>
#include <Servo.h>
#include <Preferences.h>
#include <WiFiManager.h>

Servo servoBase;  // create servo object to control a servo
Servo servoArm1;
Servo servoArm2;
Servo servoEnd;
// twelve servo objects can be created on most boards

Preferences preferences;

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

// Variable to store the HTTP request
String header;

int posServoBase = 0;
int posServoArm1 = 0;
int posServoArm2 = 0;
int posServoEnd = 0;
String posBaseServo = String(0);
String posArm1Servo = String(0);
String posArm2Servo = String(0);
String posEndServo = String(0);

int elecAimDev = 25;
int elecAimAD = 26;
int elecAimAG = 27;

// 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(115200);

  wifiConnection();
  initServo();
  initAimant();

  preferences.begin("positions", false);

  //start server  
  server.begin();
}

void loop(){
  WiFiClient client = server.available();   // Listen for incoming clients
  
  if (client) {                             // If a new client connects,
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");     // print a message out in the serial port
    String currentLine = "";    
                // make a String to hold incoming data from the client
    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) {
            manageServerResponse(header);

            loadHtmlPage(client);

            client.println();
            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
        }
      }      
      
    }
    //Serial.println(preferences.getUInt("servoBase", posServoBase));
    //Serial.println(preferences.getUInt("servoArm1", posServoArm1));
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

void wifiConnection() {
  //Local initialization of WiFiManager
  WiFiManager wm;

  bool res;
  res = wm.autoConnect("AutoConnectAP","CapsTrainer");

  if (!res) {
    Serial.println("Failed to connect to WiFi");
  }
  else {
    Serial.println("Connected to WiFi !");
  }
}

void initServo() {
  servoBase.attach(18);  // attaches the servo on the servoPin to the servo object
  servoArm1.attach(19);
  servoArm2.attach(21);
  servoEnd.attach(5);
}

void initAimant() {
  pinMode(elecAimDev, OUTPUT);
  digitalWrite(elecAimDev, HIGH);
  pinMode(elecAimAD, OUTPUT);
  digitalWrite(elecAimAD, HIGH);
  pinMode(elecAimAG, OUTPUT);
  digitalWrite(elecAimAG, HIGH);
}

void manageServerResponse(String header) {

  if(header.indexOf("GET /?value=")>=0 && header.indexOf("&servo=")>=0) {
    int posEqualURL = header.indexOf('=');
    int posAndURL = header.indexOf('&');
    String posServo = header.substring(posEqualURL+1, posAndURL);
    int posServoURL = header.indexOf("servo=");
    posEqualURL = header.indexOf('=', posServoURL);
    posAndURL = header.indexOf('&', posServoURL);
    String whichServo = header.substring(posEqualURL+1, posAndURL);
    //Rotate the servo
    Serial.println("Servo : " + whichServo);

    moveServo(whichServo, posServo);
 
    //Serial.println("posServoBase : " + posServoBase); 
    
  }
  if(header.indexOf("GET /save/load") >= 0) {
    saveServoLoadPositions();
  }  
  if(header.indexOf("GET /load/load") >= 0) {
    loadServoLoadPositions();
  }
  if(header.indexOf("GET /save/sleep") >= 0) {
    saveServoSleepPositions();
  }  
  if(header.indexOf("GET /load/sleep") >= 0) {
    loadServoSleepPositions();
  }
  if(header.indexOf("Get /reload") >= 0) {
    reloadCaps();
  }      
  // The HTTP response ends with another blank line
  
  // Break out of the while loop
  
}

void moveServo(String servo, String positionServo) {

  if (servo == "servoBase") {
      posBaseServo = positionServo;
      posServoBase = positionServo.toInt();
      servoBase.write(posServoBase);
  }
  else if (servo == "servoArm1") { 
      posArm1Servo = positionServo;
      posServoArm1 = positionServo.toInt();
      servoArm1.write(posServoArm1);
  }
  else if (servo == "servoArm2") {
      posArm2Servo = positionServo;
      posServoArm2 = positionServo.toInt();
      servoArm2.write(posServoArm2);      
  }
  else if (servo == "servoEnd") {
      posEndServo = positionServo;
      posServoEnd = positionServo.toInt();
      servoEnd.write(posServoEnd); 
  }
}

void saveServoLoadPositions() {   
  preferences.putUInt("servoBaseLoad", posServoBase);
  preferences.putUInt("servoArm1Load", posServoArm1);
  preferences.putUInt("servoArm2Load", posServoArm2);
  preferences.putUInt("servoEndLoad", posServoEnd);
}

void loadServoLoadPositions() {
  posServoBase = preferences.getUInt("servoBaseLoad", 0);
  posBaseServo = String(posServoBase);
  servoBase.write(posServoBase); 
  posServoArm1 = preferences.getUInt("servoArm1Load", 0);   
  posArm1Servo = String(posServoArm1);     
  servoArm1.write(posServoArm1);
  posServoArm2 = preferences.getUInt("servoArm2Load", 0);   
  posArm2Servo = String(posServoArm2);     
  servoArm2.write(posServoArm2);
  posServoEnd = preferences.getUInt("servoEndLoad", 0);   
  posEndServo = String(posServoEnd);     
  servoEnd.write(posServoEnd);
}

void saveServoSleepPositions() {   
  preferences.putUInt("servoBaseSleep", posServoBase);
  preferences.putUInt("servoArm1Sleep", posServoArm1);
  preferences.putUInt("servoArm2Sleep", posServoArm2);
  preferences.putUInt("servoEndSleep", posServoEnd);
}

void loadServoSleepPositions() {
  posServoBase = preferences.getUInt("servoBaseSleep", 0);
  posBaseServo = String(posServoBase);
  servoBase.write(posServoBase); 
  posServoArm1 = preferences.getUInt("servoArm1Sleep", 0);   
  posArm1Servo = String(posServoArm1);     
  servoArm1.write(posServoArm1);
  posServoArm2 = preferences.getUInt("servoArm2Sleep", 0);   
  posArm2Servo = String(posServoArm2);     
  servoArm2.write(posServoArm2);
  posServoEnd = preferences.getUInt("servoEndSleep", 0);   
  posEndServo = String(posServoEnd);     
  servoEnd.write(posServoEnd);
}

void reloadCaps() {
  goToBottlePosition();
  delay(2000);
  elecAimOff();
  delay(1000);
  goToSleepPosition();
  delay(500);
  elecAimOn();  
}

void goToBottlePosition() {
  servoBase.write(preferences.getUInt("servoBaseLoad", 0));
  servoArm1.write(preferences.getUInt("servoArm1Load", 0));  
  servoArm2.write(preferences.getUInt("servoArm2Load", 0));
  servoEnd.write(preferences.getUInt("servoEndLoad", 0));
}

void elecAimOff() {
  digitalWrite(elecAimDev, LOW);
  digitalWrite(elecAimDev, LOW);
  digitalWrite(elecAimDev, LOW);
}

void goToSleepPosition() {
  servoEnd.write(preferences.getUInt("servoEndSleep", 0));
  servoArm2.write(preferences.getUInt("servoArm2Sleep", 0));
  servoArm1.write(preferences.getUInt("servoArm1Sleep", 0));
  servoBase.write(preferences.getUInt("servoBaseSleep", 0));
}

void elecAimOn() {
  digitalWrite(elecAimDev, HIGH);
  digitalWrite(elecAimDev, HIGH);
  digitalWrite(elecAimDev, HIGH);
}

void loadHtmlPage(WiFiClient client) {
  // 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();

  // Display the HTML web page
  client.println("<!DOCTYPE html><html>");
  client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" charset=\"UTF-8\">");
  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>body { text-align: center; font-family: \"Trebuchet MS\", Arial; margin-left:auto; margin-right:auto;}");
  client.println(".tab {overflow: hidden;border: 1px solid #ccc;background-color: #f1f1f1;}");
  client.println(".tab button {background-color: inherit;float: left;width: 50%;border: none;outline: none;cursor: pointer;padding: 14px 16px;transition: 0.3s;}");
  client.println(".tab button:hover {background-color: #ddd;}");
  client.println(".tab button.active {background-color: #ccc;}");
  client.println(".tabcontent {display: none; padding: 6px 12px;}");
  client.println(".slider { width: 300px; }</style>");
  client.println("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js\"></script>");
            
  // Web Page
  client.println("</head><body><h1>CAPS TRAINER</h1>");
  client.println("<div class=\"tab\"><button class=\"tablinks\" onclick=\"openTab(event, 'Setup')\" id=\"defaultOpen\">Setup</button><button class=\"tablinks\" onclick=\"openTab(event, 'Use')\">Use</button></div>");
  client.println("<div id=\"Setup\" class=\"tabcontent\">");
  client.println("<p>Position base : <span id=\"basePos\"></span></p>");          
  client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"baseSlider\" onchange=\"servo(this.value,'servoBase')\" value=\""+posBaseServo+"\"/>");
  client.println("<p>Position bras 1 : <span id=\"arm1Pos\"></span></p>");          
  client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"arm1Slider\" onchange=\"servo(this.value,'servoArm1')\" value=\""+posArm1Servo+"\"/>");
  client.println("<p>Position bras 2 : <span id=\"arm2Pos\"></span></p>");          
  client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"arm2Slider\" onchange=\"servo(this.value,'servoArm2')\" value=\""+posArm2Servo+"\"/>");
  client.println("<p>Position tête : <span id=\"endPos\"></span></p>");          
  client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"endSlider\" onchange=\"servo(this.value,'servoEnd')\" value=\""+posEndServo+"\"/>");
  client.println("<p>Enregistrer la position de recharge: <span id=\"save\"></span></p><a href=\"/save/load\"><button>Save</button></a>"); 
  client.println("<p>Charger la position de recharge: <span id=\"load\"></span></p><a href=\"/load/load\"><button>Load</button></a>"); 
  client.println("<p>Enregistrer la position de repos: <span id=\"save\"></span></p><a href=\"/save/sleep\"><button>Save</button></a>"); 
  client.println("<p>Charger la position de repos: <span id=\"load\"></span></p><a href=\"/load/sleep\"><button>Load</button></a>"); 
  client.println("</div>");
  client.println("<div id=\"Use\" class=\"tabcontent\">");
  client.println("<p>Recharger les CAPS : <span id=\"recharge\"></span></p><a href=\"/reload\"><button>Recharger</button></a>");
  client.println("</div>");
  client.println("<script>");
  client.println("var sliderBase = document.getElementById(\"baseSlider\"); var servoBasePos = document.getElementById(\"basePos\"); servoBasePos.innerHTML = sliderBase.value;" );
  client.println("sliderBase.oninput = function() { sliderBase.value = this.value; servoBasePos.innerHTML = this.value; }");
  client.println("var sliderArm1 = document.getElementById(\"arm1Slider\"); var servoArm1Pos = document.getElementById(\"arm1Pos\"); servoArm1Pos.innerHTML = sliderArm1.value;");
  client.println("sliderArm1.oninput = function() { sliderArm1.value = this.value; servoArm1Pos.innerHTML = this.value; }");
  client.println("var sliderArm2 = document.getElementById(\"arm2Slider\"); var servoArm2Pos = document.getElementById(\"arm2Pos\"); servoArm2Pos.innerHTML = sliderArm2.value;");
  client.println("sliderArm2.oninput = function() { sliderArm2.value = this.value; servoArm2Pos.innerHTML = this.value; }");
  client.println("var sliderEnd = document.getElementById(\"endSlider\"); var servoEndPos = document.getElementById(\"endPos\"); servoEndPos.innerHTML = sliderEnd.value;");
  client.println("sliderEnd.oninput = function() { sliderEnd.value = this.value; servoEndPos.innerHTML = this.value; }");
  client.println("function openTab(evt, cityName) {");
  client.println("var i, tabcontent, tablinks;tabcontent = document.getElementsByClassName(\"tabcontent\");");
  client.println("for (i = 0; i < tabcontent.length; i++) {tabcontent[i].style.display = \"none\";}");
  client.println("tablinks = document.getElementsByClassName(\"tablinks\");");
  client.println("for (i = 0; i < tablinks.length; i++) {tablinks[i].className = tablinks[i].className.replace(\" active\", \"\");}");
  client.println("document.getElementById(cityName).style.display = \"block\";evt.currentTarget.className += \" active\";}");
  client.println("document.getElementById(\"defaultOpen\").click();");
  client.println("$.ajaxSetup({timeout:1000}); function servo(pos, servo) { ");
  client.println("$.get(\"/?value=\" + pos + \"&\" + \"servo=\" + servo + \"&\"); {Connection: close};}</script>");
  
  client.println("</body></html>"); 
}

Le code V2 :

#include <WiFi.h>
#include <Servo.h>
#include <Preferences.h>
#include <WiFiManager.h>

Servo servoBase;  // create servo object to control a servo
Servo servoArm1;
Servo servoArm2;
Servo servoEnd;
// twelve servo objects can be created on most boards

Preferences preferences;

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

// Variable to store the HTTP request
String header;

int posServo = 0;
int posServoBase = 90;
int posServoArm1 = 90;
int posServoArm2 = 90;
int posServoEnd = 90;

int elecAimDev = 25;
int elecAimAD = 26;
int elecAimAG = 27;

// 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(115200);

  wifiConnection();
  initServo();
  initAimant();

  preferences.begin("positions", false);

  //start server
  server.begin();
}

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

  if (client) {  // If a new client connects,
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");  // print a message out in the serial port
    String currentLine = "";
    // make a String to hold incoming data from the client
    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) {
            manageServerResponse(header);

            Serial.println("Before html load");
            loadHtmlPage(client);
            Serial.println("After html load");
            client.println();
            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
        }
      }
    }
    //Serial.println(preferences.getUInt("servoBase", posServoBase));
    //Serial.println(preferences.getUInt("servoArm1", posServoArm1));
    // Clear the header variable
    header = "";
    // Close the connection
    Serial.println("Stopping client");
    client.stop();
    Serial.println("Client stopped");
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

void wifiConnection() {
  //Local initialization of WiFiManager
  WiFiManager wm;

  bool res;
  res = wm.autoConnect("AutoConnectAP", "CapsTrainer");

  if (!res) {
    Serial.println("Failed to connect to WiFi");
  } else {
    Serial.println("Connected to WiFi !");
  }
}

void initServo() {
  servoBase.attach(18);  // attaches the servo on the servoPin to the servo object
  servoArm1.attach(19);
  servoArm1.write(90);
  servoArm2.attach(21);
  servoEnd.attach(5);
}

void initAimant() {
  pinMode(elecAimDev, OUTPUT);
  digitalWrite(elecAimDev, HIGH);
  pinMode(elecAimAD, OUTPUT);
  digitalWrite(elecAimAD, HIGH);
  pinMode(elecAimAG, OUTPUT);
  digitalWrite(elecAimAG, HIGH);
}

void manageServerResponse(String header) {

  if (header.indexOf("GET /?value=") >= 0 && header.indexOf("&servo=") >= 0) {
    int posEqualURL = header.indexOf('=');
    int posAndURL = header.indexOf('&');
    int newPosServo = header.substring(posEqualURL + 1, posAndURL).toInt();
    int posServoURL = header.indexOf("servo=");
    posEqualURL = header.indexOf('=', posServoURL);
    posAndURL = header.indexOf('&', posServoURL);
    String whichServo = header.substring(posEqualURL + 1, posAndURL);
    //Rotate the servo
    Serial.println("Servo : " + whichServo);

    Servo servo = findServo(whichServo);
    moveServo(servo, posServo, newPosServo);
    delay(5000);
    writeNewPos(whichServo, newPosServo);
    //Serial.println("posServoBase : " + posServoBase);
  }
  if (header.indexOf("GET /save/load") >= 0) {
    saveServoLoadPositions();
  }
  if (header.indexOf("GET /load/load") >= 0) {
    loadServoLoadPositions();
  }
  if (header.indexOf("GET /save/sleep") >= 0) {
    saveServoSleepPositions();
  }
  if (header.indexOf("GET /load/sleep") >= 0) {
    loadServoSleepPositions();
  }
  if (header.indexOf("GET /reload") >= 0) {
    reloadCaps();
  }
  // The HTTP response ends with another blank line

  // Break out of the while loop
}

Servo findServo(String servo) {

  if (servo == "servoBase") {
    posServo = posServoBase;

    return servoBase;
  } else if (servo == "servoArm1") {
    posServo = posServoArm1;
    return servoArm1;
  } else if (servo == "servoArm2") {
    posServo = posServoArm2;
    return servoArm2;
  } else if (servo == "servoEnd") {
    posServo = posServoEnd;
    return servoEnd;
  }
}

void moveServo(Servo servo, int basePos, int newPos) {
  Serial.println("basePos : " + String(basePos));
  Serial.println("newPos : " + String(newPos));
  if (basePos <= newPos) {
    Serial.println("test");
    for (int i = basePos; i <= newPos; i += 1) {
      servo.write(i);
      delay(100);
    }
  } else {
    Serial.println("test1");
    for (int i = basePos; i >= newPos; i -= 1) {
      servo.write(i);
      delay(50);
    }
  }
}

void saveServoLoadPositions() {
  preferences.putUInt("servoBaseLoad", posServoBase);
  preferences.putUInt("servoArm1Load", posServoArm1);
  preferences.putUInt("servoArm2Load", posServoArm2);
  preferences.putUInt("servoEndLoad", posServoEnd);
}

void loadServoLoadPositions() {
  moveServo(servoBase, posServoBase, preferences.getUInt("servoBaseLoad", 0));
  posServoBase = preferences.getUInt("servoBaseLoad", 0);

  moveServo(servoArm1, posServoArm1, preferences.getUInt("servoArm1Load", 0));
  posServoArm1 = preferences.getUInt("servoArm1Load", 0);

  moveServo(servoArm2, posServoArm2, preferences.getUInt("servoArm2Load", 0));
  posServoArm2 = preferences.getUInt("servoArm2Load", 0);

  moveServo(servoEnd, posServoEnd, preferences.getUInt("servoEndLoad", 0));
  posServoEnd = preferences.getUInt("servoEndLoad", 0);
}

void saveServoSleepPositions() {
  preferences.putUInt("servoBaseSleep", posServoBase);
  preferences.putUInt("servoArm1Sleep", posServoArm1);
  preferences.putUInt("servoArm2Sleep", posServoArm2);
  preferences.putUInt("servoEndSleep", posServoEnd);
}

void loadServoSleepPositions() {
  moveServo(servoBase, posServoBase, preferences.getUInt("servoBaseSleep", 0));
  posServoBase = preferences.getUInt("servoBaseLoad", 0);

  moveServo(servoArm1, posServoArm1, preferences.getUInt("servoArm1Sleep", 0));
  posServoArm1 = preferences.getUInt("servoArm1Sleep", 0);

  moveServo(servoArm2, posServoArm2, preferences.getUInt("servoArm2Sleep", 0));
  posServoArm2 = preferences.getUInt("servoArm2Load", 0);

  moveServo(servoEnd, posServoEnd, preferences.getUInt("servoEndSleep", 0));
  posServoEnd = preferences.getUInt("servoEndLoad", 0);
}

void reloadCaps() {
  goToBottlePosition();
  delay(2000);
  elecAimOff();
  delay(1000);
  goToSleepPosition();
  delay(500);
  elecAimOn();
}

void goToBottlePosition() {
  servoBase.write(preferences.getUInt("servoBaseLoad", 0));
  servoArm1.write(preferences.getUInt("servoArm1Load", 0));
  servoArm2.write(preferences.getUInt("servoArm2Load", 0));
  servoEnd.write(preferences.getUInt("servoEndLoad", 0));
}

void elecAimOff() {
  digitalWrite(elecAimDev, LOW);
  digitalWrite(elecAimDev, LOW);
  digitalWrite(elecAimDev, LOW);
}

void goToSleepPosition() {
  servoEnd.write(preferences.getUInt("servoEndSleep", 0));
  servoArm2.write(preferences.getUInt("servoArm2Sleep", 0));
  servoArm1.write(preferences.getUInt("servoArm1Sleep", 0));
  servoBase.write(preferences.getUInt("servoBaseSleep", 0));
}

void elecAimOn() {
  digitalWrite(elecAimDev, HIGH);
  digitalWrite(elecAimDev, HIGH);
  digitalWrite(elecAimDev, HIGH);
}

void writeNewPos(String servo, int value) {
  if (servo == "servoBase") {
    posServoBase = value;
  } else if (servo == "servoArm1") {
    posServoArm1 = value;
  } else if (servo == "servoArm2") {
    posServoArm2 = value;
  } else if (servo == "servoEnd") {
    posServoEnd = value;
  }
}



void loadHtmlPage(WiFiClient client) {
  // 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.flush();
  client.println("HTTP/1.1 200 OK");
  Serial.println("HTTP/1.1 200 OK");
  client.println("Content-type:text/html");
  Serial.println("Content-type:text/html");
  client.println("Connection: close");
  Serial.println("Connection: close");
  client.println();
  // Display the HTML web page
  client.println("<!DOCTYPE html><html>");
  client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" charset=\"UTF-8\">");
  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>body { text-align: center; font-family: \"Trebuchet MS\", Arial; margin-left:auto; margin-right:auto;}");
  client.println(".tab {overflow: hidden;border: 1px solid #ccc;background-color: #f1f1f1;}");
  client.println(".tab button {background-color: inherit;float: left;width: 50%;border: none;outline: none;cursor: pointer;padding: 14px 16px;transition: 0.3s;}");
  client.println(".tab button:hover {background-color: #ddd;}");
  client.println(".tab button.active {background-color: #ccc;}");
  client.println(".tabcontent {display: none; padding: 6px 12px;}");
  client.println(".slider { width: 300px; }</style>");
  client.println("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js\"></script>");

  // Web Page
  client.println("</head><body><h1>CAPS TRAINER</h1>");
  client.println("<div class=\"tab\"><button class=\"tablinks\" onclick=\"openTab(event, 'Setup')\" id=\"defaultOpen\">Setup</button><button class=\"tablinks\" onclick=\"openTab(event, 'Use')\">Use</button></div>");
  client.println("<div id=\"Setup\" class=\"tabcontent\">");
  client.println("<p>Position base : <span id=\"basePos\"></span></p>");
  Serial.println("Before strin,g html");
  client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"baseSlider\" onchange=\"servo(this.value,'servoBase')\" value=\"" + String(posServoBase) + "\"/>");
  client.println("<p>Position bras 1 : <span id=\"arm1Pos\"></span></p>");
  client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"arm1Slider\" onchange=\"servo(this.value,'servoArm1')\" value=\"" + String(posServoArm1) + "\"/>");
  client.println("<p>Position bras 2 : <span id=\"arm2Pos\"></span></p>");
  client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"arm2Slider\" onchange=\"servo(this.value,'servoArm2')\" value=\"" + String(posServoArm2) + "\"/>");
  client.println("<p>Position tête : <span id=\"endPos\"></span></p>");
  client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"endSlider\" onchange=\"servo(this.value,'servoEnd')\" value=\"" + String(posServoEnd) + "\"/>");
  Serial.println("Test string html");
  client.println("<p>Enregistrer la position de recharge: <span id=\"save\"></span></p><a href=\"/save/load\"><button>Save</button></a>");
  client.println("<p>Charger la position de recharge: <span id=\"load\"></span></p><a href=\"/load/load\"><button>Load</button></a>");
  client.println("<p>Enregistrer la position de repos: <span id=\"save\"></span></p><a href=\"/save/sleep\"><button>Save</button></a>");
  client.println("<p>Charger la position de repos: <span id=\"load\"></span></p><a href=\"/load/sleep\"><button>Load</button></a>");
  client.println("</div>");
  client.println("<div id=\"Use\" class=\"tabcontent\">");
  client.println("<p>Recharger les CAPS : <span id=\"recharge\"></span></p><a href=\"/reload\"><button>Recharger</button></a>");
  client.println("</div>");
  client.println("<script>");
  client.println("var sliderBase = document.getElementById(\"baseSlider\"); var servoBasePos = document.getElementById(\"basePos\"); servoBasePos.innerHTML = sliderBase.value;");
  client.println("sliderBase.oninput = function() { sliderBase.value = this.value; servoBasePos.innerHTML = this.value; }");
  client.println("var sliderArm1 = document.getElementById(\"arm1Slider\"); var servoArm1Pos = document.getElementById(\"arm1Pos\"); servoArm1Pos.innerHTML = sliderArm1.value;");
  client.println("sliderArm1.oninput = function() { sliderArm1.value = this.value; servoArm1Pos.innerHTML = this.value; }");
  client.println("var sliderArm2 = document.getElementById(\"arm2Slider\"); var servoArm2Pos = document.getElementById(\"arm2Pos\"); servoArm2Pos.innerHTML = sliderArm2.value;");
  client.println("sliderArm2.oninput = function() { sliderArm2.value = this.value; servoArm2Pos.innerHTML = this.value; }");
  client.println("var sliderEnd = document.getElementById(\"endSlider\"); var servoEndPos = document.getElementById(\"endPos\"); servoEndPos.innerHTML = sliderEnd.value;");
  client.println("sliderEnd.oninput = function() { sliderEnd.value = this.value; servoEndPos.innerHTML = this.value; }");
  client.println("function openTab(evt, cityName) {");
  client.println("var i, tabcontent, tablinks;tabcontent = document.getElementsByClassName(\"tabcontent\");");
  client.println("for (i = 0; i < tabcontent.length; i++) {tabcontent[i].style.display = \"none\";}");
  client.println("tablinks = document.getElementsByClassName(\"t ablinks\");");
  client.println("for (i = 0; i < tablinks.length; i++) {tablinks[i].className = tablinks[i].className.replace(\" active\", \"\");}");
  client.println("document.getElementById(cityName).style.display = \"block\";evt.currentTarget.className += \" active\";}");
  client.println("document.getElementById(\"defaultOpen\").click();");
  client.println("$.ajaxSetup({timeout:1000}); function servo(pos, servo) { ");
  client.println("$.get(\"/?value=\" + pos + \"&\" + \"servo=\" + servo + \"&\"); {Connection: close};}</script>");

  client.println("</body></html>");
}

J'ai aussi essayé de passer la partie HTML/CSS via SPIFFS mais avec les mêmes résultats. J'ai aussi modifié le delay présent dans la boucle (plus ou moins long), sans résultats.

Qu'indique ta sortie série ?

J'ai tout ça (chargement de la page html + changement de position 90 --> 109 et 109 --> 125

13:31:33.491 -> New Client.
13:31:33.491 -> GET / HTTP/1.1
13:31:33.491 -> Host: 192.168.1.43
13:31:33.491 -> Connection: keep-alive
13:31:33.491 -> Cache-Control: max-age=0
13:31:33.491 -> Upgrade-Insecure-Requests: 1
13:31:33.491 -> User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36
13:31:33.491 -> Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
13:31:33.531 -> Accept-Encoding: gzip, deflate
13:31:33.531 -> Accept-Language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7
13:31:33.531 -> 
13:31:33.531 -> Before html load
13:31:33.531 -> Charge html
13:31:33.531 -> HTTP/1.1 200 OK
13:31:33.531 -> Content-type:text/html
13:31:33.531 -> Connection: close
13:31:33.563 -> Test string html
13:31:33.563 -> Fin html
13:31:33.563 -> After html load
13:31:33.599 -> Stopping client
13:31:33.599 -> Client stopped
13:31:33.599 -> Client disconnected.
13:31:33.599 -> 
13:31:34.821 -> New Client.
13:31:34.821 -> GET /?value=109&servo=servoArm1& HTTP/1.1
13:31:34.821 -> Host: 192.168.1.43
13:31:34.821 -> Connection: keep-alive
13:31:34.821 -> Accept: */*
13:31:34.821 -> User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36
13:31:34.821 -> X-Requested-With: XMLHttpRequest
13:31:34.821 -> Referer: http://192.168.1.43/
13:31:34.821 -> Accept-Encoding: gzip, deflate
13:31:34.821 -> Accept-Language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7
13:31:34.859 -> 
13:31:34.859 -> Servo : servoArm1
13:31:34.859 -> basePos : 90
13:31:34.859 -> newPos : 109
13:31:34.859 -> test
13:31:36.817 -> Before html load
13:31:36.861 -> Charge html
13:31:36.861 -> HTTP/1.1 200 OK
13:31:36.861 -> Content-type:text/html
13:31:36.861 -> Connection: close
13:31:36.861 -> Test string html
13:31:36.861 -> Fin html
13:31:36.861 -> After html load
13:31:36.861 -> Stopping client
13:31:36.861 -> Client stopped
13:31:36.861 -> Client disconnected.
13:31:36.861 -> 
13:32:28.790 -> New Client.
13:32:28.790 -> GET /?value=125&servo=servoArm1& HTTP/1.1
13:32:28.790 -> Host: 192.168.1.43
13:32:28.790 -> Connection: keep-alive
13:32:28.790 -> Accept: */*
13:32:28.790 -> User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36
13:32:28.790 -> X-Requested-With: XMLHttpRequest
13:32:28.791 -> Referer: http://192.168.1.43/
13:32:28.791 -> Accept-Encoding: gzip, deflate
13:32:28.791 -> Accept-Language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7
13:32:28.835 -> 
13:32:28.835 -> Servo : servoArm1
13:32:28.835 -> basePos : 109
13:32:28.835 -> newPos : 125
13:32:28.835 -> test
13:32:30.529 -> Before html load
13:32:30.529 -> Charge html
13:32:30.529 -> HTTP/1.1 200 OK
13:32:30.529 -> Content-type:text/html
13:32:30.529 -> Connection: close
13:32:30.529 -> Test string html
13:32:30.529 -> Fin html
13:32:30.529 -> After html load
13:32:30.529 -> Stopping client
13:32:30.529 -> Client stopped
13:32:30.529 -> Client disconnected.
13:32:30.529 -> 

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