Autor Tema: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)  (Leído 45910 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5362
    • Picmania by Redraven
Preámbulo:

Primero deciros que estaba dudando entre postear este hilo aquí, en el subforo de C, o hacerlo en el de Robótica ya que en el fondo lo que deseo describir es un algoritmo, una idea de cómo hacer algo mas que una implementación de esa idea en un idioma concreto, pero al final me he decidido por éste ya que es mi entorno habitual y el foro de Robótica lo frecuento poco, mas que nada por mi desconocimiento del tema aunque poco a poco iré entrando mas en él.

Por ahí tengo ya posteados algunos hilos dedicados a este tema de los servos y los PWM's, concretamente recuerdo Controlando un SERVO con el PIC desde nuestro PC,  El Termo-Servo o un servo controlado por temperatura. o Proyecto Radiocontrol : Receptor RC asistido por PIC ...

Todos ellos han tratado de un único servo, apuntando algunas ideas para poder manejar mayor cantidad de ellos, pero sin concretar nada sobre dicha posibilidad. Como alguno de ustedes sabéis estoy empeñado en cierto proyecto de temas de RC (radiocontrol) cuyas repercusiones en el foro las tenéis en los hilos Proyecto de Barco a Vela radiocontrolado o el ¿Conocéis módulos RF?. En cualquiera de ellos se prevee manejar no uno sino muchos servos, así que ahora ha llegado el momento de acometer el tema.

La idea de cómo hacerlo la he tomado prestada de la gente de IEArobotics y quiero dejar aquí constancia de ello y de mi público agradecimiento.

Introducción:

No vamos a entrar en una descripción detallada de cómo manejar un servo, para ello a quien le interese puede visitar uno de los hilos anteriormente mencionados, pero vamos a dar al menos un somero repaso al tema.

Un servo, de los que usamos los hobbystas, se alimenta con unos 5V y se controla mediante una señal PWM con una frecuencia de 50 Hz, o sea con un periodo de 20 ms, y con un Duty Cycle que varía entre el 6% y el 15%, o sea entre un periodo en alto de unos 0.5 ms a 2.5 ms (estos valores pueden cambiar según el modelo concreto de servo que utilicemos, los Hitec van desde los 0.5 a los 2.5 ms y los Futaba desde los 0.3 a los 2.3 ms aproximadamente)

Con un pulso de unos 0.7 ms el servo se posiciona en un extremo de su recorrido, con un pulso de unos 2.3 ms el servo se posiciona en el extremo contrario y con un pulso intermedio, de unos 1.5 ms, se posiciona en el centro de su recorrido.

Aquí tenéis un cronograma de cómo reacciona un servo ante estos tipos de pulsos PWM:



Implementar la generación de un solo pulso PWM no es cuestión difícil y en los hilos mencionados antes tenéis formas sencillas de hacerlo.

La cosa sin embargo se complica conforme vamos acumulando una tras otra la necesidad  de controlar mas y mas servos. Y todo es un problema de tiempos, conforme mas servos vamos intentando controlar nuestras rutinas se van complicando, ocupando mas tiempo de proceso, y empiezan a perder la precisión necesaria en la generación de los pulsos de cada uno de los servos. Éstos empiezan a temblar y a hacer cosas "raras", vibran, tiemblan, dan saltos ... y todo producido por una inestabilidad en los anchos de los pulsos que le llegan.

Es mi intención en este hilo la de presentaros una forma económica en recursos y tiempos de proceso, en el PIC para controlar hasta 8 servos de forma estable y precisa, haciendo además uso de una única interrupción: La del desborde del Timer1 (rodando a 16 bits de precisión).

Descripción del algoritmo:

Para describiros el algoritmo tenemos que hacer un uso intensivo de la calculadora. El primer dato a tener en cuenta es la frecuencia del pulso PWM de los servos, que como dijimos anteriormente es de 50 Hz. Esto significa que cada pulso a cada servo tiene un periodo, o tiempo que transcurre entre dos flancos sucesivos:

[ latex ]T=\frac{1}{F}=\frac{1}{50}=0,02s=20ms[ /latex ].

Este periodo lo podemos dividir entre 8 para obtener lo que vamos a denominar una "ventana" para cada uno de los servos.

[ latex ]W=\frac{20}{8}=2.5ms[ /latex ].

Dentro de cada una de estas "ventanas" de tiempo de 2.5 ms de duración vamos a controlar un solo servo, pero uno tras otro hasta completar los 8 que son nuestro objetivo. Esto significa que independientemente del tiempo que esté en alto el pulso de un servo, recordad que decíamos que podía ser entre 0.7 ms y 2.3 ms, cada 2.5 ms ponemos en alto el siguiente servo, y como han transcurrido 2.5 ms desde la puesta en alto del anterior éste ya debe de haber sido bajado porque ningún pulso en alto puede sobrepasar los 2.3 ms.

Esto hace que dentro de cada 2.5 ms se pone en alto y después en bajo la señal de un servo. Como son 8 servos y por lo tanto 8 "ventanas" de 2.5 ms, a cada servo le tocará de nuevo ponerle la señal en alto 8 * 2.5 ms = 20 ms. O sea el periodo correspondiente a la frecuencia de 50 Hz que necesita.

Esto puede verse de forma mucho mas clara mediante el siguiente cronograma:



Fijaos cómo las señales de cada uno de los servos se van generando una tras otra, de forma sucesiva, pero separadas cada una de la siguiente los mismos 2.5 ms hasta completar los 20 ms con los 8 servos, y cómo independiente de en qué momento se ponga en alto uno de ellos individualmente, a los 20 ms vuelve a tocarle a ese mismo ponerse en alto.

Ahora la cuestión pasa por generar los "timmings" necesarios para ser capaces de producir este tren de pulsos de ancho controlado.

Recursos a utilizar:

Como os puse mas arriba el principal recurso a utilizar es una única interrupción, la del desborde del Timer1. Pero antes debemos tratar otro tema relacionado con éste.

Una idea que a nadie se le debe escapar, pero que por mas obvia que sea no voy a dejar de mencionar, es la de que hace falta un PIC razonablemente rápido. Con un pulso al extremo, de los 2.3 ms, vamos a tener sólo 0.2 ms para detectar el fin del pulso y ponerlo a bajo. No es mi intención calcular qué frecuencia FOSC mínima podríamos utilizar, he escogido un PIC que puede volar a 20 Mhz con el que tenemos mas que suficiente y si deseáis probar con frecuencias menores os rogaría que me hicieseis partícipe de los resultados.

Con un cristal de 20 Mhz y el Timer1 configurado para como contador de 16 bits, con prescaler a 1:1 tenemos los siguientes "timmings" :



El dato fundamental es el del tiempo de incremento de un Tick del Timer1, que resulta ser de 0.2 uS, o lo que es lo mimo 0.0002 ms.

Podemos así expresar en esta unidad de Ticks los tiempos en alto de cada uno de los servos. Si todos tuviesen que estar en el centro de su recorrido sus PWM deberían de ser de 1.5 ms en alto:

[latex]Tx=\frac{1.5ms}{0,0002ms}=7.500Ticks[/latex]

Así si habilitamos la interrupción por desbordamiento del Timer1 la primera vez que desborde ponemos en alto el pin correspondiente al Servo número 1 y precargamos el valor del Timer1 con 7.500 ticks antes del desborde, que se produce a los 65.535 ticks, con lo que ponemos el Timer1 a 65.535 - 7.500 = 58.035, de esta forma obtendremos la siguiente interrupción cuando transcurran esos 7.500 ticks.

Cuando la interrupción salta de nuevo y entramos por segunda vez tenemos que prefijar entonces el tiempo que ha de transcurrir para completar la ventana de 2.5 ms hasta el comienzo del control del siguiente servo. Como en nuestro ejemplo hemos utilizado un valor de 1.5 ms ó 7.500 Ticks tendremos ahora que esperar 2.5 ms - 1.5 ms = 1 ms por lo que vamos a precargar de nuevo el Timer1 con 65.535 - 5.000 = 60.535 y nuestra interrupción saltará de nuevo transcurrido 1 ms.

Ahora le toca al siguiente Servo con el que procederemos de la misma forma: ponemos en alto el pin del servo 2, precargamos el Timer1 restando al desborde en numero de ticks correspondiente a su ancho de pulso, esperamos la siguiente interrupción en la que ponemos en bajo el pin del servo y precargamos de nuevo con los ticks necesarios para completar los 2.5 ms de su ventana y de nuevo a empezar pero con el siguiente servo.

Esta es la idea fundamental. Cada dos interrupciones se controla completamente un Servo y entre ambas transcurre exactamente 2.5 ms, independiente del estado en alto que tenga que tener cada servo, cada 16 interrupciones se vuelve de nuevo al principio, al primer servo, y han transcurrido exactamente 20 ms.

Con una simple tabla de 8 enteros de 16 bits para guardar el número de ticks que tiene que estar en alto cada pulso de cada servo y con dos simples cálculos aritméticos de suma y resta en una única interrupción tenemos perfectamente controlados hasto 8 servos.

Implementación en CCS C:

Para realizar la implementación de este algoritmo en C comenzaremos por comentar algunos detalles importantes.

Vamos a usar la directiva #use fast_io(X) y fijar el funcionamiento de los pines con el set_tris_x(). Esto hace que el compilador no incluya los set_tris() automáticamente cada vez que se encuentra un output_low() o output_high() con lo que quitaremos instrucciones innecesarias de en medio y ganaremos en velocidad y precisión en nuestro programa.

En el ejemplo que he preparado interactuo con el PIC mediante el canal serie del mismo con un MAX232. Así que he habilitado también la interrupción por recepción serie. Como los tiempos, "timmings" les llamábamos, son fundamentales en esta aplicación vamos también a usar la directiva #priority timer1,rda que nos va a hacer prioritaria la interrupción del timer1 sobre la de recepción serie. Ante la duda el Timer1 gana y nosotros con él en estabilidad y precisión.

He creado una tabla int16 Servo_PWM[8] en la que guardo los Ticks de ancho que tienen que durar cada uno de los pulsos de cada uno de los servos. Son los necesarios para restárselos a 65.535 tras inicio de cada pulso y para sumárselos al ancho de la ventana tras su final para colocar la interrupción al inicio del siguiente pulso.

Como el inicio de un pulso de servo siempre llega con una interrupción impar y el final de ese mismo pulso llega con la interrupción par me he creado un int1 flag_Phase que va a hacerme saber si estoy al comienzo o al final de cada pulso.

Si estoy al final, flag_Phase=1, entonces incremento el número del siguiente Servo que me toca tratar y que será al que le tengo que levantar la señal en la siguiente interrupción. Si al incrementar el siguiente servo es mayor que el último vuelvo a ponerlo a 0 y recomienzo de nuevo con el primero.

El programa queda tal como sigue:

Código: C#
  1. #include <18f1320.h>
  2. #fuses HS,NOMCLR,PUT,NOWDT,NOPROTECT,BROWNOUT,BORV45,NOLVP,NOCPD,NODEBUG,NOWRT
  3. #use delay(clock=20000000)
  4. #use rs232(baud=115200, xmit=PIN_B1, rcv=PIN_B4)
  5. #use fast_io(A)
  6. #use fast_io(B)
  7.  
  8. #priority timer1,rda
  9.  
  10. #define SERVO1 PIN_B5
  11. #define SERVO2 PIN_B3
  12. #define SERVO3 PIN_A0
  13. #define SERVO4 PIN_A4
  14. #define SERVO5 PIN_B2
  15. #define SERVO6 PIN_A3
  16. #define SERVO7 PIN_B0
  17. #define SERVO8 PIN_B5
  18.  
  19. const int16  Ticks4Window  = 12500;  // PWM Window for servo = 2.5 ms x 8 = 20 ms
  20. const int16  Ticks4Minimum =  3500;  // PWM High for Minimum Position = 0.7 ms  
  21. const int16  Ticks4Center  =  7500;  // PWM High for Center  Position = 1.5 ms  
  22. const int16  Ticks4Maximum = 11500;  // PWM High for Maximum Position = 2.3 ms  
  23.  
  24. static char  command;
  25. static int16 Servo_PWM[8]={Ticks4Center,Ticks4Center,Ticks4Center,Ticks4Center,0,0,0,0};
  26. static int8  Servo_Idx=0;
  27. static int1  SERVO1_ON=1;
  28. static int1  SERVO2_ON=1;
  29. static int1  SERVO3_ON=1;
  30. static int1  SERVO4_ON=1;
  31. static int1  SERVO5_ON=0;
  32. static int1  SERVO6_ON=0;
  33. static int1  SERVO7_ON=0;
  34. static int1  SERVO8_ON=0;
  35. static int1  flag_Phase;
  36. static int16 Ticks4NextInterrupt=53036;
  37.  
  38. #int_rda
  39. void serial_isr(void){
  40.  
  41.    if(kbhit()){
  42.       command=getc();
  43.    }
  44. }
  45.  
  46. #int_timer1
  47. void timer1_isr(void){
  48.  
  49.    if(flag_Phase==0){
  50.       if(Servo_Idx==0 && SERVO1_ON) output_high(SERVO1);
  51.       if(Servo_Idx==1 && SERVO2_ON) output_high(SERVO2);
  52.       if(Servo_Idx==2 && SERVO3_ON) output_high(SERVO3);
  53.       if(Servo_Idx==3 && SERVO4_ON) output_high(SERVO4);
  54.       if(Servo_Idx==4 && SERVO5_ON) output_high(SERVO5);
  55.       if(Servo_Idx==5 && SERVO6_ON) output_high(SERVO6);
  56.       if(Servo_Idx==6 && SERVO7_ON) output_high(SERVO7);
  57.       if(Servo_Idx==7 && SERVO8_ON) output_high(SERVO8);
  58.       Ticks4NextInterrupt = 65535 - Servo_PWM[Servo_Idx];
  59.       set_timer1(Ticks4NextInterrupt);
  60.    }
  61.    if(flag_Phase==1){
  62.       if(Servo_Idx==0 && SERVO1_ON) output_low(SERVO1);
  63.       if(Servo_Idx==1 && SERVO2_ON) output_low(SERVO2);
  64.       if(Servo_Idx==2 && SERVO3_ON) output_low(SERVO3);
  65.       if(Servo_Idx==3 && SERVO4_ON) output_low(SERVO4);
  66.       if(Servo_Idx==4 && SERVO5_ON) output_low(SERVO5);
  67.       if(Servo_Idx==5 && SERVO6_ON) output_low(SERVO6);
  68.       if(Servo_Idx==6 && SERVO7_ON) output_low(SERVO7);
  69.       if(Servo_Idx==7 && SERVO8_ON) output_low(SERVO8);
  70.       Ticks4NextInterrupt = 65535 - Ticks4Window + Servo_PWM[Servo_Idx];
  71.       set_timer1(Ticks4NextInterrupt);
  72.       if(++Servo_Idx>7) Servo_Idx=0;
  73.    }
  74.    ++flag_Phase;
  75. }
  76.  
  77. void pres_menu(void){
  78.  
  79.    printf("\r\nA 18F1320 listen on RS-232");
  80.    printf("\r\nEight Servos Control Algorithm");
  81.    printf("\r\n");
  82.    printf("\r\n[?] This menu");
  83.    printf("\r\n[I] All to Minimum");
  84.    printf("\r\n[C] All to Center");
  85.    printf("\r\n[X] All to Maximum");
  86.    printf("\r\n[+] Step to front");
  87.    printf("\r\n[-] Step to back");
  88.    printf("\r\n\n>");
  89.  
  90. }
  91.  
  92. void main(void) {
  93.  
  94.    int1 valid_command;
  95.    int8 i;
  96.  
  97.    disable_interrupts(global);
  98.    setup_adc_ports(NO_ANALOGS);
  99.    setup_adc(ADC_OFF);
  100.    setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
  101.    setup_timer_0(RTCC_OFF);
  102.    setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
  103.    setup_timer_2(T2_DISABLED,0,1);
  104.    setup_timer_3(T3_DISABLED);
  105.    port_b_pullups(FALSE);
  106.  
  107.    set_tris_a(0b00000000);
  108.    set_tris_b(0b00010000);
  109.  
  110.    output_low(SERVO1);
  111.    output_low(SERVO2);
  112.    output_low(SERVO3);
  113.    output_low(SERVO4);
  114.    output_low(SERVO5);
  115.    output_low(SERVO6);
  116.    output_low(SERVO7);
  117.    output_low(SERVO8);
  118.  
  119.    delay_ms(1000);
  120.  
  121.    command='\0';
  122.  
  123.    enable_interrupts(int_rda);
  124.    set_timer1(Ticks4NextInterrupt);
  125.    enable_interrupts(int_timer1);
  126.    enable_interrupts(global);
  127.  
  128.    pres_menu();
  129.  
  130.    do {
  131.       // Comandos serie
  132.       if(command!='\0'){
  133.          command=toupper(command);
  134.          valid_command=0;
  135.          printf("%c\r\n>",command);
  136.  
  137.          if(command=='?'){
  138.             pres_menu();
  139.             valid_command=1;
  140.          }
  141.          if(command=='I'){
  142.             printf("> All to Minimum\r\n>");
  143.             for(i=0;i<4;i++) Servo_PWM[i]=Ticks4Minimum;
  144.             valid_command=1;
  145.          }
  146.          if(command=='C'){
  147.             printf("> All to Center\r\n>");
  148.             for(i=0;i<4;i++) Servo_PWM[i]=Ticks4Center;
  149.             valid_command=1;
  150.          }
  151.          if(command=='X'){
  152.             printf("> All to Maximum\r\n>");
  153.             for(i=0;i<4;i++) Servo_PWM[i]=Ticks4Maximum;
  154.             valid_command=1;
  155.          }
  156.          if(command=='+'){
  157.             printf("> Step to front\r\n>");
  158.             for(i=0;i<4;i++) Servo_PWM[i]+=80;
  159.             valid_command=1;
  160.          }
  161.          if(command=='-'){
  162.             printf("> Step to back\r\n>");
  163.             for(i=0;i<4;i++) Servo_PWM[i]-=80;
  164.             valid_command=1;
  165.          }
  166.  
  167.          if(!valid_command) printf("?\r\n>");
  168.          command='\0';
  169.       }
  170.  
  171.    } while (TRUE);
  172. }
  173.  
  174.  

Mi montaje funcionando:

Solo tengo 4 servos disponibles así que solo 4 le he conectado físicamente, pero el programa contempla los 8 aunque los 4 últimos no los secuencia en dos interrupciones sino que una de ellas salta inmediatamente y es la segunda la que hace todo el recorrido de la ventana de esos servos.



Y este es el pequeño menú que me he preparado para controlar su funcionamiento:



Os aseguro que los servos se desplazan suavemente, sin vibraciones ni temblores, entre ambos extremos siguiendo puntualmente las ordenes que les mando desde el PC.

En este menú, como véis, manejo todos los servos a la vez, de hecho lo que hago es solo cargar la tabla Servo_PWM con los valores extremos y central y dejo que la interrupción haga el resto. Y la verdad es que va absolutamente de lujo.

Era una espinita que tenía clavada hace tiempo y que por fin he podido quitarme. Y quería compartirlo con todos ustedes.

Ea, ya está bien por hoy. Mañana más.  :mrgreen:








« Última modificación: 14 de Abril de 2014, 16:34:51 por RedPic »
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado Thanathos

  • PIC10
  • *
  • Mensajes: 10
Re: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)
« Respuesta #1 en: 03 de Febrero de 2008, 01:13:26 »
Ante todo saludos estimado REDPIC, si a alguien debo lo que se es a ti.
Definitivamente otra vez me dejaste sin palabras...

Me voy a poner a analizar tu codigo, lo mire asi rapidito y tiene cosas de verdad interezantes...

1 pregunta, ¿Que Porcentaje de maquina consume el programa?, es que hace unos dias hice un programa igual para 8 servos con un 877 y la verdad gastaba maquina.

Desconectado darklord

  • PIC10
  • *
  • Mensajes: 16
    • Tech Freaks
Re: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)
« Respuesta #2 en: 03 de Febrero de 2008, 02:43:23 »
Muy bueno!!!  :shock:

He seguido tus avances en tu página Diego, y me gusta mucho tu forma de escribir tanto el código como los artículos, todo muy bien estructurado. Estaba buscando algoritmos para controlar servos y di con tu artículo, voy a analizarlo, pero ante todo, gracias por compartirlo.

No te ha pasado por la cabeza la idea de un controlador de servos USB?

Recibe un coordial saludo.
« Última modificación: 03 de Febrero de 2008, 02:52:08 por darklord »
Visita mi blog: http://tech-freaks.net

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 17452
    • MicroPIC
Re: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)
« Respuesta #3 en: 03 de Febrero de 2008, 05:04:40 »
Don Diego, felicidades por un nuevo magnífico artículo.

Dices que cuando se solapan varios servos en el mismo pulso ascendente, para luego bajar cuando a cada uno le corresponda, has observado vibraciones extrañas.
Aunque me encanta la forma de resolverlo que has tenido, reservando una parcela de tiempo exclusiva para cada uno, yo sospecho que la velocidad del PIC es más que suficiente para manejar con soltura una situación como la planteada.
¿No crees que existe la posibilidad de que la causa fuera otra?, ¿estuviste peleando mucho con esa idea hasta abandonarla?
Un saludo desde Sevilla, España.
Visita MicroPIC                                                                                        ɔ!doɹɔ!ɯ ɐʇ!s!ʌ

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5362
    • Picmania by Redraven
Re: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)
« Respuesta #4 en: 03 de Febrero de 2008, 07:32:12 »
El tema tal como lo tenía anteriormente planteado tenía un fallo evidente con el ejemplo simple de todos los servos a la misma posición. Tenía la interrupción de Timer1 que solo servía para generar un pulso cada 20 ms, precargando el timer con el valor correspondiente, y poniendo en alto todas las señales de todos los servos.

Y después en el main() e independiente de la velocidad a la que corriese el PIC tenia la batería de comparaciones de tiempos transcurridos para cada servo, en caso de sobrepasar su valor debía ponerlos a bajo. Esto llevaba a la paradoja de que si todos los servos estaban en la misma posición todos las señales debían caer al mismo tiempo, cosa a todas luces imposible.

Y también, si los servos tenían posiciones cercanas pero no iguales, lo suficientemente cerca como para depender del tiempo de proceso del que le precedía o del que le sucedía en el flujo del programa resultaba que la estabilidad absoluta de un servo dependía de la posición de sus vecinos.

No, no intenté seguir por ahí porque me daba cuenta de que jamás iba a conseguir precisión.

Deberías ver ahora como responden estos al aumento tick a tick del ancho de pulso, es casi inapreciable el movimiento que produce, suave y firme.  :mrgreen:

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5362
    • Picmania by Redraven
Re: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)
« Respuesta #5 en: 03 de Febrero de 2008, 07:36:48 »

No te ha pasado por la cabeza la idea de un controlador de servos USB?


Si, claro que sí. Pero el tema es que el método por que le haga llegar las posiciones, o mejor dicho lo valores de las posiciones a la memoria del PIC es irrelevante y no necesito una velocidad tan grande como el USB me puede brindar.

Además la aplicación para la que estamos investigando todo esto de los servos, y otras cosas como los motores DC o PaP, es para ser radiocontrolados en un modelo naval y ahí va a ser difícil usar el USB.  :mrgreen: 
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 17452
    • MicroPIC
Re: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)
« Respuesta #6 en: 03 de Febrero de 2008, 07:47:57 »
Abundando en la idea, y sin ánimo de darte la coña más, porque ya lo tienes solucionado.

Imagina que en el momento de levantar las señales haces un "if" con condición TRUE por cada servo lo cual los levantará todos, pero con un miniretraso entre ellos que corresponde al tiempo que tarda el pic en pasar de cada uno al siguiente.

Y ahora en el momento de bajarlas haces lo mismo, un "if" para cada servo que introducirá a cada uno un miniretraso equivalente al que usaste al levantarlas.

En teoría, sería como si pones ese diagrama de tiempos tan chulo que has pintado, pero con las señales "casi" superpuestas, sólo decaladas por ese miniretraso que comentaba antes.

¿No crees que funcionaría?
Un saludo desde Sevilla, España.
Visita MicroPIC                                                                                        ɔ!doɹɔ!ɯ ɐʇ!s!ʌ

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5362
    • Picmania by Redraven
Re: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)
« Respuesta #7 en: 03 de Febrero de 2008, 08:02:11 »
Si, debería funcionar perfectamente. De echo es similar a lo que estoy haciendo con la interrupción salvo que la "ventana" la definen los if() consecutivos de subida y bajada.

Pero y es el único pero que le encuentro, esta en el resto del programa. Me decidí a poner la interrupción  enlazada servo tras servo para tener todo el main() para mi solo, como la cama cuando mi esposa se va a ver a la nieta.

Así en el main() puedo hacer y deshacer cálculos todo lo complejo que quiera sabiendo siempre que los servos están atendidos correctamente. Cuanto termino un cálculo actualizo el doble-byte de ese servo y sé que cuando le toque se irá a la posición adecuada, o puedo estar sensando otros puertos o dedicado al tema de las comunicaciones mientras el sistema de pulsos PWM está en "automático".
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 17452
    • MicroPIC
Re: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)
« Respuesta #8 en: 03 de Febrero de 2008, 08:12:38 »
Perfecto. Que sepas que has conseguido incrementar en una unidad mi pila de insatisfacciones, en forma de proyectos que me gustaría hacer y no tengo tiempo.
Un saludo desde Sevilla, España.
Visita MicroPIC                                                                                        ɔ!doɹɔ!ɯ ɐʇ!s!ʌ

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5362
    • Picmania by Redraven
Re: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)
« Respuesta #9 en: 03 de Febrero de 2008, 08:21:00 »
Tú bien sabes que yo tampoco tengo tiempo, pero esto lo hago como medida terapéutica. O lo hago a plena satisfacción o caigo enfermo. De vez en cuando hay que hacer cosas como esta, no todo pueden ser Iacedeses finde tras finde.  :mrgreen:
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado stk500

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4735
Re: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)
« Respuesta #10 en: 03 de Febrero de 2008, 08:26:12 »
Felicitaciones Diego por tu gran Clase como siempre  :-/ :-/

estupendo Servo Tutorial nos has dados muchas gracias  :-/ :-/

Desconectado jfmateos2

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3138
Re: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)
« Respuesta #11 en: 03 de Febrero de 2008, 08:33:23 »
Enhorabuena RedPIC.

Me surge una duda al leer tu código. En lugar de usar este tipo de if consecutivos de los que, obviamente, no pueden ser ciertos más de uno a la vez, ¿en los PICs también sería más eficiente recurrir a estructuras switch...case o if...else if?

Código: [Seleccionar]
      if(Servo_Idx==0 && SERVO1_ON) output_high(SERVO1);
      if(Servo_Idx==1 && SERVO2_ON) output_high(SERVO2);
      if(Servo_Idx==2 && SERVO3_ON) output_high(SERVO3);
      if(Servo_Idx==3 && SERVO4_ON) output_high(SERVO4);
      if(Servo_Idx==4 && SERVO5_ON) output_high(SERVO5);
      if(Servo_Idx==5 && SERVO6_ON) output_high(SERVO6);
      if(Servo_Idx==6 && SERVO7_ON) output_high(SERVO7);
      if(Servo_Idx==7 && SERVO8_ON) output_high(SERVO8);

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5362
    • Picmania by Redraven
Re: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)
« Respuesta #12 en: 03 de Febrero de 2008, 09:01:36 »
Enhorabuena RedPIC.

Me surge una duda al leer tu código. En lugar de usar este tipo de if consecutivos de los que, obviamente, no pueden ser ciertos más de uno a la vez, ¿en los PICs también sería más eficiente recurrir a estructuras switch...case o if...else if?

Código: [Seleccionar]
      if(Servo_Idx==0 && SERVO1_ON) output_high(SERVO1);
      if(Servo_Idx==1 && SERVO2_ON) output_high(SERVO2);
      if(Servo_Idx==2 && SERVO3_ON) output_high(SERVO3);
      if(Servo_Idx==3 && SERVO4_ON) output_high(SERVO4);
      if(Servo_Idx==4 && SERVO5_ON) output_high(SERVO5);
      if(Servo_Idx==5 && SERVO6_ON) output_high(SERVO6);
      if(Servo_Idx==6 && SERVO7_ON) output_high(SERVO7);
      if(Servo_Idx==7 && SERVO8_ON) output_high(SERVO8);

Si. Así lo tenía antes.

Pero de este modo lo veía como mas bonito, mas estético.  :oops: :oops: :oops:
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 17452
    • MicroPIC
Re: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)
« Respuesta #13 en: 03 de Febrero de 2008, 09:05:23 »
Me suena que se compilan igual los switch/case que los if/else.
Un saludo desde Sevilla, España.
Visita MicroPIC                                                                                        ɔ!doɹɔ!ɯ ɐʇ!s!ʌ

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5362
    • Picmania by Redraven
Re: Algoritmo para controlar hasta 8 servos con una sola interrupción (en C)
« Respuesta #14 en: 03 de Febrero de 2008, 09:09:07 »
No lo he comprobado pero la diferencia debe ser mínima.

Ademas el Switch solo switcheaba entre los servos y dentro de cada case tenía que poner un if() para saber si el servo ese estaba o no activo, asi que decidi poner solo el if().

Ademas asi la rutina siempre tarda lo mismo, mientras que con el switch() tarda menos con el primero y todo con el último. Que no se si tendrá importancia o no pero ahí está.
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania


 

anything