PID 제어: 현재, 과거, 미래의 오차
P는 현재 오차에, I는 쌓인 오차에, D는 오차의 변화 속도에 반응합니다. 각 항의 효과와 튜닝 순서.
u = Kp·e + Ki·∫e dt + Kd·de/dt
각 항의 역할
| 항 | 반응 대상 | 올리면 |
|---|---|---|
| P | 지금의 오차 | 빨라지지만 오버슈트, 진동 증가. 정상상태 오차 남음 |
| I | 쌓인 오차 | 정상상태 오차 제거, 너무 크면 느린 출렁임 |
| D | 오차 변화 속도 | 오버슈트 억제(브레이크), 노이즈 증폭 |
코드
float pid_step(pid_t *p, float target, float meas, float dt) {
float e = target - meas;
p->integ += p->ki * e * dt;
p->integ = clamp(p->integ, -p->imax, p->imax); // 안티 와인드업
float deriv = -(meas - p->prev_meas) / dt; // 측정값 미분 (목표 급변 시 튐 방지)
p->prev_meas = meas;
return clamp(p->kp * e + p->integ + p->kd * deriv, -p->umax, p->umax);
}
튜닝 순서 (현장식)
- I, D를 0으로 두고 P를 올리며 응답이 빨라지되 진동 직전까지
- P를 조금 낮추고 I를 올려 정상상태 오차 제거
- 오버슈트가 크면 D를 조금 추가 (D 앞에 저역통과 필터)
- 외란(손으로 밀기, 무게 추가)을 주고 회복을 확인
실험실의 PID 3D 시뮬레이션에서 게인을 바꾸며 각 항의 효과를 눈으로 확인해 보세요.
그림으로 보기: 게인에 따른 응답
세 항이 하는 일
| 항 | 보는 것 | 올리면 | 지나치면 |
|---|---|---|---|
| P | 지금의 오차 | 반응이 빨라짐 | 출렁임, 발산 |
| I | 쌓인 오차 | 남은 오차가 사라짐 | 오버슈트, 느린 출렁임 |
| D | 오차가 변하는 속도 | 출렁임이 줄어듦 | 노이즈에 떨림 |
P만 쓰면 목표 근처에서 오차가 조금 남습니다. 오차가 0이면 출력도 0이 되는데, 부하를 이기려면 출력이 필요하기 때문입니다. 이 남은 오차를 I가 시간을 들여 없앱니다.
3D 실험실여기까지 읽은 내용을 직접 돌려 볼 수 있습니다→실제로 쓰는 코드
typedef struct { float kp, ki, kd, integ, prev_meas, out_min, out_max; } pid_t;
float pid_update(pid_t *p, float target, float meas, float dt) {
float err = target - meas;
float d = -(meas - p->prev_meas) / dt; // 측정값을 미분 (목표 급변에 튀지 않음)
p->prev_meas = meas;
float out = p->kp * err + p->integ + p->kd * d;
if (out > p->out_max) out = p->out_max; // 출력 제한
else if (out < p->out_min) out = p->out_min;
else p->integ += p->ki * err * dt; // 포화되지 않았을 때만 적분
return out;
}
교과서 식과 다른 점이 두 가지 있습니다.
- 적분 와인드업 방지: 출력이 한계에 붙어 있는 동안에도 적분을 계속 쌓으면, 오차가 반대로 바뀐 뒤에도 쌓인 값이 풀릴 때까지 한참 한쪽으로 밀립니다. 포화 상태에서는 적분을 멈춥니다.
- 측정값 미분: 오차를 미분하면 목표를 갑자기 바꾸는 순간 미분항이 크게 튑니다. 측정값만 미분하면 이 충격이 없습니다.
손으로 튜닝하는 순서
- I와 D를 0으로 두고 P를 올립니다. 출렁이기 시작하면 그 절반 정도로 내립니다.
- I를 조금씩 올려 남은 오차가 적당한 시간 안에 사라지게 합니다.
- 오버슈트가 거슬리면 D를 조금 넣습니다. 떨리면 줄이거나 미분에 저역 통과 필터를 답니다.
한 번에 하나씩, 두 배나 절반으로 크게 바꿔 보며 경향을 먼저 잡는 것이 빠릅니다.
주기가 일정해야 한다
dt가 흔들리면 같은 게인이라도 응답이 달라집니다. 제어 루프는 메인 루프가 아니라 타이머 인터럽트에서 정해진 주기로 돌립니다. 주기는 시스템이 반응하는 속도보다 10배 이상 빠르게 잡습니다. 전류 루프는 수십 μs, 속도 루프는 1 ms, 온도 제어는 100 ms 정도가 흔한 값입니다.
현업에서 자주 터지는 문제
- 부호가 반대로 연결되어 오차가 커질수록 더 밀어내는 양의 피드백
- 센서 노이즈가 D항으로 증폭되어 모터에서 소리가 남
- 제어 주기보다 느리게 갱신되는 센서 값을 그대로 미분
- 단위를 섞어 써서 게인의 의미가 달라짐(rad와 deg, 초와 ms)
영상으로 이어 보기모터 시리즈 10편세상을 움직이는 힘 = DC모터, 이 영상 하나로 정리해드립니다.PROJECT COURSEPID를 실제 로봇에서 튜닝해 보고 싶다면밸런싱 로봇 하나를 요구사항, 회로와 PCB, 펌웨어, 앱까지 실무 순서대로 만드는 강의입니다. 10파트 165강.강의 살펴보기 →FREE PDF무료 전자책 3권 받기이 주제를 한 권으로 이어서 읽고 싶다면. BLDC 모터 제어, 직렬통신, 센서를 책 분량으로 묶었습니다. 이메일만 남기면 바로 받습니다.무료로 받기 →