Si además quieres enviarnos un Artículo para el Blog y redes sociales, pulsa el siguiente botón:
Buenas a todos.
Últimamente he estado mirándome el tema del PWM estoy intentando controlar un servomotor FUTABA 3003, pero tengo dos problemas.
En primer lugar, la mecánica del servo tiene un ángulo de 360 grados (ya que le quite el tope al trucarlo). Pero controlándolo por PWM el ángulo que puedo recorrer del máximo al mínimo es de menos de 50 grados. Me gustaría saber cómo puedo hacerlo para ampliar ese rango.
En segundo lugar, cuando el servo llega a la posición (media, mínima o máxima), se queda vibrando. ¿Eso es normal? En caso de que no lo sea me gustaría saber cómo puedo evitar que vibre. He comprobado que vibra ya que estoy todo el rato enviándole pulsos. ¿Como lo puedo hacer para que cuando el servo este posicionado donde lo quiero pare de enviar pulsos?
Adjunto el código que utilizo para controlar el servo:
#include <16F876A>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES RC //Resistor/Capacitor Osc with CLKOUT
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES BROWNOUT //Reset when brownout detected
#FUSES LVP //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
//------------------------------------------------------------------------------
//Registros
#byte PORTB = 0x06
#byte TRISB = 0x86
//LED
#bit LED = PORTB.1
//SERVOS
#bit servo1 = PORTB.0
//Otros
#define ON 1
#define OFF 0
const int AJUSTE_FINO_DE_RTCC = 61;
const int ticks_PULSO_MINIMO = 62;
const int ticks_PULSO_MEDIO = 93;
const int ticks_PULSO_MAXIMO = 125;
int1 flagRTCC = 0;
int contRTCC = 0;
int1 flagSERVO1 = 0;
int tSERVO1 = ticks_PULSO_MEDIO;
int ValTIMER0;
#int_RTCC
void RTCC_isr()
{
++contRTCC;
if(contRTCC == 4)
{
set_TIMER0(AJUSTE_FINO_DE_RTCC);
}
if(contRTCC == 5)
{
flagRTCC = 1;
contRTCC = 0x00;
}
}
void main(){
//Configuracion
//---------------------------------------------------------------------------
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
//---------------------------------------------------------------------------
setup_counters(RTCC_INTERNAL,RTCC_DIV_16);
// Configura les interrupciones.
enable_interrupts(global);
enable_interrupts(int_RTCC);
// Inicialitza el timer a 0
set_TIMER0(0);
TRISB = 0x00;
PORTB = 0
while(1){
// DISPARO DEL PULSO PWM
if(flagRTCC == 1)
{
flagRTCC = 0;
servo1 = ON;
flagSERVO1 = 1;
}
// CONTROL DE ANCHO DEL PULSO PWM
if(flagSERVO1 == 1)
{
valTIMER0 = get_TIMER0();
if(valTIMER0 > tSERVO1)
{
flagSERVO1 = 0;
servo1 = OFF;
}
}
}
}
Saludos y gracias.
Saludos.
dragonet80, no creo que participe en ninguna competicion en la siguiente CP de momento estoy haciendo un robot "explorador".
Ya he hecho los ejercicios con el LED y tengo claro como funcionan las interrupciones y los timers.
He modificado el código, ahora ya no es un lio. (creo) xD
El problema es que continua sin funcionar:
//------------------------------------------------------------------------------
// Control de SERVO X
//------------------------------------------------------------------------------
// Cuadro de Tiempos :
// Periodo 20 ms (Frecuencia 50 Hz)
// TMR1 a 1:1 -> 1 Desbordamiento cada 5 ms
// -> 1 Tick cada 5 / 65536 = 0.076ms
// -> precarga = 40536
// -> 20 ms = 4 INT_TIMER1 Completas
//------------------------------------------------------------------------------
#include <16F876A>
#device adc=8
#priority timer1
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High Speed
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES BROWNOUT //Reset when brownout detected
#FUSES LVP //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#use delay(clock=20000000)
#use delay(crystal=20000000)
#use standard_io(B)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
// Registros
#byte PORTB = 0x06
#byte TRISB = 0x86
// SERVOS
#bit SERVO1 = PORTB.7
// Misc.
#define ON 1
#define OFF 0
//------------------------------------------------------------------------------
// Funcions
void disparoPulso();
void controlPulso();
// Constants
const int32 precarga = 40536;
const int32 posMin = 13157; // 1ms
const int32 posMid = 19736; // 1.5ms
const int32 posMax = 26315; // 2ms
// Variables
int picoServo1 = 0;
int picoDesbordamiento = 0;
int32 ticksServo1 = posMid;
int contDesbordamientos = 0;
int32 valorTIMER1 = 0;
#INT_TIMER1
void TMR1_Contar()
{
++contDesbordamientos;
set_TIMER1(precarga);
if(contDesbordamientos == 4){
picoDesbordamiento = 1;
contDesbordamientos = 0;
}
}
void main(){
//Configuracion
//---------------------------------------------------------------------------
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
//---------------------------------------------------------------------------
// Configura les interrupciones.
enable_interrupts(global);
enable_interrupts(INT_TIMER1);
TRISB = 0x00;
PORTB = 0x00;
set_TIMER1(precarga);
while(TRUE)
{
disparoPulso();
controlPulso();
}
}
// DISPARO DEL PULSO PWM
void disparoPulso()
{
if(picoDesbordamiento == 1)
{
picoDesbordamiento = 0;
SERVO1 = ON;
picoServo1 = 1;
}
}
// CONTROL DE ANCHO DEL PULSO PWM
void controlPulso()
{
if(picoServo1 == 1)
{
valorTIMER1 = get_TIMER1();
if(valorTIMER1 - precarga > ticksServo1)
{
picoServo1 = 0;
SERVO1 = OFF;
}
}
}
Creo que el problema esta en ese IF, ya que asi el servo no para de dar vueltas, si cambio el signo el servo no se mueve.
if(valorTIMER1 - precarga > ticksServo1)
Si alguien me puede ayudar ^^
Saludos y gracias.
He puesto un delay en el IF y si que entra.
El servo no me interpreta las señales que le envio y actua como si de un motor DC controlado por PWM se tratara.
He desmontado la electronica y he hecho girar el potenciometro manualmente, el motor no responde y sigue en el mismo sentido de giro.
Creo que problema de la electronica no es, ya que me pasa lo mismo con 2 servos y con otro programa el potenciometro si me respondia (aunque lo hiciera mal).
Saludos.
Wolfskin, si estás en la Uni, coge un osciloscopio y mira que señal te saca el micro, a ver si es correcta o le estas mandando algo diferente.
dragonet80, finalmente lo solucione. Tenia los tiempos de los ticks mal.
T_T (menuda tonteria, no se calcular).
Muchas gracias por todo!
Ves, eso, con un osciloscopio lo habrías visto enseguida 😉
Bueno, si no te da tiempo de preparar un velocista, al menos un robotracker tienes que hacer para la campus. La base ya la tienes del año pasado, y tienes los días previos en la campus para la programación 😈