基于OpenMV 循迹小车 + WIFI无线图传 您所在的位置:网站首页 循迹小车的原理及方法 基于OpenMV 循迹小车 + WIFI无线图传

基于OpenMV 循迹小车 + WIFI无线图传

2023-06-28 13:29| 来源: 网络整理| 查看: 265

文章目录 一、工程环境二、OpenMV1. 色块选定2. 色块识别3. 串口通信4. WiFi无线图传5. 代码汇总 三、MSP430四、视频演示

一、工程环境

1. 软件

OpenMV IDECode Composer StudioMicrosoft Edge

2. 硬件

MSP430F5529OpenMV4 H7及其 WiFi拓展板视觉云台旋转编码器、oled显示屏等等iPone

在这里插入图片描述

二、OpenMV

循迹其本质为寻找色块,即通过色块的位置判定小车走向。

1. 色块选定

可在OpenMV IDE中选中帧缓冲区的图片进行阈值选择,将你所选择的色块瞄成白色,将阈值剔出来作色块识别。

具体操作如下:

在这里插入图片描述

在这里插入图片描述

2. 色块识别

色块识别实例代码可在OpenMV官网查看,以下我已贴出以供参考: 以下参考资料来源于OpenMV官网

# Single Color RGB565 Blob Tracking Example # # This example shows off single color RGB565 tracking using the OpenMV Cam. import sensor, image, time, math threshold_index = 0 # 0 for red, 1 for green, 2 for blue # Color Tracking Thresholds (L Min, L Max, A Min, A Max, B Min, B Max) # The below thresholds track in general red/green/blue things. You may wish to tune them... thresholds = [(30, 100, 15, 127, 15, 127), # generic_red_thresholds (30, 100, -64, -8, -32, 32), # generic_green_thresholds (0, 30, 0, 64, -128, 0)] # generic_blue_thresholds sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) 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 clock = time.clock() # Only blobs that with more pixels than "pixel_threshold" and more area than "area_threshold" are # returned by "find_blobs" below. Change "pixels_threshold" and "area_threshold" if you change the # camera resolution. "merge=True" merges all overlapping blobs in the image. while(True): clock.tick() img = sensor.snapshot() for blob in img.find_blobs([thresholds[threshold_index]], pixels_threshold=200, area_threshold=200, merge=True): # These values depend on the blob not being circular - otherwise they will be shaky. if blob.elongation() > 0.5: img.draw_edges(blob.min_corners(), color=(255,0,0)) img.draw_line(blob.major_axis_line(), color=(0,255,0)) img.draw_line(blob.minor_axis_line(), color=(0,0,255)) # These values are stable all the time. img.draw_rectangle(blob.rect()) img.draw_cross(blob.cx(), blob.cy()) # Note - the blob rotation is unique to 0-180 only. img.draw_keypoints([(blob.cx(), blob.cy(), int(math.degrees(blob.rotation())))], size=20) print(clock.fps())

即需先找到色块位于循迹信号线中心的位置,可通过查看色块中心点的坐标得到。

for blob in img.find_blobs([thresholds[threshold_index]], 即blobs是一个列表 find_blobs对象返回的是多个blob的列表。(注意区分blobs和blob,这只是一个名字,用来区分多个色块,和一个色块)。

列表类似与C语言的数组,一个blobs列表里包含很多blob对象,blobs对象就是色块,每个blobs对象包含一个色块的信息。

blob色块对象 blob有多个方法:

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]来获取。

blob.rotation() 返回色块的旋转角度(单位为弧度)(float)。如果色块类似一个铅笔,那么这个值为0~180°。如果色块是一个圆,那么这个值是无用的。如果色块完全没有对称性,那么你会得到0 ~ 360°,也可以通过blob[7]来获取。

blob.code() 返回一个16bit数字,每一个bit会对应每一个阈值。举个例子:

blobs = img.find_blobs([red, blue, yellow], merge=True)

如果这个色块是红色,那么它的code就是0001,如果是蓝色,那么它的code就是0010。注意:一个blob可能是合并的,如果是红色和蓝色的blob,那么这个blob就是0011。这个功能可以用于查找颜色代码。也可以通过blob[8]来获取。

blob.count() 如果merge=True,那么就会有多个blob被合并到一个blob,这个函数返回的就是这个的数量。如果merge=False,那么返回值总是1。也可以通过blob[9]来获取。

blob.area() 返回色块的外框的面积。应该等于(w * h)

blob.density() 返回色块的密度。这等于色块的像素数除以外框的区域。如果密度较低,那么说明目标锁定的不是很好。 比如,识别一个红色的圆,返回的blob.pixels()是目标圆的像素点数,blob.area()是圆的外接正方形的面积。

3. 串口通信

相同OpenMV官网也已提供示例代码,我贴出如下以供参考:

import sensor, image, time import json from pyb import UART # 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 = ( 46, 100, -68, 72, 58, 92) # 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) while(True): clock.tick() # Track elapsed milliseconds between snapshots(). img = sensor.snapshot() # Take a picture and return the image. blobs = img.find_blobs([yellow_threshold]) if blobs: #print('sum : %d'% len(blobs)) data=[] for b in blobs: # Draw a rect around the blob. img.draw_rectangle(b.rect()) # rect img.draw_cross(b.cx(), b.cy()) # cx, cy data.append((b.cx(),b.cy())) #{(1,22),(-3,33),(22222,0),(9999,12),(0,0)} data_out = json.dumps(set(data)) uart.write(data_out +'\n') print('you send:',data_out) else: print("not found!")

所以,需将以上俩个代码作个简单合并,即可将设别到色块的位置通过串口发送给单片机,单片机及时做出回应。

4. WiFi无线图传

此功能需购买WiFi拓展版,且官方也已给出示例代码,我贴出如下以供参考:

# MJPEG Streaming AP. # # 这个例子展示了如何在AccessPoint模式下进行MJPEG流式传输。 # Android上的Chrome,Firefox和MJpegViewer App已经过测试。 # 连接到OPENMV_AP并使用此URL:http://192.168.1.1:8080查看流。 import sensor, image, time, network, usocket, sys SSID ='OPENMV_AP' # Network SSID KEY ='1234567890' # wifi密码(必须为10字符) HOST = '' # 使用第一个可用的端口 PORT = 8080 # 任意非特权端口 # 重置传感器 sensor.reset() # 设置传感器设置 sensor.set_contrast(1) sensor.set_brightness(1) sensor.set_saturation(1) sensor.set_gainceiling(16) sensor.set_framesize(sensor.QQVGA) sensor.set_pixformat(sensor.GRAYSCALE) # 在AP模式下启动wlan模块。 wlan = network.WINC(mode=network.WINC.MODE_AP) wlan.start_ap(SSID, key=KEY, security=wlan.WEP, channel=2) #您可以阻止等待客户端连接 #print(wlan.wait_for_sta(10000)) def start_streaming(s): print ('Waiting for connections..') client, addr = s.accept() # 将客户端套接字超时设置为2秒 client.settimeout(2.0) print ('Connected to ' + addr[0] + ':' + str(addr[1])) # 从客户端读取请求 data = client.recv(1024) # 应该在这里解析客户端请求 # 发送多部分head client.send("HTTP/1.1 200 OK\r\n" \ "Server: OpenMV\r\n" \ "Content-Type: multipart/x-mixed-replace;boundary=openmv\r\n" \ "Cache-Control: no-cache\r\n" \ "Pragma: no-cache\r\n\r\n") # FPS clock clock = time.clock() # 开始流媒体图像 #注:禁用IDE预览以增加流式FPS。 while (True): clock.tick() # 跟踪snapshots()之间经过的毫秒数。 frame = sensor.snapshot() cframe = frame.compressed(quality=35) header = "\r\n--openmv\r\n" \ "Content-Type: image/jpeg\r\n"\ "Content-Length:"+str(cframe.size())+"\r\n\r\n" client.send(header) client.send(cframe) print(clock.fps()) while (True): # 创建服务器套接字 s = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM) try: # Bind and listen s.bind([HOST, PORT]) s.listen(5) # 设置服务器套接字超时 # 注意:由于WINC FW bug,如果客户端断开连接,服务器套接字必须 # 关闭并重新打开。在这里使用超时关闭并重新创建套接字。 s.settimeout(3) start_streaming(s) except OSError as e: s.close() print("socket error: ", e) #sys.print_exception(e)

此功能可将摄像头拍到的图片以图片流的方式传输到网址上,用户在PC或移动端都可自由查看。

5. 代码汇总

以下贴出我汇总后的示例代码:

# Single Color RGB565 Blob Tracking Example # # This example shows off single color RGB565 tracking using the OpenMV Cam. import sensor, image, time, math, pyb, json from image import SEARCH_EX, SEARCH_DS from pyb import UART uart = UART(3, 115200) threshold_index = 0 # 0 for red, 1 for green, 2 for blue # Color Tracking Thresholds (L Min, L Max, A Min, A Max, B Min, B Max)uo # The below thresholds track in general red/green/blue things. You may wish to tune them... thresholds = [(42, 0, -128, 127, -90, 127), # 黑 色块阈值选择 (70, 20, 14, 127, -128, 127), # 红 (0, 30, 0, 64, -128, 0)] sensor.reset() #摄像头重置 sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) # 设置分辨率大小 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 clock = time.clock() ROI=(75,66,184,121) #感应区域设置 # Only blobs that with more pixels than "pixel_threshold" and more area than "area_threshold" are # returned by "find_blobs" below. Change "pixels_threshold" and "area_threshold" if you change the # camera resolution. "merge=True" merges all overlapping blobs in the image. while(True): clock.tick() img = sensor.snapshot() #截取摄像头的一个图像 for blob in img.find_blobs([thresholds[0]], roi=ROI, x_stride=10, y_stride=5,pixels_threshold=10, area_threshold=10, merge=True): #模板匹配函数 img.draw_rectangle(blob.rect()) #给识别出来的色块画矩形 img.draw_rectangle(ROI) #给感应区画矩形 print('x='+str(blob.cx())+' y='+str(blob.cy())) x=blob.cx() #print(blob.area()) if x>140 and x=100 and x=60 and x=200 and x250 and x switch(flag) { case 1: SetPwm_Init(24,1000,400); SetPwm_Init(25,1000,400); UCA0IE |= UCRXIE; break; case 2: SetPwm_Init(24,1000,200); SetPwm_Init(25,1000,500); UCA0IE |= UCRXIE; break; case 3: SetPwm_Init(24,1000,100); SetPwm_Init(25,1000,600); UCA0IE |= UCRXIE; break; case 4: SetPwm_Init(24,1000,500); SetPwm_Init(25,1000,200); UCA0IE |= UCRXIE; break; case 5: SetPwm_Init(24,1000,600); SetPwm_Init(25,1000,100); UCA0IE |= UCRXIE; break; } } } /* -------------- 串口中断(OpenMV通信) ----------------*/ // Echo back RXed character, confirm TX buffer is ready first,发送数据之前确定发送缓存准备好 #pragma vector=USCI_A0_VECTOR __interrupt void USCI_A0_ISR(void) { switch(__even_in_range(UCA0IV,4)) { case 0: //无中断 break; // Vector 0 - no interrupt case 2: // Vector 2 - RXIFG 接受中断 while (!(UCA0IFG&UCTXIFG)); // USCI_A1 TX buffer ready? UCTXIFG(USCI Transmit Interrupt Flag) if(UCA0RXBUF=='1'){ flag=1; } else if(UCA0RXBUF=='2'){ flag=2; } else if(UCA0RXBUF=='3'){ flag=3; } else if(UCA0RXBUF=='4'){ flag=4; } else if(UCA0RXBUF=='5'){ flag=5; } OLED_ShowNum(65,24,flag,1,16,1); OLED_Refresh(); UCA0IE &=~ UCRXIE; break; case 4: break; // Vector 4 - TXIFG 发送中断 default: break; } } 四、视频演示

OpenMV视觉循迹+WiFi无线图传



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有