Servo responde al probador de servo, no al microcontrolador. Las señales se ven iguales

Tengo un servo TowerPro MG90D ( Manufactuer Link ) ( ServoDatabase Link ).
Tiene un rango de 180 grados (no continuo).

TorrePro MG90D

Responde muy bien a mi servo probador:
Probador de servos

Observe el siguiente ciclo de trabajo del 7% (alrededor de 90 grados) en el probador:

probador de servo de alcance

probador de servo de alcance

El servo responde bien.


Sin embargo, cuando lo uso servo.write()con mi clon Arduino Mega 2560, el servo no responde a ninguna salida de ángulo. Tengo varios otros servos que funcionan bien con el mismo código en los mismos pines.

Observe el siguiente ciclo de trabajo del 7% en el Arduino con servo.write(90):

alcance arduino servo 90deg

Ninguna respuesta. El servo está "flojo"; no ocupa ninguna posición.


Mientras escribía esta pregunta, pensé en intentarlo servo.writeMicroseconds().

Aquí está servo.writeMicroseconds(1450):

alcance arduino servo 1450ms

¡Servo responde!

¡ Aquí está servo.writeMicroseconds(1472)(trabajando), que tiene los mismos intervalos de tiempo que el anterior sin trabajar servo.write(90)!

alcance arduino servo 1472ms

servo.writeMicroseconds(1550)(laboral):

alcance arduino servo 1550ms


¿Cuál es la diferencia?
El servo probador funcionó a 49,5 Hz, pero servo.write()falló a 49,9 Hz. Me preguntaba si de alguna manera esos 0,4 Hz marcaban la diferencia, pero luego veo que servo.writeMicroseconds()también funcionaba a 49,9 Hz.

En las capturas de alcance anteriores, se puede ver que ambos servo.write(90)y servo.writeMicroseconds(1472)tienen los mismos intervalos de tiempo:
 1,474,560ns HIGH
18,544,640ns LOW

Las señales son tan parecidas... ¿Qué podría hacer servo.write()que no funcione?

Mi código es lo más básico posible:

#include <Servo.h>
Servo serv1;

void setup() {
  serv1.attach(3); // Pin 3
}

void loop() {
  serv1.write(90); // No response
  delay(3000);

  serv1.writeMicroseconds(1472); // Works
  delay(3000);

  serv1.write(0); // No response
  delay(3000);

  serv1.writeMicroseconds(1800); // Works
  delay(3000);
}

esquemático

simular este circuito : esquema creado con CircuitLab

Probé una fuente de alimentación lineal de sobremesa y también intenté usar un convertidor reductor para bajar de 9V.
¿Estás seguro de que tienes una onda constante durante los 3 segundos completos cuando usas write? Realmente no hay razón para que el servo no funcione, así que cuestionaría sus señales.
@DmitryGrigoryev Me parece bastante estable. No hay sacudidas ni parpadeos en mi alcance que puedo ver.
@Bort Entonces me cuesta creer tu historia.
@DmitryGrigoryev Yo también. Pero sigo pellizcándome y siento que esto no es un sueño.
Verificaría el suelo entre el servo y el Arduino. Tal vez el conector esté un poco desalineado y haga mejor contacto con los pines del probador del servo.
@JRE Ground no importa, por alguna razón servo.write()envía una señal diferente a la prueba del servo y servo.writeMilliseconds(uS) . Creo que el OP está buscando cuál es la diferencia real entre las señales, porque para todos los efectos, parecen ser iguales.
@BigHomie: Las señales son idénticas en lo que respecta a las imágenes del alcance. Algo está pasando además de la señal. Una mala conexión a tierra es algo que podría causar diferentes reacciones a señales nominalmente idénticas.
¿Dónde estás conectando tu alcance? en la entrada del servo o en la placa?
@laptop2d Hay un cable de ~8 cm desde la placa que se conecta al cable de ~8 cm del servo. Ese cruce es donde se adjunta mi alcance.
Mirando el servo.write()código , llama servo.writeMicroseconds(). Así que es muy sorprendente que digas que writeMicroseconds()funciona y write()no.
Si es posible, capture dos rastros del osciloscopio en la línea de señal del servo con el servo conectado . Un seguimiento solo con serv1.write() y un seguimiento solo con serv1.writeMicroseconds(). Publica ambos rastros. Para un encanto adicional, agregue un tercer trazo de su probador con el servo conectado .
Mencionaste otros servos funcionando, ¿correcto? ¿Son estos servos del mismo modelo? ¿Los has probado en este pin en particular?
Estoy de acuerdo con JRE. Hay una diferencia en alguna parte que no está teniendo en cuenta.

Respuestas (2)

Primero, un aparte rápido. Parece que tienes un ligero malentendido sobre cómo funcionan los servos. Los servos no están controlados por PWM, y no saben ni les importa que estés enviando pulsos a 49, sea cual sea el Hz. No saben que el pulso es un porcentaje de un período arbitrario. Al servo no podría importarle menos cuál es el tiempo entre pulsos. Digo esto porque pareces inusualmente concentrado en cosas que en realidad no importan.

Los servos ni siquiera saben o no les importa si el voltaje es alto o bajo en un momento dado. Solo les importa una cosa: el tiempo entre un flanco ascendente y un flanco descendente.

El servo se controla detectando un borde de voltaje ascendente y midiendo el tiempo hasta que hay un borde descendente. Los tiempos válidos suelen estar entre 1,0 y 2,0 ms, pero pueden variar de un servo a otro.

Puede controlarlo a 1 Hz, 10 Hz, 50 Hz, 100 Hz. La mayoría responderá a frecuencias de pulso aún más altas, pero nuevamente esto es variable. Lo que estoy tratando de decir es que la frecuencia, el ciclo de trabajo, la duración entre pulsos, todo no podría ser menos relevante para su problema, que es que el servo no responde cuando lo espera.

Lo único que es relevante son los bordes de tu pulso, a los que no has prestado atención. Si quiere resolver esto, comience por mirar las cosas que importan, proporcione capturas de cerca de los bordes de su pulso, ese tipo de cosas. No capturó nada útil en esas capturas de pantalla, por lo que probablemente no parece haber ningún problema o diferencia. Hay muchos problemas o diferencias que nunca serían visibles con lo que ha medido.

Lo que puedo ver es que la captura del tren de pulsos que no funciona está notablemente más sucia, tanto el pulso como el suelo, que cualquiera de los otros. Lo cual es extraño, ya que debería estar llamando a la misma función que los demás. ¿Por qué ese es mucho más ruidoso?

Más importante aún, en la captura que no funciona, mire el 'tiempo de caída'. 809µs? Su osciloscopio cree ver un tiempo de caída que dura 0,8 ms. Eso es malo. Claramente eso es incorrecto, pero el hecho permanece, eso es lo que mide.

Ese es un signo clásico de un borde sucio. Piénsalo. Si este pulso está engañando a su equipo de prueba de gama alta, que es su osciloscopio, para que vea un borde ridículamente largo o un tiempo de caída, o tal vez tan sucio que simplemente no puede detectar correctamente el borde descendente todo el tiempo (o quién sabe), entonces ¿Qué posibilidades tiene ese pobre servo de $ 8 de mierda de recoger un borde descendente decente?

Si un servo no obtiene un pulso válido (por ejemplo, si el flanco descendente tarda demasiado, está demasiado sucio o se pierde) dentro del rango de pulso aceptable, y los servos calculan por los flancos que pueden o no tener algo que haga con lo que considere que son los bordes del pulso, entonces responde como si estuviera apagado.

En otras palabras, no solo no se mueve, sino que no resistirá el movimiento de su eje. Simplemente estará fláccido, exactamente como lo estás viendo.

Ahora, esto plantea la pregunta... ¿por qué llamar a servo.write afectaría la calidad del borde?

Dijiste un clon. ¿Como éste?ingrese la descripción de la imagen aquí

Estos clones en particular tienden a comportarse de manera errática debido al desacoplamiento increíblemente pobre. Debería haber condensadores de desacoplamiento en cada pin de alimentación y lo más cerca posible del mega2560. Y en el arduino real, de hecho los hay. Sin embargo, en estos clones, están demasiado lejos, o quizás faltan, es difícil saberlo. Es obvio al mirar el tablero que no se comportará de manera confiable, eso es lo importante.

Entonces, ¿cuál es la diferencia?

Cuando llama a servo.write, empuja la pila más alto que si llama a writeMicroseconds. Dado el puntero de pila de 3 bytes del mega2560 (17 bits), tiene que voltear un montón de bits críticos que no tiene que hacer cuando llama a writemicroseconds. Sé que esto parece una diferencia poco probable, pero he experimentado una buena cantidad de microcontroladores mal desacoplados, y los atmegas en particular parecen exhibir un comportamiento extraño específicamente cuando usan temporizadores y/o empujan o abren la pila. Me sucedió algo similar, solo que la pila se corrompió cuando intentaba controlar los LED con PWM, pero si puse todo en línea sin empujar la pila, funcionó. El desacoplamiento deficiente fue en última instancia el problema.

Esperaría que un desacoplamiento deficiente pueda, por razones conocidas por atmega2560 y nadie más, tener un efecto perjudicial en la calidad del borde de ese pulso, pero solo cuando está empujando la pila justo antes. Este servo simplemente no es capaz de manejar la forma en que se ensucian esos bordes, por lo que no ve pulsos válidos en ese caso. Otros servos obviamente lo manejan.

Desacoplar cosas siempre es extraño e hiperespecífico como este. Por eso es tan importante el desacoplamiento. Mantenga a raya los problemas de pesadilla que la falta de capacitancia puede causarle con tapas de cerámica bonitas y gordas y tan cerca del chip como sea físicamente posible.

Esto puede estar relacionado con la configuración del pin de salida realizada por la rutina .write(). Intente usar una resistencia desplegable de 1K, si no funciona, retírela y utilícela. esto equilibrará el efecto de cualquier resistencia pull-up/pull-down de semana interna que pueda establecer la rutina. Cuando está midiendo la señal con su alcance, la resistencia interna de la sonda actúa como un pull-down.
La mayoría de los servos también liberarán energía al motor interno si la señal no está preestablecida para 10 pulsos seguidos. Esto se utiliza para ahorrar energía.

Me temo que tu respuesta no es correcta. servo.write() toma un ángulo como entrada, no el tiempo. La gente no debería votar las respuestas a ciegas.
Sí, error mío, no leí bien el código. esto puede estar relacionado con la configuración del pin de salida realizada por la rutina .write().
Este habría sido mi primer pensamiento, sin embargo, los rastros del alcance parecen refutar esto. Una conexión a tierra faltante y una situación diferente de pull-up/-down pueden explicar que se envíe la misma señal pero que no llegue allí (después de la ubicación de la sonda).
Creo que @KallieMP probablemente tenga razón. Las resistencias pullup/down bien podrían ser la respuesta. Podrían limitar la corriente. Los pulsos pueden formarse correctamente pero sin suficiente impulso. Entonces, sin importar la función particular de servo.write(), los niveles actuales deben coincidir con precisión con la salida del probador de servo para obtener el mismo resultado.