MSPM0G3507 上手把手实现简易 PID:从代码结构到调参避坑
简介这份资源面向学习TI MSPM0G3507微控制器的嵌入式初学者与进阶开发者提供一套可直接编译运行的简易PID项目完整代码帮助读者理解PID算法在电机控制等场景中的落地方式。压缩包共56个文件约158KB以15个C源文件与13个头文件为核心涵盖电机驱动、编码器、按键、定时器、LCD与OLED显示、串口通信及系统模式管理等模块同时附带IAR、Keil、TI Clang与GCC多套工程配置以及SysConfig生成文件、链接脚本、启动文件和README说明方便在不同工具链下快速搭建与移植。目前已有158人学习下载。读者可从中获得完整的工程目录结构、外设初始化与任务调度思路、PID控制代码实现及多平台构建配置参考适合作为课程设计、竞赛准备或自学MSPM0系列MCU的实践素材。1. 从零理解 MSPM0G3507 上的简易 PID为什么它值得你花一个周末如果你手头正好有一块 TI MSPM0G3507 的 LaunchPad又刚好在调一个带编码器或电位器反馈的小电机、小温控、小云台那你大概率绕不开 PID。很多人第一次接触 PID 是在 Arduino 上抄一段Kp*error Ki*integral Kd*derivative跑起来能动就完事但一旦换成 MSPM0G3507 这种 Cortex-M0 内核、带硬件 Timer 和 12 位 ADC 的 MCU问题就来了采样周期怎么定、定时器中断里该放什么、积分项什么时候该清、输出怎么限幅。这个标题讲的不是某个高深算法而是一套能在 MSPM0G3507 上真正跑通、能复现、能改参数的简易 PID 完整代码结构。它适合刚上手 MSPM0 系列、想用 PID 做闭环控制、又不想被复杂框架劝退的嵌入式开发者。我见过太多人卡在“代码能编译但电机抖成筛子”这一步其实问题往往不在 PID 公式而在采样、限幅和积分抗饱和这几个工程细节上。2. 先把 PID 的骨架搭在 MSPM0G3507 上位置式还是增量式2.1 为什么 MSPM0G3507 更适合位置式 PID 起步PID 有两种常见形态位置式和增量式。位置式直接算出控制量的绝对值增量式算的是本次相对上次的增量。在 MSPM0G3507 上我一般建议新手先用位置式原因是它和硬件外设的映射更直观——ADC 读回反馈值定时器中断里算一次输出直接写进 PWM 比较寄存器。增量式虽然天然抗积分饱和、适合执行器带积分特性的场景但它对历史输出的依赖让调试时不容易一眼看出当前误差和输出的关系。MSPM0G3507 的 TimerA 支持周期中断配合 12 位 ADC 的连续采样位置式 PID 的采样-计算-输出链路非常清晰。下面是一个最小可用的位置式 PID 结构体定义放在pid.h里// pid.h #ifndef PID_H #define PID_H typedef struct { float Kp; // 比例系数 float Ki; // 积分系数 float Kd; // 微分系数 float setpoint; // 目标值 float integral; // 积分累加项 float prev_error; // 上一次误差用于微分 float out_min; // 输出下限 float out_max; // 输出上限 float integral_min; // 积分限幅下限抗饱和 float integral_max; // 积分限幅上限 } PID_Handle; void PID_Init(PID_Handle *pid, float kp, float ki, float kd, float out_min, float out_max, float int_min, float int_max); float PID_Compute(PID_Handle *pid, float feedback, float dt); #endif这段结构体把 PID 需要的全部状态都显式列出来了。integral和prev_error必须放在结构体里而不是函数内静态变量因为一个工程里可能有多个 PID 回路静态变量会导致回路之间互相污染。dt是采样周期单位秒后面在定时器中断里传入。integral_min/max是积分限幅这是抗积分饱和的第一道防线很多人只做输出限幅不做积分限幅结果电机堵转时积分项一路涨到天上松开的瞬间输出猛冲。2.2 采样周期怎么定TimerA 中断频率与 ADC 的配合采样周期是 PID 里最容易被忽视但影响最大的参数。太慢微分项没意义、系统响应迟钝太快MSPM0G3507 的 M0 内核在中断里算浮点会吃力而且 ADC 采样噪声会被放大。我的经验是电机速度环用 1kHz 到 5kHz温度环用 10Hz 到 50Hz位置环用 500Hz 到 2kHz。在 MSPM0G3507 上用 TimerA 产生周期中断假设总线时钟 32MHz预分频 32周期值 1000就是 1kHz。配置代码大致如下// timer_config.c #include ti_msp_dl_config.h void TimerA_PID_Init(void) { // 假设已通过 SysConfig 生成基础配置这里手动调整周期 DL_TimerA_setLoadValue(TIMER_PID_INST, 1000 - 1); DL_TimerA_setPrescaler(TIMER_PID_INST, 32 - 1); DL_TimerA_enableInterrupt(TIMER_PID_INST, DL_TIMERA_INTERRUPT_ZERO_EVENT); DL_TimerA_startCounter(TIMER_PID_INST); } // 中断服务函数 void TIMER_PID_INST_IRQHandler(void) { switch (DL_TimerA_getPendingInterrupt(TIMER_PID_INST)) { case DL_TIMERA_IIDX_ZERO: g_pid_tick_flag 1; // 只置标志主循环里算 PID break; default: break; } }这里有个关键选择中断里只置标志PID 计算放主循环。原因是 MSPM0G3507 是 M0 内核没有 FPU浮点运算是软件模拟在中断里做完整 PID 计算会拉长中断时间影响其他外设响应。如果非要中断里算至少把dt固定成常数避免在中断里做除法。DL_TimerA_setLoadValue的参数是周期值减一setPrescaler也是分频值减一这两个减一是 TI 驱动库的约定忘了减一会导致周期差一个计数。ADC 那边建议用连续采样模式在 PID 计算前读最近一次结果不要每次重新启动转换再等那样会引入不确定延迟。2.3 PID 计算函数的实现与参数含义有了结构体和定时器核心计算函数就是整个项目的心脏。下面这个实现包含了积分限幅、输出限幅和微分项处理// pid.c #include pid.h void PID_Init(PID_Handle *pid, float kp, float ki, float kd, float out_min, float out_max, float int_min, float int_max) { pid-Kp kp; pid-Ki ki; pid-Kd kd; pid-setpoint 0.0f; pid-integral 0.0f; pid-prev_error 0.0f; pid-out_min out_min; pid-out_max out_max; pid-integral_min int_min; pid-integral_max int_max; } float PID_Compute(PID_Handle *pid, float feedback, float dt) { float error pid-setpoint - feedback; float derivative; float output; // 积分累加并限幅 pid-integral error * dt; if (pid-integral pid-integral_max) { pid-integral pid-integral_max; } else if (pid-integral pid-integral_min) { pid-integral pid-integral_min; } // 微分项用误差差分dt 固定时可直接用差分 derivative (error - pid-prev_error) / dt; pid-prev_error error; output pid-Kp * error pid-Ki * pid-integral pid-Kd * derivative; // 输出限幅 if (output pid-out_max) { output pid-out_max; } else if (output pid-out_min) { output pid-out_min; } return output; }Kp决定响应速度太大会振荡太小会迟钝。Ki消除稳态误差但太大会超调甚至积分饱和。Kd抑制超调但对噪声敏感MSPM0G3507 的 ADC 如果没有硬件滤波Kd要谨慎给。dt必须和实际定时器周期一致比如 1kHz 就是 0.001f。integral_min/max一般设成out_min/Ki和out_max/Ki的量级具体看执行器。prev_error在每次计算后更新第一次计算时它是 0会有一个微分冲击可以在PID_Init后先调用一次PID_Compute把prev_error初始化成当前误差或者让setpoint从 0 缓慢爬升。3. 把 PID 接到真实外设PWM 输出与反馈采样的完整链路3.1 PWM 输出配置与占空比映射PID 算出来的output是个浮点数最终要变成 PWM 比较寄存器的值。MSPM0G3507 的 TimerA 可以产生 PWM假设用 16 位定时器周期值 4000那么占空比映射就是compare (uint16_t)(output * 4000 / 100.0f)前提是output范围 0 到 100。这里要注意输出限幅的范围要和 PWM 周期匹配不要出现负数或超过周期值。配置代码// pwm_config.c void PWM_Init(void) { DL_TimerA_setLoadValue(PWM_INST, 4000 - 1); DL_TimerA_setPrescaler(PWM_INST, 1 - 1); DL_TimerA_setCaptureCompareValue(PWM_INST, 0, DL_TIMER_CC_0_INDEX); DL_TimerA_enableOutput(PWM_INST, DL_TIMER_CC_0_INDEX); DL_TimerA_startCounter(PWM_INST); } void PWM_SetDuty(float duty_percent) { uint16_t compare; if (duty_percent 0.0f) duty_percent 0.0f; if (duty_percent 100.0f) duty_percent 100.0f; compare (uint16_t)(duty_percent * 40.0f); // 4000/100 DL_TimerA_setCaptureCompareValue(PWM_INST, compare, DL_TIMER_CC_0_INDEX); }DL_TimerA_setCaptureCompareValue的第二个参数是比较值第三个是通道索引。PWM_SetDuty里做了二次限幅防止 PID 输出异常时把比较值写飞。40.0f是 4000 除以 100 的结果如果周期值改了这个系数也要跟着改。建议把周期值定义成宏映射系数用(float)PERIOD / 100.0f计算避免硬编码。3.2 反馈采样ADC 读取与滤波反馈值来自 ADCMSPM0G3507 的 ADC 是 12 位参考电压通常 3.3V。如果反馈是电位器直接读电压如果是编码器需要用定时器捕获或外部中断计数。这里以电位器为例// adc_feedback.c #define ADC_MAX 4095.0f #define VREF 3.3f float ADC_GetFeedback(void) { uint16_t raw; float voltage; // 假设已配置 ADC 连续采样读取最近结果 raw DL_ADC12_getMemResult(ADC_INST, DL_ADC12_MEM_IDX_0); voltage (float)raw * VREF / ADC_MAX; return voltage; }DL_ADC12_getMemResult返回最近一次转换结果DL_ADC12_MEM_IDX_0是内存索引。如果 ADC 噪声大可以在软件里做滑动平均或一阶低通。一阶低通公式filtered filtered * 0.9f new * 0.1f系数越小越平滑但延迟越大。对于 PID 的微分项反馈噪声会被放大所以反馈滤波比输出滤波更重要。我一般会在 ADC 读取后加一个 5 点滑动平均再送进 PID。3.3 主循环里的完整调用顺序把上面几块拼起来主循环的结构就很清晰了// main.c #include ti_msp_dl_config.h #include pid.h PID_Handle g_pid; volatile uint8_t g_pid_tick_flag 0; int main(void) { float feedback, output; SYSCFG_DL_init(); TimerA_PID_Init(); PWM_Init(); ADC_Init(); PID_Init(g_pid, 2.0f, 0.5f, 0.1f, 0.0f, 100.0f, -50.0f, 50.0f); g_pid.setpoint 50.0f; // 目标 50% 占空比对应值 while (1) { if (g_pid_tick_flag) { g_pid_tick_flag 0; feedback ADC_GetFeedback(); output PID_Compute(g_pid, feedback, 0.001f); PWM_SetDuty(output); } } }PID_Init里的参数是示例值实际要调。g_pid_tick_flag用volatile修饰因为它在中断里改、主循环里读。dt传 0.001f 对应 1kHz。这个顺序保证了采样、计算、输出在同一个节拍里完成不会出现用旧反馈算新输出的情况。4. 调参和避坑MSPM0G3507 上 PID 最容易翻车的几个地方4.1 现象电机一上电就满速冲然后剧烈振荡原因通常是积分项在启动瞬间累积过大或者Kp给得太激进。MSPM0G3507 的 ADC 上电第一次读数可能不稳定如果此时setpoint已经设好误差很大积分项会迅速饱和。解决方法是启动时先让setpoint从 0 缓慢增加到目标值或者先只开Kp等系统稳定后再加Ki。另外检查integral_min/max是否设得太宽一般不要超过out_max/Ki的两倍。4.2 现象输出一直在下限或上限反馈怎么都不动先看 PWM 有没有真正输出用示波器或 LED 测一下。如果 PWM 正常再看 ADC 反馈是否接对通道、参考电压是否选对。MSPM0G3507 的 ADC 通道和引脚复用容易搞混SysConfig 里选错通道会导致读回一直是 0 或满量程。还有一种可能是PID_Compute里的dt传成了 0除法产生无穷大输出被限幅卡死。检查dt是否和定时器周期一致。4.3 现象系统响应慢加了Ki也没用可能是采样周期太长或者Ki的量级不对。Ki的单位是 1/s如果dt是 0.001Ki给 0.001 和给 1.0 效果差一千倍。建议先把Kp调到系统开始小幅振荡然后退回 60%再加Ki消除静差。Kd最后加从 0 开始每次加一点点观察是否抑制了超调。MSPM0G3507 没有 FPU浮点乘法耗时如果采样率很高可以考虑把 PID 改成定点运算但简易项目用浮点足够。4.4 现象编译通过但运行卡死或复位常见原因是中断优先级冲突或栈溢出。MSPM0G3507 的默认栈大小可能不够PID 结构体和浮点运算会占一些栈空间。在链接脚本里把栈调大一点比如从 0x200 调到 0x400。另外检查TIMER_PID_INST_IRQHandler的名字是否和启动文件里的向量表一致名字写错会进默认死循环。还有volatile漏加导致编译器优化掉标志位读取也会卡死。4.5 现象PID 输出抖动厉害电机有啸叫这是微分项放大了反馈噪声。先确认 ADC 有没有做滤波没有的话加滑动平均。然后降低Kd或者对微分项单独做低通滤波。还有一种可能是 PWM 频率落在电机听觉敏感区把 PWM 频率提到 20kHz 以上或者改定时器预分频。MSPM0G3507 的 TimerA 可以跑很高频率但要注意占空比分辨率会下降。5. 进阶技巧把简易 PID 改成可在线调参和抗饱和的版本5.1 用串口在线修改 PID 参数简易项目调参最痛苦的是每次改参数都要重新编译下载。可以在主循环里加一个串口命令解析收到特定格式就改g_pid的系数。比如收到P2.5就把Kp改成 2.5。MSPM0G3507 的 UART 配置好之后用DL_UART_Main_receiveData非阻塞读拼成字符串再解析。这样调参效率会高很多尤其是Kd这种需要反复试的参数。5.2 积分分离误差大时先不积分积分分离是抗饱和的进阶做法当误差绝对值大于某个阈值时把Ki暂时置 0只用 PD 快速逼近误差进入小范围后再恢复积分消除静差。实现上就是在PID_Compute里加一个判断if (fabsf(error) pid-integral_sep_threshold) { pid-integral error * dt; // 限幅... } else { // 误差大不累加积分甚至可以缓慢衰减 pid-integral * 0.99f; }integral_sep_threshold根据实际系统设一般是目标值的 10% 到 20%。这个技巧在电机启动和大幅设定值变化时特别有用能明显减少超调。5.3 用定时器捕获做编码器反馈的注意事项如果反馈是编码器而不是电位器MSPM0G3507 的 TimerA 可以配成捕获模式但要注意编码器信号频率和定时器时钟的关系。正交编码器需要两个通道MSPM0G3507 的 TimerA 支持正交编码模式配置成DL_TIMER_MODE_QUADRATURE_ENCODER后直接读计数寄存器就是位置。速度环的话每个 PID 周期读一次计数差值再除以dt。这里有个坑计数寄存器是 16 位的会溢出读的时候要做差值处理不能直接读绝对值当速度。5.4 一个我常用的调参顺序最后分享一个我自己的调参习惯先把Ki和Kd置 0Kp从 0 慢慢加加到系统开始等幅振荡记下这个Kp叫Ku振荡周期叫Tu。然后按 Ziegler-Nichols 经验公式Kp 0.6*KuKi 2*Kp/TuKd Kp*Tu/8。这套公式给的是起点不是终点但能让你少走很多弯路。调的时候用串口在线改边看反馈曲线边微调。MSPM0G3507 的 RAM 不大别开太大的数组存曲线存最近 100 个点就够看趋势了。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

RucBase数据库管理系统实战:C++源码编译、运行与索引实验

RucBase数据库管理系统实战:C++源码编译、运行与索引实验

简介:这份源码资源是面向计算机专业学生与数据库系统实现学习者的RucBase关系数据库管理系统原型,参考CMU15445的BusTub与Stanford CS346的Redbase设计,适合作为《数据库系统实现》课程实验的参考框架,帮助理解并动手实现数据库核…

2026/10/13 16:27:42 阅读更多 →
ArcGIS空间分析实验配套光盘part-1:从解压到避坑的完整指南

ArcGIS空间分析实验配套光盘part-1:从解压到避坑的完整指南

简介:《ArcGIS地理信息系统空间分析实验教程(第2版)》配套光盘part-1,由汤国安主编教程分割后的第一部分,对应第3、4、5、7、8、9(1)章,面向GIS专业学生、科研人员及ArcGIS 10.0自学者,主要用于…

2026/10/13 16:27:42 阅读更多 →
Python 读写 DXF 实战:用 ezdxf 批量处理 CAD 图纸

Python 读写 DXF 实战:用 ezdxf 批量处理 CAD 图纸

简介:ezdxf 是一个与 DXF 版本无关的 Python 程序包,面向需要以编程方式创建、读取和修改 DXF 图纸的开发者,尤其适合 CAD 二次开发、工程图纸自动化处理等场景。它支持 R12 至 R2018 各版本 DXF 的读写与新建,能完整保留未知标签…

2026/10/13 16:27:42 阅读更多 →

最新新闻

矩阵论期末复习:Jordan标准形、QR分解与广义逆手算全攻略

矩阵论期末复习:Jordan标准形、QR分解与广义逆手算全攻略

简介:矩阵论期末考试参考答案是一份针对矩阵论课程期末考试的完整解题资料,面向正在复习矩阵论、线性代数的本科生及考研备考生,也适用于需要快速回顾核心计算方法的工程类学生。资源包内共1个PDF文件,大小约284KB,文件…

2026/10/13 19:15:31 阅读更多 →
OSPF协议细节深度解析:LSA类型、邻居状态机与SPF算法

OSPF协议细节深度解析:LSA类型、邻居状态机与SPF算法

1. 为什么OSPF不是“配通就行”,而是网络工程师的分水岭 在某高校网络实验室带学生做路由实验时,我见过太多次这样的场景:A同学花15分钟把OSPF邻居关系配通, show ip ospf neighbor 显示FULL,ping测试全通&#xff0…

2026/10/13 19:15:30 阅读更多 →
夸克网盘免费扩容1TB全攻略:从活动入口到空间验证一步不落

夸克网盘免费扩容1TB全攻略:从活动入口到空间验证一步不落

夸克网盘免费扩容1TB这个话题,隔一阵子就会有人翻出来问一遍。网上教程截图满天飞,但真正把入口在哪、任务怎么算完成、到账怎么验证、有效期怎么查讲清楚的并不多。我这次直接把2026年还能跑通的路径重新过了一遍,从准备工作到领取完成&…

2026/10/13 19:15:30 阅读更多 →
免费开源ERP系统选型与实施:进销存+财务+生产一体化实战指南

免费开源ERP系统选型与实施:进销存+财务+生产一体化实战指南

这几年在圈子里被问得最多的一个问题,就是中小公司和创业团队到底要不要上ERP。我的答案一直很干脆:要上,但别一上来就盯着那套贵得离谱的商业软件。免费开源的进销存财务生产ERP系统,这些年成熟度已经很高了,尤其适合…

2026/10/13 19:15:30 阅读更多 →
免费开源一体化ERP实战:进销存+财务+生产+SaaS部署与权限管理

免费开源一体化ERP实战:进销存+财务+生产+SaaS部署与权限管理

我一个干制造业信息化多年的人,这几年最深的感受就是:太多中小工厂被Excel管生产、管库存、管账的方式拖住了。业务一多,采购下单靠拍脑袋,仓库月底盘点对不上数,财务月底对账加班到深夜,生产领料不知道库存…

2026/10/13 19:15:30 阅读更多 →
多智能体电梯群控:基于目的楼层预约与PPO的深度强化学习实现

多智能体电梯群控:基于目的楼层预约与PPO的深度强化学习实现

简介:本资源是一套面向计算机、人工智能、自动化等专业学生的毕业设计与课程设计实践项目,聚焦于多智能体协同下的电梯群控优化问题,采用深度强化学习实现目的楼层预约调度算法,解决传统电梯响应延迟高、能耗大、乘客等待时间长等…

2026/10/13 19:14:30 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →