专科生第一次参加智能车飞檐走壁创意组备赛指南

发布时间:2026/8/30 1:36:43
专科生第一次参加智能车飞檐走壁创意组备赛指南 专科学校第一次参加智能车比赛能不能不被虐这是很多第一次参赛队伍的真实顾虑。尤其是看到“飞檐走壁”这种听起来就很卷的创意组题目时第一反应往往是我们学校没有传承没有实验室底子也没有学长留下的代码进去大概率就是陪跑。但我想先给一个判断第一次参赛最大的价值不是拿奖而是把一套完整技术流程走通。只要车能稳定跑完一圈你就已经赢过了多数还没上车的队伍。全国大学生智能车竞赛每年报名队伍很多真正能把车调到稳定完赛的队伍比例并没有想象中那么高。专科院校第一次参赛最大的竞争对手不是那些老牌强校而是“连车都没跑起来”的自己。这篇文章不会给你画大饼。我重点讲三件事飞檐走壁创意组到底在考什么一个零基础的队伍怎么从零开始备赛以及第一年最应该避开的坑。如果你正准备参加智能车竞赛尤其是第一次参赛的专科队伍建议先把这篇文章收藏后面备赛遇到问题可以回来对照。1. 飞檐走壁创意组它不是更难的竞速组而是换了一条赛道很多第一次参赛的同学会误以为创意组就是“普通竞速组的加强版”觉得飞檐走壁肯定比传统竞速更难。这个理解其实不太对。从智能车竞赛的组别设置来看传统竞速组和创意组是两条并行的赛道。传统竞速组比的是在固定赛道上的极限速度和稳定性规则清晰、赛道元素明确多年沉淀下来各校的解决方案已经非常成熟新手直接去拼速度起步成本很高。而创意组例如科大讯飞创意组更侧重智能算法的应用、任务场景的理解、以及软硬结合的综合能力题目每年变化大没有现成的标准答案反而给了新队伍更多发挥空间。“飞檐走壁”这个名字听起来很玄其实从技术角度看它考察的核心能力可以拆成几块赛道环境的感知能力车需要知道自己在哪赛道边界是什么样前方有没有需要处理的元素。车辆运动控制能力在识别出赛道信息后如何让转向、速度、制动配合起来让车又快又稳。任务决策能力遇到不同赛道元素时车选择加速、减速还是绕行这背后是一个简单的状态机。机械与电气稳定性摄像头固定的角度、重心高度、轮胎摩擦力、供电稳定性这些看起来不起眼的细节往往会决定车能不能完赛。所以飞檐走壁创意组真正考察的不是“你的车能跑多快”而是“你有没有能力把一辆小车从无到有地调成一套稳定系统”。对第一次参赛的专科队伍来说后者反而更容易在几个月内追上来因为它的瓶颈不在资源的堆砌而在方法和耐心。还有一个重要的背景是智能车竞赛的知名指导老师卓晴老师每年都会在竞赛期间发布大量技术指导、国赛名单和优秀方案解读。从热搜词可以看到第二十一届智能车竞赛的国赛名单、各分赛区获奖名单、讯飞创意组国赛名单等话题都非常热。这说明什么说明这个比赛的信息公开度很高优秀队伍的方案和代码往往有迹可循。第一次参赛的队伍完全可以通过研究往届优秀方案来缩短差距不必从零硬造轮子。2. 第一次备赛最怕的不是不会写代码而是没有方法和不少第一次带队的指导老师、参赛队长聊过之后会发现专科院校第一次参加智能车竞赛最大的困难通常集中在三个维度维度典型痛点影响经验断层没有学长留下的代码和车模所有东西从零摸起步慢容易在基础环境上卡几周技术储备嵌入式开发经验少不会看原理图不会调试硬件遇到问题不知道从哪里查起信息差不知道官方手册在哪看、不知道逐飞库怎么配、不知道往届方案去哪找自己闭门造车效率很低这三个痛点本质都不是“能力不够”而是“不知道路怎么走”。所以这篇文章想做的其实是给你一条已经在别人身上验证过的路径先拆解技术栈再搭最小系统最后逐步优化。一个完整的智能车系统从宏观上可以分成五层感知层 - 决策层 - 执行层 - 机械层 - 供电与调试 摄像头 主控芯片 舵机/电机 车架/轮胎 电池/串口第一次备赛时最合理的策略不是五层同步推进而是先把每一层的最小可用版本跑通摄像头能出图主控能跑代码舵机能打角电机能转动电池能稳定供电。等这个“最小系统”成立之后再一层层去优化。很多队伍第一年失败不是死在算法上而是死在“车还没能动起来就去调PID”上。把握好节奏比什么都重要。3. 备赛技术栈全景你需要认识这些关键部分在开始动手之前先建立一个整体认知。以下是一个典型的摄像头组智能车会用到的核心组件飞檐走壁创意组大体也在这个框架内具体型号以你拿到的官方技术手册为准。3.1 车模与机械部分车模是整车的骨架。智能车竞赛中常见的车模类型有A车、B车、C车等不同车模的轴距、轮径、转向机构都不一样。第一次备赛不建议自己改装车模的机械结构先用官方提供的标准车模跑通算法等有经验了再去调整重心、加装减震、改造轮胎。机械部分真正需要新手关注的是几个细节摄像头安装高度与角度摄像头决定车“看”到的画面安装高度太高会看到太多远处噪声太低会丢失近处赛道信息。一般原则是先装到中间高度再根据图像效果微调。重心位置重心偏高或偏后过弯时车容易侧翻或甩尾。可以适当在前轮区域配重。轮胎状态新轮胎的抓地力可能不足有些队伍会用酒精擦拭轮胎表面增加摩擦力但这属于调校细节第一年不必太纠结。3.2 主控芯片与嵌入式软件主控是智能车的“大脑”。目前主流方案中逐飞科技提供的主控核心板常见的有TC264、TC377等系列在智能车竞赛中使用率很高配套的底层库也比较完善。第一次备赛强烈建议不要自己画板子、不要自己从寄存器底层开始写驱动直接使用成熟的核心板加官方库把精力集中在图像处理和运动控制上。嵌入式开发环境常用的有IAR、Keil、VS Code配合工具链等。不同芯片使用不同IDE具体以主控型号对应的开发文档为准。备赛初期先把“编译、下载、运行”这条链路跑通后面所有代码都在这个基础上迭代。3.3 摄像头、编码器与传感器摄像头用于获取赛道图像。常见的灰度摄像头、数字摄像头各有优劣第一次建议选择资料较多的型号。摄像头输出的图像质量直接影响后面所有算法所以要学会通过调试工具实时查看摄像头画面。编码器用于测量车轮转速是速度闭环控制的基础。编码器数据读不准速度PID就是空中楼阁。其他传感器创意组通常还会用到一些和任务场景相关的传感器比如用于检测特定元素的模块。具体以官方手册为准不要盲目堆传感器。3.4 电机、舵机与驱动电路电机的驱动方式一般是“主控输出PWM - 驱动芯片放大 - 电机转动”。舵机用于控制前轮转向同样的PWM控制原理。第一次备赛你需要在调试工具里确认几件事给某个占空比的PWM电机的实际转速是多少。给某个占空比的PWM舵机是否在中位、左极限、右极限正确打角。电池电压下降后相同PWM下电机转速是否明显变化。4. 环境搭建与工程初始化先跑通最小系统无论你的主控芯片是什么型号环境搭建的核心目标是一样的创建一个空的工程能成功编译能下载到板子上运行能通过串口或屏幕看到调试信息。不要一上来就想着写图像处理先把这个最小闭环跑通。下面以一个基于逐飞库的常见主控为例演示工程初始化的思路。具体引脚号、库函数名以你手上的核心板资料为准但整体流程是通用的。4.1 创建工程并引入底层库一般的做法是从逐飞科技官网下载对应主控的支持库新建一个工程目录把库的源码添加到工程中。目录结构类似smartcar_project/ ├── code/ # 用户代码 │ ├── main.c │ ├── isr.c │ ├── image_process.c │ └── control.c ├── libraries/ # 官方底层库 │ ├── fv_... │ ├── ... └── project.eww # IAR 工程文件4.2 主函数初始化示例主函数要做的事很清晰初始化各个模块然后进入主循环。中断服务函数一般单独放在 isr.c 中。// 文件路径code/main.c #include headfile.h int main(void) { // 1. 底层系统初始化包括时钟、中断优先级等 system_init(); // 2. 外设初始化串口、摄像头、编码器、PWM、舵机、按键、屏幕 uart_init(UART_1, 115200); camera_init(); encoder_init(); pwm_init(); steer_init(); key_init(); tft180_init(); // 3. 全局变量初始化 int16_t speed_now_left 0; int16_t speed_now_right 0; int16_t steer_angle_mid 500; // 舵机中值需要实测标定 // 4. 开启摄像头采集 camera_start(); while (1) { // 主循环中不做耗时操作图像处理与控制在中断中完成 if (frame_ready_flag) { frame_ready_flag 0; // 1. 获取一帧图像 image_get(IMAGE_SOURCE_0, image_use); // 2. 图像处理后续章节细讲 image_process(image_use); // 3. 控制计算根据处理结果输出舵机和电机PWM steering_control(); speed_control(); // 4. 调试信息发送到上位机 debug_send(); } } }这一段代码看起来简单但它帮你建立了智能车程序的基本骨架主循环只负责触发图像处理和控制都依赖摄像头帧完成。很多新手喜欢在 while 循环里加delay这是大忌所有延迟都会导致图像处理到一半就被打断最终车跑起来时控制滞后非常严重。4.3 中断服务函数示例摄像头场中断作用是告诉你“新的一帧图像已经准备好了”。在这里置一个标志位主循环检测到标志位后再处理图像。// 文件路径code/isr.c #include isr.h volatile uint8_t frame_ready_flag 0; // 摄像头场中断新一帧图像到来 void vsync_isr(void) { frame_ready_flag 1; } // 定时器中断用于周期性的编码器采集和速度计算 void pit_isr(void) { // 读取编码器计数值 encoder_get_speed(); // 可在此处进行速度环控制也可以在主循环中做 speed_control(); }中断是嵌入式开发中很容易出错的点。新手常见的错误包括中断服务函数里写耗时操作、中断标志位没有清、变量声明没有加 volatile。这三点先记下来后面调试时会帮你省很多时间。4.4 串口调试输出示例串口是智能车调试最重要的工具。你需要在代码里加一个简单的格式化输出函数方便随时把图像处理结果、舵机占空比、速度值打印出来。// 文件路径code/debug.c #include headfile.h void debug_send(void) { char buff[128] {0}; sprintf(buff, L:%d R:%d P:%d S:%d\r\n, speed_left, speed_right, steer_pwm, target_speed); uart_write_string(UART_1, buff); }运行验证时把串口接上USB转TTL模块电脑上打开串口助手设置好波特率如果能看到类似L:120 R:118 P:530 S:200的数据在不断刷新说明程序主循环和串口都工作正常。5. 核心代码实现读图、找边、控车正式进入飞檐走壁创意组最核心的部分。这里我们不讨论具体赛题元素因为每年规则都会变需要以官方手册为准。但图像处理、赛道边缘提取、方向控制、速度控制这套“铁四角”是所有视觉类智能车都绕不开的技术底座。5.1 图像二值化摄像头采集回来的原始图像一般是灰度图每个像素点的灰度值范围是0到255。为了把赛道和背景快速分开最简单的办法是设定一个阈值灰度值大于阈值的置为白色赛道小于阈值的置为黑色背景这就是二值化。// 文件路径code/image_process.c #define IMAGE_W 160 // 图像宽度以实际配置为准 #define IMAGE_H 120 // 图像高度以实际配置为准 #define THRESHOLD 128 // 二值化阈值需要根据环境光线标定 uint8_t image_binary[IMAGE_H][IMAGE_W]; void image_binarize(uint8_t image_gray[IMAGE_H][IMAGE_W]) { for (int row 0; row IMAGE_H; row) { for (int col 0; col IMAGE_W; col) { if (image_gray[row][col] THRESHOLD) { image_binary[row][col] 1; // 白色赛道 } else { image_binary[row][col] 0; // 黑色背景 } } } }这里真正容易踩坑的地方是阈值固定。如果你在比赛现场遇到灯光变化、反光、阴影干扰固定阈值可能会导致图像大面积丢失赛道信息。进阶方案是使用大津法OTSU自动计算阈值但第一年备赛建议先把固定阈值调好理解整条链路之后再去优化。5.2 赛道边缘提取有了二值化图像之后下一步是从每一行找到赛道的左右边界。基本思路是从图像底部一行的中间位置开始先找到白色赛道的起始点再向左、向右扫描找到最近的黑色像素点作为左右边界。// 文件路径code/image_process.c typedef struct { uint8_t valid; // 这一行是否找到有效边线 uint8_t left; // 左边界列号 uint8_t right; // 右边界列号 uint8_t center; // 赛道中心列号 } line_row_t; line_row_t line_data[IMAGE_H]; void image_find_edge(void) { int mid_col IMAGE_W / 2; for (int row IMAGE_H - 1; row 0; row--) { // 从中间向两侧找左边界 int left_edge -1; for (int col mid_col; col 0; col--) { if (image_binary[row][col] 0 image_binary[row][col 1] 1) { left_edge col; break; } } // 从中间向两侧找右边界 int right_edge -1; for (int col mid_col; col IMAGE_W; col) { if (image_binary[row][col] 0 image_binary[row][col - 1] 1) { right_edge col; break; } } line_data[row].left left_edge; line_data[row].right right_edge; if (left_edge 0 right_edge 0) { line_data[row].valid 1; line_data[row].center (left_edge right_edge) / 2; } else { line_data[row].valid 0; } } }这段代码的逻辑值得仔细看一遍在二值化图像中赛道边缘实际上就是“白色像素和黑色像素交界的那一列”。从中间出发如果在某一列遇到黑色像素且它右边是白色像素说明你找到了赛道的左边界右边界同理。这个算法本身不难但对新手来说真正难的是当某一行的赛道丢失时如何用上一行的数据补全这部分需要你在实际调车中慢慢积累经验。5.3 方向控制 PID提取到赛道中心线之后就可以计算舵机打角量。最常用的方法是把当前赛道中心与图像中心的偏差作为输入用PID计算出舵机PWM增量。// 文件路径code/control.c #define STEER_MID 500 // 舵机中值实测标定 #define STEER_KP 1.2f // 比例系数 #define STEER_KD 0.8f // 微分系数 int16_t steer_pwm STEER_MID; float error_last 0.0f; void steering_control(void) { // 取图像中偏下、距离较近的一行作为控制参考 int ref_row IMAGE_H - 10; if (ref_row 0) ref_row 0; // 赛道中心相对图像中心的偏差 float error line_data[ref_row].center - IMAGE_W / 2; // 简单PD控制微分项帮助抑制抖动 float derivative error - error_last; error_last error; int16_t delta (int16_t)(STEER_KP * error STEER_KD * derivative); steer_pwm STEER_MID delta; // 限幅保护舵机 if (steer_pwm STEER_MID 200) steer_pwm STEER_MID 200; if (steer_pwm STEER_MID - 200) steer_pwm STEER_MID - 200; }请注意这里的STEER_MID不是凭感觉写的。你必须在上电后手动给舵机发一个PWM观察前轮是否处于正中间位置然后把这个值写进代码里。每个舵机的中值都可能不一样这是调车的第一步也是最容易被忽略的一步。5.4 速度控制与状态机速度控制的核心是编码器测速 速度PID。编码器读取当前实际速度和期望速度比较用PID调整PWM占空比。// 文件路径code/control.c #define TARGET_SPEED_FAST 300 #define TARGET_SPEED_SLOW 150 int16_t target_speed 200; float speed_error_integral 0.0f; void speed_control(void) { int16_t speed_now (speed_left speed_right) / 2; float speed_error target_speed - speed_now; // 简单速度PI控制积分项消除稳态误差 speed_error_integral speed_error; if (speed_error_integral 500) speed_error_integral 500; if (speed_error_integral -500) speed_error_integral -500; int16_t pwm_out (int16_t)(0.5f * speed_error 0.02f * speed_error_integral); // 将 pwm_out 设置为电机占空比 set_motor_pwm(pwm_out); }创意组和传统竞速组的一个区别是速度不能从头到尾恒定。当车识别到某些赛道元素时需要主动减速或加速。这时候就需要一个简单的状态机typedef enum { RUN_NORMAL 0, // 正常巡线 RUN_SLOW, // 低速通过 RUN_STOP, // 停车等待 } car_state_t; car_state_t car_state RUN_NORMAL; void state_update(void) { switch (car_state) { case RUN_NORMAL: target_speed TARGET_SPEED_FAST; if (need_slow_down()) { car_state RUN_SLOW; } break; case RUN_SLOW: target_speed TARGET_SPEED_SLOW; if (speed_now_finished()) { car_state RUN_NORMAL; } break; default: break; } }状态机的引入会让程序结构变得清晰很多。第一次写控制代码时不要把所有逻辑都堆在一个大 if 里面状态机是一个非常值得养成的工程习惯。6. 运行与验证先让车动起来再让它跑好代码写完之后下一步就是上电实测。很多新手队伍在这里会陷入一个误区希望代码一次写完一上电就能跑得很好。这是不现实的。正确的调车顺序是分层验证。6.1 第一步验证图像链路把车放在赛道上连接调试器或无线图传观察处理器屏幕上显示的图像。重点确认二值化是否把赛道和背景清晰分开。每一行是否都找到了左右边界。赛道中心线是否与图像中心线形成合理的偏差。如果图像不对后面所有控制都是空谈。6.2 第二步原地验证转向把车架空轮子离地推动赛道图像模拟过弯效果观察舵机是否随赛道中心偏差左右打角。注意此时不接电机电源只验证转向链路。6.3 第三步低速验证整圈把目标速度调到一个非常保守的值比如 50让车真正在赛道上跑起来。这时候的目标只有一个能否完整跑完一圈不掉出赛道。如果不行先降低速度再逐步提高。验证过程中最实用的调试方式是串口输出和屏幕显示。每一步调完都要记录当时的参数值和现象方便回退对比。重要提醒在正式比赛场地调试时一定要留足时间让车载电池充电建议多备一块电池轮换使用。纯电动车的续航只有几分钟一次充满电可能只够完整跑几圈如果电池供电不足电机和舵机都会出现异常抖动很容易被误判为代码问题。7. 常见问题与排查思路根据智能车竞赛备赛中高频出现的问题整理了一份排查表。如果你的车跑不起来先对照这张表逐项排查多数问题都能在这里找到方向。问题现象可能原因排查方式解决方案编译报错找不到头文件底层库路径没有添加到工程检查工程设置的 include 路径把 libraries 目录加入头文件搜索路径代码下载成功但车没反应电源开关没开、电池电压低、主控板供电异常测量电池电压确认电源指示灯上电顺序先开电源再下载代码电压不足就换电池图像全是白色或全黑摄像头初始化失败、曝光异常、画面未开启查看摄像头寄存器配置、屏幕预览重新初始化摄像头检查摄像头排线图像有严重的拖影或噪声曝光时间过长、视角晃动、光源变化降低曝光固定摄像头支架调节摄像头曝光参数优化安装固定左右边界线断断续续二值化阈值不合适、赛道元素干扰将二值化图像发到屏幕观察调整阈值或增加补线逻辑舵机抖动严重PID的KD偏大、舵机中值错误原地打印误差值和PWM输出值重新标定舵机中值降低微分系数车跑偏严重摄像头安装偏斜、PID出力方向反了查看图像中赛道中心是否与车辆真实位置一致调整摄像头安装角度检查控制方向符号速度忽快忽慢编码器读数异常、电池电压波动、PWM设置错误串口打印实际速度观察编码器值检查编码器接线安装是否松动校准电机PWM范围这里再强调一次调试时一定要分层做验证不要同时怀疑所有环节。比如车跑偏先通过串口打印确定“图像偏差值是否正确”再判断“控制量输出是否合理”最后看“执行机构是否动作”。每次只改动一个变量否则很容易陷入“改了很多参数也不知道哪个生效”的泥潭。8. 第一年参赛的工程化建议专科队伍也能打的路线图第一次参加智能车竞赛尤其是专科院校团队资源相对有限所以更要把精力花在刀刃上。下面这些建议是基于大量新队伍的实际备赛经验总结出来的可以直接复用。8.1 团队分工要按“系统”切不要按“代码”切很多第一次带队的同学喜欢把任务分成“图像组的写图像控制组的写控制”结果两个人互相等对方代码项目整体进度很慢。更合理的分工方式是按系统切机械与硬件一人负责车模组装、摄像头支架、电源接线、电池管理。算法与图像一人负责图像采集、二值化、边缘提取、补线逻辑。控制与调试一人负责舵机、电机、编码器、PID控制、串口调试。这样切的好处是每个人都能独立完成一个子系统并且能单独验证。等到联调阶段再把三个系统拼起来。8.2 代码必须做版本管理第一次参赛的队伍代码出问题了经常是“之前明明好的改了一下就不行了”然后只能从头翻代码。强烈建议从第一天就把代码托管到 Gitee 或 GitHub 私有仓库每次改动都提交一次写明改了什么、为什么改。一个简单的提交习惯# 初始化仓库 git init # 添加所有文件 git add . # 提交一次改动信息写清楚 git commit -m 调整摄像头曝光时间解决图像过暗问题哪怕只是调了一个参数也要提交。因为一个参数的改动很多时候需要结合当时的赛道环境才有意义不记录下来第二天就可能忘得一干二净。8.3 建立一个“调车记录本”这是一个非常土但非常有效的方法。每一次下赛道调试都记录三件事本次改了哪些参数或代码。在什么赛道环节、什么速度下测试。现象是什么是变好了还是变差了。很多队伍调车调了两个月最后连“上次能跑完一圈的参数是多少”都不知道。一个简单的记录本就能帮你避免这种悲剧。8.4 善用往届资料但不要全盘照搬智能车竞赛的公开资料非常多卓晴老师的微信公众号、官方论坛、逐飞科技的文档和开源库都是很好的学习资源。第一次参赛建议花一周时间把往届优秀方案的技术报告和代码框架看一遍理解别人是如何拆解问题的而不是直接复制粘贴。尤其要注意的是赛题每年都在变。往届代码中针对特定赛道元素的判断逻辑今年可能完全不适用。你要复用的是底层架构和调试方法而不是具体的阈值和参数。8.5 把“完赛”当做第一目标第一次参加智能车竞赛最现实的目标不是冲击国奖而是在分赛区比赛中顺利完成三圈有效成绩。这个目标看似不高但需要你在硬件、算法、机械、稳定性四个方面都达到一定水平。等你能稳定完赛了再来谈速度优化、锐角过弯、元素识别这些进阶问题。9. 写在最后轻点虐的前提是先上场回到标题里那句“佬们轻点虐”。等你真正站到比赛现场会发现那些老牌强队不会故意“虐”你大家各跑各的车彼此之间更重要的是交流和学习。真正的压力往往来自你对自己的怀疑。专科学校第一次参加智能车“飞檐走壁”创意组确实没有任何先发优势。但智能车竞赛最公平的一点是车不会说谎。代码写得对不对、参数调得准不准、机械装得稳不稳最后都会体现在赛道成绩上。只要你愿意扎扎实实走完前面说的每一步——从最小系统到图像处理到PID控制到整圈调试——你完全有机会在第一次参赛时就跑出让自己满意的成绩。最后给第一次参赛的队伍三个行动建议第一本周就把官方技术手册和往届优秀方案下载下来带着团队读一遍。第二两周内务必跑通“摄像头出图 串口打印”的最小系统先看到一帧图像。第三把第一版车模组装好哪怕算法很差也要让它先动起来。车只要动起来后面所有问题都能逐个击破。祝你们的车第一次站上赛场就能稳稳跑完全程。