roboforum.ru

Технический форум по робототехнике.

Помогите настроить PID регулятор

Помогите настроить PID регулятор

wrgcpp » 22 янв 2015, 13:08

Собрал робота на 3х колёсах из корпуса дисковода. Два ведущих колеса, а третье подруливающее. Мотор-редукторы с ебея, 1:120.
IMG_20150122_134544.jpg
Фото робота

Причем выходной вал выходит у него с двух сторон, с одной стороны крепится колесо, а с другой стороны я приделал диск для энкодера с 20 прорезями.
IMG_20150122_134645.jpg
Фото энкодера

Микроконтроллер на управляющей платке стоит Atmega328, и прерывания с энкодеров заведены на PCINT12 и PCINT13, т.е. обработчик прерывания у них один. Поскольку прорезей на диске не так уж много, а обороты колеса небольшие, я считаю как восходящие фронты, так и падающие, итого у меня получается 40 импульсов энкодера за 1 оборот колеса. Но моторы то разные (хоть и одинаковые :) ), так что крутятся с разной скоростью, и тележка едет по дуге. Поэтому я решил закодить PID регулятор, который бы держал обороты колёс на одном уровне, даже под разной нагрузкой. Вот что у меня получилось
Код: Выделить всёРазвернуть
#include "pid.h"

// желаемая скорость моторов
uint16_t left_speed = 15;
uint16_t right_speed = 15;
// включение и выключение регулятора
uint8_t pid_enable;

static int16_t left_prev_error = 0;
static int16_t right_prev_error = 0;
static float left_integral = 0;
static float right_integral = 0;
static uint8_t overflows = 0;


void pid_init()
{
    // настройка таймера для вызова прерываний
    // предделитель 1024
    TCCR2B |= _BV(CS22) | _BV(CS21) | _BV(CS20);
    TIMSK2 |= _BV(TOIE2);
}

void pid_process(void)
{
    int16_t l_pwm = pid_compute(encoder[LEFT], left_speed, &left_prev_error, &left_integral);
    int16_t r_pwm = pid_compute(encoder[RIGHT]-3, right_speed, &right_prev_error, &right_integral);
    motor_setspeed(MLeft, l_pwm);
    motor_setspeed(MRight, r_pwm);
    encoder[LEFT] = 0;
    encoder[RIGHT] = 0;
}

int16_t pid_compute(int measured, int setpoint, int16_t *prev_error, float *integral)
{
    int16_t error = setpoint - measured;

    int16_t output;
    float derivate;
   
    *integral += (error * PID_INTERVAL);

    if(*integral > MOTOR_MAX_SPEED) *integral = MOTOR_MAX_SPEED;
    if(*integral < MOTOR_MIN_SPEED) *integral = MOTOR_MIN_SPEED;

    derivate = (error - (*prev_error)) / (float)PID_INTERVAL;
    output = (kP * error) + (kI * (*integral)) + (kD * derivate);
    *prev_error = error;
   
    if(output > MOTOR_MAX_SPEED) output = MOTOR_MAX_SPEED;
    if(output < MOTOR_MIN_SPEED) output = MOTOR_MIN_SPEED;
   
    return output;
}

ISR(TIMER2_OVF_vect)
{
    if(overflows < 8){
        ++overflows;
    } else {
        // примерно 1/10 секунды прошла, запускаем пид регулятор
        pid_process();
        overflows = 0;
        PORTC ^= _BV(Led);
    }
}


Желаемая скорость моторов задана переменными left_speed и right_speed (в импульсах энкодера, т.е. скорость 15 соответствует 15 импульсам энкодера). Функция pid_process() обслуживает прерывания и вызывается примерно раз, в 261мс, после восьми пререполнений таймера 2. Частота контроллера 8МГц, предделитель таймера 1024. Используемые макросы объявлены в def.h, вот его часть
Код: Выделить всёРазвернуть
/**********************************
*   коэффициенты ПИД-регулятора  *
**********************************/

#define kP              7
#define kI      0.08
#define kD      0.002

#define PID_INTERVAL 261

/*******************************
*   настройки моторчиков      *
*******************************/

#define MOTOR_MAX_SPEED    255
#define MOTOR_MIN_SPEED    0

Проблема в том, что я никак не могу подобрать правильные коэффициенты для регулятора, уже пробовал по всякому. И код вроде верный все перепроверил. А моторчики все равно крутятся неравномерно и с рывками, движения по прямой так получить и не удалось. Я ожидал, что когда колесо псовсем заблокировано (ну или на грани блокировки), регулятор будет увеличивать мощность моторов до максимума, но нет, я вчера осциллом смотрел, может 2/3 заполнение только. Если увеличивать пропорциональный коэффициент, то можно добиться мощности 100% при блокировке вала, только нестабильно это как-то все получается. В чем может быть причина? Может у меня испульсов с энкодера слишком мало? Или может какой-то другой способ поддержания заданных оборотов существует?

Re: Помогите настроить PID регулятор

Radist » 22 янв 2015, 18:39

Как настроить ПИД регулятор для данного случая - я не знаю. Но может быть пойти с другой стороны? Пропеллерные часы можно очень точно застабилизировать, обороты будут стабильными. Сделать не пид регулятор с шимом, а стабилизатор скорости вращения, управляемый напряжением.

Re: Помогите настроить PID регулятор

Aseris » 22 янв 2015, 20:21

C переменной нагрузкой неполучится, пид ты можеш настроить ток на определенные условия. Читай теорию, настройка PID.
А если быстрый совет - возьми высокий D коефт..

Плюс вопрос что ты считаеш обороты за секунду или время между импульсами, проанализируй процесс.

Re: Помогите настроить PID регулятор

wrgcpp » 22 янв 2015, 21:05

Radist писал(а):Сделать не пид регулятор с шимом, а стабилизатор скорости вращения, управляемый напряжением.


Спасибо за ответ, можно ли поподробнее? Первый раз про такие стабилизаторы слышу.

Добавлено спустя 4 минуты 5 секунд:
Aseris писал(а):Плюс вопрос что ты считаеш обороты за секунду или время между импульсами, проанализируй процесс.


Имеете в виду что есть такое left_speed и right_speed? Это количество импульсов с энкодера за промежуток между вызовами process_pid(). Знаю, что к скорости это сложно отнести, просто мне так удобнее. Допустим я выставил скорость равную 25. Это значит, что я хочу, чтобы колесо вращалось с такой скоростью, что с энкодера за 261мс (т.е за интервал времени между вызовами process_pid()) пришло 25 импульсов.

А почему стоит брать высокий D коэффициент?

Re: Помогите настроить PID регулятор

Aseris » 22 янв 2015, 22:51

wrgcpp писал(а):А почему стоит брать высокий D коэффициент?
Недавно делал подобное, так вот D пришлось взять большой чтоб система не колебалась.

В идеале мерять время между двумя импульсами енкодера, ибо ты незнаеш реально сколько оборотов было за твои 261 мс, либо напр 1.0 либо 1.1/20 а для того чтоб телега криво ехала етого хватит.

Далее за 261 мс телега на пару сантиметров уедет, т.е. неправильно выбраный дисрет реакции системы...
Вобщем думай, смотри на тележку и прикидывай ее поведение. Плюс в реальном мире робот всеравно по синусоиде будет ехать.

По коду не понял откуда появляются значения обратной связи для ПИД и зачем там -3?
Код: Выделить всёРазвернуть
...pid_compute(encoder[RIGHT]-3,....

Re: Помогите настроить PID регулятор

wrgcpp » 22 янв 2015, 23:06

Aseris писал(а):По коду не понял откуда появляются значения обратной связи для ПИД и зачем там -3?
Код: Выделить всёРазвернуть
...pid_compute(encoder[RIGHT]-3,....

encoder[] объявлен в другом файле, в этот массив заносятся количество срабатываний левого и правого энкодера соответственно. Весь код который это делает, работает верно, к нему претензий нет, поэтому его сюда не привел. А -3 потому что я сделал такой временный грязный хак, чтобы телега ехала прямо, а не по кривой примерно метра 2 радиусом :) . Регулятор я все таки настроил с горем пополам, для этого пришлось увеличить время между вызовами pid_process() до 500мс, теперь вроде не дёргается. А вот на счет идеи мерять время между двумя импульсами энкодера надо бы подумать. Только вот как мерять время? Только Timer/Counter1 вроде такое может, а он всего один, или я ошибаюсь?

Re: Помогите настроить PID регулятор

Radist » 23 янв 2015, 07:29

По стабилизатору частоты вращения: http://www.530.ru/electronics/projects.php?do=p055
Посмотрите, как его допилить чтоб с энкодерами работал. Подстроечник замените цапом на шиме - и никаких регуляторов.

Re: Помогите настроить PID регулятор

wrgcpp » 23 янв 2015, 18:21

Radist писал(а):По стабилизатору частоты вращения: http://www.530.ru/electronics/projects.php?do=p055
Посмотрите, как его допилить чтоб с энкодерами работал. Подстроечник замените цапом на шиме - и никаких регуляторов.

У меня с аналоговой электроникой всё плохо. Собрать один в один по схеме я конечно смогу, а вот наладить у меня врятли выйдет.


Rambler\'s Top100 Mail.ru counter