Manejar Servos a más hercios

Hola a todos, este es mi primer mensaje en el foro.

Estoy haciendo un proyecto con una placa arduino Duemilanove y unos mini servos 9g ( http://dx.com/p/9g-mini-servo-with-accessories-translucent-blue-121343 ) y tengo una duda.

Tras ir probando la librería de servos de arduino y ver que todo va perfectamente a los 500 hz que funciona por defecto la placa, probé también a mover los servos sin necesidad de la librería, simplemente con analogwrite(valor microsegundos entre 1000 y 2000) con el retarde de 20 ms de cada ciclo. Y todo perfecto.

Ahora me gustaría saber si cambiando la frecuencia por defecto (500 hz) del arduino, a por ejemplo, 32khz (ya lo he consegudo mediante programación a bajo nivel controlando los timers de cada pin pwm ( Arduino Playground - TimerPWMCheatsheet )), puedo mandarle al servo las señales para que se mueva.

He estado probando pero se queda colgado el servo.

Estos servos solo funcionan a una frecuencia máxima de los 500 hz del arduino? O pueden trabajar a más frecuencia, aunque se le manden los anchos de los pulsos más grandes para que equivalgan a los 1000 microsegundos o 2000 microsegundos de posición 0 o 180 grados?

Gracias

La librería servo de Arduino no funciona a 500 Hz (no te confundas con la frecuencia de las salidas PWM, no tienen nada que ver), funciona a 50 Hz (tiempo de ciclo 20 ms como luego indicas).

El pulso que recibe un servo puede durar hasta 2,5 ms y por tanto eso ya limita la frecuencia máxima que probablemente también depende de cada servo. Puedes emplear tu código empezando en 50 Hz y comprobando que funciona el servo para ir aumentando la frecuencia y ver cuál es la máxima que admite. Te adelanto que no creo que admita mucho más de 200 Hz.

Gracias por la respuesta.

Creo que me había confundido al explicarlo.

Realmente lo que quería saber es si mandando señales PWM a más frecuencia (por ejemplo, 1khz, 21khz, 32khz...), el servo funcionaba igual.

He estado probando, y sin usar la librería servo, y subiendo las frecuencias de las salidas PWM (9 y 10 , que son las que estoy probando), me funciona perfectamente. Aquí parte del código

....

int pinservo1 = 9;
int pinservo2 = 10;

......

void setup()
{

.........
  pinMode(pinservo1, OUTPUT);           // pone el pin como salida    
  pinMode(pinservo2, OUTPUT);           // pone el pin como salida
 TCCR1B = TCCR1B & 0b11111000 | 0x01; //timer 1 de los pins 9 y 10 a 31.250 hz

}

void loop()
{

      ai = Serial.read();
      ad = Serial.read();
      bytes_ms = Serial.read();

      pulsoai = map(180 - ai, 0, 180, 500, 2500); // calculamos el ancho del pulso en      microsegundos 
      pulsoad = map(180 - ad, 0, 180, 500, 2500); // calculamos el ancho del pulso en microsegundos 

      digitalWrite(pinservo1, HIGH); // activamos el pin de salida
      delayMicroseconds(pulsoai); // esperamos el tiempo que dura el pulso en microsegundos
      digitalWrite(pinservo1, LOW); // desactivamos el pin de salida

      digitalWrite(pinservo2, HIGH); // activamos el pin de salida
      delayMicroseconds(pulsoad); // esperamos el tiempo que dura el pulso en microsegundos
      digitalWrite(pinservo2, LOW); // desactivamos el pin de salida

      //retardo calculado para sincronizar con envio de vbnet por puerto serie
      milisegundos = int(bytes_ms);
      tiempo_final=micros();
      delayMicroseconds((milisegundos*1000) - (tiempo_final - tiempo_inicial));[/s]

Realmente no sé si controlas el tema de los servos y no te entiendo o si confundes las cosas.

Vuelves a hablar de enviar señales PWM al servo de hasta 32 kHz. Tal como he indicado antes el máximo teórico está en menos de 400 Hz y en la práctica no creo que un servo en general admita frecuencias mayores de 200 Hz.

Hablas de la frecuencia PWM de las salidas 9 y 10. En el código que muestras le cambias la frecuencia pero en realidad después NO usas ese PWM (se usa mediante la instrucción analogwrite). Simplemente te construyes tú la señal mediante estados HIGH y LOW y delay.

Toda la razón. Me acabo de dar cuenta de lo de digitalwrite.

Gracias por las indicaciones.

Saludos

pd=

he cambiado los valores de digitalwrite a analogwrite, colocando 255 durante x microsegundos y despues a 0, y me funciona. Es correcto entonces?

      analogWrite(pinservo1, 255); // activamos el pin de salida
      delayMicroseconds(pulsoai); // esperamos el tiempo que dura el pulso en microsegundos
      analogWrite(pinservo1, 0); // desactivamos el pin de salida

      analogWrite(pinservo2, 255); // activamos el pin de salida
      delayMicroseconds(pulsoad); // esperamos el tiempo que dura el pulso en microsegundos
      analogWrite(pinservo2, 0); // desactivamos el pin de salida

Me temo que no tienes nada claro algunos conceptos. No tiene sentido el código que has puesto para manejar servos. ¿Qué es lo que quieres hacer?

Ahora solo tengo 2 servos (mini servos 9g) y después de probarlos con la librería servo, he hecho testeas sin la la libería, solamente mandandole los pulsos y los delays de microsegundos.

De normal, sin cambiar la frecuenca de las señales pwm, con poner en HIGH el pin durante x microsegundos (de 1000 a 2000, 1 a 2 ms) se consigue la posición (de 0 a 180 grados) del servo.

Mi idea es subir la frecuencia de la señal pwm (para otros motores que voy a pedir), y poner la señal del ping en HIGH o 255 durante los 1000 o 2000 microsegundos para poder mover motores.

Saludos

Sin lees un poco de información verás que no tiene nada que ver las salidas PWM de Arduino con el control de servos.

Imagino que esos motores que hablas son brushless controlados desde variadores. El principio de funcionamiento es el mismo que para servos pero pueden no tener la misma capacidad de subir la frecuencia. Eso de subir la frecuencia, ¿quieres hacerlo por curiosidad y trastear o lo necesitas para algo? Si es el último caso, ¿para qué lo necesitas?

El código simple hecho "a mano" para manejar un servo es

   digitalWrite(pinservo1, HIGH);
   delayMicroseconds(pulsoai);
   analogWrite(pinservo1, LOW);

y este código lo ejecutas a 50 Hz (cada 20 ms). A partir de ahí puedes probar a ir subiendo la frecuencia poco a poco.

Sin embargo, siendo tan sencillo para un servo, se complica bastante para mayor número sobre todo si quieres aumentar la frecuencia ya que los tiempos de los estados HIGH para cada servo se van sumando. Para evitar que vayan sumándose yo tengo desarrollado un código para 4 servos (o motores brushless) que puedes ver en mi blog:

http://cuadricopterodiyarduino.blogspot.com.es/2012/08/control-motores-parte-2.html

Para aumentar la frecuencia no tienes nada más que editar la línea

if (micros() - TiempoControlCiclo >= 20000) {

y en lugar de 20000 (microsegundos, el tiempo de ciclo) ir bajándolo. El código es sencillo, está hecho sin interrupciones aunque si se hiciera con ellas imagino que sería más fácilmente escalable a mayor número de servos.

Otra opción podría ser editar la librería servo para subir la frecuencia. Yo nunca lo he hecho ni lo he intentado ni he buscado información así que no sé si será complicado o si quiera si es posible.

Muchísimas gracias por la información. La verdad es que hace unas semanas no tenía ni idea de lo que era arduino....y a base de investigar y probar, he podido hacer algún avance.

Voy a echar un ojo a tu blog.

De nuevo muchas gracias y disculpa por todo el lío que he formado en el post.

Saludos