基于OpenMV的自动驾驶智能小车模拟系统

一、项目简介

基于机器视觉模块OpenMV采集车道、红绿灯、交通标志等模拟路况信息,实现一辆能车道保持、红绿灯识别、交通标志识别、安全避障以及远程WiFi控制的多功能无人驾驶小车。

赛道规格:

1、编程所需软件:

OpenMV:使用OpenMV官方的OpenMV IDE

ESP8266:使用Arduino官方的Arduino IDE

STM32:使用ARM官方的Keil uVision5(ARM版)

2、功能介绍:

OpenMV:主要是利用OpenMV进行路况信息(红绿灯、交通标志、车道)的采取,以及和STM32的通信。

ESP8266:主要是利用ESP8266与手机端进行远程的指令接收和数据交互,以及和STM32的通讯。

STM32:主要是通过ESP8266接收远程控制指令和处理路况信息,并根据这些指令数据进行实时的PID控制小车运动。

二、硬件系统

主要依靠机器视觉模块OpenMV通过图像处理的方式获取实时的路况信息,以及超声波传感器获取障碍物距离信息,得到的路况数据再通过串口传输到主控器STM32上面,STM32会将实时的路况信息处理成智能小车的运动控制指令,让智能小车实现红绿灯识别、交通标志识别以及车道实时保持的功能,还有STM32也会通过WiFi模块ESP8266与手机端进行路况数据和控制指令的远程交互。硬件系统框图如下:

下面简单介绍一下,整个系统用到的硬件模块。

具体的硬件电路连接框图如下:

三、软件系统

1、OpenMV中的路况识别算法实现

本项目的主要路况数据信息都是基于OpenMV摄像头获取的图像进行图像处理得到的。要实现智能小车的自动驾驶行为,最起码要让小车识别到红绿灯、交通标志以及车道,后续主控器才能根据这些路况数据信息控制小车的运动。关于机器视觉模块OpenMV的介绍,可以浏览《初探机器视觉模块OpenMV》这篇文章。

①红绿灯识别

主要是对摄像头每帧拍摄到的图像进行图像进行阈值处理,再进行判断出现的究竟是哪种红绿灯(红灯、绿灯、黄灯),然后再将这个判定结果和其他两个数据一起打包通过串口发送出去。

【程序流程图】

【主要程序】

###################################开始####################################
...
sensor.set_pixformat(sensor.RGB565) # 图片格式设为 RGB565彩色图
light_threshold = [(59, 100, 26, 127, -128, 127),(59, 100, -128, -40, -128, 127)]; #设置红绿灯阈值,默认为0无红绿灯 1红灯 2绿灯 4黄灯
...
#定义寻找色块面积最大的函数
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):
    clock.tick() #追踪两个snapshots()之间经过的毫秒数
    img = sensor.snapshot() #拍一张照片,返回图像
    blobs = img.find_blobs(light_threshold,area_threshold=150); #找到红绿灯
    cx=0;cy=0;LED_color=0; #变量定义
    if blobs:
        max_b = find_max(blobs); #如果找到了目标颜色
        img.draw_rectangle(max_b[0:4]) #在Blob周围绘制一个矩形
        #用矩形标记出目标颜色区域
        img.draw_cross(max_b[5], max_b[6]) # cx, cy
        img.draw_cross(160, 120) # 在中心点画标记
        #在目标颜色区域的中心画十字形标记
        cx=max_b[5];
        cy=max_b[8];
        img.draw_line((160,120,cx,cy), color=(127));
        img.draw_string(cx, cy, "(%d, %d)"%(cx,cy), color=(127));
LED_color=cy; #红绿灯的阈值是数组里的cy(二进制)个
print(LED_color); #串行终端打印出 红绿灯序号数据
###################################结束####################################

②交通标志识别

主要是利用NCC(Normalized Cross Correlation)归一化互相关算法来进行交通标志的图像识别与匹配。

【NCC算法】

NCC算法的基本实现原理:主要是通过求两幅大小相近的图像的相关系数矩阵来判别两幅图像是否相关。假设需要识别的初始图片$g$的大小为$m×n$,摄像头拍摄到的图片S的大小为$M×N$,其中的以$(x,y)$为左上角点与$g$大小相同的子图像为$S_{(x,y)}$​​​​​​​​。具体的利用NCC算法实现计算图像相似度的方法如下:

【主要程序】

###################################开始####################################
...
sensor.set_pixformat(sensor.GRAYSCALE) #设置图片格式为灰度图
#导入图片模板
template1 = image.Image("/1.pgm") #直行
template2 = image.Image("/2.pgm") #向右转弯
template3 = image.Image("/3.pgm") #向左转弯
template4 = image.Image("/4.pgm") #停车让行
template5 = image.Image("/5.pgm") #鸣喇叭
#主循环
while (True):
    clock.tick()
    img = sensor.snapshot()
    flag=0
ratio=0
#匹配1.pgm(直行)串行终端打印go,flag=1
    r1 = img.find_template(template1, 0.70, step=4, search=SEARCH_EX)
    if r1:
        img.draw_rectangle(r1,color=(255,0,0))
        print("go")
        flag=1
        img.draw_string(10, 10, "%.d"%flag)
#匹配2.pgm(向右转弯)串行终端打印right,flag=2
    r2 = img.find_template(template2, 0.70, step=4, search=SEARCH_EX) 
    if r2:
        img.draw_rectangle(r2,color=(0,255,0))
        print("right")
        flag=2
        img.draw_string(10, 10, "%.d"%flag)
#匹配3.pgm(向左转弯)串行终端打印left,flag=3
    r3 = img.find_template(template3, 0.70, step=4, search=SEARCH_EX)
    if r3:
        img.draw_rectangle(r3,color=(255,0,0))
        print("left")
        flag=3
        img.draw_string(10, 10, "%.d"%flag)
#匹配4.pgm(停车让行)串行终端打印stop,flag=4
    r4 = img.find_template(template4, 0.70, step=4, search=SEARCH_EX) 
    if r4:
        img.draw_rectangle(r4,color=(255,255,0))
        print("stop")
        flag=4
        img.draw_string(10, 10, "%.d"%flag)
#匹配5.pgm(鸣喇叭)串行终端打印beep,flag=5
    r5 = img.find_template(template5, 0.70, step=4, search=SEARCH_EX)
    if r5:
        img.draw_rectangle(r5,color=(255,255,0))
        print("beep")
        flag=5
        img.draw_string(10, 10, "%.d"%flag)
###################################结束####################################

③车道识别

主要通过OpenMV模块,识别并跟踪车道阈值,通过几何运算出小车与车道中线的角度(偏左为正、偏右为负),反馈出小车与车道的真实偏离情况(可量化),后续用于PID控制。

【主要程序】

###################################开始####################################
...
sensor.set_pixformat(sensor.RGB565) # 图片格式设为 RGB565彩色图
road_threshold = [(23, 0, -45, 19, -31, 28)]; #黑线道路
ROI = (0, 100, 320, 40)
...
#省略了识别车道边框函数
#偏移角度计算算法
def get_direction(left_blob, right_blob):
    # 根据图像中的三块左中右的白色部分,计算出摄像头偏转角度
    # ratio < 0 左拐,小车在车道偏右位置
    # ratio > 0 右拐,小车在车道偏左位置

    MAX_WIDTH = 320
    # 调节theta来设置中间宽度的比重, theta越高ratio越靠近0
    # 需要根据赛道宽度与摄像头高度重新设定到合适大小
    theta = 0.01
    # 这里的b是为了防止除数是0的情况发生, 设定一个小一点的值
    b = 3
    x1 = left_blob.x() - int(0.5 * left_blob.w()) #左边黑线中心x值
    x2 = right_blob.x() + int(0.5 * right_blob.w()) #右边黑线中心x值
#车道信息计算
    w_left = x1 #左边车道外宽度
    w_center = math.fabs(x2 - x1) #车道中心x值
    w_right = math.fabs(MAX_WIDTH - x2) #右边车道外宽度
#计算摄像头偏移角度
    direct_ratio = (w_left + b + theta * w_center) / (w_left + w_right + 2 * b + 2 * theta * w_center) - 0.5
#返回摄像头偏移角度
return direct_ratio
#省略了可视化绘图函数
...
while(True): #主循环
clock.tick() #追踪两个snapshots()之间经过的毫秒数
    img = sensor.snapshot() #拍一张照片,返回图像
    blobs = img.find_blobs(road_threshold, roi=ROI, merge=True);
    a=0;ratio=0;
    if blobs:
        left_blob, right_blob = get_top2_blobs(blobs)

        if(left_blob == None or right_blob == None):
            print("Out Of Range")
            continue
        else:
#画出车道左边线
            img.draw_rectangle(left_blob.rect())
            img.draw_cross(left_blob.cx(), left_blob.cy())
#画出车道右边线
            img.draw_rectangle(right_blob.rect())
            img.draw_cross(right_blob.cx(), right_blob.cy())
#可视化显示偏转角度
            direct_ratio = get_direction(left_blob, right_blob)
            draw_direct(img,direct_ratio)
            ratio=int(math.degrees(direct_ratio)) #偏转角度转成弧度值
            img.draw_string(10, 10, "%.d"%ratio) #帧缓冲区实时画出偏转角度
            print(ratio) #串行终端打印偏转角度
    img.draw_rectangle(ROI,color=(255, 0, 0)) #画出感兴趣区域
###################################结束####################################

2、基于ESP8266的远程控制平台实现

主要是利用点灯科技-Blinker物联网平台搭建控制APP的UI界面,以及调用Blinker的控制代码,实现智能小车控制指令的下发与路况数据的上传。

【远程控制平台UI界面】

【UI配置代码】

直接使用 点灯.blinker APP导入配置代码即可获得和我一样的UI布局。

{¨config¨{¨headerColor¨¨transparent¨¨headerStyle¨¨dark¨¨background¨{¨img¨¨assets/img/headerbg.jpg¨¨isFull¨«}}¨dashboard¨|{¨type¨¨btn¨¨ico¨¨fad fa-arrow-alt-up¨¨mode¨É¨t0¨¨前进¨¨t1¨¨文本2¨¨bg¨Ì¨cols¨Ë¨rows¨Ë¨key¨¨btn-go¨´x´Ì´y´Ï¨speech¨|÷¨clr¨¨#076EEF¨}{ßAßBßC¨fad fa-arrow-alt-down¨ßEÉßF¨后退¨ßHßIßJÌßKËßLËßM¨btn-back¨´x´Ì´y´¤CßO|÷ßPßQ¨lstyle¨É}{ßAßBßC¨fad fa-arrow-alt-right¨ßEÉßF¨右转¨ßHßIßJÌßKËßLËßM¨btn-right¨´x´Ï´y´ÒßO|÷ßPßQßUÉ}{ßAßBßC¨fad fa-arrow-alt-left¨ßEÉßF¨左转¨ßHßIßJÌßKËßLËßM¨btn-left¨´x´É´y´ÒßO|÷ßPßQßUÉ}{ßAßBßC¨fad fa-power-off¨ßEÉßF¨停车¨ßHßIßJÌßKËßLËßM¨btn-stoping¨´x´Ï´y´ÏßO|÷ßPßQßUÉ}{ßA¨tex¨ßF¨😋小车远程监控系统😋¨ßH´´ßJËßC´´ßKÍßLÊßM´´´x´Ë´y´ËßO|÷ßPßQßUÊ}{ßA¨num¨ßF¨障碍物距离¨ßC¨fad fa-route¨ßPßQ¨min¨É¨max¨¢1c¨uni¨¨cm¨ßJÉßKÍßLËßM¨num-distance¨´x´É´y´¤EßO|÷ßUÊ}{ßAßgßF¨小车偏移角度¨ßC¨fad fa-tachometer-alt-fast¨ßPßQßjÉßkº0ßl´º´ßJÉßKÍßLËßM¨num-angle¨´x´Í´y´¤EßO|÷ßUÊ}{ßAßgßF¨红绿灯(红1绿2)¨ßC¨fad fa-siren-on¨ßPßQßjÉßkËßl´´ßJÉßKËßLËßM¨num-led¨´x´É´y´ÏßO|÷ßUÉ}{ßA¨deb¨ßEÉßJÉßKÑßLÌßM¨debug¨´x´É´y´ÌßO|÷ßUÉ}{ßAßgßF¨WIFI信号¨ßC¨fad fa-signal-4¨ßP¨#389BEE¨ßjÉßkº0ßl¨dbm¨ßJÉßKËßLËßM¨num-wifi¨´x´Ï´y´ÉßO|÷ßUÉ}{ßAßBßC¨fad fa-repeat-alt¨ßEÊßF¨自动驾驶模式¨ßHßIßJËßKËßLËßM¨btn-auto¨´x´Ì´y´ÒßO|÷ßPßQßUÉ}÷¨actions¨|¦¨cmd¨¦¨switch¨‡¨text¨‡´on´¨打开?name¨¨off¨¨关闭?name¨—÷¨triggers¨|{¨source¨ß16¨source_zh¨¨开关状态¨¨state¨|´on´ß19÷¨state_zh¨|´打开´´关闭´÷}÷}

【控制指令与监控数据】

【主要程序】

/***********************************开始***********************************/
...
int  flag= 0;                        //按键标志位
int  l= 0;                          //红绿灯数据
int  a= 0;                         //角度数据
int  d= 0;                        //距离数据
int  z= 0;                        //json解析出来的数据
BlinkerNumber Number0("num-wifi");//WIFI信号
BlinkerNumber Number1("num-led");//红绿灯信号
BlinkerNumber Number2("num-angle");//角度信号
BlinkerNumber Number3("num-distance");//距离信号
BlinkerButton Button0("btn-stoping");//停止状态按键
BlinkerButton Button1("btn-go");//前进状态按键
BlinkerButton Button2("btn-right");//右转状态按键
BlinkerButton Button3("btn-left");//左转状态按键
BlinkerButton Button4("btn-back");//后退状态按键
BlinkerButton Button5("btn-auto");//自动驾驶状态按键
...
/*主循环*/
void loop()
{
    Blinker.run();
    Number0.print(WiFi.RSSI());  //发送信号强度
    usartEvent();//串口中断
    l=int(z/10000);          //解析红绿灯数据
    a=int((z-10000*l)/100);  //解析偏移角度数据
d=int(z-10000*l-100*a); //解析距离数据
    Number1.print(l);  //发送红绿灯信号
    Number2.print(a);  //发送角度信号
    Number3.print(d);  //发送距离信号
//发送控制指令,灯的亮灭,主要是检查WiFi模块是否接收到数据
    if(oState == false && digitalRead(LED_BUILTIN)== LOW)//灯灭
    {
      digitalWrite(LED_BUILTIN,HIGH);//灯灭
      Serial.print(flag);                //发送指令
    }
     else if(oState == true && digitalRead(LED_BUILTIN)== HIGH)//灯亮
     {
       digitalWrite(LED_BUILTIN,LOW);//灯亮
       Serial.print(flag);                 //发送指令
     }
}
//Blinker初始化略
//WiFi连接信号检测略
//STM32数据上传解析略
...
/***********************************结束***********************************/

3、智能小车的无人控制方案实现

智能小车在接收到ESP8266的控制指令和OpenMV路况数据,会根据这些指令数据进行小车运动的控制。

【PID控制算法】

关于直流电机的PID调节,主要用来实现车道保持功能。通过OpenMV返回的偏转角度,进行实时调节电机PWM输出,使得偏转角度$Y=50$​(也就是小车与中线的偏转角为0,由于之前为了传输方便整体加上了50)。故将设定值定为50,通过实时返回的$Y$值与50做差值运算,得到PID的输入偏差,通过位置式PID返回实时的PWM值。关于PID控制算法,之前也有介绍到,这里不再深入赘述。

$$PWM=K_P\theta(t)+K_i\sum_{t=0}\theta(t)+K_d[\theta(t)-\theta(t-1)]$$其中为$\theta(t)$​​是本次OpenMV返回的偏移角度数据$Y$​​与50的差值,$\theta(t-1)$​​为上一个$Y$​​​与50的差值。

【模拟环境】

项目百度网盘地址:

链接:https://pan.baidu.com/s/16iSkrEZp5M9uslYRx2KaKg?pwd=n9sm

提取码:n9sm

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python自动化测试框架:Pytest和Unittest的区别

pytest和unittest是Python中常用的两种测试框架&#xff0c;它们都可以用来编写和执行测试用例&#xff0c;但两者在很多方面都有所不同。本文将从不同的角度来论述这些区别&#xff0c;以帮助大家更好地理解pytest和unittest。 1. 原理 pytest是基于Python的assert语句和Pytho…

Git第二章、多人协作

一、多人协作一 目前&#xff0c;我们所完成的工作如下&#xff1a; • 基本完成 Git 的所有本地库的相关操作&#xff0c;git基本操作&#xff0c;分支理解&#xff0c;版本回退&#xff0c;冲突解决等等 • 申请码云账号&#xff0c;将远端信息clone到本地&#xff0c;以及推…

一种基于目标的可解释的自动驾驶预测和规划策略

摘要&#xff1a; 本文介绍了一种通过理性逆向规划进行目标识别和多模态轨迹预测的方法。通过将目标识别与MCTS 计划相结合&#xff0c;为自车生成优化计划。 最近炒得比较火的影子模式实际就是在通过数据收集的方式不断模拟自动驾驶系统按照人类驾驶习惯实现人之间的交互过程…

Qt 中动态加载窗口(C++)

在编程中&#xff0c;我经常会遇见要根据用户触发按钮&#xff0c;动态生成窗口的情况。在此有两种方法可以动态生成窗口&#xff1a;一&#xff1a;直接在槽函数中调用窗口类。二&#xff1a;将 **.ui 添加到资源文件&#xff0c;通过 QUiLoader 加载。 现将两种方法介绍如下…

linuxOPS系统服务_Linux下用户管理

用户概念以及基本作用 **用户&#xff1a;**指的是Linux操作系统中用于管理系统或者服务的人 一问&#xff1a;管理系统到底在管理什么&#xff1f; 答&#xff1a;Linux下一切皆文件&#xff0c;所以用户管理的是相应的文件 二问&#xff1a;如何管理文件呢&#xff1f; …

【新星计划回顾】第六篇学习计划-通过自定义函数和存储过程模拟MD5数据

&#x1f3c6;&#x1f3c6;时间过的真快&#xff0c;这是导师回顾新星计划学习的第六篇文章&#xff01; 最近这段时间非常忙&#xff0c;虽然导师首次参与新星计划活动已经在4月16日圆满结束&#xff0c;早想腾出时间来好好整理活动期间分享的知识点。 &#x1f3c6;&#x1…

Unsupervised Learning(无监督学习)

目录 Introduction Clustering&#xff08;聚类&#xff09; Dimension Reduction&#xff08;降维&#xff09; PCA&#xff08;Principle component analysis&#xff0c;主成分分析&#xff09; Word Embedding&#xff08;词嵌入&#xff09; Matrix Factorization(矩…

适合嵌入式开发的GUI(嵌入式学习)

嵌入式开发的GUI如何选择&#xff1f; 常见的嵌入式GUI开发方法轻量级GUI库优缺点 基于Web技术优缺点 Qt框架优缺点 原生开发优缺点 嵌入式系统的限制 常见的嵌入式GUI开发方法 嵌入式开发中的GUI&#xff08;图形用户界面&#xff09;是指在嵌入式系统中实现图形化的用户界面…

Linux权限管理(超详解哦)

Linux权限 引言文件访问者的分类文件类型与访问权限文件类型访问权限 文件权限值的表示方法修改权限的指令chmod修改文件权限通过角色/-/权限来修改通过三个八进制数修改 chown修改所有者chgrp修改所属组umask修改或查看文件权限掩码文件创建时的权限 目录的权限粘滞位 总结 引…

驱动模块和printk函数

目录 1. 驱动模板 1.1. 在源码工程路径下创建.c文件 1.2. 编写驱动模板 1.3. 将模板放到ubuntu上 1.4. 书写Makefile 1.5. 编译和安装 2. printk 2.1. Source Insight查找命令 2.2. printk讲解 2.2.1. 分析函数 2.2.2. 编写代码 2.3. 拓展 2.3.1. 关于printk函数测…

ESP32开发环境搭建Windows VSCode集成Espressif IDF插件ESP32_IDF_V5.0开发编译环境搭建

一、安装ESP32-IDF库 下载网址&#xff1a;https://dl.espressif.com/dl/esp-idf/ 打开上面的网页&#xff0c;选择单击页面中 ESP32-IDF v5.0.2 - Offine Installer&#xff0c;5.0.2是当前最新版本&#xff0c;如果没有ESP32-IDF v5.0.2 - Offine Installer&#xff0c;说明…

ADB WIFI 链接

ADB WiFi链接手机 必须在同一网络下&#xff08;本人用的台式机网线手机连路由器WIFI&#xff09; 1.先确认USB数据线是否成功链接了手机 adb devices不管前面设备是什么名字&#xff0c;但是后面必须为device状态才算链接成功了&#xff0c;offline状态是不行的 有些没开启…

《微服务架构设计模式》第二章 服务的拆分策略

内容总结自《微服务架构设计模式》 服务的拆分策略 一、架构是什么软件架构的41视图模型为什么重要分层架构风格 二、定义微服务如何定义服务拆分难点定义服务API 一、架构是什么 软件架构的定义&#xff1a;计算机系统的软件架构是构建这个系统所需要的一组结构&#xff0c;包…

物联网Lora模块从入门到精通(八)Lora无线通信

一、前言 在某些环境下&#xff0c;无法通过有线传输数据&#xff0c;这时候我们需要使用Lora无线通信传输数据&#xff0c;Lora无线数据传输具有低功耗、距离长的特点&#xff0c;常用于工厂内等&#xff0c;需要Lora基站。 我曾做过距离测试&#xff1a;Lora模块距离测试-物联…

Linux---vim的使用

专栏&#xff1a;Linux 个人主页&#xff1a;HaiFan. 本章为大家带来Linux工具—vim Linux工具 关于rzszyumvim的基本概念vim的基本操作vim正常模式命令集vim末行模式命令集简单vim配置配置文件的位置常用配置选项 关于rzsz 这个工具用于windows机器和Linux机器通过Xshell传输…

PHP伪协议filter详解,php://filter协议过滤器

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 php://filter 一、访问数据流二、过滤数据流三、多…

electron 快速创建一个本地应用

参考官方文档流程 快速入门 | Electron 建议先全局安装electron&#xff0c;npm install -g electron 开发过程中可以在本地开发安装 使用electron快速创建一个web页面 &#xff0c;参考官方demo 实例 electron-quick-start 第一步&#xff1a; mkdir my-electron-app &am…

Linux

Linux 摘要写在前面1.Linux介绍2.Linux基本概念与命令3.Shell编程4.桌面操作系统框架5.GTK图形编程6.QT图形编程7.DBUS8.GDB9.Wine开发10.高可用存储技术11.高可用网络技术12.云计算 摘要 本篇博客参考中科方德国产操作系统的培训课程&#xff0c;对其主要内容进行总结&#x…

超越密码:网络安全认证的未来

你的物理现实的数字对应物正在惊人地增长。虽然肯定会有积极的结果&#xff0c;但随着互联网的发展&#xff0c;与之相关的风险也在迅速增加。在讨论网络安全风险管理时&#xff0c;首先想到的是密码。但当出现诈骗、网络钓鱼等威胁时&#xff0c;这还不够。 那么&#xff0c;…

大数据分析与机器学习:技术深度与实例解析【上进小菜猪大数据系列】

上进小菜猪&#xff0c;沈工大软件工程专业&#xff0c;爱好敲代码&#xff0c;持续输出干货。 大数据分析与机器学习已成为当今商业决策和科学研究中的关键组成部分。本文将深入探讨大数据技术的背景和原则&#xff0c;并结合实例介绍一些常见的大数据分析和机器学习技术。 …