Hola Manofwar, quize escribir ayer pero se me borro todo antes de enviar :2] Primero que nada dejame decirte que se ve muy bien tu controladora :mrgreen: baje los archivos los corri y me parece mejor que la mia jeje... Creo que la diferencia radica en que yo basicamente atiendo un servo a la vez, es decir haciendo el control secuencialmente con lo que puedo controlar 8 servos tranquilamente y para logra hacer 16, controlo 2 servos a la vez en paralelo obteniendo 16 en total.
(http://img50.imageshack.us/img50/7227/sealesdelosservos2el.th.jpg) (http://img50.imageshack.us/my.php?image=sealesdelosservos2el.jpg)
Y veo que tu haces los 24 servos en paralelo... yo queria hacer lo mismo pero no se me ocurrio como hacerlo. Y probablemente sea porque yo trabajo en CCS y no en Asembler (aunque en mi algoritmo hay algo de ASM) A ver si nos muestras tu magia ;)
Aca dejo lo que he avanzado, aun no esta implementado la aprte de comunicacion pues aun tengo que mejorar y probar algunas cosas... A ver que les parece...Código: CSS
#include <16F876A.h> #fuses XT, NOWDT, NOLVP, NOCPD, NOWRT, NODEBUG, NOPROTECT, NOBROWNOUT #use delay(clock=4000000) #define Nservos 16 #define High True #define Low False #byte timer0 = 0x01 #byte porta = 0x05 #byte portb = 0x06 #byte portc = 0x07 #bit t0if = 0xb.2 #bit Servo01 = portb.0 #bit Servo02 = portb.1 #bit Servo03 = portb.2 #bit Servo04 = portb.3 #bit Servo05 = portb.4 #bit Servo06 = portb.5 #bit Servo07 = portb.6 #bit Servo08 = portb.7 #bit Servo09 = porta.0 #bit Servo10 = porta.1 #bit Servo11 = porta.2 #bit Servo12 = porta.3 #bit Servo13 = porta.5 #bit Servo14 = portc.0 #bit Servo15 = portc.1 #bit Servo16 = portc.2 int8 Index, Angulo[Nservos], s[2], time[2]; void Servo(int n, int1 Estado); void Ini_Ang(); void retardo(int t); void main() { Index=0; setup_timer_0(RTCC_DIV_16); // Configura el tiempo de 2.5ms entre cada Interrupcion output_a(0); output_b(0); output_c(0); Ini_Ang(); enable_interrupts( GLOBAL ); while(1) { set_timer0(100); Servo(2*Index,High); Servo(2*Index+1,High); delay_us(300); if (Angulo[2*Index]>=Angulo[2*Index+1]) { if (Angulo[2*Index]=Angulo[2*Index+1]) { Time[0] = Angulo[2*Index]; Time[1] = 0; s[0] = 2*Index; s[1] = 2*Index+1; } else { Time[0] = Angulo[2*Index+1]; Time[1] = Angulo[2*Index]-Angulo[2*Index+1]; s[0] = 2*Index+1; s[1] = 2*Index; } } else { Time[0] = Angulo[2*Index]; Time[1] = Angulo[2*Index+1]-Angulo[2*Index]; s[0] = 2*Index; s[1] = 2*Index+1; } retardo(time[0]); Servo(s[0],Low); retardo(time[1]); Servo(s[1],Low); #asm // espera hasta que los 2.5ms hallan pasado Loop: BTFSS t0if GOTO Loop BCF t0if #endasm Index++; if (Index>=8) Index=0; } } void retardo(int t) { int w; if (t!=0) { for (w=0;w<8;w++) delay_us(t); } } void Ini_Ang() { int k; for(k=0;k<Nservos;k++) Angulo[k]=5*k; } void Servo(int n, int1 Estado) { n+=n; if (Estado) { #asm MOVF n,0 ADDWF 2,1 BSF Servo01 GOTO SalidaH BSF Servo02 GOTO SalidaH BSF Servo03 GOTO SalidaH BSF Servo04 GOTO SalidaH BSF Servo05 GOTO SalidaH BSF Servo06 GOTO SalidaH BSF Servo07 GOTO SalidaH BSF Servo08 GOTO SalidaH BSF Servo09 GOTO SalidaH BSF Servo10 GOTO SalidaH BSF Servo11 GOTO SalidaH BSF Servo12 GOTO SalidaH BSF Servo13 GOTO SalidaH BSF Servo14 GOTO SalidaH BSF Servo15 GOTO SalidaH BSF Servo16 SalidaH: #endasm } else { #asm MOVF n,0 ADDWF 2,1 BCF Servo01 GOTO SalidaL BCF Servo02 GOTO SalidaL BCF Servo03 GOTO SalidaL BCF Servo04 GOTO SalidaL BCF Servo05 GOTO SalidaL BCF Servo06 GOTO SalidaL BCF Servo07 GOTO SalidaL BCF Servo08 GOTO SalidaL BCF Servo09 GOTO SalidaL BCF Servo10 GOTO SalidaL BCF Servo11 GOTO SalidaL BCF Servo12 GOTO SalidaL BCF Servo13 GOTO SalidaL BCF Servo14 GOTO SalidaL BCF Servo15 GOTO SalidaL BCF Servo16 SalidaL: #endasm } }
Este codigo esta hecho para un 16F876 con un cristal de 4MHz, pronto lo pondre para 20MHz(aunque no se porque razon he tenido algunos problemas con este cristal) Y como podras dar cuenta atiendo 2 servos a la vez, por esa razon debo tener cuidado con la cantidad de tiempo que utilice para la comunicacion.
Vamos a ver como anda todo... pero me sigue pareciendo mas optimo tu protocolo, en especial porque optimizas totalmente el tiempo, a ver si me das ideas para mejorar el mio.
Nos vemos :-/ :-/ :-/ :-/ :-/ :-/ :-/
hay que conectar un cable null-modem entre el com1 y el com2 del pc. Ambos deben estar configurados a 115200.
The signal level on the DTR and RTS lines is also controlled by the test software and the attached inputs are read back in the software to see if these signal levels are properly returnedFuente (http://www.lammertbies.nl/comm/cable/RS-232.html)
#include <16f877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,NOBROWNOUT,PUT
#use delay (clock=20000000)
#USE RS232 (baud=9600,bits=8,parity=N,xmit=PIN_C6,rcv=PIN_C7, stream=hyper)
#USE RS232 (baud=115200,bits=8,xmit=PIN_B3, stream=pic)
#use fast_io(B)
#use fast_io(C)
int8 buffer_rx[8];// Buffer de recepción del hyper terminal
int8 i=0;
#INT_RDA
void serial_isr(void){
buffer_rx[i]=fgetc(hyper);
fputc(buffer_rx[i], hyper);// Hacemos eco
i++;
}
void main()
{
int8 buffer_tx[64];// Podemos enviar hasta 64 bytes (16servos*4bytes)
int8 j=0, i_old=0, k;
int16 valor;
set_tris_c(0b10000000);
set_tris_b(0b00000000);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
fprintf(hyper, "Listo para recibir datos\n\r");
while (TRUE)
{
if (i_old!=i){
if (buffer_rx[i-1]==13){// Si es ENTER enviamos
//for (k=0; k<=j-1; k++) fputc(buffer_tx[k], pic);// Enviamos al pic
j=0;
i=0;
fprintf(hyper, "Datos enviados!\n\r");
}
else{
switch (i){
case 1:
buffer_tx[j]=(buffer_rx[i-1]-0x30)*10;// asumo que todos son números
break;
case 2:
buffer_tx[j]=(buffer_rx[i-1]-0x30)+buffer_tx[j];
j++;
break;
case 3:
buffer_tx[j]=(buffer_rx[i-1]-0x30)*100;
break;
case 4:
buffer_tx[j]=(buffer_rx[i-1]-0x30)*10+buffer_tx[j];
break;
case 5:
buffer_tx[j]=(buffer_rx[i-1]-0x30)+buffer_tx[j];
j++;
break;
case 6:
valor=(buffer_rx[i-1]-0x30)*100;
break;
case 7:
valor=(buffer_rx[i-1]-0x30)*10+valor;
break;
case 8:
valor=(buffer_rx[i-1]-0x30)+valor;
buffer_tx[j]=make8(valor, 0);// Guardamos el byte bajo
j++;
buffer_tx[j]=make8(valor, 1);// Guardamos el byte alto
j++;
i=0;
break;
}
}
i_old=i;
}
}
}
Por ejemplo para mover el servo 2 a la velocidad 1, 9 grados, esto es:
Servo=2
Vel=1
Grados=9
Escribimos en el hyper terminal 02001009 y le damos enter.
El formato es así: SSVVVGGG escribir todo en formato decimal, del 0 al 9.
El programa no es inteligente así que ingresen bien los datos, es decir hay que escribir 8 números y luego darle a ENTER.
...
PD2: Miento, el programa envía bien los grados, envía 1ero el byte bajo y luego el alto, es decir P1 y luego P2, está bien eso?
Por ejemplo para 360º, envía P1=00000001b y P2=01101000b, lo que es lo mismo P1=1d y P2=104d
...
...
Otro ejemplo: 0101B400 ----> Servo1, velocidad "1", posición B4=11·16+4=180=0º
...
...
Por otra parte Manofwar dice que se deben de enviar los datos cuando RTS pase a 1. En el PROTEUS RTS está parpadeando contínuamente ??
...
...
Otro ejemplo: 0101B400 ----> Servo1, velocidad "1", posición B4=11·16+4=180=0º
...
Esto se supone que tendría que posicionar al SERVO1 en 0º pero no se inmuta.
...
Hola LordLaFebre:
Te dejo una imagen de mi configuración
(http://www.ual.es/personal/salguero/control_servos/serie.jpg)
A ver si soy capaz de poner a trabajas a las pocas neuronas que tengo funcionales :) :) y esta vez dar una explicación clara
La trama de bytes la envías en el orden correcto, pero como puedes ver no envío los datos como ASCII si no como HEX. Al enviarlos ASCII estás enviando el valor del carácter 1, B, 4 ó 0.
La configuración debe ser:
velocidad: 115200
bits de datos: 8
paridad: No
bits de parada: 1
Es necesario activar el RTS (control por hardware de la comunicación) ya que de otro modo se interfiere con los PWM, originándose algún temblor en los servos, esto creo que puedo arreglarlo y poder utilizar ese pin para un servo más.
Como puedes observar en mi configuración, es el puerto COM2 por donde envío los datos y en la simulación el puerto seríe está configurado con el COM1. Esto lo tuve que hacer así ya que si intentaba enviar y recibir por el mismo puerto, COM1 como en tu caso, había problemas. Si era el terminal serie el que activaba primero el COM1, proteus no protestaba al comenzar la simulación pero no hace caso a los datos enviados desde el terminal. Si es al contrario, primero ejecutamos la simulación y luego el terminal serie, este último protestaba diciendo que el puerto ya esta ocupado por otra aplicación.
¿Cómo lo haces para no tener este problema?
Hola gu1llermo:
No he visto tu hilo, el C y yo no nos llevamos demasiado bien :mrgreen:, aparte de no entrar mucho en el foro, pero descuida que lo haré y ya te formularé alguna pregunta seguro.
En cuanto a la resolución de mi código, lo tengo restringido a 0,5º pero creo recordar que podía llegar a los 0,35º (unos 5us de interrupción).
Tengo algo hecho para los 18F, también en ensamblador, y sí que tenía una resolución bajísima, otra cosa es que sea útil.
Saludos
Bueno, por fin he podido dedicarle tiempo a este proyecto. Así que os presento el diseño, espero que definitivo, de la controladora.una pregunta, de donde descargo los archivos, no veo los enlaces... :(
He aumentado el número de servos de 24 a 28, he restringido la resolución a 0,5º y el protocolo de comunicación ha cambiado un poco.
La comunicación se realiza enviando 4 bytes del siguiente modo:
S V P1 P2
- S es el número de servo a mover, de 1 a 28. (1 byte)
- V la velocidad a la que se movera el servo desde la posición actual hasta la nueva posición (1byte), ejemplo: un valor de 1 correspondería a 0,5º cada 20ms.
- P1 y P2. Estos 2 bytes son la posición a la que debe ir el servo (0 a 360), P1 corresponde al byte de menos peso y P2 al de más. ejemplo: 68 01 = 360 =+90º
Si se quiere cambiar la posición de varios servos o de todos a la vez la orden será:
S V P1 P2 S V P1 P2 S V P1 P2 ...
Espero en este fin de semana montarla y poner alguna foto para que se vea mejor el resultado final, ya que hasta ahora sólo la he montado y comprobado su funcionamiento en una protoboard.
Una imagen de como quedará
(http://www.ual.es/personal/salguero/control_servos/Placa_28_servos.jpg)
Si alguien quiere ir buscando bugs AQUÍ (http://www.ual.es/personal/salguero/control_servos/CONTROLADORA_28_SERVOS.htm) tenéis lo necesario para montarla.
Saludos
Yo hice un algoritmo para controlar 24 servomotores con el Timer1 de 16bit del pic a resolucion de 0,0075 grados, si quieren se los pongo solo digan, ademas se comunica por el RS-232 y los servos no vibran en absoluto. :)