為參加今年的工訓大賽,本人自學32和openmv,雖不深不才但學有所獲,雖結果不盡人意,但能思其所以,再之csdn教會了我很多,也想發表一下自己的芝麻設計,希望能給讀者帶來一些思考和靈感,水平有限希望理解,備注:侵立刪!
以下是openmv的巡線和識別一體化程式設計:
# 基于openmv與stm32串口通信的巡線+識別 - By:水下管道機器人智能控制設計者付智輝
#1 - 周四 12月 17 2020
import sensor, image, time, math
from pyb import UART
sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.set_framesize(sensor.QQVGA)
# _____________________________________________________________________________
#規定串行通信組合為
#turn_right=bytearray([0xb2,0xb3,0xb1,0x0d,0x0a])
#turn_left=bytearray([0xb2,0xb3,0xb2,0x0d,0x0a])
#find_red=bytearray([0xb2,0xb3,0xb3,0x0d,0x0a])
#find_green=bytearray([0xb2,0xb3,0xb4,0x0d,0x0a])
#find_black=bytearray([0xb2,0xb3,0xb5,0x0d,0x0a])
#find_blue=bytearray([0xb2,0xb3,0xb6,0x0d,0x0a])
#find_circle=bytearray([0xb2,0xb3,0xb7,0x0d,0x0a])
#find_rectangle=bytearray([0xb2,0xb3,0xb8,0x0d,0x0a])
#
#_____________________________________________________________________________
uart = UART(3,115200)
uart.init(115200,bits=8,parity=None,stop=1)
turn_right=bytearray([0xb2,0xb3,0xb1,0x0d,0x0a])
turn_left=bytearray([0xb2,0xb3,0xb2,0x0d,0x0a])
find_red=bytearray([0xb2,0xb3,0xb3,0x0d,0x0a])
find_green=bytearray([0xb2,0xb3,0xb4,0x0d,0x0a])
find_black=bytearray([0xb2,0xb3,0xb5,0x0d,0x0a])
find_blue=bytearray([0xb2,0xb3,0xb6,0x0d,0x0a])
find_circle=bytearray([0xb2,0xb3,0xb7,0x0d,0x0a])
find_rectangle=bytearray([0xb2,0xb3,0xb8,0x0d,0x0a])
white_threshold_01 = ((95, 100, -18, 3, -8, 4)); #白色閾值
black_threshold_01 = ((0, 15, -24, -1, -18, 6)); #黑色閾值
red_threshold_01 = ((35, 100, 41, 77, 24, 59));#紅色閾值
green_threshold_01 = ((50, 100, -80, -20, 8, 20));#綠色閾值
blue_threshold_01 = ((20, 100, -18, 18, -80, -30));#藍色閾值
#設定是否使用img.binary()函式進行影像分割
BINARY_VISIBLE = True
# _________________________________________________________________________________
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
sensor.skip_frames(time = 2000)
clock = time.clock()
while(True):
THRESHOLD = (190, 255)
sensor.set_auto_whitebal(False)#關閉白平衡
clock.tick()
img = sensor.snapshot().binary([THRESHOLD]) if BINARY_VISIBLE else sensor.snapshot()
img.draw_rectangle(130, 85, 30, 35, color = (0, 0, 0), thickness = 2, fill = True)
line = img.get_regression([(255,255) if BINARY_VISIBLE else THRESHOLD])
if (line):
img.draw_line(line.line(), color = 127)
theta = int(line.theta())
x = int ( (line.x1()+line.x2())/2)
print("find line")
if line.magnitude() >= 1:
print(theta,x) #x的中值大概是60
if theta>100:
print("turn_right!")
uart.write(turn_right)
elif theta<80:
print("turn_left!")
uart.write(turn_left)
else:
print("go straight!")
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False)
clock = time.clock()
clock.tick() # Track elapsed milliseconds between snapshots().
img = sensor.snapshot() # Take a picture and return the image.
# pixels_threshold=100, area_threshold=100
blobs = img.find_blobs([red_threshold_01], pixels_threshold=100, area_threshold=100, merge=True, margin=10);
blobs1 = img.find_blobs([green_threshold_01], pixels_threshold=100, area_threshold=100, merge=True, margin=10);
blobs2 = img.find_blobs([blue_threshold_01], pixels_threshold=100, area_threshold=100, merge=True, margin=10);
blobs3 = img.find_blobs([black_threshold_01], pixels_threshold=100, area_threshold=100, merge=True, margin=10);
cx=0;cy=0;cx1=0;cy1=0;cx2=0;cy2=0;
if blobs:
#如果找到了red
max_b = find_max(blobs);
# Draw a rect around the blob.
img.draw_rectangle(max_b[0:4]) # rect
#用矩形標記出目標顏色區域
img.draw_cross(max_b[5], max_b[6]) # cx, cy
img.draw_cross(160, 120) # 在中心點畫標記
#在目標顏色區域的中心畫十字形標記
cx=max_b[5];
cy=max_b[6];
img.draw_line((160,120,cx,cy), color=(127));
#img.draw_string(160,120, "(%d, %d)"%(160,120), color=(127));
img.draw_string(cx, cy, "(%d, %d)"%(cx,cy), color=(127));
print("找到紅色!")
uart.write(find_red)
sensor.reset() #初始化設定
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA)#設定為彩色設定清晰度sensor.set_framesize(sensor.SVGA)
sensor.skip_frames(time = 2000) #跳過前2000ms的影像
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() #創建一個clock便于計算FPS,看看到底卡不卡
sensor.set_auto_gain(False) # 關閉自動自動增益,默認開啟的,
sensor.set_auto_whitebal(False) #關閉白平衡,在顏色識別中,一定要關閉白平衡,
clock.tick()
img = sensor.snapshot().lens_corr(1.8) #拍攝一張照片,lens_corr函式用于非魚眼畸變矯正,默認設定引數為1.8,
for blob in img.find_blobs([black_threshold_01], pixels_threshold=100, area_threshold=100, merge=True, margin=10):
#openmv自帶的尋找色塊函式,img.find_blobs([red_threshold_01], pixels_threshold=100, area_threshold=100, merge=True, margin=10);
#pixels_threshold是像素閾值,面積小于這個值的色塊就忽略blobs4 = img.find_blobs([thresholds], pixels_threshold=100, area_threshold=100, merge=True, margin=10);
#roi是感興趣區域,只在這個區域內尋找色塊 if blobs4:
#are_threshold是面積閾值,如果色塊被框起來的面積小于這個值,會被過濾掉
print('該形狀占空比為',blob.density())
#density函式可以自動回傳色塊面積/外接矩形面積這個值
if blob.density()>0.805:#理論上矩形和他的外接矩形應該是完全重合
#但是測驗時候發現總會有偏差,多次試驗取的這個值,下面圓形和三角形亦然
print("檢測為長方形 ",end='')
uart.write(find_rectangle)
elif blob.density()>0.65:
print("檢測為圓 ",end='')
uart.write(find_circle)
else:
print("no dectedtion")
elif blobs2:
#如果找到了blue
max_b = find_max(blobs2);
# Draw a rect around the blob.
img.draw_rectangle(max_b[0:4])
img.draw_cross(max_b[5], max_b[6])
img.draw_cross(160, 120)
cx2=max_b[5];
cy2=max_b[6];
img.draw_line((160,120,cx2,cy2), color=(127));
#img.draw_string(160,120, "(%d, %d)"%(160,120), color=(127));
img.draw_string(cx2, cy2, "(%d, %d)"%(cx2,cy2), color=(127));
print("找到藍色!")
uart.write(find_blue)
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False)
sensor.set_auto_whitebal(False)
clock = time.clock()
sensor.set_auto_gain(False)
sensor.set_auto_whitebal(False)
clock.tick()
img = sensor.snapshot().lens_corr(1.8)
for blob in img.find_blobs([black_threshold_01], pixels_threshold=100, area_threshold=100, merge=True, margin=10):
print('該形狀占空比為',blob.density())
if blob.density()>0.805:
print("檢測為長方形 ",end='')
uart.write(find_rectangle)
elif blob.density()>0.65:
print("檢測為圓 ",end='')
uart.write(find_circle)
print('圓形半徑',(blob.w()+blob.h())/4)
else:
print("no dectedtion")
elif blobs3:
#如果找到了black
max_b = find_max(blobs3);
# Draw a rect around the blob.
img.draw_rectangle(max_b[0:4])
img.draw_cross(max_b[5], max_b[6])
img.draw_cross(160, 120)
cx2=max_b[5];
cy2=max_b[6];
img.draw_line((160,120,cx2,cy2), color=(127));
#img.draw_string(160,120, "(%d, %d)"%(160,120), color=(127));
img.draw_string(cx2, cy2, "(%d, %d)"%(cx2,cy2), color=(127));
print("找到黑色!")
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False)
sensor.set_auto_whitebal(False)
clock = time.clock()
sensor.set_auto_gain(False)
sensor.set_auto_whitebal(False)
clock.tick()
img = sensor.snapshot().lens_corr(1.8)
for blob in img.find_blobs([black_threshold_01], pixels_threshold=100, area_threshold=100, merge=True, margin=10):
print('該形狀占空比為',blob.density())
if blob.density()>0.805:
print("檢測為長方形 ",end='')
uart.write(find_rectangle)
elif blob.density()>0.65:
print("檢測為圓 ",end='')
uart.write(find_circle)
else:
print("no dectedtion")
else:
print("沒找到!")
print(clock.fps())
sensor.reset() #初始化設定
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.set_framesize(sensor.QQVGA)
sensor.set_auto_whitebal(False)#關閉白平衡
sensor.set_auto_gain(True)
else:
print("not line!")
以下是stm32串口通信服務程式:
#include "sys.h"
#include "usart.h"
#include "led.h"
#include "delay.h"
#include "stdio.h"
#include "motor.h"
//
//如果使用ucos,則包括下面的頭檔案即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h" //ucos 使用
#endif
#if 1
#pragma import(__use_no_semihosting)
//標準庫需要的支持函式
struct __FILE
{
int handle;
};
FILE __stdout;
//定義_sys_exit()以避免使用半主機模式
_sys_exit(int x)
{
x = x;
}
//重定義fputc函式
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//回圈發送,直到發送完畢
USART1->DR = (u8) ch;
return ch;
}
#endif
#if EN_USART1_RX //如果使能了接收
//串口1中斷服務程式
//注意,讀取USARTx->SR能避免莫名其妙的錯誤
u8 USART_RX_BUF[USART_REC_LEN]; //接識訓沖,最大USART_REC_LEN個位元組.
//接收狀態
//bit15, 接收完成標志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效位元組數目
u16 USART_RX_STA=0; //接收狀態標記
u8 t;
u8 len;
u16 times=0;
u8 date[4];
void uart_init(u32 bound){
//GPIO埠設定
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA時鐘
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//搶占優先級3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子優先級3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根據指定的引數初始化VIC暫存器
//USART 初始化設定
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長為8位資料格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//無奇偶校驗位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無硬體資料流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開啟串口接受中斷
USART_Cmd(USART1, ENABLE); //使能串口1
}
void USART1_IRQHandler(void) //串口1中斷服務程式
{
u8 Res;
#if SYSTEM_SUPPORT_OS
OSIntEnter();
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中斷(接收到的資料必須是0x0d 0x0a結尾)
{
Res =USART_ReceiveData(USART1); //讀取接收到的資料
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//接收錯誤,重新開始
else USART_RX_STA|=0x8000; //接收完成了
}
else //還沒收到0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收資料錯誤,重新開始接收
}
}
}
if(USART_RX_STA&0x8000)
{
MOTOR_FORWARD_OFF();
len=USART_RX_STA&0x3fff;//得到此次接收到的資料長度
for(t=0;t<len;t++)
{
date[t]=USART_RX_BUF[t];
}
/* openmv的通信碼:
turn_right=bytearray([0xb2,0xb3,0xb1,0x0d,0x0a])
turn_left=bytearray([0xb2,0xb3,0xb2,0x0d,0x0a])
find_red=bytearray([0xb2,0xb3,0xb3,0x0d,0x0a])
find_green=bytearray([0xb2,0xb3,0xb4,0x0d,0x0a])比賽只用藍色紅色黑色
find_black=bytearray([0xb2,0xb3,0xb5,0x0d,0x0a])
find_blue=bytearray([0xb2,0xb3,0xb6,0x0d,0x0a])
find_circle=bytearray([0xb2,0xb3,0xb7,0x0d,0x0a])
find_rectangle=bytearray([0xb2,0xb3,0xb8,0x0d,0x0a])
*/
if(date[2]==0xb1)//需右轉//
{
MOTOR_FORWARD_OFF();
MOTOR_RIGHT_ON();
delay_ms(50000);
MOTOR_RIGHT_OFF();
}
else if(date[2]==0xb2)//需左轉//
{
MOTOR_FORWARD_OFF();
MOTOR_LEFT_ON();
delay_ms(50000);
MOTOR_LEFT_OFF();
}
else if(date[2]==0xb3)//找到紅色//
{
LEDR1_ON;
delay_ms(50000);
LEDR1_OFF;
}
/*初賽不用
else if(date[2]==0xb4)//找到綠色//
{
LEDG1_ON;
delay_ms(50000);
LEDG1_OFF;
}
else if(date[2]==0xb5)//找到黑色//
{
LEDB2_ON;
delay_ms(50000);
LEDB2_OFF;
}
*/
else if(date[2]==0xb6)//找到藍色//
{
LEDB1_ON;
delay_ms(50000);
LEDB1_OFF;
}
else if(date[2]==0xb7)//找到圓//
{
LEDR2_ON;
delay_ms(50000);
LEDR2_OFF;
}
else if(date[2]==0xb8)//找到方//
{
LEDG2_ON;
delay_ms(50000);
LEDG2_OFF;
}
USART_RX_STA=0;//消除中斷標志位
}
}
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS為真,則需要支持OS.
OSIntExit();
#endif
}
#endif
關于船體轉彎是通過觸碰開關引發單片機外部中端,進入中斷程式,引起左右電機轉動轉彎,時間可調,如何歸位管道,通過openmv的直線識別,如以上程式,船體上升下淺可通過針筒排水進水改變船體重量實作,



最后感謝符同學和王同學的辛苦付出,為青春干杯🍻,走好正確的路,自己的世界才是真正光明的,才能真正談自己有世界,20.12.26
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/240884.html
標籤:其他
下一篇:5G + 邊緣計算系列文章
