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