2017年8月30日 星期三

開學囉~

今天是公托家長日

老師很用心的說明每一個細節

大鵝的號碼相當容易記,是他不喜歡的人物背號

井上雄彦筆下的赤木剛憲才是他最崇拜人物,原因是大鵝喜歡當隊長

公托有很多課後活動,畢盡曲棍球打的再混,直排輪也還略懂

圍棋和足球因為之前都沒跟大鵝聊過,所以較無興趣

最近的睡前故事已經把湘北海南之戰講完

本來已經決定下一個睡前故事將會是網球王子

看來可以足球小將翼或棋靈王也可以安排在行程內

因為十月的上午,每週有國家級足球教練來教

哇 ~ 你拔拔眼睛都亮了~ 我也想踢波呀!

除此之外,還可以讓家長選有空閒的時間來說故事給小朋友聽

所以麻麻選了一天打算讓我去講灌藍高手

這樣就結束了嗎? 每個週四是騎腳踏車日

哇!!! 這間學校也太棒了!!!


2017年8月25日 星期五

使用Arduino Nano打造調光器

鑒於調光器文章流量很高,可見大家對於此類產品有強烈的興趣

這次再寫一章使用Arduini nano實做,而且簡單的不得了,還不用怕被電到,文章是由這篇修正而來,1-10V調光技術

最後電路修正為下圖,整流器接上LED燈條(LED燈泡也同樣意思)


註:下圖黃框如果沒有12VAdapter,也可以直接將Arduino nano接到5V


這麼簡單的Source Code真是是傷大家的眼睛


int PWM = 9; // PWM pin

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

void loop()
{
  analogWrite(PWM, 255);  // PWM最大值
 delay (5000);
   analogWrite(PWM, 200); 
 delay (5000);
    analogWrite(PWM, 0);  // PWM最小值
 delay (5000);
}

來看看


Arduino Forum上有呼吸燈的Tutorial,照著貼上去

int led = 9;           // the PWM pin the LED is attached to
int brightness = 0;    // how bright the LED is
int fadeAmount = 5;    // how many points to fade the LED by

// the setup routine runs once when you press reset:
void setup() {
  // declare pin 9 to be an output:
  pinMode(led, OUTPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  // set the brightness of pin 9:
  analogWrite(led, brightness);

  // change the brightness for next time through the loop:
  brightness = brightness + fadeAmount;

  // reverse the direction of the fading at the ends of the fade:
  if (brightness <= 0 || brightness >= 255) {
    fadeAmount = -fadeAmount;
  }
  // wait for 30 milliseconds to see the dimming effect
  delay(30);
}

來看看




~~~~~~~~~~~~~~~燈控科普時間~~~~~~~~~~~~~~~~~~~~~~~

燈控可是一門技術呢! 也是一個存在已久的商業行為

小弟就別多寫什麼,這次來參考

裡面有提到Triac(智障型燈座)0-10V / 1-10V(這次的文章)
Zigbee(我們用的是WiFi+Lora)PLC(買不起 @@)DALI(這應該要請專家來說明)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

!!!UPDATE !!!

原本科普時間想要貼個文章打混過去,沒想到向神龍許願有用

調光界的高手Edmund願意幫小弟寫普時間,真是倍感光榮

~~~~~~~~~~~~~~~Edmund燈控科普時間~~~~~~~~~~~~~~~~~~~~~~~


調光,或許在一般人的眼中,不外乎就是用個旋扭式的調光開關,控制鎢絲燈泡的亮度

但其實早在20多年前,巿場上已經對調光這個應用有著更多的要求

這由源自解決傳統的相位調光(Phase-cutting)的問題

巿場上一般常買的到的調光器,絕大多數都是以前段相位調光 (Forward Phase/Leading Edge Dimming)

但大家想想,現在還有人在家中或商業的環境用鎢絲燈泡嗎?

對相位調光有興趣的朋友可以參考此文章

雖然 Trailing-Edge/Reverse Phase 能解決大部份的家用 ELV 燈源(LED/CFL省電燈泡)的調光問題,但其實相位調光存在很多不能解決的問題

一般 Trailing-Edge/Reverse Phase(後段相位調光)都偏向以可控矽 (Triac) 來設計調光應用

Triac 存在的問題難以解決


l   燈源的負載不能太大 (基本上40w以上的就會出現調光器發熱/有噪音(Buzz Noise)

試想想一個飯店的大堂(6m-12m)的高度,燈具用 LED 的話,住住會用到 25w – 50w 的燈具

以一個燈光迴路是大約 12-20 LED 燈源,大約就是大約 400w – 1000w 的負載

所以過往在策劃方案時就要把 LED 燈源的 pf (Power factor) 跟燈光迴路的總瓦數都算好


l   相位調光器一般的負載 LED 能力,常見只有大約 150w – 300w 左右

所以很多時候在處理比較大的往宅或商業的應用方案

除非客戶或燈源一定要用相位調光器(要加上調光放大器 Power Booster使用)

或改用其他的燈光調光方法 (放大器應用可以參考這篇

除了相位調光外,常用到的調光方法有以下幾種:

1.          PUSH L
2.          0-10v/1-10v
3.          DALI
4.          DMX
5.          其他的 BUS 系統 (CBUS/KNX/Pyxos 等等)

由於關心大家的鍵盤著想,避免大家看到睡著,口水氾濫成災

各種調光方法的詳細Edmund就先留待下次有機會再跟大家分享

針對幾種容易入手的先分享一下常見到的應用及特性

1、PUSH L/PUSH DIM

一種成本很低 CP 值很高的調光方法,對於迴路佈線的要求也跟傳統燈光迴路沒有太大差別,只要燈源能找到相匹配而有PUSH L 輸入的鎮流器,配上一個復位關關(門鈴開關),就能達至多位置開關/調光的效果,Edmund平日跟老婆看電影時,電視背的LED燈條就是以這種做法來作調光,而實際的應用,很多過往處理過的住宅方案,客戶沒有燈光系統的要求,但也想享受調光的氛圍,這就是一個成本效益很高的做法,
可參考這篇








2、0-10v/1-10v 

最初接觸這種調光方法,是大約 20 年前,因為有客戶想把家中所有的 T5 燈管作調光,0-10/1-10v 的調光方法對 CFL/LED 有著很大的好處,調光的效果也解決了相位調光上很嚴重的 flickering zone / dead travel zone/buzz sound 的問題,在 LED 的應用越來越廣泛的今天,相信會越來越常見,也就是本篇的應用

國際牌的 1-10V 調光器 (引用來源:Mobile01)


*1-10V T5 調光器的接線方法

3、DMX

多用於舞台燈光/指令可以包含RGB 顏色改變/調光/閃爍/燈光投射位置改變,在不少的演唱會/會所/攝影棚甚至 KTV 都常看到,有興趣的話可以參考連結
(引用來源:影視工業網)

4、DALI 

DALI 
算是一種很成熟的技術,不少的飯店/會所、尤其在大型的服飾專賣店都常看到,因為它能夠達至在同一個燈光迴路內不同的燈源可以作出不同的調光亮度,不少歐洲的名牌服飾店及博物館都是以 DALI 系統作為他們燈光應用的標準,試想想你是一家名店的櫥窗設計師,給予你每顆照明光源的亮度你可以任意調整,在店內重點區域或作為強調主打商品的展示的應用上有多方便?付出的代價就是 DALI的鎮流器會比較貴,以及 DALI 的處理器也要一定的價錢


**服飾店以DALI 燈光系統為店中的燈光營造出格調的層次感 (引用 John Cullen Lighting)

**DALI LED 整流器,可以看到端子 DA1 DA2 就是用來接收 DALI 調光信號


針對各種調光的協議的優劣及應用範圍,留待下次有機會詳細分享


觀迎親臨 9 16 日的活動


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

原來燈控有這麼多的學問啊!  這還是要請燈控界的高手Edmund來介紹,畢竟對AC要保有敬畏之心



簡單的說,玩了這次的1-10V調光器,加上之前做的智障型燈座

WiFi/Lora做結合後,就可以朝著調光王了邁進了!!!

(突然想到我們Maker一哥有個萬遲王的頭套…)

燈控這個市場確實含金量挺高的! 商業模式也很確定! 誰家不需要燈光,是吧?

P.S.小道消息是9/16,燈控界的高手會開一堂燈控相關課程,我會去做工讀掃地清潔一個小時

順便去分享這篇文章! 畢盡我燒菜好好吃的! (!?

但寫完發現太簡單了,也許去分享不用一個小時

10分鐘就夠用了,剩下的只能講笑話和世大運的賽程分析

可是9/16世大運都結束了耶

2017年8月11日 星期五

使用Linkit 7697打造SOS跌倒追踨器(Tracker)

不知道各位有沒有觀察過Tracker這類型的產品

例如台廠出貨量大的GPS人員追蹤器


以及募資成功的lota,狗狗貓貓寵物追蹤器
這個也可以拿來做導遊帶團的人員追蹤

這次要做的是Lora + GPS + SOS 按鍵追蹤器

起因是有社群的朋友問到,indoor location我們都做了,那outdoor

其實不太想寫這篇的,因為市面上太多同類型產品可挑選

但為了讓社群朋友知道這個專案能做的真的非常非常多

連室外定位也可以設定為長照的一個分支~

這一篇是由MakerPro社群賴桑的兩篇文章修改而來

做法非常簡單,Linkit7697 + MPU6050 + Button + GPS module + Lora就搞定了

光華商場一顆MPU6050 + Button不用130

GPS module我是買Ublox的,但其實哪一家都可以,價格1000元以內就行

因為這種GPS module只會有4支腳,VCC GND TX RX,接到MT7697就可以了

Lora是之前參加MakerPro的自造松留下來的

可以在沒屋頂的拍賣場找到柯大創客屋

所以做手環加下來大約2000

如果再加上前一篇做的智障型燈座,這樣要2Linkit7697 Total大約2500~2700

! lotaearly bird USD99還便宜耶!

這樣知道為什麼歐美市場比較好賺了吧~ 2500NTD放在台灣誰要買?

台灣人力最便宜了,寵物跑了就叫消防隊找囉~

但其實這種想法跟最近幾年大家開始重視汽車的安全性

主被動安全都要,而不是省油省到爆,讓整個城市都是我的潰縮區是一樣的

市場要教育,但教育會花時間

這次的電路架構如下圖,左邊是要做出來的SOS跌倒追蹤器,右邊是上一篇的近端遙控智障型燈座


經過上一篇的洗禮,決定先用手邊的Arduino Yun做,不然又被Linkit 7697坑到  @@

Arduino Yun的做法相當簡單,已經很習慣在開始之前先上Github看看有沒有勇士分享文章

結果真的有耶!!!  出來吧! 勇士 !




而這是一句那美克星語  -->  出來吧! 神龍!


文章是在說明如何使用Aduino YunSoftwareSerial取出GPS數據

簡易的code如下

#include "SoftwareSerial.h"

SoftwareSerial mySerial(10, 11); // RX, TX

void setup()
{
  // Open serial communications and wait for port to open:
  Serial.begin(9600);

  Serial.println("uBlox Neo 6M");

  // set the data rate for the SoftwareSerial port
  mySerial.begin(9600);

}

void loop() 
{
  if (mySerial.available())
    Serial.write(mySerial.read());
 }

輸出如下圖


~~~~~~~~~~~~~科普時間~~~~~~~~~~~~

GPS有許多有用的資料格式

GPGGA UTC時間、緯度值、經度值、定位狀態、觀測的GPS衛星個數、差分基準站編號

GPRMC UTC時間、定位狀態、緯度值、經度值、對地速度、日期

我們只要GPRMC或是GPGGA內的2501.5016412131.38674就行了

但這代表什麼意思呢?

網頁來輸入經緯度2501.50164, 12131.38674看看


出現上圖這個耶~ 代表圖資是不吃這種格式的

所以需要轉換格式

1、首先直接除以1002501.50164/100=25.0150164
2、把小數點的0.0150164轉為150164
3、然後(150164/60)*10000=250273333.3
4、第二步移了一個0,所以轉小數的時候,多加一個0.02502733333
5、緯度=25+0.02502733333=25. 02502733333

1、首先直接除以10012131.38674/100=121.313867
2、把小數點轉為313867
3、然後(313867/60)*10000=52311166.7
4、經度=121+0.52311166=121.523111667

所以轉換後的是25.02502733333, 121.523111667

來試試有沒有這個地方


地圖顯示我在台北市中正區南昌路二段146-1號,其實我是在MakerPro辦公室的樓下

為什麼要在樓下而不在辦公室內呢? 因為衛星是在地球上方,而GPS模組是在地面上收訊息

所以在家裡吹冷氣寫code,會發現GPS收不到訊號,圖示如下



~~~~~~~~~~~~~~~~~~~~~~~~~~~

在上一步會知道,只取出GPS格式沒用

圖資不吃這套格式,還是得轉換一下,所以就用了這篇

Arduino YunGPScode會是這樣 (主要是黃底紅字的部份,不要被大量的code嚇到)

boolean gpsStatus[] = {false, false, false, false, false, false, false};
unsigned long start;
boolean grabNext = false;
int pointerGPS = 0;
String dataGPS[6] ;
uint8_t hour,minute,second;
float buf1, buf2, buf3;

#include <SoftwareSerial.h>
SoftwareSerial gpsSerial(10, 11); // RX, TX

void setup()
{
  gpsSerial.begin(9600);
  // START OUR SERIAL DEBUG PORT
  Serial.begin(115200);
  //
  //Settings Array contains the following settings: [0]NavMode, [1]DataRate1, [2]DataRate2, [3]PortRateByte1, [4]PortRateByte2, [5]PortRateByte3,
  //[6]NMEA GLL Sentence, [7]NMEA GSA Sentence, [8]NMEA GSV Sentence, [9]NMEA RMC Sentence, [10]NMEA VTG Sentence
  //NavMode:
  //Pedestrian Mode    = 0x03
  //Automotive Mode    = 0x04
  //Sea Mode           = 0x05
  //Airborne < 1G Mode = 0x06
  //
  //DataRate:
  //1Hz     = 0xE8 0x03
  //2Hz     = 0xF4 0x01
  //3.33Hz  = 0x2C 0x01
  //4Hz     = 0xFA 0x00
  //
  //PortRate:
  //4800   = C0 12 00
  //9600   = 80 25 00
  //19200  = 00 4B 00  **SOFTWARESERIAL LIMIT FOR ARDUINO UNO R3!**
  //38400  = 00 96 00  **SOFTWARESERIAL LIMIT FOR ARDUINO MEGA 2560!**
  //57600  = 00 E1 00
  //115200 = 00 C2 01
  //230400 = 00 84 03
  //
  //NMEA Messages:
  //OFF = 0x00
  //ON  = 0x01
  //
  byte settingsArray[] = {0x03, 0xFA, 0x00, 0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //
  configureUblox(settingsArray);
}

double convertDegMinToDecDeg (float degMin) {
  double min = 0.0;
  double decDeg = 0.0;

  //get the minutes, fmod() requires double
  min = fmod((double)degMin, 100.0);

  //rebuild coordinates in decimal degrees
  degMin = (int) ( degMin / 100 );
  decDeg = degMin + ( min / 60 );

  return decDeg;
}

void loop()
{
  char recvChar;
  String sentence;
  while(1) {
    if(gpsSerial.available())
    {
    // THIS IS THE MAIN LOOP JUST READS IN FROM THE GPS SERIAL AND ECHOS OUT TO THE ARDUINO SERIAL.
      recvChar = gpsSerial.read();
      if(String(recvChar) == ",") {
        if(grabNext){
          dataGPS[pointerGPS] = sentence;
          //Serial.println(dataGPS[pointerGPS]);
          pointerGPS = pointerGPS -1;
          if(pointerGPS <1){
            grabNext = false;
             // print out data
        
         /*    Serial.println(dataGPS[5]);  // Time
             Serial.print(dataGPS[4]);   
             Serial.println(dataGPS[3]);  // North
             Serial.print(dataGPS[2]);
             Serial.println(dataGPS[1]);  // West*/
           

             dataGPS[5].toInt();
             hour = dataGPS[5].toInt()/10000+8;
             minute = (dataGPS[5].toInt()/100) %100;
             second = dataGPS[5].toInt() %100;
             Serial.print("Time:");  // Time
             Serial.print(hour); 
             Serial.print(":"); 
             Serial.print(minute); 
             Serial.print(":"); 
             Serial.println(second); 

             buf1 = dataGPS[4].toFloat();
             buf2 = dataGPS[2].toFloat();
             Serial.print("Lat, Lon:");  //Lat, Lon

             Serial.print(convertDegMinToDecDeg(buf1),6);
             Serial.print(","); 
             Serial.println(convertDegMinToDecDeg(buf2),6);

          }
        }
        if(sentence == "M$GPGGA"){
          grabNext = true;
          pointerGPS = 5;
        }
        sentence ="";
      }
      else{
      sentence = sentence + String(recvChar);
      }
    }
  }
}


void configureUblox(byte *settingsArrayPointer) {
  byte gpsSetSuccess = 0;
  Serial.println("Configuring u-Blox GPS initial state...");

  //Generate the configuration string for Navigation Mode
  byte setNav[] = {0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF, *settingsArrayPointer, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x05, 0x00, 0xFA, 0x00, 0xFA, 0x00, 0x64, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  calcChecksum(&setNav[2], sizeof(setNav) - 4);

  //Generate the configuration string for Data Rate
  byte setDataRate[] = {0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, settingsArrayPointer[1], settingsArrayPointer[2], 0x01, 0x00, 0x01, 0x00, 0x00, 0x00};
  calcChecksum(&setDataRate[2], sizeof(setDataRate) - 4);

  //Generate the configuration string for Baud Rate
  byte setPortRate[] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, settingsArrayPointer[3], settingsArrayPointer[4], settingsArrayPointer[5], 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  calcChecksum(&setPortRate[2], sizeof(setPortRate) - 4);

  byte setGLL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x2B};
  byte setGSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x32};
  byte setGSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x39};
  byte setRMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x40};
  byte setVTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x46};

  delay(2500);

  while(gpsSetSuccess < 3)
  {
    Serial.print("Setting Navigation Mode... ");
    sendUBX(&setNav[0], sizeof(setNav));  //Send UBX Packet
    gpsSetSuccess += getUBX_ACK(&setNav[2]); //Passes Class ID and Message ID to the ACK Receive function
    if (gpsSetSuccess == 5) {
      gpsSetSuccess -= 4;
      setBaud(settingsArrayPointer[4]);
      delay(1500);
      byte lowerPortRate[] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0xB5};
      sendUBX(lowerPortRate, sizeof(lowerPortRate));
      gpsSerial.begin(9600);
      delay(2000);
    }
    if(gpsSetSuccess == 6) gpsSetSuccess -= 4;
    if (gpsSetSuccess == 10) gpsStatus[0] = true;
  }
  if (gpsSetSuccess == 3) Serial.println("Navigation mode configuration failed.");
  gpsSetSuccess = 0;
  while(gpsSetSuccess < 3) {
    Serial.print("Setting Data Update Rate... ");
    sendUBX(&setDataRate[0], sizeof(setDataRate));  //Send UBX Packet
    gpsSetSuccess += getUBX_ACK(&setDataRate[2]); //Passes Class ID and Message ID to the ACK Receive function
    if (gpsSetSuccess == 10) gpsStatus[1] = true;
    if (gpsSetSuccess == 5 | gpsSetSuccess == 6) gpsSetSuccess -= 4;
  }
  if (gpsSetSuccess == 3) Serial.println("Data update mode configuration failed.");
  gpsSetSuccess = 0;


  while(gpsSetSuccess < 3 && settingsArrayPointer[6] == 0x00) {
    Serial.print("Deactivating NMEA GLL Messages ");
    sendUBX(setGLL, sizeof(setGLL));
    gpsSetSuccess += getUBX_ACK(&setGLL[2]);
    if (gpsSetSuccess == 10) gpsStatus[2] = true;
    if (gpsSetSuccess == 5 | gpsSetSuccess == 6) gpsSetSuccess -= 4;
  }
  if (gpsSetSuccess == 3) Serial.println("NMEA GLL Message Deactivation Failed!");
  gpsSetSuccess = 0;

  while(gpsSetSuccess < 3 && settingsArrayPointer[7] == 0x00) {
    Serial.print("Deactivating NMEA GSA Messages ");
    sendUBX(setGSA, sizeof(setGSA));
    gpsSetSuccess += getUBX_ACK(&setGSA[2]);
    if (gpsSetSuccess == 10) gpsStatus[3] = true;
    if (gpsSetSuccess == 5 | gpsSetSuccess == 6) gpsSetSuccess -= 4;
  }
  if (gpsSetSuccess == 3) Serial.println("NMEA GSA Message Deactivation Failed!");
  gpsSetSuccess = 0;

  while(gpsSetSuccess < 3 && settingsArrayPointer[8] == 0x00) {
    Serial.print("Deactivating NMEA GSV Messages ");
    sendUBX(setGSV, sizeof(setGSV));
    gpsSetSuccess += getUBX_ACK(&setGSV[2]);
    if (gpsSetSuccess == 10) gpsStatus[4] = true;
    if (gpsSetSuccess == 5 | gpsSetSuccess == 6) gpsSetSuccess -= 4;
  }
  if (gpsSetSuccess == 3) Serial.println("NMEA GSV Message Deactivation Failed!");
  gpsSetSuccess = 0;

  while(gpsSetSuccess < 3 && settingsArrayPointer[9] == 0x00) {
    Serial.print("Deactivating NMEA RMC Messages ");
    sendUBX(setRMC, sizeof(setRMC));
    gpsSetSuccess += getUBX_ACK(&setRMC[2]);
    if (gpsSetSuccess == 10) gpsStatus[5] = true;
    if (gpsSetSuccess == 5 | gpsSetSuccess == 6) gpsSetSuccess -= 4;
  }
  if (gpsSetSuccess == 3) Serial.println("NMEA RMC Message Deactivation Failed!");
  gpsSetSuccess = 0;

  while(gpsSetSuccess < 3 && settingsArrayPointer[10] == 0x00) {
    Serial.print("Deactivating NMEA VTG Messages ");
    sendUBX(setVTG, sizeof(setVTG));
    gpsSetSuccess += getUBX_ACK(&setVTG[2]);
    if (gpsSetSuccess == 10) gpsStatus[6] = true;
    if (gpsSetSuccess == 5 | gpsSetSuccess == 6) gpsSetSuccess -= 4;
  }
  if (gpsSetSuccess == 3) Serial.println("NMEA VTG Message Deactivation Failed!");

  gpsSetSuccess = 0;
  if (settingsArrayPointer[4] != 0x25) {
    Serial.print("Setting Port Baud Rate... ");
    sendUBX(&setPortRate[0], sizeof(setPortRate));
    setBaud(settingsArrayPointer[4]);
    Serial.println("Success!");
    delay(500);
  }
}


void calcChecksum(byte *checksumPayload, byte payloadSize) {
  byte CK_A = 0, CK_B = 0;
  for (int i = 0; i < payloadSize ;i++) {
    CK_A = CK_A + *checksumPayload;
    CK_B = CK_B + CK_A;
    checksumPayload++;
  }
  *checksumPayload = CK_A;
  checksumPayload++;
  *checksumPayload = CK_B;
}

void sendUBX(byte *UBXmsg, byte msgLength) {
  for(int i = 0; i < msgLength; i++) {
    gpsSerial.write(UBXmsg[i]);
    gpsSerial.flush();
  }
  gpsSerial.println();
  gpsSerial.flush();
}


byte getUBX_ACK(byte *msgID) {
  byte CK_A = 0, CK_B = 0;
  byte incoming_char;
  boolean headerReceived = false;
  unsigned long ackWait = millis();
  byte ackPacket[10] = {0xB5, 0x62, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  int i = 0;
  while (1) {
    if (gpsSerial.available()) {
      incoming_char = gpsSerial.read();
      if (incoming_char == ackPacket[i]) {
        i++;
      }
      else if (i > 2) {
        ackPacket[i] = incoming_char;
        i++;
      }
    }
    if (i > 9) break;
    if ((millis() - ackWait) > 1500) {
      Serial.println("ACK Timeout");
      return 5;
    }
    if (i == 4 && ackPacket[3] == 0x00) {
      Serial.println("NAK Received");
      return 1;
    }
  }

  for (i = 2; i < 8 ;i++) {
  CK_A = CK_A + ackPacket[i];
  CK_B = CK_B + CK_A;
  }
  if (msgID[0] == ackPacket[6] && msgID[1] == ackPacket[7] && CK_A == ackPacket[8] && CK_B == ackPacket[9]) {
    Serial.println("Success!");
    Serial.print("ACK Received! ");
    printHex(ackPacket, sizeof(ackPacket));
    return 10;
        }
  else {
    Serial.print("ACK Checksum Failure: ");
    printHex(ackPacket, sizeof(ackPacket));
    delay(1000);
    return 1;
  }
}


void printHex(uint8_t *data, uint8_t length) // prints 8-bit data in hex
{
  char tmp[length*2+1];
  byte first ;
  int j=0;
  for (byte i = 0; i < length; i++)
  {
    first = (data[i] >> 4) | 48;
    if (first > 57) tmp[j] = first + (byte)7;
    else tmp[j] = first ;
    j++;

    first = (data[i] & 0x0F) | 48;
    if (first > 57) tmp[j] = first + (byte)7;
    else tmp[j] = first;
    j++;
  }
  tmp[length*2] = 0;
  for (byte i = 0, j = 0; i < sizeof(tmp); i++) {
    Serial.print(tmp[i]);
    if (j == 1) {
      Serial.print(" ");
      j = 0;
    }
    else j++;
  }
  Serial.println();
}

void setBaud(byte baudSetting) {
  if (baudSetting == 0x12) gpsSerial.begin(4800);
  if (baudSetting == 0x4B) gpsSerial.begin(19200);
  if (baudSetting == 0x96) gpsSerial.begin(38400);
  if (baudSetting == 0xE1) gpsSerial.begin(57600);
  if (baudSetting == 0xC2) gpsSerial.begin(115200);
  if (baudSetting == 0x84) gpsSerial.begin(230400);
}


這裡印出的東西非常簡單,就是GPS轉換過後的數據

由於沒存到圖,又剛好在室內寫文章,故示意圖如下



好了,Arduino Yun 可以了,換上Linkit7697~

先用簡單的code

void setup(){
    Serial.begin(9600);
    Serial.println("Hello");
}

void loop(){

    Serial.println( Serial.read());

}

結果如下圖



我的天天天啊!

連食尚玩家的阿松都發現了我們找到了第4bug! 

為什麼看別人的文章都沒在寫bug,我好像在做Linkit7697 QA bug report

這個bug是代表Linkit7697不能使用SoftwareSerial.h

也就是說沒辦法自定腳位給GPS模組使用,只能用實體UartGPS

好吧~ 那我們就來接Linkit7697的實體Uart pin0pin1

但因為pin0pin1已經給USB Debug用了,所以再接上GPS模組會出現亂碼



天怒人怨啊


這表示Linkit 7697開發不能外接GPS/3G/4G...Uart模組???

其實Arduino Yun開發完了就可以直接換上Linkit 7697,因為USB Debug不會再用到了~

所以這次就用Arduino Yun開發手環連接到燈座

有朋友問到,那不如改用ESP32,也是BLE+WiFi

其實用ESP32也行! 因為我們的功能不會非常複雜



我們要支持可以跟國際市場抗衡的國貨

不是盲目的支持國貨

相信這4Bug只是MTK QA沒查到,也許下一版更新就改過來了


復習一下另外三個Bug

MTK還有論壇哦! 有問題可以po上去,但可能MTKer比較忙,又常加班的關係~

如果曾用過TIEspressifRealtek論壇,就會發現MTK回應速度

先前用過對岸的Realtek QQ群組,只能用火速來形容

這也是為什麼Espressif會在全球Maker圈中火熱起來

除了很清楚Maker要什麼之外,回應速度也飛快

好了! 抱怨結束! 回到正題!

接下來把把賴桑的code擷取下來

#include “I2Cdev.h”
#include “MPU6050.h”
#include “Wire.h”
MPU6050 accelgyro;
int16_t ax, ay, az;
int16_t gx, gy, gz;
int time_interval = 500;    //500ms
unsigned long current, lastTime = 0;
int16_t prev_accx = 0;
int16_t prev_accy = 0;
int16_t prev_accz = 0;
float acc_upv = 2.8;  //The thresholds for fall detection
void setup()
{
  Wire.begin();
  Serial.begin(115200);
  accelgyro.initialize();
  accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  prev_accx = ax;
  prev_accy = ay;
  prev_accz = az;
  lastTime = millis();
}
void loop()
{
  current = millis();                 //Set for every interval
  if(current – lastTime >= time_interval)
  {
    lastTime = current;
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
    
    float accx = ((ax – prev_accx) / 16384) * ((ax – prev_accx) / 16384);
    float accy = ((ay – prev_accy) / 16384) * ((ay – prev_accy) / 16384);
    float accz = ((az – prev_accz) / 16384) * ((az – prev_accz) / 16384);
    Serial.print(accx); Serial.print(“\t”);
    Serial.print(accy); Serial.print(“\t”);
    Serial.print(accz); Serial.println();
    if( sqrt(accx + accy + accz) > acc_upv )
      Serial.println(“GOT!!!”);
    prev_accx = ax;
    prev_accy = ay;
    prev_accz = az;
  }
}

然後再把柯大的MiniLora  Example,LoraSender與LoRaReceiver貼出來

LoraSenderà

#include <SPI.h>
#include <LoRa.h>

int counter = 0;

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

  Serial.println("LoRa Sender");

  if (!LoRa.begin(915E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
}

void loop() {
  Serial.print("Sending packet: ");
  Serial.println(counter);

  // send packet
  LoRa.beginPacket();
  LoRa.print("hello ");
  LoRa.print(counter);
  LoRa.endPacket();

  counter++;

  delay(5000);
}

LoRaReceiverà

#include "SPI.h"
#include <LoRa.h>

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

  Serial.println("LoRa Receiver");

  if (!LoRa.begin(915E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
}

void loop() {
  // try to parse packet
  int packetSize = LoRa.parsePacket();
  if (packetSize) {
    // received a packet
    Serial.print("Received packet '");

    // read packet
    while (LoRa.available()) {
      Serial.print((char)LoRa.read());
    }

    // print RSSI of packet
    Serial.print("' with RSSI ");
    Serial.println(LoRa.packetRssi());
  }
}

Sender是用在Arduino Yun上面,MPU6050判斷長輩跌倒或由按下Button送出Trigger訊號到及GPS位置到燈座

Receiver是用在Linkit7697上的code,其實Receiver將來需要修正,因為手機需要下指令到燈座,燈座再送訊號到手環取GPS位置

流程如下

手機-->Cloud Server-->燈座-->手環

手環回傳GPS位置-->燈座-->Cloud Server-->手機

猜測lota的架構大概也是這個樣子

這次留下四個PartCode給大家手動實驗~

我先去104MTKQA! 希望也可以負責論壇這一塊 ^ ^

~~~~~~~~~~~~~面試時~~~~~~~~~~~

主審官


我:ㄜ

主審官

我:鳴

 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

P.S. 實做文章應該只剩下2~3篇,主要是燈座連接到智能家居配件(smart home security)及燈座室內定位就結束了

接下來會找時間開個線上會議,看看大家對這個群組有什麼想法

基本上Simple care is yours,怎麼讓照護變得更簡單

如何內化目前專案,怎麼整合照護人員及最後一哩路

P.S.1. 這個專案整合了四大領域,長照、保全、室內定位及智能燈泡

再細分下去還有Big dataAIIOT,要做的事太多了

而這個群組內的參與人員領域很廣,也希望大家能多多幫這個社會盡一份力

動手改變世界 ^ ^

Good Luck!

加入我們吧!



FB設定搶先看的方式

設定搶先看的兩種方式 A1. 先到我家的日常粉絲團按下 …( 紅框處 ) A2. 按下追蹤中 ( 紅框處 ) A3. 按下搶先看 ( 紅框處 ) A4. 完成!!! 另一種方式 ...