problema de punto flotante utilizando PIC18F4550

1

Estoy haciendo un robot para evitar obstáculos y usando el controlador PIC mencionado. Actualmente no estoy en el obstáculo para evitar una parte, así que lo que estoy haciendo es escribir un código para controlar el movimiento, por ejemplo. Haciéndolo ir en un bucle rectangular. La forma en que funciona es que he creado funciones para ir en línea recta, girar a la izquierda / derecha y una para una pequeña detención de 2 segundos en ambas ruedas, llamada pausa. En la función recta paso un valor de RPM y una distancia, la función tiene que averiguar cuánto tiempo debe mantenerse esta velocidad para recorrer la distancia especificada. Para ello, pasa los datos a una función count_cal que devuelve el valor de los conteos que se utilizarán y luego se establecen las velocidades de la rueda y los conteos se envían a una función de temporizador para producir el tiempo deseado. Ahora el problema es que la función count_cal no está funcionando y creo que es debido a los flotadores que he usado y de alguna manera la conversión de flotar a largo no produce lo que se supone. La función del temporizador y el resto funcionan desde que pasé directamente los conteos directamente al temporizador y pasé por alto el count_cal, todo funcionó bien. Pero ignorarlo no es realmente una opción y necesito ayuda porque estoy fuera de mi alcance con estas cosas de punto flotante en los microcontroladores. Cuando intento este código como se muestra aquí, lo que sucede es que actúa como si no hubiera demora en las funciones de giro y giro a la izquierda, pero funciona bien para la pausa ya que he pasado los conteos manualmente allí.

Estoy mostrando código solo para la función recta e ignorando turn_right / left y pause porque son exactamente similares en su función.

Aquí está la parte del código relevante:

//----------FUNCTION DECLARATIONS-----------//

void send_pos_right (int data);              //Transmit sequence to right wheel(forward)
void send_pos_left (int data);               //Transmit sequence to left wheel(forward)
void straight(int rpm, float dist);         //go straight at certain rpms for certain dist
void turn_left(void);                       //make 90 degree left
void turn_right(void);                      //make 90 degree right
void pause(void);                           //halt both wheels for a brief time (2sec)

void timer(unsigned long counts);                 //produces required time delay based on counts
unsigned long counts_cal (int rpm, float dist);   //calculates number of counts required for travel

//..........GLOBAL VARIABLES...........//

float circum = 0.3989823;           //circumference of wheels
float mc = 0.0000512;               //timer period with 256 prescaler
int turning_rpm = 30;               //standard turning velocity
float turning_dist = 0.44;          //distance to make a 90 degree turn

//............MAIN CODE.............//

void main(void)
{

while(1)
{
    straight(60,4);
    pause();
    turn_left();
    pause();

   }
}

void straight(int rpm, float dist)
{
    unsigned long counts = counts_cal(rpm,dist);
    send_pos_right(rpm);
    send_pos_left(rpm);
    timer(counts);
}

void timer(unsigned long counts)
{
    unsigned char loader_H, loader_L;
    int reps = counts/65536;                        //calculates number of complete reloads required
    unsigned long sub_reps = counts-(reps*65536);   //calculates number of counts required after the complete reloads (semi relaod)
    long value = 65536 - sub_reps;                  //calculates value to load into TMR0H & TMR0L for the semi reload
    T0CON = 0x07;                                   //timer off, 256 prescaler

    while(reps>0)                   //performs the number of complete 16bit timer reloads
    {
        TMR0H = 0x00;
        TMR0L = 0x00;
        T0CONbits.TMR0ON=1;
        while(INTCONbits.TMR0IF==0);
        T0CONbits.TMR0ON=0;
        INTCONbits.TMR0IF=0;
        reps-=1;
    }

    if ((reps==0) && (sub_reps>0))  //performs the semi 16bit timer reload
    {
        loader_H = (value&0xFF00)>>8;
        loader_L = (value&0x00FF);
        TMR0H = loader_H;
        TMR0L = loader_L;

        T0CONbits.TMR0ON=1;
        while(INTCONbits.TMR0IF==0);
        T0CONbits.TMR0ON=0;
        INTCONbits.TMR0IF=0;
    }

}

unsigned long counts_cal (int rpm, float dist)
{
    float rps = rpm/60.0;
    float v = circum * rps;
    float t = dist/v;
    float temp = t/mc;
    unsigned long counts = (unsigned long)(temp);
    return(counts);                                 //returns counts which are required to produce desired time delay
}
    
pregunta Hameem

1 respuesta

1

Así que, de alguna manera, descubrí cómo hacer que esto funcione. Lo que había hecho anteriormente era esto;

unsigned long counts_cal (int rpm, float dist)
{
    float rps = rpm/60.0;
    float v = circum * rps;
    float t = dist/v;
    float temp = t/mc;
    unsigned long counts = (unsigned long)(temp);
    return(counts);                                 //returns counts which are required to produce desired time delay

}

Pero luego noté que las flotaciones causaban problemas cuando comparaba las flotaciones con las ints y pensé que podría deberse a errores de truncamiento al convertir a int o long, así que probé algo un poco diferente y reduje los primeros 5 líneas en 1 línea después de una cierta manipulación algebraica y funcionó. Creo que esto funcionó porque ahora todas las multiplicaciones ocurren antes de la división y luego, cuando se produce la división + conversión, el valor truncado tiene un error muy perdonable (apagado por menos de 100 ms de lo que he observado). Los PWM se mantienen para el tiempo requerido y todo está bien. El método de trabajo fue este;

unsigned long counts_cal (int rpm, float dist)
{
    unsigned long counts = (dist*60*78125)/(4*circum*rpm);
    return(counts);

}
    
respondido por el Hameem

Lea otras preguntas en las etiquetas