修改記錄
序號 | 修改時間 | 修改內(nèi)容 |
---|---|---|
1 | 2022-3-12 | 增加第一次補充內(nèi)容:PID控制,詳細請見“6. 第一次補充(2022.3.12)” |
2 | 2022-4-21 | 修改了PID代碼部分“誤差的計算公式”錯誤 ,由“ pid_x.Actual - pid_x.Set ”修改為“pid_x.Set - pid_x.Actual”,詳細請見“6.2.2 STM32代碼”部分 |
3 | 2022-10-22 | 增加第二次補充內(nèi)容:硬件部分改為PCB,主控芯片替換為STM32F103C8T6,詳細請見“7. 第二次補充(2022.10.22)” |
1.摘 要
??本文通過OpenMV作為是識別模塊去識別被測物體(以紅色小球為例),當其識別到紅色小球后,判斷小球中心點所在的區(qū)域信息,并將其區(qū)域標志位通過串口發(fā)送給STM32,當STM32接收到位置信息后對x軸、y軸的兩個舵機參數(shù)進行操作,最后通過定時器輸出合適的PWM波,控制舵機旋轉(zhuǎn)相應的角度,使OpenMV攝像頭對準被測物體,以實現(xiàn)物體追蹤功能。
實現(xiàn)效果
【畢業(yè)設計】基于Stm32及OpenMV的云臺追蹤裝置
??我會把我做該畢業(yè)設計的整體思路以及部分的主要代碼在文章中詳細介紹,很簡單的,在追蹤部分沒有用到PID控制哦!大家可以放心食用(手動滑稽)!很容易復刻的!
若是你很懶,不想自己一步一步自己做的話,可以直接去下載論文和源代碼。
代碼:【代碼】基于STM32及OpenMV的云臺追蹤裝置_畢業(yè)設計
全家桶:【畢設全家桶】基于Stm32及OpenMV的云臺追蹤裝置_畢業(yè)設計
注:全家桶中包含了PID以及非PID兩種控制方式的代碼工程。
(溫馨提示:是要花錢的哦,我覺得你看完這篇文章完全可以自己做出來的,沒必要花錢的,所以請一定要仔細看下去哦?。?/p>
2022.3.12 第一次補充:
新添加了PID控制追蹤的代碼:【代碼(PID)】基于Stm32及OpenMV的云臺追蹤裝置_畢業(yè)設計
注:PID的程序在上面的全家桶中包含了。
2.整體功能分析
??完成一個好的設計是要在實現(xiàn)了它的功能的基礎上,所以在進行設計之前需要確定一下本設計要實現(xiàn)的功能,然后再進行相應的設計。在本設計中使用OpenMV作為視覺模塊,STM32作為主控制MCU去控制舵機旋轉(zhuǎn),以實現(xiàn)追蹤功能。整體功能流程圖如圖2.1所示。
OpenMV:作為識別模塊,主要實現(xiàn)物體識別的功能,并將識別到的物體的位置信息通過串口傳遞給STM32。
STM32的串口部分:主要功能是與OpenMV進行數(shù)據(jù)交互,接收OpenMV發(fā)來的位置信息。
STM32的定時器部分:主要功能是通過庫函數(shù)輸出PWM波,從而控制X、Y軸的兩個舵機旋轉(zhuǎn)。以達到追蹤效果。
整體功能流程圖
3.硬件選型
??本小結(jié)主要對整個畢業(yè)設計過程所需要的硬件設備:DS3120舵機、STM32F103ZET6、LED補光板、3S鋰電池、OpenMV4 Cam H7穩(wěn)壓板進行介紹,然后進行整個硬件的連接。
3.1 OpenMV4 Cam H7
??本設計中OpenMV選用星瞳科技代理的OpenMV4 Cam H7,如圖3.1所示。選擇那一個型號的OpenMV都可以,主要影響的只是圖像的清晰度(圖像大?。阅茉胶玫腛penMV可以在更高的清晰度下運行,而差的可能會在該清晰度下報錯。
??本設計中OpenMV部分主要實現(xiàn)三個功能:完成被測物體的識別(以紅色小球為例)、尋找最大色塊區(qū)域、通過串口發(fā)送被測物體的位置信息。在這兒強調(diào)一下,其引腳3.3v-5v耐壓,過高的電壓會燒掉其中的芯片。
3.2 STM32F103ZET6
??本次設計中使用STM32F103ZET6最小系統(tǒng)板作為核心MCU,實物如圖3.3所示。使用其他的芯片已ok的,只需要確定該芯片可以輸出兩路PWM波、一個串口就行。
??本設計中STM32部分主要使用串口和定時器來實現(xiàn):通過串口接收OpenMV發(fā)來的數(shù)據(jù)、通過定時器輸出PWM波,以實現(xiàn)控制舵機旋轉(zhuǎn)追蹤的目的。
只強調(diào)一下,其引腳3.3v-5v耐壓,過高的電壓會燒掉其中的芯片。
3.3 DS3120舵機
??舵機選用達盛舵機科技有限公司生產(chǎn)的DS3120型號的舵機,實物圖及尺寸如圖3.5所示。該型號舵機運行溫度在-15℃~70℃,工作電壓范圍為4.8v-6.8v,驅(qū)動方式為PWM波,脈沖范圍為500~2500μsec,控制角度為:180° 。這里我雖然使用了180°舵機,但是在追蹤過程中,我通過在軟件中限制了舵機的最大旋轉(zhuǎn)角度,避免追蹤過程中舵機旋轉(zhuǎn)角度過大對舵機后面的接線造成影響。
??工作原理:通過給舵機的信號線(橙黃色)輸入周期為20ms的PWM波,通高電平的時間為:0.5 ~ 2.5ms,可以使舵機旋轉(zhuǎn)0~180°。如圖3.6所示。
3.4 LED補光板
??因為OpenMV進行顏色識別時,對環(huán)境的光照有一定的要求,光照強度的變換會直接對識別造成影響,所以為避免環(huán)境光線變化的影響,在本次設計中加入LED補光板,補光板由6個貼片LED及電阻組成,貼片LED選用CF12V3T3R00,電阻選用100歐姆,供電則直接接3S鋰電池,11.1v供電。
3.5 供電及穩(wěn)壓
??供電使用3s鋰電池作為整體裝置的供電,3S鋰電池可以提供11.1V的電壓,3S鋰電池實物圖如圖3.9所示。
??因為OpenMV、舵機、STM32都不能直接11.1V電壓,所以需要對電壓進行穩(wěn)壓到5v,才能給它們供電,使用穩(wěn)壓板進行穩(wěn)壓,穩(wěn)壓板選用基于LM2596芯片的DC-DC穩(wěn)壓模塊,穩(wěn)壓板的輸入端連接3S鋰電池,用電壓表測量輸出端電壓,用螺絲刀旋轉(zhuǎn)穩(wěn)壓板上的可調(diào)節(jié)電位器,直到輸出端輸出電壓為5v即可。
3.6 硬件連接
??硬件連接部分使用杜邦線連接,連接如下:3S鋰電池接穩(wěn)壓板輸入端以及直接給LED補光板供電,穩(wěn)壓板輸出端接OpenMV的VIN和GND引腳、STM32的5V和GND引腳以及兩個舵機的正(紅色)負(棕色)極。OpenMV的P4引腳(串口3的TX)接STM32的PA10引腳(串口1的RX),OpenMV的P5引腳(串口3的RX)接STM32的PA9引腳(串口1的TX),STM32的PC7引腳(定時器3通道2)接x軸的舵機的信號線(橙黃色),STM32的PC7引腳(定時器3通道1)接y軸的舵機的信號線(橙黃色)。
4.軟件功能實現(xiàn)
??軟件部分的功能主要分為兩部分,一個是OpenMV部分,另一是STM32部分,OpenMV主要實現(xiàn)功能:完成被測物體的識別、尋找最大色塊區(qū)域、判斷被測物體所在區(qū)域、通過串口發(fā)送被測物體的位置信息。STM32部分主要實現(xiàn)功能:使用串口接收OpenMV發(fā)來的數(shù)據(jù)、通過定時器輸出PWM波、以及實現(xiàn)控制舵機旋轉(zhuǎn)追蹤的目的。
4.1 OpenMV部分的功能實現(xiàn)
4.1.1 整體邏輯分析
??首先對OpenMV部分實現(xiàn)功能:首先進行攝像頭的初始化,確保其可以正常的使用。其次設置圖像格式,選用RGB模式,使其圖像為彩色模式,然后設置圖像大小,設置為QVGA格式,分辨率為320*240 dpi。而后設置顏色閾值,確保OpenMV可以識別到此顏色。然后設置白平衡,關閉自動白平衡,避免對識別的影響。接著對串口初始化,確保串口可以正常的發(fā)送數(shù)據(jù)。到此準備工作完成,進入識別部分,首先截取圖像并返回,然后判斷圖像內(nèi)是否識別到紅色區(qū)域:否則循環(huán)等待,是則判斷區(qū)域是否為最大區(qū)域,否則返回等待,是則用矩形框標出中心位置,判斷中心位置所在的區(qū)域,并將位置信息通過串口發(fā)出。以上部分除了判斷所在區(qū)域外的所有代碼都可以在星瞳科技的官網(wǎng)上找到,并且官方還有配套的詳細講解。
戳這里直接進入:星瞳科技官網(wǎng)
4.1.2 對被測物體的識別
??本設計中被測物體為一個紅色小球,因此對于物體的識別主要為顏色識別,在編程中首先需要對OpenMV的紅色的閾值進行調(diào)整,打開閾值編輯器,對LAB的閾值進行調(diào)整,使二進制圖像中只有紅色區(qū)域的映像。
注:在不同的光照環(huán)境下會對顏色識別造成很大的影,所以請在穩(wěn)定的光照環(huán)境下調(diào)整閾值以及識別。
??調(diào)整好紅色閾值后,賦值LAB閾值的參數(shù),并賦值給red_threshold,調(diào)用MicroPython函數(shù)庫中的image.find_blobs()函數(shù),對該色域進行識別。該功能部分程序如下:
import sensor, image, time, pyb
from pyb import UART
red_threshold = (14, 68, 11, 70, 9, 56) #紅色閾值設定
sensor.reset() # 初始化攝像頭傳感器.
sensor.set_pixformat(sensor.RGB565) # 使用RGB565.
sensor.set_framesize(sensor.QVGA) # 使用QVGA.
sensor.skip_frames(10) # 讓新設置生效.
sensor.set_auto_whitebal(False) # 關閉自動白平衡.
clock = time.clock() # Tracks FPS.
while(True):
img = sensor.snapshot() # 拍照并返回圖像.
blobs = img.find_blobs([red_threshold])
if blobs:
img.draw_rectangle(blobs.rect())
img.draw_cross(blobs.cx(), blobs.cy())
其中:
while循環(huán)之前為OpenMV初始化部分:
RGB565為彩色模式(顏色識別嘛,肯定得用彩色模式);
QVGA為圖像大?。?20dpi * 160dpi,像素點),這個可以根據(jù)選的OpenMV的性能來選擇;
關閉白平衡:是指關閉系統(tǒng)的自動白平衡,自動白平衡會對顏色識別造成影響。
while循環(huán)內(nèi):
image.find_blobs()函數(shù):參數(shù)主要為6個:LAB的最大最小值(可以通過之前的閾值編輯器中得到)。
img.draw_rectangle()函數(shù):則是用矩形框框出識函數(shù)參數(shù)的區(qū)域。
img.draw_cross()函數(shù):在參數(shù)位置上繪制出十字架。其中函數(shù)參數(shù)blobs.cx(), blobs.cy():分別為blobs區(qū)域的中心x、y軸坐標。
4.1.2 尋找最大色塊區(qū)域
??在OpenMV追蹤識別的過程中,可能出現(xiàn)背景或是其他區(qū)域出現(xiàn)小面積的紅色區(qū)域,如圖所示。這會對識別造成影響,所以需要用程序過濾掉那些小的紅色區(qū)域。
??通過對識別到的紅色區(qū)域進行比較,找出所有紅色區(qū)域中最大的區(qū)域,即可避免背景中的小面積紅色區(qū)域?qū)ψR別的影響,該部分程序如下:
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
if blobs:
max_blob=find_max(blobs)
??該程序中,定義一個名為find_max()的子函數(shù),該函數(shù)主要實現(xiàn)的功能就是尋找最大的紅色區(qū)域,在主函數(shù)中調(diào)用該函數(shù)以實現(xiàn)該功能,避免背景中的小面積紅色區(qū)域?qū)ψR別的影響。結(jié)果如圖所示。
4.1.3 判斷被測物體所在區(qū)域
??本段程序是判斷被測物體所在區(qū)域,將OpenMV拍攝到的畫面分為五個區(qū)域,分別為中心區(qū)域、左上區(qū)域、右上區(qū)域、左下區(qū)域、右下區(qū)域,分布結(jié)構如圖所示。
區(qū)域位置 | X軸范圍 | Y軸范圍 |
---|---|---|
中心區(qū)域 | 135-175 dpi | 110-130 dpi |
左上區(qū)域 | 0-160 dpi | 120-240 dpi |
右上區(qū)域 | 160-320 dpi | 120-240 dpi |
左下區(qū)域 | 0-160 dpi | 0-120 dpi |
右下區(qū)域 | 160-320 dpi | 0-120 dpi |
??區(qū)域分布主要是按照像素分布,我使用到QVGA格式(320*240),使用其他大小的格式,可以按照大小自行進行分配。 | ||
??本段程序主要通過識別到物體的中心點所在像素位置判斷其所在區(qū)域所完成,部分程序如下: |
x_max = 320
x_min = 0
x_1 = 135 #中心區(qū)域左邊界
x_2 = 175 #中心區(qū)域右邊界
y_max = 240
y_min = 0
y_1 = 110 #中心區(qū)域上邊界
y_2 = 130 #中心區(qū)域下邊界
flag = 0#位置信息標志
if max_blob.cx()>= x_min and max_blob.cx() <= 160 and\
max_blob.cy() >= 120 and max_blob.cy() <= y_max :
flag = 1
if max_blob.cx()>=160 and max_blob.cx() <= x_max and\
max_blob.cy() >=120 and max_blob.cy() <= y_max :
flag = 2
if max_blob.cx()>= x_min and max_blob.cx() <= 160 and \
max_blob.cy() >= y_min and max_blob.cy() <= 120 :
flag = 3
if max_blob.cx()>= 160 and max_blob.cx() <= x_max and \
max_blob.cy() >= y_min and max_blob.cy() <= 120 :
flag = 4
if max_blob.cx()>= x_1 and max_blob.cx() <= x_2 and \
max_blob.cy() >= y_1 and max_blob.cy() < =y_2 :
flag = 5
??本部分程序邏輯為先判斷被測物體的中心位置是否在左上區(qū)域,如果在則標志位flag被賦值為1,否則為不變(初始值為0),判斷被測物體的中心位置是否在右上區(qū)域,如果在則標志位flag被賦值為2,否則為不變,判斷被測物體的中心位置是否在左下區(qū)域,如果在則標志位flag被賦值為3,否則為不變,判斷被測物體的中心位置是否在右下區(qū)域,如果在則標志位flag被賦值為4,否則為不變,判斷被測物體的中心位置是否在中心區(qū)域,如果在則標志位flag被賦值為5,否則為不變。流程圖如圖所示。
4.1.5 串口發(fā)送數(shù)據(jù)
??本部分主要介紹串口發(fā)送數(shù)據(jù)給STM32的程序,發(fā)送的數(shù)據(jù)則是上一部分判斷物體中心位置所在區(qū)域的標志位,主要使用uart.write()函數(shù)來實現(xiàn)本功能。該函數(shù)為封裝好的庫函數(shù),直接調(diào)用即可,部分程序如下:
import pyb
from pyb import UART
uart = UART(3, 115200) #串口3初始化,波特率115200
while(True):
output_str="%d" %flag #方式1
print('you send:',output_str)
uart.write(output_str+'\r\n')
4.2 STM32部分軟件功能的實現(xiàn)
4.2.1 整體邏輯分析
??首先對STM32部分實現(xiàn)功能的整體邏輯進行分析,首先進行系統(tǒng)時鐘的初始化,確保STM32的時鐘周期正常運行。其次中斷優(yōu)先級的初始化,本程序中主要用到了串口1的接收中斷,所以只需要配置串口1的中斷優(yōu)先級。然后進行串口1的初始化,確保串口1可以正常的接收數(shù)據(jù)。而后進行定時器3通道1以及通道2的初始化,確??梢允蛊漭敵鯬WM波控制舵機旋轉(zhuǎn)。舵機回歸初始位置,能夠使裝置上電后,舵機回到初始位置。最后判斷串口是否接收到數(shù)據(jù),如果串口接收到數(shù)據(jù),則進入串口中斷,執(zhí)行相應的程序。反之,則進行等待。整體流程圖如圖所示。其次在使用串口接收OpenMV發(fā)來的數(shù)據(jù)、通過定時器輸出PWM波的功能進行獨立的分析。
4.2.2 串口接收數(shù)據(jù)
??本部分程序主要為串口初始化,以及串口中斷函數(shù)的編寫,主要實現(xiàn)STM32通過串口1 接收OpenMV發(fā)送來的數(shù)據(jù)。當接收到數(shù)據(jù)時,STM32的串口1接收完成位USART_IT_RXNE會被置1。進入串口1中斷,運行串口中斷內(nèi)的程序。使用庫函數(shù)編程,部分程序如下。
//串口1時鐘使能:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
//串口1引腳配置:
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX串口輸出PA9
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //復用推挽輸出
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX 串口輸入PA10
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模擬輸入
GPIO_Init(GPIOA,&GPIO_InitStructure); /*初始化GPIO*/
//串口1初始化設置:
USART_InitStructure.USART_BaudRate = bound;//波特率設置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;//無奇偶校驗位
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1,&USART_InitStructure); //初始化串口1
USART_Cmd(USART1, ENABLE); //使能串口1
//中斷優(yōu)先級配置:
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中斷通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//搶占優(yōu)先級3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子優(yōu)先級3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); //根據(jù)指定的參數(shù)初始化VIC寄存器
4.2.3 定時器輸出PWM波
??本部分程序主要為定時器3通道1和通道2的初始化,并使用STM32的固件庫中函數(shù)TIM_SetCompare1(TIM_TypeDef* TIMx,uint16_t Compare1)輸出PWM波,使舵機旋轉(zhuǎn)。該函數(shù)有兩個參數(shù),第一個參數(shù)為定時器號,第二個參數(shù)為占空比的參數(shù)。部分程序如下。
//使能定時器3的時鐘:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//配置定時器3的引腳:
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//復用推挽輸出
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);
//初始化定時器3的基本配置:
TIM_TimeBaseInitStructure.TIM_Period=per; //自動裝載值
TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分頻系數(shù)
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
//初始化輸出比較通道2:
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OC2Init(TIM3,&TIM_OCInitStructure); //輸出比較通道2初始化
//使能定時器3:
TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3,ENABLE);//使能預裝載寄存器
TIM_Cmd(TIM3,ENABLE); //使能定時器
4.2.4 控制舵機旋轉(zhuǎn)
??舵機旋轉(zhuǎn)角度主要是由占空比決定,所以通過傳遞給函數(shù)TIM_SetCompareX()的參數(shù)即可控制舵機旋轉(zhuǎn)的角度,編程思路在STM32接收到OpenMV發(fā)送的數(shù)據(jù)后,進入串口中斷,在串口中斷函數(shù)內(nèi)編寫控制舵機旋轉(zhuǎn)的程序,接收到的數(shù)據(jù)分為5種情況,即接收到被測物體所在的區(qū)域信息:1、2、3、4、5分別對應左上、右上、左下、右下、中心五個區(qū)域。接收到不同的標志位信息進行不同的動作。流程如圖所示。
??同時防止舵機追蹤時出現(xiàn)旋轉(zhuǎn)角度過大,可通過軟件進行限制,部分程序如下:
Data=USART_ReceiveData(USART1); //讀取接收到的數(shù)據(jù)
switch (Data)
{
case '1':Variable_X( 1 ); Control_X (pwm_x);
Variable_Y( 0 ); Control_Y (pwm_y);break;
case '2': Variable_X( 0 ); Control_X (pwm_x);
Variable_Y( 0 ); Control_Y (pwm_y);break;
case '3': Variable_X( 1 ); Control_X (pwm_x);
Variable_Y( 1 ); Control_Y (pwm_y);break;
case '4': Variable_X( 0 ); Control_X (pwm_x);
Variable_Y( 1 ); Control_Y (pwm_y);break;
case '5':break;
}
??以上程序中,定義了Variable_X( )、Variable_Y( )兩個子函數(shù),子函數(shù)中有兩個參數(shù):0和1 ,主要實現(xiàn)對x、y軸舵機參數(shù)的減小和增加。同時在兩個子函數(shù)中加入if語句,當舵機旋轉(zhuǎn)參數(shù)增加到一定時,保持固定不變。同理減小到一定值時,也固定保持不變。以Variable_X( )子函數(shù)為例,部分程序如下:
unsigned int Variable_X(unsigned char flag)
{
if (flag == 1)
{
pwm_x += para;
if (pwm_x >18600) //x軸的左邊界
pwm_x = 18600 ;
}
else
{
pwm_x -= para;
if (pwm_x <17600) //x軸的右邊界
pwm_x = 17600;
}
return pwm_x;
}
??其中,para代表著x、y軸兩個舵機每次旋轉(zhuǎn)的角度,通過宏定義,在調(diào)試過程中修改宏定義即可。
5. 總結(jié)
??到這里呢,就算是把我做畢設時的思路寫了下來,也是我寫畢業(yè)論文的思路,總體來說,我在實現(xiàn)追蹤的功能上取巧了,只是能實現(xiàn)簡單的、“粗糙的” 追蹤目標,而沒有使用PID控制,也歡迎大家使用PID控制去實現(xiàn)追蹤的效果,大概的思路差不多:在OpenMv的部分,在識別到目標后,返回物體中心點的橫縱坐標的值,通過串口發(fā)給Stm32,32在收到數(shù)據(jù)后與圖像的中心點坐標進行比較(我用的是320*240,那么中心點坐標就是160,120),將二者的差值作為參數(shù),通過PID控制舵機旋轉(zhuǎn),可以更加準確跟快速的對目標進行追蹤。
另:歡迎大家給出寶貴的意見!
6. 第一次補充(2022.3.12)
6.1 PID控制追蹤
??本次補充的內(nèi)容為:添加了使用PID控制進行動態(tài)追蹤,相比于之前的只是用來比例控制(P)更加的穩(wěn)定和絲滑,這里我就不擴展介紹PID了,感興趣的或是不太了解的小伙伴可以自己去B站搜索一下,那里大佬們講的通俗易懂更好理解一些。
6.2 PID控制代碼部分
??依舊分為兩部分:OpenMV的代碼和STM32的代碼
6.2.1 OpenMV代碼
??相比于之前的OpenMV的代碼,改動的部分僅僅為將串口傳遞的“區(qū)域信息”改為“被測物體中心點的x、y軸坐標”。
...
x = max_blob.cx()
y = max_blob.cy()
...
output_str="%d,%d,%dE" %(x,y,flag) #方式1
uart.write(output_str)
其中:
x: 表示為被測物體的中心點x軸坐標
y: 表示為被測物體的中心點y軸坐標
, : 為英文下的逗號,作為數(shù)據(jù)間的分隔符
flag:為標志位,取值為0,1,2;
flag取值 | 說明 |
---|---|
0 | 表示并沒有識別到物體 |
1 | 識別到物體,但物體沒有在中心區(qū)域 |
2 | 識別到物體,且物體在中心區(qū)域 |
E: 表示數(shù)據(jù)幀的結(jié)束,可以以任何字符作為結(jié)束,本代碼中以’E’為例
6.2.2 STM32代碼
??主要改動為:對串口接收到的數(shù)據(jù)幀處理、PID控制部分
(1)數(shù)據(jù)幀處理
if(str[i-1] == 'E')
{
for(i = 0;str[i] != 'E';i++ )
{
if(str[i] == ',' )
{
if(number_flag == 0)
{
x_long = j; // x的位數(shù)
}
else if (number_flag == 1)
{
y_long = j; // y的位數(shù)
}
number_flag ++;
j = 0;
}
else
{
if(number_flag == 0)
{
x_array[j] = str[i] -'0';
j++;
}
else if(number_flag == 1)
{
y_array[j] = str[i] -'0';
j++;
}
else if(number_flag == 2)
{
RED_flag = str[i] - '0';
}
}
}
if(RED_flag == 1)
{
switch(x_long)
{
case 1 : x_location = x_array[0]; break ;
case 2 : x_location = x_array[0]*10 + x_array[1]; break ;
case 3 : x_location = x_array[0]*100 + x_array[1]*10 + x_array[2]; break ;
default: break ;
}
switch(y_long)
{
case 1 : y_location = y_array[0]; break ;
case 2 : y_location = y_array[0]*10 + y_array[1]; break ;
case 3 : y_location = y_array[0]*100 + y_array[1]*10 + y_array[2]; break ;
default: break ;
}
PID_realize(x_location,y_location); // pid控制
Control_X(pwm_x); // 輸出x軸PWM
Control_Y(pwm_y); // 輸出y軸PWM
}
else
{
PID_init();
}
i = 0;
(2)PID參數(shù)初始化部分
pid_x.Set=160.0; // 圖像x軸的中心位置 本代碼對應OpenMV使用QVGA格式(320*240)所以為160,視情況更改
pid_x.Actual=0.0;
pid_x.err=0.0;
pid_x.err_last=0.0;
pid_x.err_next=0.0;
pid_y.Set=120.0;// 圖像y軸的中心位置
pid_y.Actual=0.0;
pid_y.err=0.0;
pid_y.err_last=0.0;
pid_y.err_next=0.0;
Kp=KP; // 使用宏定義,參數(shù)整定直接對pid.h中的宏定義進行修改即可
Ki=KI; //同上
Kd=KD; //同上
(3)PID控制部分
pid_x.Actual = x;
pid_x.err = pid_x.Set - pid_x.Actual;
float increment_x = Kp*(pid_x.err-pid_x.err_next)+Ki*pid_x.err+Kd*(pid_x.err-2*pid_x.err_next+pid_x.err_last);
pwm_x -=(int)increment_x;
if(pwm_x >= 18500) // 限制x軸舵機的臨界值
pwm_x = 18500;
else if(pwm_x <=17700)
pwm_x = 17700;
pid_x.err_last = pid_x.err_next;
pid_x.err_next = pid_x.err;
pid_y. Actual = y;
pid_y.err = pid_y.Set - pid_y.Actual;
float increment_y = Kp*(pid_y.err-pid_y.err_next)+Ki*pid_y.err+Kd*(pid_y.err-2*pid_y.err_next+pid_y.err_last);
pwm_y += (int)increment_y;
if(pwm_y >= 19100) // 限制y軸舵機的臨界值
pwm_y = 19100;
else if(pwm_y <=18300)
pwm_y = 18300;
pid_y.err_last=pid_y.err_next;
pid_y.err_next=pid_y.err;
6.3 第一次補充總結(jié)
??本來在最初準備做這個畢設的時候,就是準備使用PID進行追蹤的,后來因為時間的原因,取巧只使用比例控制,這次用PID實現(xiàn)了,也算是完成了當時的一個小小的心愿吧。
??最后希望希望諸君共勉吧,哦對了,在寫PID代碼的時候,我突然想到可以在openmv部分加上人臉識別,然后實現(xiàn)追蹤人臉的效果,哈哈哈哈這個我就不一定什么時候做了,算是留一個小小的坑吧,希望以后的我會給這個坑填上。
7. 第二次補充(2022.10.22)
??本次補充內(nèi)容為硬件部分更改為PCB,代碼部分優(yōu)化了OpenMV部分代碼,MCU從STM32F103ZET6替換為STM32F103C8T6,程序部分進行修改和優(yōu)化。加之3D打印的支架,整體較之前更加小巧美觀。
7.1 硬件部分
7.1.1主控PCB
??之前的洞洞板更改為PCB,整體部分看起來更加簡潔,更加小巧,而且將主控從STM32F103ZET6系統(tǒng)板替換為STM32F103C8T6最小系統(tǒng)板,大幅降低成本,除了openmv之外,剩下的器件所有加起來用不到100塊,openmv4 H7官方價格429元,閑魚250-300之間,若是只用openmv做畢設后續(xù)不準備再用了,推薦在閑魚上(或是其他二手途徑),若是過后還準備繼續(xù)深入的了解,我建議在官網(wǎng)上買,若是預算比較充足可以購買H7 plus。主控PCB尺寸:4.8cm*7.48。
PCB示意圖:
實物圖片:
焊接后:
7.1.2 補光板PCB
??為了更準確的識別和追蹤,在不穩(wěn)定的光源下進行補光。
??PCB示意圖:
??實物圖:
7.1.3OPENMV串口擴展板
??主要是連接openmv的串口RX、TX引腳和5v和GND引腳,方便走線。
??PCB示意圖:
7.2 代碼部分
??此次改動追蹤部分使用PID控制,不再使用最開始的分區(qū)域的開環(huán)控制。
7.2.1 openmv部分
??Openmv代碼進行優(yōu)化,去除中間區(qū)域,取消flag = 2 的狀態(tài)。
...
x = max_blob.cx()
y = max_blob.cy()
...
output_str="%d,%d,%dE" %(x,y,flag) #方式1
uart.write(output_str)
其中:
x: 表示為被測物體的中心點x軸坐標
y: 表示為被測物體的中心點y軸坐標
, : 為英文下的逗號,作為數(shù)據(jù)間的分隔符
flag:為標志位,取值為0,1;
flag取值 | 說明 |
---|---|
0 | 沒有識別到物體 |
1 | 識別到物體 |
E: 表示數(shù)據(jù)幀的結(jié)束,可以以任何字符作為結(jié)束,本代碼中以’E’為例。
7.2.2 stm32部分
??由于主控從STM32F103ZET6系統(tǒng)板替換為STM32F103C8T6最小系統(tǒng)板,所以串口和的控制舵機輸出pwm的定時器引腳映射更改:PC6\PC7 ->PA6\PA7,pid部分代碼進行部分優(yōu)化,pid參數(shù)重新整定。新版pid代碼與舊版的pid代碼(zet6)改動并不算大,整體控制感興趣的小伙伴可以自行進行修改。
7.2.3 3D建模
??通過3d打印openmv支架和舵機支架。
??openmv支架:
??舵機支架:
7.4 演示與購買
7.4.1 演示
【畢業(yè)設計】基于STM32及OpenMV的云臺追蹤裝置(升級版)
7.4.2 購買
(1)新版全家桶:【全家桶】基于STM32及OpenMV的云臺追蹤裝置(新版)
??全家桶包含:PCB、3D建模、新版PID代碼(STM32F103C8T6)、加上贈送的一些資料:參考論文(論文為舊版設計的論文)、外文文獻、外文翻譯等等。
(2)新版pid代碼:【代碼】基于STM32及OpenMV的云臺追蹤裝置(新版)
??新版PID代碼的主控為STM32F103C8T6,適用于新版的PCB,不適用舊版的洞洞板設計,新版pid代碼與舊版的pid代碼(zet6)改動并不算大,感興趣的小伙伴可以自行修改。文章來源:http://www.zghlxwxcb.cn/news/detail-408391.html
7.5 第二次補充總結(jié)
??本以為第二次補充會是對人臉進行追蹤,沒想到是更新了硬件,不過用洞洞板確實是比較麻煩,走線看起來還特別的亂,pcb看起來就好太多太多了;主控的話,從zet6替換為c8t6,成本大幅降低,尺寸也大幅降低,當然哈,性能絲毫不受影響;本來我是準備直接使用c8t6芯片,不使用最小系統(tǒng)板的,但是考慮到可能有的小伙伴沒辦法完好無損的焊上LQFP48封裝,所以最后選擇了最小系統(tǒng)板;整體而言,新版設計較舊版的更加的容易復刻,不能說是有手就行,只要是多少用點心,想把畢設做出來,就肯定能復刻出來。
??下一次補充我還是打算做人臉的追蹤,有可能會單獨出一篇博文簡紹。文章來源地址http://www.zghlxwxcb.cn/news/detail-408391.html
到了這里,關于【畢業(yè)設計】基于STM32及OpenMV的云臺追蹤裝置的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!