Servo sg90 suena y no responde

Estimados soy nuevo en el foro, y me gustaría el apoyo de la comunidad en un problema técnico, que no logro ver.

Estoy realizando un programa que recibe señales de dos sensores FSR (A0, A1) y en base a estos valores activa un mensaje en pantalla, enciende led y asocia el movimiento de tres servos según valores dados.

Los servos son SG90 conectados a una fuente e poder externa de 5 volt regulada (GND compartido) , el problema es que cuando corro el programa la lectura de los sensores esta OK, los mensajes en pantalla funcionan OK, pero los servos suenan y no se mueven.
Cuando cargo un programa solo para los servos con rotación de 60 grados de 10° en 10° , funciona en todos los servos al mismo tiempo.

En el programa no uso delay para no parar el proceso de captura de datos , la pantalla y los mensajes de ella están siendo ejecutados por el protocolo I2C y arduino solo controla los servos por los puertos 9, 10 y 11.

La verdad he cambiado las líneas y he chequeado el voltaje en todos los componentes y todo esta OK.

el código es:

#include <Servo.h>
#include<Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); // dependiendo del fabricante del LCD el codigo 0x27 puede cambiar
 
int fsrAnalog1 =A0; 
int fsrAnalog2 =A1; 
int fsrReading1; 
int fsrReading2; 
int rojo = 3; 
int verde = 4; 
int amarillo= 6; 
int rojo2 = 5; 
int ang;

Servo servo1;
Servo servo2;
Servo servo3;

/// declaración tipos de caras en  pantalla ///

byte chartriste1 [8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000

};

byte chartriste2 [8] = {
B00000,
B01110,
B10111,
B10111,
B11111,
B11111,
B01110,
B00000

};

byte chartriste3 [8] = {
B00000,
B01110,
B10111,
B10111,
B11111,
B11111,
B01110,
B00000

};

byte chartriste4 [8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000

};

byte chartriste5 [8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00001,
B00001,
B00000

};

byte chartriste6 [8] = {
B00000,
B00000,
B00111,
B01111,
B11000,
B10000,
B00000,
B00000

};

byte chartriste7 [8] = {
B00000,
B00000,
B11100,
B11110,
B00011,
B00001,
B00000,
B00000

};

byte chartriste8 [8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B10000,
B10000,
B00000

};


/// todo_bien///


byte charcara1 [8] = {
B00000,
B00000,
B00001,
B00000,
B00000,
B00000,
B00000,
B00000
};

byte charcara2 [8] = {
B00000,
B11110,
B00000,
B00000,
B00110,
B00110,
B00110,
B00000
};

byte charcara3 [8] = {
B00000,
B01111,
B00000,
B00000,
B01100,
B01100,
B01100,
B00000
};

byte charcara4 [8] = {
B00000,
B00000,
B10000,
B00000,
B00000,
B00000,
B00000,
B00000
};

byte charcara5 [8] = {
B00001,
B00001,
B00001,
B00000,
B00000,
B00000,
B00000,
B00000
};

byte charcara6 [8] = {
B00000,
B00000,
B10000,
B11111,
B00111,
B00000,
B00000,
B00000
};

byte charcara7 [8] = {
B00000,
B00000,
B00001,
B11111,
B11100,
B00000,
B00000,
B00000
};

byte charcara8 [8] = {
B10000,
B10000,
B10000,
B00000,
B00000,
B00000,
B00000,
B00000
};
                                  
  //// inicio  programa lectura , seteo  de las condiciones ///                                                          
                                  
void setup() {
  Serial.begin(9600);
  servo1. attach(9);
  servo2. attach(10);
  servo3. attach(11);
  pinMode(rojo, OUTPUT); 
  pinMode(verde, OUTPUT); 
  pinMode (amarillo, OUTPUT);
  pinMode (rojo2, OUTPUT);

 servo1.write(0);
 servo2.write(0);
 servo3.write(0);
  
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.begin(16,2); // configuramos el LCD de 16x2
  for(int i = 0; i<4; i++){
  }
  
  }


/// PANTALLAS DE EXPRESIÓN 
///  DOLOR      ///  
///  TODO BIEN  ///

void me_duele(){  // f(x)  expreión dolor //

  for(int i = 0 ; i <= 8; i++ ){
  lcd.createChar(1,chartriste1);
  lcd.createChar(2,chartriste2);
  lcd.createChar(3,chartriste3);
  lcd.createChar(4,chartriste4);
  lcd.createChar(5,chartriste5);
  lcd.createChar(6,chartriste6);
  lcd.createChar(7,chartriste7);
  lcd.createChar(8,chartriste8);
  lcd.setCursor(3,0);
  lcd.write(1);
  lcd.write(2);
  lcd.write(3);
  lcd.write(4);
  lcd.setCursor(3,1);
  lcd.write(5);
  lcd.write(6);
  lcd.write(7);
  lcd.write(8);
  lcd.setCursor(8,0);
  lcd.print("ME");
  lcd.setCursor(8,1);
  lcd.print("DUELE"); } 
}

void todo_bien(){ // f(x)  PACIENTE NORMAL //

for(int i = 0 ; i <= 8; i++ ){
  lcd.createChar(1,charcara1);
  lcd.createChar(2,charcara2);
  lcd.createChar(3,charcara3);
  lcd.createChar(4,charcara4);
  lcd.createChar(5,charcara5);
  lcd.createChar(6,charcara6);
  lcd.createChar(7,charcara7);
  lcd.createChar(8,charcara8);
  
  lcd.setCursor(3,0);
  lcd.write(1);
  lcd.write(2);
  lcd.write(3);
  lcd.write(4);

  lcd.setCursor(3,1);
  lcd.write(5);
  lcd.write(6);
  lcd.write(7);
  lcd.write(8);
  
     lcd.setCursor(8,0);
     lcd.print("TODO ");
     lcd.setCursor(8,1);
     lcd.print("BIEN");
  
}
}


void dolor(){
 servo1.write(120);
 servo2.write(120);
 servo3.write(120);
 
 servo1.write(0);
 servo2.write(0);
 servo3.write(0);
}



void molesto(){
 
    digitalWrite (amarillo, LOW);
    digitalWrite (rojo2, HIGH);
 servo1.write(45);
 servo2.write(45);
 servo3.write(45);
 
 servo1.write(0);
 servo2.write(0);
 servo3.write(0);
}

void alerta(){
  digitalWrite ( amarillo, HIGH);
  digitalWrite (rojo2, LOW);
}

/// LECTURA DE PROCESADOR ///

void loop(){

fsrReading1 = analogRead(fsrAnalog1); // vena
fsrReading2 = analogRead(fsrAnalog2); // tacto

Serial.print("dato 1 = ");
Serial.println(fsrReading1 );
 
Serial.print("dato 2 = ");
Serial.println(fsrReading2);


/// CONDICONES ///


if (fsrReading1 > 200 && fsrReading1 < 500){ 
me_duele();
dolor();
digitalWrite (rojo, HIGH);
digitalWrite (verde, LOW);

     }

else {
  digitalWrite(rojo,LOW);
  digitalWrite (verde, HIGH);
  lcd.clear();
  todo_bien();
     }

if (fsrReading2 > 20 && fsrReading2 < 300 ){
    alerta();
     }
 
else{
    digitalWrite( amarillo, LOW);
    }
    
if (fsrReading2 > 300 && fsrReading2 <400 ){
    molesto();
     }

else {
  digitalWrite (rojo2,LOW);
  lcd.clear();
     }
}


Si me puedan ayudar se los agradecería.

Su publicacion se MUEVE a su ubicacion actual ya que es mas adecuada.

Sube el código (lee en Normas del foro, punto 7, la forma correcta de hacerlo) porque sin verlo sería ponernos a adivinar.

Saludos

código cargado, mis disculpas.
Saludos

No le das tiempo para que los servos se muevan y ya los vuelves a 0.
Ahí está el problema.

Vuelve a revisar los ejemplos y/o lee la documentación de la librería para ver como manejar los tiempos.

Saludos

Cargado pero mal posteado. Lee las normas y usa etiquetas.

Moderador:
Por favor, lee las Normas del foro y edita tu código/error usando etiquetas de código.
Ve a edición, luego selecciona todo el código que has publicado, lo cortas y click en </>


corregido , mucha gracias

gatul, muchas gracias no había reparado en ello.
hice el cambio indicado adicionando un segundo de delay y los servos aperen como se indica.

void dolor(){
 servo1.write(120);
 servo2.write(120);
 servo3.write(120);
 delay(1000);
 
 servo1.write(0);
 servo2.write(0);
 servo3.write(0);
}

pero sigo teniendo el problema el cascabeleo de los servos, no se si el problema es de voltaje o de código.

gracias

Vamos a aclarar que estamos en etapa de pruebas, ¿de acuerdo?

Agrega también un delay() para que los servos puedan volver a 0.

Imaginate que estás en el rango de dolor, se mueven los servos hasta 120, esperas que terminen el movimiento y das la orden que vuelvan a 0.
Vuelves al loop() en cuestión de microsegundos, sigues en el rango de dolor, los servos recién están intentando volver a 0 y les dices que vayan otra vez a 120.

Como te dije antes, revisa la documentación de los servos, me parece que con 2 mseg de delay por cada grado es suficiente.

Qué corriente puede entregar la fuente?

Surbyte

La fuente es una fuente step down entregando 5 volt ( Módulo Step Down Ajustable XL4005 5A)

Gracias

Esa no es la fuente, ese es el conversor.

Que fuente de alimentación tensión y corriente usas?
La corriente y la tensión son dos valores importantes. Sabemos que la tensión luego pasa por el conversor DC DC (step down) y le entregas 5V pero a qué corriente?

Surbyte,

el step down en cada servo entrega 5 volt y 2,5 mA en forma constante, pero cuando ingreso la conexión PWM en trabajo , el valor comienza a variar de 0 a 50 mA. sin orden .
puede ser que la señal PWM este con ruido y deba filtra ese ruido.?

Gracias

No creo que el ruido de existir sea responsabilidad del Arduino o el servo, en todo caso lo será de la fuente con la que lo alimentas.
Porque no pones un capacitor electrolíico de 100uF y de tensión que supere la que estas usando, cualquier cosa por encima de 6.3V estará bien.
En bornes del Servo okay!!!
La corriente es muy baja si es que estas midiendo bien.

He consultado a Google y dice esto

Generic SG90 (China)
Voltage 4.8-6VDC (5V Typical)
Current (idle) 10mA (typical)
Current (typical during movement) 100-250mA

Es decir tu SERVO en resposo consume 10mA y en movimiento deberia consumir entre 100 y 250mA y tu hablas de 50mA. No será que tu fuente no alcanza a moverlo?

hola, nuevamente.

anoche estuve revisando todos los comentarios y mejorando en base a la indicado y el problema del ruido en los servos en posición de descanso continua, decidí rehacer el programa pero eliminando el protocolo de pantalla I2C, y el ruido de los servos se termino ... cuando incluyo la librería I2C, todo comienza nuevamente y si la desconecto tanto de los puntos SCL y SDA mas su alimentación todo funciona bien y preciso.

En el nuevo programa que no la incluye, basta que la conecte para que el ruido de fondo inicie .

Me podrían orientar en este problema , por favor.
Gracias

Cuál es la ultima versión del código que estas usando?
Viendo la primer versión esta claro que el problema no es el I2C o el LCD que lo emplea sino tu repetición bloqueante y con eso quiero decir que le pides por ejemplo a

void todo_bien(){ // f(x)  PACIENTE NORMAL //

que haga algo 8 veces?
Cuál es el objetivo de eso?
Puedes hacerlo y claramente no lo sabes sin bloquear el resto del código
Ahora te muestro cómo hacerlo.
Es el mismo código sin el bloque que representan tus for ()

#include <Servo.h>
#include<Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); // dependiendo del fabricante del LCD el codigo 0x27 puede cambiar
 
int fsrAnalog1 =A0; 
int fsrAnalog2 =A1; 
int fsrReading1; 
int fsrReading2; 
int rojo = 3; 
int verde = 4; 
int amarillo= 6; 
int rojo2 = 5; 
int ang;

Servo servo1;
Servo servo2;
Servo servo3;

enum ESTADOS = {ME_DUELE, DOLOR, SIGO};
ESTADOS estado = ME_DUELE;

/// declaración tipos de caras en  pantalla ///

byte chartriste1 [8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000

};

byte chartriste2 [8] = {
B00000,
B01110,
B10111,
B10111,
B11111,
B11111,
B01110,
B00000

};

byte chartriste3 [8] = {
B00000,
B01110,
B10111,
B10111,
B11111,
B11111,
B01110,
B00000

};

byte chartriste4 [8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000

};

byte chartriste5 [8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00001,
B00001,
B00000

};

byte chartriste6 [8] = {
B00000,
B00000,
B00111,
B01111,
B11000,
B10000,
B00000,
B00000

};

byte chartriste7 [8] = {
B00000,
B00000,
B11100,
B11110,
B00011,
B00001,
B00000,
B00000

};

byte chartriste8 [8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B10000,
B10000,
B00000
};


/// todo_bien///


byte charcara1 [8] = {
B00000,
B00000,
B00001,
B00000,
B00000,
B00000,
B00000,
B00000
};

byte charcara2 [8] = {
B00000,
B11110,
B00000,
B00000,
B00110,
B00110,
B00110,
B00000
};

byte charcara3 [8] = {
B00000,
B01111,
B00000,
B00000,
B01100,
B01100,
B01100,
B00000
};

byte charcara4 [8] = {
B00000,
B00000,
B10000,
B00000,
B00000,
B00000,
B00000,
B00000
};

byte charcara5 [8] = {
B00001,
B00001,
B00001,
B00000,
B00000,
B00000,
B00000,
B00000
};

byte charcara6 [8] = {
B00000,
B00000,
B10000,
B11111,
B00111,
B00000,
B00000,
B00000
};

byte charcara7 [8] = {
B00000,
B00000,
B00001,
B11111,
B11100,
B00000,
B00000,
B00000
};

byte charcara8 [8] = {
B10000,
B10000,
B10000,
B00000,
B00000,
B00000,
B00000,
B00000
};
                                  
  //// inicio  programa lectura , seteo  de las condiciones ///                                                          
                                  
void setup() {
  Serial.begin(9600);
  servo1. attach(9);
  servo2. attach(10);
  servo3. attach(11);
  pinMode(rojo, OUTPUT); 
  pinMode(verde, OUTPUT); 
  pinMode (amarillo, OUTPUT);
  pinMode (rojo2, OUTPUT);

  servo1.write(0);
  servo2.write(0);
  servo3.write(0);

  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.begin(16,2); // configuramos el LCD de 16x2
  
}


/// PANTALLAS DE EXPRESIÓN 
///  DOLOR      ///  
///  TODO BIEN  ///

void me_duele(){  // f(x)  expreión dolor //
  lcd.createChar(1,chartriste1);
  lcd.createChar(2,chartriste2);
  lcd.createChar(3,chartriste3);
  lcd.createChar(4,chartriste4);
  lcd.createChar(5,chartriste5);
  lcd.createChar(6,chartriste6);
  lcd.createChar(7,chartriste7);
  lcd.createChar(8,chartriste8);
  lcd.setCursor(3,0);
  lcd.write(1);
  lcd.write(2);
  lcd.write(3);
  lcd.write(4);
  lcd.setCursor(3,1);
  lcd.write(5);
  lcd.write(6);
  lcd.write(7);
  lcd.write(8);
  lcd.setCursor(8,0);
  lcd.print("ME");
  lcd.setCursor(8,1);
  lcd.print("DUELE"); 
}

vosid todo_bien(){ // f(x)  PACIENTE NORMAL //
  lcd.createChar(1,charcara1);
  lcd.createChar(2,charcara2);
  lcd.createChar(3,charcara3);
  lcd.createChar(4,charcara4);
  lcd.createChar(5,charcara5);
  lcd.createChar(6,charcara6);
  lcd.createChar(7,charcara7);
  lcd.createChar(8,charcara8);

  lcd.setCursor(3,0);
  lcd.write(1);
  lcd.write(2);
  lcd.write(3);
  lcd.write(4);

  lcd.setCursor(3,1);
  lcd.write(5);
  lcd.write(6);
  lcd.write(7);
  lcd.write(8);

  lcd.setCursor(8,0);
  lcd.print("TODO ");
  lcd.setCursor(8,1);
  lcd.print("BIEN");   
}


void dolor(){
  servo1.write(120);
  servo2.write(120);
  servo3.write(120);
  
  servo1.write(0);
  servo2.write(0);
  servo3.write(0);
}



void molesto(){
  digitalWrite (amarillo, LOW);
  digitalWrite (rojo2, HIGH);
  servo1.write(45);
  servo2.write(45);
  servo3.write(45);

  servo1.write(0);
  servo2.write(0);
  servo3.write(0);
}

void alerta(){
  digitalWrite ( amarillo, HIGH);
  digitalWrite (rojo2, LOW);
}

/// LECTURA DE PROCESADOR ///

void loop(){

  fsrReading1 = analogRead(fsrAnalog1); // vena
  fsrReading2 = analogRead(fsrAnalog2); // tacto

  Serial.print("dato 1 = ");
  Serial.println(fsrReading1 );
  Serial.print("dato 2 = ");
  Serial.println(fsrReading2);

  /// CONDICONES ///
  if (fsrReading1 > 200 && fsrReading1 < 500){ 
      switch(estado) {
        case ME_DUELE: me_duele();
                       if (cuentoMeDuele++ > 7) {
                          cuentoMeDuele = 0;
                          estado = DOLOR;
                       }
                       break;
        case DOLOR:   dolor();
                      estado = SIGO;
                      break;
        case SIGO:    digitalWrite (rojo, HIGH);
                      digitalWrite (verde, LOW);
                      estado = ME_DUELE;
                      break;
      }
  }
  else {
      digitalWrite(rojo,LOW);
      digitalWrite (verde, HIGH);
      lcd.clear();
      todo_bien();
  }
  if (fsrReading2 > 20 && fsrReading2 < 300 ){
      alerta();
  }

  else{
      digitalWrite( amarillo, LOW);
  }

  if (fsrReading2 > 300 && fsrReading2 <400 ){
     molesto();
  }

  else {
      digitalWrite (rojo2,LOW);
      lcd.clear();
  }
}

muchas gracias, revisare el código y te comento. Efectivamente estaba repitiendo la sentencia varias veces ....

Muchas gracias

Y esa era la razón para que se detuviera el funcionamiento de los servos.
Siempre debes hacer los códigos mas suaves. Estos microcontroladores tienen limitaciones, no se puede pedir que haga algo y olvidarse de lo demás. Hay que hacerlo de manera que todas las tareas sean debidamente atentidas brindándole a cada una un poquito de atención por ciclo.

hola nuevamente,

Surbyte, te comento que he estado tratando de trabajar el código que amablemente me enviaste y logre entender medianamente la lógica del mismo , pero cuando llego a esta parte no comprendo las instrucciones. Mi idea es no copiar por que si , es entender un poco . Me podrías explicar esta parte del código , sobre todo la condición cuentoMeDuele++ > 7.

Muchas gracias

Si, perdona. Hay varias cosas involucradas ahi
cuntoMeDuele es un contador, eso ya lo has entendido
Pero esto

cuentoMeDuele++;
// es lo mismo que esto
cuentoMeDuele = cuentoMeDuele +1; 

En una condición uno puede poner las dos cosas del modo que lo hice. Y funciona de esta manera.

if (cuentoMeDuele > 7) {

Esto lo entiendes, si el contador vale mas que 7 hace lo que sigue sino, otra cosa o nada.
pero esta variante

if (cuentoMeDuele++ > 7) {

Es lo mismo y luego de verificar la condicion ingrementa en 1 cuentoMeDuele
Entonces cada vez que pasa chequea la condición y al terminar la incrementa, cuando supera 7 hace lo que tiene entre llaves.

Entendido esto, pasemos a la máquina de estados.
Una maquina lógica de estados es una secuencia de tareas que se ejecutan cuando se cumplen ciertas condiciones.
Yo use este recurso para eliminar la parte bloqueante de tu código anterior.
Ahora visualiza todo esto de este modo.
Cada vez que estamos en la condición

if (fsrReading1 > 200 && fsrReading1 < 500){

debe hacer algo, y qué hace?
Bueno, empieza por ME_DUELE que era lo que tu hacias. cuantas veces 8, contadas de 0 a 7. Y cuando supero 7 que hago? Paso a un nuevo estado lógico DOLOR, que era tu segunda rutina.
Lo que cambió es que yo hice las rutinas de un me_duele() y dolor() de un simple paso.
En todos vez como el código va fluyendo sin bloqueos.
Ahora si hay un cambio en alguno de tus indicadores eso reacciona mucho mas rapido que antes.