高通台灣AI黑客松|競賽說明會
|

【Tutorial】3步成師:無線電地震傾斜感測器DIY教學

   

作者:賴桑

台灣座落於地殼頻繁變動的環太平洋地震帶,近年來板塊運動似乎是越來越頻繁,前一陣子在台灣花蓮地區發生大地震,甚至造成部分地區嚴重的損害與傷亡。面對這樣的環境,若有一台可以及時感測的設備,不僅能提前預防災害,對於人們的日常生活安全也將大大提升!

前陣子參加活動時,正巧遇見出席的我們漁客松2018比賽的隊友郭振聲大大。聊天的過程中,郭振聲大大說到感覺他家附近的房屋好像「越看越近」?這是怎麼一回事?!恰巧,我認識一個台北科技大學的學弟沈志全,正是這方面的專家!沈志全學弟說如果要做到像專業土木測量,恐怕不能只用一般的感測器,專業測量需要有傾斜計、雷達等其他輔助的感測裝置。

這便給了我一個靈感:「如果能在周遭布置很多可以感測震動的裝置,固定時間間隔內傳回所感測到的震動狀況,那像是土石流、土壤鬆動與液化、建築物受外力影響的穩定狀況…是不是就可以因為分析這些震動狀況來得知自己所在地的安全呢?」

除了拿本身已經有Sigfox低功耗無線電網路的UnaShield V2S以外,我又附加一個加速度計在上頭,恰好合用!然後用Sigfox後台的Callback程序把震動的感測記錄傳給QBoat Sunny,這樣就形成一個簡單的功能雛型了!嘿嘿嘿,幫別人解決問題的時候,說不定是連自己都幫到XD~~

所需材料

  1. QBoat Sunny一台
  2. UnaShield V2S一個
  3. Arduino Uno一組

原理

UnaShield V2S上已經附有MMA8451這個加速度計,所以我的做法就是每0.2秒求三個軸上的變量,然後求100次以下公式的總和,其中x’、y’、z’三個代表上一個0.2秒時XYZ三軸各自的讀值。

 

接著求平均,三次平均再放進Buffer;等到Buffer中10次的平均值已經滿了就Uplink到Sigfox backend,周而復始。

Arduino Uno上的程式

#include <Wire.h> #include <SPI.h> #include <SoftwareSerial.h>

#include “SIGFOX.h” // Include the unabiz-arduino library. static const String device = “g88pi”; // Set this to your device name if you’re using UnaBiz Emulator. static const bool useEmulator = false; // Set to true if using UnaBiz Emulator. static const bool echo = true; // Set to true if the Sigfox library should display the executed commands. static const Country country = COUNTRY_TW; // Set this to your country to configure the Sigfox transmission frequencies. static UnaShieldV2S transceiver(country, useEmulator, device, echo);

#include <Adafruit_MMA8451.h> #include <Adafruit_Sensor.h>

Adafruit_MMA8451 mma = Adafruit_MMA8451();

static long prev_x, prev_y, prev_z, x, y, z;

/* * 1 Sigfox Send every 10 min = 600,000 ms * 600,000 / 10 (snapshot every 1 min) = 60,000 readings * 60,000 / 200 (sampling rate) = 300 readings * 300 / 150 (data buffer len) = 2 avg_reading (can’t read all 300 reading because it somehow breaks the module sending capability…) */

#define DELAY_TIME 200 // Sampling delay in ms (= 200ms) #define DATA_LEN 100 // BUFF_LEN * DTA_LEN * DELAY_TIME(ms) plus delay time

static unsigned int delta[DATA_LEN]; static int delta_index=0;

#define AVG_LEN 3 static int avg[AVG_LEN]; static int avg_index=0;

#define BUFF_LEN 10 // For each sense is about DELAY_TIME milisecond static int buff[BUFF_LEN]; static int buff_index=0;

//#define coff 1 // The value to multiply #define coff 0.025 // 9999 / 255 is about 1/40=0.025

long duration; int distance;

void setup() { Serial.begin(9600);

if (!transceiver.begin()) stop(F(“Unable to init Sigfox module, may be missing”));

if (! mma.begin(0x1c)) { //// // NOTE: Must use 0x1c for UnaShield V2S Serial.println(F(“Cannot start G-sensor”)); while (1); }

mma.setRange(MMA8451_RANGE_2_G); mma.setDataRate(MMA8451_DATARATE_800_HZ);

// Set up the varibles prev_x = prev_y = prev_z = 0;

delay(DELAY_TIME); // Wait for G-sensor

transceiver.sendMessage(“01”); // Send start up message }

void sendSigfox() { Serial.println();

char str[24]; sprintf( str, “%02d%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X”, 2, (int) round(buff[0] * coff), (int) round(buff[1] * coff), (int) round(buff[2] * coff), (int) round(buff[3] * coff), (int) round(buff[4] * coff), (int) round(buff[5] * coff), (int) round(buff[6] * coff), (int) round(buff[7] * coff), (int) round(buff[8] * coff), (int) round(buff[9] * coff) ); Serial.println(str); transceiver.sendMessage(String(str));

Serial.println(F(“\nBuffered records have been transmitted.”)); }

void loop() { mma.read(); x = mma.x; y = mma.y; z = mma.z;

long d = (x>prev_x?x-prev_x:prev_x-x)+(y>prev_y?y-prev_y:prev_y-y)+(z>prev_z?z-prev_z:prev_z-z);

delta[delta_index++] = d; Serial.print(F(“Variance = “)); Serial.print(d); Serial.print(F(” #”)); Serial.print(buff_index); Serial.print(F(“.”)); Serial.println(delta_index);

prev_x = x; prev_y = y; prev_z = z;

if( !(delta_index < DATA_LEN) ) // Reach another one minute { long _delta_sum = 0; // Get the average of variance per second long _avg; for(int i = 0; i < DATA_LEN; i++) _delta_sum += delta[i]; _avg = _delta_sum / DATA_LEN; avg[avg_index++] = _avg; delta_index = 0;

Serial.print(F(“>>>>>>>>>>>>>>>>> AVERAGE #”)); Serial.print(avg_index); Serial.print(F(” = “)); Serial.println(_avg);

if (avg_index >= AVG_LEN) { long _avg_sum = 0; for (int j = 0; j < AVG_LEN; j++) { _avg_sum += avg[j]; } _avg_sum /= AVG_LEN; Serial.print(F(“>>>>>>>>>>>>>>>>> AVERAGE TOTAL = “)); Serial.println(_avg_sum);

buff[buff_index++] = _avg_sum; avg_index = 0; }

if (buff_index >= BUFF_LEN) { // Has buffered enough data sendSigfox(); // Send the record first buff_index = 0; } }

delay(DELAY_TIME); }

QBoat Sunny在這裡是利用QIoT,把Sigfox backend上的Callback程序產生的訊息收回來,之後再看要如何去進行分析與處理。值得一提的是,就算在家裡,只要進行3個步驟,一樣可以透過QBoat Sunny把Sigfox backend上的Callback程序訊息收回來!

Step 1:設定Sigfox backend的Callback程序

Step 2:如何搭配QIoT設定,以家用Wireless AP router為例

然後登入你的QBoat Sunny,進行網路組態與確認,先進入CloudLink雲聯通。

Step 3 :新增QIoT的IoT Application來實際接收

先看實際Sigfox backend的Callback程序設定範例。(請注意綠色的數字)

首先必須新增一個Thing來對應UnaShield V2S

上面綠色的數字2的部分就要對應Sigfox backend的Callback程序下的header,記得大小寫有分別:綠色數字1的部分就是Sigfox backend的Callback程序要傳回資訊的網址。

要傳回資訊的網址格式:<主機名稱:對外埠號>/resources/<上圖數字1也就是topic的部分>

舉例來說,本範例傳回資訊的網址就設定為:http://laisanMakerPro.myqnapcloud.com:1194/resources/qiot/things/admin/UnaGSensor/V2SGSensor

最後其實是資料內容部分,本範例搭配QIoT採用json,而資料就看Sigfox backend的Callback程序提供的內容你想傳回哪些,本範例的就是:

最後就是用個IoT Application串場,搞定!

對於執行的步驟有任何問題,也可以參考這支教學影片

(責任編輯:廖庭儀)

賴建宏

訂閱MakerPRO知識充電報

與40000位開發者一同掌握科技創新的技術資訊!

Author: 賴建宏

社群稱號為「賴桑」的他,以電子電機的背景,熱衷於OSHW的應用開發與實作。取得台北科技大學電子所博士學位,目前主推「農林漁牧大業」計畫的迷你型魚菜共生系統開發。

Share This Post On
468 ad

Submit a Comment

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *