资讯动态

电赛轮腿式平衡小车:姿态解算与串级PID控制实战

发布时间:2026/10/21 2:07:29 来源:尧图企业网站定制
简介这份资源是面向电子设计竞赛参赛者、自动控制与机器人方向学生的轮腿式自平衡小车完整项目包聚焦动态平衡原理与嵌入式控制实践。压缩包共1311个文件约49.48MB以C源码619个和头文件316个为主体辅以汇编、链接脚本、工程配置及数学库文件覆盖从底层驱动到控制算法的完整代码链路。项目围绕轮式推进与腿部支撑相结合的创新结构展开涉及陀螺仪与加速度计数据采集、传感器融合滤波、PID姿态控制、电机驱动逻辑及运动控制策略并可能包含硬件原理图、PCB布局、元器件清单与调试测试记录。已有585人学习下载适合希望深入理解自平衡控制、嵌入式系统开发与传感器应用的读者参考复现也可作为电赛备赛与课程设计的实战素材。1. 从一堆“趴窝”的轮腿代码说起这份电赛平衡小车资源到底能跑通什么如果你正在准备电赛控制类题目或者手头有一个轮腿式平衡小车项目卡在“能直立但走不稳、一碰就倒”的阶段这份《电赛平衡小车轮腿式平衡小车.zip》大概率能帮你省下不少从零搭框架的时间。轮腿式平衡小车和普通两轮平衡车最大的区别在于它把轮式底盘的滚动效率和腿式结构的越障能力揉在一起控制上要同时处理直立环、速度环、转向环还要协调腿部关节的位姿补偿。很多人第一次做这个结构代码写了几百行结果小车要么高频抖动要么缓慢漂移调参调到怀疑人生。这份资源的核心价值就是给出一套已经跑通基础平衡的工程框架包含姿态解算、串级PID、电机驱动和腿部舵机控制这几块适合已经学过STM32或Arduino、想直接上手轮腿结构验证算法的同学。它不是那种“点开就能用”的成品固件但骨架清晰改起来有迹可循。2. 轮腿平衡的底层逻辑姿态解算与串级PID怎么搭2.1 为什么轮腿结构不能照搬两轮平衡车的控制思路普通两轮平衡车的控制对象是一个倒立摆重心高、支撑面窄控制目标就是让轮子追着重心跑。轮腿式结构多了一对可伸缩或可摆动的腿这就带来两个新问题第一腿的位姿会改变整体重心高度和转动惯量直立环的PID参数不能固定不变第二腿在落地瞬间会给车身一个额外的冲击力矩如果速度环响应太慢这个冲击会直接反映成车身俯仰角的突变。常见做法是把腿的控制和轮的控制解耦成两个频率层轮子负责快速平衡控制周期1ms到2ms腿负责慢速姿态调整控制周期5ms到10ms。这样直立环不用频繁适应腿的动调参难度会下降不少。我一般会先让腿固定在一个中间位姿把轮子的直立环和速度环调稳再逐步加入腿的动态补偿。如果一上来就全开波形会乱成一团根本分不清是哪个环在振荡。2.2 姿态解算MPU6050原始数据到欧拉角的处理链资源里用的是MPU6050这类六轴传感器输出加速度和角速度。直接拿加速度算角度会有运动加速度干扰直接积分角速度会漂移所以必须做融合。常见方案是互补滤波或Mahony滤波资源里给的是互补滤波的简化实现计算量小适合跑在STM32F1这类没有FPU的片子上。// 互补滤波加速度计低频可信陀螺仪高频可信 // dt为控制周期单位秒alpha为滤波系数通常取0.96~0.99 float alpha 0.98f; float angle_acc atan2f(acc_y, acc_z) * 57.29578f; // 加速度解算角度 angle alpha * (angle gyro_x * dt) (1 - alpha) * angle_acc;这段代码里angle是融合后的俯仰角gyro_x是陀螺仪x轴角速度dt必须和实际控制周期严格一致。如果dt写死成0.01但实际中断是8ms角度会缓慢漂移小车会往一个方向慢慢加速。参数alpha越大越信任陀螺仪动态响应好但静态漂移明显越小越信任加速度计静态稳但运动时容易被干扰。我一般从0.98开始试如果小车静止时角度跳动超过0.5度就降到0.96。注意MPU6050的安装方向必须和代码里的轴定义一致否则角度符号反了直立环会变成正反馈一上电就满速冲出去。2.3 串级PID直立环、速度环、转向环的嵌套关系资源里的控制结构是标准串级PID外环速度环内环直立环转向环单独叠加。直立环的输入是目标角度和当前角度的偏差输出是PWM占空比速度环的输入是编码器反馈的车速和目标速度通常为0输出是目标角度的修正量。这样设计的好处是当小车被推动时速度环会通过改变目标角度让小车“追”回原位而不是硬抗。// 直立环PD控制角度偏差 角速度阻尼 float angle_error target_angle - current_angle; float gyro_rate gyro_x; // 角速度直接作为微分项避免微分噪声 float balance_out Kp_angle * angle_error - Kd_angle * gyro_rate; // 速度环PI控制编码器速度偏差输出叠加到目标角度 float speed_error target_speed - current_speed; speed_integral speed_error * dt; float speed_out Kp_speed * speed_error Ki_speed * speed_integral; // 最终目标角度 机械中值 速度环修正 target_angle mechanical_zero speed_out;这里有个关键点直立环的微分项直接用陀螺仪角速度而不是对角度做差分。角度差分噪声大陀螺仪本身测的就是角速度信噪比更好。速度环的积分限幅一定要加否则小车长时间堵转时积分会饱和松开的瞬间会猛冲。参数上Kp_angle通常从200左右开始试对应PWM满量程1000Kd_angle从0.5到2之间调Kp_speed和Ki_speed要小一个数量级先调直立再调速度顺序不能反。3. 从压缩包到跑起来工程导入与参数整定步骤3.1 工程目录结构与编译环境确认解压后一般能看到几个标准文件夹User放主函数和中断Hardware放电机、编码器、OLED驱动Control放PID和姿态解算Library是STM32标准库或HAL库。先看User/main.c里的初始化顺序常见是时钟→GPIO→定时器PWM→编码器接口→串口→MPU6050→OLED。如果用的是Keil打开.uvprojx直接编译如果是IAR注意启动文件是否匹配。编译报错最多的是库文件路径不对在工程设置里把Library目录加进Include Paths就行。# 如果用的是Makefile工程先确认交叉编译工具链 arm-none-eabi-gcc --version # 编译 make clean make -j4 # 烧录假设用st-flash st-flash write build/firmware.bin 0x8000000这段命令适用于Makefile工程-j4是四线程编译加快速度。烧录地址0x8000000是STM32F1的Flash起始地址F4系列也是这个地址但如果是F0或G0系列要查手册确认。烧录前最好先擦除全片避免旧程序残留导致中断向量表错位。3.2 电机死区与编码器极性检查上电后先别急着调PID把小车架起来让轮子悬空。给一个很小的PWM比如5%占空比看轮子转不转。如果嗡嗡响但不转说明死区没补偿。资源里一般有Motor_DeadZone宏改成实际值就行。编码器极性更关键用手往前推轮子串口打印的速度值应该是正数如果推着往前走但读数是负的把编码器计数取反否则速度环会变成正反馈小车会疯跑。// 编码器读数处理根据实际方向调整符号 int16_t encoder_raw TIM_GetCounter(TIM3); int16_t speed encoder_raw * ENCODER_DIR; // ENCODER_DIR为1或-1 TIM_SetCounter(TIM3, 0); // 每个控制周期清零测的是增量ENCODER_DIR这个宏就是用来翻转方向的改一个符号比改硬件接线快得多。控制周期清零计数器是M法测速的常规操作周期越短速度分辨率越低但延迟小。平衡车一般用2ms到5ms的测速周期。3.3 直立环参数整定先P后D看波形说话把速度环和转向环先关掉只开直立环。Kp_angle从0开始加每次加20直到小车能勉强站住但还在低频晃动。这时候加Kd_angle从0.1开始每次加0.1直到晃动明显减弱但高频抖动还没出现。如果小车往一个方向加速倒下说明机械中值不对调整mechanical_zero直到松手后小车能原地静止几秒。这个过程最好用上位机看波形没有上位机就看OLED上的角度值目标角度和实际角度的偏差应该在±2度以内。提示调直立环时电池电压要充足电压下降会导致PWM实际输出变小参数看起来“变软”调好的参数换块电池可能又不行了。3.4 速度环与转向环的叠加顺序直立环稳了之后把速度环的Kp_speed从0.1开始加Ki_speed从0.01开始。速度环的目标是让小车在原地不漂移所以target_speed设为0。如果小车缓慢往一个方向跑加大Kp_speed如果小车前后低频摆动减小Ki_speed。转向环最简单遥控器给转向指令时直接给左右轮差速Kp_turn从50开始试能顺畅转弯就行。三个环都开之后如果小车出现高频抖优先降直立环的Kd_angle如果出现低频晃优先降速度环的Ki_speed。4. 避坑与排查轮腿平衡车最容易翻车的五个地方4.1 上电就满速冲出去现象一开电机小车直接往一个方向全速跑根本来不及反应。原因姿态解算的轴方向反了或者直立环的符号写反负反馈变成了正反馈。解决先不接电机用手倾斜车身看OLED上的角度变化方向是否和实际倾斜方向一致。如果反了把angle取反或者把直立环输出取反。另外检查MPU6050的acc_y和acc_z是否对应代码里的轴。4.2 小车原地高频抖动电机发热严重现象小车能站住但一直高频抖电机烫手。原因Kd_angle太大或者陀螺仪数据没滤波噪声被微分放大。解决先降Kd_angle每次降0.2如果还抖在陀螺仪读数后加一个低通滤波截止频率设50Hz左右。另外检查控制周期是否稳定如果中断里做了OLED刷新或串口打印周期会抖动把耗时操作挪到主循环。4.3 速度环积分饱和导致“松手猛冲”现象用手按住小车几秒再松开小车会猛冲一下才恢复。原因速度环积分项在堵转时持续累加饱和后松开瞬间输出很大。解决给积分项加限幅比如speed_integral限制在±500以内同时加一个“堵转检测”如果PWM很大但编码器速度为0超过200ms强制清零积分。4.4 腿部位姿变化导致平衡点漂移现象腿伸直时小车能站住腿弯曲后小车往前倒。原因腿的位姿改变了重心机械中值需要动态补偿。解决在代码里根据腿部舵机角度查表修正mechanical_zero或者简单点把腿固定在一个常用位姿先不做动态补偿。如果比赛要求腿必须动那就把腿的控制周期放慢让轮子有时间响应。4.5 电池电压下降后参数失效现象刚充满电能站住跑十分钟后小车开始晃甚至倒。原因电机PWM输出和电池电压成正比电压降了之后同样的PID输出对应的实际力矩变小。解决在PWM输出前乘以电压补偿系数用ADC测电池电压actual_pwm pid_out * (nominal_voltage / current_voltage)。这个补偿不加调好的参数只能在满电附近有效。5. 进阶技巧用SD卡记录波形做离线调参调平衡车最痛苦的是“看不到内部状态”OLED只能显示一两个变量串口波形又受传输速率限制。我后来养成一个习惯在控制中断里把关键变量打包成结构体每10ms写一次SD卡跑完一圈把卡拔下来用Python画图。这样能同时看角度、角速度、PWM、速度四条曲线哪个环在振荡一目了然。// 每10ms调用一次数据打包写入SD卡缓冲区 typedef struct { float angle; float gyro; int16_t pwm; int16_t speed; } LogFrame; LogFrame frame {current_angle, gyro_x, balance_out, current_speed}; f_write(file, frame, sizeof(frame), bytes_written);LogFrame结构体四个变量刚好16字节对齐后写入效率高。SD卡用SPI模式初始化时先降速到400kHz识别成功后再切到高速。注意不要在中断里直接写SD卡写入耗时可能几毫秒会打乱控制周期。正确做法是中断里把数据放进环形缓冲区主循环慢慢写。# 上位机解析用numpy读二进制文件并画图 import numpy as np import matplotlib.pyplot as plt data np.fromfile(log.bin, dtypenp.dtype([ (angle, f4), (gyro, f4), (pwm, i2), (speed, i2) ])) fig, ax plt.subplots(4, 1, sharexTrue) ax[0].plot(data[angle]); ax[0].set_ylabel(Angle) ax[1].plot(data[gyro]); ax[1].set_ylabel(Gyro) ax[2].plot(data[pwm]); ax[2].set_ylabel(PWM) ax[3].plot(data[speed]); ax[3].set_ylabel(Speed) plt.show()这段Python代码用np.fromfile直接读二进制dtype要和C结构体严格对应f4是小端四字节浮点i2是小端两字节整数。画出来的四条曲线如果角度和PWM相位差接近180度说明直立环在正确工作如果速度曲线有低频包络说明速度环积分太强。从那以后我每次调新车都强制走一遍SD卡记录哪怕只是换个电机也先跑一圈看波形再改参数省得靠猜。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑