잠시만요, 달이 떠오르면 글도 환해질 거예요.
#include <stdint.h>
/* =========================
* 速度 PI 控制器
* ========================= */
typedef struct
{
float kp;
float ki;
float integral;
float integral_max;
float output_max;
} SpeedPI_t;
/* 限幅函数 */
static float Limit(float value, float min, float max)
{
if (value > max)
return max;
if (value < min)
return min;
return value;
}
/* 速度 PI 初始化 */
void SpeedPI_Init(SpeedPI_t *pi,
float kp,
float ki,
float integral_max,
float output_max)
{
pi->kp = kp;
pi->ki = ki;
pi->integral = 0.0f;
pi->integral_max = integral_max;
pi->output_max = output_max;
}
/* 速度闭环控制 */
float SpeedPI_Update(SpeedPI_t *pi,
float target_speed,
float current_speed,
float dt)
{
/* 1. 计算速度误差 */
float error = target_speed - current_speed;
/* 2. 更新积分项 */
pi->integral += error * dt;
/* 3. 积分限幅,减轻 Integral Windup */
pi->integral = Limit(
pi->integral,
-pi->integral_max,
pi->integral_max
);
/* 4. PI 控制 */
float output =
pi->kp * error
+ pi->ki * pi->integral;
/* 5. 执行器输出限幅 */
output = Limit(
output,
-pi->output_max,
pi->output_max
);
return output;
}error = target_speed - current_speed;
integral += error * dt;
output = kp * error + ki * integral;typedef struct
{
float kp;
float ki;
float kd;
float integral;
float last_error;
float integral_max;
float output_max;
} SteeringPID_t;
void SteeringPID_Init(SteeringPID_t *pid,
float kp,
float ki,
float kd,
float integral_max,
float output_max)
{
pid->kp = kp;
pid->ki = ki;
pid->kd = kd;
pid->integral = 0.0f;
pid->last_error = 0.0f;
pid->integral_max = integral_max;
pid->output_max = output_max;
}
float SteeringPID_Update(SteeringPID_t *pid,
float target_angle,
float current_angle,
float dt)
{
/* 1. 转角误差 */
float error = target_angle - current_angle;
/* 2. 积分 */
pid->integral += error * dt;
pid->integral = Limit(
pid->integral,
-pid->integral_max,
pid->integral_max
);
/* 3. 微分 */
float derivative =
(error - pid->last_error) / dt;
/* 4. PID 输出 */
float output =
pid->kp * error
+ pid->ki * pid->integral
+ pid->kd * derivative;
/* 5. 输出限幅 */
output = Limit(
output,
-pid->output_max,
pid->output_max
);
/* 保存上一周期误差 */
pid->last_error = error;
return output;
}error = target - feedback;
integral += error * dt;
output = control(error, integral, derivative);
0. 들어가며
실제 기기 제어에서는 이런 문제를 자주 만난다. 구동 모터에 목표 속도
v_{\mathrm{ref}}=3\mathrm{m/s}를 주면, 차량은 정말 그 속도로 안정적으로 주행할까? 조향 모터에 목표 조향각3\mathrm{m/s}을 주면, 앞바퀴는 정말 그 각도를 정확히 유지할까?\delta_{\mathrm{ref}}=10^\circ10^\circ경험에 의존해 모터에 고정된 PWM만 인가한다면, 답은 대개 '아니오'다.
배터리 전압은 변하고, 모터에는 내부 저항과 역기전력이 있으며, 기계 시스템에는 관성과 마찰이 존재한다. 차량은 경사로, 타이어 저항, 그리고 노면의 복원 토크에도 영향을 받는다. 같은 PWM이라도 차량을 공중에 띄웠을 때, 평지에서 달릴 때, 오르막을 오를 때 얻어지는 속도는 대개 전혀 다르다. 조향 모터의 출력이 같아도 정지 상태와 고속 주행 상태에서 실제 조향각은 서로 다를 수 있다.
그래서 실제 제어 시스템이 진짜로 풀어야 하는 문제는 이것이다.
\boxed{\text{输出与目标之间存在误差时,系统应该如何自动修正?}}이것이 바로 폐루프 제어가 해결하려는 문제다.
이 글에서는 폐루프 제어 자체에서 출발해, 구동 모터 속도 루프와 조향 모터 조향각 루프를 함께 살펴보며, 실제 제어 시스템이 어떻게 물리 모델에서 출발해 수학적 모델링, 제어기 설계, 안정성 해석을 거쳐 MCU에서 실제로 돌아가는 제어 알고리즘으로 완성되는지 분석해 본다.
1. 개루프 제어부터
이제 모터 한 대를 제어한다고 해 보자.
가장 간단한 방법은 경험에 따라 모터에 제어량
u(t)를 주는 것이다. 예를 들어 일정한 듀티비의 PWM이 여기에 해당한다. 이 제어량이 모터와 기계 구조를 거쳐 최종적으로 출력y(t)을 만들어 낸다.시스템 관점에서 쓰면 다음과 같다.
u(t)\longrightarrow G(s)\longrightarrow y(t)여기서
G(s)는 제어 대상, 즉 모터, 전동 구조, 타이어, 부하 등 모든 물리적 과정이 함께 이루는 시스템을 뜻한다.구동 모터의 경우에는 간단히 이렇게 이해할 수 있다.
\mathrm{PWM}\longrightarrow\text{驱动电路}\longrightarrow\text{电机}\longrightarrow\text{车轮}\longrightarrow v이런 제어 방식을 개루프 제어라고 한다.
개루프 제어의 문제는 다음과 같다.
하지만 실제 시스템은 분명히 이 조건을 만족하지 않는다.
예를 들어 실험에서 PWM 듀티비를
40%로 주었을 때 차량이 평탄한 노면에서3\mathrm{m/s}의 속도로 안정적으로 주행했다고 하자. 그렇다면 이후로도 계속40%PWM만 출력하면 속도가 영원히3\mathrm{m/s}라고 볼 수 있을까?아니다.
차량이 경사로에 들어서면 부하 토크가 커지고, 배터리 전압이 떨어지면 같은 듀티비에 대응하는 평균 모터 전압이 낮아진다. 타이어 온도, 노면 마찰, 기계 전동 효율, 심지어 차량 질량의 변화까지도 최종 속도를 바꾼다.
그래서 실제 속도는 이렇게 될 수 있다:
v=2.6\mathrm{m/s}, 그런데도 제어기는 여전히 원래의 PWM을 출력한다이것이 개루프 시스템의 가장 근본적인 문제다.
\boxed{\text{控制器没有利用实际输出的信息}}2. 폐루프 제어
시스템이 스스로 오차를 보정하게 하려면, 실제 출력을 다시 제어기로 되돌려 보내야 한다.
시스템의 목표값을
r(t), 실제 출력을y(t)이라 하자.오차를 정의하면:
\boxed{e(t)=r(t)-y(t)}제어기는 이제 경험에 따라 고정된 제어량을 내보내는 대신, 현재 오차
e(t)를 바탕으로 제어 입력을 계산한다:u(t)=C(s)e(t)여기서
C(s)는 제어기를 나타낸다.그러면 전체 제어 과정은 이렇게 된다.
r\longrightarrow e\longrightarrow C(s) \longrightarrow G(s) \longrightarrow y동시에 출력
y는 다시 입력단으로 피드백되어 목표r와 비교된다. 속도 제어를 예로 들면 다음과 같다.e_v(t)=v_{\mathrm{ref}}(t)-v(t)실제 속도가 목표 속도보다 작으면:
e_v>0제어기는 모터 출력을 높인다. 실제 속도가 목표 속도를 넘으면:
e_v<0제어기는 모터 출력을 줄인다. 즉, 폐루프 시스템은 오차를 계속 관찰하면서 제어량을 보정한다.
이것이 폐루프 제어의 가장 중요한 사상이다.
\boxed{\text{不断修正错误直到获得正确的结果}}3. 폐루프 전달함수는 어떻게 구하는가
폐루프 시스템을 더 분석하려면 앞서 살펴본 관계를 수학적 형태로 정리해야 한다.
단위 부궤환 시스템에서:
E(s)=R(s)-Y(s)제어기 출력은:
U(s)=C(s)E(s)제어 대상의 출력은:
Y(s)=G(s)U(s)제어기 관계식을 대입하면:
Y(s)=G(s)C(s)E(s)다시 다음 관계를 이용해
E(s)=R(s)-Y(s)다음과 같이 된다.
Y(s)=G(s)C(s)\left[R(s)-Y(s)\right]그런 다음
Y(s)를 포함하는 모든 항을 정리하면:Y(s)\left[1+C(s)G(s)\right]=C(s)G(s)R(s)따라서:
\boxed{\frac{Y(s)}{R(s)}=\frac{C(s)G(s)}{1+C(s)G(s)}}개루프 전달함수를 다음과 같이 정의하면
L(s)=C(s)G(s)폐루프 전달함수는 이렇게 된다.
\boxed{T(s)=\frac{L(s)}{1+L(s)}}여기서 가장 중요한 부분은 분모다.
1+L(s)폐루프 시스템의 극점은
1+C(s)G(s)=0에 의해 결정되기 때문이다. 그리고 폐루프 극점의 위치는 시스템의 안정성 여부와, 응답이 빠른지 느린지 혹은 진동하는지를 곧바로 좌우한다. 그래서 뒤에서 PI, PID를 설계하는 일은 본질적으로 제어기C(s)를 통해 시스템 전체의 폐루프 극점을 바꾸는 일이다.4. 피드백이 외란에 강한 이유
모형 자동차 한 대가 안정적으로 주행하다가 갑자기 오르막에 들어섰다고 하자. 경사는 구동 시스템에 부하 외란
d(t)을 더한 것과 같다. 개루프 시스템에서는 제어 입력이 변하지 않으므로 차량 속도가 떨어진다. 반면 폐루프 시스템에서는 속도 저하가 곧바로 다음을 일으킨다.v<v_{\mathrm{ref}}그러면 제어기는 모터 출력을 높여 전류와 구동 토크를 키우고, 차량을 다시 목표 속도로 되돌린다. 주파수 영역에서 보면 감도 함수를 정의할 수도 있다.
S(s)=\frac{1}{1+L(s)}여기서
L(s)=C(s)G(s)이고, 우리가 관심을 두는 주파수 범위에서|L(j\omega)|\gg1이라면|S(j\omega)|\approx\frac{1}{|L(j\omega)|}\ll1이 된다. 이는 외란이 출력에 미치는 영향이 폐루프 피드백을 통해 크게 약화된다는 뜻이다. 그래서 간단히 이렇게 이해할 수 있다.\boxed{\text{闭环反馈让系统对扰动具有主动纠正能力}}하지만 그렇다고 해서 게인이 무조건 클수록 좋은 것은 아니다.
루프 게인이 지나치게 높으면, 특히 시간 지연과 고차 동특성이 존재하는 상황에서는 시스템의 위상 지연이 점점 심해져 결국 빠른 응답이 진동으로, 나아가 불안정으로 바뀔 수 있다.
그래서 폐루프 제어에서 진짜로 균형을 맞춰야 하는 것은 다음이다.
\boxed{\text{响应速度}+\text{跟踪精度}+\text{抗扰能力}+\text{稳定性}}5. PID 제어기는 도대체 무엇을 하는가
엔지니어링에서 가장 흔히 쓰는 폐루프 제어기는 바로 PID다.
u(t)=K_p e(t)+K_i\int_0^t e(\tau),d\tau+K_d\frac{de(t)}{dt}여기에는 각각 비례, 적분, 미분 세 부분이 들어 있다.
1. 비례항 P
비례 제어는 다음과 같다.
u_P(t)=K_p e(t)논리는 아주 단순하다. 오차가 클수록 더 강하게 보정한다.
목표 속도가
v_{\mathrm{ref}}=3\mathrm{m/s}이고 실제 속도가 겨우v=2\mathrm{m/s}라면,e_v=1\mathrm{m/s}제어기는
K_p에 따라 그에 맞는 제어 출력을 만들어 낸다.K_p를 키우면 대개 시스템 응답이 빨라지지만, 비례 게인이 너무 크면 목표값을 넘어섰다가 반대로 보정하고, 다시 목표값을 지나치는 과정이 반복되며 결국 진동하게 된다.즉 비례 제어는 다음을 결정한다.
2. 적분항 I
적분 제어는 다음과 같다.
u_I(t)=K_i\int_0^t e(\tau),d\tau적분 제어가 주로 해결하는 문제는 장기간 남아 있는 작은 오차다.
차량 목표 속도가 여전히
v_{\mathrm{ref}}=3\mathrm{m/s}이라고 하자. 경사 부하 때문에 비례 제어가 결국 속도를v=2.9,\mathrm{m/s}에서 안정시켰다면, 이때 오차는 겨우e_v=0.1,\mathrm{m/s}비례 제어가 만드는 보정량만으로는 부하를 계속 이겨 내기에 부족할 수 있어, 시스템은 고정된 오차를 유지하게 된다.
적분을 더하면 다음 조건이 성립하는 한
e_v\neq0\int e_v(t),dt는 계속 누적된다. 오차가 아주 작더라도 충분히 오래 지속되면 적분항은 계속 제어 출력을 키워 결국 오차를 0에 가깝게 만든다.따라서 적분항의 가장 중요한 의미는 다음과 같다.
\boxed{\text{消除恒定参考和恒定扰动产生的稳态误差}}3. 미분항 D
미분 제어는 다음과 같다.
u_D(t)=K_d\frac{de(t)}{dt}이것이 주목하는 것은 오차가 얼마나 빠르게 변하고 있는가다.
시스템이 목표값에 빠르게 접근하고 있는 상황이라면, 현재 오차가 남아 있더라도 미분항이 변화 추세를 근거로 제어 작용을 미리 줄일 수 있습니다. 그래서 미분항은 흔히 시스템 감쇠를 높여 오버슈트와 진동을 억제하는 역할로 이해됩니다. 다만 실제 센서 데이터에는 반드시 노이즈가 섞여 있고, 미분은 고주파 성분을 증폭시킵니다.
그래서 실제 제어기에서는 이상적인 미분을 그대로 쓰지 않고,
K_d s저역 통과 필터를 덧붙인 형태를 더 흔히 사용합니다:
C_D(s)=K_d\frac{Ns}{s+N}실제 모터 속도 제어에서 완전한 PID보다 PI가 더 자주 쓰이는 이유도 여기에 있습니다.
6. 예제 1: 구동 모터 속도 폐루프
기본적인 폐루프 개념을 이해했으니, 이제 첫 번째 실제 시스템을 살펴봅시다: 모터 속도 루프입니다.
속도 제어의 목표는 아주 명확합니다:
v(t)\rightarrow v_{\mathrm{ref}}(t)그런데 제어기를 제대로 설계하려면 먼저 이런 질문에 답해야 합니다:
그러므로 먼저 모터 모델을 세워야 합니다.
설명을 단순화하기 위해 여기서는 고전적인 직류 모터 모델을 사용합니다. BLDC나 PMSM이라도 하위 단에 빠른 전류 루프가 이미 있다면, 그 속도 외곽 루프는 일정 조건에서 이와 비슷한 기계 시스템으로 근사할 수 있습니다.
7. 모터의 전기적 모델
직류 모터에서 전기자 회로는 키르히호프 전압 법칙을 만족합니다:
u(t)=Ri(t)+L\frac{di(t)}{dt}+e_b(t)여기서
R는 권선 저항,L는 권선 인덕턴스,e_b는 역기전력입니다. 역기전력은 모터 각속도에 거의 비례합니다:e_b(t)=K_e\omega(t)따라서 다음과 같습니다:
\boxed{L\frac{di}{dt}+Ri+K_e\omega u}이 식에는 아주 중요한 물리적 의미가 담겨 있습니다.
모터 속도가 올라가면
\omega\uparrow역기전력도 커지고K_e\omega\uparrow저항과 인덕턴스에 실제로 걸리는 유효 전압은 줄어듭니다.즉 모터 속도와 입력 전압 사이의 관계가 단순한 선형 비례는 아니라는 뜻입니다.
8. 모터의 기계적 모델
모터가 발생하는 전자기 토크는 다음과 같이 근사할 수 있습니다:
\tau_m=K_t i여기서
K_t는 모터 토크 상수입니다.회전계에 대한 뉴턴의 제2법칙에 따라:
J\frac{d\omega}{dt}=\tau_mB\omega\tau_L전자기 토크를 대입하면:
\boxed{J\frac{d\omega}{dt}+B\omega=K_t i\tau_L}여기서
J는 모터 축 기준으로 환산한 등가 관성 모멘트,B는 점성 감쇠,\tau_L는 부하 토크입니다.여기까지 오면 다음을 얻을 수 있습니다:
\text{电压}\rightarrow\text{电流}\rightarrow\text{转矩}\rightarrow\text{加速度}\rightarrow\text{转速}9. 미분방정식에서 속도 전달함수 구하기
시스템을 분석하기 위해 부하 외란은 일단 무시합시다:
\tau_L=0영초기 조건에서 라플라스 변환을 적용합니다. 전기 방정식에서
(Ls+R)I(s)+K_e\Omega(s)=U(s), 기계 방정식에서(Js+B)\Omega(s)=K_tI(s)를 얻으므로 다음과 같습니다:I(s)=\frac{Js+B}{K_t}\Omega(s)이를 전기 방정식에 다시 대입하면:
(Ls+R)\frac{Js+B}{K_t}\Omega(s)+K_e\Omega(s)=U(s)정리하면 다음과 같습니다:
\boxed{\frac{\Omega(s)}{U(s)}=\frac{K_t}{LJs^2+(LB+RJ)s+RB+K_tK_e}}보시다시피 이 모델에서 입력 전압에서 모터 회전속도까지는 2차 시스템입니다.
바퀴 반지름이
r_w이고 감속비가n_g라면, 타이어의 종방향 슬립을 무시할 때 다음이 성립합니다:v=\frac{r_w}{n_g}\omega그러면 차량 속도 모델은 이렇게 쓸 수 있습니다:
\boxed{G_v(s)=\frac{V(s)}{U(s)}\frac{\dfrac{r_wK_t}{n_g}}{LJs^2+(LB+RJ)s+RB+K_tK_e}}이로써 실제 '차량 속도 제어 문제'를 표준적인 제어 시스템 문제로 바꿔 놓은 셈입니다.
10. 속도 루프에 보통 PI를 쓰는 이유
속도 제어에서 가장 흔히 쓰이는 제어기는 완전한 PID가 아니라 PI입니다:
C_v(s)=K_p+\frac{K_i}{s}속도 루프의 주요 임무가 딱 두 가지이기 때문입니다:
첫째, 목표 속도를 빠르게 따라가는 것.
둘째, 지속적인 부하를 받은 뒤에도 정상 편차를 0으로 유지하는 것.
비례항은 빠른 응답을, 적분항은 일정한 외란이 만들어내는 정상 상태 오차를 없애는 역할을 맡습니다.
속도 대상이 다음과 같이 단순화된다고 합시다:
G(s)=\frac{b_0}{a_2s^2+a_1s+a_0}PI 제어기는 다음과 같고:
C(s)=\frac{K_ps+K_i}{s}폐루프 시스템의 특성방정식은 다음을 만족합니다:
1+C(s)G(s)=0대입하면:
s(a_2s^2+a_1s+a_0)+b_0(K_ps+K_i)=0정리하면:
\boxed{a_2s^3+a_1s^2+(a_0+b_0K_p)s+b_0K_i=0}적분을 더하면서 원래 2차였던 모터 대상이 3차 폐루프 시스템이 되었다는 점을 쉽게 알 수 있습니다.
3차 다항식의 경우 라우스-후르비츠 안정 판정법에 따르면, 모든 계수가 양수이더라도 다음 조건을 추가로 만족해야 합니다:
\boxed{a_1(a_0+b_0K_p)>a_2b_0K_i}이 조건은 아주 중요한 사실을 말해 줍니다:
\boxed{K_i\text{ 并不是越大越好}}적분 이득이 너무 작으면 정상 편차가 더디게 사라지고, 너무 크면 시스템 감쇠가 눈에 띄게 낮아져 진동이 생길 수 있습니다.
결국 이른바 PID 튜닝이란, 응답 속도와 안정성 사이에서 적절한 폐루프 극점을 찾아가는 작업입니다.
11. 실제 모터에 이중 폐루프를 자주 쓰는 이유
기계 방정식을 보면
J\dot{\omega}+B\omega=K_ti-\tau_L, 모터 토크를 직접 결정하는 것은 전류임을 알 수 있습니다:\tau_m=K_ti그래서 현대 모터 제어에서는 보통 다음과 같은 방식을 그대로 쓰지 않고
\text{速度误差}\rightarrow\mathrm{PWM}이렇게 설계합니다:
v_{\mathrm{ref}}\rightarrow\text{速度 PI}\rightarrow i_{\mathrm{ref}}\rightarrow\text{电流 PI}\rightarrow\mathrm{PWM}\rightarrow\text{电机}속도 루프가 속도 오차로부터 '지금 필요한 토크'를 계산하고, 그 토크를 목표 전류
i_{\mathrm{ref}}로 표현합니다.이어서 전류 루프가 빠르게
i\rightarrow i_{\mathrm{ref}}를 만들어 주는데, 그 이유는 다음과 같습니다:\tau_m=K_ti따라서 전류 루프가 충분히 빠르다면, 속도 루프는 자신이 사실상 이상적인 토크원을 제어하고 있다고 간주할 수 있습니다.
이 구조에서 가장 핵심이 되는 설계 원칙은 다음과 같습니다:
\boxed{\text{内环快,外环慢}}즉, 전류 루프의 대역폭이 속도 루프의 대역폭보다 확실히 높아야 한다는 것입니다.
12. 예제 2: 조향 모터 폐루프
이번에는 또 다른 아주 전형적인 폐루프를 살펴봅시다: 조향 루프입니다.
속도 루프가 차량 속도
v를 제어한다면, 조향 루프는 실제 바퀴 조향각\delta를 제어합니다.목표 조향각을
\delta_{\mathrm{ref}}라 하고 실제 조향각을\delta라 하면, 조향각 오차는 다음과 같습니다:
\boxed{e_\delta=\delta_{\mathrm{ref}}\delta}조향 제어기의 임무는
e_\delta\rightarrow0를 만드는 것, 즉 다음과 같이 만드는 것입니다:\delta\rightarrow\delta_{\mathrm{ref}}얼핏 보면 속도 폐루프와 완전히 같아 보이지만, 실제 조향 액추에이터는 대개 훨씬 복잡합니다.
13. 조향 시스템이 더 복잡한 이유
조향 모터가 출력을 내도 그것이 곧바로 바퀴 조향각이 되지는 않습니다.
제어 작용은 보통 다음 단계를 차례로 거칩니다:
\text{电机}\rightarrow\text{减速器}\rightarrow\text{齿轮或齿条}\rightarrow\text{拉杆}\rightarrow\text{前轮}기계 시스템에는 마찰과 탄성, 유격도 존재합니다.
더구나 주행 중에는 타이어 자체가 조향 기구에 복원 토크를 가합니다. 그래서 조향 모터에 일정한 제어량을 줘도 최종 조향각은 차량 속도나 노면 상태에 따라 달라질 수 있습니다. 기구 전체를 바퀴 조향각
\delta기준으로 환산하면 다음과 같은 단순화된 기계 모델을 세울 수 있습니다:J_\delta\ddot{\delta}+B_\delta\dot{\delta}+K_\delta\delta=K_{t,s}i_s\tau_{\mathrm{road}}여기서
J_\delta는 조향 기구의 등가 관성,B_\delta는 기계 감쇠,K_\delta는 등가 강성 또는 복원 특성,\tau_{\mathrm{road}}는 노면과 타이어가 만드는 외란 토크입니다.조향 모터 자체는 여전히 전기 방정식을 따릅니다:
L_s\dot{i}*s+R_si_s+K*{e,s}\dot{\delta}=u_\delta전류를 소거하면 조향 액추에이터의 근사 전달함수를 얻을 수 있습니다:
\boxed{G_\delta(s)=\frac{\Delta(s)}{U_\delta(s)}\frac{K_{t,s}}{L_sJ_\delta s^3+(R_sJ_\delta+L_sB_\delta)s^2+(R_sB_\delta+L_sK_\delta+K_{e,s}K_{t,s})s+R_sK_\delta}}보시다시피 이 단순화 모델에서도 조향 시스템은 이미 3차 시스템으로 나타납니다.
속도 루프에 비해 동적 요소가 더 많기 때문에, 제어기 파라미터와 기계 공진, 시간 지연에 대개 더 민감합니다.
14. 조향 폐루프에도 적분이 필요한 이유
목표 조향각이
\delta_{\mathrm{ref}}=10^\circ이고 차량이 조향한 뒤 타이어가 계속 복원 토크\tau_{\mathrm{road}}\neq0를 낸다고 합시다. 만약 비례 제어만 쓴다면u_\delta=K_p e_\delta, 모터가 노면 복원 토크에 맞서는 제어 출력을 계속 내려면u_\delta\neq0를 만족해야 합니다. 그런데 비례 제어는e_\delta\neq0일 때만 0이 아닌 제어량을 만들어냅니다. 따라서 차량은 결국\delta=9^\circ에서 안정화될 수 있습니다. 이때 시스템은 이미 안정되어 더는 진동하지 않지만, 목표는10^\circ이것이 바로 정상 상태 오차입니다.
적분을 더하면:
u_\delta=K_pe_\delta+K_i\int e_\delta(t),dt조향각이 실제로 목표값에 도달하지 않는 한,
e_\delta\neq0적분기는 충분히 큰 지속 조향 토크를 만들어낼 수 있을 때까지 보상량을 계속 증가시킵니다.따라서:
\boxed{\text{稳定不代表准确,稳定性与稳态误差是两个不同的问题}}15. 조향 폐루프와 차량 횡방향 제어는 다른 개념이다
차량 시스템에서는 흔히 '조향 제어'와 '경로 추종'을 뒤섞어 이야기합니다. 하지만 실제로 이 둘은 서로 다른 제어 계층에 속합니다.
하위 조향 서보가 해결하는 것은:
\delta_{\mathrm{ref}}\rightarrow\delta즉, 상위에서 앞바퀴를10^\circ만큼 돌리라고 요구하면 하위 계층이 액추에이터를 실제로10^\circ까지 돌아가게 만드는 일입니다. 반면 차량 횡방향 제어가 해결하는 것은:\text{路径误差}\rightarrow\delta_{\mathrm{ref}}예를 들어 차량이 트랙 중심에서 벗어나면 Pure Pursuit, Stanley, LQR, MPC 등의 알고리즘이 횡방향 오차와 방향 오차를 바탕으로 다음을 계산합니다.
\delta_{\mathrm{ref}}목표 조향각은 얼마여야 하는가.따라서 전체 구조는 실제로 다음과 같습니다.
\text{目标轨迹}\rightarrow\text{横向控制器}\rightarrow\delta_{\mathrm{ref}}\rightarrow\text{转角闭环}\rightarrow\delta\rightarrow\text{车辆}그러므로 상위 계층에서 아무리 복잡한 알고리즘을 쓴다 해도, 하위 조향 기구가 목표 조향각을 정확히 실행하지 못하면 최종 경로 추종 성능은 제한될 수밖에 없습니다.
16. 시뮬레이션으로 무엇을 검증해야 하는가
모델을 세웠다면 먼저 시뮬레이션부터 해야 합니다.
속도 루프라면 우선 계단형 목표값을 넣어 보면 됩니다. 예를 들어:
v_{\mathrm{ref}}:0\rightarrow3\mathrm{m/s}차량 속도가 정지 상태에서 목표 속도까지 어떻게 응답하는지 살펴봅니다.
기본적인 시뮬레이션이라도 최소한 다음은 기록해야 합니다.
예를 들어 백분율 오버슈트는 다음과 같이 정의할 수 있습니다.
M_p=\frac{y_{\max}-y_{\mathrm{ref}}}{y_{\mathrm{ref}}}\times100%정상 상태 오차는 이렇게 정의합니다.
e_{\mathrm{ss}}=\lim_{t\rightarrow\infty}e(t)계단 응답만으로는 충분하지 않습니다.
속도 루프에서 더 중요한 실험은 차량이 이미 안정적으로 주행하는 중에 갑자기 부하 외란을 가하는 것입니다.
\tau_L:0\rightarrow\tau_d속도가 눈에 띄게 떨어지는지, 그리고 컨트롤러가 얼마 만에 차량을 목표 속도로 되돌리는지 확인합니다.
조향 루프도 마찬가지로 다음과 같이 시작한 뒤,
\delta_{\mathrm{ref}}:0\rightarrow10^\circ특정 시점에 노면 복원 토크를 가해 볼 수 있습니다.
\tau_{\mathrm{road}}:0\rightarrow\tau_d그리고 P, PI, PID 제어기의 응답을 비교합니다.
일반적으로 다음과 같은 경향을 관찰할 수 있습니다. P 제어는 응답이 빠르지만 일정한 외란이 있으면 정상 상태 편차가 남을 수 있고, 적분항을 더하면 이 편차를 없앨 수 있지만 적분이 너무 강하면 진동이 커질 수 있습니다. 적절한 미분항을 더하면 감쇠가 개선되지만, 시스템이 센서 노이즈에 더 민감해집니다.
시뮬레이션의 의미는 다음을 검증하는 데 있습니다.
17. 시뮬레이션에서는 안정적인데 실차에서 진동하는 이유
실제 제어에서 가장 흔한 상황 중 하나는 MATLAB이나 Python 시뮬레이션 곡선은 아주 깔끔한데, 정작 컨트롤러를 MCU에서 돌리면 진동하기 시작하는 경우입니다.
원인은 앞선 모델이 수많은 실제 요인을 무시하고 있기 때문입니다.
첫째, 실제 컨트롤러는 이산적으로 동작합니다.
샘플링 주기를
T_s라고 하면, 제어 알고리즘은t=kT_s의 이산 시점에서만 실행됩니다.적분항도 연속 형태에서
\int e(t),dt다음과 같이 바뀝니다.T_s\sum e[k]간단한 디지털 PI는 이렇게 쓸 수 있습니다.
u[k]=K_pe[k]+K_iT_s\sum_{j=0}^{k}e[j]제어 주파수가 너무 낮으면, 연속 시스템에서는 안정적이던 파라미터가 이산 구현 후에는 같은 안정 여유를 유지하지 못할 수 있습니다.
18. PWM 포화와 적분 와인드업
두 번째 문제는 액추에이터에 한계가 있다는 점입니다.
모터 드라이버가 낼 수 있는 최대 출력이
|u|\le U_{\max}인데 컨트롤러가 계산한 이론 출력은
u^\ast>U_{\max}일 수 있습니다. 이때 실제 출력은 이미 최댓값으로 제한되어 있는데도 적분기는 계속 오차를 누적할 수 있습니다.
예를 들어 차량이 오르막에 들어서며 속도가 떨어지면 PI 컨트롤러는 출력을 계속 높이지만, PWM은 이미
100%에 도달해 있습니다.이때 적분을 계속해 봐야 더 많은 전압이 나오지도 않으면서 적분 상태만 점점 커집니다.
그러다 차량이 다시 평지로 돌아오면 속도가 이미 목표에 가까워졌는데도 적분기에 과거 오차가 잔뜩 남아 있어 모터가 계속 과도한 출력을 내고, 결국 심한 오버슈트가 발생합니다.
이런 현상을 이렇게 부릅니다.
\boxed{\text{积分饱和}}그래서 실제 PI/PID 컨트롤러에는 보통 Anti-Windup이 필요합니다. 적분 한계 설정, 조건부 적분, 역계산법 등이 그 예입니다.
19. 엔코더는 완벽한 센서가 아니다
속도 루프는 속도를 측정해야 하고, 실제 모델 차량은 보통 엔코더를 사용합니다.
엔코더가 1회전당
N_{\mathrm{enc}}개의 카운트를 발생시키고, 샘플링 주기T_s동안\Delta N개의 카운트가 측정되었다면, 모터 각속도는 다음과 같이 근사할 수 있습니다.\omega\approx\frac{\Delta N}{N_{\mathrm{enc}}}\frac{2\pi}{T_s}고속에서는 한 번의 샘플링에 수십에서 수백 개의 카운트가 쌓이므로 속도 계산이 비교적 매끄럽습니다.
하지만 저속에서는
\Delta N=0,\ 1,\ 2처럼 이산적이고 매끄럽지 않은 값이 나올 수 있습니다.그러면 측정된 속도는 연속적으로 변하지 않고 몇 개의 이산값 사이를 오갑니다. 여기서 이 속도를 그대로 미분까지 하면 노이즈는 더욱 증폭됩니다.
그래서 실제 제어 시스템에서의 데이터 필터링, 속도 추정, 샘플링 주기는 그 자체로 컨트롤러 설계의 일부이며, 얼마든지 무시해도 되는 주변적인 문제가 아닙니다.
20. 시간 지연이 위험한 이유
실제 제어 과정은 보통 다음과 같은 단계를 거칩니다.
\text{采样}\rightarrow\text{读取传感器}\rightarrow\text{算法计算}\rightarrow\text{PWM 更新}\rightarrow\text{驱动器}\rightarrow\text{机械响应}이 모든 과정에서 지연이 발생합니다.
총 지연을
\tau_d이라 하면 연속 모델에서는 다음과 같이 근사할 수 있습니다.G_d(s)=e^{-s\tau_d}여기서
s=j\omega를 대입하면 다음을 얻습니다.G_d(j\omega)=e^{-j\omega\tau_d}이 항의 크기는 항상
|G_d(j\omega)|=1이지만 추가적인 위상이 생깁니다.
\boxed{\angle G_d(j\omega)=-\omega\tau_d}즉, 주파수가 높을수록 지연으로 인한 위상 손실이 더 심해집니다. 이것이 컨트롤러가 대역폭을 무한정 높일 수 없는 이유입니다.
시스템 응답을 매우 빠르게 조정하면 할수록 지연과 모델링되지 않은 고주파 동특성이 점점 더 중요해지고, 결국 원래 안정적이던 시스템을 진동으로 몰아넣을 수 있습니다.
21. 실제로 주의해야 할 폐루프 성능
폐루프 시스템을 평가할 때는 다음만 물어서는 안 됩니다.
속도가 최종적으로
3\mathrm{m/s}에 도달했더라도 중간에,\mathrm{m/s}까지 치솟았다면, 분명 좋은 제어라고 할 수 없습니다.완전한 폐루프 시스템이라면 보통 최소한 다음을 살펴야 합니다.
상승 시간
t_r은 시스템이 목표에 얼마나 빨리 접근하는지를 나타냅니다.오버슈트
M_p는 시스템이 목표값을 얼마나 넘어서는지를 나타냅니다.정착 시간
t_s은 시스템이 얼마 만에 목표 근처에서 실제로 안정되는지를 나타냅니다.정상 상태 오차
e_{\mathrm{ss}}는 장시간 운전 후에도 목표값과 실제 출력 사이에 편차가 남는지를 나타냅니다.이 외에도 외란 실험과 파라미터 섭동 실험도 해 보아야 합니다.
예를 들어 모터 관성을
J'=1.2J로 바꾸거나 배터리 전압을 낮춘 뒤에도 제어 시스템이 여전히 안정적인지 확인합니다.
실제 차량의 파라미터는 결코 우리가 모델링에 사용한 값과 정확히 같지 않기 때문입니다.
좋은 컨트롤러란 다음과 같아야 합니다.
\boxed{\text{面对扰动、参数变化、噪声和延迟时仍然能够稳定工作}}22. 맨 처음 질문으로 돌아가서
이제 글 서두의 질문으로 다시 돌아가 봅시다.
차량이 다음 속도로 주행하도록 요구한다면,
v_{\mathrm{ref}}=3\mathrm{m/s}고정된 PWM 하나를 찾아 그것이 언제나
3\mathrm{m/s}에 대응한다고 여겨서는 안 됩니다.더 합리적인 방법은 이렇습니다.
v_{\mathrm{ref}}\rightarrow e_v\rightarrow\text{速度控制器}\rightarrow\text{电机}\rightarrow v실제 속도가 떨어지면 컨트롤러가 출력을 자동으로 높이고, 실제 속도가 올라가면 출력을 자동으로 낮춥니다.
마찬가지로 앞바퀴를 다음 각도로 유지하도록 요구한다면,
\delta_{\mathrm{ref}}=10^\circ특정 PWM이나 특정 전압이 무조건
10^\circ에 대응한다고 단순하게 생각해서도 안 됩니다.대신 다음과 같은 구조를 만들어야 합니다.
\delta_{\mathrm{ref}}\rightarrow e_\delta\rightarrow\text{转角控制器}\rightarrow\text{转向机构}\rightarrow\delta노면 토크가 바뀌면 컨트롤러는 새로운 오차에 따라 조향 모터 출력을 다시 조정합니다.
이렇게 해서 속도 제어와 조향 제어는 전혀 다른 물리 시스템을 다루면서도 결국 동일한 제어 논리를 갖게 됩니다.
\boxed{\text{目标}\rightarrow\text{测量}\rightarrow\text{比较}\rightarrow\text{修正}\rightarrow\text{再次测量}}23. 예제와 설명
앞에서 다룬 이론은 결국 실제 제어 프로그램으로 구현되어야 합니다. MCU에서는 폐루프 제어가 연속적으로 수행되는 것이 아니라, 정해진 제어 인터럽트 주기마다 끊임없이 다음 작업을 반복합니다.
\boxed{\text{读取传感器}\rightarrow\text{计算误差}\rightarrow\text{计算控制量}\rightarrow\text{驱动执行器}}1. PI 컨트롤러 구현
연속 형태의 PI 컨트롤러는 다음과 같습니다.
u(t)=K_p e(t)+K_i\int_0^t e(\tau),d\tau마이크로컨트롤러에서는 컨트롤러가 샘플링 주기
T_s로 주기적으로 동작하므로, 오차는 다음과 같이 쓸 수 있습니다.e[k]=r[k]-y[k]적분항은 다음과 같이 이산화할 수 있습니다.
I[k]=I[k-1]+e[k]T_s따라서 이산 PI 컨트롤러는 이렇게 됩니다.
u[k]=K_p e[k]+K_i I[k]차량 속도 루프에서는
e_v[k]=v_{\mathrm{ref}}[k]-v[k]컨트롤러가 목표 속도와 엔코더로 측정한 실제 속도를 바탕으로 다음 제어 주기의 PWM을 계산합니다.
코드에서 핵심은 사실상 다음뿐입니다.
각각 다음에 대응합니다.
e_v=v_{\mathrm{ref}}-vI=\int e_v(t)\,dt그리고 다음도 있습니다.
u=K_p e_v+K_iI2. 조향 PID 제어와 구현
조향 폐루프 역시 이산 제어의 개념에 따라 구현할 수 있습니다.
조향각 오차를 정의하면 다음과 같습니다.
e_\delta[k]=\delta_{\mathrm{ref}}[k]-\delta[k]이산 PID는 간단히 다음과 같이 쓸 수 있습니다.
u[k]=K_p e[k]+K_i I[k]+K_d\frac{e[k]-e[k-1]}{T_s}여기서
I[k]=I[k-1]+e[k]T_s목표 조향각이 다음과 같다고 가정하면
\delta_{\mathrm{ref}}=10^\circ현재 실제 조향각이 다음과 같을 때
\delta=6^\circ다음이 성립합니다.
$e_\delta=10\circ-6\circ=4^\circ$
비례항은 우선 현재 오차를 기준으로 주된 제어 출력을 만들어 냅니다.
u_P=K_p e_\delta조향 기구가 점차 목표 각도에 가까워지면
4^\circ\rightarrow2^\circ\rightarrow1^\circ\rightarrow0비례 제어의 작용도 계속 줄어듭니다.
타이어의 복원 토크 때문에 조향 시스템이 결국 다음과 같은 지점에 머문다면
\delta=9.7^\circ여전히 오차가 남아 있습니다.
e_\delta=0.3^\circ적분항은 이 오차를 계속 누적합니다.
I[k]=I[k-1]+0.3^\circ T_s지속적인 제어량이 충분히 만들어져 다음 상태가 될 때까지 말입니다.
\delta\rightarrow10^\circ미분항은
K_d\frac{e[k]-e[k-1]}{T_s}주로 오차의 변화 속도에 따라 감쇠 작용을 만듭니다. 조향 기구가 목표 각도로 빠르게 접근할 때 미분항은 과도한 제어 출력을 미리 억제하여 오버슈트와 진동을 줄여 줍니다.
3. 정리
속도 PI든 조향 PID든 프로그램의 기본 로직은 사실상 같습니다.
하지만 이 몇 줄의 코드에는 완전한 폐루프 제어 이론이 담겨 있습니다.
\boxed{\text{目标}\rightarrow\text{误差}\rightarrow\text{控制器}\rightarrow\text{被控对象}\rightarrow\text{反馈}}외부 부하나 노면 토크, 배터리 전압이 변하더라도 시스템은 각각의 외란을 미리 정확히 알 필요 없이, 실제 출력과 목표 출력 사이의 오차를 이용해 제어량을 계속 보정합니다.
그러니 PID 코드 자체는 그리 복잡하지 않습니다.
제어 성능을 실제로 좌우하는 것은 제어 대상의 동특성에 대한 이해, 그리고 제어 주기, 피드백 측정, 파라미터 튜닝, 포화 처리, 노이즈 처리 같은 요소입니다.
24. 맺음말
PID는 피드백을 구현하는 방법 중 하나일 뿐이며, 온전한 제어 설계는 물리 시스템에서 출발해야 합니다.
\text{物理建模}\rightarrow\text{数学模型}\rightarrow\text{控制器设计}\rightarrow\text{稳定性分析}\rightarrow\text{仿真}\rightarrow\text{离散实现}\rightarrow\text{实际器件验证}제어 대상이 무엇인지 모른 채
K_p과K_i값만 바꾼다면K_d결국 경험에 의존한 튜닝에 머무를 뿐입니다.반대로 전압이 어떻게 전류를 만들고, 전류가 어떻게 토크를 만들며, 토크가 어떻게 속도를 바꾸는지 알고, 조향 모터가 기계 구조를 거쳐 앞바퀴 조향각에 어떻게 영향을 주는지 알고, 외란이 어디서 들어와 센서가 무엇을 측정하며 액추에이터가 어떤 제약을 받는지 안다면, PID 파라미터는 더 이상 “시행착오로 맞춰야 하는” 세 개의 숫자가 아닙니다.
그것들은 구체적인 시스템의 폐루프 동특성을 바꾸는 값입니다.
그래서 저는 폐루프 제어를 아주 단순한 한 문장으로 이해하고 싶습니다.
제어 시스템이 오차를 낼 수 있게 두고, 그 오차로 계속 보정한다
모형 차량에서는 이 사고방식이 제어 시스템 전체를 관통합니다.
가장 아래 단계인 전류 루프부터 속도 루프, 조향각 루프, 나아가 차량 횡방향 제어와 경로 추종에 이르기까지, 본질적으로는 모두 같은 질문에 계속 답하는 과정입니다.
그것이 바로 폐루프 제어입니다.