Shaking servos on robotic marionette

Need help. My servos in this marionette robotic head are shaking.

YouTube preview of the machine and sounds coming out of it.

They are connected straight to Li-ion 3,7v 2600 mA battery (and control pins to WeMos D1)

I am using:
6x servos BlueBird 127 MV
WeMos D1 Mini Pro
WeMos Battery Shield for D1

Thank you for your help or suggestions.

Hi @petr-puppeteer .
I don't know if this is your case, but if you "tell" the servo to turn to angle X, but block its movement at angle X - Y, it will try to reach angle X and therefore it will be vibrating all the time .
RV mineirin

Generally, servo problems are caused by a lack of power. You have apparently avoided the common mistake of trying to power your servos from the micro controller but I'll guess that your battery isn't up to the task.

I see that there's a Bluebird 127 WV - I couldn't see the MV variant at their site. The minimum voltage for that one is, to my surprise, 3.7V. I suspect that your battery voltage is sagging below that when you try to run six servos off it.

3.7V is the minimum for those servos (specs from here). Twitching servos often is a sign of lack of power. Monitor the supply voltage to the servos. Does it remain 3.7V or higher? Does the voltage dip when 1 or more servos are in motion?

Thank you very much!

Woud the solution be to plug two batteries in the series and increase the voltage going to servos to about 8V (I would power WeMos separately with 3,7V)?

Worth a try. It may still be problematic though - six servos pull a lot of current.

No. You need more current, not voltage. Small servos require about 1 Ampere per servo, larger ones up to 3 Amperes per servo, so the servo power supply should be able to provide at the very least 6 Amperes. I suggest to use a 4.8-6V NiMH battery pack with 10C discharge capability.

I was not able to find a specification for the start/stall current of that servo, but it is usually 5X to 10X the free running, no load current.

Sorry for my lame questions but then if I connect let say 4 of the batteries I have (Li-ion Cell 2600mAh 3,7 V) into serial connection it should give me enough current and discharge capability, right? It is quite crucial for the marionette to be light... Then I guess I will anyway need 4,8-6V batteries. It will speed up the servos, which is wanted.

NiMH battery packs for RC vehicles are lightweight, are intended for high current operation and are available in a wide range of voltages. They are much more tolerant of abuse than LiPo batteries, and easier to charge.

However, if you insist on using those LiPo cells, to increase current, use parallel connections. First try two or three 3.7V batteries in parallel.

But 3.7 V is the absolute minimum voltage for that servo, so you might try using four of those batteries, with two sets of parallel connected batteries in series (2S2P). You will need a 2S LiPo charger for that combination.

Schematic:
Capture

Thank you very much. I definitely don't insist on LiPo batteries. Just having them here/now... Will buy NiMH cells in 3days after our public holidays :slight_smile:

However. I did try both versions putting 3 batteries to parallel connection and 2paraller+2paraller connected batteries into serial connection (with separate battery for WeMos) and the buzz is still there without any change.

Hope I will not have to change the engines :sleepy:

Something else is wrong. Do you have all the grounds connected?

Connect just one servo, and check to see if you can control it without jitter. Add a second and test, add the third, etc.

Great. Thank you. I have to go home from the workshop now and will try that agian in the morning. I am in Prague (EU). Thanks a lot for your support!

So I have connected new engines to make sure there is no connection problem and to be able to plug in/off each engine separately and the results are:

– If I disconnect any of the two Arduinos (server–engines or client–controller device part) all the engines stop shivering (Arduinos communicate via wifi)
– If I connect less engines the shivering goes even higher

I suppose there will be some sort of problem with Arduino. Unfortunately I am not Arduino programmer so will have to wait till Wednesday for the guy who was programming it all....

Post the code, using code tags.

Thanks, but please go back and add CODE TAGS to your post.

Let me translate the tags and pass it again.

#include <Wire.h>

/**
******************************************************************************
  @author    Arduino development
  @version  3.0
  @date     22.09.2020
  @brief    ESP Server - marionettes.cz

*/

#define SERIAL_DEBUG_OUT
#define SERIAL_BAUDRATE       115200

#define SERVER_PORT           80
#define CLIENT_TOUT           2000
#define DATA_LENGTH           11
#define KEEP_ALIVE_T          9999

//pinout same as here: https://docs.wemos.cc/en/latest/d1/d1_mini.html
#define SERVO_EYES_HOR_PIN    5   //D1 – horizontal eyes
#define SERVO_EYES_VER_PIN    4   //D2 – vertival eyes
#define SERVO_LEYELID_PIN     0   //D3 – left eyelid
#define SERVO_REYELID_PIN     2   //D4 – right eyelid  
#define SERVO_ARM_PIN         14  //D5 – arm
#define SERVO_EYEBROW_PIN     12  //D6 – eyebrow
#define SERVO_NOSE_PIN        13  //D7 – nose
#define SERVO_MOUTH_PIN       15  //D8 – mouth

#define EYE_HORIZONTAL_LEFT   50  /* look left (accordin to servo instalation) – value has to be less then 10° comparing to CNT value*/
#define EYE_HORIZONTAL_CNT    90  /* look stright */
#define EYE_HORIZONTAL_RIGHT  130 /* look right/left (accordin to servo instalation) – value has to be more then 10° comparing to CNT value*/
#define EYE_VERTICAL_UP       70  /* look down (accordin to servo instalation) – value has to be less then 10° comparing to CNT value*/
#define EYE_VERTICAL_CNT      120  /* look stright */
#define EYE_VERTICAL_DOWN     150 /* look up (accordin to servo instalation) – value has to be more then 10° comparing to CNT value*/

#define EYE_SERVO_OFFSET      10  /* Deviation for binary use of joystick */

#define L_EYELID_EXCITEMENT   175  /* left eyelid up (excitemet) */
#define L_EYELID_NORMAL       155/* left eyelid normaly open */
#define L_EYELID_ANGER        140 /* left eyelid half way down (angry) */
#define L_EYELID_SURPRICE     110 /* left eyelid down */
#define L_EYELID_BLINK        105/* left eyelid blink */

#define R_EYELID_EXCITEMENT   0 /* right eyelid up (excitemet) */
#define R_EYELID_NORMAL       25  /* right eyelid normaly open */
#define R_EYELID_ANGER        35  /* right eyelid half way down (angry) */
#define R_EYELID_SURPRICE     65  /* right eyelid down */
#define R_EYELID_BLINK        70 /* right eyelid blink */

/* Hand movement can be inverted by changing min and Max */
#define ARM_MIN               20  /* after pressing and holing a buttton */
#define ARM_MAX               150  /* after releasing the button */

#define NOSE_LEFT             80  /* moving nose up (accordin to servo instalation) */
#define NOSE_NORMAL           90  /* nose middle position */
#define NOSE_RIGHT            100 /* moving nose down (accordin to servo instalation) */

#define EYEBROW_UP            110  /* Excitement eyebrows up */
#define EYEBROW_NORMAL        90  /* Eyebrows normal position */
#define EYEBROW_DOWN          70 /* Eyebrows down (angry) */

#define MOUTH_MIN             0 /* minimal angle of the mouth servo */
#define MOUTH_MAX             140 /* maximal angle of the mouth servo */

/* time contacts */
#define AUTO_BLINK_T          5000  /* winking frequency in ms */
#define BLINK_T               500     /* Delay during blink in ms */
#define NOSE_T                5     /* Delay during nose movement in ms */

/* Following are program constants, do not modify !!! */
#define INIT_DELAY            1000

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

Servo servoEyesHorizontal;
Servo servoEyesVertical;
Servo servoRightEyelid;
Servo servoLeftEyelid;
Servo servoArm;
Servo servoEyebrow;
Servo servoNose;
Servo servoMouth;

const char* ssid = "loutkaAP";
const char* password = "LoutkaAP1234#";

IPAddress local_IP(192, 168, 0, 1);
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);

WiFiServer server(SERVER_PORT);
WiFiClient client;
bool clientConnected = false;
bool blinkEnabled = false;
bool blinkTimeRecorded = false;
bool blinkDone = false;

uint32_t blinkFlag = 0;
uint32_t blinkNow = 0;

bool autoBlinkStarted = false;
bool autoBlinkOn = false;
uint32_t autoBlinkFlag = 0;
uint32_t autoBlinkNow = 0;

uint32_t noseFlag = 0;
uint32_t noseNow = 0;
bool noseTrigger = false;
bool noseFirst = false;

struct Data {
  bool armButton = 0;
  bool blinkButton = 0;
  bool excitementButton = 0;
  bool noseButton = 0;
  bool angerButton = 0;
  bool surpriceButton = 0;
  uint8_t joyLeft = 0;
  uint8_t joyRight = 0;
  uint8_t joyForward = 0;
  uint8_t joyRear = 0;
  uint8_t potMouth = 0;
};

struct ActualAngles {
  uint8_t armAngle = 0;
  uint8_t eyesHorizontalAngle = 0;
  uint8_t eyesVerticalAngle = 0;
  uint8_t leftEyelid = 0;
  uint8_t rightEyelid = 0;
  uint8_t noseAngle = 0;
  uint8_t eyebrowAngle = 0;
  uint8_t mouthAngle = 0;
};

Data data;
ActualAngles actualAngles;

uint8_t rxBuffer[DATA_LENGTH];
uint32_t tFlag = 0;
uint32_t now = 0;

void serverBegin();
void serverRoutine();
void processIncomingData();

void armRoutine();
void eyelidRoutine();
void noseRoutine();
void eyebrowRoutine();
void eyesRoutine();
void mouthRoutine();

void updateAngles();
void blinkHandler();
void autoBlinkRoutine();

void servosBegin();
void servosRoutine();
uint8_t countServoStep(uint8_t numOfSteps, uint8_t minAngle, uint8_t maxAngle);

void serverBegin() {
  Serial.print("AP CONFIG... ");
  Serial.println(WiFi.softAPConfig(local_IP, gateway, subnet) ? "OK" : "NOK");

  Serial.print("SETTING AP SSID and PWD... ");
  Serial.println(WiFi.softAP(ssid, password) ? "OK" : "NOK");

  Serial.print("AP IP ADDRESS: ");
  Serial.println(WiFi.softAPIP());

  server.begin();
}

void serverRoutine() {
  if (client.connected()) {
    if (!clientConnected) {
      clientConnected = true;
      client.setTimeout(CLIENT_TOUT);
      client.keepAlive(KEEP_ALIVE_T, 75, 2);
    }
    uint16_t avail = client.available();
    if (avail > 0) {
      Serial.println(avail);
      memset(rxBuffer, 0, DATA_LENGTH);
      client.readBytes(rxBuffer, DATA_LENGTH);
      tFlag = millis();
      processIncomingData();
      servosRoutine();
    }
    else {
      now = millis();
      if (now - tFlag > CLIENT_TOUT) {
        if (clientConnected) {
          clientConnected = false;
          client.stop();
          Serial.println("CONNECTION TO CLIENT LOST");
        }
      }
    }
  }
  else {
    client = server.available();
    if (client.connected()) {
      Serial.println("CONNECTION TO CLIENT ESTABLISHED");
      tFlag = millis();
    }
  }
}

void processIncomingData() {
  data.armButton = rxBuffer[0];
  data.blinkButton = rxBuffer[1];
  data.excitementButton = rxBuffer[2];
  data.noseButton = rxBuffer[3];
  data.angerButton = rxBuffer[4];
  data.surpriceButton = rxBuffer[5];
  data.joyLeft = rxBuffer[6];
  data.joyRight = rxBuffer[7];
  data.joyForward = rxBuffer[8];
  data.joyRear = rxBuffer[9];
  data.potMouth = rxBuffer[10];

  armRoutine();
  eyelidRoutine();
  noseRoutine();
  eyebrowRoutine();
  eyesRoutine();
  mouthRoutine();
}

void armRoutine() {
  //arm handling – hold arm button
  (data.armButton) ? actualAngles.armAngle = ARM_MIN : actualAngles.armAngle = ARM_MAX;
}

void eyelidRoutine() {
  if (data.excitementButton) {
    actualAngles.rightEyelid = R_EYELID_EXCITEMENT;
    actualAngles.leftEyelid = L_EYELID_EXCITEMENT;
  }
  else if (data.angerButton) {
    actualAngles.rightEyelid = R_EYELID_ANGER;
    actualAngles.leftEyelid = L_EYELID_ANGER;
  }
  else if (data.surpriceButton) {
    actualAngles.rightEyelid = R_EYELID_SURPRICE;
    actualAngles.leftEyelid = L_EYELID_SURPRICE;
  }
  else {
    actualAngles.rightEyelid = R_EYELID_NORMAL;
    actualAngles.leftEyelid = L_EYELID_NORMAL;
  }
  //right eye blink – joystick button
  if (data.blinkButton && !blinkDone && actualAngles.rightEyelid == R_EYELID_NORMAL) {
    blinkEnabled = true;
  }
  else if (!data.blinkButton && blinkDone) {
    blinkDone = false;
  }
  //auto blink – triggers both eyelids
  autoBlinkRoutine();
  //control right eye blink and full blink (auto blink)
  blinkHandler();
}

void noseRoutine() {
  //nose handling – hold nose button
  if (data.noseButton) {
    if (!noseTrigger) {
      noseTrigger = true;
      noseFlag = millis();
    }
    noseNow = millis();
    if (noseNow - noseFlag > NOSE_T || noseFirst != true) {
      noseFirst = true;
      if (actualAngles.noseAngle == NOSE_RIGHT) {
        actualAngles.noseAngle = NOSE_LEFT;
      }
      else {
        actualAngles.noseAngle = NOSE_RIGHT;
      }
      noseTrigger = false;
    }
  }
  else {
    actualAngles.noseAngle = NOSE_NORMAL;
    noseTrigger = false;
    noseFirst = false;
  }
}

void eyebrowRoutine() {
  if (data.excitementButton) {
    actualAngles.eyebrowAngle = EYEBROW_UP;
  }
  else if (data.angerButton) {
    actualAngles.eyebrowAngle = EYEBROW_DOWN;
  }
  else {
    actualAngles.eyebrowAngle = EYEBROW_NORMAL;
  }
}

void eyesRoutine() {
  uint8_t horizontalAngle = 0;
  uint8_t verticalAngle = 0;

  //horizontal eye movement
  (data.joyLeft >= data.joyRight) ? horizontalAngle = map(data.joyLeft, 255, 0, EYE_HORIZONTAL_LEFT, EYE_HORIZONTAL_CNT)
      : horizontalAngle = map(data.joyRight, 0, 255, EYE_HORIZONTAL_CNT, EYE_HORIZONTAL_RIGHT);

  //this condition makes servo movement binary (bad sensitivity of a actaul joystick)
  //code is prapred for non binary version
  if (horizontalAngle > EYE_HORIZONTAL_CNT + EYE_SERVO_OFFSET) {
    actualAngles.eyesHorizontalAngle = EYE_HORIZONTAL_RIGHT;
  }
  else if (horizontalAngle < EYE_HORIZONTAL_CNT - EYE_SERVO_OFFSET) {
    actualAngles.eyesHorizontalAngle = EYE_HORIZONTAL_LEFT;
  }
  else {
    actualAngles.eyesHorizontalAngle = EYE_HORIZONTAL_CNT;
  }

  //vertival eye movement
  (data.joyRear >= data.joyForward) ? verticalAngle = map(data.joyRear, 255, 0, EYE_VERTICAL_DOWN, EYE_VERTICAL_CNT)
      : verticalAngle = map(data.joyForward, 0, 255, EYE_VERTICAL_CNT, EYE_VERTICAL_UP);

  //this condition makes servo movement binary (bad sensitivity of a actaul joystick)
  //code is prapred for non binary version
  if (verticalAngle > EYE_VERTICAL_CNT + EYE_SERVO_OFFSET) {
    actualAngles.eyesVerticalAngle = EYE_VERTICAL_UP;
  }
  else if (verticalAngle < EYE_VERTICAL_CNT - EYE_SERVO_OFFSET) {
    actualAngles.eyesVerticalAngle = EYE_VERTICAL_DOWN;
  }
  else {
    actualAngles.eyesVerticalAngle = EYE_VERTICAL_CNT;
  }
}

void mouthRoutine() {
  actualAngles.mouthAngle = map(data.potMouth, 0, 255, MOUTH_MIN, MOUTH_MAX);
}


void blinkHandler() {
  if (actualAngles.rightEyelid == R_EYELID_BLINK && !blinkTimeRecorded) {
    blinkEnabled = false;
  }
  if (blinkEnabled) {
    if (!blinkTimeRecorded) {
      blinkTimeRecorded = true;
      blinkFlag = millis();
    }
    actualAngles.rightEyelid = R_EYELID_BLINK;
    if (autoBlinkOn) {
      actualAngles.leftEyelid = L_EYELID_BLINK;
    }
    blinkNow = millis();
    if (blinkNow - blinkFlag > BLINK_T) {
      blinkEnabled = false;
      blinkTimeRecorded = false;
      blinkDone = true;
      actualAngles.rightEyelid = R_EYELID_NORMAL;
      if (autoBlinkOn) {
        actualAngles.leftEyelid = L_EYELID_NORMAL;
        autoBlinkOn = false;
      }
    }
  }
}

void autoBlinkRoutine() {
  if (!autoBlinkStarted) {
    autoBlinkFlag = millis();
    autoBlinkStarted = true;
  }
  if (autoBlinkStarted) {
    autoBlinkNow = millis();
    if (autoBlinkNow - autoBlinkFlag > AUTO_BLINK_T) {
      if (actualAngles.leftEyelid == L_EYELID_NORMAL && actualAngles.rightEyelid == L_EYELID_NORMAL) {
        autoBlinkOn = true;
        blinkEnabled = true;
      }
      autoBlinkStarted = false;
    }
  }
}

void servosBegin() {
  Serial.println("SETTING SERVOS TO BASE POSITION");
  servoEyesHorizontal.attach(SERVO_EYES_HOR_PIN);
  servoEyesVertical.attach(SERVO_EYES_VER_PIN);
  servoRightEyelid.attach(SERVO_REYELID_PIN);
  servoLeftEyelid.attach(SERVO_LEYELID_PIN);
  servoArm.attach(SERVO_ARM_PIN);
  servoEyebrow.attach(SERVO_EYEBROW_PIN);
  servoNose.attach(SERVO_NOSE_PIN);
  servoMouth.attach(SERVO_MOUTH_PIN);
  delay(INIT_DELAY);

  Serial.println("SERVOS READY");
}

void servosRoutine() {
  servoEyesHorizontal.write(actualAngles.eyesHorizontalAngle);
  servoEyesVertical.write(actualAngles.eyesVerticalAngle);
  servoRightEyelid.write(actualAngles.rightEyelid);
  servoLeftEyelid.write(actualAngles.leftEyelid);
  servoArm.write(actualAngles.armAngle);
  servoEyebrow.write(actualAngles.eyebrowAngle);
  servoNose.write(actualAngles.noseAngle);
  servoMouth.write(actualAngles.mouthAngle);
}

void setup() {
  // initialize serial communication
#ifdef SERIAL_DEBUG_OUT
  Serial.begin(SERIAL_BAUDRATE);
  delay(1);
  Serial.println(F("ESP Server - Loutky.cz"));
  Serial.println(F("Version 3.0"));
  Serial.println(F("Developed by Arduino development"));
  Serial.println(F("development.arduino-shop.cz"));
  Serial.println();
#endif

  serverBegin();
  servosBegin();
  Serial.println("WAITING FOR CLIENT CONNECTION");
}

void loop() {
  serverRoutine();
}

// #ifdef SERIAL_DEBUG_OUT
//
// #endif

/**
  @brief
  @param
  @retval
*/
/**
******************************************************************************
  @author    Arduino development
  @version  3.0
  @date     21.09.2020
  @brief    ESP Client - Loutky.cz

*/

#define SERIAL_DEBUG_OUT
#define SERIAL_BAUDRATE     115200

#define SERVER_PORT         80

#define DEBOUNCE_TICKS      20
#define DATA_LENGTH         11

#define ANALOG_X            0
#define ANALOG_Y            1

#define CONNECTION_LED      16

//pinout same as here: https://docs.wemos.cc/en/latest/d1/d1_mini.html
#define ARM_BUTTON_PIN      0  //D3
#define BLINK_BUTTON_PIN    2  //D4
#define MOUTH_POT_PIN       A0 //A0

/* keypad definitions */
#define BUTTON_1            '1'
#define BUTTON_2            '2'
#define BUTTON_3            '3'
#define BUTTON_4            '4'

#define T_KEY_DEBOUNCE      20  //ms
#define T_KEY_HOLD          500 //ms

#define NO_KEY_PRESSED      '\000'

#define N_KEYPAD_ROWS       2
#define N_KEYPAD_COLS       2

#define PIN_COL_1           15  //D8
#define PIN_COL_2           13  //D7

#define PIN_ROW_1           14  //D5
#define PIN_ROW_2           12  //D6

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ObjectButton.h>
#include <interfaces/IOnPressListener.h>
#include <Adafruit_ADS1X15.h>
#include <Wire.h>
#include <Keypad.h>

const char* ssid = "loutkaAP";
const char* password = "LoutkaAP1234#";

char keyMap[N_KEYPAD_ROWS][N_KEYPAD_COLS] = {
  {BUTTON_1, BUTTON_2},
  {BUTTON_3, BUTTON_4},
};

uint8_t rowPins[N_KEYPAD_ROWS] = {PIN_ROW_1, PIN_ROW_2};
uint8_t colPins[N_KEYPAD_COLS] = {PIN_COL_1, PIN_COL_2};

Keypad keypad = Keypad(makeKeymap(keyMap), rowPins, colPins, N_KEYPAD_ROWS, N_KEYPAD_COLS);

struct DataOutput {
  bool armButton = 0;
  bool blinkButton = 0;
  bool excitementButton = 0;
  bool noseButton = 0;
  bool angerButton = 0;
  bool surpriceButton = 0;
  uint8_t joyLeft = 0;
  uint8_t joyRight = 0;
  uint8_t joyForward = 0;
  uint8_t joyRear = 0;
  uint8_t potMouth = 0;
};

uint16_t anValX;
uint16_t anValY;
uint16_t anValXCnt;
uint16_t anValYCnt;

uint8_t txBuffer[DATA_LENGTH];

DataOutput dataOut;

IPAddress server(192, 168, 0, 1);
WiFiClient client;

Adafruit_ADS1115 adConverter;

void adConverterBegin();
void clientBegin();
void connectToAP();
void connectToServer();
void clientRoutine();
void readPeripherals();
void joystickReading();
void potentiometrReading();
void keypadReading();
void processKeypadData(bool state, char key);
void processJoystickData();
void sendData();

class Buttons : private virtual IOnPressListener {
  public:
    Buttons() = default;

    void init();

    void update();

  private:

    void onPress(ObjectButton &button) override;

    void onRelease(ObjectButton &button) override;

    void onLongPressStart(ObjectButton &button) override {};

    void onLongPressEnd(ObjectButton &button) override {};

    ObjectButton armButtonObj = ObjectButton(ARM_BUTTON_PIN, true);
    ObjectButton blinkButtonObj = ObjectButton(BLINK_BUTTON_PIN, true);
};

void Buttons::onPress(ObjectButton &button) {
  switch (button.getId()) {
    case ARM_BUTTON_PIN:
      dataOut.armButton = true;
      break;
    case BLINK_BUTTON_PIN:
      dataOut.blinkButton = true;
      break;
  }
}

void Buttons::onRelease(ObjectButton &button) {
  switch (button.getId()) {
    case ARM_BUTTON_PIN:
      dataOut.armButton = false;
      break;
    case BLINK_BUTTON_PIN:
      dataOut.blinkButton = false;
      break;
  }
}

void Buttons::init() {
  armButtonObj.setDebounceTicks(DEBOUNCE_TICKS);
  armButtonObj.setOnPressListener(this);
  blinkButtonObj.setDebounceTicks(DEBOUNCE_TICKS);
  blinkButtonObj.setOnPressListener(this);
}

void Buttons::update() {
  armButtonObj.tick();
  blinkButtonObj.tick();
}

// buttons instance
Buttons *buttons;

void adConverterBegin() {
  // ads.setGain(GAIN_TWOTHIRDS);  // 2/3x gain +/- 6.144V  1 bit = 3mV      0.1875mV (default)
  adConverter.setGain(GAIN_ONE);        // 1x gain   +/- 4.096V  1 bit = 2mV      0.125mV
  // ads.setGain(GAIN_TWO);        // 2x gain   +/- 2.048V  1 bit = 1mV      0.0625mV
  // ads.setGain(GAIN_FOUR);       // 4x gain   +/- 1.024V  1 bit = 0.5mV    0.03125mV
  // ads.setGain(GAIN_EIGHT);      // 8x gain   +/- 0.512V  1 bit = 0.25mV   0.015625mV
  // ads.setGain(GAIN_SIXTEEN);    // 16x gain  +/- 0.256V  1 bit = 0.125mV  0.0078125mV
  adConverter.begin();

  anValYCnt = adConverter.readADC_SingleEnded(ANALOG_Y);
  anValXCnt = adConverter.readADC_SingleEnded(ANALOG_X);

  //if GAIN_ONE set, DA range is 0 – 65536
  anValYCnt = map(anValYCnt, 0, 65536, 0, 255);
  anValXCnt = map(anValXCnt, 0, 65536, 0, 255);
}

void clientBegin() {
  connectToAP();
  connectToServer();
}

void connectToAP() {
  WiFi.begin(ssid, password);
  Serial.println("CONNECTING TO AP");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(200);
    digitalWrite(CONNECTION_LED, HIGH);
    delay(20);
  }
  Serial.println("\nAP CONNECTION ESTABLISHED");
}

void connectToServer() {
  Serial.println("CONNECTING TO SERVER");
  while (!client.connect(server, SERVER_PORT)) {
    Serial.print(".");
    delay(200);
    digitalWrite(CONNECTION_LED, HIGH);
    delay(20);
  }
  digitalWrite(CONNECTION_LED, LOW);
  delay(20);
  Serial.println("\nSERVER CONNECTION ESTABLISHED");
}

void clientRoutine() {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("CONNECTION WITH SERVER LOST");
    clientBegin();
  }
  readPeripherals();
  sendData();
}

void readPeripherals() {
  //joystick
  joystickReading();
  processJoystickData();
  //potentiometr
  potentiometrReading();
  //keypad
  keypadReading();
}

void joystickReading() {
  anValY = adConverter.readADC_SingleEnded(ANALOG_Y);
  anValX = adConverter.readADC_SingleEnded(ANALOG_X);

  anValY = map(anValY, 0, 65536, 0, 255);
  anValX = map(anValX, 0, 65536, 0, 255);
}

void potentiometrReading() {
  uint16_t anMouthVal = analogRead(MOUTH_POT_PIN);
  dataOut.potMouth = map(anMouthVal, 0, 1023, 0, 255);
}

void keypadReading() {
  if (keypad.getKeys()) {
    for (uint8_t i = 0; i < N_KEYPAD_ROWS * N_KEYPAD_COLS ; i++) {
      if (keypad.key[i].stateChanged) {
        switch (keypad.key[i].kstate) {
          case PRESSED:
            processKeypadData(true, keypad.key[i].kchar);
            break;
          case RELEASED:
            processKeypadData(false, keypad.key[i].kchar);
            break;
          default:
            break;
        }
      }
    }
  }
}

void processKeypadData(bool state, char key) {
  switch (key) {
    case '1':
      (state) ? dataOut.excitementButton = true : dataOut.excitementButton = false;
      dataOut.noseButton = false;
      dataOut.angerButton = false;
      dataOut.surpriceButton = false;
      break;
    case '2':
      dataOut.excitementButton = false;
      (state) ? dataOut.noseButton = true : dataOut.noseButton = false;
      dataOut.angerButton = false;
      dataOut.surpriceButton = false;
      break;
    case '3':
      dataOut.excitementButton = false;
      dataOut.noseButton = false;
      (state) ? dataOut.angerButton = true : dataOut.angerButton = false;
      dataOut.surpriceButton = false;
      break;
    case '4':
      dataOut.excitementButton = false;
      dataOut.noseButton = false;
      dataOut.angerButton = false;
      (state) ? dataOut.surpriceButton = true : dataOut.surpriceButton = false;
      break;
  }
}

void processJoystickData() {
  if (anValY <= anValYCnt) {
    dataOut.joyRear = map(anValY, anValYCnt, 0, 0, 255);
    dataOut.joyForward = 0;
  }
  else {
    dataOut.joyForward = map(anValY, anValYCnt, 127, 0, 255);
    dataOut.joyRear = 0;
  }

  if (anValX <= anValXCnt) {
    dataOut.joyLeft = map(anValX, anValXCnt, 0, 0, 255);
    dataOut.joyRight = 0;
  }
  else {
    dataOut.joyRight = map(anValX, anValXCnt, 127, 0, 255);
    if (dataOut.joyRight < 150) {
      dataOut.joyRight = 0;
    }
    dataOut.joyLeft = 0;
  }
}

void sendData() {
  memset(txBuffer, 0, DATA_LENGTH);
  txBuffer[0] = dataOut.armButton;
  txBuffer[1] = dataOut.blinkButton;
  txBuffer[2] = dataOut.excitementButton;
  txBuffer[3] = dataOut.noseButton;
  txBuffer[4] = dataOut.angerButton;
  txBuffer[5] = dataOut.surpriceButton;
  txBuffer[6] = dataOut.joyLeft;
  txBuffer[7] = dataOut.joyRight;
  txBuffer[8] = dataOut.joyForward;
  txBuffer[9] = dataOut.joyRear;
  txBuffer[10] = dataOut.potMouth;

  if (client.connected() != 0) {
    client.write(txBuffer, DATA_LENGTH);
    client.flush(); //waits for the transmission of outgoing serial data to complete
  }
  else {
    if (WiFi.isConnected() != WL_CONNECTED) {
      connectToAP();
    }
    connectToServer();
  }
}

void setup() {
  // initialize serial communication
#ifdef SERIAL_DEBUG_OUT
  Serial.begin(SERIAL_BAUDRATE);
  delay(1);
  Serial.println(F("ESP Client - Loutky.cz"));
  Serial.println(F("Version 3.0"));
  Serial.println(F("Developed by Arduino development"));
  Serial.println(F("development.arduino-shop.cz"));
  Serial.println();
#endif

  pinMode(CONNECTION_LED, OUTPUT);
  digitalWrite(CONNECTION_LED, HIGH);
  pinMode(MOUTH_POT_PIN, INPUT);
  delay(20);

  //client setting
  clientBegin();

  //ad converter setting
  adConverterBegin();

  //object button setting
  buttons = new Buttons();
  buttons->init();

  //keypad setting
  keypad.setDebounceTime(T_KEY_DEBOUNCE);
  keypad.setHoldTime(T_KEY_HOLD);
}

void loop() {
  buttons->update();
  clientRoutine();
}

// #ifdef SERIAL_DEBUG_OUT
//
// #endif

/**
  @brief
  @param
  @retval
*/

Hi,
Welcome to the forum.

To add code please click this link;

Thanks... Tom. :smiley: :+1: :coffee: :australia:

Cheers.
Petr