Autor Tema: Duda Joystick y CCS  (Leído 1900 veces)

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

Desconectado Cloudff7

  • PIC10
  • *
  • Mensajes: 5
Duda Joystick y CCS
« en: 09 de Julio de 2015, 19:54:57 »
Duda Joysticks y CCS

Versión CCS 4.104
Nivel de Programación: Intermedio
Referencias: Servomotores, ADC, PWM, Joystick


Hola amigos del foro,
Actualmente me encuentro realizando un trabajo para mi experiencia recepcional que es el control de un brazo robotico por medio de Joysticks, lo cual prácticamente esta todo ya echo.

Como todos saben los Joysticks (en su mayoría no son mas que potenciometros)
por lo que al activar la lectura analógica del Micro puedo hacer la respectiva conversión para posicionar un servomotor en base al ancho de pulso calculado.

Hasta ahí todo bien, pero como algunos ya imaginaran el Joystick siempre regresa a su punto de origen(centro) al dejar de aplicarle una fuerza; por lo que mi servomotor se va a posicionar a 0º(o el angulo que haya calculado para ese valor del ADC que en este caso digamos que es 128, suponiendo una conversión a 8 bits).

La parte de mi código que se encarga de la lectura es el siguiente:

Código:
#include PIC18F4550.h;
#device ADC=10
#FUSES HSPLL,NOPROTECT, NODEBUG,NOWRT,MCLR,PLL5
#use delay(clock=1000000)
#include lcd.c;
#include stdlib.h;
#include math.h;
#define M PIN_E0 // STANDBY
#define A PIN_D0 // Motor 1   //Defino la seccion de los motores (2 motores x seccion)
#define B PIN_D1 // Motor 2
#define C PIN_D2 // Motor 3

int duty=21;
int16 IMP;  
int16 PWM;
int16 IMP1;  
int16 PWM1;  

//***************************Seleccion de Servos******************************//
void main(void){

setup_CCP1(CCP_PWM);
setup_CCP2(CCP_PWM);
setup_timer_2(T2_DIV_BY_16,255,1);
setup_comparator(NC_NC_NC_NC);
setup_oscillator(OSC_1MHZ|OSC_INTRC);
setup_adc_ports( AN0_TO_AN1 );
setup_adc(ADC_CLOCK_INTERNAL);
goto STANDBY;

//Menu para seleccionar la sección
STANDBY:
output_high(PIN_D0);
                do{
    
                    if (input(A)){
    output_LOW(PIN_D0);
        goto MOTORBASEBRAZO;
                  }
                    if (input(B)){
    output_LOW(PIN_D0);
        goto MOTORCODO;
                  }
                    if (input(D)){
    output_LOW(PIN_D0);
        goto MOTORMUNECA;
                  }
                  }while(TRUE);
  
MOTORBASEBRAZO:
//Lectura ADC y posicionamiento del ADC a la variable PWM
do{
output_high(PIN_D3);
if (input(M)){
goto STANDBY;
}
while(true)
{
set_adc_channel(0); //Eje x
delay_ms(30);  
IMP=read_ADC();
PWM=(IMP/8)+20;
set_pwm1_duty(pwm);                        



set_adc_channel(1); //Eje Y
delay_ms(30);                            
IMP1=read_ADC();
PWM1=(IMP1/8)+20;
set_pwm2_duty(pwm1);

 if (input(M)){
 output_LOW(PIN_D3);
        goto STANDBY;
 }
 }
}while(TRUE);

}

Nota: El código esta incompleto ya que como verán tengo 3 secciones y en esta solo estoy poniendo una, pero en todas utilizo la misma lógica por lo que omito ponerlas para no hacer muy largo el código, también uso el ADC a 10 bits, pero planeo dejarlo en 8 por lo que la lógica sigue siendo la misma.

Mi pregunta es: ¿Que podría hacer para que cuando deje de aplicar fuerza al Joystick y empiece a regresar al centro, mi servo no regrese junto con el(por así decirlo) si no que se quede en la ultima posición en la que lo deje.

Izquierda:
Valor del ADC desde 0-127
Centro:
Valor del ADC 128
Derecha:
Valor del ADC 129-255

¿Podrían darme alguna idea? he pensado varias cosas pero no me caería nada mal algún consejo. ...

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Duda Joystick y CCS
« Respuesta #1 en: 09 de Julio de 2015, 20:15:43 »
En ves de usar una logica de ...

IMP=read_ADC();
PWM=(IMP/8)+20;
set_pwm1_duty(pwm);  


En el que el valor del PWM depende exclusivamente del ADC.
Podrias utilizar otra "logica" o forma de pensamiento.

Sabiendo que tenes el centro y tiene un valor, supongamos 0x01FF.
Definis una guarda alrededor de ese punto supongamos +-0x30 en el que no se mueve para nada el valor del PWM. De ahora en adelante voy a suponer que va para un lado nomas el potenciometro para que sea mas simple

Divido el rango de mi potenciometro en varias partes y que van a tener una caracteristica, segun el valor del ADC va a incrementarse una cierta cantidad el duty del PWM ( esto es un solo lado, si es para el otro lado es decrementarse )

0x1FF ---------- 0x22F ------------  0x2CF ----------  0x36F ------------- 0x3FF
           +0                      +1                     +2                       +3

Entonces uso un timer que por ejemplo cada 250ms actualize el valor del duty del PWM,entonces cada 250ms, se fija que valor tiene el ADC, si por ejemplo esta en 0X2FF, al duty que tengo lo aumento en 2. Siempre limitandolo al maximo ( creo que acepta hasta 1024 el set_pwm_duty() )

Esto daria una sensacion de variacion de velocidad segun vas moviendo el joystick para un lado o para el otro. y cuando lo soltas no se mueve para ningun lado. Por otra parte esa "guarda" te proteje de que si el potenciometro no quedo muy centrado no aumente o decremente.

Como dije usas un timer, asi que esto lo podes hacer de 2 formas:
- Cada seccion incrementa en una cantidad distinta como hice el ejemplo, y se incrementa en un tiempo "fijo" 250ms segun mi ejemplo.
- O podes incrementar siempre 1, pero cada seccion modifica el tiempo de ese incremento (resumiendo le cambias el valor que le cargas al timer), ejemplo:

0x1FF ---------- 0x22F ------------  0x2CF ----------  0x36F ------------- 0x3FF
           +0                      +1                     +1                       +1
                                   300ms                 150ms                  100ms

- O pones un tiempo fijo mas chico y contas la cantidad de veces a entrar.. Si esta en la zona de 0x22F a 0x2CF que entre 3 veces , la siguiente 2 y la otra 1 antes de incrementar el duty

Es lo unico que se me ocurre.

Otra cosa aunque todo parezca muy lindo pueden haber problemas.
El principal es que si tu PIC aumenta demasiado rapido el duty y tu servo no puede seguirlo, cuando vuelva a la posicion de 0 el servo va a seguir moviendose, asi que la velocidad con que aumentes el duty tiene que ser tal que tu servo pueda seguirlo.
Seguro que se puede solucionar con mas elementos en el circuito pero eso significa complicarla mucho mas. Y si no queres complicarla mucho podes hacer directamente:

0x1FF ---------- 0x22F ------------ 0x3FF
           +0                      +1      

Y solo tenes una velocidad, la fijas vos cuanto aumenta y listo :) Y ahi si podes reemplazar el codigo que puse arriba por un:
Código: C
  1. int IMP,X;
  2. IMP=128;   //Comienza centrado
  3. #define VELOCIDAD 1
  4.  
  5. while(1)
  6. {
  7.    X = read_ADC()                                                   //Leo el ADC (8bits)
  8.    if(X>140)                                                           // Valor Centro(128) + guarda(12), asi para la derecha
  9.    {
  10.       if( IMP > (255-VELOCIDAD) ) { IMP=255; }          // Me asguro que si sumo no supere los limites, sino lo pongo al limite
  11.       else { IMP+= VELOCIDAD; }
  12.    }
  13.    else if ( X<116 )                                                // Lado izquierdo, Centro - guarda(12)
  14.    {
  15.       if( IMP < VELOCIDAD ) { IMP=0; }                    // Cambio la posicion, siempre y cuando pueda ir restando
  16.       else { IMP-= VELOCIDAD; }
  17.    }
  18.    PWM=(IMP/8)+20;                                             // Calculo la posicion en base a IMP que es de 0 a 255 y no incrementando de a 1, es una conversion mas simple ( por la formula podria haber hecho IMP de 0 a 32 )
  19.    set_pwm1_duty(pwm);                                      //  Seteo duty, si fuera estuvierae en el centro el joystick, el PWM no cambiaria ya que no se modificaria IMP
  20. }
(En ese codigo use un ADC de 8 bits como lo planteaste)

------------------------

Con respecto a la programacion, evita el uso de GOTO, por que es una instruccion en ASM mas que para C, el compilador se maneja de una forma y que me parece que no tenes clara logrando hasta un stack overflow.
Si queres salir de un while() usa break;
« Última modificación: 09 de Julio de 2015, 22:33:43 por KILLERJC »


 

anything