平衡车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仿真,源程序说明,模型制作方法及图片

!GUIDE平衡车仿真界面截图

核心回调函数分享一个,比如“启动仿真”的:

% --- 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°以内,速度波动也不大。

四、简易物理模型制作

仿真玩腻了,想做个实物模型?材料超便宜:

  1. 驱动轮与电机: 某宝10块钱一对的TT电机+小车轮,配L298N/L293D驱动板。
  2. 控制板: Arduino Uno/Nano,性价比之王,资料多到爆。
  3. 姿态传感器: MPU6050六轴传感器,3块钱一个,能直接读倾角和角速度,不用自己写卡尔曼滤波(库文件Arduino IDE里直接搜MPU6050就能找到)。
  4. 车架: 用硬纸板或者PVC板裁剪,做成倒T型,底部装电机,顶部装MPU6050和电池。
  5. 电源: 3节7号电池(1.5V×3=4.5V),刚好给L298N和电机供电,或者用18650锂电池(需要加降压模块到5V给MPU6050和Arduino供电)。

!硬纸板制作的简易平衡车实物图

Logo

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

更多推荐