関数型言語HaskellでIoTを楽にしようという無謀な試み。GHCのバグ?環境整備の問題?インジェクション・ローバーミニの車載コンピュータのモニタリング,Macではstack環境下で順調に開発・運用していますが,ラズパイでの運用は未完。4.14.79-V7+)した場合とで異なる。ラズパイ上ではなぜかbytestringのインターナルモジュール内の定義を参照し,呼び出し側は,モジュール内で明示的に指定した公開ライブラリを見にいっています。具体的には,serialportパッケージのsend関数の第2引数の型が合いません。Intと定義されています。0x0a)みたいな感じで呼び出しています。引数の型は合っているはず。ByteStringです(尤も,D.B.C内のByteStringの定義は,後述の通り,Internalモジュールからインポートしていますが)。buildをした場合,問題なく通りますし,運用もできます。定義されているbytestring-0.10.8.1:Data.ByteString.Internal.ByteStringと合わないというわけで,型の不一致とされてしまいます。原因分析:何が原因かserialportのソースをおっかけてみると,まずByteStringの定義は前述の通り,D.B.Cを参照しています。sendの第2引数は,途中でWord8に変換するため,B.unpackをかけており,その先のD.B.Cのほうでは,unpackは結局,内部関数のunpackAppendCharsLazyを束縛しています。(後略)されています。(Typeable)となっています。これは外部公開していないモジュールのはずですから,ここを参照すべきではないでしょうし,D.B.Cのほうで,ちゃんとByteStringをエクスポートしています。冒頭で述べたように,stackでの開発がラズパイ上ではできていません。ライブラリのコンパイルをはじめて,大きなライブラリのコンパイルでメモリが不足して止まってしまう(一応,仮想メモリとして4GBを確保してあるのですが)。バージョンや,Stackを使った場合と生で呼び出した場合のGHCに渡されるオプションや構成の違いが真因の可能性も。考えられる対処いずれにしても,検証するには環境を合わせることから始める必要がありそうです。バージョンも違うため,そこらへんを合わせてみることが必要なのかもしれません。go言語で組み直してみる?手続き型言語の冗長さと,代数データ型やモナドが使えないなどの面倒さにつきあうのはためらいがありますが...。蛇足こんなデータを0.5秒おきにとっています。開発目的は,時々発生するECU気絶に由来すると思われるエンジン停止や回転数低下の原因を特定したいためと,IoTや関数型言語でのプログラミングの勉強。下記画像では,右端の部分で時々横線が入っているように見える部分が,そこが,ECUのデータ読み出しができなかった瞬間です。左側の数値が羅列されている部分でいうと,文字列が並んでいる行です。気が付かれる方もあるかもしれませんが,魚野の車はマニュアル車です。ECUが原因かという検証のため,修理業者さんが別の車のオートマ用ECUをつないでくれたために,オートマと表示しています。ECUが変わっても,瞬停や回転数落ちはまだ発生していますので,ECUそのものが原因ではないと思っています。2019/09/23ECUモニタ開発状況ローバーミニ,すでにクラッシックカーの領域に入りつつありますが,1992年以降に日本で新車として販売されたミニにはインジェクション方式が導入され,制御用のコンピュータECUも載せている。使ってこの制御用コンピュータのデータをモニタリングしようとしてきましたが,少しづつ開発を進めています。ちなみに現在も引き続き車内にMacBookAirを持ち込んで,運転中に自動記録しつつ,車載モニターにライブデータを表示しています。全体としては安定してモニタリングできるようになり,プログラムの一部を改造しても他の部分に影響を出しにくくなりました(モジュラー化が進んだ。以前は各パーツが密接に絡み合っていたため,一部を改造するとしばらくコンパイルエラーのみならずロジックエラーを誘発していた。スクリーンショットこれは2019年5月にとったスクリーンショット。数値表示だけでは一瞥したときに全体像が把握できないなと,アスタリスクによる各データのリアルタイム棒グラフをつけたもの。ECUモニタのスクリーンショットそしてこちらは過去データや他のデータとの相関を見たいと思い,縦棒グラフを並べるようになったバージョン。2019年9月現在の画面そして現在は複数のデータを同一のグラフに描画しています。一通り走った後,エンジンを停止した状態(エンジンを切っても10秒くらいはECUが動作しています。冷却液用の冷却ファンをしばらくまわすため)での画面キャプチャ。画面右側は,テキスト表示でむりやり表現した温度や回転数など各種センサー値の重ね合わせグラフ。テキスト表示なのは,ラズパイなど超小型コンピュータで動作させる際に簡単に実現できそうだからです(GUIはメモリや処理能力に要求される水準がTUIに比べて圧倒的に高いが,超小型コンピュータにそれを求めるのは酷ですものね)。ループ処理や例外処理を見直し,エンジンの稼働状況やECUと繋がれた信号線の状態に影響を受けにくくなり,安定して稼働するようにしました。こちらのログは岡崎から名古屋に帰る道すがら記録したものです。時々接続が切れて再接続しています(再接続に1秒近くかかっているのはあえて待ち時間を1000m秒入れているから)。路面の凸凹やアクセルオフ時の振動に連動(?)して接続が切れているので,コネクタかセンサ固定に何か問題がありそう。Data得られた学び前回の報告から進展したHaskellの学び,Haskell中級編といったところでしょうか。モナドを作れるようになったモナド,Haskell初心者のつまづきの石です。わかってしまえばなんてことはない概念ですが,RealWorldHaskellとかでゆっくりまなびつつ,試しにECUとのコミュニケーションモジュールで自作のモナドを作ってみました。裏で動く仕組みが理解できたため,ソースを見ても動作に検討がつくようになりましたし,liftとか融合とか,避けていた知識を身に着けたら,いろんなことがより簡素に表現できるようになりました。ちなみに,モナドはRealWorldHaskellの記載内容から変わったところ(変わるところ)があるので,要注意。Haskell”を電子書籍で購入して並行プログラミング関係だけ読み,初歩はマスターできました。このプロジェクトではマルチスレッド間の資源の取り合いはほとんどないので,できるだけ例外をマスクして,Eitherなどで把握・対処するようにしています。STMを利用したチャンネルで,スレッド間の通信をおこなうようにしました。Haskell用TUIライブラリを使ってみたBrickを使ってみました。GUIの基礎概念は知ってはいましたが,使ってみたのはほぼ初めて。POSシステム,パソコン通信プログラム(端末エミュレータ)などを作っていました。オブジェクト指向という考えが広まる前で,インタフェースもGUI普及前。Plusで卒業論文を書いていたのでまさにエバンジェリストといった感じでしたが,イベント処理とか,GUIやオブジェクト指向でのクラスとかいった概念は,Smalltalkでちょっと触ったくらい。いえ,Brickのドキュメントを読むと一通り書いてあるので,それで済ませましたが。グラフの作成TextPlotというそのものズバリの名前の,テキスト文字によるグラフ作成ライブラリを使ってみました。ライブラリのソースを読んでみたのですが,仕組みとしては事前に考えていた内容そのものであったものの,その表現が関数プログラミングの利点を活用してすごく簡素に書かれていてびっくり。機能がシンプルで,随分前に進化が止まっているようなので,カラー化とか凡例表示とか,Vector化とか,いろいろ改造していきたい。本来はMacBookAirなどノートパソコンではなく,ラズパイなど超小型コンピュータで稼働させたいところですが,大型ライブラリBrickを使うために,ラズパイで直接コンパイルすることは難しそう。利用してのコンパイルはまだ完了していません。これをなんとかしたい。表示要素が多いと,グラフの把握が難しくなります。カラー機能自体は既に使っていますが,TextPlot側が対応していないので,要改造。凡例表示や,X軸時刻表示(今は単なる相対時系列番号)も課題。終わりに向かってハードの監視というきわめてHaskell向きではない分野で手続き的な表現を多用していましたが,少しづつ関数プログラミングらしい表現を取り入れています(FunctorやAplicativeFunctorな演算子の導入とか)。抽象化が進むので,機能を増やしてもそれほどソースの行数が増えず,実行速度もあまり遅くならないことに感動。プロトコルが記載されているサイト内でのURLが変更されていた1。サイトのリニューアルにともなうものらしい。ことで,Roverグループが自社の車の車載制御システムとしてモトローラグループと開発し,1990年代に使用していたもの。1.3iも搭載している。関数型言語Haskellの学習を兼ねて作成していたMEMSデータの常時読み出し・表示プログラムは,概ね動作するようになった。実装済みの機能としては,1)ECUデータやエラーデータの読み出しと表示(概ね0.4秒サイクル),2)ECUのエラーリセットコマンドの発行,3)ECUコマンド(アクチュエータ操作)の発行の3つ(ただし,3)についてはすべてのコマンドを実装したわけではなく,動作確認のためいくつか実装したのみ)。Pi(Paspberian)環境下でも動作させられるかの実験中。実験が成功すれば,ラズパイを車載し,モバイルバッテリーあるいは12V電源の変圧で走行時は常時データを表示・採取できるようにしたい。読み出しているECUデータただし,うちのECU(型式不明)は,駐車またはニュートラルの信号がエアコンオンオフの信号になっている。著作者の表記が当該サイトにはないので,誰がメンテナンスしているかは不明。当初は某大学のサイトに掲載されていたので,その大学の卒業生が運営しているのではないかと推測。ECUデータ読み出しプログラムを動作させるためにRaspberryPiを用意したのだが,Haskellのコンパイルがstackを使ってはできなかった。stackが使えないと,ライブラリの準備とかが大変。buildすると,アセンブラが,この機械語はARMでは使えないとのたまうエラー発生。原因はコンパイル時にCPUアーキテクチャがGHCに伝わらないstackのバグ。対策は海外サイトのブログを参考に,GHCの設定ファイルにアーキテクチャ指示オプションの追加。以下は上記の参考サイトに書いてあるものだが,実際にはGHCの8.6.3がインストールされていたので,適宜8.0.1を8.6.3に読み替え。Miniはあえなく修理にまわすことに...。ラズパイによるECUのモニタリングソフトの出番は先です。現在はRaspberianのもとになるディストリビューションが変更されたためか,関係者のご尽力により普通に入れられます(ただし,前述のGHCのコンパイルオプションが渡されないバグに注意)。大型のライブラリをコンパイルしたり,インストール直後の何もコンパイルされていない状態から大量のライブラリをコンパイルすると,メモリとディスク上のスワップ領域を使い切ってOSごと固まってしまう模様。WiFiドングルにはドライバが必要(ただし,ヤマダ電機で購入したElecomのドングル(型式:●●)は最新のOSだと初期設定でそのまま動きました)。Mini,ただいま乾燥中。2019/08/03そして午後は別の事業者さんを訪問そして午後は別の事業者さんのところへ新商品開発の状況聴取と経営相談に行ったのですが,先程ご紹介したとおり,途中でコンビニに立ち寄って停車しようとしたら突然のラジエータ液噴出でびっくり。皮膚が赤くなったくらいで幸い火傷もなかったですし,周りの方が心配して見に来たり車を押していただいたりしてありがたかったです。車内の電線がやたら多いのは,開発中のミニのECUからデータをひろうモニタープログラムのため(ブレブレの画面が開発中のテキスト文字表示バージョン)。今回の一件を教訓に,冷却液温度の警告表示機能なんかも追加しなければ。帰りは気晴らしに映画か外食かと迷いましたが,パスタに惹かれて外食に。大府駅前にてさて,栄養もとったので,帰宅します。Brickこのコンテンツはパスワードで保護されています。閲覧するには以下にパスワードを入力してください。MEMSからのデータの読み出し,ちょこちょこと作り込みの甘い部分はあるものの,データは収集できるようになったので,今日の遠出の往復の際のデータを記録し,手作業で視覚化してみた。これは豊田から名古屋へ移動した際のデータの抜粋。灰色の幅ひろいデータは酸素濃度センサ値。数値で見たときはかなりばらついているんじゃないかと思ったが,グラフ化してみたらきれいに一定幅に収まっている。異常値(20V)がある。定電圧装置が故障しかかっているのかなと思ったが,その瞬間のエンジン回転数は863rpmなので,発電電圧がそれほど上がっているとも思えない。コイルタイムなるものも記録をとったが,みると,蓄電池電圧の上下に反比例して変動している。MEMSの解説文書によれば,インジェクタ方式の制御ではエンジン回転数とバッテリ電圧に応じて点火装置の通電時間を制御しているとのことなので,このことなのだろう。その文書では3.0から3.5ミリ秒の範囲で制御しているとのことであったが,手元のデータでは4.58から6.17ミリ秒となっている。ちなみにエンジンルームでのコネクタと電線はこんな処理。車内側は基盤むき出しです。ひっかけて短絡しないようエポキシ樹脂で適当にかばってあります。ECUからどデータ読み出しプログラム,一段落しました。アプリを関数プログラミング言語Haskellで作るというかわった取り組みです。出ている不具合の原因究明の参考情報をとりたいがためにはじめました。アイドリング中にエンジン停止する不具合が時々発生している他,アクセルを踏み込むと,特に上り坂で1800rps付近でエンジンが瞬停(?ノッキング?)するような現象が雨の日や標高の高い山間地でよく発生するような状況です。1.3iに搭載されているECU接続用のUSB-シリアル変換ケーブルを作成した。変換チップ付きUSBケーブルは電子工作ではおなじみ秋月から購入し,自分で電線をはんだ付け。ECU側からの信号線はコネクタは通販で大垣の某事務用品店から購入,電線は大須の電気街で耐熱電線を購入して,自分ではんだ付け。Gaugeを動作させることができた。この環境で,しばらくログを取ってみた。上記の不具合との関連はわからないが,時々,各センサの値がおかしな値となるほか,バッテリ電圧も降下する様子。コネクトが切れ,再接続をしなければならない現象も発生。電装系にトラブルを抱えている模様。テスタを車内に持ち込み,シガレットプラグで電圧をモニタリング。当初は特に不具合はなかったが,そのうちエンジンの回転数に合わせて電圧が比例して変化する現象が発生。修理業者さんに見てもらったところ,発電機の定電圧化装置が壊れていたので修理。エンジン停止が頻発したため,一時期,修理業者さんに長期入院させる。この頃,業者さんも発電機交換やECU点検・交換など様々な取り組みをしていただいたが,現象はおさまらなかった。鉄製の部品に穴の空いた場所を電線が走っており,その部分の被覆が剥けているのを見つけていただき,補修していただいた折はしばらく現象はおさまったが,その後復活。ECUのコネクタ部分の接触が悪くなっているかもと爪をおこしていただいたりした後,やはりしばらく現象はおさまったが,その後復活。修理業者さんいわく,動力系に不具合はなく,この年式にしては状態が良いとのこと。Gaugeを立ち上げ,接続させ,ログをとる,という一連の作業をだんだんわずらわしく思うようになり,macOSのTerminal.appで直接動くものを作ることに。Piに簡単に移植できるだろうから,気軽に使えるようになるだろうという目論見。やるなら新しいことに挑戦ということで,関数型言語Haskellで作ることにする。IoTと抽象化・遅延評価などというHaskellの特徴はあまり相性が良いというわけではないが,だからこそ誰もそんなにやらないだろうということで挑戦。HaskellでUSB−シリアル変換ケーブルの通信をするのにOSのシステムコールを使うかとも思ったが,serialportというライブラリをHackageで見つけ,これを使うことに。Haskell環境に慣れていなかったため,当初はうまく自動で組み込めず,ソースを自分のプログラムのソースに移して動作させ始めた(その後,パッケージ管理の仕組みを学んで,外部ライブラリとして管理できるようになった)。Gaugeのソースを参考にしながら接続アプリを開発。当初は初期化コマンドは通ったが,コマンドに対する反応をうまく拾えなかった(4バイト読み込み指定でも2バイトしか拾えないなど。ECU側が数10MHzで動いているし,9600bpsという速度なので,タイムアウトの設定かといろいろ変えてみたが,結局,1バイトずつ読み込むことで解決)。Gaugeは32バイトを設定している)。ECUのログを見ると2016年4月3日のものが残っていたので,遅くともその頃から実際に試行錯誤していたはずだが,記事として出てくるのは2016年から。2Bとディスプレイを発注した記録が残っている。Gaugeのタイムスタンプは2016年2月。非公開の書きかけ記事で関数型言語プログラミングのデザインパターンに関するものが2015年5月2日付けで見つかった。HaskellをECUデータ読み出し用に使おうとしだしたのは2015年から2016年にかけてか。以下,魚野のサイト内ページです。Miniの現状...2016/7/10付。このときにはすでにデータをとっている。MyECU...2017/4/16付。ありもののソフトを動かしてもよいのだけれど,ログを解析するのにやっぱりmacでやりたいのと,日本仕様ECUの対応を組み込むのが楽という点で,自作を続けます。今後の予定パフォーマンス計測と改善。現在は80と7Dのデータを読み込んで表示する1周期に400ミリ秒程度。非同期IO・マルチスレッドにしてもよいのだが,どうせデータを待っている間にmac側がすることもないので,シングルスレッドの基本線は変えない予定。改修はHaskellのチューニングの勉強として,読みづらい表現の変更や例外処理の改善(ByteStringでindexの指定を間違うとHaskellといえど実行時エラーで止まってしまう—止まってしまうのは黙って意図しない処理が行われるよりよっぽどマシなのだが—のでその対策をきちんとする)など。上記と関連するが,ちゃんとHaskellらしい構造に。今はファイルハンドル情報(を含んだSerialPort型の情報)をあちこち持ち回っているが,本来,カプセル化すべき。文字列の++演算も遅いだろうし,メモリリークの現状も把握できていない。1回あたり数十バイトの情報を保持するのにByteStringを多用してループをまわしているので,かなり効率の悪い構造になっていてガベージコレクションの時間もかなりとなれているのではと想像する。出力はcsv形式なので,これをもとに別途GUIを使った表示の仕組みを用意する。得体の知れない互換ワンボードが用意してあるので,そちらで動くようにHaskell環境,OS環境,ディスプレイ環境を整え,車内に常時備え付けられるようにする。ケーブルは今の半自作USBシリアル変換ケーブルをそのまま転用。広域低電力WANなどの利用で1992年式Miniをコネクティッドカーにする?関数型言語でのIoT対応について,何かしら発展の方向性を考えてみる(たくさんのセンサからいろんなデータが来て,それを処理していく。センサからデータを拾う頻度がまちまちになるだろう。データの処理について,おそらくは柔軟にユーザーに変更できるようにしたくなるだろう。モナドなどは概念をある程度理解し,使えるようにはなった(作れるまでには至っていない)ので,Haskellでのモナド,並行並列処理,GUI,DSL,FRPを使いこなせるように。関数型言語プログラミングでの抽象化やモナドなどの考え方は,生物の意識という問題と何かしら関係がありそうな気がするので,それを検討してみる。Bourassa氏のページ。MEMSの診断プロトコルに関するページ。今はbearinghead.comというドメインに掲載されている(記事の掲載日時は2014-04-21となっているが,2015年6月と12月に追記されている)。オープンソースで無料の診断情報ソフト(MEMSGauge)やライブラリ(librosco)が紹介されている他,接続用のシリアルケーブルの作り方(利用するUSBシリアルチップやコネクタの規格・入手先情報を含む),ECUのプロトコルなどの詳細が紹介されている。このページがなければ,今回のプロジェクトはなかった。上記サイトからリンクされている。2015年に開設された模様。(ビデオ)...最近見つけた,おそらく販売店向けなどのために作られた技術解説ビデオ。ECUがどんな情報をもとに何を制御しているかを簡単に解説している。diagnostics...android用の診断ソフトを紹介している。androidは興味の対象外なので一応あるということだけ知っておく。Pascalや,Pascalを開発したWirthが後継として開発した言語,Modula-2を使って端末エミュレーションプログラムなどを作っていました。シリアル通信の大枠は理解しているのですが,今回はmacOSというUnix系のOSで,しかもUSBポートを通じてのシリアル通信ですので,いろいろよくわからない点があります。HOWTOなどであらためて基礎から勉強してみました。HOWTO...シリアル通信の基礎情報や,Linux上での情報。さんのサイトに,Androidoのソフトと自作ケーブルを使った接続事例,市販されているらしい簡易モニタでの診断事例が時々紹介されている。気になる」...2013/2/1付。Diag」を発見」...2015/2/1付。ケーブル作成記録など。junkなMiniとあたい「Androidのアプリ「MEMS_Diag」を試してみます。」...2015/8/29付。lite」をミニクーパーに接続してみる」...2016/2/6付。自作ケーブルとAsusuのAndroidを使った接続事例。みんカラ「自作ECU故障診断器?」kazsp氏...2016/6/12付。Androidで参考ページなども掲載。ガソリンエンジン車の終焉も近いでしょうし,カーシェアリングなども東京ほどではないですが名古屋でも充実してきつつありますので,いつまでMiniを所有し続けるのかはわかりません。そもそもデータを吸い出しても400ミリ秒単位では,現在出ているような瞬停みたいな現象や前触れのない回転数の低下の原因究明に役立つものでもなさそうですが...。工学部出身の元エンジニアとしては,こういう技術探求がしたくなるのです。データを拾うプロジェクト,ぼちぼち進めています。やっていますが,実際の稼働ではラズパイなどワンボードの小型PCでやろうかと。はあちことのプラットフォームで動くのでいいのですが,問題はGUI。他のプラットフォームと共通のデザインだとものすごい違和感を感じます。いう新しい考え方に基づく実装例も増えてきています。)も2016年に出版されたので,計算機科学分野の英語の復習の意味も含めて電子ブックを買い求めて読み進めています(ちなみに最近,書店店頭で翻訳本を見かけましたが,意味が読み取りにくい翻訳となっている箇所が多数あったため,購入は見送りました)。ライブラリについて調べてみることにしました。閲覧した際の記述内容に基づいたもの。フレームワークである。いまどきは誰でもブラウザをインストールしている。インストールするだけでよい。このライブラリは多数のプラットフォームで動作する。ユーザインタフェースを作成する際、HTMLの機能をすべて使用することができる。これは素晴らしいことではあるが、うっかりするとはまり込んでしまうことにもなりかねない。それゆえ、このライブラリには、CSSを使用しなくてもユーザインタフェースを素早く構築できるよう、レイアウトコンビネータが含まれている。他言語接続機能)を利用してブラウザの中でJavaScriptを走らせることも可能である。より、ユーザーとのやりとりのプログラミングでイベント駆動式のスタイルを伝統的な手続き型言語で構築するときに陥りがちなスパゲッティコードを避けることができる。ライブラリを持っているが、それを使うか否かは自由である。できないことウェブのフロントエンドではない。サーバはローカルホストで稼働することを想定している。(ネットを経由する)ウェブアプリとして使用するには遅延が問題となるだろう。ローカルネットワークの多数のユーザーを想定した場面には向いているということ。