fbpx

Expresate

Si además quieres enviarnos un Artículo para el Blog y redes sociales, pulsa el siguiente botón:

Buena resolucion pa...
 
Avisos
Vaciar todo

Buena resolucion para los servos

10 Respuestas
6 Usuarios
0 Reactions
4,136 Visitas
mif
Respuestas: 1095
 Mif
Topic starter
(@mif)
Noble Member
Registrado: hace 19 años

¡Muy buenas compañeros!
Como algunos sabeis estoy rehaciendo el programa de control de TupperBot, y claro, una de las cosas principales que necesito modificar es el tema de la resolucion en los servos, ya que ahora mismo tengo unos 7º de resolucion, y claro, es bastante cutre para mover la camara... ¿no creeis?

Bien, pues aqui viene mi pregunta... Necesito manejar dos servos, Pan & Tilt, que deberian tener una resolucion algo mejor de la que tengo... cuanto mayor sea mejor funcionara, claro...
¿Cómo hago los cálculos para conseguir una buena resolucion? Programo en CCS un 16F876, con un cristal a 20Mhz, y ahora mismo tengo configurado el TIMER con "setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1)" es decir, que hace un OverFlow cada 51.2us... pero claro, asi me va...
Entonces... cuál es el truco para conseguir una buena resolucion?
El código de control de los servos que hice es este:
#int_RTCC
RTCC_isr()
{
//Posicion Minima 17 en decimal = 11 Hex
//Posicion Máxima 45 en decimal = 2D
if (Tim19968us==1)
{
set_timer0(0);
Tim19968us=0;
TimTot=0;
output_bit(Servo1, 1);
output_bit(Servo2, 1);
output_bit(LedR, 1); //LedR
output_bit(LedG, 1); //LedG
output_bit(LedB, 1); //LedB
}

if (TimTot==390) //Ya lleva 19,968ms
{
set_timer0(96);
Tim19968us=1;
}

if (TimTot == PosServo1) output_bit(Servo1, 0);
if (TimTot == PosServo2) output_bit(Servo2, 0);

if (TimTot == DutyRed) output_bit(LedR, 0);
if (TimTot == DutyGreen) output_bit(LedG, 0);
if (TimTot == DutyBlue) output_bit(LedB, 0);

++TimTot;

}

Se que es muy malo mi sistema de control deservos, pero hasta ahora me ha funcionado... je je je...

Bueno, ya por ultimo, os hago otra pregunta...
Ahora mismo uso un micro para controlar todo el robot, que en total tiene:
-2 Servos
- Comunicacion RS 232
- 3 PWM (Estos ahora mismo van como si fuesen servos, pero es para controlar leds, de modo que no me hace falta mas resolucion de la que tengo ahora)
- 2 Entradas analogicas

Creeis que estoy sobre cargando mucho el micro?

Mil gracias por la atencion.
Mif

Responder
9 respuestas
eagleman
Respuestas: 25
(@eagleman)
Eminent Member
Registrado: hace 19 años

Hola,

Yo no he usado nunca el PWM que trae el PIC, por tanto no sabía cuales eran sus frecuencias mínimas y máximas, me he leido el datasheet y he visto que la mínima frecuencia para un cristal de 20MHz sería de unos 1,22KHz algo que está realmente muy por encima de nuestras necesidades 50Hz.
Para que el circuito de PWM funcionase con un periodo de 20ms (50Hz) sería necesario que la frecuencia de oscilación del PIC fuese de unos 819KHz como máximo.

Por tanto la mejor solución es implementarlo mediante rutinas software, como el ejemplo de Andrés.

P.D. Mif la precisión que tiene Andrés no es de 1,7 sino de 1,17Grados él tiene 153 posiciones.

Responder
mif
Respuestas: 1095
 Mif
Topic starter
(@mif)
Noble Member
Registrado: hace 19 años

Vaya, veo entonces que el sistema del PWM no nos va a ayudar mucho... claro que he pensado que quiza haya una posibilidad de hacerlo con la base del PWM, el TMR2

Por lo que estoy viendo, este timer tiene mucha mas resolucion que el TMR0, asi que podemos hacer lo siguiente:

1- Servo en nivel bajo y TMR2 configurado asi:
setup_timer_2(T2_DIV_BY_16,255,16); con esto hacemos que interrumpa a los 13.1ms, asi que 18ms - 13.1ms = 4.9ms

2- En la primera interrupcion habran pasado 13.1ms, asi que lo configuramos para que la proxima sea dentro de 4.9ms:
setup_timer_2(T2_DIV_BY_16,96,16); El servo sigue en nivel bajo.

3- Despues de la segunda interrupcion estamos en el periodo de tiempo en alto del servo, asi que configuramos el TMR0 asi:
setup_timer_2(T2_DIV_BY_1,9,1); lo que nos da una interrupcion cada 2us = 0.002ms, con lo que tenemos 2ms / 0.002ms = 1000 posiciones, es decir, tenemos una resolucion de 180º/1000 = 0.18º... si no me he equivocado esto puede ser una pasada, no?

Quiza tener esa resolucion sea incluso demasiado, pero jugando con esta ultima configuracion podemos hacer que la resolucion cambie:
-setup_timer_2(T2_DIV_BY_1,0,1); interrumpe cada 0.2us, lo que da una resolucion de 0,018º, 10000 posiciones para 180º
-setup_timer_2(T2_DIV_BY_1,4,1); interrumpe cada 1us lo que da una resolucion de 0,09º, 2000 posiciones para 180º
-setup_timer_2(T2_DIV_BY_1,9,1); interrumpe cada 2us lo que da una resolucion de 0.18º, 1000 posiciones para 180º
-setup_timer_2(T2_DIV_BY_1,19,1); interrumpe cada 4us lo que da una resolucion de 0.36º, 500 posiciones para 180º
-setup_timer_2(T2_DIV_BY_1,39,1); interrumpe cada 8us lo que da una resolucion de 0.72º, 250 posiciones para 180º

Y asi podemos seguir buscando la resolucion que queremos para nuestro bucho, no?

Me estoy equivocando? porque esto me parece demasiado bonito y facil... el problema de este sistema puede estar en el tiempo que tarda en ejecutar las instrucciones, no? porque si tomamos la resoluciond e 1000 posiciones para 180º, tenemos una interrupcion cada 2us, si la frecuencia del reloj es de 20Mhz, su periodo es de 0.05us, si cada instruccion (en ASM) tarda 4 ciclos, tenemos que ejecuta una instruccion cada 0.2us, asi que podemos poner menos de 10 instrucciones en ASM si no queremos problemas... creeis que esto es un problema al programar en C? por otro lado, si usamos la resolucion de 250 posiciones, tenemos una interrupcion cada 8us, lo que nos deja hasta 40 instrucciones de ASM...

Una de las cosas a tener en cuenta en ese periodo de 2ms de alto trabajo del TMR2 es que hay que desactivar todas las interrupciones y dejar al micro que se dedique plenamente al TMR0, no creeis?

Responder
mif
Respuestas: 1095
 Mif
Topic starter
(@mif)
Noble Member
Registrado: hace 19 años

Vale, el codigo que he escrito es este:

#include "C:ProyectosTBC 2.0TMR2TMR2.h"
int8 EstadoTMR2=0; //0 indica que esta en el periodo de 13.1ms, al acabar se pasa a estado 1 y se configura para 4.9ms
//1 indica que esta en el periodo de 4.9ms, al acabar se pasa a estado 2 y se configura para los 2ms restantes, dedicacion plena del micro
// en estado 2 se configurara el TMR2 para una resolucion de 250 posiciones:
// setup_timer_2(T2_DIV_BY_1,39,1); interrumpe cada 8us lo que da una resolucion de 0.72º, 250 posiciones para 180º
//se contara entonces con una variable tipo int8 (PosServo) el numero de interrupciones de TMR2
int8 PosServo=124;
int8 ServoActual=0; //Variable que indica la posicion actual del tiempo en alto del servo
int8 ServoMax = 250; //Posicion final del servo
int flag=0;

#int_TIMER2
TIMER2_isr()
{
switch (EstadoTMR2)
{
case 2:
ServoActual++;
if (ServoActual==PosServo)
{
output_bit(LedR, 0); //#define LedR 49 //PIN_B1 -> Led Rojo
output_bit(Servo1, 0); //#define Servo1 56 //PIN_C0 -> Servo 1
}

if (ServoActual==ServoMax)
{
EstadoTMR2 = 0;
ServoActual = 0;
setup_timer_2(T2_DIV_BY_16,255,16);
}

case 1:
//disable_interrupts(INT_RDA);
output_bit(LedR, 1);
output_bit(Servo1, 1);
setup_timer_2(T2_DIV_BY_1,39,1);//1 indica que esta en el periodo de 4.9ms, al acabar se pasa a estado 2 y se configura para los 2ms restantes, dedicacion plena del micro
EstadoTMR2 = 0;

case 0: //0 indica que esta en el periodo de 13.1ms, al acabar se pasa a estado 1 y se configura para 4.9ms
output_bit(LedR, 0);
setup_timer_2(T2_DIV_BY_16,96,16); //Configuracion del TMR2 a 4.9ms
EstadoTMR2 = 1;
break;
}
}

void main()
{
Presentacion();
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DIV_BY_16,255,16);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
}

pero por alguna extraña razon no consigo que entre en la interrupcion TIMER2_isr()... empiezo a sospechar que hay problemas con el pic o con el Bootloader, porque he probado de todo, hasta encender un led nada mas al entrar por primera vez en la interrupcion, y no hace ni eso... que raro, porque los demas programas me funcionan en el robot, solo me falla este, en el que uso el TMR2... mañana seguire investigando que hoy ya es tarde.

Responder
ranganok
Respuestas: 3875
(@ranganok)
Ardero
Registrado: hace 19 años

Mif, porque no usas el TMR1 comno base de tiempos (con los 16 bits de resolución)??

Haces que levante un flag por interrupción cada Xms y en programa principal pones unos contadores que hagan las cosas (pe. movimiento de servos) cada vez que detecten el flag.

Más o menos así (en pseudocódigo):

//Interrupción TIMER 1
void interrupt_TR1()
{
//Desactivar interrupción TR1
flag = 1;
//Activar interrupción TR1
}

void main()
{
bit flg2, flg4, flg8
//(...) Ejecución del código
if(flag) //Interrupción de X ms
{
flag=0;
//(...) código que se ejecuta cada Xms
flg2++;
if(flg2)
{
flg2 = 0;
//(...) código que se ejecuta cada X*2 ms
flg4++;
if(flg4)
{
flg4 = 0;
//(...) código que se ejecuta cada X*4 ms
//(...) etc...
}
}

}
}

S2

Ranganok Schahzaman

Responder
TumBos
Respuestas: 158
(@tumbos)
Estimable Member
Registrado: hace 19 años

Tambien estoy con el calculo del TMR1 para intentar mover varios servos. ¿cual es la mejor resolución/recursos? es decir, ¿que precision es suficiente para un servo convencional? supongo que la aplicacion es la que manda, pero tambien supongo que habrá un valor por debajo del cual ya no ganes precision. ¿y que salto en microsegundos usan el emisor/receptor de aeromodelismo por ejemplo? a ver me estoy pasando en precision 😆
¿sabeis de algún ejemplo de fuente en C para mover varios servos?

Un saludo

Responder
Página 2 / 2
Compartir: