一直有想要写些东西的想法正好最近比较闲以及大创项目和电赛备赛需要用到OpenMV所以就记录一下学习过程。因为小白第一次写文章有什么错误希望大家包含在评论区指正。
2.1、Openmv端
这里OpenMV端仅作为数据的发送端,所以只需要共地,以及OpenMV的TX(P4)与开发板的RX端连接即可。
2.2、STM32端
将开发板连接STM芯片RX端与转串口TX端的跳帽取下,再将OpenMV的TX端(P4)与STM的RX连接。如果使用USB转TTL则将TTL的RX端与STM的TX端连接,STM的RX端与OpenMV的TX端(P4)连接,然后共地,这样就可以在串口调试助手中查看数据的传输情况了。
3.1、OpenMV端
# Blob Detection and uart transport
import sensor, image, time, math, pyb
from pyb import UART
import json
import ustruct
# For color tracking to work really well you should ideally be in a very, very,
# very, controlled enviroment where the lighting is constant...A
yellow_threshold = (8, 22, -60, -3, 127, -128)
# You may need to tweak the above settings for tracking green things...
# Select an area in the Framebuffer to copy the color settings.
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA) #设置图像大小QVGA大小为320*240,所以中心坐标应该是(160,120)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False) # must be turned off for color tracking
sensor.set_auto_whitebal(False) # must be turned off for color tracking
red_threshold_01=(66, 31, -58, -24, 127, -128)
clock = time.clock()
uart = UART(3, 115200)
uart.init(115200, bits=8, parity=None, stop=1) # OpenMV端初始化与STM端配置一样即可。
#**************************传输数据的函数************************************
def sending_data(cx,cy):
global uart;
#frame=[0x2C,18,cx%0xff,int(cx/0xff),cy%0xff,int(cy/0xff),0x5B];
#data = bytearray(frame)
data = ustruct.pack(", #格式为俩个字符俩个短整型(2字节)
0x2C, #帧头1
0x12, #帧头2
int(cx), # up sample by 4 #数据1
int(cy), # up sample by 4 #数据2
0x5B)
uart.write(data); #必须要传入一字节的数组,这个函数似乎不能发送单个字节,必须得一次发送多个字节
#**************************************************************************
#**************************找到最大的色块函数*******************************#
def find_max(blobs):
max_size=0
for blob in blobs:
if blob.pixels() > max_size:
max_blob=blob
max_size = blob.pixels()
return max_blob
#**************************************************************************#
while(True):
img = sensor.snapshot() # Take a picture and return the image.
blobs = img.find_blobs([yellow_threshold])
if blobs:
max_blob=find_max(blobs)
#print('sum :', len(blobs))
img.draw_rectangle(max_blob.rect())
img.draw_cross(max_blob.cx(), max_blob.cy())
output_str="[%d,%d]" % (max_blob.cx(),max_blob.cy())
print('you send:',output_str) #打印色块中心点坐标到串行终端便于数据核验
sending_data(max_blob.cx(),max_blob.cy())#发送色块框的中心点坐标
#FH = bytearray([0x2C,0x12,blobs[0].cx(),blobs[0].cy(),0x5B])
#uart.write(FH)
else:
print('not found!')
sending_data(567,789)#如果没有找到符合条件的色块,那么发送一个不可能出现的坐标
#FH = bytearray([0x2C,0x12,0x77,0x55,0x5B])
#uart.write(FH)
颜色识别:
这里只需要使用阈值编辑器,将想要识别的颜色调节到纯白色如下图所示,然后将下面的LAB阈值填入 red_threshold_01=() 即可。
获取中心坐标:
blob.rect() 返回这个色块的外框——矩形元组(x, y, w, h),可以直接在 image.draw_rectangle中使用。
blob.x() 返回色块的外框的x坐标(int),也可以通过blob[0]来获取。
blob.y() 返回色块的外框的y坐标(int),也可以通过blob[1]来获取。
blob.w() 返回色块的外框的宽度w(int),也可以通过blob[2]来获取。
blob.h() 返回色块的外框的高度h(int),也可以通过blob[3]来获取。
blob.pixels() 返回色块的像素数量(int),也可以通过blob[4]来获取。
blob.cx() 返回色块的外框的中心x坐标(int),也可以通过blob[5]来获取。
blob.cy() 返回色块的外框的中心y坐标(int),也可以通过blob[6]来获取。
3.2、STM32端
void DEBUG_USART_IRQHandler(void)
{
uint8_t com_data;
uint8_t i;
static uint8_t RxCounter1=0;
static uint16_t RxBuffer1[7]={0};
static uint8_t RxState = 0;
// static uint8_t RxFlag1 = 0;
if( USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) //接收中断
{
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志
com_data = USART_ReceiveData(DEBUG_USARTx );
if(RxState==0&&com_data==0x2C) //0x2c帧头
{
RxState=1;
RxBuffer1[RxCounter1++]=com_data; //RxBuffer1[0]==0x2c RxCounter1==1
}
else if(RxState==1&&com_data==0x12) //0x12帧头
{
RxState=2;
RxBuffer1[RxCounter1++]=com_data; //RxBuffer1[0]==0x12 RxCounter1==2
}
else if(RxState==2) //开始接收有效数据
{
RxBuffer1[RxCounter1++]=com_data; //全部接收完,RxCounter1==7
if(RxCounter1>=7||com_data == 0x5B) //RxBuffer1接受满了,接收数据结束
{
RxState=3;
// RxFlag1=1;
Cx=(RxBuffer1[RxCounter1-4]<<8)+(RxBuffer1[RxCounter1-5]); //RxBuffer1[2]是openmv发送的第一个数据的低八位,RxBuffer1[3]是openmv发送的第一个数据的高八位
Cy=(RxBuffer1[RxCounter1-2]<<8)+(RxBuffer1[RxCounter1-3]); //RxBuffer1[4]是openmv发送的第二个数据的低八位,RxBuffer1[5]是openmv发送的第二个数据的高八位
printf("X=%d,Y=%d\n",Cx,Cy);
delay_ms(300); //延时防止大量数据造成上位机卡顿
}
}
else if(RxState==3) //检测是否接受到结束标志
{
if(RxBuffer1[RxCounter1-1] == 0x5B)
{
USART_ITConfig(DEBUG_USARTx,USART_IT_RXNE,DISABLE);//关闭DTSABLE中断
// if(RxFlag1)
// {
//
// OLED_ShowNum(0,0,Cx,3,1,2);
// OLED_ShowNum(0,2,Cy,3,1,2);
//
// }
// RxFlag1 = 0;
RxCounter1 = 0;
RxState = 0;
USART_ITConfig(DEBUG_USARTx,USART_IT_RXNE,ENABLE);
}
else //接收错误
{
RxState = 0;
RxCounter1=0;
for(i=0;i<7;i++)
{
RxBuffer1[i]=0xff; //将存放数据数组清零
}
}
}
else //接收异常
{
RxState = 0;
RxCounter1=0;
for(i=0;i<7;i++)
{
RxBuffer1[i]=0xff; //将存放数据数组清零
}
}
}
}
看到这里或许会存在疑问,为什么我们发送五个数据却要定义一个七位的数据的接收数组呢?在OpenMV端的发送函数里面有一个"
左边是OpenMV IDE串行终端的数据,右边是调试助手中的数据。可以发现虽然延时导致部分数据没有被打印出来但是调试助手中的数据全部来自串行终端,所以代码正确。
代码部分参考了这篇文章写的很好很详细。完整的工程代码可以去Gitee下载。