# Arduino - 小兵立大功-防盜神器 ###### tags: `Arduino` [Arduino作品目錄](https://hackmd.io/KH0oMN6ZSiuiogFCy5s_mA) ## 概念簡述 設計一個包包中的防盜裝置,透過偵測與手機的距離來判別使用者是否在身邊。 + 手機上的App會一直發出藍牙訊號來讓防盜裝置確認使用者位置。 + 如果使用者在裝置附近並持續收到訊號,則繼續待機; + 如果使用者遠離裝置而收不到手機訊號,則進入防盜模式; + 防盜模式下倘若包包被拿走,則發出警報聲。 ## 功能設計 ### §套件需求 1. 藍牙模組 HC-05 2. 陀螺儀與三軸加速器 MPU6050(GY-521) 3. 蜂鳴器模組 ### §功能描述 :::info #### 防盜裝置部分: + 透過`藍牙模組hc-05` 來與手機app做藍牙訊號的溝通,以判定使用者是否在身邊。 + `MPU6050`用來偵測防盜模式下裝置是否有晃動,以此判定是否被他人偷走包包。 + 蜂鳴器模組用來發出警報聲 #### 手機APP部分: + APP能與防盜裝置上的HC05套件建立藍牙連接 + 建立藍牙連接後持續發送訊息,讓防盜裝置判定使用者位置 + 可以在警報模式時發送訊息,讓防盜裝置取消警報 ::: ### §邏輯設計 從功能描述中可以得知,防盜裝置主要有3種模式: ``` 1.待機模式: 會持續偵測手機APP的藍牙訊號,如果收不到訊號則進入防盜模式。 2.防盜模式: 持續偵測手機APP的藍牙訊號,如果收到訊號則回到待機模式;持續透過偵測防盜裝置是否晃動, 如果晃動則進入警報模式。 3.警報模式: 持續發出警報,如果收到手機解除警報訊號會立刻解除警報, ``` 手機APP部分: ``` 1.搜尋與選擇附近藍牙訊號。 2.建立藍牙連線後,持續對藍牙套件發出待機模式訊號。 3.藍牙斷線後,持續搜尋附近訊號來嘗試與該套件建立連線。 主要應對於短暫離開包包後回到包包身邊的狀況。讓防盜裝置回到待機狀態。 4.可以在防盜裝置發出警報時,送出藍牙訊號來解除警報。這裡須注意與待機模式的訊號衝突。 ``` ### §示意圖 #### 防盜裝置 ```mermaid graph TD; A(偵測訊號)-->|收到APP待機訊號|B(待機模式) A(偵測訊號)-->|收不到APP訊號|C(防盜模式) B-->|收不到APP訊號|C C-->|偵測到晃動|D(警報模式) C-->|收到APP待機訊號|B(待機模式) D-->|收到APP解除警報訊號|A ``` #### 手機APP :::warning 由於當時寫APP所使用的APP inventor對於背景程式支援性較差,需要用到多個計時器來實現持續訊號發送的功能。實現的手段較為複雜,此處就不做展示,僅須了解APP的作用即可。 ::: ![](https://drive.google.com/u/2/uc?id=1mb9JuoDwZAkQqqT7JK0jpfwUKMcoB6yj&export=download ) ## 認識 Arduino 模組 ### (P)藍牙模組 HC05 + 用於實現手機與防盜裝置的連線 + 連線後手機便可接收訊號判別防盜裝置現在的模式 + 藍牙端可以接收手機訊號來依照設計改變模式 #### 接腳配置 ||HC05|UNO板| |:------:|:------:|:------:| |正電源|VCC|5V| |接地|GND|GND| |資訊傳輸|TXD|RXD| |資訊傳輸|RXD|TXD| :::danger ### :zap: HC05鮑率必須正確設置才能在不同模式與其他裝置連接 #### AT指令設置 + HC05藍牙模組在使用前必須先進入AT模式設置一系列指令,才能正常使用 >建議參考以下兩篇文章來進行操作 >[七月DM]手机控制+HC-05蓝牙+Arduino.干货! https://www.bilibili.com/video/BV16T4y1w79Z >[趙珩宇(HENRY)][Arduino實用] HC-05 AT mode主從配對 https://livingtech.education/2018/06/03/arduino%E5%AF%A6%E7%94%A8-hc-05-at-mode%E4%B8%BB%E5%BE%9E%E9%85%8D%E5%B0%8D/ ```cpp= BTSerial.begin(9600); ``` + **ATMODE時** + HC-05鮑率=38400 + **AT設置好後,手機傳輸訊號時** + HC-05鮑率=9600 ::: ![](https://drive.google.com/u/2/uc?id=1MB1qCAXYtLWqEpQDv5hO9GNJnwUZ4f0N&export=download ) [圖片來源: 超圖解Arduino互動設計入門](https://swf.com.tw/?p=693) ___ ### (P)陀螺儀與三軸加速器 + 用來偵測搖晃,在防盜模式下晃動便可進入警報模式 + 透過偵測 x,y,z軸加速度,本設計為計算1.5秒內加速度變化度 + 需要焊接才能使用,否則用沾黏的方式會比較麻煩 + 可參考下圖,基本上用那排接腳裝上去後會有空隙,所以需要焊接 ![](https://drive.google.com/u/2/uc?id=1n1Dk3oeK6VljVlUhcowX3H8saQsjrurL&export=download ) #### 接腳配置 ||MPU6050 (GY-521)|UNO板| |:------:|:------:|:------:| |正電源|VCC|5V| |接地|GND|GND| |時脈線|SDA|A4(SDA)| |數據線|SCL|A5(SCL)| ___ ### (P)蜂鳴器 + 發出警報 ||蜂鳴器|UNO板| |:------:|:------:|:------:| |正電源|VCC|5V| |接地|GND|GND| |資訊傳輸|I/O|D2| ## 參考文章 ### MPU6050 MPU6050 datasheet https://pdf1.alldatasheet.com/datasheet-pdf/download/517744/ETC1/MPU-6050.html ### HC05 [七月DM]手机控制+HC-05蓝牙+Arduino.干货! https://www.bilibili.com/video/BV16T4y1w79Z [趙珩宇(HENRY)][Arduino實用] HC-05 AT mode主從配對 https://livingtech.education/2018/06/03/arduino%E5%AF%A6%E7%94%A8-hc-05-at-mode%E4%B8%BB%E5%BE%9E%E9%85%8D%E5%B0%8D/ HC-05 Bluetooth module not recognized by mobile phone https://electronics.stackexchange.com/questions/67739/hc-05-bluetooth-module-not-recognized-by-mobile-phone ## 程式碼 ### (P)以手機接收訊號來辨別模式 由於此裝置需要與手機保持溝通,所以在此設計一些輸出訊號,來讓手機輔助判別裝置狀態,方便用來除錯。 :::info a : 偵測手機輸入訊號中... b : 進入待機模式... c : 跳出待機模式... d : 目前為待機模式... ___ e: 進入防盜模式... f: 跳出防盜模式... g: 目前為防盜模式... h: 偵測搖晃中,需要3秒... ___ i: 進入警報模式 j: 跳出警報模式. k: 目前為警報模式,可以輸入b跳出此模式... ::: + 實際套件組合完成後的接腳配置以程式碼為主 ```cpp= #include <Wire.h> #include <MPU6050.h> #include <SoftwareSerial.h> //藍牙 SoftwareSerial BTSerial(10, 11); // RX | TX //三軸加速器+三軸陀螺儀 MPU6050 MPU6050 mpu; //蜂鳴器 int buzzer_pin=2;//設pin8設定為UNO對蜂鳴器的輸出接腳 void setup() { //Serial初始化 Serial.begin(9600); //藍牙部分初始化 Serial.println("初始化 藍牙HC05...\n"); pinMode(9, OUTPUT); // this pin will pull the HC-05 pin 34 (key pin) HIGH to switch module to AT mode digitalWrite(9, HIGH); BTSerial.begin(9600); // HC-05 default speed in AT command more //MPU6050初始化 Serial.println("初始化 三軸加速器+三軸陀螺儀...\n"); while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G)) { Serial.println("三軸加速器+三軸陀螺儀無反應!\n"); delay(500); } //蜂鳴器初始化 Serial.println("初始化 蜂鳴器...\n"); pinMode( buzzer_pin,OUTPUT);//設定腳位,將UNO板的pin8設定為輸出 } //重新判定當前模式 void loop() { int mode= detectMode(); gotoMode(mode); } //偵測訊號 int detectMode() { //偵測五次來決定當前訊號 char mode_msg=detectFiveTimes(); switch(mode_msg) { //有讀取到訊號,待機模式 case 'a' : return 1; break; //讀取到NULL,表示藍牙斷線,防盜模式 case 'n' : return 2; break; default: Serial.println("收到無效切換模式訊息...\n"); Serial.println(mode_msg); delay(200); break; }//switch }//detectMode //偵測一段時間來判定輸入訊號 char detectFiveTimes() { int countNULL=0; int countA=0; int countB=0; char readinput='q'; while(true) { Serial.println("偵測手機輸入訊號中...需要6.5秒....\n"); BTSerial.println('a'); countNULL=0; countA=0; countB=0; for (int i=0;i<5;i++) { delay(1300); char readinput=BTSerial.read(); switch(readinput) { case 'a': countA+=1; break; case 'b': countB+=1; break; default: countNULL+=1; break; }//switch }//for if(countA>=3) return 'a'; else if(countB>=3) return 'b'; else if(countNULL>=5) return 'n'; }//while } //進入模式 void gotoMode(int mode) { switch(mode) { case 1: MODE1(); break; case 2: MODE2(); break; default: Serial.println("進入模式時,意外狀況發生...\n"); break; } } //待機模式 void MODE1() { Serial.println("進入待機模式...\n"); BTSerial.println('b'); while(true) { char receiveA=detectFiveTimes(); if(receiveA!='a') { Serial.println("跳出待機模式..."); BTSerial.println('c'); break; } else { Serial.println("目前為待機模式...\n"); BTSerial.println('d'); } } } //防盜模式 void MODE2() { Serial.println("進入防盜模式...\n"); BTSerial.println('e'); while(true) { char receiveA=detectFiveTimes(); if(receiveA=='a') { Serial.println("跳出防盜模式...\n"); BTSerial.println('f'); break; } else { Serial.println("目前為防盜模式...\n"); BTSerial.println('g'); } //偵測搖晃 if(detectStable()==false) { MODE3(); break; //之後警報模式解除後回來此行,也要跳出防盜模式 } } } //搖晃偵測 bool detectStable() { Serial.println("偵測搖晃中,需要3秒...\n"); BTSerial.println('h'); bool flag=true; Vector rawAccel = mpu.readRawAccel(); Vector normAccel = mpu.readNormalizeAccel(); float lastX=normAccel.XAxis; float lastY=normAccel.YAxis; float lastZ=normAccel.ZAxis; float variationX=0; float variationY=0; float variationZ=0; for (int i=0;i<5;i++) { rawAccel = mpu.readRawAccel(); normAccel = mpu.readNormalizeAccel(); float currentX=normAccel.XAxis;; float currentY=normAccel.YAxis;; float currentZ=normAccel.ZAxis;; variationX+= abs(currentX-lastX); variationY+= abs(currentY-lastY); variationZ+= abs(currentZ-lastZ); Serial.print(lastX); Serial.print(" "); Serial.print(lastY); Serial.print(" "); Serial.println(lastZ); lastX=currentX; lastY=currentY; lastZ=currentZ; delay(600); } if(variationX>1.5||variationY>1.5||variationZ>1.5) { flag=false; } return flag; } //警報模式 void MODE3() { Serial.println("進入警報模式...\n"); BTSerial.println('i'); while(true) { tone( buzzer_pin,523); char receiveB=detectFiveTimes(); if(receiveB=='b') { noTone( buzzer_pin); Serial.println("跳出警報模式...\n"); BTSerial.println('j'); break; } delay(500); Serial.println("目前為警報模式,可以輸入b跳出此模式...\n"); BTSerial.println('k'); } } ```