Arduino servomotor "wont work"

I am doing a project for my university, i made the code and it worked perfectly in tinkercad but when i sent them the code they reported that "after pressing A it woudlnt go back" or "it looks like its stuck trying to go to 180 degrees" so i was wondering if something was wrong with my code.

#include <Servo.h> //Libreria
Servo servo2; // objeto servomotor
Servo servo3;
Servo servo4;
Servo servo5;
Servo servo6;
const int led1 = 7; //Los ojos
const int piezo = 8; //Buzzer
const int pump = 9; //Bomba de agua
int angulo=0; //angulo de los motores
//30,45,60,90,120,135,150,180 grados


void setup(){
  Serial.begin(9600);
  servo2.attach(2); //la senal pwm se genera en el pin 2
  servo3.attach(3); //la senal pwm se genera en el pin 3
  servo4.attach(4); //la senal pwm se genera en el pin 4
  servo5.attach(5); //la senal pwm se genera en el pin 5
  servo6.attach(6); //la senal pwm se genera en el pin 6
  pinMode(piezo, OUTPUT); 
}

void loop () {
  servo2.write(90);
  servo3.write(90);
  servo4.write(90);
  servo5.write(90);
  servo6.write(90);
  digitalWrite(led1,HIGH);
  digitalWrite(pump,LOW);
  
  char x = Serial.read();
  
  if (x == 'A'){//MOver patas frontales a la derecha
    servo2.write(180);
    servo3.write(180);
    delay(300);
    servo2.write(30);
    servo3.write(30);
    delay(600);
  }
  if (x == 'B'){ //MOver patas frontales a la izquierda
    servo2.write(30);
    servo3.write(30);
    delay(300);
    servo2.write(180);
    servo3.write(180);
    delay(600);
  }
  
  if (x == 'C'){ //MOver patas traseras a la derecha
    servo4.write(180);
    servo5.write(180);
    delay(300);
    servo4.write(30);
    servo5.write(30);
    delay(600);
  }
  if (x == 'D'){ //MOver patas traseras a la izquierda
    servo4.write(30);
    servo5.write(30);
    delay(300);
    servo4.write(180);
    servo5.write(180);
    delay(600);
  }
  if (x == 'E'){ //MOver la cola
    servo6.write(30);
    delay(300);
    servo6.write(180);
    delay(600);
    servo6.write(30);
    delay(900);
    servo6.write(120);
    delay(1100);
  }
  if (x == 'F'){ // Apaga sus ojos
 	digitalWrite(led1,LOW);
    delay(500);
    digitalWrite(led1,HIGH);
    delay(500);
    digitalWrite(led1,LOW);
 }
  if (x == 'H'){//agacharse(en caso de error inviertan los angulos)
    servo2.write(130);
    servo3.write(45);
    servo4.write(130);
    servo5.write(45);
    delay(1000);
  }
  if (x == 'I'){//Ladrar
    tone(piezo,261.63,200); //Do durante 0,1 s
 	delay(100);
    tone(piezo,293.66,200); //Do durante 0,1 s
 	delay(100);
  }
  if (x == 'L'){//Bomba de agua
    digitalWrite(pump,HIGH);
    delay(500);
  }
}

Thanks in advance for any help

Never power motors from the Arduino 5V pin !


char x = Serial.read();

Only read a character when you detect there is one to read.

In real life your circuit would not work because the servos take way more current than you can get from an Arduino 5V pin. The USB can only supply up to 500mA and each individual servo needs at least an amp capacity to handle switch on surges. Also you have no decoupling capacitors on these servos.

I don't use tinkercad or any other sort of emulator.

Who are the "they" that you speak of?

Hi, I understand how to install capacitors but how do i fix the only read characters when you detect there is one to read?

Hi, thanks for your response. "they" are my project group. Also which kind of battery should i use to power the circuit?

So ask them why they say that, because apart from the your incorrect use of the serial read the only thing that would stop it from not returning would be that the delay you give it to move to the required position is not long enough.

It depends on how long you want it to run before you have to have new batteries or recharge the ones you have.

There is a call that shows you how many bytes are waiting to be read.
See
Arduino Serial
and
serial available

A servo motor like the one in the pic can draw up to 800mA of current. I round that to 1 amp per servo. Just to run the servos you'll need 5+ amps available.

Running that much power through a breadboard will not work out well. I build my own servo power distribution boards. If you cannot do such I recommend using a power distribution board of some sort.




to provide power to the servos. Connect the servo power ground to the MCU's ground.

Use the Serial.available() function. If it returns a value of 0 then there is no serial data to read so don't do it

void fReceiveSerial_LIDAR( void * parameters  )
{
  char OneChar;
  char *str;
  str = (char *)ps_calloc(300, sizeof(char) ); // put str buffer into PSRAM
  bool BeginSentence = false;
  sSerial.reserve ( StringBufferSize300 );
  for ( ;; )
  {
    EventBits_t xbit = xEventGroupWaitBits (eg, evtReceiveSerial_LIDAR, pdTRUE, pdTRUE, portMAX_DELAY);
    if ( LIDARSerial.available() >= 1 )
    {
      while ( LIDARSerial.available() )
      {
        OneChar = LIDARSerial.read();
        if ( BeginSentence )
        {
          if ( OneChar == ‘>’)
          {
            if ( xSemaphoreTake( sema_ParseLIDAR_ReceivedSerial, xSemaphoreTicksToWait10 ) == pdTRUE )
            {
              xQueueOverwrite( xQ_LIDAR_Display_INFO, ( void * ) &sSerial );
              xEventGroupSetBits( eg, evtParseLIDAR_ReceivedSerial );
              //
            }
            BeginSentence = false;
            break;
          }
          sSerial.concat ( OneChar );
        }
        else
        {
          if ( OneChar == ‘<’ )
          {
            sSerial = “”; // clear string buffer
            BeginSentence = true; // found begining of sentence
          }
        }
      } //  while ( LIDARSerial.available() )
    } //if ( LIDARSerial.available() >= 1 )
    xSemaphoreGive( sema_ReceiveSerial_LIDAR );
  }
  vTaskDelete( NULL );
} //void fReceiveSerial_LIDAR( void * parameters  )

I use if ( LIDARSerial.available() >= 1 ) to check if 1 byte is available before the code enters a loop to collect the serial data.

often if ( LIDARSerial.available() > 0 ) is used instead of a 1.

not sure this will answer your question

the following will always return all your servos to 90deg. shouldn't this only be done once in setup()

there is a read regardless of whether there is anything available. shouldn't this be done after checking if (Serial.available()) { as well as the processing of any received char

you could just do to skip any processing until there is serial input

void
loop (void) {
    if ( ! Serial.available ())
        return;
    ...

Thanks, ill move the servo.writes to the setup. also should i just drop

if ( ! Serial.available ())
        return;

under loop (void) and then i drop all of my code under it?

yes ,
hopefully it's clear that this is somewhat simpler than putting all that code inside the if (Serial.available()) condition (or possibly in a sub-function)

Alright, i placed the servowrites on te setup and placed my code under the !serial.aviable and it works and although i need to return the servomotors to the neutral pose (90) in all of my functions i think this is way more stable and better.

Thanks.

so in the code below, 30 deg is not the final position?

No i made it so its like this now

if (x == 'A'){//MOver patas frontales a la derecha
    servo2.write(180);
    servo3.write(180);
    delay(300);
    servo2.write(30);
    servo3.write(30);
    delay(600);
    servo2.write(90);
    servo3.write(90);
    delay(700);
  }

btw would you happen to know a good battery we can use to power the circuit up? i dont think the usb alone is going to cut it.

The original use of Serial.read() is fine. The 0xFFFF returned when the buffer is empty will get truncated to 0xFF when saved in 'x' and that will not match any of the letters being tested for. The loop() will repeat. There is very little advantage to either checking Serial.available() or explicitly checking the value returned by Serial.read() for -1.

hi, thanks for your response. so should i just leave it as it is?

You can. Or you can add code to make it clear you know that Serial.read() will return -1 if the buffer is empty. Something like:

  if (!Serial.available())
    return;

just before "char x = Serial.read();"

yeah @gcjr suggested that i should do that. Thanks