ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TM4C123G飞控实战:四元数姿态解算与串级PID调参全解析

TM4C123G飞控实战:四元数姿态解算与串级PID调参全解析 简介基于德州仪器TM4C123G单片机的飞控系统资料包面向电子信息、自动化及计算机相关专业学生适用于课程设计、毕业设计或飞控入门进阶。工程已实现定高与姿态两种控制模式姿态解算和控制算法移植自匿名领航者并兼容匿名地面站支持在线调参。包内共512个文件以C语言源码和头文件为主205个h、117个c还包括MDK/IAR/CCS等多套工程配置、编译生成的o/axf/hex/map文件、PCB/原理图、说明文档与演示图片总计24.47MB目录结构便于检索。该资料为高分项目代码经测试运行稳定配套详细文档和调参说明可帮助理解飞控算法与嵌入式开发流程也便于在此基础上二次开发。目前已有140人学习下载适合动手实践与项目借鉴。1. 课程设计选 TM4C123G 做飞控不跟风 F405把姿态解算和 PID 学透这套 TIVA_FC 工程用 TI 的 TM4C123G 单片机做了一台真正能飞的多旋翼飞控姿态解算和控制算法直接移植自匿名的领航者并且能和匿名地面站全兼容在线调参。现在玩飞控的人大多直接买 STM32F405 成品板可在课程设计或答辩场景里F405 的板载固件往往是个黑盒讲不清楚姿态环和 PID 是怎么算出来的。TM4C123G 不一样Cortex-M4F 带 FPUTivaWare 库和传感器库全部可读外设映射、中断优先级、I2C 读传感器再到四元数更新每一层都能在代码里看到。这个高分项目已经实现了定高模式和姿态模式不是只转电机的演示程序适合做单片机课程设计、毕业设计也适合想从 51/STM32 切到 TI 生态的开发者。2. TIVA_FC 工程骨架与外设分配先看懂 TM4C123G 能干什么拿到资源后第一件事不是点开.uvguix编译而是确认 TM4C123G 的资源和飞控后端需求是否匹配。飞控实时性要求摆在那里姿态解算 1 kHz 跑控制输出 500 Hz 到 1 kHz外设要同时伺候 IMU、气压计、遥控器接收机、电调和地面站串口。TM4C123GH6PM 的主频是 80 MHzFlash 256 KBSRAM 32 KB单精度 FPU。匿名领航者原版在 Cortex-M4 上跑完全没问题移植到 TM4C123G 后 CPU 占用大概在 25% 到 35% 之间剩下的余量足够塞进定高融合和地面站协议解析。2.1 选型理由不是所有飞控都要上 STM32用 APM 和 PX4 的玩家习惯性把飞控等同于 STM32但对课程设计来说越偏门的外设反而越难答辩。TM4C123G 的 PWM 模块、I2C 模块和 UART 模块都是 TivaWare 官方库直接封装好的代码风格统一出问题能查 datasheet。它的 PWM 发生器可以输出最多 16 路 PWM常规四轴加云台、LED、蜂鸣器都够用。加上片内 12 位 ADC电池电压采样不用外挂 ADC 芯片。I2C 模块支持标准 I2C 和 SMBus工程里那个smbus.c就是为传感器总线准备的接 MPU6050 这类 IMU 时比软件模拟 I2C 稳得多。单片机和嵌入式系统最大的区别在于外设时序可控性飞控尤其在意这一点。TM4C123G 的定时器中断延迟在 ARM Cortex-M4F 里算稳定不会因为一个 printf 阻塞导致姿态环抖动。项目中用 TivaWare 的SysTick或Timer做时基主循环里只做状态机高频运算全部放在中断里这个结构适合移植匿名领航者的算法也适合后续自己加超声波定高或光流定位。2.2 工程文件清单里藏着什么信息Keil 项目名是TIVA_FC.uvguix.uvguix是 MDK 的用户界面布局配置不是源码本体。TIVA_FC.axf是编译产物说明资源里已经跑通过。driverlib.a和libdriver.a是 TivaWare 的驱动库sensorlib.a和libsensor.a是 TivaWare 传感器库emac.c、usb.c、smbus.c分别是以太网 MAC、USB 和 SMBus 的模板文件。这个工程保留了 TivaWare 的外设驱动全集实际飞控跑得最多的是 PWM、UART、I2C 和 SysTick但emac.c和usb.c的保留说明这块板子未来可以接地面站网口或 USB 虚拟串口。库文件编译成.a后源码里看不到 driverlib 内部实现但函数声明都在头文件里。调试时用 Keil 的 Go To Definition 能跳到汇编或反汇编不过一般用不到TivaWare 的函数名已经足够自解释。真正要改的是main.c、传感器配置、PID 参数和地面站协议解析这几块。拿到资源先打开工程里usercfg.h或param.h这类配置文件看默认的陀螺仪方向、遥控器通道映射和电调 PWM 频率。不同硬件的 PWM 频率差异很大PWM 频率设在 50 Hz 还是 400 Hz直接影响电调响应和电机噪声。2.3 外设映射和主循环写法我一般会把外设映射固定成一张表贴在代码注释里避免调完一个模块忘了另一个模块占用同一个引脚。TM4C123G 的 GPIO 复用比较复杂一个引脚能切到多个外设必须在SysCtlPeripheralEnable之后显式配置GPIOPinConfigure和GPIOPinTypePWM。下面的初始化代码是这套工程里最典型的主控制逻辑骨架#include stdbool.h #include stdint.h #include driverlib/sysctl.h #include driverlib/gpio.h #include driverlib/pwm.h #include driverlib/uart.h // g_att: 姿态结构体, g_alt: 高度结构体, g_motor_armed: 解锁标志 extern volatile att_t g_att; extern volatile alt_t g_alt; extern volatile bool g_motor_armed; int main(void) { // 外部 16 MHz 晶振 PLL, 系统主频 80 MHz SysCtlClockSet(SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ | SYSCTL_SYSDIV_2_5); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0); SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1); GPIOPinConfigure(GPIO_PF1_M0PWM1); GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_1); PWMGenConfigure(PWM0_BASE, PWM_GEN_0, PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC); PWMGenEnable(PWM0_BASE, PWM_GEN_0); PWMOutputState(PWM0_BASE, PWM_OUT_1_BIT, true); // 飞控主循环2 kHz 姿态环, 1 kHz 控制输出 while (1) { if (g_motor_armed) { attitude_loop(g_att, 0.5f); // 姿态环, dt0.5ms height_loop(g_alt, 80, g_throttle); // 定高, 目标高度 80 cm } } }这段代码不是完整程序但揭示了飞控主循环的层次。SysCtlClockSet里的四个参数分别表示使用 PLL、主振荡器、16 MHz 外部晶振、分频得到 80 MHz 主频。这里最容易犯错的是SYSCTL_SYSDIV_2_5这个参数TM4C123G 官方库把分频值写成2_5意思是 400 MHz PLL 输出除 5实际得到 80 MHz。如果改成别的分频会导致 PWM 频率和串口波特率全部偏掉。attitude_loop第二个参数是姿态环周期单位毫秒函数内部用增量式 PID 输出电机修正量。height_loop第三个参数是期望高度单位厘米资源里默认给的是 80 cm实际飞行前要改成你自己飞机悬停位置。主循环里没有 delay所有节拍由定时器中断记录循环体只做状态切换这是保证姿态环时间一致性的最低要求。3. 匿名领航者姿态解算移植从传感器原始值到四元数姿态解算是整个飞控的核心匿名领航者的算法胜在把加速度计和陀螺仪融合得比较稳定不像 APM 的老版本那样对振动过于敏感。移植到 TM4C123G 时最关键的不是把原版代码复制过来而是让 TivaWare 的 sensorlib 输出和原版算法的输入对齐。3.1 对齐传感器量纲和坐标系匿名领航者的姿态算法通常直接使用加速度计原始值归一化角速度用弧度每秒。如果 TivaWare 的 sensorlib 返回的是原始寄存器值必须先除以灵敏度系数。以 MPU6050 为例加速度计量程设为 ±2g 时灵敏度是 16384 LSB/g陀螺仪量程 ±2000 dps 时灵敏度是 131 LSB/dps。很多移植失败都是因为这里少除了一个系数导致陀螺仪积分后角度漂移快得吓人。我习惯在移植前先写一个小函数把原始值转换成物理量再喂给姿态解算方便地面站直接显示曲线。转换函数放在单独的imu_convert.c里不在原版算法文件里改这样以后换 MPU6500 或 ICM20602 时只动一个文件。// 从 sensorlib 读取 MPU6050 原始数据并转成物理量 void imu_poll(float acc_g[3], float gyro_dps[3]) { int16_t raw_acc[3], raw_gyro[3]; if (imu_read_raw(raw_acc, raw_gyro) ! 0) { return; // I2C 读取失败, 保留上一次数据 } for (int i 0; i 3; i) { // MPU6050: ±2g 加速度, 灵敏度 16384 LSB/g acc_g[i] raw_acc[i] / 16384.0f; // MPU6050: ±2000dps 陀螺仪, 灵敏度 131 LSB/dps gyro_dps[i] raw_gyro[i] / 131.0f; } }imu_read_raw是封装了 TivaWare sensorlib 的读取函数返回 0 表示成功。读取失败时保留上一次数据这个动作很关键因为 I2C 在电机大电流启动瞬间容易被干扰如果直接返回非法值后面的四元数归一化会出现无穷大。实际项目中还会在imu_poll里加一个超时计数连续失败超过 10 次就强制解锁失败避免传感器失效后电机继续输出。3.2 互补滤波四元数更新算法匿名领航者原版的姿态解算思路可以理解为陀螺仪积分提供短期姿态加速度计修正提供长期姿态磁力计修正偏航角。下面是精简后的核心更新过程和原版相比去掉了磁力计部分只保留加速度计修正适合没有磁罗盘的硬件或室内磁场干扰严重的环境#define Kp 2.0f #define Ki 0.01f static float q0 1.0f, q1 0.0f, q2 0.0f, q3 0.0f; void attitude_update(float gx, float gy, float gz, float ax, float ay, float az, float dt) { static float integralFBx 0.0f, integralFBy 0.0f, integralFBz 0.0f; float norm, halfvx, halfvy, halfvz; float ex, ey, ez; // 加速度计归一化, 得到单位重力方向 norm sqrtf(ax * ax ay * ay az * az); if (norm 1e-6f) { return; // 加速度模值异常, 跳过本次修正 } ax / norm; ay / norm; az / norm; // 从当前四元数计算期望的重力方向 halfvx q1 * q3 - q0 * q2; halfvy q0 * q1 q2 * q3; halfvz 0.5f - q1 * q1 - q2 * q2; // 叉积误差: 实际重力方向和期望方向的偏差 ex ay * halfvz - az * halfvy; ey az * halfvx - ax * halfvz; ez ax * halfvy - ay * halfvx; // 误差积分项, 消除陀螺仪零偏导致的漂移 integralFBx Ki * ex * dt; integralFBy Ki * ey * dt; integralFBz Ki * ez * dt; gx Kp * ex integralFBx; gy Kp * ey integralFBy; gz Kp * ez integralFBz; // 四元数一阶积分 q0 0.5f * (-q1 * gx - q2 * gy - q3 * gz) * dt; q1 0.5f * ( q0 * gx q2 * gz - q3 * gy) * dt; q2 0.5f * ( q0 * gy - q1 * gz q3 * gx) * dt; q3 0.5f * ( q0 * gz q1 * gy - q2 * gx) * dt; // 归一化四元数 norm sqrtf(q0 * q0 q1 * q1 q2 * q2 q3 * q3); q0 / norm; q1 / norm; q2 / norm; q3 / norm; }这段代码里的Kp是加速度计修正权重值越大姿态跟随加速度计越快但会引入更多高频振动。Ki是陀螺仪零偏积分补偿值过大会让姿态在小角度震荡后出现回摆。TM4C123G 有 FPUsqrtf和浮点乘除不消耗太多时间这个函数跑 1 kHz 时单次耗时大约 6 到 8 微秒。资源原版里可能还有磁力计修正分支手上没磁力计就保留q3的漂移靠遥控器微调偏航。3.3 移植时容易踩的坑第一个坑是坐标系符号。传感器安装方向不同加速度计和陀螺仪的正方向可能和原版算法不一致。最典型的症状是飞控上电倾斜时地面站显示的角度方向反了。解决办法是先在桌面把板子绕 X 轴正转 90 度观察姿态输出是否跟着正转反了就在imu_poll里把对应轴取负。第二个坑是陀螺仪零偏没有校准。匿名领航者原版一般有上电静止采集零偏的逻辑但移植后如果初始化顺序不对零偏是在传感器还没稳定时采集的结果起飞后 Yaw 漂移特别快。我一般会在解锁前强制机身静止 2 秒采集 50 组陀螺仪数据求平均然后写入姿态解算的偏移变量。第三个坑是smbus.c的时序。TivaWare sensorlib 里有的传感器驱动默认按 SMBus 时序操作飞控 I2C 总线上还挂了气压计如果总线速率不统一MPU6050 能读到但气压计偶发超时。建议把 IMU 和气压计都挂在同一个 I2C 外设上速率统一设 400 kHz并且在每个传感器事务之间加 1 微秒左右的空闲时间避免连续读两个传感器时总线繁忙。4. 姿态模式与定高模式控制PID 参数怎么给第一版实现了姿态解算相当于有了飞控的感知层真正的控制层是内外环 PID。资源里的高分工程并没有用复杂的最优控制而是把匿名领航者的串级 PID 搬了过来姿态模式用角度外环加角速度内环定高模式用高度外环加垂直速度内环。这个结构看懂之后后面改悬停、改航线都只是在换期望值来源。4.1 串级 PID 控制结构姿态模式中遥控器摇杆输入映射成期望横滚角cmd_roll和期望俯仰角cmd_pitch满幅范围通常是正负 45 度。外环角度 PID 只需要比例项输出是期望角速度内环角速度 PID 用完整 PID输出是电机差速量。内环比外环快 2 到 3 倍TM4C123G 上一般外环 200 Hz内环 1 kHz。如果里外环频率一样角度滞后会变大飞起来机身会明显点头。typedef struct { float kp_angle; // 角度外环 P, 单位: 1/s float kp_rate; // 角速度内环 P float ki_rate; // 角速度内环 I float kd_rate; // 角速度内环 D } attitude_pid_t; void attitude_control(attitude_pid_t *pid, float cmd_roll, float dt) { static float roll_integral 0.0f; static float roll_prev_rate 0.0f; // 外环: 角度误差 - 期望角速度 float err_angle cmd_roll - att.roll; float rate_des pid-kp_angle * err_angle; // 内环: 角速度误差 - 电机输出量 float err_rate rate_des - gyro.roll; roll_integral err_rate * dt; float d_term (gyro.roll - roll_prev_rate) / dt; float output pid-kp_rate * err_rate pid-ki_rate * roll_integral pid-kd_rate * d_term; roll_prev_rate gyro.roll; // output 经过限幅后叠加到四个电机的基础油门 motor_mix(0, output); }这段代码的限幅被我删掉了实际工程不能删。output要限制在正负基础油门的 30% 以内否则内环瞬间误差大时电机会直接满油门。roll_integral也要做积分限幅常见做法是限制在 20% 油门以内防止起飞前电机锁止时积分一直累加解锁瞬间弹跳。kd_rate在 TM4C123G 上用角速度差分实现1 kHz 下差分噪声可以被接受但如果 IMU 数据有明显毛刺D 项会把毛刺放大成机身抖动这时候不如把kd_rate改成 0。4.2 定高模式的高度估计与油门融合定高模式比姿态模式多了一条高度控制链。气压计原始高度噪声很大直接用会造成油门忽大忽小所以要把气压计和加速度计 Z 轴融合。下面的融合函数是典型的互补滤波参数含义用注释写清楚。static float fusion_alt 0.0f; static float vel_est 0.0f; void alt_fusion(float baro_alt, float acc_z, float dt) { float alt_pred fusion_alt vel_est * dt; float vel_pred vel_est acc_z * dt; // 高度误差增益取 0.05, 垂直速度误差增益取 0.4 fusion_alt alt_pred (baro_alt - alt_pred) * 0.05f; vel_est vel_pred (baro_alt - alt_pred) * 0.4f; }fusion_alt是最终用于高度环的高度估计单位米。vel_est是垂直速度估计单位米每秒。高度误差增益 0.05 表示只信一点点气压计高度修正主要靠加速度积分维持短期垂直速度垂直速度误差增益 0.4 表示垂直速度更信任气压计差分避免加速度计零偏导致垂直速度漂移。定高模式下期望高度cmd_alt是由遥控器锁存的油门摇杆在中位附近时高度环接管油门输出偏离中位则切换回手动油门。实际飞行时气压计高度在油门变化瞬间会有一个反向冲击这是螺旋桨气流打到机身引起的压力突变。解决办法是把高度环的低通截止频率降低在代码里表现为加速度计 Z 轴先过 10 Hz 低通再进融合函数。匿名领航者原版也可能用二阶低通但移植到 TM4C123G 后要确认滤波系数是否匹配当前主频系数写错会出现低频振荡。4.3 第一版 PID 参数表给课程设计调参最怕从零开始慢慢试。我建议直接用下面的参考值做第一次试飞然后把每个参数按 20% 步进调整。油门行程校准和电调协议先确认再动 PID否则任何参数看起来都不对。表格中参数名沿用匿名领航者的习惯角度外环kp_angle只调 P角速度内环kp_rate、ki_rate、kd_rate一起调。定高部分的高度外环kp_alt也只用 P垂直速度内环kp_vel、ki_vel做 PI 控制。参数含义参考范围异常现象kp_angle角度外环比例0.08 - 0.15过小: 打杆后回正慢; 过大: 机身低频晃动kp_rate角速度内环比例0.20 - 0.50过小: 角速度跟随慢; 过大: 机身高频抖ki_rate角速度内环积分0.01 - 0.03过大: 悬停时周期回摆kd_rate角速度内环微分0.01 - 0.02过大: 电机声音发麻kp_alt高度外环比例2.0 - 5.0过小: 高度回不到期望点kp_vel垂直速度比例50 - 150过小: 定高像弹簧; 过大: 垂直方向抖动ki_vel垂直速度积分0 - 10过大: 油门缓慢上下漂第一次起飞不要把飞机解锁放在手上建议把四轴绑在一个可以活动但不会飞走的测试架上。先切姿态模式推油门到 50%观察机身是否往一个方向偏再切定高模式观察高度是否在目标点附近震荡。振幅随参数增大而增大说明某个环增益过高振幅缓慢发散说明积分限幅或者相位裕度不够需要降低外环参数。5. 匿名地面站兼容与在线调参协议解析和链路实现这套资源最爽的一点是地面站兼容匿名上位机可以在电脑上在线改 PID不用每次改完参数重新烧录。匿名地面站的数据链路本质是串口收发只要帧格式对、波特率对、校验对TM4C123G 就能被识别。下面梳理一下移植协议时最核心的几个环节。5.1 匿名协议帧格式匿名地面站常见的数据帧由帧头、功能字、数据长度、数据体和校验和组成。帧头是连续两个0xAA功能字说明这一帧是姿态数据还是参数写入数据长度只统计数据体字节数校验和是把功能字、数据长度和数据体所有字节累加后取低八位。发送一帧姿态数据时payload 里按顺序存放横滚、俯仰、偏航角度每个浮点占 4 字节。下面的表按实际收发顺序列出帧结构这是自己和地面站联调时必须对齐的格式字节序号内容长度说明00xAA1帧头10xAA1帧头2功能字10x01 传感器, 0x04 参数等3数据长度1数据体字节数4 到 n数据体n按协议顺序排列n1校验和1功能字长度数据体累加低八位在线调参走的是参数写入帧数据体里包含参数 ID 和新的参数值。地面站发一帧过来飞控解析后直接更新全局 PID 结构体不需要重新编译工程。为了兼容匿名地面站功能字的数值不能随意改最好对比资源里的ano_protocol.h里面应该已经定义齐全。5.2 发送函数和接收状态机发送逻辑很简单把地面站需要的姿态、高度、电池电压打包成 payload然后调用串口发送。下面是简化的发送函数#include string.h #include driverlib/uart.h void ano_send_packet(uint8_t func, uint8_t *payload, uint8_t len) { uint8_t buf[128]; uint8_t cs func len; uint8_t i 0; buf[0] 0xAA; buf[1] 0xAA; buf[2] func; buf[3] len; for (i 0; i len; i) { buf[4 i] payload[i]; cs payload[i]; } buf[4 len] cs; UARTWrite(UART1_BASE, buf, len 5); }cs从功能字、数据长度和数据体逐字节累加最后和校验和一起发出。UARTWrite是 TivaWare 的阻塞写飞控主循环中一毫秒一帧数据数据长度几十字节115200 波特率下没问题。如果地面站收帧乱码先检查波特率是否一致再看UARTWrite是否被高优先级中断打断。TM4C123G 的 UART FIFO 只有 16 字节建议发送前先查 FIFO 空位不要一个长帧连续写入导致丢字节。接收端不能用轮询要在 UART 中断里做状态机。每次收到一个字节按当前状态判断是否匹配帧头、长度和校验和typedef enum { ST_WAIT_AA1, ST_WAIT_AA2, ST_FUNC, ST_LEN, ST_DATA, ST_CHECK } rx_state_t; static rx_state_t rx_state ST_WAIT_AA1; static uint8_t rx_func, rx_len, rx_sum, rx_buf[64]; void UART1_IRQHandler(void) { uint8_t ch UARTCharGetNonBlocking(UART1_BASE); switch (rx_state) { case ST_WAIT_AA1: if (ch 0xAA) rx_state ST_WAIT_AA2; break; case ST_WAIT_AA2: if (ch 0xAA) rx_state ST_FUNC; else rx_state ST_WAIT_AA1; break; case ST_FUNC: rx_func ch; rx_sum ch; rx_state ST_LEN; break; case ST_LEN: rx_len ch; rx_sum ch; rx_index 0; rx_state ST_DATA; break; case ST_DATA: rx_buf[rx_index] ch; rx_sum ch; if (rx_index rx_len) rx_state ST_CHECK; break; case ST_CHECK: if (ch rx_sum) { ano_process_packet(rx_func, rx_buf, rx_len); } rx_state ST_WAIT_AA1; break; default: rx_state ST_WAIT_AA1; break; } }接收状态机里最容易被忽略的是rx_index在数据长度和实际数据不匹配时的越界保护。rx_len来自地面站恶意或错误数据可能给到 200直接写rx_buf就把栈冲掉了。工程里应该在ST_LEN里判断rx_len sizeof(rx_buf)超过就直接回到等待帧头状态。校验和通过后再调用ano_process_packet这个函数里根据rx_func分发到参数更新或遥控指令处理分支。5.3 在线调参的实际操作流程地面站兼容不是插上线就能用还要保证 TM4C123G 上电后主动发送姿态数据地面站才会进入接收状态。常见的处理是主循环里用一个 50 ms 的软件定时器定时发送一帧包含姿态角和高度的数据地面站显示曲线后进入参数调整页面选择对应参数 ID 写入新值。参数 ID 和 PID 结构体成员的对应关系很重要。我一般会在param_table数组里把每个参数的 ID、地址、大小和上下限都登记好这样地面站写参数时可以直接查表写入防止把kp_angle写进ki_rate。写入完成后只改 RAM 里的值如果掉电想保存需要额外把参数写入片内 Flash 最后一个扇区。TM4C123G 的 Flash 写操作要关闭中断或使用专用函数在线调参时不要每次写都存 Flash否则 Flash 寿命会被迅速消耗。6. 起飞前的验证日志回放和危险参数保护飞控这种系统代码跑通和能安全起飞是两码事。匿名地面站不只是在线调参工具它还能保存飞行日志。上电后先把地面站的数据记录打开推油门到 20% 让电机低速转动看姿态曲线有没有明显毛刺这个动作能提前暴露陀螺仪滤波不足的问题。我习惯在工程里加一条 UART2 调试输出把姿态环最终输出的 PWM 占空比、高度融合值和内环误差打印成日志格式类似LOG:1000,2000,1500,0.35,-0.02。地面站解析这一行之后就能看到 PID 输出是否频繁打上限。如果输出曲线几乎贴住限幅线说明参数离震荡不远了立刻降kp_rate和kp_angle各 20%。危险参数保护是加分项答辩时也容易讲。第一版工程应该把解锁条件做成两个一是遥控器最低油门加偏航锁尾持续 2 秒二是陀螺仪零偏小于某个阈值。定高模式启用前检查气压计高度是否连续 20 次都在同一高度附近偏差超过 50 厘米就拒绝切定高。这样即使地面站误发了过大的kp_alt飞控也只在安全范围内响应。调参时记住一个节奏先调姿态内环比外环快再调定高垂直速度环最后调高度环。每次只改一个参数改完看 30 秒曲线不要同时调三个环。TM4C123G 的优势在于串口中断和定时器中断独立日志输出不会影响控制环时序所以可以放心地把调试日志一直开着。把资源里的代码原样跑通再用这套日志和保护逻辑做二次开发才是这个高分项目最值得拿走的部分。本文还有配套的精品资源点击获取
返回列表