---
# System prepended metadata

title: Arduino - 小兵立大功-防盜神器
tags: [Arduino]

---

# 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');
  }
  
  
}
```
