当前位置: 首页 > news >正文

电子设计大赛【摄像头循迹】讲解

目录

系统概述与基础原理

1.循迹定义

2.核心原理

硬件系统的搭建

1.摄像头模块

(1)机器视觉能力

(2)开发支持

2.主控芯片

3.电机驱动模块

(1)芯片组合定位与分工

(2)关键芯片能力解析

1. STM32F103VCT6(ARM Cortex-M3 MCU)

2. Cyclone IV EP4CE6E22C8N(Intel FPGA)

(3)电机驱动架构 

软件代码讲解

一、直线循迹核心流程

二、关键代码解析

1. 图像预处理

 2. ROI区域定义

 3. 直线检测核心函数

4. 偏转角计算

 5. 数据封装与发送

 6. 主循环中的循迹处理

三、关键技术点

四、数据处理流程

效果展示


系统概述与基础原理

1.循迹定义

智能小车沿指定(黑线)路径循迹。

2.核心原理

摄像头采集路面图像 → 图像处理识别路径 → 生成控制信号 → 驱动执行机构(电机/舵机)


硬件系统的搭建

1.摄像头模块

搭载 Kendryte K210 芯片的 AI 摄像头模组。

(1)机器视觉能力

  • 实时目标检测:识别物体/人脸的位置、大小及类型,输出坐标信息。
  • 颜色/形状追踪:通过 HSV 空间过滤与连通域分析,定位最大色块并反馈中心坐标。
  • 神经网络模型支持:可部署 YOLOv2 Tiny 等轻量模型,适用于边缘端 AI 推理。

(2)开发支持

  • 编程环境:支持 MicroPython(MaixPy 框架),代码简洁易上手,提供图像处理库(如 find_blobs 色块检测)。

  • 通信接口:集成 UART/I2C/SPI,可连接 STM32 等主控,通过串口传输坐标数据。

  • 扩展性:支持 TF 卡存储模型文件,GROVE 兼容接口便于连接传感器。

2.主控芯片

采用ATMEGA2560-16AU这款芯片是 Arduino Mega 2560 开发板的核心微控制器芯片。

特性参数
架构8 位 AVR RISC 处理器
主频16MHz(-16AU 后缀表示 16MHz 版本)
Flash 程序存储器256KB
SRAM8KB
EEPROM4KB
PWM 通道15 路(12 位精度,支持相位校正/快速 PWM)
数字 I/O 引脚54 个(含 PWM 引脚)
串口4 个 UART
外部中断所有 I/O 引脚均支持

3.电机驱动模块

(1)芯片组合定位与分工

芯片核心角色电机驱动中的核心任务
STM32F103VCT6主控决策层 (MCU)系统调度、通信协议、高级算法(PID/FOC)
Cyclone IV EP4CE6E22C8N实时执行层 (FPGA)超高速PWM生成、编码器捕获、硬件保护逻辑

💡 协作逻辑
STM32 计算电机控制量 → FPGA 执行精确的功率器件驱动 → 实时反馈信号由 FPGA 捕获后送回 STM32


(2)关键芯片能力解析

1. STM32F103VCT6(ARM Cortex-M3 MCU)
  • 核心参数

    • 72MHz 主频,256KB Flash,48KB RAM

    • 高级定时器 × 3(支持6路互补PWM,死区时间可编程)

    • 12位ADC × 3(21通道,1μs转换速度)

  • 电机控制专长

    • 原生支持无感FOC算法(配合ST MotorControl SDK)

    • 3路霍尔/编码器接口(用于电机位置检测)

    • 硬件过流保护触发(BKIN引脚直连FPGA)

2. Cyclone IV EP4CE6E22C8N(Intel FPGA)
  • 核心参数

    • 6272 逻辑单元(LEs),270Kb 嵌入式存储器

    • 15个18×18乘法器(DSP模块)

    • 最大182个用户I/O

  • 电机控制专长

    • 纳秒级PWM响应:可生成分辨率<10ns的PWM(远优于MCU的百纳秒级)

    • 硬实时保护:过流/过压保护延迟<500ns(比软件中断快100倍)

    • 多路编码器并行处理(支持1024线增量式编码器@10万RPM)

(3)电机驱动架构 


软件代码讲解

一、直线循迹核心流程

二、关键代码解析

1. 图像预处理

# 拍摄原始图像
img = sensor.snapshot()# 转换为灰度图(巡线模式下)
if img_color_type == 0:img = img.to_grayscale(copy=False)# 动态调整灰度阈值
get_mean_gray(img,320,240)

 2. ROI区域定义

ROIS = {'left': (0, 0, 180, 50),            # 左侧纵向检测区'right': (0, 190, 180, 50),         # 右侧纵向检测区'up': (240, 0, 80, 240),            # 上方横向检测区'middle_up': (160, 0, 80, 240),     # 中上方横向检测区'middle_down': (80, 0, 80, 240),    # 中下方横向检测区'down': (0, 0, 80, 240),            # 下方横向检测区
}

 3. 直线检测核心函数

def find_blobs_in_rois(img):'''在预定义ROI区域中检测黑线'''roi_blobs_result = {}for roi_direct in ROIS.keys():# 初始化结果字典roi_blobs_result[roi_direct] = {'cx':0, 'cy':0, 'w':0, 'blob_flag': False}for roi_direct, roi in ROIS.items():# 在ROI区域内寻找符合阈值的色块blobs = img.find_blobs(LINE_COLOR_THRESHOLD, roi=roi, merge=True)if blobs:# 找到最大色块largest_blob = max(blobs, key=lambda b: b.pixels())if largest_blob.area() > 1000:  # 面积过滤小噪点# 记录色块中心坐标和宽度roi_blobs_result[roi_direct]['cx'] = largest_blob.cy()roi_blobs_result[roi_direct]['cy'] = largest_blob.cx()roi_blobs_result[roi_direct]['w'] = largest_blob.h()roi_blobs_result[roi_direct]['blob_flag'] = True# 调试模式下绘制检测框if is_debug:x,y,width,height = largest_blob[:4]img.draw_rectangle((x,y,width, height), color=(255))return roi_blobs_result

4. 偏转角计算

def state_deflection_angle(roi_blobs_result):'''计算车辆偏转角度和路口状态'''# ROI区域权重配置(重点关注上下区域)ROIS_WEIGHT = [1, 0, 0, 1]  # [上, 中上, 中下, 下]state_crossing = Falsedeflection_angle = 0down_center = 0center_num = 0# 1. 计算加权中心位置centroid_sum = (roi_blobs_result['up']['cx'] * ROIS_WEIGHT[0] + roi_blobs_result['middle_up']['cx'] * ROIS_WEIGHT[1] +roi_blobs_result['middle_down']['cx'] * ROIS_WEIGHT[2] + roi_blobs_result['down']['cx'] * ROIS_WEIGHT[3])# 2. 统计有效检测区域数量if roi_blobs_result['up']['blob_flag']:center_num += ROIS_WEIGHT[0]if roi_blobs_result['middle_up']['blob_flag']:center_num += ROIS_WEIGHT[1]# ... 其他区域类似# 3. 计算中心位置(避免除零错误)if center_num > 0:center_pos = centroid_sum / sum(ROIS_WEIGHT)else:center_pos = IMG_WIDTH / 2  # 默认中心位置# 4. 计算偏转角(图像中心 - 检测中心)deflection_angle = (IMG_WIDTH / 2) - center_pos# 5. 路口检测逻辑# 检测左右两侧是否有黑线(可能进入十字路口)if roi_blobs_result['left']['blob_flag'] or roi_blobs_result['right']['blob_flag']:# 检查是否在图像下方1/3区域内if (roi_blobs_result['left']['cy'] <= (IMG_HEIGHT/3) or roi_blobs_result['right']['cy'] <= (IMG_HEIGHT/3)):# 检查下方黑线宽度是否超过阈值(十字路口特征)if roi_blobs_result['down']['w'] > 140:state_crossing = True# 如果两侧同时检测到黑线,确定为十字路口if (roi_blobs_result['left']['blob_flag'] and roi_blobs_result['right']['blob_flag'] androi_blobs_result['left']['cy'] <= (IMG_HEIGHT/3) and roi_blobs_result['right']['cy'] <= (IMG_HEIGHT/3)):state_crossing = Truereturn down_center, state_crossing, deflection_angle

 5. 数据封装与发送

def data_format_wrapper(down_center, state_crossing, deflection_angle):'''封装循迹数据为通信协议格式'''send_data = [0x55,  # 帧头0x02,  # 数据长度0x91,  # 指令类型(循迹)down_center,  # 底部中心标志(未使用)1 if state_crossing else 0,  # 路口标志get_symbol(deflection_angle),  # 偏转角符号(+/-)abs(int(deflection_angle)),  # 偏转角绝对值0xbb   # 帧尾]return bytes(send_data)def UsartSend(str_data):'''通过串口发送数据'''uart.write(str_data)

 6. 主循环中的循迹处理

while True:# ... 其他代码# 巡线模式激活if Flag_track:# 1. 在ROI区域检测黑线roi_blobs_result = find_blobs_in_rois(img)# 2. 计算偏转角和路口状态down_center, state_crossing, deflection_angle = state_deflection_angle(roi_blobs_result)# 3. 定时发送数据(50ms周期)if is_need_send_data:UsartSend(data_format_wrapper(down_center, state_crossing, deflection_angle))

三、关键技术点

  1. 动态阈值调整

    • 使用get_mean_gray()函数实时计算图像平均灰度

    • 基于平均灰度动态调整黑线检测阈值,适应不同光照条件

  2. 多区域检测策略

    • 将图像分为6个关键区域

    • 横向区域(上、中上、中下、下)用于计算偏转角

    • 纵向区域(左、右)用于十字路口检测

  3. 加权中心计算

    • 使用[1, 0, 0, 1]权重配置,重点考虑图像顶部和底部的检测结果

    • 有效减少中间区域的干扰

  4. 十字路口识别

    • 同时检测左右两侧出现黑线

    • 要求黑线位置在图像下方1/3区域内

    • 下方黑线宽度超过140像素作为辅助判断

四、数据处理流程

  1. 主控STM32通过串口发送0x55 0x02 0x91 0x01 ...启动循迹

  2. K210进入循迹模式,开始处理图像

  3. 每50ms计算一次偏转角并通过串口发送

  4. 发送数据格式:[帧头, 长度, 指令, 底部标志, 路口标志, 符号, 偏转值, 帧尾]

  5. STM32根据偏转值调整电机PWM输出,实现方向控制


效果展示

摄像头循迹1.0


http://www.lryc.cn/news/597684.html

相关文章:

  • 第1章第2章笔记
  • 力扣-贪心/动归dp-持续更新中。。。。。。
  • 白盒测试核心覆盖率标准详解文档
  • 【Windows命令手册】Windows中的常用命令,并与 Linux 做比较
  • micro avg、macro avg 和 weighted avg 的区别
  • Oracle19c HINT不生效?
  • 闲庭信步使用图像验证平台加速FPGA的开发:第三十一课——车牌识别的FPGA实现(3)车牌字符分割预处理
  • java设计模式 -【策略模式】
  • 闲庭信步使用图像验证平台加速FPGA的开发:第三十二课——车牌识别的FPGA实现(4)车牌字符的分割定位
  • Android组件化实现方案深度分析
  • 向华为学习——学习华为政务数据安全建设指南【附全文阅读】
  • 【机器学习深度学习】生成式模型的评估与验证
  • QPixmap::scaled参数说明
  • 跟著Qcadoo MES系统学习产品设计001
  • 突发限制下的破局之路:国产之光 Lynx 重构 AI 开发安全壁垒
  • [CH582M入门第十步]蓝牙从机
  • Nestjs框架: 基于Prisma的多租户功能集成和优化
  • 【大模型】Hugging Face常见模型格式详解
  • Linux Debian操作系统、Deepin深度操作系统手动分区方案参考
  • 解决Playwright启动报错:Executable doesn‘t exist at .../chrome-linux/chrome
  • 2025年华为HCIA人工智能认证发展前景如何?客观分析!
  • 459. 重复的子字符串
  • 系统思考:经济反馈的循环
  • [每日随题15] 前缀和 - 拓扑排序 - 树状数组
  • C# 日期与时间 DateTime 结构和TimeSpan 结构
  • 扫地机产品的电池CQC认证遵循哪个标准?
  • socket编程(TCP)
  • 位运算在算法竞赛中的应用(基于C++语言)_位运算优化
  • 代码随想录训练营第二十九天| 77.组合 216.组合总和lll 17.电话号码的字母组合
  • 【LeetCode 热题 100】78. 子集——(解法三)位运算