回顧
今年暑假基本上待在了學校,一方面是因爲準備出去工作了,爭取再學點東西;另一方面便是準備一下17年8月的全國大學生電子競賽。
賽場是我們學院所在的實驗室,比賽期間幾乎都待在實驗室,甚至於睡覺。
我們選的題目是I組-室內可見光定位,有很多成員貢獻出可行的方案,也逐步嘗試突破。
前言
競賽不僅練就的是承受壓力的能力和團隊協作能力,也是對本身所學知識的總結利用。故在這篇博客中我想對我們組針對電賽I題的解決方案做一些彙總。
因爲通過了廣西區的評比之後,將我們的作品進行了封箱處理,所以在此時我記錄這件事時,沒有辦法提供實物圖樣以及演示效果展示,所以我想盡量詳細地去敘述。
首先這次競賽用到的主要材料有:
OpenMV2
、白光LED燈1w*3
、80cm*80cm木製板*5
、51單片機開發板
、12864LCD液晶顯示屏
正文
① I組題目以及其要求
② 提供方案
- 將
LED燈
放置於頂部三個不同位置,根據不同位置光通信時間差,計算出接收點位置。該方案是首先實行的,但是因爲對硬件性能要求高,比如LED
的頻閃,傳感器的延遲都會導致出現很大的誤差,所以不可行。- 將
LED燈
放於頂部中心,並將底部的接收器做成金字塔樣式,四個面分別貼和放置一個光線強度傳感器,這樣在底部不同位置,根據每個面的不同光照強度,從而判斷底部傳感器所在位置。該方案較爲容易實現,但是受環境影響大,可以判斷傳感器大致所在區域,並不能確定其精確位置。該方案採用了,並作爲一個作品去參與了競賽,拿到了廣西區二等獎。- 採用底部放置攝像頭的方式,說實話是挺鋌而走險的方案。該方案是再頂部面板中心放置單點光源
LED燈
,點亮的LED燈
會在上頂部面板中形成亮斑,而攝像頭則至於底部,用於捕捉該白色色斑,根據其亮斑在採集圖像中的相對位置,計算出底部攝像頭(傳感器)的位置。該方案幫助我們拿到了廣西區一等獎。
② 方案實行
我們採用的是底部放置攝像頭的方案,分爲三個模塊,模塊一是題中要求的LED燈
,我們將三個LED燈
匯聚成一個燈,讓它看起來像是一個亮點,該點放置於頂部面板對角線交點;模塊二是傳感器模塊,我們將傳感器模塊水平放置於底部座標面板上,並且攝像頭的圖像採集照片平面的長寬要和底部面板座標軸平行;模塊三是數據顯示模塊,我們是用51單片機開發板結合12864LCD液晶顯示器,通過串口接收數據,實現在屏幕上實時刷新當前座標位置。
注意點:
1. 實物搭建,木製板80*80cm*5
塊形成立方體,內壁貼滿黑色表面磨砂紙,可用於較少外界光以及立方體內LED
燈反光干擾。
2. 是捕捉白色色斑,我們設置爲捕捉單點最亮白色色塊,因爲五面立方體,有一面暴露與室外環境,故室外光線太強會導致目標色斑捕捉錯誤。故我們將三個LED燈
匯聚成一點,增強光照強度,即使在外界光照較爲強烈的情況下也不會產生干擾。
③ 具體代碼以及詳解
在OpenMV開發板中寫入的代碼
更多教程可以參考@雲江科技的教程:【直達鏈接】
import sensor, image, time
from pyb import UART
uart = UART(3, 9600) #設置爲串口3、波特率爲9600發送數據
thresholds = (245, 255) #設置監測色塊閾值
sensor.reset() #攝像頭初始化
sensor.set_pixformat(sensor.GRAYSCALE) #設置爲灰度模式
sensor.set_framesize(sensor.QQVGA) #畫幅爲QQVGA即分辨率爲160*120
sensor.skip_frames(time = 2000) #跳過起始畫面,獲取穩定圖像
sensor.set_auto_gain(False) #在色塊檢測模式下關閉自動補光
sensor.set_auto_whitebal(False) #關閉白平衡
clock = time.clock()
xPositionNow = 0 # 初始化各座標值
yPositionNow = 0
xPositionLast = 0
yPositionLast = 0
imageSize = 128
while(True):
clock.tick()
img = sensor.snapshot() #獲取當期所採集到的圖像快照
# 設置色塊閾值,具體數值情況可以通過OpenMVIDE中的閾值調整功能來得出
# 工具 → Mechine Vision → Threshold Editor
# area_threshold面積閾值設置爲100 ,如果色塊被面積小於100,則會被過濾掉
# pixels_threshold 像素個數閾值,如果色塊像素數量小於這個值,會被過濾掉
# merge 設置爲True,合併所有重疊的尋找到的blob爲一個色塊
for blob in img.find_blobs([thresholds], pixels_threshold=100, area_threshold=100, merge=True):
# 繪製相應的圖形,方便我們測試的時候使用
img.draw_rectangle(blob.rect())
img.draw_cross(blob.cx(), blob.cy())
x = blob.cx() - (imageSize/2)
y = (imageSize/2) - blob.cy()
xPositionLast = xPositionNow
yPositionLast = yPositionNow
# 這個0.7的數值不固定,只是在調試的時候爲了使得像素點和座標單位cm匹配所設置的數值
xPositionNow = x * 0.7
yPositionNow = y * 0.7
# 測試時打印出當前座標
print(xPositionNow, yPositionNow, end = ',')
# 通過串口將座標數據發送給單片機處理,實際上發送的就是一段文本
uart.write(',' + str(xPositionNow) + ',' + str((-1)*yPositionNow) + ',')
# 判斷當前所在區域(A\B\C\D)
if abs(xPositionNow) < 20 and abs(yPositionNow) < 20:
uart.write('A\n')
print('A')
elif yPositionNow < -20 and yPositionNow < xPositionNow and (-1)*yPositionNow > xPositionNow:
uart.write('B\n')
print('B')
elif xPositionNow > 20 and (-1)*yPositionNow < xPositionNow and yPositionNow < xPositionNow:
uart.write('C\n')
print('C')
elif yPositionNow > 20 and xPositionNow < yPositionNow and (-1)*xPositionNow < yPositionNow:
uart.write('D\n')
print('D')
else:
uart.write('E\n')
print('E')
# 0.5s更新一下座標數據
time.sleep(500)
在作爲顯示設備的51單片機中寫入的代碼
在這裏51單片機
+LCD12864液晶屏
只是作爲一個顯示設備,只需要顯示串口接收到的數據,需要注意的是波特率的一致,串口接收到的數據將會處理成亂碼。之前的原代碼沒有能找到了,找到了之前做GPS定位
項目時的代碼,作爲顯示設備可以通用,現在貼上代碼:
#include<reg52.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#define uchar unsigned char
#define uint unsigned int
#define Buf_Max 80
#define GPS_Buffer_Length 80
#define gpsRxBufferLength 76
#define false 0
#define true 1
sbit led1 = P1^1;
sbit led2 = P1^2;
bit flag = 1;
typedef struct SaveData
{
char GPS_Buffer[GPS_Buffer_Length];
char isGetData; //是否獲取到GPS數據
char isUsefull; //定位信息是否有效
} xdata _SaveData;
char idata gpsRxBuffer[gpsRxBufferLength];
uchar RX_Count = 0;
_SaveData Save_Data;
char tempr;
#include "uart.h"
#include "lcd.h"
/*********初始化函數*********/
void init()
{
TMOD=0x20; //設定定時器T1工作方式2
PCON=0x00; //串口波特率正常9600,不加倍;
SCON=0x50; //藍牙串口工作方式爲3
TH1=0xfd; //T1定時器裝初值
TL1=0xfd; //T1定時器裝初值
TR1=1; //啓動T1定時器
REN=1; //允許串口接收
SM0=0; //設定串口工作方式1
SM1=1; //設定串口工作方式1
EA=1; //開總中斷
ES=1; //開串口中斷
EX1=1;
}
/***********主函數**********/
void main()
{
init(); //初始化
lcd_init();
flag = 0;
while(1)
{
printfGps();
// write_cmd(0x01);
}
}
void sint() interrupt 4
{
ES=0;
if(RI == 1 && flag == 0)
{
RI=0;
tempr=SBUF;
if(tempr == '\n')
{
memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length); //清空
memcpy(Save_Data.GPS_Buffer, gpsRxBuffer, RX_Count); //保存數據
Save_Data.isGetData = true;
RX_Count = 0;
memset(gpsRxBuffer, 0, gpsRxBufferLength); //清空
gpsRxBuffer[RX_Count] = '\0';//添加結束符
}
else
{
gpsRxBuffer[RX_Count++] = tempr;
}
}
ES=1;
}
寫在最後
發現寫博客雖然對鞏固知識很有幫助,但是有時候真是一件費時費力的事情,本來計劃詳細講解一下過程,分享一下經驗。又因爲馬上要出學校開始找工作了,所以覺得時間完全不夠用啊,包括寫這篇博文記錄一下,中間也是跨了一個多月的時間才重新總結,所以想想先把分析思路和主要代碼貼出來,關於更多具體的分析,之後有時間的話再進行更新吧。
這樣子算寫了半個總結了吧~~~