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

openmv与stm32通信

控制小车视觉循迹使用 OpenMV 往往是不够的。一般使用 OpenMV 对图像进行处理,将处理过后的数据使用串口发送给STM32,使用STM32控制小车行驶。本文主要讲解 OpenMV 模块与 STM32 间的串口通信以及两种循迹方案,分别是划分检测区域和线性回归。

一、OpenMV模块与STM32间的串口通信

1、硬件连接

OpenMV端:UART_RX—P5、UART_TX—P4

STM32端:USART_TX—PA9 、USART_RX—PA10

STM32的TX接OpenMV的RX、STM32的RX接OpenMV的TX。

2、OpenMV 端串口发送数据

uart = UART(3,115200,bits=8, parity=None, stop=1, timeout_char = 1000)FH = bytearray([0x2C,0x12,cx,cy,ch,ci,0x5B])
uart.write(FH)

波特率为115200

0x2C、0x12为帧头,0x5B为桢尾

bytearray([ ])函数:用于把十六进制数据以字节形式存放到字节数组中,以便以数据帧的形式发送出去进行通信。

也可打包为函数形式:

def sending_data(cx,cy,cw,ch):global uart;data = ustruct.pack("<bbhhhhb", 0x2C,                    0x12,                    int(cx),   int(cy),   int(ch),   int(ci),   0x5B)uart.write(data);   #必须要传入一个字节数组sending_data(cx,cy,ch,ci)

3、STM32串口以中断方式接收数据

static u8 Cx=0,Cy=0,Ch=0,Ci=0;
//USART1 全局中断服务函数
void USART1_IRQHandler(void)             
{u8 com_data; u8 i;static u8 RxCounter1=0;static u16 RxBuffer1[10]={0};static u8 RxState = 0;  static u8 RxFlag1 = 0;if( USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)        //接收中断  {USART_ClearITPendingBit(USART1,USART_IT_RXNE);   //清除中断标志com_data = USART_ReceiveData(USART1);if(RxState==0&&com_data==0x2C)  //0x2c帧头{RxState=1;RxBuffer1[RxCounter1++]=com_data;OLED_Refresh();}else if(RxState==1&&com_data==0x12)  //0x12帧头{RxState=2;RxBuffer1[RxCounter1++]=com_data;}else if(RxState==2){RxBuffer1[RxCounter1++]=com_data;if(RxCounter1>=10||com_data == 0x5B)  //RxBuffer1接受满了,接收数据结束{RxState=3; RxFlag1=1;Cx=RxBuffer1[RxCounter1-5];Cy=RxBuffer1[RxCounter1-4];Ch=RxBuffer1[RxCounter1-3];Ci=RxBuffer1[RxCounter1-2];}}else if(RxState==3)     //检测是否接受到结束标志{if(RxBuffer1[RxCounter1-1] == 0x5B){USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);//关闭DTSABLE中断RxFlag1 = 0; RxCounter1 = 0; RxState = 0;USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);}else   //接收错误{RxState = 0;  RxCounter1=0;for(i=0;i<10;i++){RxBuffer1[i]=0x00;      //将存放数据数组清零}}} else   //接收异常{RxState = 0;  RxCounter1=0;for(i=0;i<10;i++){RxBuffer1[i]=0x00;      //将存放数据数组清零}}}   
}

二、视觉循迹方案一:划分检测区域

该方法和一般循迹模块的原理相同。使用五个红框对图像进行分割,对应五路循迹模块的五个输出。

为提高识别精度,将图像二值化后再进行黑线检测。(若要识别其他颜色的线则需要使用常规的设置阈值法)

import pyb, sensor, image, math, time
from pyb import UART
import ustruct
from image import SEARCH_EX, SEARCH_DS
sensor.set_contrast(1)
sensor.set_gainceiling(16)
clock = time.clock()
uart = UART(3,115200,bits=8, parity=None, stop=1, timeout_char = 1000)
# 划分五个区域
roi1 =     [(0, 40, 20, 40),     #  x y w h 分别对应x、y坐标,框的宽度、高度(35, 40, 20, 40),(70, 40, 10, 10),(105, 40, 20, 40),(140, 40, 20, 40)]     sensor.reset() 
sensor.set_pixformat(sensor.RGB565) 
sensor.set_framesize(sensor.QQVGA)
sensor.skip_frames(time=2000) 
sensor.set_auto_whitebal(True)
sensor.set_auto_gain(False) 
sensor.set_vflip(False)
sensor.set_hmirror(False)
clock = time.clock()GRAYSCALE_THRESHOLD = [(20,100)]
low_threshold = (0, 50)  while(True):clock.tick()blob1=Noneblob2=Noneblob4=Noneblob5=Nonecx=cy=cw=i=0img = sensor.snapshot().lens_corr(strength = 1.7 , zoom = 1.0)img.mean(2)binary_img = img.binary(GRAYSCALE_THRESHOLD) # 二值化blob1 = binary_img.find_blobs([low_threshold],roi=roi1[0])blob2 = binary_img.find_blobs([low_threshold],roi=roi1[1])blob3 = binary_img.find_blobs([low_threshold],roi=roi1[2])blob4 = binary_img.find_blobs([low_threshold],roi=roi1[3])blob5 = binary_img.find_blobs([low_threshold],roi=roi1[4])if blob1:cx = 1if blob2:cy = 1if blob3:cw = 1if blob4:ch = 1if blob5:ci = 1FH = bytearray([0x2C,0x12,cx,cy,ch,ci,0x5B])uart.write(FH)for rec in roi1:img.draw_rectangle(rec, color=(255,0,0))#绘制出roi区域

实验效果:

三、视觉循迹方案二:线性回归

将控制线的偏移距离与角度偏差作为PID控制对象,分别计算其控制输出,最后相加。

下面直接附上详细注释版的代码:

THRESHOLD = (21, 0, -77, 5, -110, 127)  
#定义一个阈值元组用于图像二值化处理。这个阈值将用于将图像转换为二进制图像,用于线检测。
import sensor, image, time  
#导入了用于图像处理的sensor、image模块,以及用于时间相关操作的time模块。
from pyb import LED 
from pid import PID #从pid模块中导入了PID类,用于实现PID控制算法。
import time
from pyb import UART #从pyb模块中导入了UART类,用于串口通信。
import math rho_pid = PID(p=0.37, i=0)    #创建一个PID对象rho_pid,用于控制线的偏移距离。
theta_pid = PID(p=0.001, i=0) #创建一个PID对象theta_pid,用于控制线的角度偏差。
#rho 是从图像原点到直线的垂直距离, theta 是直线与垂直轴之间的角度。LED(1).on()
LED(2).on()
LED(3).on()
uart = UART(3,19200)        # 创建一个UART对象uart,用于串口通信,波特率为19200。
sensor.reset()              # 重置图像传感器
sensor.set_vflip(True)      # 设置图像传感器垂直翻转,即上下颠倒。
sensor.set_hmirror(True)    # 设置图像传感器水平镜像,即左右翻转。
sensor.set_pixformat(sensor.RGB565) # 设置图像传感器的像素格式为RGB565。
sensor.set_framesize(sensor.QQQVGA) # 设置图像传感器的帧大小为QQQVGA。
sensor.skip_frames(time = 2000)     # 跳过2000毫秒的图像帧,使传感器稳定。
clock = time.clock()                # 创建一个时间对象clock,用于计时。while(True):clock.tick() #记录当前时间。img = sensor.snapshot().binary([THRESHOLD]) #获取图像的快照,并将其转换为二值图像,根据之前定义的阈值进行二值化处理。line = img.get_regression([(100,100)], robust = True) #在二值图像中检测线段,返回一个线段对象line。#参数[(100,100)]表示检测线段时使用的区域,robust=True表示使用鲁棒回归算法进行线段拟合。if (line): #如果检测到了线段。rho_err = abs(line.rho())-img.width()/2  #计算线段的偏移距离,即线段的rho值减去图像宽度的一半。if line.theta()>90: #如果线段的角度大于90度。theta_err = line.theta()-180 #计算线段的角度偏差,即线段的角度减去180度。else:theta_err = line.theta() # 小于等于90度 直接将线段的角度作为角度偏差。img.draw_line(line.line(), color = 127) # 在图像上绘制检测到的线段。print(rho_err,line.magnitude(),rho_err) # 打印线段的偏移距离、线段的长度和偏移距离。if line.magnitude()>8: # 如果线段的长度大于8。rho_output = rho_pid.get_pid(rho_err,1) #使用PID控制算法计算线段偏移距离的控制输出。theta_output = theta_pid.get_pid(theta_err,1) #使用PID控制算法计算线段角度偏差的控制输出。output = rho_output + theta_output #将线段偏移距离和角度偏差的控制输出相加。if(output<0): #控制输出小于0,STM32不好处理负数,所以要将计算出的负数取绝对值+100#stm32通过判断其值是否大于100来判断其是否为负数。output = abs(output) + 100  #将控制输出取绝对值并加上100。OUTPUT = str(round(output)) #将控制输出四舍五入转换为字符串。因为UART的write()只接受字符串作为参数,不接受数值类型uart.write(OUTPUT) #将控制输出通过串口发送。uart.write('\r\n') #发送回车换行符。print(OUTPUT)   #打印控制输出。pass

pid.py 文件见OpenMV官方源码:https://book.openmv.cc/project/follow-lines.html

实验效果:

相关文章:

openmv与stm32通信

控制小车视觉循迹使用 OpenMV 往往是不够的。一般使用 OpenMV 对图像进行处理&#xff0c;将处理过后的数据使用串口发送给STM32&#xff0c;使用STM32控制小车行驶。本文主要讲解 OpenMV 模块与 STM32 间的串口通信以及两种循迹方案&#xff0c;分别是划分检测区域和线性回归。…...

C++ STL全面解析:六大核心组件之一----序列式容器(vector和List)(STL进阶学习)

目录 序列式容器 Vector vector概述 vector的迭代器 vector的数据结构 vector的构造和内存管理 vector的元素操作 List List概述 List的设计结构 List的迭代器 List的数据结构 List的内存构造 List的元素操作 C标准模板库&#xff08;STL&#xff09;是一组高效的…...

【c数据结构】OJ练习篇 帮你更深层次理解链表!(相交链表、相交链表、环形链表、环形链表之寻找环形入口点、判断链表是否是回文结构、 随机链表的复制)

目录 一. 相交链表 二. 环形链表 三. 环形链表之寻找环形入口点 四. 判断链表是否是回文结构 五. 随机链表的复制 一. 相交链表 最简单粗暴的思路&#xff0c;遍历两个链表&#xff0c;分别寻找是否有相同的对应的结点。 我们对两个链表的每个对应的节点进行判断比较&…...

微软开源GraphRAG的使用教程(最全,非常详细)

GraphRAG的介绍 目前微软已经开源了GraphRAG的完整项目代码。对于某一些LLM的下游任务则可以使用GraphRAG去增强自己业务的RAG的表现。项目给出了两种使用方式&#xff1a; 在打包好的项目状态下运行&#xff0c;可进行尝试使用。在源码基础上运行&#xff0c;适合为了下游任…...

使用Refine构建项目(1)初始化项目

要初始化一个空的Refine项目&#xff0c;你可以使用Refine提供的CLI工具create-refine-app。以下是初始化步骤&#xff1a; 使用npx命令&#xff1a; 在命令行中运行以下命令来创建一个新的Refine项目&#xff1a; npx create-refine-applatest my-refine-project这将引导你通过…...

【Docker】安装及使用

1. 安装Docker Desktop Docker Desktop是官方提供的桌面版Docker客户端&#xff0c;在Mac上使用Docker需要安装这个工具。 访问 Docker官方页面 并下载Docker Desktop for Mac。打开下载的.dmg文件&#xff0c;并拖动Docker图标到应用程序文件夹。安装完成后&#xff0c;打开…...

[大语言模型-论文精读] 以《黑神话:悟空》为研究案例探讨VLMs能否玩动作角色扮演游戏?

1. 论文简介 论文《Can VLMs Play Action Role-Playing Games? Take Black Myth Wukong as a Study Case》是阿里巴巴集团的Peng Chen、Pi Bu、Jun Song和Yuan Gao&#xff0c;在2024.09.19提交到arXiv上的研究论文。 论文: https://arxiv.org/abs/2409.12889代码和数据: h…...

提升动态数据查询效率:应对数据库成为性能瓶颈的优化方案

引言 在现代软件系统中&#xff0c;数据库性能是决定整个系统响应速度和处理能力的关键因素之一。然而&#xff0c;当系统负载增加&#xff0c;特别是在高并发、大数据量场景下&#xff0c;数据库性能往往会成为瓶颈&#xff0c;导致查询响应时间延长&#xff0c;影响用户体验…...

Prometheus+grafana+kafka_exporter监控kafka运行情况

使用Prometheus、Grafana和kafka_exporter来监控Kafka的运行情况是一种常见且有效的方案。以下是详细的步骤和说明&#xff1a; 1. 部署kafka_exporter 步骤&#xff1a; 从GitHub下载kafka_exporter的最新版本&#xff1a;kafka_exporter项目地址&#xff08;注意&#xff…...

在vue中:style 的几种使用方式

在日常开发中:style的使用也是比较常见的&#xff1a; 亲测有效 1.最通用的写法 <p :style"{fontFamily:arr.conFontFamily,color:arr.conFontColor,backgroundColor:arr.conBgColor}">{{con.title}}</p> 2.三元表达式 <a :style"{height:…...

商城小程序后端开发实践中出现的问题及其解决方法

前言 商城小程序后端开发中&#xff0c;开发者可能会面临多种问题。以下是一些常见的问题及其解决方法&#xff1a; 一、性能优化 问题&#xff1a;随着用户量的增加和功能的扩展&#xff0c;商城小程序可能会出现响应速度慢、处理效率低的问题。 解决方法&#xff1a; 对数…...

阿里Arthas-Java诊断工具,基本操作和命令使用

Arthas 是阿里巴巴开源的一款Java诊断工具&#xff0c;深受开发者喜爱。它可以帮助开发者在不需要修改代码的情况下&#xff0c;对运行中的Java程序进行问题诊断和性能分析。 软件具体使用方法 1 启动 Arthas&#xff0c;此时可能会出现好几个jvm的进程号&#xff0c;输入序号…...

Go 1.19.4 路径和目录-Day 15

1. 路径介绍 存储设备保存着数据&#xff0c;但是得有一种方便的模式让用户可以定位资源位置&#xff0c;操作系统采用一种路径字符 串的表达方式&#xff0c;这是一棵倒置的层级目录树&#xff0c;从根开始。 相对路径&#xff1a;不是以根目录开始的路径&#xff0c;例如 a/b…...

jEasyUI 创建标签页

jEasyUI 创建标签页 jEasyUI&#xff08;jQuery EasyUI&#xff09;是一个基于jQuery的框架&#xff0c;它为Web应用程序提供了丰富的用户界面组件。标签页&#xff08;Tabs&#xff09;是jEasyUI中的一个常用组件&#xff0c;用于在一个页面内组织多个面板&#xff0c;用户可…...

鸿蒙HarmonyOS开发:一次开发,多端部署(界面级)天气应用案例

文章目录 一、布局简介二、典型布局场景三、侧边栏 SideBarContainer1、子组件2、属性3、事件 四、案例 天气应用1、UX设计2、实现分析3、主页整体实现4、具体代码 五、运行效果 一、布局简介 布局可以分为自适应布局和响应式布局&#xff0c;二者的介绍如下表所示。 名称简介…...

使用 Python 模拟光的折射,反射,和全反射

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

大厂太卷了!又一款国产AI视频工具上线了,免费无限使用!(附提示词宝典)

大家好&#xff0c;我是程序员X小鹿&#xff0c;前互联网大厂程序员&#xff0c;自由职业2年&#xff0c;也一名 AIGC 爱好者&#xff0c;持续分享更多前沿的「AI 工具」和「AI副业玩法」&#xff0c;欢迎一起交流~ 记得去年刚开始分享 AI 视频工具的时候&#xff0c;介绍的大多…...

vue3扩展echart封装为组件库-快速复用

ECharts ECharts&#xff0c;全称Enterprise Charts&#xff0c;是一款由百度团队开发并开源&#xff0c;后捐赠给Apache基金会的纯JavaScript图表库。它提供了直观、生动、可交互、可个性化定制的数据可视化图表&#xff0c;广泛应用于数据分析、商业智能、网页开发等领域。以…...

随机掉落的项目足迹:Vue3 + wangEditor5富文本编辑器——toolbar.getConfig() 查看工具栏的默认配置

问题引入 小提示&#xff1a;问题引入是一个讲故事的废话环节&#xff0c;各位小伙伴可以直接跳到第二大点&#xff1a;问题解决 我的项目不需要在富文本编辑器中引入添加代码块的功能&#xff0c;于是我寻思在工具栏上把操作代码的菜单删一删 于是我来到官网文档工具栏配置 …...

更新 Git 软件

更新 Git 软件本身是指将你当前安装的 Git 版本升级到最新版本。不同的操作系统有不同的更新方法。以下是针对 Windows、macOS 和 Linux 的 Git 更新步骤&#xff1a; Windows 检查当前版本&#xff1a; git --version访问官网下载最新版本&#xff1a; 访问 Git 官方网站 (ht…...

Keil根据map文件确定单片机代码存储占用flash情况

可以从map文件中查看得知&#xff0c;代码占用内存情况大概为35KB,而在在线仿真时&#xff0c;可以看到在flash的0x8008F64地址前均有数据&#xff0c;是代码数据&#xff0c;8F64(HEX)36708(DEC),36708/102335,刚好35。因此&#xff0c;要想操作读写flash&#xff0c;必须在不…...

ByteTrack多目标跟踪流程图

ByteTrack多目标跟踪流程图 点个赞吧&#xff0c;谢谢。...

什么是L2范数

定义&#xff1a; 在数学和计算中&#xff0c;L2 范数是一种用于测量向量长度或大小的方法&#xff0c;也被称为欧几里得范数。对于一个 n 维向量 x ( x 1 , x 2 , … , x n ) \mathbf{x} (x_1, x_2, \dots, x_n) x(x1​,x2​,…,xn​)&#xff0c;其 L2 范数定义为&#x…...

Scrapy爬虫IP代理池:提升爬取效率与稳定性

在互联网时代&#xff0c;数据就是新的黄金。无论是企业还是个人&#xff0c;数据的获取和分析能力都显得尤为重要。而在众多数据获取手段中&#xff0c;使用爬虫技术无疑是一种高效且广泛应用的方法。然而&#xff0c;爬虫在实际操作中常常会遇到IP被封禁的问题。为了解决这个…...

信息技术(IT)行业的发展

近年来&#xff0c;信息技术&#xff08;IT&#xff09;行业的发展呈现出前所未有的活力和潜力。随着全球数字化转型的加速&#xff0c;IT行业正逐步成为推动社会经济发展的重要引擎。无论是互联网、大数据、人工智能&#xff0c;还是云计算、物联网&#xff0c;这些新兴技术都…...

C++primer第十一章使用类(矢量随机游走实例)

操作符重载 操作符重载(operator overoading)是一种形式的 C多态。 第8章介绍了C是如何使用户能够定义多个名称相同但特征标(参数列表)不同的函数的。这被称为函数重载(function overloading)或函数多态(functional polymorphism)&#xff0c;旨在让您能够用同名的函数来完成…...

服务器为什么会受到网络攻击?

随着科技的 快速发展&#xff0c;企业也开展了越来越多的线上业务&#xff0c;但同时也遭受到各种各样的网络攻击&#xff0c;那服务器为什么会受到网络攻击呢&#xff1f;下面就让小编带领大家一起来了解一下吧&#xff01; 首先企业中服务器被攻击的原因有很多&#xff0c;主…...

IDA Pro基本使用

IDA Pro基本使用 1.DllMain的地址是什么? 打开默认在的位置1000D02E就是DllMain地址 按空格键可以看到图形化界面选择options、general勾选对应的选项在图像化也能看到 2.使用Imports 窗口并浏览到 gethostbyname&#xff0c;导入函数定位到什么地址? 这里可以打开Impo…...

Day.js时间插件的安装引用与常用方法大全

&#x1f680; 个人简介&#xff1a;某大型国企资深软件研发工程师&#xff0c;信息系统项目管理师、CSDN优质创作者、阿里云专家博主&#xff0c;华为云云享专家&#xff0c;分享前端后端相关技术与工作常见问题~ &#x1f49f; 作 者&#xff1a;码喽的自我修养&#x1f9…...

aws 容器镜像仓库操作

aws 容器镜像仓库产品叫ECR&#xff0c;官方文档参考&#xff1a;Amazon Elastic Container Registry。 1&#xff09;账号认证 # 配置aws命令 $ aws configure set aws_access_key_id ${ak} $ aws configure set aws_secret_access_key ${sk} 2&#xff09;镜像仓库登陆 #…...