2021电赛F题控制:freeRTOS巡线自动返回工程实践

简介:这是针对2021年电赛F题研发的智能小车控制工程,以freeRTOS协调巡线、十字路口识别、黑白块识别与自动返回等任务,基于Keil和CubeMX开发,采用HAL库驱动,适合电赛参赛者及嵌入式开发者,可帮助解决多任务并行与稳定循迹问题。压缩包共1402个文件,主体为C源文件和头文件,含Keil工程配置、CubeMX配置及编译生成文件,整体约51.49MB,目录清晰便于查阅。已有5725人学习下载,属于真实赛题方案。工程代码展示了freeRTOS任务调度、信号量与中断处理的实际运用,可学习巡线数据采集、路口与黑白块识别、自动返回及电机控制等核心模块,也能借助CubeMX快速调整外设参数。工程各模块划分明确,可直接编译烧录或二次开发,对电赛备赛和STM32嵌入式开发有较高参考价值。

1. 2021电赛F题控制部分:这套freeRTOS巡线自动返回工程,能让你现场少熬夜

2021电赛F题的控制部分,真正到了调车现场你会发现,大家拼的不是谁的巡线算法更高明,而是谁的代码经得起临时改。灰度传感器要重新标定、返回路径要加一段减速、按键得临时多一个功能——如果你的控制逻辑全部挤在一个while(1)里,任何一次改动都可能牵起一串全局变量和隐藏状态。把巡线、自动返回这些模块交给freeRTOS之后,每个功能都有自己的任务和入口,现场改参数只需要打开对应那个任务,这是这套Keil工程最值钱的地方。这篇笔记会按 CubeMX 建工程、freeRTOS 任务拆解、巡线算法、自动返回状态机的顺序讲完,最后把我调车时踩过的坑列出来。工程基于STM32F411 + HAL库,Keil MDK直接打开编译即可,思路换到F103或GD32也成立。

2. 用CubeMX生成STM32F411的HAL工程:时钟和外设一次配到位

2.1 CubeMX 里的四个关键配置,先把时基和外设安排明白

做这套控制部分之前,我先说为什么不用标准外设库。HAL库确实啰嗦,但CubeMX能一次性把引脚、时钟、DMA和FreeRTOS都生成出来,对时间紧的比赛场景是最省事的。F411的Cortex-M4F带FPU,跑浮点PID毫不费力,选它主要看中主频高、ADC通道够用。下面的配置是我调过的一套方案,不是唯一解,但大多数8路灰度+双电机的巡线小车可以直接照抄。

时钟树这块,我习惯把SYSCLK放到96MHz而不是100MHz。原因是CubeMX里选96MHz时PLL参数容易凑成整倍数,生成代码后不容易出警告;而且96MHz对48MHz的APB1、96MHz的APB2都能整除,定时器分频更好算。外接25MHz晶振时直接填25,CubeMX会自动算PLLM/PLLN/PLLP。如果板子上没有外部晶振,用HSI也能跑,但温度变化时内部RC会漂,PWM频率跟着变,比赛现场不建议赌这个。

ADC和TIM1的配置取决于外设挂哪条总线。F411的ADC1输入引脚PA0~PA7正好连续,适合做8路扫描;TIM1挂在APB2上,输出PWM频率不会因为APB1分频受影响。打开CubeMX后,把这些外设全部使能,然后进Clock Configuration把SYSCLK调到96MHz,IDE选MDK-ARM,生成工程。

还有一个很容易忽略的选项:SYS里的Timebase Source。默认是SysTick,但FreeRTOS也要用SysTick。如果不改,后面HAL_Delay和osDelay会打架,我建议直接从源头改成TIM6,这一下就能避开后面避坑章节里那个最经典的卡死问题。

配置项设置值需注意
HSE25MHz Crystal根据板子实际晶振改
SYSCLK96MHzPLL参数由CubeMX自动算
SYS Timebase SourceTIM6避开FreeRTOS的SysTick
ADC18通道扫描+DMA循环采样时间先拉长到84周期以上
TIM1PWM输出CH1/CH2,10kHz用APB2定时器时钟

2.2 Keil 工程里怎么拆任务:巡线、状态、UI 各干各的

CubeMX生成工程后,打开freertos.c,所有任务都在MX_FREERTOS_Init里创建。我习惯把任务分成三个:line_task负责读灰度、算PID、写PWM;state_task负责状态机切换;ui_task负责按键扫描和显示。这么分的依据是调度周期不同:巡线要100Hz,状态切换100Hz,人机交互20Hz就够。

// MX_FREERTOS_Init:创建巡线、状态、人机交互三个任务 void MX_FREERTOS_Init(void) { osThreadAttr_t line_task_attr = { .name = "line_task", .stack_size = 512 * 4, // 栈空间 2KB,放ADC缓冲和PID浮点变量 .priority = osPriorityAboveNormal }; line_task_handle = osThreadNew(Line_Task, NULL, &line_task_attr); osThreadAttr_t state_task_attr = { .name = "state_task", .stack_size = 256 * 4, // 1KB,状态机里没有大数组 .priority = osPriorityNormal }; state_task_handle = osThreadNew(State_Task, NULL, &state_task_attr); osThreadAttr_t ui_task_attr = { .name = "ui_task", .stack_size = 128 * 4, // 512B,只处理按键和OLED显示 .priority = osPriorityLow }; ui_task_handle = osThreadNew(UI_Task, NULL, &ui_task_attr); }

任务优先级按什么标准定?line_task最高,因为它直接决定小车对弯道的响应,被抢占一个周期车就可能偏出去;ui_task最低,晚50ms刷新屏幕没人看得出。优先级的代价是line_task占用CPU多了,state_task可能被饿着,所以我给line_task周期10ms,状态任务10ms,UI任务50ms。最高优先级任务里不要做任何阻塞调用,比如HAL_UART_Transmit和osDelay。

栈大小的估算是调试期最容易翻车的。Keil的默认栈检查不可靠,我一般是先给大一点,比如line_task给2048字节,跑一晚上不出问题再往小压。现场判断栈够不够,最简单是在任务函数里定义一个局部数组凑够栈深,运行后用调试器看这个数组地址附近的数据有没有被踩掉,踩掉就说明栈溢出。

任务优先级栈大小周期职责
Line_TaskosPriorityAboveNormal2048B100HzADC灰度读取、PID计算、PWM输出
State_TaskosPriorityNormal1024B100Hz状态机流转、丢线处理、启停控制
UI_TaskosPriorityLow512B20Hz按键扫描、OLED显示

任务之间传数据,我建议先别急着上队列。巡线任务独占灰度数据,状态任务只读丢线标志,用volatile标志位就够了,语义清楚,也省得调一个优先级反转。只有当UI任务要改巡线参数时,才考虑用osMessageQueuePut,因为参数是低频小数据,队列反而安全。

工程编译这块,记得把浮点单元选成FPU单精度。Options for Target → Target → Floating Point Hardware选Single Precision。不选的话,浮点计算会进软件模拟,PID跑起来很慢,现场手感完全不一样。

3. 巡线算法与灰度传感器:从 ADC 采样到 PID 输出

3.1 灰度传感器排布与 ADC 多通道 DMA 采样

灰度传感器我用的8路,输出是模拟电压,黑线反光弱、白底反光强。8个传感器并排装在车头,间距大概2cm,正好覆盖赛道黑线加两侧余量。CubeMX里把PA0~PA7配成ADC1的8个通道,扫描模式打开,DMA循环搬运。

// HAL_ADC_ConvCpltCallback 只做一件事:置位通知 volatile uint8_t line_data_ready = 0; void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { if (hadc == &hadc1) { line_data_ready = 1; // Line_Task 看到标志就取数据 } }

不要在这个回调里做PID计算。中断里跑浮点会把任务调度时钟打乱,还要处理临界区,得不偿失。设一个标志就好,Line_Task周期性检查,主循环天然和DMA采集频率对齐。

#define SENSOR_NUM 8 uint32_t gray_raw[SENSOR_NUM]; uint16_t gray_threshold[SENSOR_NUM]; // 返回偏差,单位 0.1 个传感器间距;全丢线返回 999 int16_t calc_offset_from_gray(void) { int32_t weighted_sum = 0; int32_t active_count = 0; for (int i = 0; i < SENSOR_NUM; i++) { uint8_t on_black = (gray_raw[i] < gray_threshold[i]) ? 1 : 0; weighted_sum += on_black * i * 10; active_count += on_black; } if (active_count == 0) { return 999; // 一路线都没看到 } int16_t offset = (int16_t)(weighted_sum / active_count - (SENSOR_NUM - 1) * 5); return offset; }

这组代码的逻辑是位置加权平均:每个传感器如果压到黑线,权值就是编号乘10,中心位置在(N-1)*5=35,所以减去35后偏差范围大约-35到+35。这个偏差直接送给PID作为输入,不做归一化,因为KC量级对PID来说好调。

阈值标定最常见做法是上电后做一次自动校准:车先在白底放2秒,读一遍每个通道的亮值;再把车推到黑线上,读一遍暗值;阈值取二者中值。注意要在两个场地都留够时间,等传感器稳定后再采样,上电瞬间的红外LED电流还没稳。

ADC采样时间我直接设84个ADC时钟周期,不追求速度。8个通道扫描一轮不到8微秒,完全够用,采样周期长一点反而能滤掉高频毛刺。如果比赛场地灯光频闪严重,可以在DMA回调里加一层中值滤波,取最近3轮同通道原始值的中间值。

3.2 PID 巡线参数:先调比例,再加微分,积分只做修边

巡线PID我用浮点实现,F411的FPU跑这些运算就是几条指令的事。下面的PID结构体不绑死某个库,可以直接丢进你的工程。

typedef struct { float kp; float ki; float kd; float integral; float last_error; float limit; // 积分限幅 } PID_TypeDef; void PID_Init(PID_TypeDef *pid, float kp, float ki, float kd, float limit) { pid->kp = kp; pid->ki = ki; pid->kd = kd; pid->integral = 0; pid->last_error = 0; pid->limit = limit; } float PID_Update(PID_TypeDef *pid, float error, float dt) { pid->integral += error * dt; // 积分限幅,防止长时间丢线导致积分饱和 if (pid->integral > pid->limit) pid->integral = pid->limit; if (pid->integral < -pid->limit) pid->integral = -pid->limit; float derivative = (error - pid->last_error) / dt; pid->last_error = error; return pid->kp * error + pid->ki * pid->integral + pid->kd * derivative; }

dt直接取Line_Task的调度周期0.01s,不要用HAL_GetTick去现算,那个值受任务调度抖动影响。积分限幅设成转向输出限幅的30%左右,防止过弯时积分项堆积太多,出弯半天回不来。

PID输出到左右轮差速,我这样处理:

// 差速转向:左轮减、右轮加,转向量由PID输出决定 int base_duty = 260; // 基础PWM占空比 int pid_out = (int)PID_Update(&follow_pid, line_offset, 0.01f); int left_duty = base_duty - pid_out; int right_duty = base_duty + pid_out; left_duty = CLAMP(left_duty, 0, 420); right_duty = CLAMP(right_duty, 0, 420); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, left_duty); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, right_duty);

参数初调我建议按这个顺序:先只给Kp,把车放直道上,开到能勉强跟线;然后加Kd,高速冲弯道看甩尾是否被压住;最后加一点点Ki,解决长时间贴外弯的问题。别上来就三参数一起调,翻车了都不知道是哪个参数的问题。

参数初调值现象调整方向
Kp8.0直线走不直,弯道反应慢加大Kp
Kd30.0高速过弯甩尾加大Kd
Ki0.2长时间贴边微增Ki
积分限幅转向限幅的30%出弯回不来减小限幅

提示:调PID先关掉自动返回,只保留巡线状态。每次只改一个参数,改完原地复位,不要分不清是哪个参数引起的。

4. 自动返回与丢线处理:用状态机把三段路径理顺

4.1 从巡线到自动返回的状态机设计

自动返回最怕的就是把逻辑堆在巡线函数里,丢线时既要减速又要掉头又要数编码器,一个标志位套一个标志位,最后谁都说不清现在跑到哪一步。所以我用状态机把整个流程拆成待机、巡线、丢线、返回、停止五个状态,每个状态只关心自己的输入和输出。

typedef enum { STATE_IDLE, STATE_FOLLOW, STATE_LOST, STATE_RETURN, STATE_STOP } RobotState; volatile RobotState robot_state = STATE_IDLE;

状态转移关系是固定的:启动后进入巡线;连续丢线超过阈值进入丢线处理;掉头完成后进入返回;回到终点触发停止。这样每个阶段都有一份独立的处理代码,不会出现“我在巡线但又在往出发点跑”的混乱。

void State_Task(void *argument) { TickType_t last_wake = xTaskGetTickCount(); for (;;) { switch (robot_state) { case STATE_IDLE: if (start_button_pressed) { PID_Reset(&follow_pid); robot_state = STATE_FOLLOW; } break; case STATE_FOLLOW: if (line_lost_ms >= 50) { SaveReturnParams(); // 记录当前编码器位置和航向 robot_state = STATE_LOST; } break; case STATE_LOST: if (TurnAroundDone()) { robot_state = STATE_RETURN; } break; case STATE_RETURN: if (ReturnDone()) { MotorStop(); robot_state = STATE_STOP; } break; default: break; } vTaskDelayUntil(&last_wake, 10); } }

line_lost_ms不是用HAL_GetTick累加,而是在Line_Task里置一个丢线标志,状态任务每次循环对这个标志计数。原因很实际:状态任务周期固定10ms,用自己周期累加出来的时间比查系统Tick更准,不会被调度抖动带偏。

4.2 返回路径:编码器、航向修正、终点停车

自动返回的实现,我按可靠性排过三种方案:纯编码器倒计时、陀螺仪加编码器、终点传感器精停。纯编码器实现最简单,丢线点记录左右轮编码器值,返回时按同样脉冲反向走,但误差会累积,适合短距离。陀螺仪加编码器最稳,用IMU的Z轴角速度积分得到朝向,返回时先转到出发航向,再直线走回丢线点距离。终点处加一个起点传感器做精停。

typedef struct { int32_t left_count; int32_t right_count; int16_t heading; // 记录丢线时朝向,单位 0.1° } ReturnContext; ReturnContext return_ctx; void SaveReturnParams(void) { return_ctx.left_count = encoder_left_count; return_ctx.right_count = encoder_right_count; return_ctx.heading = (int16_t)(imu_yaw * 10); } void DoReturnByEncoder(void) { // 目标:左右轮各自回到丢线前的位置 int32_t left_target = encoder_left_count - return_ctx.left_count; int32_t right_target = encoder_right_count - return_ctx.right_count; if (left_target < 0) SetMotorLeftDirection(DIR_BACKWARD); else SetMotorLeftDirection(DIR_FORWARD); if (right_target < 0) SetMotorRightDirection(DIR_BACKWARD); else SetMotorRightDirection(DIR_FORWARD); }

编码器用定时器编码器模式,CubeMX里把TIM2/TIM3设成Encoder Mode,计数频率一般按4倍频理解。返程距离就是当前计数值减丢线点保存值,方向取反,左右轮分别闭环。返回速度要低于巡线速度,我一般取巡线base_duty的60%左右,接近终点前降到30%,否则冲过终点再倒回来就很狼狈。

返回过程中不要用巡线PID。返程时车头很可能离线很远,灰度传感器全丢,PID积分直接饱和,越修越偏。返回阶段更适合用角度闭环:陀螺仪读出当前航向,目标航向是丢线时记录的heading,用一个独立的航向PID控制左右轮差速。

终点停车不能只看编码器,因为打滑和机械误差会让实际距离偏出不少。我在起点放了一组独立的起点传感器,车回到起点后先减速,再检测到触发信号就停车。现场调车时,这个终点传感器的触发阈值要单独测,别用灰度阈值一套通吃。

5. 巡线小车避坑与排查:freeRTOS 环境下最经典的四个问题

5.1 PWM占空比周期性抖动,低速时电机一顿一顿

现象:巡线任务单独跑时PWM输出很干净,加了freeRTOS之后电机在低速时明显一顿一顿,示波器看PWM波形占空比跳动。

原因:最典型的是在中断或高优先级任务里做了耗时的浮点运算,比如printf或OLED刷新,把PWM的更新时刻往后拖了。另一个原因是两个任务同时修改占空比变量,没有加保护,导致调度器看到的值和任务实际写入的值不一致。

解决:把PWM输出放到Line_Task最后,用局部变量算完再一次性写入定时器比较寄存器。printf改成DMA发送或只用低优先级UI任务。如果多个任务确实都要改电机,加一个临界区,让PWM变量访问不可重入。

5.2 加了freeRTOS之后HAL_Delay卡死,任务全部停摆

现象:代码里某个地方调用了HAL_Delay(10),程序就再也跑不动,连LED都不闪。

原因:CubeMX默认把HAL时基源设置为SysTick,而FreeRTOS的时基源也是SysTick。FreeRTOS启动后接管了SysTick的中断优先级,HAL_Delay依赖的uwTick没法更新;或者SysTick优先级高于PendSV,HAL_Delay在临界区里反复等待,把调度器卡住。

解决:CubeMX里把SYS的Timebase Source从SysTick改成TIM6,重新生成代码。然后把代码里所有HAL_Delay替换成osDelay或vTaskDelay。注意TIM6的初始化代码MX_TIM6_Init要在MX_FREERTOS_Init之前调用,顺序别颠倒。

5.3 8路灰度ADC的值忽高忽低,阈值标定总失败

现象:巡线车慢速走过黑线,偏差摆动很大,一个传感器在黑白之间反复跳。

原因:ADC采样时间太短,传感器输出阻抗高,采样电容没充满;GPIO没配成模拟模式;或者DMA搬运宽度设置错误,8位宽度把4字节数据传输拆乱。还有一种玄学是现场灯光频闪,红外传感器在50Hz工频干扰下每帧结果都不一样。

解决:先在CubeMX里确认PA0~PA7是Analog模式,采样时间设84周期以上,DMA外设和内存都设Word宽度。如果场地灯光干扰明显,在中值滤波里处理,取最近3轮同一通道的中间值。

// 对最近3轮原始值做中值滤波,取中间值上送 uint32_t gray_filtered[SENSOR_NUM]; for (int i = 0; i < SENSOR_NUM; i++) { uint32_t a = gray_buf_prev2[i]; uint32_t b = gray_buf_prev1[i]; uint32_t c = gray_buf_curr[i]; gray_filtered[i] = (a > b) ? ((b > c) ? b : (a > c ? c : a)) : ((a > c) ? a : (b > c ? c : b)); }

阈值标定不要在通电瞬间做,等上电3秒后再读,红外LED和模拟电路需要稳定时间。标定完把阈值通过串口打印出来,确认每个通道黑白差别明显,如果某一路阈值特别接近,多半是传感器位置偏了。

5.4 自动返回时车走斜,方向偏移越拉越大

现象:巡线出去时很直,掉头后回程越来越偏,到终点偏出去二三十厘米。

原因:左右电机死区不一致。PWM小信号时一个轮子已经转了,另一个还卡着,两个轮子实际走的距离不相等。返程如果只按总脉冲数控制,误差会一直累积到终点。

解决:把左右轮各自标定最小启动占空比,返回时给死区大的轮子加一个补偿量,或者给死区小的减一个补偿量。更靠谱的是编码器闭环,让左右轮分别追目标脉冲数,而不是只给固定PWM。返程速度降到巡线的60%,用慢速换精度,现场微调时最好用一块空地反复测,别在正式赛道上边跑边改。

6. 现场最实用的两个技巧:串口DMA日志和任务心跳看门狗

6.1 让 printf 走 DMA,不干扰巡线

现场调车最需要的就是看清PID输出和偏差值,但直接用HAL_UART_Transmit的printf会阻塞任务,日志一多,巡线直接变形。我一般写一个很轻量的日志函数,把HAL_UART_Transmit换成DMA版本,调用后立即返回。

// 简单地把整条日志打包,用DMA发送,调用后立即返回 void Debug_Print(const char *str, uint16_t len) { HAL_UART_Transmit_DMA(&huart2, (uint8_t *)str, len); }

日志输出频率控制在20Hz以内,只在后期调参时临时打开。这样串口打印不会抢走巡线任务的CPU时间,现场看曲线也够用。

6.2 给每个任务加心跳,死循环直接复位

比赛现场最怕的不是编译报错,而是小车跑着跑着突然不动,面板没有任何提示。我给每个任务加一个心跳时间戳,放在最低优先级的UI任务里检查,超过1秒没更新就系统复位。

volatile uint32_t task_heartbeat[3]; // 0: line 1: state 2: ui // 每个任务循环末尾更新 task_heartbeat[0] = uwTick; // UI任务里调用 void HeartBeat_Check(void) { for (int i = 0; i < 3; i++) { if (uwTick - task_heartbeat[i] > 1000) { __disable_irq(); NVIC_SystemReset(); // 直接复位,比硬看门狗更省硬件 } } }

这个方案不需要外部看门狗,也不用开FreeRTOS的运行时统计。现场如果车停了,看一眼心跳复位时间大概能猜到是哪个任务卡住,比对着调试器干瞪眼舒服得多。我后来每套控制工程的末尾都会留这个检查,车跑丢了自动重启,至少不会在展示时尴尬。

这就是我这套2021电赛F题控制部分最想保留的两个习惯:日志走DMA,任务有心跳。前者保证巡线性能不被调试拖垮,后者保证现场故障不至于找不到原因。希望帮到你。

本文还有配套的精品资源,点击获取

相关新闻

RDP Wrapper 完整教程:替换 rdpwrap.ini 让 Windows 支持多会话远程桌面

RDP Wrapper 完整教程:替换 rdpwrap.ini 让 Windows 支持多会话远程桌面

RDP Wrapper 完整教程:替换 rdpwrap.ini 让 Windows 支持多会话远程桌面 【免费下载链接】rdpwrap.ini RDPWrap.ini for RDP Wrapper Library by StasM 项目地址: https://gitcode.com/GitHub_Trending/rd/rdpwrap.ini rdpwrap.ini 仓库为 RDP Wrapper Library 提供配置…

2026/10/20 11:00:58 阅读更多 →
看故事,学系统集成:TCPI - 极限生存

看故事,学系统集成:TCPI - 极限生存

小时候的Walkman...故事小时候读书&#xff0c;穷&#xff01;一个月300块就能生存。结果买了随身听&#xff0c;现在身上只剩30块了&#xff01;要撑到月底的话&#xff0c;以往是要180块的&#xff01;只能啃馒头了&#xff0c;一块钱当作6块钱来用&#xff01;问题为什么是“…

2026/10/20 11:00:58 阅读更多 →
【SRC】EDU实战篇6:XSS规则边界与利用验证技巧

【SRC】EDU实战篇6:XSS规则边界与利用验证技巧

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

2026/10/20 11:00:58 阅读更多 →

最新新闻

Pygame性能优化:把静态障碍画进背景并用Mask碰撞检测

Pygame性能优化:把静态障碍画进背景并用Mask碰撞检测

我先说自己踩过的一个坑&#xff1a;做一个小游戏&#xff0c;十几种障碍物各自做成独立精灵对象&#xff0c;视觉上没问题&#xff0c;但数量一多&#xff0c;每帧要遍历、更新、碰撞检测&#xff0c;开销一下上去了。后来改成把所有障碍直接画到背景面上&#xff0c;再配合 m…

2026/10/20 11:58:56 阅读更多 →
VS2019下DuiLib从零配置WIN32空项目完整指南

VS2019下DuiLib从零配置WIN32空项目完整指南

DuiLib 这名字&#xff0c;做 Windows 客户端的老兵肯定不陌生。当年从 MFC 切到 DirectUI 的朋友&#xff0c;多少都摸过这套库&#xff0c;或者至少听过它的大名。到现在&#xff0c;VS2019 出来都这么多年了&#xff0c;网上翻来覆去找资料&#xff0c;很多还是老版本的方案…

2026/10/20 11:58:56 阅读更多 →
MPU6050 DMP直接输出pitch/roll/yaw原理与实战解析

MPU6050 DMP直接输出pitch/roll/yaw原理与实战解析

简介&#xff1a;本资源是一套基于MPU6050传感器DMP&#xff08;数字运动处理器&#xff09;功能实现姿态解算的完整嵌入式工程&#xff0c;面向嵌入式初学者、智能硬件开发者及飞控/机器人方向实践者&#xff0c;解决传统姿态解算中万向锁、算法复杂、滤波调试难等痛点。资源无…

2026/10/20 11:58:56 阅读更多 →
贝叶斯优化实战:从高斯过程到深度学习超参数调优

贝叶斯优化实战:从高斯过程到深度学习超参数调优

简介&#xff1a;面向机器学习与深度学习从业者&#xff0c;这份资源聚焦贝叶斯优化超参数调优&#xff0c;旨在解决手动调参效率低、模型性能难提升的痛点。压缩包共4个文件&#xff0c;核心是两个Python脚本&#xff0c;一个面向支持向量机、随机森林等传统机器学习模型&…

2026/10/20 11:58:56 阅读更多 →
CutMix数据增强在医学病灶检测中的实践:稳住训练与提升小病灶召回

CutMix数据增强在医学病灶检测中的实践:稳住训练与提升小病灶召回

1. 病灶检测的“过山车式”训练&#xff1a;问题到底出在哪做医疗图像的病灶检测有一段时间的人&#xff0c;大概率都见过这样一种场景&#xff1a;训练曲线前期掉得很快&#xff0c;一切看起来都正常&#xff0c;然后到某个阶段开始来回震荡&#xff0c;loss曲线像过山车一样上…

2026/10/20 11:58:56 阅读更多 →
如意报表 Ming-WebReport-V3 安装配置与避坑指南

如意报表 Ming-WebReport-V3 安装配置与避坑指南

简介&#xff1a;如意报表&#xff08;Ming-WebReport-V3&#xff09;安装程序面向需要在Web环境中搭建数据可视化与报表系统的开发者及企业信息化人员&#xff0c;帮助快速完成报表工具的部署与集成。资源包共408个文件&#xff0c;约26.45MB&#xff0c;涵盖o、mrf报表模板、…

2026/10/20 11:57:55 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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/20 10:02:08 阅读更多 →
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/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练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/20 9:50:45 阅读更多 →