PID 제어

장승현·2023년 3월 22일
0

자율주행

목록 보기
1/3
post-thumbnail

개요

PID제어는 제어공학에 등장하는 제어 방법으로, 자율주행에서 차량의 종방향 제어에 많이 사용된다.

제어공학

제어공학은 동적 시스템의 동작이 원하는 대로 이루어질 수 있도록 연구하는 학문이다. 여기에는 컨트롤 루프(Control Loop)라는 개념이 등장하며, 이를 사용 또는 관리하는 시스템을 제어 시스템(Control System)이라 한다. 이는 두 가지의 종류로, 먼저 개회로 제어 시스템(Open-loop Control System)은 순차 제어, 시퀀스 제어라고도 불리며, 입력에 따라 출력과 상관없이 오차가 많이 발생하는 특징이 있다. 이를 개선한 시스템이 폐회로 제어 시스템(Closed-loop Control System)으로, 피드백 제어라고도 불린다. 폐회로 제어 시스템은 출력값과 목표값을 비교하여 생긴 오차값(error)을 입력값에 반영해 목표값에 도달한다는 특징이 있다. 이를 통해 인간의 개입 없이 자동적으로 목표한 동작을 수행하는 자동 제어가 가능해진다. PID제어는 이 중 폐회로 제어 시스템으로, 실제 응용분야에서 많이 사용되는 대표적인 제어기법이다.

PID제어

PID제어는 출력값과 목표값의 오차에 대하여 비례(Proportional), 적분(Integral), 미분(Differential)을 수행하여 반영하는 제어기법이다. 이를 수식으로 표현하면 다음과 같다.

비례항은 빠른 수렴을 위한 역할을 하며, 적분항은 정상상태(steady-state)의 오차를 없애는 역할을 한다. 미분항은 출력값의 급격한 변화에 제동을 걸어 오버슛(overshoot)을 줄이고 안정성(stability)을 향상시킨다.
경우에 따라 비례(P) 또는 비례-적분(PI), 비례-미분(PD)항만을 가지는 단순화된 형태로 사용하기도 한다.
위 수식은 Kp로 묶어서 정리할 수 있으며, 이 때 Ti는 integral time, Td는 derivative time이라 한다.

튜닝

위의 식에서 각 항이 제 역할을 안정적으로 수행하기 위해서는 적절한 제어 파라미터(Kp, Ki, Kd) 설정이 필요하다. 그 값을 찾아내는 과정을 튜닝(tuning)이라 하며, 이는 수학적 또는 실험적/경험적 방법을 통해 계산된다. 그 중 가장 널리 알려진 것이 실험적 방법인 지글러-니콜스 방법(Ziegler-Nichols Method)이다.
지글러-니콜스 방법은 계단응답곡선을 이용한 방법과 주파수 응답 방법으로 두 가지 방법이 있지만, 계단응답곡선은 적분기가 없고 안정적인 시스템에서만 사용할 수 있다. 주파수 응답 방법은 I 게인 값과 D 게인 값을 0으로 둔 채, P 게인 값만을 0에서부터 점차 올리며 일정한 진동을 반복하는 파형을 만드는 방법이다. 이때의 P 게인 값(임계 이득, Kcr)과 주기(임계 주기, Pcr)를 다음 표에 적용하면 모든 게인 값을 구할 수 있다.

코드 구현

#include <iostream>
#include <cmath>

float control_time{0.1}; // 10Hz
float Kp{0.05}; // p gain
float Ki{0.003}; // i gain
float Kd{0.005}; // d gain
float prev_error{0}, i_terms{0};

float pid(float init_spd, float target_spd){
    float error = target_spd - init_spd;
    float p_terms = Kp * error;
    i_terms += Ki * (error * control_time);
    float d_terms = Kd * ((error - prev_error) / control_time);

    float control_value = p_terms + i_terms + d_terms;
    prev_error = error;
    return control_value;
}

int main(){
    float current_spd{0};
    float target_spd{50};
    float control_value{0};

    while (round(current_spd) != round(target_spd)){
        control_value = pid(current_spd, target_spd);
        current_spd += control_value;
        std::cout<<current_spd<<std::endl;
    };

    return 0;
}

Reference

https://blog.naver.com/PostView.naver?blogId=ycpiglet&logNo=222404466982&categoryNo=91&parentCategoryNo=0
https://namu.wiki/w/%EC%A0%9C%EC%96%B4%EA%B3%B5%ED%95%99
https://ko.wikipedia.org/wiki/PID_%EC%A0%9C%EC%96%B4%EA%B8%B0
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=dkwltmdgus&logNo=220939484841

profile
늦더라도 끝이 강한 내가 되자

0개의 댓글