estrategia PWM para motor con carga variable

1

Tengo un controlador de motor Raspberry Pi y PWM que maneja un chasis DAGU con orugas. Cada una de las ruedas motrices tiene su propio codificador de 8 polos, y cuento un borde ascendente o descendente como "tic". Así que hay 22.5 grados / tick. Los motores están engranados 48: 1.

Las pistas y las ruedas proporcionan una carga desigual al motor en cada rotación completa. En otras palabras, en el transcurso de una rotación completa, el motor (o su mano) encontrarán las pistas más fáciles de girar en algunos puntos y más difíciles en otros. Esto se debe a que las ruedas / peldaños están un poco fuera de lugar.

Esto hace que mi bucle PWM también oscile. No estoy seguro de cómo "sintonizar" esto sin embargo. Lo primero que se piensa es calcular el error durante un período de tiempo más largo, pero luego los motores tardan una eternidad en ponerse al día.

¿Hay una estrategia general para esto, o debería usar algo como:

if motor is stopped
  use fast PWM rate
otherwise if motor has been moving for a while
  use a slower rate

Disculpas si este es el sitio SE incorrecto. No estaba seguro de si aquí o TAN sería correcto.

Bucle principal:

    #define MOTOR_TICK_DELAY    1000000000LL //1000ms
    motorA.target = 1.5;
    motorB.target = 1.5;

    debug("Standby off.\n");
    bcm2835_gpio_set(STBY);

    struct timespec time;
    uint64_t cTime = 0, lTime = 0, refreshTime = 0, lTimeA = 0, lTimeB = 0;
    int timeCount = 0;

    clock_gettime(CLOCK_MONOTONIC_RAW, &time);
    lTime = time.tv_sec * MOTOR_TICK_DELAY + time.tv_nsec;

    while (quit == 0)
    {
        clock_gettime(CLOCK_MONOTONIC_RAW, &time);
        cTime = time.tv_sec * MOTOR_TICK_DELAY + time.tv_nsec;
        refreshTime = cTime - lTime;

        motorUpdate(&motorA, &cTime, &lTimeA);
        motorUpdate(&motorB, &cTime, &lTimeB);

        if (refreshTime > REFRESH_SPEED)
        {//Refresh the ncurses output}
    }

Método de cálculo de PWM del motor:

void motorUpdate(struct Motor* motor, uint64_t* cTime, uint64_t* lTime)
{
    if (encoderTick(motor->encoderPin)) ++motor->encoderCount;

    uint64_t dt = (uint64_t)(*cTime) - (uint64_t)(*lTime);

    if (dt > MOTOR_TICK_DELAY)
    {
        //debug("ctime: %llu\n", *cTime);
        //debug("ltime: %llu\n", *lTime);
        //debug("diff: %llu\n", dt);

        //actual speed = tick count / (dt in ???seconds)
        motor->actual = (float)motor->encoderCount / (dt / 100000000LL);
        motor->encoderCount = 0; //TODO need rolling average
        *lTime = *cTime; //reset motor last tick time

        //calculate raw PWM
        motor->lastError = motor->error;
        motor->error = (motor->target - motor->actual);
        motor->dError = motor->error - motor->lastError;
        motor->iError += motor->error;
        motor->pwm = (motor->error * 75 + motor->iError * 120 + motor->dError * 5);
        //motor->pwm = (motor->error * 50 + motor->iError * 100 + motor->dError * 10); //pretty smooth, takes a while
        //motor->pwm = (motor->error * 60 + motor->iError * 120 + motor->dError * 10); //a bit jerky, but doesn't overshoot

        //clamp PWM
        if (motor->pwm > PWM_RANGE) motor->pwm = PWM_RANGE;
        else if (motor->pwm < 0) motor->pwm = 0;

        //set PWM
        bcm2835_pwm_set_data(motor->pwmChannel, motor->pwm);
    }
}

El código completo también está disponible aquí: enlace

    
pregunta Nick

2 respuestas

1

En primer lugar, agregue un bucle feedforward con LUT. Para el primer experimento, una LUT se puede calcular como \ $ U_ {estática} = k_ {PWM} \ cdot k_u \ cdot v_ {SP} \ $ Donde \ $ k_u \ $ es la constante del motor \ $ [\ dfrac {V} { rpm}] \ $, \ $ v \ $ es la velocidad \ $ [rpm] \ $, \ $ U_ {static} \ $ are% PWM y \ $ k_ {PWM} \ $ es una constante de su puente H \ $ [\ dfrac {\% PWM} {V}] \ $
Puedes sintonizar cualquier controlador con el método Ziegler-Nichols. A una velocidad muy baja, su codificador no es capaz de proporcionar buena información, por lo que puede implementar un interruptor que desactive el controlador. Comience a configurar con pasos pequeños, primero use solo el controlador P, luego recurra a PI, el PID podría ser solo un dolor de cabeza. OMI, el P-controler es lo que se adapta a su demanda.

    
respondido por el Marko Buršič
1

Figura1.EsteeselkitdecodificadorderuedasdeDAGU,uncomplementosimpleparacualquierrobotconruedasquepuedeayudaramedirlavelocidadoladistanciaquerecorreelchasis.Cadakitdecodificadorderuedaconstadedosimanesdeneodimiode8polosconcubosdegomaydossensoresdeefectoHallterminadosconcablesde150mmycabezalesdeservohembrade3pines.Estoscodificadoresderuedarequierenunatensióndealimentaciónde3-24Vconunacorrientedealimentaciónde4mA.Fuente: Sparkfun .

El codificador tiene 8 polos. El codificador viene con dos sensores, por lo que al colocar estos un múltiplo impar de 360/16 = 22.5 ° podemos duplicar el número de pulsos y duplicar la resolución del codificador de 8 a 16 pulsos por revolución.

simular este circuito : esquema creado usando CircuitLab

Figura 2. Usando dos sensores podemos duplicar la resolución.

simular este circuito

Figura 3. Es posible obtener 32 pulsos por revolución utilizando dos sensores y detección de flanco ascendente y descendente.

Al compensar los sensores con un múltiplo impar de 360/32 = 11.25 °, se pueden sentir 32 bordes del codificador por revolución. Esto tomará dos entradas micro por codificador y un pequeño código de rebote y detección de bordes, pero no debería ser demasiado difícil.

Es posible que esto no resuelva todos sus problemas, pero debería facilitarlos al menos cuatro veces.

    
respondido por el Transistor

Lea otras preguntas en las etiquetas