Go Down

Topic: Bucle loop no se llama el mismo numero de veces (Read 3023 times) previous topic - next topic

Ytsneumon

Saludos,

   Llevo tiempo ya jugueteando con Arduino y hace relativamente poco he empezado a trabajar con servos para un proyecto que tengo entre manos. El problema es que aún con el ejemplo más simple, llega un momento en que no funciona. Me explico, cargo un programa, el cual lo único que hace es que cada segundo cambia el ángulo del servo 10 grados más o menos según le toque. Bien, cuando lleva un rato el servo se queda parado y al poco vuelve a moverse, pero de golpe y a veces sigue por donde iba y otras se queda colgado (parado).

   Hice una prueba para ver cuantas veces se llamaba al bucle loop en cada segundo y de media eran unas 120000 veces/segundo. Pues descubrí que cuando se quedaba bloqueado y luego seguía de golpe, sólo se llamaba al bucle unas 20000 veces o menos en ese segundo.

   También he probado con distintos servos (del mismo modelo) y con distintos periodos de temporización para el servo. Además de la librería Servo del propio Arduino con la que también me falla.

   Mi pregunta en sí es... ¿Es normal que Arduino tenga estos problemas de temporización? ¿Podría ser que mi Arduino estuviera roto? ¿A alguien se le ocurre alguna otra prueba para desentrañar el misterio?

   Gracias de antemano.

chico_del_maiz

#1
Dec 07, 2010, 06:24 pm Last Edit: Dec 07, 2010, 06:51 pm by chico_del_maiz Reason: 1
Tendrias que poner el programa si quieres que te ayudemos. Por que tiene pinta de ser tu programa ya que yo he usado servos con arduino sin ningun otro problema.

Un saludo.

Ytsneumon

Quote

int angulo;
int anchoPulso;
int maxPulso;
int minPulso;
int rTime;
int incremento;
unsigned long lastPulse;
unsigned long lastChange;
unsigned long veces;

int angle2widthPulse(int angle){
  return map(angle, 0, 180, 700, 2200);
}

void setup(){
  Serial.begin(9600);
  veces = 0;
  incremento = 10;
  angulo = 91;
  anchoPulso = angle2widthPulse(angulo);
  maxPulso = 2200;
  minPulso = 700;
  rTime = 18;
  pinMode(2,OUTPUT);
  lastPulse = millis();
  lastChange = millis();
}

void loop(){
  veces++;
  if(millis() - lastPulse >= rTime){
    digitalWrite(2, HIGH);
    delayMicroseconds(anchoPulso);
    digitalWrite(2, LOW);
    lastPulse = millis();
  }
  if(millis() - lastChange >= 1000){
    angulo = angulo + incremento;
    if(angulo > 180){
      incremento = -10;
      angulo = 170;
    }else if(angulo < 0){
      incremento = 10;
      angulo = 10;
    }
    anchoPulso = angle2widthPulse(angulo);
    lastChange = millis();
    Serial.println(veces/1000, DEC);
    veces = 0;
  } 
}



chico_del_maiz

1º creo que el problema lo tienes en la separacion entre los pulsos, 18 milisegundos es poco (rTime = 18;), yo suelo poner 200 ms, esto puedes consultarlo p.e. en wiki. http://es.wikipedia.org/wiki/Servomotor_de_modelismo. Por ello creo que rTime=200;
2º por el problema que te surge con veces, debes de tener en cuenta que haces un delayMicroseconds(anchoPulso); y con ello estas parando el micro lo que hace que con un pulso de 2200uS se ejecuten menos instruciones por segundo que con un pulso de 700uS. Ademas he encontrado un fallo de concepto, aunque dividas un long entre 1000, obtendras un valor mayor de 65535 por lo cual producir un overflow y el valor no sera el correcto.


Igor R

Por qué no usas una salida PWM???

http://arduino.cc/es/Reference/AnalogWrite
http://arduino.cc/es/Tutorial/PWM

;)

chico_del_maiz

#5
Dec 08, 2010, 05:43 am Last Edit: Dec 08, 2010, 05:47 am by chico_del_maiz Reason: 1
Creo que tienes algun fallo (si me equivoco por favor corregirme):
1º Para usar el pwm hay que usar analogwrite y esa llamada no la estas haciedo.
2º Creo que el pin 2 no tiene funcion PWM.
3º Ademas la frecuncia de pwm es 500hz lo que equivale a 2 ms de periodo.
4º Si quieres usar pwm deverias irte a la libreria servo que trae arduino, ahi un ejemplo en http://arduino.cc/es/Tutorial/Sweep muy parecido a lo que tu quieres.

Un saludo.

Ytsneumon

Gracias por responder,

   En la Wikipedia (edición española) es cierto que dicen que el tiempo de refresco debe ser de 200 ms, pero lo cierto es que si se consulta la Wikipedia (edición inglesa) o cualquier página donde expliquen cómo controlar un servo, dicen que un servo espera un pulso cada 18-25 ms.

   Es cierto también que podría usar salidas PWM para controlar el servo de manera analógica, pero prefiero hacerlo con una salida digital, pues me hace falta que la salida sea digital para controlar más servos en un futuro.

   La variable veces nunca llega a tener un valor mayor que 120000, por lo que al dividir entre 1000, se queda en 120 o así.

   Por último es cierto que deteniendo el micro el tiempo del loop varía. Voy a intentar meterle mano al problema por ahí.

   Gracias por vuestra ayuda, si se os ocurre algo más ya sabeis.

Igor R

#7
Dec 09, 2010, 11:08 am Last Edit: Dec 09, 2010, 11:35 am by igorreal Reason: 1
Quote
PWM para controlar el servo de manera analógica

A que te refieres con esto?
Le llaman en Arduino asi (analogWrite), por el hecho de que variando el tiempo a on de una senyal de frecuencia constante, estas creando un voltage medio proporcional a dicho tiempo. Pero de analogico no tiene nada.... ;D
Es cierto que le han dado un nombre un poco confuso.

Al final tu estas creando un PWM mediante soft, y el micro dispone de un modulo hardware preparado para esto, que no te gasta recursos y te aseguras tiempos correctos de tu senyal cuadrada.
http://www.olimex.cl/tutorial/Guia%20MCI%20-%20Servo%20motor%20con%20Arduino.pdf
http://smrobots.com/node/22


Aunque lo puedes hacer mediante los dos metodos: polling o usando PWM.

Tambien puedes usar esta libreria y mirar el codigo de como  lo resuelven :
http://www.arduino.cc/playground/ComponentLib/Servo
http://arduino.cc/en/Reference/Servo

;)

Ytsneumon

   Gracias por la aclaración sobre el PWM. Cuando decía analógico era por eso mismo, porque en Arduino lo llaman así. De todas formas no sabía si realmente era analógico o no (tampoco me interesaba cómo estaba implementado, pero siempre es bueno saber algo más). Probaré con estas salidas esta tarde a ver si no tengo esos problemas de tiempo.

   De todas formas, en un futuro quería controlar 12 servos o más a la vez, por eso lo de controlar los servos con las salidas no-PWM. Pero supongo que tendré que comprarme un Mega u otro Arduino o un controlador de Servos.

  Aún así, creo que se debe de poder usar las salidas no-PWM para controlar servos de la manera en que lo estoy haciendo, porque como dices estoy haciendo mediante software lo que hace Arduino por hardware. Seguiré investigando.

  Si a alguien se le ocurre algo más no dudeis en aportar ideas.

  Gracias.

Igor R

#9
Dec 09, 2010, 12:32 pm Last Edit: Dec 09, 2010, 12:42 pm by igorreal Reason: 1
Que version de Arduino IDE estas usando?? Lo digo porque leyendo delayMicroseconds, parece como que en el pasado desconectaba las interrupciones, y esto es un problema para millis().

http://www.arduino.cc/en/Reference/DelayMicroseconds
(As of Arduino 0018, delayMicroseconds() no longer disables interrupts. )

[edit]
Acabo de ver una cosa!!!!
if(millis() - lastPulse >= rTime)


-----------------------------------------
http://arduino.cc/en/Reference/Millis
Tip:
Note that the parameter for millis is an unsigned long, errors may be generated if a programmer tries to do math with other datatypes such as ints.
-----------------------------------------

rTime es un int en tu programa !!!!

[/edit]


Ytsneumon

   Estoy utilizando la 0021, la última creo. Probaré también a cambiar los tipos de datos.

   Gracias por el aporte.

Igor R

#11
Dec 09, 2010, 12:47 pm Last Edit: Dec 09, 2010, 12:55 pm by igorreal Reason: 1
Ya contaras si era eso del rTime.... ;)
Con la version 21 no hay problemas con delayMicroseconds.

Por cierto, cuando envias por puerto serie, tienes un delay (tiene que ir esperando a que se envie un byte, para poner otro en el buffer de transmision,y tienes que tener en cuenta que cada caracter enviado es 1 byte en ASCII). A 9600 bps que estas usando, este "retraso" puede ser considerable.... Lo digo, porque usando "polling", hay que tener cuidado con estas cosas, si quieres tener "controlados" tus tiempos.... en esto es la ventaja de usar el modulo PWM del micro!!!    ;D

chico_del_maiz

#12
Dec 09, 2010, 01:01 pm Last Edit: Dec 09, 2010, 01:03 pm by chico_del_maiz Reason: 1
Hola,
tenias razon los servos pueden funcionar con tiempos mas bajos, una cosa nueva que aprendo. Mis montajes siempre han funcionado a 200ms segun decia wiki y no me habia molestado en probar otros tiempos. Gracias.

He montado un servo y tu programa en arduino version 18 y no me da ningun problema, el servo funciona correctamente y da valores entre 121 y 130.

Tal vez sea tu servo????
Tal vez sea el tiempo??? en vez 700us a 2200uS prueba 1000us a 2000uS.

Lo unico que no entiendo es como te da valores de 200, ya que aunque el servo fuera el que este roto, el programa seguira funcionando bien, Tal vez igor tenga razon y solo sea que rtime no este inicializada con long.

No se me ocurre nada mas.





Ytsneumon

Bueno, acabo de probar con PWM y ahora si que me temo que mi Arduino esta loco. Resulta que mi programa es el que sigue:

Quote

int pin;
unsigned long nTimes;

void setup(){
  nTimes = 0;
  pin = 9;
  pinMode(pin,OUTPUT);
}

void loop(){
  if(nTimes == 0){
    analogWrite(pin, 121);
    nTimes++;
  } 
}



Como podéis comprobar, más sencillo, imposible. Según la teoría del PWM, se mantiene la señal cuadrada hasta que se llame de nuevo a analogWrite. La llamo una vez al principio y luego nunca más.

Pues bien el comportamiento es el siguiente:
El servo va a la posición indicada por el parámetro de analogWrite. Al cabo de un rato (alrededor de medio minuto o así) se va a 0º, luego a ciento y pico grados y luego vuelve a su posición correcta.

De lo que sí me he dado cuenta es de que cuando falla, se enciende el LED "L" del Arduino. Que no sé qué significa, la verdad.

Si se os ocurre alguna otra prueba para hacer será bienvenida.


chico_del_maiz

#14
Dec 09, 2010, 09:33 pm Last Edit: Dec 09, 2010, 09:36 pm by chico_del_maiz Reason: 1
Cuando usas analogwrite, al poner un valor, este sigue presente en la salida pwm hasta que lo cambias de nuevo.
Cando usas PWM, te recuerdo que el perido es 2 ms y necesitas 20ms entre pulsos.

Go Up