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% при блокировке вала, только нестабильно это как-то все получается. В чем может быть причина? Может у меня испульсов с энкодера слишком мало? Или может какой-то другой способ поддержания заданных оборотов существует?
Аватара пользователя
wrgcpp
 
Сообщения: 52
Зарегистрирован: 22 янв 2015, 01:43
Откуда: Нижний Тагил
прог. языки: C, C++, Tcl

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

Сообщение Radist » 22 янв 2015, 18:39

Как настроить ПИД регулятор для данного случая - я не знаю. Но может быть пойти с другой стороны? Пропеллерные часы можно очень точно застабилизировать, обороты будут стабильными. Сделать не пид регулятор с шимом, а стабилизатор скорости вращения, управляемый напряжением.
Аватара пользователя
Radist
 
Сообщения: 2254
Зарегистрирован: 01 июл 2009, 08:59
Откуда: Екатеринбург
прог. языки: асемблер AVR

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

Сообщение Aseris » 22 янв 2015, 20:21

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

Плюс вопрос что ты считаеш обороты за секунду или время между импульсами, проанализируй процесс.
Аватара пользователя
Aseris
 
Сообщения: 1142
Зарегистрирован: 01 сен 2009, 14:58
Откуда: Чехия
прог. языки: C/С++, VHDL, Verilog, ASM, Python

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

Сообщение wrgcpp » 22 янв 2015, 21:05

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


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

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


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

А почему стоит брать высокий D коэффициент?
Аватара пользователя
wrgcpp
 
Сообщения: 52
Зарегистрирован: 22 янв 2015, 01:43
Откуда: Нижний Тагил
прог. языки: C, C++, Tcl

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

Сообщение Aseris » 22 янв 2015, 22:51

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

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

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

По коду не понял откуда появляются значения обратной связи для ПИД и зачем там -3?
Код: Выделить всёРазвернуть
...pid_compute(encoder[RIGHT]-3,....
Аватара пользователя
Aseris
 
Сообщения: 1142
Зарегистрирован: 01 сен 2009, 14:58
Откуда: Чехия
прог. языки: C/С++, VHDL, Verilog, ASM, Python

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

Сообщение wrgcpp » 22 янв 2015, 23:06

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

encoder[] объявлен в другом файле, в этот массив заносятся количество срабатываний левого и правого энкодера соответственно. Весь код который это делает, работает верно, к нему претензий нет, поэтому его сюда не привел. А -3 потому что я сделал такой временный грязный хак, чтобы телега ехала прямо, а не по кривой примерно метра 2 радиусом :) . Регулятор я все таки настроил с горем пополам, для этого пришлось увеличить время между вызовами pid_process() до 500мс, теперь вроде не дёргается. А вот на счет идеи мерять время между двумя импульсами энкодера надо бы подумать. Только вот как мерять время? Только Timer/Counter1 вроде такое может, а он всего один, или я ошибаюсь?
Аватара пользователя
wrgcpp
 
Сообщения: 52
Зарегистрирован: 22 янв 2015, 01:43
Откуда: Нижний Тагил
прог. языки: C, C++, Tcl

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

Сообщение Radist » 23 янв 2015, 07:29

По стабилизатору частоты вращения: http://www.530.ru/electronics/projects.php?do=p055
Посмотрите, как его допилить чтоб с энкодерами работал. Подстроечник замените цапом на шиме - и никаких регуляторов.
Аватара пользователя
Radist
 
Сообщения: 2254
Зарегистрирован: 01 июл 2009, 08:59
Откуда: Екатеринбург
прог. языки: асемблер AVR

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

Сообщение wrgcpp » 23 янв 2015, 18:21

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

У меня с аналоговой электроникой всё плохо. Собрать один в один по схеме я конечно смогу, а вот наладить у меня врятли выйдет.
Аватара пользователя
wrgcpp
 
Сообщения: 52
Зарегистрирован: 22 янв 2015, 01:43
Откуда: Нижний Тагил
прог. языки: C, C++, Tcl


Вернуться в Новичкам или основы основ роботостроения.

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 9