平衡车GUI:一阶倒立摆模型制作、仿真与源程序说明
平衡车GUI:一阶倒立摆,GUI仿真,源程序说明,模型制作方法及图片
想自己搭个平衡车玩?先别急着焊板子烧电机,用MATLAB/Simulink搭个一阶倒立摆的GUI仿真器练手太爽了——直接在电脑上调PID、看实时姿态曲线,甚至还能仿真加减速,踩雷成本低到几乎为零!
一、平衡车核心模型:一阶倒立摆的简化
平衡车本质就是一个“带轮子的一阶倒立摆”嘛!把人和车整体看成倒立摆的摆杆,两轮等效成一个驱动轮(简化模型常用,双轮的话算法更复杂,但核心思路一样),只考虑x轴方向的位移和摆杆的倾斜角θ,忽略摩擦、空气阻力这些小因素,就能列运动学方程啦:
% 简化一阶倒立摆运动学方程求解器函数
function dx = invPendulumODE(t, x, params, u)
% 输入参数:时间t,状态向量x,系统参数,控制输入u
% 状态向量:x(1)=小车位移x,x(2)=小车速度x_dot,x(3)=摆杆倾角θ,x(4)=摆杆角速度θ_dot
% 系统参数定义
m = params.m; % 摆杆(人+车)质量 kg
M = params.M; % 驱动轮质量 kg
L = params.L; % 摆杆重心到轮轴距离 m
g = params.g; % 重力加速度 m/s²
% 计算状态导数
dx = zeros(4, 1);
dx(1) = x(2);
dx(2) = (u + m*L*(x(4)^2)*sin(x(3)) - m*g*sin(x(3))*cos(x(3))) / (M + m - m*(cos(x(3))^2));
dx(3) = x(4);
dx(4) = ( (M + m)*g*sin(x(3)) - u*cos(x(3)) - m*L*(x(4)^2)*sin(x(3))*cos(x(3)) ) / ( L*(M + m - m*(cos(x(3))^2)) );
end
这个函数是仿真的“心脏”,Simulink里会用ODE45求解器调用它算每一步的状态,不用自己手动积分,超省心。
二、MATLAB/Simulink GUI仿真界面
我用GUIDE拖了个简单但够用的界面,包含参数设置区(可以改m/M/L/g的值模拟不同载重)、PID参数调节区、实时状态显示区(摆杆倾角、小车速度)、曲线绘制区(位移x、速度xdot、倾角θ、角速度θdot)、操作按钮区(启动/暂停/重置,手动给速度扰动)。
平衡车GUI:一阶倒立摆,GUI仿真,源程序说明,模型制作方法及图片
核心回调函数分享一个,比如“启动仿真”的:
% --- Executes on button press in btnStart.
function btnStart_Callback(hObject, eventdata, handles)
% 获取当前GUI句柄下的系统参数和PID参数
handles.params.m = str2double(get(handles.editM, 'String'));
handles.params.M = str2double(get(handles.editMCar, 'String'));
handles.params.L = str2double(get(handles.editL, 'String'));
handles.params.g = str2double(get(handles.editG, 'String'));
handles.PID.Kp = str2double(get(handles.editKp, 'String'));
handles.PID.Ki = str2double(get(handles.editKi, 'String'));
handles.PID.Kd = str2double(get(handles.editKd, 'String'));
% 初始化状态向量,假设初始小车不动,摆杆轻微倾斜(比如0.1rad)
handles.x0 = [0; 0; 0.1; 0];
% 初始化积分项
handles.PID.Integral = 0;
% 初始化时间变量
handles.t = 0;
handles.dt = 0.01; % 仿真步长
% 开启定时器,每隔dt执行一次仿真
handles.timer = timer('ExecutionMode', 'fixedRate', 'Period', handles.dt, ...
'TimerFcn', @(src,evt)simStep(src,evt,handles));
start(handles.timer);
% 更新GUIDE数据
guidata(hObject, handles);
end
三、PID控制器代码与调试技巧
平衡车稳定的关键就是双环PID控制:外环控摆杆倾角θ(让它保持垂直),内环控小车速度x_dot(配合外环避免位移过大)。我这里为了简化,只用了单环倾角PID,但加个速度环也很简单,复制粘贴外环代码改变量就行。
% --- 定时器回调的仿真计算函数
function simStep(src,evt,handles)
% 获取当前状态
x = handles.x0;
% 计算控制输入u(倾角PID)
error = x(3); % 误差=目标倾角(0rad)-当前倾角
handles.PID.Integral = handles.PID.Integral + error * handles.dt;
derivative = x(4); % 角速度直接是状态的导数
u = handles.PID.Kp * error + handles.PID.Ki * handles.PID.Integral + handles.PID.Kd * derivative;
% 调用运动学方程求解器算下一步状态
dx = invPendulumODE(handles.t, x, handles.params, u);
handles.x0 = x + dx * handles.dt;
handles.t = handles.t + handles.dt;
% 更新界面显示
set(handles.txtTheta, 'String', num2str(rad2deg(x(3))));
set(handles.txtVel, 'String', num2str(x(2)));
% 更新曲线
axes(handles.axes1);
hold on;
plot(handles.t, rad2deg(x(3)), 'r.', 'MarkerSize', 5);
ylim([-45 45]);
xlabel('Time (s)');
ylabel('摆杆倾角 (°)');
title('实时倾角曲线');
axes(handles.axes2);
hold on;
plot(handles.t, x(2), 'b.', 'MarkerSize', 5);
ylim([-2 2]);
xlabel('Time (s)');
ylabel('小车速度 (m/s)');
title('实时速度曲线');
% 更新GUIDE数据
guidata(handles.figure1, handles);
end
调试小技巧: Kp先给个小值(比如50),让摆杆能晃起来;Ki慢慢加(每次+0.1),消除稳态误差;Kd最后加(每次+1),抑制震荡。我试了一下,Kp=60,Ki=0.5,Kd=5的时候,摆杆能在2秒内回正到0.1°以内,速度波动也不大。
四、简易物理模型制作
仿真玩腻了,想做个实物模型?材料超便宜:
- 驱动轮与电机: 某宝10块钱一对的TT电机+小车轮,配L298N/L293D驱动板。
- 控制板: Arduino Uno/Nano,性价比之王,资料多到爆。
- 姿态传感器: MPU6050六轴传感器,3块钱一个,能直接读倾角和角速度,不用自己写卡尔曼滤波(库文件Arduino IDE里直接搜MPU6050就能找到)。
- 车架: 用硬纸板或者PVC板裁剪,做成倒T型,底部装电机,顶部装MPU6050和电池。
- 电源: 3节7号电池(1.5V×3=4.5V),刚好给L298N和电机供电,或者用18650锂电池(需要加降压模块到5V给MPU6050和Arduino供电)。

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)