简单实现物体追踪
- OpenMV简介
- 材料准备
- OpenMV实现脱机运行
- 1.将OpenMV与电脑连接
- 2.使用IDE把色块追踪代码烧录到OpenMV
- 单片机准备好串口通信
OpenMV简介
open_mv是一款很方便的人工智能摄像头,自带很多ai算法,有很多应用的场景,今天我来教大家如何使用open_mv实现物体追踪、色块识别,并且把识别到的物品坐标信息通过串口传输给单片机等处理器。
如果你还没用过OpenMV,建议先简单入门IDE软件,然后进入到我们的主题:
材料准备
- OpenMV摄像头一个(不限版本)
- sd卡一张(内存不限,实在没有也可以不用)
- 单片机一块(能用串口功能的都行)
- 安卓线一根(能传输数据的)
OpenMV实现脱机运行
1.将OpenMV与电脑连接
如图所示,将OpenMV插上sd卡后,将usb口与电脑端相连,这时候电脑就会发出“咚咚”的声音,相当于是把U盘插入了电脑,这时候我们就可以打开这个U盘查看sd卡里面有什么文件,这里我建议把其他文件删除,剩下一个空的sd卡。如果是没插sd卡的话,模块自带的也有一个76kb的储存空间。
2.使用IDE把色块追踪代码烧录到OpenMV
首先点击左下角的两个按键使电脑成功连接OpenMV,这个时候软件左上角就可以实时显示拍下的画面
再点击左上角随便打开一个代码
然后把下面的代码复制过去
# Blob Detection and uart transport
import sensor, image, time
from pyb import UART
import json
# For color tracking to work really well you should ideally be in a very, very,
# very, controlled enviroment where the lighting is constant...
yellow_threshold = (65, 100, -10, 6, 24, 51)
# 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() # Initialize the camera sensor.
sensor.set_pixformat(sensor.RGB565) # use RGB565.
sensor.set_framesize(sensor.QQVGA) # use QQVGA for speed.
sensor.skip_frames(10) # Let new settings take affect.
sensor.set_auto_whitebal(False) # turn this off.
clock = time.clock() # Tracks FPS.
uart = UART(3, 115200)
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()) #方式1
#output_str=json.dumps([max_blob.cx(),max_blob.cy()]) #方式2
print('you send:',output_str)
uart.write(output_str+'\r\n')
else:
print('not found!')
我这段代码是从官方找到的最精简的代码,完全没有其他什么乱七八糟的函数,只传输面积最大的色块的x,y中心坐标,方便你使用它来传输物体坐标位置,实现追踪。找到上面yellow_threshold =(,,,,) 赋值的语句,意思是识别黄色色块,你要根据你的物体的颜色对这个语句进行赋值,可以百度一下你所需要的颜色的阈值,然后复制过去就可以了,最后保存一下。
下一步就是烧录程序了
点击左上角工具->save open…->点击弹出窗口的Yes
这时候,你再把OpenMV的文件盘打开,就会发现里面多了几个文件,其中有一个main.py文件就说烧录好的可执行文件,OpenMV脱机运行的时候会从该文件开始执行代码,并且把色块中心位置的坐标通过串口发送出去啦!
单片机准备好串口通信
OpenMV可以发送数据了,这时候就需要单片机接收数据了。首先编写一个串口功能初始化代码
void uart4_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //串口端口配置结构体变量
USART_InitTypeDef USART_InitStructure;//串口参数配置结构体变量
NVIC_InitTypeDef NVIC_InitStructure;//串口中断配置结构体变量
//使能 UART4 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); //打开串口复用时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //打开PC端口时钟
//UART4_TX GPIOC.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PC.10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//设定IO口的输出速度为50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC.10
//UART4_RX GPIOC.11初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PC.11
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = 115200;//串口波特率为115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式使能
USART_Init(UART4, &USART_InitStructure); //初始化串口4
USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(UART4, ENABLE); //使能串口4
//如下语句解决第1个字节无法正确发送出去的问题
USART_ClearFlag(UART4, USART_FLAG_TC); //清串口4发送标志
}
然后通过编写串口中断实现接收数据
void UART4_IRQHandler(void) //串口4全局中断服务函数
{
u8 com_data;
//接收中断
if( USART_GetITStatus(UART4,USART_IT_RXNE) )
{
USART_ClearITPendingBit(UART4,USART_IT_RXNE);//清除中断标志
com_data = UART4->DR;
Openmv_Receive_Data(com_data);//openmv数据处理函数
}
}
void Openmv_Receive_Data(int16_t data)//接收Openmv传过来的数据
{
static u8 openmv[18]; //存取数据
static u8 state = 0;
static u8 bit_number=0;
if(state==0&&data==0x2C)
{
state=1;
openmv[bit_number++]=data;
}
else if(state==1&&data==18)
{
state=2;
openmv[bit_number++]=data;
}
else if(state==2)
{
openmv[bit_number++]=data;
if(bit_number>=17)
{
state=3;
}
}
else if(state==3) //检测是否接受到结束标志
{
if(data == 0x5B)
{
state = 0;
openmv[bit_number++]=data;
}
else if(data != 0x5B)
{
state = 0;
for(i=0;i<18;i++)
{
openmv[i]=0x00;
}
}
}
else
{
state = 0;
bit_number=0;
for(i=0;i<18;i++)
{
openmv[i]=0x00;
}
}
}
这时候就大功告成喇!你就可以在单片机中利用传输过来的数据进行分析利用,可以做一个追小球的车子或者做板球系统调pid等等。
补充一个字符串转数字函数,方便大家串口接收到openmv数据后的使用
if(USART3_RX_STA&0x8000)
{
u8 x=0,y=0,z=0;
len=USART3_RX_STA&0x3fff;
for(t =0;t<len;t++)
{
USART3->DR=USART3_RX_BUF[t];
while((USART3->SR&0X40)==0);
if(USART3_RX_BUF[t]=='[')x=1,y=0;
if(USART3_RX_BUF[t]==','){x=0,y=1;xx[t-1]='\0';}
if(USART3_RX_BUF[t]==']'){yy[z]='\0';x=0,y=0,z=0;};
if(x==1&&USART3_RX_BUF[t]!='[')xx[t-1] = USART3_RX_BUF[t];
if(y==1&&USART3_RX_BUF[t]!=','){yy[z] = USART3_RX_BUF[t]; z++;};
}
for(t=0;t<2;t++)
{
USART3->DR=USART3LAST[t];
while((USART3->SR&0X40)==0);//µÈ´ý·¢ËͽáÊø
}
Xt=atoi(&xx[0]);
Yt=atoi(&yy[0]);
OLED_ShowNum(0,52,Yt,3,12);
OLED_ShowNum(64,52,Xt,3,12);
stop=0;
USART3_RX_STA=0;
}