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

news2024/7/6 19:47:52

文章目录

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


一、工程环境

1. 软件

  • OpenMV IDE
  • Code Composer Studio
  • Microsoft Edge

2. 硬件

  • MSP430F5529
  • OpenMV4 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<200:
            uart.write("1")
            print("1")
        elif x>=100 and x<=140:
            uart.write("2")
            print("2")
        elif x>=60 and x<100:
            uart.write("3")
            print("3")
        elif x>=200 and x<=250:
            uart.write("4")
            print("4")
        elif x>250 and x<290:
            uart.write("5")
            print("5")


        # 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())

测得车子位于信号上的色块x坐标为140~200,当然这只是我测得在我这的结果,具体还需自测。当x坐标减小时,即为偏向左,反偏右,此x值为距离左上角的x轴位置,即根据x坐标点的不同位置返回不同数值。

最后,将写好的代码保存到OpenMv Cam中,即为模块上电后启动该程序。
在这里插入图片描述

三、MSP430

此小节即为小车接受到OpenMV打过来的数据,作出相应动作,小车循迹这块我已经介绍许多遍了,相信大家也无需我多言,直接上代码

int main(void)
{
	WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer
	LED_Init();
	Anjian_Init();
	motor_gpio_init();
	OLED_Init();
    OLED_ShowString(10,7,"  OpenMV_Car",16,1);
	OLED_Refresh();
	openmv_init();
	InitMPU6050();
	TIMER_B0_Init(5);
	head();
	while(1)
	{


	    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无线图传

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/666481.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国际原油期货怎么开户?国际原油期货开户流程是什么?

随着国际原油期货交易的大众化&#xff0c;国际原油期货交易的入市门槛也在逐渐降低&#xff0c;使越来越多的国际原油期货交易爱好者能够参与到这个交易市场中。很多朋友可能对国际原油期货开户有很多的疑问&#xff0c;是不是很繁琐&#xff1f;需不需要很多的证明文件&#…

论文解读 | 皮质电图系统与软机器人致动器的完美结合

原创 | 文 BFT机器人 01 研究内容 主要研究内容是关于一种电皮层图谱系统的部署&#xff0c;该系统使用软体机器人致动器。论文详细介绍了该系统的制造和实验方法&#xff0c;并提供了相关的图表和参考文献。该系统的设计旨在提高电皮层图谱系统的灵活性和可植入性&#xff0c…

vite+vue3+cesium环境搭建

1.创建一个Vite项目 npm create vitelatest 2.安装cesium插件&#xff1a;vite-plugin-cesium npm i cesium vite-plugin-cesium vite -D 3、配置vite.config.js import cesium from vite-plugin-cesium; export default defineConfig({ plugins: [vue(),cesium()] }) 4、清空…

软件测试技能,JMeter压力测试教程(二)

目录 前言 一、案例场景 二、登录请求 三、Json 提取器 四、关联请求 五、遇到的坑 前言 现在很多接口的登录是返回一个json数据&#xff0c;token值在返回的json里面&#xff0c;在jmeter里面也可以直接提取json里面的值 上一个接口返回的token作为下个接口的入参 一、…

Python基础(12)——Python字符串详解

Python基础&#xff08;12&#xff09;——Python字符串详解 文章目录 Python基础&#xff08;12&#xff09;——Python字符串详解课程&#xff1a;字符串目标一. 认识字符串1.1 字符串特征1.2 字符串输出1.3 字符串输入 二、下标2.1 快速体验 三、切片3.1 语法3.2 体验 四、常…

Generative Adversarial Network(生成对抗网络)

目录 Generative Adversarial Network&#xff08;生成对抗网络&#xff09; Basic Idea of GAN GAN as structured learning Can Generator learn by itself Can Discriminator generate Theory behind GAN Conditional GAN Generative Adversarial Network&#xff08;…

SpringBoot + Vue前后端分离项目实战 || 一:Vue前端设计

文章目录 环境配置开发工具下载Vue前端模板前端项目启动前端说明及修改修改导航栏自定义菜单与子菜单增加导航标签功能 前端数据格式 B站视频讲解&#xff1a;2023全网最简单但实用的SpringBootVue前后端分离项目实战 不想看视频可浏览此文章笔记&#xff0c;比较详细 环境配置…

民族工业领军企业:大族激光全流程数字化增长路径揭秘

1.关于大族激光 大族激光科技产业集团&#xff08;简称“大族激光”&#xff0c;股票代码 002008&#xff09;于 1996 年创立、2004 年上市&#xff0c;是亚洲最大、世界排名前三的工业激光加工及自动化整体解决方案服务商&#xff0c;专业从事工业激光加工设备与自动化等配套…

Python面向对象编程2-面向过程的银行账号模拟程序 项目2.2 取款与查看余额

项目总目标&#xff1a;用面向过程思想设计一个简单的银行账号模拟程序。本次将迭代多个程序版本&#xff0c;每个版本都将添加更多功能。虽然这些程序没有达到发布的质量标准&#xff0c;但整个项目的目的是关注于代码如何与一个或多个银行账户的数据进行交互。 分析项目的必要…

MySQL8漏洞处理之小版本升级至8.0.33

MySQL低版本经常会出现一些漏洞&#xff0c;有些高危漏洞就得处理&#xff0c;以防未知风险。 一、漏洞描述 MySQL 安全漏洞(CVE-2023-21912)(CVE-2023-21980): Oracle MySQL 5.7.41 版本及之前版本和 8.0.32 版本及之前版本的 Client programs 组件存在安全漏洞。低权限攻击…

使用Channel的一些业务场景

使用Channel的一些业务场景 首先需要明确的就是&#xff0c;发送方才知道什么时候关闭 channel &#xff0c;这个是比较符合逻辑的。 我们需要知道哪些情况会使 channel 发生 panic 关闭一个 nil 值会引发关闭一个已经关闭的 channel 会引发向一个已经关闭的 channel 发送数据…

职场人的AI私塾,帮你打造得力的AI助手

你有没有想过&#xff0c;为什么有一些周围的小伙伴&#xff0c;工作量看着也不少&#xff0c;但事务处理速度特别快&#xff0c;质量也不差&#xff1b;一些看起来难度比较大或者生疏的工作&#xff0c;也能轻松应付得来&#xff0c;难道他们都是天生的工作能力出众&#xff1…

小白速看!带你轻松解决Java的空指针异常

关注“Java架构栈”微信公众号&#xff0c;回复暗号【Java面试题】即可获取大厂面试题 异常案例 对很多Java初学者来说&#xff0c;在学习的初期是很容易遇到各种异常的&#xff0c;就比如咱们今天要讲的这个空指针异常。所谓“授之以鱼&#xff0c;不如授之以渔”&#xff0c;…

Q-Vision+Kvaser CAN/CAN FD/LIN总线解决方案

智能联网技术在国内的发展势头迅猛&#xff0c;随着汽车智能化、网联化发展大潮的到来&#xff0c;智能网联汽车逐步成为汽车发展的主要趋势。越来越多整车厂诉求&#xff0c;希望可以提供本土的测量软件&#xff0c;特别是关于ADAS测试。对此&#xff0c;Softing中国推出的Q-V…

CppUnit——【由JUnit移植过来的】C++单元测试框架——的下载安装

C单元测试框架CppUnit的下载与安装 简介下载地址导入到Virtual Studio准备条件根据VS版本选择导入对应的.sln文件 简介 CppUnit是【由JUnit移植过来的】C测试框架。 下载地址 从我使用的CppUtest框架中的文档/readme/ReadmePart1_VisualStudio.rtf文件中看到了官网的地址cpp…

前端性能优化:高在性能,大在范围,必要前置知识一网打尽!(下)

前言 在上一篇 前端性能优化&#xff1a;高在性能&#xff0c;大在范围&#xff0c;必要前置知识一网打尽&#xff01;&#xff08;上&#xff09; 一文中介绍了和前端性能优化相关的一些前置知识&#xff0c;那么本篇就针对优化方案进行总结&#xff0c;核心的方向还是上篇文…

C++基础(6)——类和对象(4)

前言 本文主要介绍了C中运算符重载的基本知识。 4.5.1&#xff1a;加号运算符重载&#xff08;成员函数和全局函数都可实现&#xff09; 运算符重载&#xff1a;对已有的运算符重新进行定义&#xff0c;赋予其另一种功能&#xff0c;以适应不同的数据类型 1&#xff1a;成员…

管理类联考——写作——素材篇——论说文——写作素材03——志篇:逆境·考验04——志篇:初心

管理类专业学位联考 (写作能力) 论说文素材 03——志篇&#xff1a;逆境考验 论文说材料: 逆境是天才的进身之阶&#xff1b;信徒的洗礼之水&#xff1b;能人的无价之宝&#xff1b; 弱者的无底之渊。 ——巴尔扎克 一&#xff1a;道理论据 不是一番寒彻骨&#xff0c;怎得…

【Azure】微软 Azure 基础解析(九)Azure 标识、身份管理、Azure AD 的功能与用途

本系列博文还在更新中&#xff0c;收录在专栏&#xff1a;「Azure探秘&#xff1a;构建云计算世界」 专栏中。 本系列文章列表如下&#xff1a; 【Azure】微软 Azure 基础解析&#xff08;三&#xff09;云计算运营中的 CapEx 与 OpEx&#xff0c;如何区分 CapEx 与 OpEx 【A…

测量设备频宽范围选择要素—系统响应速度

系统响应速度是输入信号经过电压/电流驱动系统输出响应的幅值升到终值过程的斜率&#xff0c;而上升时间是系统响应速度的一种度量&#xff0c;上升时间越短&#xff0c;响应速度越快。 由一阶系统响应定义中&#xff0c;稳定的一阶系统上升时间 定义是响应从终值10%上升到终值…