新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于STM32F103的摄像头循迹小车:从图像处理到PID控制全解析

发布时间:2026/9/8 22:14:27来源:尧图网络
基于STM32F103的摄像头循迹小车:从图像处理到PID控制全解析
简介基于STM32F103的摄像头循迹智能小车系统面向嵌入式开发学习者和智能车竞赛爱好者融合OV7670图像采集、二值化道路识别和超声波避障等关键技术可广泛应用于毕业设计、课程设计与机器人入门实践。压缩包共166个文件以C源码与头文件为主体77个h、72个c另有Keil工程配置uv2、启动文件s、编译脚本bat、固件hex及测试位图bmp等整体仅751KB结构紧凑便于按模块查阅和移植。已有2338人学习是经过实践验证的完整项目。资源内提供全套工程源码涵盖摄像头驱动、图像二值化与边缘检测、道路边界提取、循迹方向控制、超声波测距避障等模块代码注释清晰配合Keil工程可直接编译烧录适合对照原理图逐模块学习也可在此基础上进行二次开发。 手头这个“基于stm32f103摄像头循迹.zip”我相信很多人是跟我一样从学长手里拷过来或者从某个开源社区下载的。解压以后一看里面的工程文件、原理图、文档乱七八糟折腾了半天也不知道从哪下手。作为一个把摄像头循迹小车从入门到放弃再到入门反复折腾过好几遍的人今天我就拿这个典型工程当例子把基于STM32F103的摄像头循迹项目拆开揉碎从硬件选型到图像处理再到PID控制一次讲清楚。这篇文章不光是解释代码重点是把“为什么这么设计”讲明白。比如为什么很多人选F103而不是F407为什么摄像头要用带FIFO的OV7670而不是直接怼DVP接口为什么边线提取要按行扫描而不是全局遍历。这些都是课本上不讲、但实际做项目一定绕不开的问题。无论你是准备智能车竞赛还是做毕业设计或者是单纯想给自己搞一辆能自动跑的小车这篇文章都值得你花十分钟看完。1. 项目整体设计与方案选型1.1 为什么主控选STM32F103摄像头循迹这个场景对主控的要求其实就三条能采集图像、能跑图像处理算法、能输出PWM控制电机。STM32F103系列虽然已经是“上古时代”的芯片了但在这个场景下简直是为它量身定做的。以最常见的STM32F103C8T6为例72MHz主频、64KB Flash、20KB SRAM。很多人担心20KB内存不够用实际上摄像头循迹根本不需要存整幅大图。如果用的是OV7670带FIFO的模块输出分辨率可以设到QQVGA160x120二值化之后每个像素只需要1个bit整幅图也才160x120/8 2400字节内存完全绰绰有余。就算是灰度图160x120个unsigned char也才19.2KB勉强能塞下。这里顺便说一句20KB SRAM这个数字决定了你不能用太大分辨率的图像直接做全图处理后面讲算法的时候会提到怎么在内存限制下做优化。F103的另一个优势是生态成熟。标准外设库V3.5随便一搜就是下载链接中文参考手册也到处都是。哪怕你用的不是C8T6换成了RCT6或者ZET6代码基本不用改改一下启动文件和芯片型号就能跑起来。对于学生项目来说这是巨大的时间成本优势。1.2 摄像头模块怎么选OV7670与总钻风对比摄像头模块是整个项目里最关键的传感器选错了一切白搭。先明确一点循迹小车用的摄像头核心任务不是拍出好看的照片而是“在尽量低的主控负载下清晰地区分出赛道和背景”。目前市面上主流的选择就两类一是OV7670带FIFO模块。这是入门最常见的方案。模块自带AL422B FIFO芯片摄像头把图像数据先写入FIFO主控需要的时候再从FIFO读出来。这解决了OV7670本身没有读时钟、必须按像素时序读出的尴尬问题。主控只需要控制FIFO的读使能和读时钟就能把数据慢慢读出来不要求实时处理对主控的时序压力小很多。二是总钻风MT9V032这是智能车竞赛圈子里用得很多的方案。它的优势是灰度输出、动态范围大、对光线适应性好而且逐飞科技有配套的库和资料上手非常方便。当然价格也比OV7670贵不少。如果你是想快速把项目跑起来我建议先用OV7670 FIFO模块成本控制在30块以内坏了不心疼。等把整个流程调通了再考虑要不要换总钻风。1.3 工程文件结构这个zip包里应该有什么一个规范的摄像头循迹工程解压以后至少应该有这几块内容基础驱动层包括GPIO初始化、定时器PWM初始化、串口初始化、I2C初始化用于配置OV7670寄存器。这部分属于“伺候硬件”的活代码量最大但技术含量相对低。摄像头驱动层核心是摄像头的寄存器初始化序列和图像采集逻辑。OV7670的寄存器配置非常繁琐网上的初始化函数动辄几百行但基本都是对着数据手册抄的注意SCCB接口的时序要严格按手册来。图像处理层这是整个项目的灵魂。包括灰度图转二值图、边线提取、中线计算、偏差输出。后面我会重点拆这部分。控制层根据图像处理得到的偏差计算舵机打角和电机转速。通常用PID实现。调试辅助层串口打印图像、参数在线调整、蓝牙遥控等。拿到一个陌生工程我建议先按照这个分层去读代码不要上来就盯着一两个函数死磕。2. 硬件搭建与电路设计要点2.1 最小系统的供电与接线方案摄像头循迹小车说白了就是一个典型的嵌入式系统硬件搭建的核心是供电和信号连接。先说供电大部分人的第一辆车都是用两节18650锂电池串联标称7.4V。这个电压给电机驱动模块如TB6612或L298N非常合适但给STM32、摄像头、舵机供电就必须降压。实际测试下来我推荐的分配方案是这样的器件供电电压来源STM32F103最小系统板3.3VAMS1117-3.3稳压OV7670摄像头3.3VAMS1117-3.3稳压需单独滤波舵机如SD-55V-6V独立降压模块或电池直接视舵机规格电机驱动逻辑部分5V/3.3V视模块型号电机本体7.4V电池直接接驱动板有个容易踩的坑OV7670的FIFO芯片和摄像头的感光元件对电源纹波比较敏感如果和舵机共用同一个5V降压打舵瞬间可能导致图像出现横纹。建议摄像头的3.3V单独用一路LDO并且串联一个10uF电容滤波。2.2 核心接线DVP接口与PWM通道STM32F103和摄像头的连接我用PA0-PA7做8位数据线PC0接FIFO读时钟PC1接FIFO读使能PC2接FIFO写时钟PC3接VSYNC场中断。这套方案的优点是8位数据线全部挤在PA口读数据的时候可以直接用GPIOA-IDR一次读取不需要逐bit拼凑效率高很多。PWM通道分配上舵机用TIM2_CH1PA0输出50Hz的PWM信号电机驱动用TIM3_CH1和TIM3_CH2PA6、PA7输出10kHz的PWM信号控制转速和方向。注意舵机是50Hz电机是10kHz两者频率完全不同不能共用一个定时器的同一个通道。2.3 摄像头安装角度与高度这个细节课本上从不讲但实际影响巨大。摄像头的高度和俯仰角直接决定了你“看得多远、看得多宽”。以我的车为例CCD/CMOS摄像头安装在车头前方约15cm处高度25cm俯仰角约10度。这个角度下图像底部的行对应车前的赛道约10cm远处顶部的行对应约1.2米远处。为什么要这样设置因为摄像头循迹和红外循迹最大的区别就是“预期性”。红外传感器只能检测车底的赛道线而摄像头能看到前方1米多的赛道情况为转向提前做出预判。俯仰角越小看得越远但底部盲区越大俯仰角太大视野太近高速过弯时反应不过来。这个需要根据自己的赛道速度实际调试没有绝对标准。3. 图像处理与循迹算法核心3.1 二值化从灰度图到黑白图的阈值选择摄像头采集回来的原始数据是灰度值0-255赛道是白的背景是黑的假设是深色背景目标就是通过一个阈值把图像变成纯黑和白。大于阈值的置1小于阈值的置0。阈值怎么选是第一个大坑。固定阈值在室内固定灯光下勉强能用但一旦环境光变化比如太阳光照到赛道上同样的阈值就废了。我试过几种方案按推荐度排序大津法OTSU自动根据灰度直方图计算最优阈值。原理简单说就是让分割出的前景和背景类内方差最小、类间方差最大。计算量也不大256个灰度级遍历一遍即可在F103上跑一个160x120的图像耗时约5ms完全能接受。动态阈值只取图像底部几行的灰度平均值再加上一个固定偏移作为当前帧阈值。优点是速度快缺点是对突然的光照变化反应迟缓。固定阈值仅仅是调试时的临时方案不建议作为最终方案。具体大津法的实现不复杂核心就是统计灰度直方图然后遍历阈值计算类间方差取最大值对应的灰度级。在标准库工程里大概四五十行代码就能搞定。3.2 边线提取按行扫描与丢线处理二值化之后图像变成了一个0和1组成的二维数组。接下来要找到赛道的左右边线。最常用的办法是从图像底部往顶部逐行扫描对于每一行从左往右找到第一个黑到白的跳变点作为左边界从右往左找到第一个白到黑的跳变点作为右边界。两个边界之间的区域就是赛道。但实际赛道不是平整的会遇到各种“意外”情况。最常见的两种丢线摄像头只拍到赛道的一侧边界另一侧超出了视场角。比如急弯的时候左边界还在图像内右边界找不到了。这时候的常规做法是“丢线补线”用上一帧该侧边界的斜率推断当前帧的位置或者直接镜像另一侧边界。更简单粗暴的做法是用图像边界作为丢失侧的边界。全白/全黑整幅图像全是白色比如到了十字路口中央全是赛道或者全是黑色比如跑出赛道。这种时候不能靠图像直接算出偏差必须有状态机逻辑处理。在写边线提取函数的时候我强烈建议每一行都记录边线是否有效。这不仅是为了防止数组越界也是后面处理十字和环岛的必要条件。3.3 十字路口与补线逻辑十字路口是摄像头循迹的最大难点之一。小车接近十字时图像底部是垂直的赛道线左右两边都是赛道边线提取算法会同时检测到多条边界导致计算出的中线严重偏左或偏右车就歪了。处理策略是在上层增加赛道状态判断常见做法是检测底部的赛道宽度突变。正常行驶时底部赛道宽度大约在40到60像素之间当头接近十字时底部赛道宽度会突然超过80甚至达到满幅。一旦检测到这种情况就进入“十字模式”直接保持上一帧的舵机角度直行直到底部赛道宽度恢复正常。进阶一点的方案是补线逻辑。检测到十字之后在拐角处人为补一条虚拟边线让中线计算保持正常车横穿十字的时候既不犹豫也不偏转。这就是热词里“十字补线”的来由。补线的实现说穿了就是在边线数组里把丢失的那一侧用另一侧镜像加上一个固定偏移量填充。总钻风摄像头因为图像质量高补线效果会更好。具体补线代码的逻辑大致是这样的从底部往上扫描当某一行某一侧边线丢失时取该行另一侧有效边线按赛道经验宽度比如60像素计算出一个虚拟边界。这样中线依然是两边界的平均值算法流程完全不用改。3.4 PID控制从偏差到舵机打角图像处理最终输出的是一个偏差值通常定义为中心列坐标与实际中线列坐标的差值。假设图像宽160中心列是80算出中线在第70列偏差就是-10意味着车偏左了要往右打。舵机的控制用PD控制器就够了。P项让舵机角度正比于偏差D项让舵机对偏差的变化率敏感能有效抑制直道上的蛇形摆动。I项在舵机控制里通常不用因为舵机本身有回中力静态误差不严重。实际参数整定我的经验是先给一个较小的P值比如0.3-0.5把D设为0让车能在低速下跑起来然后逐步加大P直到出现左右摆动再加D抑制摆动直到高速过弯也不抖。电机的速度控制则要看有没有编码器。如果有编码器可以加一个速度闭环让车在直道自动加速、弯道自动减速。如果没有编码器做简单的开环控制根据偏差大小实时调整PWM占空比偏差大说明在弯道里就减速偏差小说明在直道就加速。这种方案简单有效赛道适应性稍差但作为入门完全够用。4. 核心代码解析与实战配置4.1 摄像头初始化与DMA采集工程里摄像头初始化一般是一个大函数里面几十个寄存器配置。OV7670 默认输出RGB565我们需要把它配置成YUV422或者RAW格式再手动转灰度。不过更省事的办法是直接用RGB565格式读取时只取高字节也就是Y分量效果等效于灰度图。这里有一个性能关键点从FIFO读取数据时如果用GPIO逐位读取再移位拼接速度很慢而且会占用大量CPU时间。推荐的做法是用DMA配合定时器触发把FIFO的数据直接搬到内存数组里。但F103的DMA通道不多配置也繁琐很多人一开始搞不定。如果你也是初学者可以退而求其次直接靠GPIO读160x120的分辨率下一帧读取时间大约在20ms左右帧率还能维持20fps以上完全可以接受。我最开始也是直接用GPIO读等整个系统调通了才改的DMA这样排查问题的时候范围更小。4.2 图像处理主循环一份可直接参考的框架// 主循环伪代码在一个while(1)里面 while (1) { // 1. 等待摄像头的VSYNC场中断标志 while (vsync_flag 0); vsync_flag 0; // 2. 从FIFO读取一帧图像到Image[120][160] Read_FIFO_To_Image(); // 3. 用OTSU计算阈值并二值化 uint8_t threshold OTSU((uint8_t *)Image, 120 * 160); for (int row 0; row 120; row) { for (int col 0; col 160; col) { Binary[row][col] (Image[row][col] threshold) ? 1 : 0; } } // 4. 提取左右边线和有效标志 for (int row IMG_H - 1; row 0; row--) { Find_Left_Right(row); } // 5. 补线、计算中线、计算偏差 Fill_Lost_Edge(); int error Calc_Center_Error(); // 6. PID计算舵机角度 Set_Servo_PWM(PD_Controller(error)); // 7. 根据偏差和赛道形状控制电机速度 Set_Motor_PWM(Speed_Plan(error)); }这套框架的好处是把图像采集、处理、控制完全解耦每个环节都可以单独调试。我调车的时候会先在串口上位机里把二值化图像打印出来看效果确认边线提取没问题再切到电机控制。4.3 关键参数配置参考表以我调通的这套参数为例OV7670 FIFO、STM32F103C8T6、120x160分辨率参数数值说明PCLK频率24MHz由外部XCLK 12MHz倍频而来图像分辨率160x120QQVGA兼顾视野和速度二值化阈值OTSU自适应实测阈值约90-140之间波动舵机PID系数P0.35D0.8I0舵机回中良好舵机PWM频率50Hz周期20ms高电平0.5ms-2.5ms电机PWM频率10kHz避免电机啸叫直道目标速度1.8m/s开环PWM约65%占空比弯道减速阈值偏差25像素超过此值开始减速这里特别提一下舵机的PWM频率很多新手直接把电机PWM频率套到舵机上结果舵机吱吱叫且行程不对。舵机必须用50Hz脉宽1.5ms左右是回中位这是舵机的固有规格不要改。5. 调试实录与常见问题排查5.1 串口上位机调试如何“看见”摄像头看到的画面调试摄像头循迹最让人头疼的问题就是车在路上跑你根本看不到它“眼里”的画面到底是什么。解决办法是做一个简单的串口上位机。我用的是匿名上位机或者自己写的一个Python小工具通过串口接收STM32发回来的二值化数组然后在电脑上以ASCII字符或者图形界面的方式还原出来。每行图像按160个像素打印成160个字符黑色用空格、白色用#号一帧120行。然后就能非常直观地看到算法到底把赛道处理成了什么样。这个调试手段最大的价值在于它能把图像处理和实际物理环境对应起来。比如某个弯道丢线严重通过上位机就能看到是算法问题还是摄像头角度问题而不是靠猜。5.2 常见问题速查表根据我自己的调试经历和帮别人调车的经验整理了这份排查表现象可能原因解决思路上电后上位机无图像摄像头SCCB初始化失败检查I2C引脚配置用逻辑分析仪抓波形确认应答图像全白阈值过高或曝光过度查看灰度值分布降低OTSU上限或减少曝光时间图像全黑FIOF读时序错误检查读时钟频率不能超过FIFO最高允许频率直道走S形P过大或D过小减小P加大D弯道直接冲出赛道看得太近或速度过快调大摄像头俯仰角降低入弯速度十字路口抖动状态机误判增加判断的连续帧数比如连续3帧都满足条件才确认阳光一照就乱跑固定阈值不适用换成OTSU或加三档手动切换5.3 调试顺序建议调试一定要有顺序不要一上来就调PID。我的顺序是摄像头出图确认看到的赛道清晰、无横纹。二值化保证赛道和背景能明确分开。边线提取上位机里确认左右边线基本贴合赛道。舵机打角用手推车在不同偏差下看舵机是否按预期转向。最后才让车跑起来调速度。前四步都是静态调试不需要电池大电流放电也不存在失控风险。只有最后一步才需要宽阔的场地和防撞准备。5.4 一个容易被忽视的“坑”陀螺仪融合很多人做到这里会发现纯靠图像PID速度一上来就会甩尾。这是因为摄像头看到的偏差是位置偏差缺少对车辆横摆角速度的感知。进阶方案是加一个陀螺仪比如MPU6050只用Z轴角速度把陀螺仪角速度和图像偏差做加权融合相当于对转向做一个阻尼能让车尾稳定很多。我当时是加了陀螺仪的Z轴角速度作为舵机PID的D项补充效果立竿见影同样一段S弯原来1.5m/s就甩尾融合之后能稳稳跑到2.2m/s。这是我非常推荐的一个升级方向。最后的几句经验摄像头循迹这个项目说难不难说简单也不简单。我见过很多人拿到现成代码烧进去能跑就觉得自己“会了”结果一换场地、一换灯光就原形毕露。所以我特别想强调代码只是载体真正值钱的是你对图像处理流程的理解和对参数的调优能力。如果你也是刚拿到这样的zip工程我建议你第一件事不是烧代码而是打开原理图和配置文件把数据流捋明白——摄像头怎么把图像送进来、主控怎么处理、处理后怎么控制车。把这套“数据流”刻在脑子里比背一百个API都有用。等你能做到不看代码就能口述整条处理链路那这辆车就真正是你的车了。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Starship “No Nerd Font“ 预设全解:不安装 Nerd Font 也能完整渲染全部模块符号 2026/9/8 22:50:33

Starship “No Nerd Font“ 预设全解:不安装 Nerd Font 也能完整渲染全部模块符号

Starship "No Nerd Font" 预设全解:不安装 Nerd Font 也能完整渲染全部模块符号 【免费下载链接】starship ☄🌌️ The minimal, blazing-fast, and infinitely customizable prompt for any shell! 项目地址: https://gitcode.com/GitHub_T…

阅读更多 →
2026年实测这3个口碑爆棚的AI智能降重工具,毕业论文AIGC检测达标毫无压力! 2026/9/8 22:50:33

2026年实测这3个口碑爆棚的AI智能降重工具,毕业论文AIGC检测达标毫无压力!

最近辅导学弟学妹写论文,发现一个明显的变化:大家不再只担心查重率高,更怕的是被AIGC检测出痕迹。导师一句“AI痕迹太重”,可能直接让整篇论文前功尽弃。现在知网、维普的AI检测红线卡在10%,一旦超标就存在风险。网上各…

阅读更多 →
LlamaIndex 中的 LanceDB 多模态托管索引:LanceDBMultiModalIndex 全解析 2026/9/8 22:50:33

LlamaIndex 中的 LanceDB 多模态托管索引:LanceDBMultiModalIndex 全解析

LlamaIndex 中的 LanceDB 多模态托管索引:LanceDBMultiModalIndex 全解析 【免费下载链接】llama_index LlamaIndex is the leading document agent and OCR platform 项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index 本文基于 LlamaIndex 仓…

阅读更多 →
Docling 解析 LaTeX 学术论文实战:从 arXiv 2501.00089 天体物理论文看 Docling 的 LaTeX→Markdown 转换管线 2026/9/8 22:50:33

Docling 解析 LaTeX 学术论文实战:从 arXiv 2501.00089 天体物理论文看 Docling 的 LaTeX→Markdown 转换管线

Docling 解析 LaTeX 学术论文实战:从 arXiv 2501.00089 天体物理论文看 Docling 的 LaTeX→Markdown 转换管线 【免费下载链接】docling Get your documents ready for gen AI 项目地址: https://gitcode.com/GitHub_Trending/do/docling 导读 本文围绕 Doc…

阅读更多 →
BMC固件工程师:服务器健康系统的底层调度者 2026/9/8 22:50:33

BMC固件工程师:服务器健康系统的底层调度者

1. BMC固件工程师不是“写BIOS的”,而是服务器健康系统的总调度员很多人第一次听说BMC(Baseboard Management Controller),下意识会把它和主板BIOS划等号——毕竟都跑在板子上、都带“固件”俩字、都能进底层。但这种类比就像把消…

阅读更多 →
AI前沿日报:Agent工程化、AI编程、视频生成与企业落地全解析 2026/9/8 22:47:32

AI前沿日报:Agent工程化、AI编程、视频生成与企业落地全解析

今天是2026年9月1日,周二。我照例在早上七点半坐到电脑前,趁咖啡还烫手,把过去24小时里 AI 领域值得看的东西梳理了一遍。这份“AI 前沿日报”我已经写了快两年,从一开始的模型发布号外,到现在的 Agent 工程实践、内容…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞