极品馒头泬19p,国产精品亚洲一区二区三区,狠狠色噜噜狠狠狠7777奇米,国产精品视频一区二区三区无码,国产欧美日韩久久久久

【E398】基于OpenMV的無(wú)人駕駛智能小車(chē)模擬系統(tǒng)

2021-08-20 17:49:15      索煒達(dá)電子      3365     

項(xiàng)目編號(hào):E398

文件大?。?M

源碼說(shuō)明:帶中文注釋

開(kāi)發(fā)環(huán)境:C編譯器

簡(jiǎn)要概述

一、項(xiàng)目簡(jiǎn)介

基于機(jī)器視覺(jué)模塊OpenMV采集車(chē)道、紅綠燈、交通標(biāo)志等模擬路況信息,實(shí)現(xiàn)一輛能車(chē)道保持、紅綠燈識(shí)別、交通標(biāo)志識(shí)別、安全避障以及遠(yuǎn)程WiFi控制的多功能無(wú)人駕駛小車(chē)。

【E398】基于OpenMV的無(wú)人駕駛智能小車(chē)模擬系統(tǒng)

二、硬件系統(tǒng)

本項(xiàng)目《基于OpenMV的無(wú)人駕駛智能小車(chē)模擬系統(tǒng)》,主要依靠機(jī)器視覺(jué)模塊OpenMV通過(guò)圖像處理的方式獲取實(shí)時(shí)的路況信息,以及超聲波傳感器獲取障礙物距離信息,得到的路況數(shù)據(jù)再通過(guò)串口傳輸?shù)街骺仄鱏TM32上面,STM32會(huì)將實(shí)時(shí)的路況信息處理成智能小車(chē)的運(yùn)動(dòng)控制指令,讓智能小車(chē)實(shí)現(xiàn)紅綠燈識(shí)別、交通標(biāo)志識(shí)別以及車(chē)道實(shí)時(shí)保持的功能,還有STM32也會(huì)通過(guò)WiFi模塊ESP8266與手機(jī)端進(jìn)行路況數(shù)據(jù)和控制指令的遠(yuǎn)程交互。硬件系統(tǒng)框圖如下:

【E398】基于OpenMV的無(wú)人駕駛智能小車(chē)模擬系統(tǒng)

【E398】基于OpenMV的無(wú)人駕駛智能小車(chē)模擬系統(tǒng)

【E398】基于OpenMV的無(wú)人駕駛智能小車(chē)模擬系統(tǒng)

三、軟件系統(tǒng)

1、OpenMV中的路況識(shí)別算法實(shí)現(xiàn)

本項(xiàng)目的主要路況數(shù)據(jù)信息都是基于OpenMV攝像頭獲取的圖像進(jìn)行圖像處理得到的。要實(shí)現(xiàn)智能小車(chē)的自動(dòng)駕駛行為,最起碼要讓小車(chē)識(shí)別到紅綠燈、交通標(biāo)志以及車(chē)道,后續(xù)主控器才能根據(jù)這些路況數(shù)據(jù)信息控制小車(chē)的運(yùn)動(dòng)。關(guān)于機(jī)器視覺(jué)模塊OpenMV,之前我在《初探機(jī)器視覺(jué)模塊OpenMV》里面已經(jīng)介紹過(guò)了,這里不再贅述。


①紅綠燈識(shí)別

主要是對(duì)攝像頭每幀拍攝到的圖像進(jìn)行圖像進(jìn)行閾值處理,再進(jìn)行判斷出現(xiàn)的究竟是哪種紅綠燈(紅燈、綠燈、黃燈),然后再將這個(gè)判定結(jié)果和其他兩個(gè)數(shù)據(jù)一起打包通過(guò)串口發(fā)送出去。


【程序流程圖】

【E398】基于OpenMV的無(wú)人駕駛智能小車(chē)模擬系統(tǒng)

【主要程序】

###################################開(kāi)始####################################

...

sensor.set_pixformat(sensor.RGB565) # 圖片格式設(shè)為 RGB565彩色圖

light_threshold = [(59, 100, 26, 127, -128, 127),(59, 100, -128, -40, -128, 127)]; #設(shè)置紅綠燈閾值,默認(rèn)為0無(wú)紅綠燈 1紅燈 2綠燈 4黃燈

...

#定義尋找色塊面積最大的函數(shù)

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

#主循環(huán)

while(True):

    clock.tick() #追蹤兩個(gè)snapshots()之間經(jīng)過(guò)的毫秒數(shù)

    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); #如果找到了目標(biāo)顏色

        img.draw_rectangle(max_b[0:4]) #在Blob周?chē)L制一個(gè)矩形

        #用矩形標(biāo)記出目標(biāo)顏色區(qū)域

        img.draw_cross(max_b[5], max_b[6]) # cx, cy

        img.draw_cross(160, 120) # 在中心點(diǎn)畫(huà)標(biāo)記

        #在目標(biāo)顏色區(qū)域的中心畫(huà)十字形標(biāo)記

        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; #紅綠燈的閾值是數(shù)組里的cy(二進(jìn)制)個(gè)

print(LED_color); #串行終端打印出 紅綠燈序號(hào)數(shù)據(jù)

###################################結(jié)束####################################

②交通標(biāo)志識(shí)別

主要是利用NCC(Normalized Cross Correlation)歸一化互相關(guān)算法來(lái)進(jìn)行交通標(biāo)志的圖像識(shí)別與匹配。


【NCC算法】


NCC算法的基本實(shí)現(xiàn)原理:主要是通過(guò)求兩幅大小相近的圖像的相關(guān)系數(shù)矩陣來(lái)判別兩幅圖像是否相關(guān)。假設(shè)需要識(shí)別的初始圖片$g$的大小為$m×n$,攝像頭拍攝到的圖片S的大小為$M×N$,其中的以$(x,y)$為左上角點(diǎn)與$g$大小相同的子圖像為$S_{(x,y)}$。具體的利用NCC算法實(shí)現(xiàn)計(jì)算圖像相似度的方法如下:


$\rho{(x,y)}$的定義為:隨機(jī)變量$X$、$Y$的相關(guān)系數(shù)


$$ \rho{(x,y)}=\frac{\sigma(S_{x,y},g)}{\sqrt[]{D_{x,y}D}} $$ 式中:$\sigma(S_{x,y},g)$是$S_{x,y}$和$g$的協(xié)方差;


$D_{x,y}=\frac {1}{mn}\sum_{i=1}^{m} \sum_{j=1}^{n}{(S_{x,y}(i,j)-\overline S_{x,y})^2}$為$S_{x,y}$的方差;


$D=\frac {1}{mn}\sum_{i=1}^{m} \sum_{j=1}^{n}{(g(i,j)-\overline g)^2}$為$g$的方差;


$\overline g$為$g$的灰度均值;


$\overline S_{x,y}$為$S_{x,y}$的灰度均值;


將$D_{x,y}$和D代入$\rho{(x,y)}$,會(huì)有:


$$ \rho{(x,y)=\frac{ \frac {1}{mn}\sum_{i=1}^{m} \sum_{j=1}^{n}{(S_{x,y}(i,j)-\overline S_{x,y})(g(i,j)-\overline g)}}{\sqrt[]{\frac {1}{mn}\sum_{i=1}^{m} \sum_{j=1}^{n}{(S_{x,y}(i,j)-\overline S_{x,y})^2}}\sqrt[]{\frac {1}{mn}\sum_{i=1}^{m} \sum_{j=1}^{n}{(g(i,j)-\overline g)^2}}}} $$ 其中,相關(guān)系數(shù)$\rho{(x,y)}$滿(mǎn)足:$\rho{(x,y)\le1}$。


$\rho{(x,y)}$越接近1,說(shuō)明兩幅圖像越接近,也就是大圖像的子集中越有可能包含有小圖像。通過(guò)選取恰當(dāng)?shù)南嚓P(guān)系數(shù),我們就可以認(rèn)為,相關(guān)系數(shù)大于該設(shè)定值的圖像為所需識(shí)別的圖像,也就是可以實(shí)現(xiàn)交通標(biāo)識(shí)的識(shí)別。

【程序流程圖】

###################################開(kāi)始####################################

...

sensor.set_pixformat(sensor.GRAYSCALE) #設(shè)置圖片格式為灰度圖

#導(dǎo)入圖片模板

template1 = image.Image("/1.pgm") #直行

template2 = image.Image("/2.pgm") #向右轉(zhuǎn)彎

template3 = image.Image("/3.pgm") #向左轉(zhuǎn)彎

template4 = image.Image("/4.pgm") #停車(chē)讓行

template5 = image.Image("/5.pgm") #鳴喇叭

#主循環(huán)

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(向右轉(zhuǎn)彎)串行終端打印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(向左轉(zhuǎn)彎)串行終端打印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(停車(chē)讓行)串行終端打印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)

###################################結(jié)束####################################

③車(chē)道識(shí)別

主要通過(guò)OpenMV模塊,識(shí)別并跟蹤車(chē)道閾值,通過(guò)幾何運(yùn)算出小車(chē)與車(chē)道中線(xiàn)的角度(偏左為正、偏右為負(fù)),反饋出小車(chē)與車(chē)道的真實(shí)偏離情況(可量化),后續(xù)用于PID控制。


【程序流程圖】

【E398】基于OpenMV的無(wú)人駕駛智能小車(chē)模擬系統(tǒng)

【主要程序】


###################################開(kāi)始####################################

...

sensor.set_pixformat(sensor.RGB565) # 圖片格式設(shè)為 RGB565彩色圖

road_threshold = [(23, 0, -45, 19, -31, 28)]; #黑線(xiàn)道路

ROI = (0, 100, 320, 40)

...

#省略了識(shí)別車(chē)道邊框函數(shù)

#偏移角度計(jì)算算法

def get_direction(left_blob, right_blob):

    # 根據(jù)圖像中的三塊左中右的白色部分,計(jì)算出攝像頭偏轉(zhuǎn)角度

    # ratio < 0 左拐,小車(chē)在車(chē)道偏右位置

    # ratio > 0 右拐,小車(chē)在車(chē)道偏左位置


    MAX_WIDTH = 320

    # 調(diào)節(jié)theta來(lái)設(shè)置中間寬度的比重, theta越高ratio越靠近0

    # 需要根據(jù)賽道寬度與攝像頭高度重新設(shè)定到合適大小

    theta = 0.01

    # 這里的b是為了防止除數(shù)是0的情況發(fā)生, 設(shè)定一個(gè)小一點(diǎn)的值

    b = 3

    x1 = left_blob.x() - int(0.5 * left_blob.w()) #左邊黑線(xiàn)中心x值

    x2 = right_blob.x() + int(0.5 * right_blob.w()) #右邊黑線(xiàn)中心x值

#車(chē)道信息計(jì)算

    w_left = x1 #左邊車(chē)道外寬度

    w_center = math.fabs(x2 - x1) #車(chē)道中心x值

    w_right = math.fabs(MAX_WIDTH - x2) #右邊車(chē)道外寬度

#計(jì)算攝像頭偏移角度

    direct_ratio = (w_left + b + theta * w_center) / (w_left + w_right + 2 * b + 2 * theta * w_center) - 0.5

#返回?cái)z像頭偏移角度

return direct_ratio

#省略了可視化繪圖函數(shù)

...

while(True): #主循環(huán)

clock.tick() #追蹤兩個(gè)snapshots()之間經(jīng)過(guò)的毫秒數(shù)

    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:

#畫(huà)出車(chē)道左邊線(xiàn)

            img.draw_rectangle(left_blob.rect())

            img.draw_cross(left_blob.cx(), left_blob.cy())

#畫(huà)出車(chē)道右邊線(xiàn)

            img.draw_rectangle(right_blob.rect())

            img.draw_cross(right_blob.cx(), right_blob.cy())

#可視化顯示偏轉(zhuǎn)角度

            direct_ratio = get_direction(left_blob, right_blob)

            draw_direct(img,direct_ratio)

            ratio=int(math.degrees(direct_ratio)) #偏轉(zhuǎn)角度轉(zhuǎn)成弧度值

            img.draw_string(10, 10, "%.d"%ratio) #幀緩沖區(qū)實(shí)時(shí)畫(huà)出偏轉(zhuǎn)角度

            print(ratio) #串行終端打印偏轉(zhuǎn)角度

    img.draw_rectangle(ROI,color=(255, 0, 0)) #畫(huà)出感興趣區(qū)域

###################################結(jié)束####################################

2、基于ESP8266的遠(yuǎn)程控制平臺(tái)實(shí)現(xiàn)

主要是利用點(diǎn)燈科技-Blinker物聯(lián)網(wǎng)平臺(tái)搭建控制APP的UI界面,以及調(diào)用Blinker的控制代碼,實(shí)現(xiàn)智能小車(chē)控制指令的下發(fā)與路況數(shù)據(jù)的上傳。


【遠(yuǎn)程控制平臺(tái)UI界面】

【E398】基于OpenMV的無(wú)人駕駛智能小車(chē)模擬系統(tǒng)

【UI配置代碼】


直接使用 點(diǎn)燈.blinker APP導(dǎo)入配置代碼即可獲得和我一樣的UI布局。


{¨config¨{¨headerColor¨¨transparent¨¨headerStyle¨¨dark¨¨background¨{¨img¨¨assets/img/headerbg.jpg¨¨isFull¨?}}¨

【E398】基于OpenMV的無(wú)人駕駛智能小車(chē)模擬系統(tǒng)

【E398】基于OpenMV的無(wú)人駕駛智能小車(chē)模擬系統(tǒng)

【主要程序】


/***********************************開(kāi)始***********************************/

...

int  flag= 0;                        //按鍵標(biāo)志位

int  l= 0;                          //紅綠燈數(shù)據(jù)

int  a= 0;                         //角度數(shù)據(jù)

int  d= 0;                        //距離數(shù)據(jù)

int  z= 0;                        //json解析出來(lái)的數(shù)據(jù)

BlinkerNumber Number0("num-wifi");//WIFI信號(hào)

BlinkerNumber Number1("num-led");//紅綠燈信號(hào)

BlinkerNumber Number2("num-angle");//角度信號(hào)

BlinkerNumber Number3("num-distance");//距離信號(hào)

BlinkerButton Button0("btn-stoping");//停止?fàn)顟B(tài)按鍵

BlinkerButton Button1("btn-go");//前進(jìn)狀態(tài)按鍵

BlinkerButton Button2("btn-right");//右轉(zhuǎn)狀態(tài)按鍵

BlinkerButton Button3("btn-left");//左轉(zhuǎn)狀態(tài)按鍵

BlinkerButton Button4("btn-back");//后退狀態(tài)按鍵

BlinkerButton Button5("btn-auto");//自動(dòng)駕駛狀態(tài)按鍵

...

/*主循環(huán)*/

void loop()

{

    Blinker.run();

    Number0.print(WiFi.RSSI());  //發(fā)送信號(hào)強(qiáng)度

    usartEvent();//串口中斷

    l=int(z/10000);          //解析紅綠燈數(shù)據(jù)

    a=int((z-10000*l)/100);  //解析偏移角度數(shù)據(jù)

d=int(z-10000*l-100*a); //解析距離數(shù)據(jù)

    Number1.print(l);  //發(fā)送紅綠燈信號(hào)

    Number2.print(a);  //發(fā)送角度信號(hào)

    Number3.print(d);  //發(fā)送距離信號(hào)

//發(fā)送控制指令,燈的亮滅,主要是檢查WiFi模塊是否接收到數(shù)據(jù)

    if(oState == false && digitalRead(LED_BUILTIN)== LOW)//燈滅

    {

      digitalWrite(LED_BUILTIN,HIGH);//燈滅

      Serial.print(flag);                //發(fā)送指令

    }

     else if(oState == true && digitalRead(LED_BUILTIN)== HIGH)//燈亮

     {

       digitalWrite(LED_BUILTIN,LOW);//燈亮

       Serial.print(flag);                 //發(fā)送指令

     }

}

//Blinker初始化略

//WiFi連接信號(hào)檢測(cè)略

//STM32數(shù)據(jù)上傳解析略

...

/***********************************結(jié)束***********************************/

3、智能小車(chē)的無(wú)人控制方案實(shí)現(xiàn)

智能小車(chē)在接收到ESP8266的控制指令和OpenMV路況數(shù)據(jù),會(huì)根據(jù)這些指令數(shù)據(jù)進(jìn)行小車(chē)運(yùn)動(dòng)的控制。


【程序流程圖】


【PID控制算法】


關(guān)于直流電機(jī)的PID調(diào)節(jié),主要用來(lái)實(shí)現(xiàn)車(chē)道保持功能。通過(guò)OpenMV返回的偏轉(zhuǎn)角度,進(jìn)行實(shí)時(shí)調(diào)節(jié)電機(jī)PWM輸出,使得偏轉(zhuǎn)角度$Y=50$(也就是小車(chē)與中線(xiàn)的偏轉(zhuǎn)角為0,由于之前為了傳輸方便整體加上了50)。故將設(shè)定值定為50,通過(guò)實(shí)時(shí)返回的$Y$值與50做差值運(yùn)算,得到PID的輸入偏差,通過(guò)位置式PID返回實(shí)時(shí)的PWM值。關(guān)于PID控制算法,之前也有介紹到,這里不再深入贅述。 $$ PWM=K_P\theta(t)+K_i\sum_{t=0}\theta(t)+K_d[\theta(t)-\theta(t-1)] $$ 其中為$\theta(t)$是本次OpenMV返回的偏移角度數(shù)據(jù)$Y$與50的差值,$\theta(t-1)$為上一個(gè)$Y$與50的差值。

【E398】基于OpenMV的無(wú)人駕駛智能小車(chē)模擬系統(tǒng)

目錄│文件列表:

 └ OpenMV-autodrive

    └ OpenMV-autodrive

       ├ ESP8266

       │  └ ESP8266.ino

       ├ OpenMV

       │  ├ 交通標(biāo)志識(shí)別

       │  │  │ traffic_sign_recognition.py

       │  │  └ 交通標(biāo)志模板

       │  │     │ 1.pgm

       │  │     │ 2.pgm

       │  │     │ 3.pgm

       │  │     │ 4.pgm

       │  │     └ 5.pgm

       │  └ 紅綠燈識(shí)別+車(chē)道識(shí)別

       │     └ road_angle_light.py

       └ STM32

          │ keilkilll.bat

          ├ CORE

          │  │ core_cm3.c

          │  │ core_cm3.h

          │  └ startup_stm32f10x_hd.s

          ├ HARDWARE

          │  ├ BEEP

          │  │  │ beep.c

          │  │  └ beep.h

          │  ├ ESP8266

          │  │  │ esp8266.c

          │  │  └ esp8266.h

          │  ├ LED

          │  │  │ led.c

          │  │  └ led.h

          │  ├ OPENMV

          │  │  │ openmv.c

          │  │ beep.d

          │  │ beep.o

          │  │ core_cm3.crf

          │  │ core_cm3.d

          │  │ core_cm3.o

          │  │ delay.crf

          │  │ delay.d

          │  │ delay.o

          │  │ esp8266.crf

          │  │ esp8266.d

          │  │ esp8266.o

          │  │ led.crf


TAG無(wú)人駕駛
  • 15 次
  • 1 分