2017年2月18日 星期六

High Altitude Ballooning with LoRa fifth launch


總之終於來到了第五次的飛行,與之前的不同在於這次終於將分時多工投入測試了
雖然很久以前就開始跑分時多工,但是測試都只放出一個,並沒有真的跑過一次同時一個以上
最主要的問題在於GPS並沒有辦法Lock住,這等等來講.將GPS解決了之後,TDMA跑起來就很順了
上圖可以很明顯地感覺到掃Channel的感覺

同時由於舊的接收機內部真的太亂,組裝有點鬆散,所以決定設計一套新的電路專門做為接收機用
架構圖如下:


硬體上主要是有四個LoRa模組(對不起我的SX1301 Gateway測試頗失敗的,所以還是四個單通道去湊)然後第一組LoRa模組可以用SX1278+RF FE(30db PA)取代,這樣也能讓接收機去打訊號給node,為未來的Project鋪路,然後模組與ATmega328相連之後用UART接上MT7688.
供電的部分則是透過mini USB或者是鋰電池供電,可以同時接也可以只接任意一個,然後MT7688透過Step-down供電,ATmega328+LoRa模組透過LDO供應.
另外附帶USB轉UART,透過SW切MT7688 Serial console or ATmega328.GPS則是外接一個模組.

不過問題大概就是SD卡的WP/CD沒有拉/接地,所以剛開始7688抓不到SD卡


有電路板差很多
MT7688透過Nodejs架的Server基本上差不多,就只是多了幾個通道這樣,不過因為我發現如果我把四組做上去的話,外殼應該是拿不下來了(RF接頭擋到),所以先上兩個

然後就是新版的Node了,以前到現在最大的問題就在於GPS的穩定性,前幾次由於換成了沒有LNA的天線,訊號更弱了,所以測試起來GPS有時有有時無,但是有趣的是,我去掏寶買了兩種GPS模組,一個是MAX-7Q自製版(拿uBlox的IC做),另外一個是L7(MT3333),MT3333的模組看起來就很正常,雖然TTFF也是需要將近80~100s,但是至少穩定的定到位,反而uBlox的就常常定不了
後來熱風槍一拆才發現,MT3333的模組有一個SAW在旁邊,uBlox的沒有,所以這問題大概是由於底下的LoRa模組打訊號打到上面的GPS模組,有SAW的話就能濾掉了.所以新版的就是加了外部的LNA+SAW,讓TTFF壓到了<50s.


另外這次的氣球也改用塑膠氣球,不過因為比較小顆所以一次要弄五六顆才行.
(重量基本上也是在21~25g之間)

由於這次的地面測試比較頻繁一點,正式升空的時候問題不大,訊號都還不錯

接收機的設置是一個全向性一個指向性(~10db),而距離最遠達到72km,然後,是的我又忘記把計算完的仰角與方位角放到網頁上,所以我指的方向有點落差.


軌跡大概是這樣,可以看到氣球衝過邊界層之後風向改變往東,然後又跌回邊界層的兩個又再次轉向西北.

氣球也很爭氣,一路撐到LOS都沒有顯著的洩氣.最遠的那個還在繼續飄

這次測試有一個問題就是通道是切好了,但是不同模組之間如果同時收到封包,很可能造成切到了下一個通道才把上一個通道的資料傳回來,然後就被誤認成下一個通道的資料
看起來需要切通道的時候檢查Buffer,或者是調整一下SPI的速度






2016年11月26日 星期六

GPS Antenna test


可能有人注意到我在High Altitude Ballooning with LoRa Fourth launch用的探空儀
GPS天線的部份兩個是不一樣的,主要是因為我當時在設計的時候找到一個非常小的GPS天線
原本抓地到訊號,但是一把其他零件裝上去卻又遲遲Lock不住,所以只好換成另外一種7mm的GPS天線.

所以為了測試天線的效能,這次做一次地面的探空儀測試,兩組裝上不同GPS天線,固定在三角架上測試GPS的性能以外,順便也做一次耗電量的測試.


探空儀還是同一個設計,只是GPS模組的部分因為MTK沒有指令可以Query 目前的GPS資料
只能把一些多餘的NEMA關掉,對Atmega328的Interrupt base的UART來說,TDMA的第一格可能會出問題,因為要處裡GPS丟出來的訊號.所以我還是回去用ublox的MAX 7Q.



最終結果如下:

下兩張圖是GPS衛星的天空軌跡,shaded的顏色是衛星經過時的訊號強度,中間的一槓代表板子的擺放,而凸出來的那根是表示板子的正面
7mm晶片型天線

迷你型晶片天線
首先來講一下7mm的那支天線,可以很明顯的看出來因為板子不是為了這支天線所設計的,焊接的時候並不能避免天線的背面的衰減,理想上應該是要一個圓形對稱
迷你型的比較正常,基本上呈現圓對稱,但是訊號弱了大概1~5db,其中在低仰角的部分根本低到0db了
再來講到細節,注意到板子背面其實還有一個小的死角,其中迷你天線的訊號比較沒那麼低
我的猜測是電池座的鐵片干擾到了天線的接收,而由於電路板上面有做迷你天線的反射面,所以對其影響不大.


電池的話則是出現一個很有趣的現象,看起來用迷你的天線比較省電
另外就是因為電池用的是一次性鋰電池,初始電壓達到1.7,不過迅速降到1.4之後平緩的下降
可惜沒有整個過程都跑完,不過總時間達到四小時三十七分鐘

其他問題最大的大概就是氣壓計的初始誤差了,可以看到兩台的溫溼度基本上一致
但是兩個的氣壓差了
大概0.6hPa左右,還滿恐怖的不過還在Datasheet的正負1hpa之內

2016年11月9日 星期三

High Altitude Ballooning with LoRa Fourth launch



這次最主要的是探空儀改版,從上圖很明顯的可以看出來面積再次的下降
壓到了2x5cm(不包含外部感應器),幾乎是兩個AAA電池的大小了

為了縮小面積,最主要的GPS模組換成MAX-7相容的L70-R,氣壓計換成BMP280
另外Atmega328也換成MLF的版本,唯獨16Mhz的Crystal與RFM98沒換
而升壓電路維持同一個晶片,但是電感換成體積更小的了

BMP280真的很小,旁邊有一個0402的電容可以比較

另外也把SHT21+GPS的天線做在同一張板子上,這樣一來就不用另外再接線了,減低重量也簡化組裝,SHT21為了減少主板的影響,所以中間的PCB寬度很窄,一不小心真的會扳斷

而ISP換成1.25mm的插座,原本用接觸點+彈簧針的方式真的是很不方便而且占面積

天線也換成5/8波長的多芯線,比之前的單芯線重量少很多
所以..這次的減重答案就是.....

各位觀眾,七公克,七公克,七公克
雖然加上電池就變十五克,但是比起之前的重量少了快60%

這次還是打算用鋁箔氣球做測試


接收機還是一樣一個全向性與指向性

一樣還是全向性接收機用的是Linkit 7688架的Server,然後指向性天線是用筆電收

所以iPhone和筆記型電腦都可以直接看到接收的狀態

然後這次的飛行最主要的問題就是我的指向性天線沒有對準,所以導致全向性天線接收機的RSSI比指向性天線好非常多,當然也有可能是我的指向性天線已經有點問題了,這可能要在查一下,不過幸好全向性天線的狀況不錯,整個過程都能接收的到訊號,所以基本上資料沒斷

結果如下:

基本上還是一到高度就開始漏氣然後往下掉,最高到四千公尺左右

電壓這次的測量方式改成用內建的Bandgap,應該比較準一點,可以看到從一剛開始的1.47v一路下降到1.34v,但是有趣的是之後的斜率有點改變,而整個曲線也不像是正常的電池放電那種
我可能之後會做一個正常的探空圖,不過多少用這個可以看看端倪
這天基本上沒啥逆溫層,上去下來的溫度也差不多,不過濕度差異頗大,可以看到1000m處
應該是有雲啦,要算一下水氣量

RSSI的話很明顯可以看到這次指向性比全向性還要好,最主要的問題是我指錯方向..
下一版接收軟體應該會把方位角與仰角顯示出來
這張是兩個資料合併的結果,所以RSSI的變化有點大,不過還是可以看出來基本上極限在-96~100附近

最後就是GPS衛星數最大有11顆,以一個晶片型天線來說很不錯了
還有最遠距離13.19km,不過基本上是因為氣球掉下去才結束的






2016年9月24日 星期六

旋轉撥號器-mobile phone with Linkit one

最近Openlab找到一批傳統電話上的撥號盤,覺得滿有趣的就拿回家試試,
然後用Linkit one做成行動電話

我想留點關於這撥號盤的note,所以先來講一下運作方式
首先有三條線,其中一個地線,其他兩個分別是撥號開始與號碼數

當使用者開始轉的時候,撥號開始這條線會接地,而使用者轉完,開始倒轉的時候
每過一格,號碼數的那條線會有一個脈衝出來,轉完之後撥號開始這條就恢復斷路
畫成圖的話是這樣:



要注意的是,畢竟這是一個純機械的裝置,訊號一定會有彈跳的現象發生,所以程式的部分一定要做Debounce.
另外就是撥號盤沒有掛電話的按鈕,所以另外再做一個上去.

然後就沒啥問題了,Linkit one 的GSM example寫得很清楚,用LGSM的library很快


#define dial_pin 6
#define count_pin 7
#define hang_pin 2
#define DEBOUNCE_TIME 50
#include <LGSM.h>

String remoteNumber = "";
char charbuffer[20];
uint32_t first_digit = 0;

void setup() {
Serial.begin(115200);
Serial.println("Started");
pinMode(dial_pin,INPUT_PULLUP);
pinMode(count_pin,INPUT_PULLUP);
pinMode(hang_pin,INPUT_PULLUP);
pinMode(13,OUTPUT);
digitalWrite(13,HIGH);
}
int readDigit(){
      bool catched = 0;
      int count = 0;
      uint32_t lastmillis;
      bool diaing = 1;
      while(diaing){
       
          if(digitalRead(count_pin)==1 && catched==0 && millis()-lastmillis>DEBOUNCE_TIME && digitalRead(dial_pin)==0){
           
              catched = 1;
              count ++;
              lastmillis = millis();
          }
          if(digitalRead(count_pin)==0){
              catched = 0;
          }
          if(digitalRead(dial_pin)==1){
            delay(5);
            if(digitalRead(dial_pin)==1){
            diaing = 0;
            }
          }
      }
      count = count%10;
      return count;
}
void loop() {

if(digitalRead(dial_pin)==0){
  digitalWrite(13,LOW);
        uint32_t last_digit = millis();
        int digit_count=0;
        while(millis()-last_digit<3000){//digit_count<10 &&
           if(digitalRead(dial_pin)==0){
              delay(10);
              last_digit = millis();
              int count = readDigit();
              Serial.print("Number:");Serial.println(count);
              digit_count++;
              remoteNumber+=String(count);
           }
       }
       Serial.print("Phone Number:");Serial.println(remoteNumber);
       if(digit_count==10){
        Serial.print("Calling to : ");
        Serial.println(remoteNumber);
        Serial.println();
        digitalWrite(13,HIGH);
        remoteNumber.toCharArray(charbuffer, 20);
        if(LVoiceCall.voiceCall(charbuffer))
          {
            Serial.println("Call Established. Enter line to end");
            // Wait for some input from the line
            while(digitalRead(hang_pin) == 1);
            // And hang up
            LVoiceCall.hangCall();
          }
        Serial.println("Call Finished");
       }
       remoteNumber= "";
}

}