资讯动态

基于STM32的轮腿式平衡小车:MPU6050姿态解算与三环PID控制

发布时间:2026/10/17 19:12:14 来源:尧图企业网站定制
简介面向电赛的轮腿式平衡小车完整工程包覆盖硬件配置、传感器融合、平衡控制与运动调试全流程。资源基于STM32平台结合轮式驱动与腿部支撑结构可供电子设计竞赛备赛、嵌入式控制算法学习及机器人项目二次开发参考。压缩包共1311个文件体积约49.48MB以C语言源文件619个和头文件316个为主体另有汇编启动文件、链接脚本、Keil开发环境工程、STM32CubeMX配置、CMSIS-DSP数字信号处理库、可烧录的hex固件等方便直接编译、烧录与调试。项目内可系统学习PID控制、卡尔曼滤波、IMU数据处理与电机驱动逻辑并借助调试脚本和文档快速复现整机方案。对于自动控制与机器人方向开发者这套资料能有效降低轮腿式平衡车的复现门槛已有584人学习很适合作为电赛实战与项目进阶的参考。1. 轮腿式平衡小车一个底盘两种走路姿势市面上的电赛平衡小车绝大多数是把两个直流减速电机直接固定在底盘两侧靠PID把车身立起来。这个项目不太一样轮子不是装在底盘上而是挂在两条腿的末端。收腿时它是一台标准的两轮自平衡车能原地转、能走直线展开腿部摆臂之后轮子变成支撑点整车可以用步进的方式跨过小台阶和减速带。翻遍工程的源码MPU6050姿态解算、一阶互补滤波、三环PID、轮腿模式切换、串口波形调试这些底层的活都已经做完了拿到手可以直接编译烧录。这个资源适合两类人。一类是第一次接触平衡类控制的新手想搞清楚传感器数据到底怎么一步步变成PWM输出另一类是准备在竞赛里做二次开发的老手想在轮腿结构上挂自己的超声波模块、摄像头或者自定义遥控协议。我拆这份工程的时候发现它的代码分层做得很干净控制逻辑全放在中断里主循环只做调试和显示这种结构非常利于在上面加自己的功能。2. 软硬件架构从STM32F103到电机的完整链路2.1 硬件选型为什么是这个组合先看整车的器件清单这套工程的硬件选型非常典型几乎每个模块都能在淘宝上直接买到而且价格都不高。我把它们在系统里承担的角色整理成了下面这张表。模块型号选型在系统里承担的工作主控STM32F103C8T6姿态解算、PID运算、模式管理姿态传感器MPU6050输出三轴加速度和三轴角速度电机带霍尔编码器的直流减速电机1:30提供轮端力矩和速度测量电机驱动TB6612FNG双路H桥输出PWM并支持换向腿摆机构金属齿轮舵机轮腿两种形态的展开与收拢电源7.4V 2S锂电池 5V稳压电机直接吃电池电逻辑部分吃5V调试OLEDSSD1306 串口显示角度和PID参数、向PC发送波形STM32F103C8T6是72MHz主频、64KB Flash、20KB RAM。这套系统的控制周期跑2ms一次每次中断里做一次I2C读取、一次互补滤波、三个PID计算和一路PWM更新CPU占用不超过三成。想换成F407完全没必要多出来的性能在这个场景里用不上反而会引入更大的封装和更高的功耗。MPU6050提供六轴数据工程里实际使用的是俯仰轴的加速度和角速度Z轴的角速度则用来给转向环提供阻尼。电机减速比选1:30是个均衡点1:10减速比的车响应很快但电流一大电机就发烫跑几分钟控制就会变软1:50以上的减速比力矩大但转速不够跨台阶时轮子反而转不动。1:30能让车既能站稳又保留一点速度余量去完成步进动作。舵机驱动的腿摆机构是这台车和普通平衡车最大的区别。腿摆臂的末端装轮子舵机控制摆臂的开合角度。收腿时整车重心低适合高速行驶展开腿后重心抬高但轮子可以小角度抬起实现类似步行的跨障动作。这种轮腿融合的结构在机械上并不复杂难的是控制逻辑要能识别当前处于哪种形态并动态调整PID参数。2.2 工程目录控制代码都放在哪源码包解压后是一个CubeMX生成的MDK工程。目录结构不算复杂核心代码集中在App目录下CubeMX生成的外设代码在Core里。我从头到尾标了一遍文件职责非常清晰。BalanceCar/ ├── Core/ │ ├── Inc/ │ └── Src/ │ ├── main.c │ ├── stm32f1xx_it.c │ └── gpio.c ├── App/ │ ├── balance_task.c # 2ms控制主循环三环PID在这里串联 │ ├── filter.c # 一阶互补滤波 │ ├── pid.c # 通用PID结构体 │ ├── mpu6050.c # I2C驱动与姿态解算 │ ├── encoder.c # 编码器速度测量 │ ├── motor.c # PWM输出与方向控制 │ ├── mode_switch.c # 轮腿切换状态机 │ └── uart_debug.c # 串口波形发送 ├── User/ │ └── main.c ├── Drivers/ ├── Output/ └── BalanceCar.ioc # CubeMX配置文件main函数里的while(1)只做三件事扫描按键、刷新OLED、处理遥控指令。真正的控制节奏由TIM3定时器中断驱动每2ms进入一次Balance_Task。中断里依次执行MPU6050读数据、互补滤波更新角度、编码器算速度、串级PID计算、PWM输出全部走完一趟大约耗时0.6ms剩余时间留给系统处理中断嵌套。这里要特别提醒一个新手常踩的坑千万不要在控制中断里调用HAL_Delay或者串口阻塞发送。串口打印一帧12字节在115200波特率下要花大约1ms如果放在控制中断里整个控制周期会被拉长到3ms直立环的相位裕度直接被吃掉车会开始低频抖动。我一般把波形发送放在主循环里并且用DMA或者双缓冲避免阻塞。2.3 三环PID在整车上的分工整车控制由三个PID环串联组成各自的任务边界非常明确。直立环是整个系统的命脉它输入目标角度通常为0测量值是MPU6050融合出来的俯仰角输出是跟倾角偏差成正比的PWM直接叠加到左右两个电机。可以把它理解成一根弹簧倾角越大回正力越大车就越倾向于站直。速度环在直立环外面它输出的不是PWM而是“目标角度修正量”当编码器测到车在后退速度环就让目标角度往前倾斜几度车为了追上重心自然会往前走。转向环则只输出左右轮的差速让车绕Z轴转动。控制环输入测量量输出典型参数范围直立环0 或速度环修正俯仰角同向PWMKP 200~500速度环目标速度编码器速度目标角度修正KP 15~40KI 0.2~1转向环目标角速度陀螺仪Z轴差速PWMKP 5~20表格里的参数范围只是一个起点实际值跟电机型号、供电电压、整车重量都有关系后面第四章会专门讲整定顺序。这里记住一个原则内环响应速度必须远高于外环。直立环2ms跑一次速度环的反馈来自编码器积分每10ms更新一次绰绰有余。如果两个环跑在同一个周期里速度环的延迟会直接串进直立环的回路车子会表现出“一抽一抽”的步进感那是典型的环路带宽没有拉开。3. 核心代码拆解姿态融合、串级PID与轮腿切换状态机3.1 MPU6050读取和一阶互补滤波姿态部分的核心代码只有几十行。它做了两件事通过I2C把MPU6050的原始寄存器数据读出来再用一阶互补滤波把加速度计和陀螺仪合并成一个稳定的单轴角度。代码里只处理了俯仰角因为这个工程中车身只在前后方向上有平衡需求。// mpu6050.c 关键片段读取原始数据并融合出俯仰角 #define MPU6050_ADDR (0x68 1) // I2C器件地址AD0接地 #define GYRO_SCALE 2000.0f / 32768.0f // 陀螺仪量程±2000dps16位ADC #define RAD_TO_DEG 57.29578f static float angle_pitch 0.0f; // 融合后的俯仰角单位° static float gyro_bias 0.0f; // 陀螺仪零漂上电静止时校准 void MPU6050_Update(float dt) { uint8_t buf[14]; int16_t acc[3], gyro[3]; // 一次读取 0x3B 开始的 14 字节加速度计陀螺仪原始值 HAL_I2C_Mem_Read(hi2c1, MPU6050_ADDR, 0x3B, I2C_MEMADD_SIZE_8BIT, buf, 14, 100); acc[0] (buf[0] 8) | buf[1]; acc[1] (buf[2] 8) | buf[3]; acc[2] (buf[4] 8) | buf[5]; gyro[0] (buf[8] 8) | buf[9]; gyro[1] (buf[10] 8) | buf[11]; gyro[2] (buf[12] 8) | buf[13]; // 加速度计求俯仰角重力在Y和Z轴上的分量投影 float acc_pitch atan2f((float)acc[1], (float)acc[2]) * RAD_TO_DEG; // 陀螺仪积分先扣掉零漂 float gyro_rate (float)gyro[0] * GYRO_SCALE - gyro_bias; float gyro_pitch angle_pitch gyro_rate * dt; // 一阶互补滤波长期信加速度计短期信陀螺仪 angle_pitch 0.98f * gyro_pitch 0.02f * acc_pitch; }为什么不在这里上卡尔曼滤波F103的算力做卡尔曼会占用大量时间每次矩阵运算几百微秒塞进2ms控制周期里会让中断变得很挤。一阶互补滤波在频域上的特性和卡尔曼滤波在这个场景下表现非常接近加速度计低频准确但高频噪声大陀螺仪高频可靠但低频会漂移互补滤波就是让两个传感器在各自擅长的频段上发声。参数说明GYRO_SCALE是陀螺仪的比例因子量程±2000dps时16位ADC输出±32768每个LSB对应约0.061°/s。ACCEL_SCALE虽然没有显式写出来但atan2f里两个加速度轴相除单位比例自然抵消。0.98和0.02是滤波权重权重越大越信任陀螺仪波形更平滑但响应变慢。注意这个权重跟控制周期dt是耦合的如果把控制周期从2ms改成5ms0.98需要调大到约0.995才能维持同样的滤波时间常数。零漂gyro_bias在上电静止时采样100次取平均得到不消零漂的话车会在静止状态慢慢朝一个方向偏。3.2 串级PID三个环怎么衔接源码里的PID实现是一个通用的结构体加一个计算函数串级的结构体现在Balance_Task里。先看通用PID的实现// pid.c 通用PID结构体与计算函数 typedef struct { float kp, ki, kd; float integral; float last_error; float out_limit; // 输出限幅防止积分饱和和突变 } PID_t; float PID_Compute(PID_t *pid, float target, float measure, float dt) { float err target - measure; // 积分分离误差过大时停止积分防止上电瞬间积分起飞 if (err -10.0f err 10.0f) { pid-integral err * dt; } float diff (err - pid-last_error) / dt; pid-last_error err; float out pid-kp * err pid-ki * pid-integral pid-kd * diff; if (out pid-out_limit) out pid-out_limit; if (out -pid-out_limit) out -pid-out_limit; return out; }然后看2ms控制主循环里三个环是怎么串联起来的// balance_task.c 每2ms由TIM3中断调用一次 void Balance_Task(void) { static const float dt 0.002f; MPU6050_Update(dt); // 1. 更新姿态角 speed_measure Encoder_GetSpeed(); // 2. 编码器测速 // 3. 速度环(外环)目标速度0输出是目标倾角修正量 float angle_extra PID_Compute(g_pid_speed, 0.0f, speed_measure, dt); // 4. 直立环(内环)让实际俯仰角跟踪修正后的目标角 float balance_out PID_Compute(g_pid_balance, angle_extra, angle_pitch, dt); // 5. 转向环目标角速度默认0遥控时外部赋值 float turn_out PID_Compute(g_pid_turn, 0.0f, gyro_yaw, dt); // 6. 差速合成同向输出差速输出 float pwm_left balance_out turn_out; float pwm_right balance_out - turn_out; Motor_SetPWM(pwm_left, pwm_right); }代码里的执行顺序非常考究。MPU6050_Update必须在速度环之前因为速度环输出的角度修正量最终要和实测角度比较角度数据必须是当前控制周期的。速度环与直立环的衔接是串级结构的核心速度环的误差为正车正在后退时angle_extra会输出一个正角度让车往前倾重力分量把车往前拉编码器速度逐渐归零这就是速度环影响直立环目标值的完整闭环。积分分离是一个很实用的保护。第一次上电调车时我遇到过整车被PWM直接“踹”飞的情况查到最后就是上电瞬间角度偏差巨大积分项瞬间饱和。加上误差大于10度停止积分之后上电过程才变得可控。输出限幅也值得注意PWM用了定时器ARR999的周期理论上满占空比是999。我把直立环的out_limit设成700留出30%的余量给转向环和速度环的修正防止两个环的输出叠加后超出PWM范围产生削顶失真。3.3 轮腿切换限位开关触发一次形态转变轮腿切换的代码是一个典型的有限状态机只有两个状态轮式MODE_WHEEL和腿式MODE_LEG。切换条件来自遥控器通道或者板载按键切换动作本身则由腿部舵机和限位开关配合完成。// mode_switch.c 轮腿双模式状态机 typedef enum { MODE_WHEEL 0x01, MODE_LEG 0x02 } RunMode_t; static RunMode_t current_mode MODE_WHEEL; static float angle_offset 0.0f; // 腿式重心补偿角单位° void Mode_SwitchTask(void) { uint8_t switch_cmd Remote_GetSwitchChannel(); // 遥控器通道 uint8_t leg_ok GPIO_ReadPin(LEG_LIMIT_PORT, LEG_LIMIT_PIN); if (switch_cmd 1 current_mode MODE_WHEEL) { // 轮式切腿式先低速收腿等限位开关到位 Leg_MoveTo(LEG_FOLD_ANGLE); if (leg_ok) { current_mode MODE_LEG; angle_offset -3.5f; // 重心前移补偿倾斜角 PID_GainScale(0.6f); // 先降强度避免切换抖动 } } else if (switch_cmd 0 current_mode MODE_LEG) { // 腿式切轮式展开摆腿同样等限位开关 Leg_MoveTo(LEG_EXTEND_ANGLE); if (leg_ok) { current_mode MODE_WHEEL; angle_offset 0.0f; PID_GainScale(1.0f); // 恢复完整PID增益 } } }切换过程的关键在限位开关。腿部机构从折叠到展开机械上有一个明显的行程终点到达终点时微动开关会触发。我见过有人用延时来替代限位开关舵机动作200ms后直接切换模式结果十次里有三次摔车。原因很简单舵机堵转或者负载变化时走到位的时间漂移很大延时估算根本不靠谱。angle_offset这个偏移量是腿式模式特有的补偿。展开腿之后整车重心会明显前移如果还按轮式模式把目标角度设为0车会不停往后退来找平衡点。正确的做法是切到腿式后把车扶稳读取当前静止时的俯仰角把它的相反数写进angle_offset目标角度就变成了angle_pitch -3.5°车在腿式模式下就能稳定站住。4. 从烧录到跑通编译、波形调试与调参顺序4.1 工程导入与烧录用KEIL MDK 5打开工程根目录下的BalanceCar.uvprojx第一次编译前先确认三件事魔术棒选项卡里芯片型号是STM32F103C8T6Flash Download里勾选了Reset and RunST-Link调试器的SWD接口接线正确。烧录配置里我习惯把下载速度从默认的4MHz降到1MHz特别是用杜邦线连接ST-Link时高速下载经常偶发校验失败降速后一次过。烧录完成后先不要放地上跑。打开串口助手115200波特率正常的话OLED屏会显示当前的俯仰角串口会以50Hz的频率往外吐数据。把车拿在手里前后缓慢转动观察OLED上的角度数值是否跟随变化且方向正确。如果角度变化方向反了说明MPU6050的安装方向或者安装角度定义有问题把传感器转180度重新贴而不是在代码里改符号——代码里强行改符号容易让后续的PID极性判断一团糟。4.2 串口波形把PID曲线拉到电脑上看调PID全靠看角度数字是没法调的必须看波形。源码里已经实现了VOFA的JustFloat协议一帧12字节三个float分别发送目标角度、实际俯仰角和直立环输出。VOFA的上位机设置为波特率115200协议选择JustFloat打开串口就能看到三条实时曲线。// uart_debug.c 发送3个floatVOFA JustFloat帧格式 float dbg_array[3]; dbg_array[0] angle_target; // 目标角度 dbg_array[1] angle_pitch; // 实际俯仰角 dbg_array[2] balance_out; // 直立环输出 uint8_t tx_buf[12]; memcpy(tx_buf, dbg_array, 12); // float在STM32小端模式下本身就是4字节 HAL_UART_Transmit(huart1, tx_buf, 12, 10);JustFloat协议比文本协议高效得多文本模式每秒发50帧、每帧几十个字符串口带宽直接占满JustFloat每帧固定12字节115200波特率下占用不到5%剩下的带宽留给遥控指令和日志打印。看波形时重点观察两个时刻一是车拿在手里前后摆动时实际角度曲线是否平滑跟随目标角度有没有明显滞后二是把车放下让它自平衡时两条曲线是否在一个小范围内纠缠震荡振幅越大说明增益越接近临界。4.3 调参顺序先直立再速度最后转向调参顺序是这份源码里最值得抄作业的部分。三步走的策略能保证每一步都有明确的验证标准而不是靠运气和手感。第一步调直立环。把速度环和转向环的目标全部清零只保留直立环。KP从小往大加KP太小车放下后会缓慢倒下角度曲线一路偏离KP合适车能原地站立3秒以上用手推一下会快速回正回正过程中有一两次过冲但能收敛KP过大车会以几赫兹的频率高频抖动电机发烫。抖动出现时先降KP再加一点KDKD能把高频分量压掉但KD太大会引入新的噪声所以KD只在临界抖动时用。直立环调好之后车应该能无支撑站立不倒这是进入下一步的前提。第二步调速度环。速度环的目标固定为0从KP10开始加。验证方法是推一下车观察它是否回正到原来的位置推它一下它往前走一点然后停住说明速度环正常如果推完它停不住越走越远说明速度环的反馈极性反了把Encoder_GetSpeed的符号取反如果推完它剧烈来回振荡说明速度环KP过大。速度环还有一个积分项KI它的作用是消除静态误差——车放在不平的地面上直立环会让它慢慢往低处溜KI能把这个趋势收住。KI从小往大加加到车在倾斜地面上也能原地不动即可。第三步调转向环。转向环最宽松KP从5开始加手持车绕Z轴转动感受阻尼阻尼感适中、能迅速停住转动就是合适的值。转向环调不好最多是转向不够灵敏或发飘不会让车摔倒所以放在最后处理。4.4 电池电压监测与低电保护调参过程中有一个容易被忽略的变量是电池电压。7.4V锂电池从满电到截止电压电压变化超过1V而电机在同一PWM占空比下的输出力矩跟电压近似成正比。换句话说上午调好的参数下午电池电压降了车就会变软甚至点头。源码里加了一个低电保护逻辑用ADC采集电池电压通过分压电阻接入PA1引脚。// power.c 每500ms检查一次电池电压 void Power_CheckTask(void) { voltage ADC_GetBatteryVoltage(); // 分压电阻校准后的电池电压 if (voltage 7.2f) { speed_target 0; // 第一阈值禁止速度指令 } if (voltage 6.8f) { Motor_SetPWM(0, 0); // 第二阈值直接停机保护 LED_Alarm(); } }电压采集的时机放在慢任务里每500ms检查一次。电压回差要留够如果单一阈值在7.0V电压在阈值附近抖动会让电机反复启停我一般设两个阈值7.2V先限制功能6.8V才彻底停机中间留出电压回差。5. 避坑笔记这台小车最容易翻车的五个瞬间5.1 现象上电瞬间电机猛转车直接弹出去第一次给这台小车上电时我的反应是立刻拔掉电池——电机在接通电源的瞬间以最大占空比猛转了一下车直接从桌上弹飞了。原因上电时序里PWM使能早于MPU6050初始化完成。传感器还在配置寄存器时读出的数据全是0俯仰角被算成0度直立环认为车身已经站直了于是输出0。但电机驱动芯片此时已经使能一旦传感器输出一个瞬间的跳变直立环就会在几个控制周期内输出满占空比。解决把PWM输出使能放到MPU6050初始化并完成静止校准之后再延时200ms等待传感器数据稳定。同时在上电后的前1秒内让目标角度从当前实测角度缓慢过渡到0而不是直接设定为0这样即使车放得不水平上电瞬间也不会产生大角度误差。5.2 现象静止时电机嗡嗡抖动车身发烫调好参数的车放在地上能站住但电机一直发出高频嗡嗡声用手摸电机外壳明显发烫电池的掉电速度也比预期快得多。原因直立环的KP太大系统进入了极限环振荡。控制周期2ms但KP的增益让每个周期都产生一个超出阻尼能力的修正量车实际上在以一个肉眼几乎看不清的频率来回微荡。另一个常见原因是控制周期不稳定——串口阻塞或OLED刷新占用了中断时间导致控制周期从2ms漂到3ms、4ms。解决先降KP直到静止时听不到高频噪声再检查中断优先级确认TIM3中断优先级高于所有外设中断同时把OLED刷新和串口打印全部移出中断放到主循环最后在互补滤波里把权重从0.98往0.995方向微调角度输出会更平滑给微分项减少噪声输入。5.3 现象满电时好好的跑几分钟后控制变软上午调完参数车能稳定跑直线。下午换了一块快没电的电池车就开始前后点头速度环也回不正位置。原因电池电压下降后电机在同一PWM占空比下的力矩输出变小。我调参时是在满电状态整定的PID的增益是针对满电压的力矩水平设计的电压一降等效于整个被控对象的增益降了一截。直立环的相位裕度随之下降系统开始接近临界不稳定。解决加电压前馈补偿。ADC实时采样电池电压在Motor_SetPWM之前对输出做一次校正PWM输出乘以一个系数系数等于标称电压除以当前电压。7.4V标称实测6.8V时补偿系数约1.09。这个补偿不参与PID计算只作用在最终输出上不会影响已经整定好的环路稳定性。同时配合第四章的低电保护把保护阈值设好。5.4 现象MPU6050数据偶尔跳变车突然猛点头运行过程中角度波形偶尔出现一个尖锐的毛刺持续一个控制周期但就是这一个毛刺会让直立环输出一个很大的尖峰车会猛地顿一下。原因I2C线使用了过长的杜邦线电机启停瞬间的大电流在线上感应出噪声导致I2C读到错误的字节。MPU6050挂在1米长的杜邦线上I2C是开漏结构线上阻抗不匹配很容易产生位错误。解决硬件上把I2C线剪短到10cm以内加上4.7k上拉电阻并用胶带把线束固定在底盘上减少电机震动带来的接触不良。软件上做一层中值滤波如果当前角度变化率超过一个阈值比如每2ms超过2度就丢弃这一拍直接沿用上一拍的角度值。这个保护只拦截突变正常运动不受影响。5.5 现象轮腿切换的瞬间整车直接摔倒轮式模式下跑得好好的一切换到腿式模式车先是一抖然后朝着一个方向干脆利落地倒下去不带一点犹豫。原因切换瞬间腿部机构的重心突变。展开腿的过程在100ms内完成整车重心从低位移到高位直立环按原来的增益和原来的目标角度去平衡一个已经变了结构的车结果就是过冲。更隐蔽的问题是切换动作本身还没完成时限位开关还没有触发但控制代码已经开始按新模式跑了。解决按3.3节的状态机设计把切换过程拆成三个步骤先降低直立环增益到原来的0.6倍再执行舵机动作等限位开关到位后才切换模式和恢复增益。同时标定腿式模式的重心补偿角度在稳定状态下让车自己调整一个小角度来抵消重心偏移。从那以后我每次改完机械结构都会重新走一遍这个切换流程不确认限位开关的触发时序就不下地。6. 二次开发超声波避障、蓝牙遥控与在线调参6.1 超声波避障优先级覆盖转向环输出在车头装一个HC-SR04超声波模块只在转向环上做优先级覆盖不动直立环和速度环的代码。当测距结果小于30cm时把转向环的目标角速度强制设为一个转弯值距离恢复到安全范围后切回正常遥控目标。注意覆盖逻辑必须在Balance_Task之外计算好只把最终的目标角速度放进PID结构体避免在中断里跑超声波测距。6.2 蓝牙遥控透传协议与校验用HC-08蓝牙模块接USART2协议帧定成三字节0xAA帧头、命令字节、校验和。命令字节里bit6~bit4是目标速度档位bit3~bit0是转向量。解析放在主循环里每50ms扫描一次串口缓冲区解析成功后直接写入速度环和转向环的目标值。校验和只做一次异或成本低能挡掉大部分空中干扰。6.3 OLED在线调参不用重新烧录也能改PID把三个PID结构体里的kp、ki、kd全部暴露成全局变量在OLED菜单里用按键调整长按确认后写入内部Flash的最后一个扇区。上电时先读取Flash读不到就用默认参数。这样一个下午就能把车从“能站住”调到“跑得稳”省去无数次拔下ST-Link重新烧录的时间。改参数后先用波形确认角度曲线收敛再下地跑别一边跑一边盯着OLED改数。做完这些改造之后我养成了一个固定习惯每次换电池、换轮胎或者改机械结构都先做一次上电悬停测试观察电机响应方向和波形是否正常再开始跑功能。整车控制这种项目机械和软件永远是一体的改了一边不动另一边迟早会在某个瞬间给你翻车。希望帮到你。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑