http://m-and-i.cocolog-nifty.com/freetalk/2017/02/raspberry-pilaz.html 参照
Raspberry piでLazarusを使ってIoT
Raspberry pi/RaspbianでのC#/mono実行環境ではデータ入力と送信のサイクル限界が200ms程度とあまりよろしくありませんでした。Raspbian上のmonoが遅いのか、MCP3208アクセスライブラリが遅いのか原因はよくわかりこれはませんが、何とか処理スピードを上げられないかと、ネイティブコンパイラであるLazarusを使用してみました。
ADコンバータMCP3208用のライブラリは、トランジスタ技術のダウンロードサービスから2014年7月号の「特集 第6章 HDMIテレビにグラフ表示! 8チャネル・ロング・メモリ・データ・ロガー」をダウンロードして、この中のspi_mcp3208.pasを使用させていただきました。
また、MQTTライブラリにはmqtt-free-pascal-masterを使用しています。
尚、そのままではLaspbian上でコンパイルした実行ファイルがMQTTに接続する時点で、Semaphore init failed (possibly too many concurrent threads)エラーが出て停止してしまうため、プロジェクトソースに以下の変更を加えています(Web上で見つけた解決策です)。
1 2 3 4 5 6 7 8 9 10 | program publish; {$mode objfpc}{$H+} uses {$DEFINE UseCThreads} ←この一行を追加 {$IFDEF UNIX}{$IFDEF UseCThreads} cthreads, { $ENDIF }{ $ENDIF } |
Lazarusで作成したアプリケーションでは、データ入力と送信のサイクル限界が30msまで上がりました。この性能が出ると、50msサイクル程度までは安定した出力が保証できそうです。8チャンネル分の入力データをいちいちフォーム上に表示させていてこのスピードですから、さすがはネイティブコンパイラといった感じでしょうか。入力データの表示を行わなければ、もっとスピードが上がるかもしれません。
Delphi使いの私としては、Lazarusは言語仕様がDelphi互換でフォームデザインも同じ感覚で行うことが出来るので、使っていてまったく違和感がありません。また、LazarusはWindows上でも使用できるためフォームデザインから基本的なプログラミングまでをWindows上で行ってRaspbian上にプロジェクトをコピーして仕上げることが出来ます。Visual Studio/C#ではWindows上で作成した実行ファイルがRaspbian/mono上でそのまま動くという利点はありますが、GPIO処理などのRaspberry pi依存部分のデバッグは遅くて貧弱なRaspbian上のMonoDevelopで行う必要がありますので、Lazarusの方が優位と行った感じでしょうか。
Lazarus/Raspbianでの主な処理は以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | unit Unit1; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, Spin, DateUtils, IniFiles, MQTT, spi_mcp3208; // スタート procedure TForm1 . StartBtnClick(Sender: TObject); var URL: string ; i: integer ; begin Topic := PTopic . Text; URL := BURL . Text; MQTTClient := TMQTTClient . Create(URL, 1883 ); MQTTClient . Connect; Sleep( 500 ); if MQTTClient . isConnected then begin IdleTimer1 . Interval := Interval . Value; IdleTimer1 . Enabled:= True ; StopBtn . Enabled:= True ; StartBtn . Enabled:= False ; BURL . Enabled := False ; PTopic . Enabled:= False ; for i := 1 to 8 do CB[i].Enabled:= False ; Pdt := 0 ; end else begin MQTTClient . ForceDisconnect; MQTTClient . Free; MessageDlg( 'MQTT connection was failed.' , mtError, [mbOK], 0 ); end ; end ; // データ入力・Publish処理 procedure TForm1 . IdleTimer1Timer(Sender: TObject); var InData: array [ 0..7 ] of single ; i, tgap: integer ; tdt: TDateTime; pub, tmp: ansistring ; begin // 出力フォーマット // YYYY/MM/DD h:min:sec.msec, interval, data1, data2, .... ,data8 // intervalは前回データ取得から今回までの間の時間(msec) tdt := Now; if Pdt > 0 then tgap := MilliSecondsBetween(Pdt, tdt) //前回から今回までの時間をmsecで取得 else tgap := 0 ; Pdt := tdt; DateTimeToString(pub, 'yyyy/mm/dd hh:nn:ss.z' , tdt); tmp := IntToStr(tgap); pub := pub + ',' + tmp; ADC8 . Read(InData); for i:= 1 to 8 do begin if CB[i].Checked then begin tmp := FloatToStr(InData[i- 1 ]); if MonitorStat . Checked then DT[i].Text:= tmp; pub := pub + ',' + tmp; end else pub := pub + ',' ; end ; MQTTClient . Publish(Topic, pub); end ;
|
0 件のコメント:
コメントを投稿