简介:一阶倒立摆是控制理论中经典的动力学模型,常用于验证动态稳定性与反馈控制算法。这份资源面向自动化、机械工程、机器人学等方向的初学者与研究人员,系统讲解基于MATLAB/Simulink的建模、仿真与控制实现。压缩包为rar格式,约14KB,轻量便携,便于快速获取参考。内容覆盖一阶倒立摆的动力学方程推导,综合考虑重力、惯性、摩擦力等因素;在Simulink中搭建仿真模型,利用数学运算、信号处理和控制设计库块连接完整系统;介绍PID控制器参数整定方法,并讨论滑模控制、LQR等高级控制策略的适用场景;还展示了通过Scope块观察摆杆角度变化、在不同初始条件和外部扰动下评估控制效果的过程。已有3844人学习浏览,适合希望借助实际案例理解动态系统控制原理并开展仿真实验的学习者。
1. 一阶倒立摆到底在建模什么:先搞清楚“一阶”不是系统阶数
一阶倒立摆(也叫单级倒立摆)是我做过的最能“以小见大”的控制对象:一个小车在直线轨道上滑行,摆杆通过轴承铰接在小车顶部,目标是在不扶的情况下让摆杆保持直立,同时把小车停在预设位置或限定在导轨范围内。你叫它“一阶”,很容易误以为系统是一阶惯性环节,但它真实模型是四阶状态空间,这里的“一阶”是“一级摆”的意思。它最值钱的地方在于:建模过程跨了拉格朗日力学、非线性系统线性化、状态反馈设计、数字仿真四个环节,正好覆盖“建模与仿真分析”这条主线。不管你是做课程设计、准备研究生数学建模竞赛,还是想在 MATLAB/Simulink 里练手,这套链路都值得完整走一遍,今天我就按自己常用的落地顺序讲。
2. 从拉格朗日方程到状态空间:一阶倒立摆建模推导与选型理由
2.1 为什么我选拉格朗日而不是牛顿:建模前先想清楚机制
一阶倒立摆是两个刚体(小车加摆杆)构成的平面运动系统。用牛顿法做,第一步要对小车和摆杆分别画受力图,再引入铰链处的约束力,最后还要把约束力消掉才能得到“力到加速度”的关系,符号稍微写错一个,后面所有控制设计都会跟着错。所以常见做法是改用拉格朗日方程:把系统能量写成广义坐标的函数,直接对时间和广义坐标求导,得到动力学方程,整个过程不需要解约束力,符号检查也容易得多。
我常用的广义坐标是小车位移 x 和摆杆相对竖直方向的夹角 theta,并且约定 theta=0 表示摆杆竖直向上。注意这个方向约定非常重要,后面线性化、控制极性都以它为准。摆杆长度为 L,质心到转轴距离为 l(均匀摆杆 l=L/2),小车质量为 M,摆杆质量为 m,小车与导轨的粘滞摩擦系数为 b。把动能 T、势能 V 耗散函数 D 写出来:
动能由三部分组成:小车平动动能,摆杆质心平动动能,以及摆杆绕质心的转动动能。摆杆质心在水平方向的位置是 x + l sin(theta),竖直方向是 l cos(theta),所以质心速度平方是 x_dot^2 + 2 l cos(theta) x_dot theta_dot + l^2 theta_dot^2。摆杆转动惯量用对质心的 I 表示。因此:
T = 0.5 M x_dot^2 + 0.5 m (x_dot^2 + 2 l cos(theta) x_dot theta_dot + l^2 theta_dot^2) + 0.5 I theta_dot^2
势能 V = m g l cos(theta),这里以转轴为参考高度,theta=0 时摆杆竖直向上,势能最大。耗散项只用小车摩擦:D = 0.5 b x_dot^2,摆杆轴承摩擦先忽略,后面在避坑章节再补。
把拉格朗日量 L = T - V 代入方程,得到两条非线性动力学方程:
(M+m) x_ddot + m l cos(theta) theta_ddot - m l sin(theta) theta_dot^2 + b x_dot = F
m l cos(theta) x_ddot + (I + m l^2) theta_ddot - m g l sin(theta) = 0
这里的 F 是施加在小车上的水平外力,方向与 x 正方向一致。第一条方程描述小车和摆杆的耦合平动,第二条描述摆杆绕转轴的转动。注意如果摆杆质量分布不均匀,I 要按实际惯量算;很多初学者把 I 当成“绕转轴惯量”又额外加 ml^2,最后矩阵就重复计了一次。
下面这段 MATLAB 函数直接实现了这个非线性模型,专门用来做“被控对象”,后面所有仿真都会复用它。函数输入是状态 q=[x; x_dot; theta; theta_dot] 和参数结构体 p,输出是状态导数 dq。
function dq = inverted_pendulum_ode(t, q, p, u) % q = [x; x_dot; theta; theta_dot] % p.M 小车质量, p.m 摆杆质量, p.b 摩擦系数 % p.l 质心到转轴距离, p.I 摆杆对质心惯量, p.g 重力加速度 M = p.M; m = p.m; b = p.b; l = p.l; I = p.I; g = p.g; x = q(1); dx = q(2); theta = q(3); dtheta = q(4); % 两条动力学方程写成: % A1*ddx + B1*ddtheta = C1 % A2*ddx + B2*ddtheta = C2 A1 = M + m; B1 = m * l * cos(theta); C1 = u - b * dx + m * l * sin(theta) * dtheta^2; A2 = m * l * cos(theta); B2 = I + m * l^2; C2 = m * g * l * sin(theta); det = A1 * B2 - A2 * B1; ddx = (C1 * B2 - C2 * B1) / det; ddtheta = (A1 * C2 - A2 * C1) / det; dq = [dx; ddx; dtheta; ddtheta]; end这段代码每行都是在解一个“二元一次线性方程组”,而不是做数值积分。为什么要把方程拆成 A1d dx + B1d dtheta 的形式?因为在每个仿真时刻,cos(theta) 和 sin(theta) 都是已知的,ddx 和 ddtheta 是未知数,用克拉默法则一步就能算出来。det 是两条方程左侧系数行列式,它在模型里通常不会为零,但如果 theta 恰好走到某些奇异位置,或者参数乱填,det 会变成很小甚至零,仿真就会出 NaN,这在避坑章节会专门说。
有了被控对象函数,下一步就是线性化,因为 LQR、极点配置这些控制器的设计都离不开线性模型。
2.2 在平衡点做线性化:为什么小角度近似不是偷懒
控制目标是让摆杆停在 theta=0(竖直向上),这是一个不稳定的平衡点。在这个平衡点附近,theta 很小,sin(theta) 可以近似成 theta,cos(theta) 近似成 1,theta_dot^2 是二阶小量直接舍掉。把上面两条非线性方程做小角度近似,就得到:
(M+m) x_ddot + m l theta_ddot + b x_dot = F
m l x_ddot + (I + m l^2) theta_ddot - m g l theta = 0
这套线性方程和原来的非线性模型在 ±10 度以内误差很小,超过 15 度误差会明显变大。我一般会保留非线性模型做仿真验证,用线性模型设计控制器,这样两条腿走路。接下来要把它整理成状态空间形式 x_dot = A x + B u。状态向量选 x=[x; x_dot; theta; theta_dot],输入 u=F。经过消元,得到:
A = [0 1 0 0; 0 -(I+m l^2)b/Den -m^2 g l^2/Den 0; 0 0 0 1; 0 -m l b/Den m g l (M+m)/Den 0]
B = [0; (I+m l^2)/Den; 0; -m l/Den]
其中 Den = (M+m) I + M m l^2。这个 Den 是线性化后小车通道和摆杆通道解耦后的公共分母,它必须为正。这里有个很容易看反的符号:B 的最后一个元素是负的。它的物理直觉是:给小车一个向右的力 F,小车先向右加速,摆杆因为惯性会“相对向左倒”,所以 theta_ddot 的初始方向与 F 方向相反。很多人在这一步把 B 写反,导致后面 LQR 出来的 K 是“负反馈变成正反馈”,一闭环就发散。
下面这段脚本把参数和 A、B 矩阵定义好,后续 LQR 和 Simulink 都会从工作区取这些变量。
% 一阶倒立摆线性化状态空间模型 p.M = 0.5; % 小车质量 kg p.m = 0.2; % 摆杆质量 kg p.b = 0.1; % 小车与导轨粘滞摩擦 N/(m/s) p.L = 0.3; % 摆杆总长 m p.l = p.L / 2; % 质心到转轴距离 m p.I = p.m * p.L^2 / 12; % 摆杆对质心惯量 kg*m^2 p.g = 9.8; M = p.M; m = p.m; b = p.b; l = p.l; I = p.I; g = p.g; Den = (M + m) * I + M * m * l^2; A = [0 1 0 0; 0 -(I + m*l^2)*b/Den -m^2*g*l^2/Den 0; 0 0 0 1; 0 -m*l*b/Den m*g*l*(M+m)/Den 0]; B = [0; (I + m*l^2) / Den; 0; -m*l / Den]; C = eye(4); % 假设四个状态都可测 D = zeros(4, 1); sys_lin = ss(A, B, C, D);这段代码里的参数不是随便填的。M 和 m 的比例决定摆杆对小车运动的“反作用力”有多大;b 如果设成 0,模型会更容易发散,但控制设计也更难。C 矩阵设成单位阵,表示位置、速度、角度、角速度四个状态都能直接拿到,这在纯仿真里没问题。如果后面接真实硬件,角度和位置可以从编码器读,速度要用差分或状态观测器。
到这里,前向模型已经能用了。下面一步是把模型“跑起来”,分两路:一路用 MATLAB 脚本做非线性验证,另一路用 Simulink 做控制布局。
3. 把一阶倒立摆仿真跑起来:MATLAB/Simulink 的两种落地路径
3.1 用 MATLAB 脚本仿真非线性被控对象:先证明模型没有符号错
拿到非线性 ODE 函数和参数后,我习惯先做一个“开环下落测试”:给摆杆一个很小的初始角度 theta=0.1 rad(约 5.7 度),初始角速度也稍微给一点,然后不施加任何控制力,看摆杆是否会自然倒下并摆动。如果 theta 最终走向 180 度附近并且来回摆动,说明模型的基本符号和惯量项是对的;如果仿真直接报 NaN 或者 theta 一直单调增大到几千度,那肯定是 ODE 函数里的符号或参数有问题。
下面是完整测试脚本:
% 参数结构体 p 沿用上一节的定义 p = struct('M',0.5,'m',0.2,'b',0.1,'L',0.3,'g',9.8); p.l = p.L / 2; p.I = p.m * p.L^2 / 12; % 初始状态:小车位置0,小车速度0,摆角0.1rad,角速度0.2rad/s q0 = [0; 0; 0.1; 0.2]; tspan = [0 3]; % 开环仿真:u 恒为 0 [t, q] = ode45(@(t, q) inverted_pendulum_ode(t, q, p, 0), tspan, q0); figure; subplot(2,1,1); plot(t, q(:,3)*180/pi); xlabel('时间 (s)'); ylabel('摆杆角度 (deg)'); grid on; subplot(2,1,2); plot(t, q(:,1)); xlabel('时间 (s)'); ylabel('小车位置 (m)'); grid on;逻辑说明:ode45 在 MATLAB 里用的是变步长四阶龙格库塔法,对这类有轻微刚性但又不算刚性的多刚体系统足够。q 矩阵每行对应一个时刻的四维状态,q(:,3) 是角度,单位是弧度,所以画图时乘以 180/pi 转成度。第二个子图画小车位置,你会看到摆杆倒下过程中小车被“带着跑”,这是小车与摆杆耦合的正常表现。
参数说明:初始角速度 dtheta=0.2 rad/s 是为了打破系统在竖直倒立位置的“对称性”,否则在理想模型下摆杆可能永远停在顶端(只是数值上不稳定)。如果你把初始角度改成 0.01 rad,也会看到它慢慢倒下,只是时间更长。这里没有给控制力,所以摆杆最终绕转轴摆动,角度曲线会呈现明显的周期性。这个测试很重要,因为它验证的是“开环被控对象”,后面的控制器设计都是在给这个被控对象加反馈。
3.2 Simulink 里的“四段式”搭建:别把模型包成黑匣子
用 MATLAB 脚本做验证很快,但做控制实验时,很多人还是想用 Simulink 把输入力、被控对象、控制律、显示四个环节搭出来。我推荐的做法不是在一个框里堆一堆积分器,而是分成四个子系统,保持结构清晰。
第一个子系统是“被控对象”,可以直接用 State-Space 模块,把上一节算好的 A、B、C、D 填进模块参数里。初值设成 x0=[0;0;0.1;0.2],这样一启动摆杆就是偏的。第二个子系统是“控制律”,里面放 Gain 矩阵 K 或者 PID 控制器。第三个子系统是“输入合成”,把参考信号和反馈信号做差得到控制力 U。第四个是“显示与记录”,用 Scope 和 To Workspace 模块把状态导出到 MATLAB 工作区,方便后续画图。
实际操作时,求解器设置这一块容易踩坑。我一般把仿真时间设成 5 秒,求解器选变步长 ode45,最大步长 Max step size 设为 0.01,相对容差 1e-6。千万别用默认的 ode45 不加限制,否则当摆杆角度接近 180 度时,系统“翻倒”瞬间速度变化很快,积分步长会自动变得很小,仿真速度慢到像卡住。
下面是一份最小可用的 State-Space 模块参数清单:
| 参数项 | 设置值 | 说明 |
|---|---|---|
| State Space 的 A | A(工作区变量) | 线性化矩阵 |
| State Space 的 B | B | 输入矩阵 |
| State Space 的 C | eye(4) | 输出四个状态 |
| State Space 的 D | zeros(4,1) | 无直通 |
| 初始状态 | [0;0;0.1;0.2] | 摆杆偏离竖直方向 0.1 rad |
| 求解器 | ode45 变步长 | 适合非刚性模型 |
| Max step size | 0.01 | 防止步长过大丢失动力学细节 |
| 输出点 | To Workspace | 变量名 q_sim,格式 Timeseries |
如果你不用 State-Space 模块,而是想按积分器一点一点搭,那就要处理“加速度是由位置反馈计算出来的”这个反向依赖关系,很容易形成代数环。常见解决方法是给加速度信号串一个 1/s 积分器再变成速度,但本质上只要用 State-Space 模块或把非线性函数写成 S-Function 就可以绕开。我的建议是:既然前面已经有非线性 ODE 函数,Simulink 里可以直接用一个 S-Function 模块调用 inverted_pendulum_ode,控制输入接一个来自 LQR 增益的 Goto 线,这样既能保留非线性模型,又不会遇到代数环问题。
到这里,模型仿真链路已经通了。下面进入控制设计。
4. LQR 控制器的设计与调参:一阶倒立摆控制设计的关键
4.1 LQR 原理与 Q/R 矩阵的物理含义
一阶倒立摆是典型的多变量系统,四个状态互相耦合。PID 当然可以做,但 LQR 能一次性把四个状态纳入代价函数,设计出来的增益向量是最小二乘意义下的最优解。LQR 的目标函数是:
J = ∫ (x^T Q x + u^T R u) dt
其中 Q 是四维对角矩阵,R 是标量。Q 的对角元素分别惩罚小车位置偏差、小车速度、摆杆角度偏差、摆杆角速度。R 惩罚控制力。这里的关键是:Q 和 R 不是随便填的,它们表达的是“你愿意为纠偏付出多大力”。
我常用的初始值是 Q = diag([100, 10, 100, 1]),R = 0.01。逻辑是:摆杆角度偏差直接决定能不能“站住”,所以 Q(3,3) 尽量大;位置偏差也要管,不然小车会慢慢漂移,给 100;速度项给 10 是防止控制过于激进;角速度给 1 是因为它本身来自角度微分,已经有惩罚效果。R 给 0.01 说明控制力被允许达到几十牛顿的量级,适合小车模型。如果你用的是质量很小的小车,R 要调大,否则控制力会被放大到不切实际。
4.2 MATLAB 实战:把 LQR 接进非线性仿真,看它真的能回正
下面这段代码是在上一章的 ode45 框架里加入 LQR 控制律,直接对非线性模型做闭环仿真。这样做能同时验证两个东西:一是 LQR 线性设计在非线性模型上是否还能工作,二是 Q/R 参数是否让控制力过大。
% 设计 LQR,K 为状态反馈增益向量 Q = diag([100, 10, 100, 1]); R = 0.01; K = lqr(A, B, Q, R); % 闭环仿真:控制律 u = -K*x tspan = [0 5]; q0 = [0; 0; 0.1; 0.2]; % 初始角度 0.1rad,角速度 0.2rad/s [t, q] = ode45(@(t, q) closed_loop_ode(t, q, p, K), tspan, q0); % 画结果 figure; subplot(3,1,1); plot(t, q(:,3)*180/pi); ylabel('摆杆角度 (deg)'); grid on; subplot(3,1,2); plot(t, q(:,1)); ylabel('小车位置 (m)'); grid on; subplot(3,1,3); u = -K * q(:,2:end)'; % 注意 q 每行是状态,转置后乘 K plot(t, u); ylabel('控制力 (N)'); xlabel('时间 (s)'); grid on; % 闭环ODE函数 function dq = closed_loop_ode(t, q, p, K) x = q(1:4); u = -K * x; dq = inverted_pendulum_ode(t, q, p, u); end逻辑说明:闭环 ODE 函数先由状态 x 算出控制力 u,然后把 u 传给上一章的非线性被控对象函数。这就是“状态反馈”的基本结构。画图时注意第三个子图,控制力 u 是由 K 和状态向量逐点乘积得到的,q 矩阵有 N 行 4 列,所以先用 q 的每一行取出来乘。这个脚本运行后,第一眼看摆杆角度是不是在 0 附近收敛,第二眼看控制力是不是曲线平滑。如果控制力在初始时刻飙到几十牛顿以上,说明 R 取太小或 Q 取太大,需要回调。
参数说明:K 是 1x4 的行向量,它的每一项不是独立物理量,而是由 Q/R 耦合出来的。调参经验是:先固定 R=0.01,把 Q(3,3) 从 100 调到 500,你会发现收敛更快但控制力更猛;再把 R=0.1,控制力就温和很多。这个过程没有绝对的对错,只有“你的执行器能输出多大力”的约束。真实电机如果给出几十牛顿的指令,早就饱和了。
4.3 从 LQR 到 PID:为什么很多项目把角度环做成 PD
LQR 的全状态反馈本质上是一组比例-微分增益的组合:u = -K1x - K2x_dot - K3theta - K4dtheta。你可以把它拆成“角度 PD + 位置 PD”两个环路。很多实际项目不直接用 LQR,而是把角度环做成 PD:u = KP * theta + KD * dtheta,先把摆杆扶正,再用外环位置 PD 把小车的位移拉回零。这种做法在 Simulink 里改起来快,调试时也更直观,但它的耦合没有 LQR 那么系统化,参数只能靠试凑。
如果你只是想验证“倒立摆能站起来”,角度 PD 确实够用。但如果想写进课程设计报告,或者准备数学建模竞赛里的控制题,LQR 是更规范的选择,因为你能明确写出 Q/R 的物理意义和设计依据。后面避坑章节里那些发散问题,大部分也和 PID 参数没有理论边界有关。
5. 一阶倒立摆仿真常见问题排查:发散、抖振与模型失真
5.1 现象:仿真跑到一半 theta 直接翻过 180 度,随后变成乱跳
原因:最常见的是给控制器设置了过大的初始角度,比如 theta=0.5 rad(约 28 度)。此时线性模型的小角度假设已经不成立,LQR 在设计时只保证了 theta 在 0 附近时收敛,当 theta 大到接近水平甚至超过 90 度,非线性项会占主导,反馈增益完全按错的方向发力,摆杆就被“推”过头了。另一个原因是 R 设得太小,控制力饱和后模型飞了。
解决:把仿真里的初始角度限制在 ±0.2 rad 以内,这是线性控制器的有效范围。如果确实需要从大角度拉起,必须改成非线性控制器(比如能量整形)或先做摆起控制,再用 LQR 镇住。我在仿真里一般会加一个角度限制逻辑:当 abs(theta) 超过 0.35 rad 时,直接把控制力置零,等待摆杆回摆后再切入 LQR,这样能避免数值爆炸。
5.2 现象:闭环控制后小车高频抖振,像在“打摆子”
原因:Q 里速度项和角速度项设得太大,尤其是 Q(2,2) 和 Q(4,4)。速度惩罚过大会让控制器对微小的速度变化非常敏感,一点噪声就能产生很大的控制力变化,高频抖振随之而来。Simulink 里还会因为步长太小,在状态变量接近零时产生噪声放大。
解决:把 Q(2,2) 从 10 降到 1,Q(4,4) 从 1 降到 0.5,同时增大 R。控制力的高频成分会明显下降。另外检查一下速度信号是不是直接由位移差分得到的,如果是,给速度信号加一个一阶低通滤波,时间常数取 0.01s 左右,能有效平滑。
5.3 现象:LQR 设计时提示矩阵奇异,或者算出 K 里有 NaN
原因:A/B 矩阵的公共分母 Den 变成了零,或者某个参数被意外覆盖成了 0。Den = (M+m) I + M m l^2,当 M、m、l 都是正值时,Den 不会为零。一旦出 NaN,大概率是之前脚本里把 p 结构体里的 l 覆盖成了 0,或者 I 没有赋值。
解决:在 lqr 调用前加一句 assert(Den > 0),并打印 A 和 B 检查数值。还有一个小坑:如果 C 矩阵取了某个不可观测的组合,lqr 不会报错但仿真效果会差,检查 A 矩阵第三四列符号,theta 通道的第三列应该是正值。发现 B 最后一项符号反了,K 算出来也“能用”,但闭环仿真会瞬间发散。
5.4 现象:Simulink 仿真慢得像 PPT,跑 5 秒要等一分钟
原因:求解器步长自动缩小到极小。这种情况多出现在摆杆角度接近 180 度时,因为重力矩和惯性力在垂直向下位置形成了强非线性,步长被逼到 1e-6 以下。另一个原因是模型中存在代数环或不连续信号(比如饱和模块的 switch 点),变步长求解器在切换点反复试步。
解决:把初始角度控制在 0.2 rad 以内,避免摆杆翻过 90 度。同时设置 Max step size=0.01,并用 State-Space 模块替换手拼积分器。如果模型里用了 Saturation 限幅,勾选 Solve for continuous time 中的 “Zero-crossing detection” 选项,或把限幅换成饱和函数 smooth 近似。我自己的经验是,把纯 Simulink 模型改成 MATLAB ode45 后,速度能快几十倍,所以第一版调试一般都用脚本。
5.5 现象:小角度能回正,但是给一个 5 度以上的初始偏差就再也回不来
原因:线性模型设计时只考虑了平衡点附近的收敛,没有对角度偏差做积分。LQR 状态反馈只能保证“回到平衡”,但如果偏差稍微大一点,非线性摩擦力或者摆杆重力矩的平方项就把控制系统拖出了线性区。另一个可能原因是观测器没有引入角度偏差的积分状态,导致存在残余误差。
解决:在 LQR 框架里增加积分项,把角度偏差的积分作为第五个状态放进 A 和 B 矩阵,例如 x5 = ∫theta dt,控制律 u = -K x - Ki x5。或者更简单的办法是给角度环并联一个积分环节,但注意积分项也会让收敛变慢,初始积分值必须清零。实际到硬件上,这个问题会更明显,因为电机死区和齿轮间隙都会吃掉小角度的控制效果。
6. 仿真之后还能做什么:加摩擦、限位和抗扰验证
模型能跑通、LQR 能回正之后,先别急着收工。我一般会再加三个验证,把仿真结果从“看起来对”变成“能在实物上有参考意义”。
第一,给摆杆转轴处加一个粘滞摩擦系数 b_theta,比如 0.01 N.m.s/rad,在非线性 ODE 的 theta_ddot 表达式中加上 -b_theta*dtheta 项。这个改动很小,但能让高角速度时的抖振曲线更接近真实。
第二,给控制力加饱和限幅,比如最大输出 5N。很多仿真里控制力曲线好看,其实峰值已经飙到 20N,这在真实电机车上不可能实现。加上限幅后,如果 LQR 参数不够好,就很容易看到摆杆在饱和极限来回弹,这是衡量控制器鲁棒性的好办法。
第三,加一段脉冲扰动:在仿真进行到 2 秒时,给 theta 通道叠加一个 0.05 rad 的角度偏差,看系统能否自己回正。如果回正则说明抗扰能力足够,如果震荡超过 3 秒,说明角速度惩罚太低。这一步能直接暴露 Q/R 选择是否合理。
我做倒立摆仿真最大的教训是:当初直接用线性模型设计完就写报告,没有回到非线性模型里验证,结果到实物上推了一下,摆杆直接倒掉。从那以后,我给自己定了一个习惯:所有控制参数先在 Simulink 非线性模型里跑一轮,再写进嵌入式代码。这个习惯帮我省了很多次翻车。希望帮到你。
本文还有配套的精品资源,点击获取