pole
assignment & lqr tracking simulation for modern control theory
0 题目要求
假设在惯性坐标系下移动机器人的坐标为\(O=(x,y,θ)^T\),参考机器人的坐标为\(q_r=(x_r,y_r,θ_r)^T\),跟踪误差坐标在载体坐标系下的坐标为\(p_e=(x_e,y_e,θ_e)^T\)。
(1)通过载体坐标系旋转变换以及图1的几何关系试建立移动机器人跟踪误差线性状态空间模型。
(2)如果参考机器人轨迹是一个半径\(2\)米的圆,参考线速度为\(0.4\)米/秒,参考角速度为\(0.5\)弧度/秒,试设计一个稳定化的状态反馈控制器,使得系统的超调量\(\le 4 \%\),调节时间\(\le5\)秒,并用MATLAB给出响应曲线(按\(2\%\)准则)。
(3)在相同的参数下设计LQR控制器,并用MATLAB给出响应曲线。
图1
1 推导
1.1 定义坐标与误差
实际机器人在世界坐标系下的状态:
\[
q = \begin{bmatrix}
x \\
y \\
\theta
\end{bmatrix}
\]
参考轨迹的状态:
\[
q_r = \begin{bmatrix}
x_r \\
y_r \\
\theta_r
\end{bmatrix}
\]
跟踪误差坐标在参考机器人坐标系下定义为:
\[
p_e = \begin{bmatrix}
x_e \\
y_e \\
\theta_e
\end{bmatrix} = \begin{bmatrix}
x - x_r \\
y - y_r \\
\theta - \theta_r
\end{bmatrix}
\]
1.2 坐标变换推导
利用旋转矩阵: \[
R_r = \begin{bmatrix}
\cos\theta_r & \sin\theta_r & 0 \\
-\sin\theta_r & \cos\theta_r & 0 \\
0 & 0 & 1
\end{bmatrix}
\]
可以将实际机器人坐标系下的状态转换到参考机器人坐标系下的跟踪误差坐标:
\[
p_e = \begin{bmatrix}
x_e \\
y_e \\
\theta_e
\end{bmatrix} = \begin{bmatrix}
cos\theta_r(x - x_r) + sin\theta_r(y - y_r)\\
-sin\theta_r(x - x_r) + cos\theta_r(y - y_r) \\
\theta - \theta_r
\end{bmatrix}
\]
1.3 机器人运动学模型
定义机器人人动力学模型。
定义实际机器人状态:
\[
\left\{
\begin{aligned}
\dot{x} &= v \cos\theta \\
\dot{y} &= v \sin\theta \\
\dot{\theta} &= \omega
\end{aligned}
\right.
\]
定义参考机器人状态:
\[
\left\{
\begin{aligned}
\dot{x}_r &= v_r \cos\theta_r \\
\dot{y}_r &= v_r \sin\theta_r \\
\dot{\theta}_r &= \omega_r
\end{aligned}
\right.
\]
1.4 误差状态空间模型
对\(x_e\),\(y_e\),\(\theta_e\)分别求导。
对于\(x_e\):
\[
\begin{aligned}
\dot{x}_e &= \frac{d}{dt}[cos\theta_r(x - x_r) + sin\theta_r(y -
y_r)] \\
&= -sin\theta_r \dot{\theta}_r (x - x_r) + cos\theta_r (\dot{x} -
\dot{x}_r) + cos\theta_r \dot{\theta}_r (y - y_r) + sin\theta_r (\dot{y}
- \dot{y}_r) \\
\end{aligned}
\]
将导数带入得到:
\[
\dot{x}_e = -sin\theta_r \omega_r (x - x_r) + cos\theta_r (v \cos\theta
- v_r \cos\theta_r) + cos\theta_r \omega_r (y - y_r) + sin\theta_r (v
\sin\theta - v_r \sin\theta_r)
\]
我们做小误差角度近似:假设\(\theta =
\theta_r + \theta_e\),并且在\(\theta_e\)较小时展开:
\[
\begin{aligned}
cos\theta &\approx cos\theta_r - \theta_e \sin\theta_r \\
sin\theta &\approx sin\theta_r + \theta_e cos\theta_r
\end{aligned}
\]
带入\(x_e\)的导数中,省略高阶项并化简,得到:
\[
\dot{x}_e = -v_r + v cos\theta_r + \omega_r y_e
\]
同理,对于\(y_e\):
\[
\begin{aligned}
\dot{y}_e &= \frac{d}{dt}[-sin\theta_r(x - x_r) + cos\theta_r(y -
y_r)] \\
&= -cos\theta_r \dot{\theta}_r (x - x_r) - sin\theta_r (\dot{x} -
\dot{x}_r) + sin\theta_r \dot{\theta}_r (y - y_r) + cos\theta_r (\dot{y}
- \dot{y}_r)
\end{aligned}
\]
带入并化简,得到:
\[
\dot{y}_e = v sin\theta_e - \omega_r x_e
\]
对于\(\theta_e\),显然:
\[
\dot{\theta}_e = \dot{\theta} - \dot{\theta}_r = \omega - \omega_r
\]
最终得到非线性误差模型:
\[
\left\{
\begin{aligned}
\dot{x}_e &= -v_r + v cos\theta_r + \omega_r y_e \\
\dot{y}_e &= v sin\theta_e - \omega_r x_e \\
\dot{\theta}_e &= \omega - \omega_r
\end{aligned}
\right.
\]
1.5 线性化误差模型
当误差很小时,使用小角度近似:
\[
\begin{aligned}
sin\theta_e &\approx \theta_e \\
cos\theta_e &\approx 1
\end{aligned}
\]
将其代入上式,得到线性化的误差状态空间模型:
\[
\left\{
\begin{aligned}
\dot{x}_e &= -v_r + v + \omega_r y_e \\
\dot{y}_e &= v \theta_e - \omega_r x_e \\
\dot{\theta}_e &= \omega - \omega_r
\end{aligned}
\right.
\]
设误差状态:
\[
X_e = \begin{bmatrix}
x_e \\
y_e \\
\theta_e
\end{bmatrix}
\]
控制输入误差:
\[
U_e = \begin{bmatrix}
v - v_r \\
\omega - \omega_r
\end{bmatrix}
\]
得到线性化的误差状态空间模型:
\[
\dot{X}_e = A X_e + B U_e
\]
其中,状态矩阵\(A\)和输入矩阵\(B\)为:
\[
A = \begin{bmatrix}
0 & \omega_r & 0 \\
-\omega_r & 0 & v_r \\
0 & 0 & 0
\end{bmatrix}, \quad B = \begin{bmatrix}
1 & 0 \\
0 & 0 \\
0 & 1
\end{bmatrix}
\]
2 控制器设计
2.1 极点配置
极点配置方法是通过选择合适的状态反馈增益矩阵\(K\)来将系统的极点移动到期望的位置。
2.1.1 可控性检验
首先检查系统的可控性。构造可控性矩阵\(C\): \[
C = \begin{bmatrix}
B & AB & A^2B
\end{bmatrix} \in \mathbb{R}^{3 \times 6}
\Rightarrow rank(C) = 3 \Rightarrow 可控
\]
在mATLAB中可以使用ctrb
函数验证可控性:
1 2 3 4 5 6 7 8 9 10 11
| A = [0 0.5 0; -0.5 0 0.4; 0 0 0]; B = [1 0; 0 0; 0 1];
C = ctrb(A, B);
if rank(C) == size(A, 1) disp('系统可控'); else disp('系统不可控'); end
|
2.1.2 性能指标转化
设计要求:
- 超调量\(M_p \leq 4\%\)
- 调节时间\(t_s \leq 5\)秒
\[
M_p = e^{-\frac{\zeta \pi}{\sqrt{1 - \zeta^2}}} = 0.04 \Rightarrow \zeta
\approx 0.7156 \Rightarrow \zeta = 0.72
\]
调节时间满足\(2\%\)准则:
\[
t_s = \frac{4}{\zeta \omega_n} \leq 5 \Rightarrow \omega_n \geq
\frac{4}{\zeta t_s} = \frac{4}{0.72 \times 5} \approx 1.1111 \Rightarrow
\omega_n = 1.2
\]
计算目标极点:
\[
s_{1,2} = -\zeta \omega_n \pm j \omega_n \sqrt{1 - \zeta^2} = -0.864 + j
0.847
\]
设第3个极点为实数且收敛更快:
\[
s_3 = -5 \zeta \omega_n = -4.32
\]
所以期望极点为:
\[
s = \{-0.864 + j 0.847, -0.864 - j 0.847, -4.32\}
\]
2.1.3 求解增益矩阵
给定参考速度\(v_r =
0.4\)m/s,参考角速度\(\omega_r =
0.5\)rad/s,得到状态矩阵\(A\)和输入矩阵\(B\):
\[
A = \begin{bmatrix}
0 & 0.5 & 0 \\
-0.5 & 0 & 0.4 \\
0 & 0 & 0
\end{bmatrix}, \quad B = \begin{bmatrix}
1 & 0 \\
0 & 0 \\
0 & 1
\end{bmatrix}
\]
使用MATLAB的place
函数求解增益矩阵\(K\):
1 2 3 4 5 6 7 8 9 10
| A = [0 0.5 0; -0.5 0 0.4; 0 0 0]; B = [1 0; 0 0; 0 1];
desired_poles = [-0.864 + 0.847i, -0.864 - 0.847i, -4.32];
K = place(A, B, desired_poles);
disp('增益矩阵K:'); disp(K);
|
2.2 LQR控制器设计
LQR控制器设计是通过最小化状态和控制输入的加权二次型来获得最优控制增益矩阵\(K_{lqr}\)。
LQR求解最优控制律:
\[
u = -K_{lqr} X_e
\]
通过代价函数:
\[
J = \int_0^\infty (X_e^T Q X_e + U_e^T R U_e) dt
\]
设计目标:
- 惩罚\(x_e\),\(y_e\)偏差 \(\rightarrow\) Q权重大
- 控制输入不宜过大 \(\rightarrow\)
R不能过小
2.2.1 定义权重矩阵
选择常用状态权重矩阵\(Q\)和控制输入权重矩阵\(R\): \[
Q = \begin{bmatrix}
10 & 0 & 0 \\
0 & 10 & 0 \\
0 & 0 & 1
\end{bmatrix}, \quad R = \begin{bmatrix}
1 & 0 \\
0 & 1
\end{bmatrix}
\]
2.2.2 求解LQR增益矩阵
使用MATLAB的lqr
函数求解LQR增益矩阵\(K_{LQR}\):
1 2 3 4 5 6 7 8 9 10 11
| A = [0 0.5 0; -0.5 0 0.4; 0 0 0]; B = [1 0; 0 0; 0 1];
Q = [10 0 0; 0 10 0; 0 0 1]; R = [1 0; 0 1];
K_LQR = lqr(A, B, Q, R);
disp('LQR增益矩阵K_LQR:'); disp(K_LQR);
|
而在c++中,需要求解Algebraic Riccati Equation
(ARE)来得到LQR增益矩阵\(K_{LQR}\):
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| MatrixXd SolveLQR(const MatrixXd& A, const MatrixXd& B, const MatrixXd& Q, const MatrixXd& R){ MatrixXd P = Q; for(int i = 0; i < 100; i++){ MatrixXd P_next = Q + A.transpose() * P * A - A.transpose() * P * B * (R + B.transpose() * P * B).inverse() * B.transpose() * P * A; if((P_next - P).norm() < 1e-6){ break; } cout<<"Iteration " << i << ": P norm = " << (P_next - P).norm() << endl; P = P_next; } return (R + B.transpose() * P * B).inverse() * B.transpose() * P; }
|
得到控制增益矩阵\(K_{lqr}\)后,可以将其应用于控制输入:
\[
A_{lqr} = A - B K_{lqr}
\]
3 仿真
3.1 matlab仿真
基于上述推导和设计,使用MATLAB进行仿真。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
| v_r = 0.4; omega_r = 0.5;
A = [0, omega_r, 0; -omega_r, 0, v_r; 0, 0, 0]; B = [-1, 0; 0, 0; 0, -1];
disp('系统矩阵 A:'); disp(A); disp('输入矩阵 B:'); disp(B);
Co = ctrb(A, B); rank_Co = rank(Co); if rank_Co < size(A,1) disp('系统不可控,极点配置可能失败或存在问题。'); else disp('系统可控。'); end
Mp_spec = 0.04; ts_spec = 5;
zeta = sqrt(log(Mp_spec)^2 / (pi^2 + log(Mp_spec)^2));
if zeta < 0.7156 zeta = 0.72; end omega_n_min = 4 / (zeta * ts_spec);
omega_n = 1.2; if omega_n < omega_n_min omega_n = omega_n_min * 1.1; end
fprintf('设计参数: zeta = %f, omega_n = %f rad/s\n', zeta, omega_n);
P_dominant_1 = -zeta*omega_n + 1j*omega_n*sqrt(1-zeta^2); P_dominant_2 = -zeta*omega_n - 1j*omega_n*sqrt(1-zeta^2); P_third = -5 * zeta * omega_n;
P_desired = [P_dominant_1, P_dominant_2, P_third]; disp('期望配置的极点:'); disp(P_desired);
K_pp = place(A, B, P_desired); disp('极点配置控制器增益 K_pp:'); disp(K_pp);
A_cl_pp = A - B * K_pp; sys_cl_pp = ss(A_cl_pp, zeros(3,1), eye(3), 0);
disp('极点配置后闭环系统 A-BK_pp 的特征值:'); disp(eig(A_cl_pp));
Q = diag([10, 10, 1]);
R = diag([0.1, 0.1]);
[K_lqr, S_lqr, E_lqr] = lqr(A, B, Q, R); disp('LQR 控制器增益 K_lqr:'); disp(K_lqr);
A_cl_lqr = A - B * K_lqr; sys_cl_lqr = ss(A_cl_lqr, zeros(3,1), eye(3), 0);
disp('LQR 控制器闭环系统 A-BK_lqr 的特征值 (E_lqr):'); disp(E_lqr);
t_sim = 0:0.05:10; p_e0 = [0.5; 0.3; 0.2];
[y_pp, t_pp, x_pp] = initial(sys_cl_pp, p_e0, t_sim); [y_lqr, t_lqr, x_lqr] = initial(sys_cl_lqr, p_e0, t_sim);
figure; sgtitle('跟踪误差响应曲线 (初始误差: x_e=0.5, y_e=0.3, \theta_e=0.2)');
subplot(3,1,1); plot(t_pp, x_pp(:,1), 'r-', 'LineWidth', 1.5); hold on; plot(t_lqr, x_lqr(:,1), 'b--', 'LineWidth', 1.5); ylabel('x_e (m)'); legend('极点配置', 'LQR'); title('纵向误差 x_e'); grid on;
subplot(3,1,2); plot(t_pp, x_pp(:,2), 'r-', 'LineWidth', 1.5); hold on; plot(t_lqr, x_lqr(:,2), 'b--', 'LineWidth', 1.5); ylabel('y_e (m)'); legend('极点配置', 'LQR'); title('横向误差 y_e'); grid on;
subplot(3,1,3); plot(t_pp, x_pp(:,3), 'r-', 'LineWidth', 1.5); hold on; plot(t_lqr, x_lqr(:,3), 'b--', 'LineWidth', 1.5); ylabel('\theta_e (rad)'); xlabel('时间 (s)'); legend('极点配置', 'LQR'); title('方向误差 \theta_e'); grid on;
disp('--- 极点配置控制器性能分析 ---');
info_xe_pp = stepinfo(x_pp(:,1), t_pp, 0, 'SettlingTimeThreshold', 0.02);
initial_xe = p_e0(1); ts_xe_pp = NaN; overshoot_xe_pp = 0;
settling_threshold_xe = 0.02 * abs(initial_xe); for k = 1:length(t_pp) if all(abs(x_pp(k:end,1)) <= settling_threshold_xe) ts_xe_pp = t_pp(k); break; end end
if initial_xe > 0 && min(x_pp(:,1)) < -eps overshoot_xe_pp = abs(min(x_pp(:,1))) / initial_xe * 100; elseif initial_xe < 0 && max(x_pp(:,1)) > eps overshoot_xe_pp = abs(max(x_pp(:,1))) / abs(initial_xe) * 100; end fprintf('x_e (极点配置): 超调量 ≈ %.2f%%, 调节时间 (2%%) ≈ %.2f s\n', overshoot_xe_pp, ts_xe_pp); if overshoot_xe_pp <= Mp_spec*100 && ts_xe_pp <= ts_spec fprintf('x_e 响应满足设计指标。\n'); else fprintf('x_e 响应未能完全满足设计指标。可能需要调整期望极点。\n'); end
|
3.2 c++仿真
基于opencv和Eigen库,使用c++简单实现了LQR控制器的仿真。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
| #include <iostream> #include "Eigen/Dense" #include "opencv2/opencv.hpp" using namespace std; using namespace cv; using namespace Eigen;
constexpr double v_r = 0.4; constexpr double w_r = 0.5; constexpr double radius = 2.0; constexpr double dt = 0.01; constexpr double sim_time = 10.0; constexpr int steps = static_cast<int>(sim_time / dt);
MatrixXd SolveLQR(const MatrixXd& A, const MatrixXd& B, const MatrixXd& Q, const MatrixXd& R){ MatrixXd P = Q; for(int i = 0; i < 100; i++){ MatrixXd P_next = Q + A.transpose() * P * A - A.transpose() * P * B * (R + B.transpose() * P * B).inverse() * B.transpose() * P * A; if((P_next - P).norm() < 1e-6){ break; } cout<<"Iteration " << i << ": P norm = " << (P_next - P).norm() << endl; P = P_next; } return (R + B.transpose() * P * B).inverse() * B.transpose() * P; }
int main(){ Matrix3d A; A << 0, w_r, 0, -w_r, 0, v_r, 0, 0, 0; MatrixXd B(3, 2); B << 1, 0, 0, 0, 0, 1;
Matrix3d Q; Q << 10, 0, 0, 0, 10, 0, 0, 0, 5; Matrix2d R; R << 1, 0, 0, 1; Matrix<double, 2, 3> K = SolveLQR(A, B, Q, R); cout<<"K matrix:\n" << K << endl; Vector3d x_e(0.5, 0.2, 0.1); vector<cv::Point> trajectory, reference_trajectory;
int size = 600; int origin = size >> 1; double scale = 100.0; Mat canvas(size, size, CV_8UC3, Scalar(255, 255, 255));
for(int i = 0; i < steps; i++) { double t = i * dt; double x_r = radius * cos(w_r * t); double y_r = radius * sin(w_r * t); double theta_r = w_r * t;
Vector2d u = -K * x_e;
Vector3d dx_e = A * x_e + B * u; x_e += dx_e * dt;
Matrix2d R_theta; R_theta << cos(theta_r), -sin(theta_r), sin(theta_r), cos(theta_r); Vector2d pe = R_theta * x_e.head<2>();
double x = x_r + pe(0); double y = y_r + pe(1);
cv::Point p(static_cast<int>(origin + x * scale), static_cast<int>(origin - y * scale)); trajectory.push_back(p); reference_trajectory.emplace_back(static_cast<int>(origin + x_r * scale), static_cast<int>(origin - y_r * scale)); } canvas = Scalar(255, 255, 255); for(int i = 0; i < trajectory.size(); i++){ if(i == 0) { circle(canvas, trajectory[i], 5, Scalar(0, 255, 0), -1); } if(i == trajectory.size() - 1) { circle(canvas, trajectory[i], 5, Scalar(0, 0, 255), -1); } circle(canvas, trajectory[i], 1, Scalar(211, 85, 186), -1); circle(canvas, reference_trajectory[i], 1, Scalar(255, 0, 0), -1);
if(i != 0 && i != trajectory.size() - 1 && i % 20 == 0) circle(canvas, trajectory[i], 5, Scalar(128, 128, 240), 1);
imshow("LQR Trajectory", canvas); char key = (char)waitKey(1); if(key == 27) { break; } }
waitKey(0); return 0; }
|
3.3 仿真结果



4 总结
本文通过推导移动机器人跟踪误差的线性状态空间模型,设计了极点配置和LQR控制器,并在MATLAB和C++中进行了仿真。结果表明,所设计的控制器能够有效地跟踪参考轨迹,满足超调量和调节时间的要求。极点配置方法和LQR方法都能实现稳定的跟踪控制,但LQR方法在处理多变量系统时更为灵活和高效。
代码见github,仿真视频见bilibili。