2016年1月19日 星期二

[Raspberry Pi] Ad Hoc


Ad Hoc,拉丁原文有"將就的、隨意的"的語意,在Wifi協定中代表"無線隨意網路",也就是不需要中央基地台,通訊端之間即能夠構成的網絡

相較於Ad Hoc模式,Infrastructure就是日常生活中熟悉的中心輻射式網路拓樸,網路內通訊統一透過中央基地台分發

在Linux下設定Ad Hoc模式的步驟非常簡單,只要改/etc/network/interface內設定再重開裝置即可!
參考:http://spin.atomicobject.com/2013/04/22/raspberry-pi-wireless-communication/

步驟:

  1. $sudo vim /etc/network/interface #改網路設定
  2. wlan0設定如下
    1. iface wlan0 inet static   #靜態IP
    2. address 192.168.1.1      #設定IP
    3. netmask 255.255.255.0    #設定子網路遮罩
    4. wireless-channel 1  #訊號通道
    5. wireless-essid RPiAdHocNetwork #暴露在可用的Wifi清單中的名稱
    6. wireless-mode ad-hoc #模式:ad-hoc
  3. 存檔
  4. $sudo ifdown --force wlan0  #先將wlan0關閉(強制下架)
  5. $sudo ifup wlan0 #再將wlan0重新打開,套用方才設定的設定值

如此一來就可以了,果真隨意簡單

原先以為通訊上不用經過HUB或許傳輸上會變快,殊不知ad hoc是比Infrastructure更為古老的架構,許多針對Wifi傳輸最佳化的方法可能都不支援,而且還帶有一些毛病,參考此篇:Limitations of Ad Hoc Mode Wireless Networking


實際用iperf測速,使用Ad Hoc相較於Infrastructure,傳輸速度完全沒有提昇,該是嘗試Wifi Direct看看





2016年1月10日 星期日

[.NET] Memory Leaks


前陣子在工作上遇到了"OutOfMemory"的例外,深感驚訝,以為在GC環境下,這種像是慢性病的東西可以從此與我絕緣,真要下手查BUG時,突然理解到,關於GC,關於記憶體分配模型,我理解的太模糊,才會感覺每一行指令好像都值得懷疑似的(最後發現是TextBox內容控制機制有問題)

.NET的記憶體分配模型:


  • 堆疊(Stack):
    • 何時被分配?
      • 進入函式,配置實值物件,或宣告實例參考時
      • 依序連續分配,像是盤子一層層疊起來所以稱為Stack
    • 什麼東西會被分配?
      • 實值型別(Value Type)物件
        • 註:可以從物件是否繼承自System.ValueType來確定是否為實值型別
        • 例如:Int , Float , 使用Structure宣告的物件
      • 參考型別(Reference Type)參考(Reference),可稱為Handle,概念上可以想成指標
    • 何時被回收?
      • 當函式退出(Return)時,按照分配順序一層層移除,後進先出
      • 註:所以若在此函式範圍做了 Object a = new Object,在退出此函式時參考a會被沒收,此時跟a鏈結的物件,就成了無主遊魂,很快地會被牛頭馬面GC(Garbage Collector)回收,帶到陰曹地府等待投胎轉世(輪迴?)

  • 託管堆積(Managed Heap):
    • 何時被分配?
      • 隨時隨地,在你使用New配置物件時
    • 什麼東西會被分配?
      • 參考型別物件,可稱為Instance
        • 註:String是參考型別物件,分配在堆積上,只是其屬性為不可修改(Immutable)
    • 何時會被回收?
      • 當GC掃描到此Instance並無任何參考指向他,便會標記起來,接著自動回收

  • 非託管堆積(Unmanaged Heap):
    • 何謂非託管?
      • 就是非在CLR上執行的程式,不受.NET管理,好比你用C語言基於Standard Library寫出來的程式
    • 何時被分配?
      • 隨時隨地,在你使用New/malloc配置物件時
    • 什麼東西會被分配?
      • 任何你用New/malloc配置的東西
    • 何時會被回收?
      • 必須手動明確(Explicit)地呼叫Delete/Free,此物件所佔據的記憶體空間才會被釋放

可能的記憶體洩漏原因:

  • 有問題的非託管程式碼
    • 物件被分配(New/malloc)出來了,但忘記寫下Delete(Free),典型的錯誤
    • 最可怕的是第三方供應商的函式庫有問題,你沒程式碼他又不想理你
  • 託管程式碼:
    • 對於IDisposable物件,使用過後未呼叫Dispose()
      • 非託管程式碼或是運用到獨佔資源(Resource)的物件可能會實作此介面,作為提供呼叫端明確呼叫釋放時機的可能性
      • 例如:Filestream、SqlConnection、Usercontrol
      • 需要手動控制釋放時機的物件才實做IDisposable(程式結束時釋放的那種不算)
      • 對於所有IDisposable物件,盡量使用Using,減少人為失誤造成的困擾
    • 物件已失去參考,但隸屬的EventHandler仍與活動中的Event連結
      • 由於成員函式隱含實例作為參考,可能會使得EventHandler對應的物件無法被釋放(這點相當有趣,物件成員函式預設至少有一引數為自己)
    • 其他,自己應用上的失誤
      • Queue:Enqueue沒有Dequeue的快,結果就是一直累積
      • 傾盡CPU全力,狂寫檔案(StreamWriter.Write()),緩衝區被玩爆(這種問題很快會爆發,好查)
      • 記憶體控制機制設計有問題

分析記憶體洩漏的好工具,perfmon.exe

    • 心得:
      • 帶出的數據非常完整,而且可以設定固定採集時間長度,記錄在不同的採集檔內,比起自己在程式碼內寫LOG,用這工具比較能確保實驗在固定的資料搜集條件下進行
    • 抓漏心法:
      • 找出可能的嫌疑點,開perfmon設定長度N分鐘週期M秒採樣,時間到後觀察增長趨勢
      • 沒改善,表示找錯方向,改動其他嫌疑點,重複上面過程,再看一遍
    • 詳細使用方法:
    • 非常好的評論:


參考資料:
經常性的字串處理你該用StringBuilder
Using using as grantee (even for the filestream):
Close and Dispose
Heap、Stack、Reference Type、Value Type、Boxing、Unboxing

2016年1月4日 星期一

[Raspberry PI] PWM


PWM,Pulse Width Modulation,以數位方式控制高低電位週期比例來達到模擬類比電壓的效果,比方說控制馬達速度、LED燈亮度...

值得一提的是,因為是模擬的方式所以PWM訊號頻率其實也會出現在輸出訊號的頻譜裏,當然也要輸出裝置頻寬夠高才能夠被察覺.

樹莓派身為一塊萬用開發版當然有辦法輸出PWM,目前查到有下面幾個方法:


  • RPi.GPIO
    • 指令下達方式:Python
    • PWM生成方式:軟體模擬
    • 安裝
        • #sudo apt-get install python-dev python-rpi.gpio
    • 用法:
        • #sudo python #進入Python
        • >>import RPi.GPIO as GPIO
        • >>GPIO.setmode(GPIO.BCM)
        • >>GPIO.setup(18, GPIO.OUT)    #設定GPIO18為輸出腳
        • >>pwm = GPIO.PWM(18, 500)   #建立PWM實例,在GPIO18輸出,頻率為500Hz
        • >>pwm.start(100) #開始輸出DUTY=100%的脈波
    • 心得:
      • 用在伺服馬達(Servo)上會感覺到顫振,確實是用軟體方式來輸出,持續輸出脈寬的重複性不佳,大概只適合做LED燈控制等人機應用.
      • 軟體輸出方式大概是以系統內建計時器,去計時控制輸出腳位為高位/低位,由於Linux並非即時系統,各行程(process)無法保證被定時呼喚,因此即便系統計時器是可靠的,在上位做控制的行程也沒辦法總是在計時到達的當下去處理.



  • RPIO
    • 指令下達方式:Python
    • PWM生成方式:半軟體模擬?(文件上寫著透過DMA通道,不太清楚背後機制)
    • 安裝
        • #sudo apt-get install python-setuptools
        • #sudo easy_install -U RPIO
    • 用法:
        • #sudo python #進Python
        • >> from RPIO import PWM
        • >> servo = PWM.Servo()           #建立一個Servo實例,預設週期為50Hz
        • >> servo.set_servo(18,1500)    #在GPIO18上持續輸出脈寬為1500us的脈波
        • >> servo.set_servo(19,10000)  #在GPIO19上持續輸出脈寬為10000us的脈波
    • 心得:
        • 發現如果將其中一隻Pin輸出關閉,所有輸出都會被關閉,不知道是不是BUG?
        • 可以多通道輸出(但不曉得通道代表什麼意思),比方說
          • >> servo0 = PWM.Servo(0)
          • >> servo1 = PWM.Servo(1)
          • 如此就建立了兩個Servo物件對應到不同的DMA通道,但操作起來仍發現會相互干擾
        • 顫陣比GPIO小,但仍能感受到.


  • pigpio
    • 指令下達方式:pipe 、c-interface、python
    • PWM生成方式:軟體模擬(p指令)、硬體輸出(hp指令)

      • #git clone https://github.com/joan2937/pigpio #跟上最新版
      • cd PIGPIO
      • make
      • sudo make install

    • 用法(pipe方式):

      • #sudo pigpiod #喚起掌管輸出入的專用daemon
      • #pigs  p 19 255 #在GPIO19上輸出DUTY 100%的PWM信號(軟體模擬輸出)
      • #pigs hp 18 100 500000#在GPIO18上輸出頻率為100Hz DUTY為50%的PWM信號(硬體直接輸出)

    • 心得:
      • "硬"PWM,直接用樹莓派BCM2835晶片內建兩個底層PWM輸出單元生成PWM信號,直接以IC輸出信號重複性一定是最穩定的,也就是脈寬不會有忽大忽小的問題
        • pigpio只是作為寫入晶片上特定registor的API罷了
      • BCM2835只有兩個PWM通道(Channel),甚至在Pi2上只有一隻引腳被接到介面IO上,而Raspberry PI B+則有GPIO18,GPIO19可用.
      • 操作起來真的是顫陣最低的(滿意)!
      • 另外要說pigpio的shell指令很豐富,初期拿來測試硬體相當順手,文件也建立的很完整(滿意)!
      • 各型Raspberry PI GPIO表:http://elinux.org/RPi_BCM2835_GPIOs
從BCM2835文件可以發現這塊晶片頂多只能輸出兩個PWM信號,真要再多的話就要以通訊方式(I2C UART)送出命令透過PWM IC代為輸出穩定的PWM信號了,類似透過這樣的晶片

後記:
即便是用了Hardware PWM,功率電路之間的相互干擾也是另一令人頭痛的因素....尚待努力


其他參考:
BCM2835硬體Sheet