MEMS(ECU)モニタ開発状況 GHCのバグ?環境整備の問題?

エンジンルームを乾燥中の Rover Mini 1.3i

インジェクション・ローバーミニの車載コンピュータのモニタリング,Macではstack環境下で順調に開発・運用していますが,ラズパイでの運用は未完。stackでのコンパイルがまだできないので,ghcで直接コンパイルをしてみたのですが…

現状把握:何が起こっているか

使用している serialport パッケージ内の関数で引数の型として指定されている ByteString の参照先が Mac でstackを使ってコンパイル(stack 2.1.3) した場合と RaspberryPi で直接GHCでコンパイル(GHC 8.0.1 on Raspberian 4.14.79-V7+)した場合とで異なる。ラズパイ上ではなぜかbytestringのインターナルモジュール内の定義を参照し,呼び出し側は,モジュール内で明示的に指定した公開ライブラリを見にいっています。

具体的には,serialportパッケージのsend関数の第2引数の型が合いません。serialportの中では

> import qualified Data.ByteString.Char8 as B
>(中略)
> send :: SerialPort -> B.ByteString -> IO Int

と定義されています。一方,自作のモジュール内では,

> import qualified Data.ByteString.Char8 as BS
> (中略)
> send p $ BS.singleton (chr 0x0a)

みたいな感じで呼び出しています。

引数の型は合っているはず。Data.ByteString.Char8 (以下,「D.B.C」と省略)でのsingletonの定義は,

> singleton :: Char -> ByteString

です(尤も,D.B.C内のByteStringの定義は,後述の通り,Internalモジュールからインポートしていますが)。

実際,macOSでstack buildをした場合,問題なく通りますし,運用もできます。ところがraspberianで ghc でのコンパイルをすると,BS.ByteString は Data.ByteString.Internal で定義されているbytestring-0.10.8.1:Data.ByteString.Internal.ByteStringと合わないというわけで,型の不一致とされてしまいます。うーむ。

原因分析:何が原因か

serialportのソースをおっかけてみると,まずByteStringの定義は前述の通り,D.B.Cを参照しています。また,sendの第2引数は,途中でWord8に変換するため,B.unpackをかけており,その先のD.B.Cのほうでは,unpackは結局,内部関数のunpackAppendCharsLazyを束縛しています。

> unpackChars :: ByteString -> [Char]
> unpackChars bs = unpackAppendCharsLazy bs []
> (後略)

そこでunpackAppendCharsLazyを見ると,内部のByteStringの定義を用いて関数が定義

> unpackAppendCharsLazy :: ByteString -> [Char] -> [Char]
> unpackAppendCharsLazy (PS fp off len) cs
> (後略)

されています。

InternalモジュールでのByteStringの定義は
> data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload
> {-# UNPACK #-} !Int -- offset
> {-# UNPACK #-} !Int -- length
> deriving (Typeable)

となっています。これは外部公開していないモジュールのはずですから,ここを参照すべきではないでしょうし,D.B.Cのほうで,ちゃんとByteStringをエクスポートしています。

> module Data.ByteString.Char8 (
>
> -- * The @ByteString@ type
> ByteString, -- abstract, instances: Eq, Ord, Show, Read, Data, Typeable, Monoid
> (後略)

ですので,D.B.Cを指定したByteStringで型は一致するはずなのですが…

真因追求:本当の原因として考えられること

  • raspberian 上で整えた GHC の環境がおかしい? … 冒頭で述べたように,stackでの開発がラズパイ上ではできていません。cabal ライブラリのコンパイルをはじめて,大きなライブラリのコンパイルでメモリが不足して止まってしまう(一応,仮想メモリとして4GBを確保してあるのですが)。stackの環境構築がこのように中途半端になっているので,それがローカルなライブラリDBを構成するなどの悪さをしている?
  • 環境・構成に依存するGHCの挙動の違い? … GHC のバージョンや,Stackを使った場合と生で呼び出した場合のGHCに渡されるオプションや構成の違いが真因の可能性も。

考えられる対処

いずれにしても,検証するには環境を合わせることから始める必要がありそうです。そもそも stack ・ GHC 直接という違いもあり,macOS と raspberian とでは GHC のバージョンも違うため,そこらへんを合わせてみることが必要なのかもしれません。

思い切って,ラズパイ用は go言語で組み直してみる?手続き型言語の冗長さと,代数データ型やモナドが使えないなどの面倒さにつきあうのはためらいがありますが…。

蛇足

こんなデータを0.5秒おきにとっています。開発目的は,時々発生するECU気絶に由来すると思われるエンジン停止や回転数低下の原因を特定したいためと,IoTや関数型言語でのプログラミングの勉強。

下記画像では,右端の部分で時々横線が入っているように見える部分が,そこが,ECUのデータ読み出しができなかった瞬間です。左側の数値が羅列されている部分でいうと,文字列が並んでいる行です。

気が付かれる方もあるかもしれませんが,魚野の車はマニュアル車です。ですが,ECUが原因かという検証のため,修理業者さんが別の車のオートマ用ECUをつないでくれたために,オートマと表示しています。ECUが変わっても,瞬停や回転数落ちはまだ発生していますので,ECUそのものが原因ではないと思っています。

Rover Mini ECU(MEMS) Monitor CSV Data
Rover Mini ECU(MEMS) Monitor CSV Data

ECUモニタ開発状況

ローバーミニ,すでにクラッシックカーの領域に入りつつありますが,1992年以降に日本で新車として販売されたミニにはインジェクション方式が導入され,制御用のコンピュータECUも載せている。趣味として関数プログラミング言語 Haskell を使ってこの制御用コンピュータのデータをモニタリングしようとしてきましたが,少しづつ開発を進めています。ちなみに現在も引き続き車内にMacBookAirを持ち込んで,運転中に自動記録しつつ,車載モニターにライブデータを表示しています。

スライドショーには JavaScript が必要です。

開発の現況

全体としては安定してモニタリングできるようになり,プログラムの一部を改造しても他の部分に影響を出しにくくなりました(モジュラー化が進んだ。以前は各パーツが密接に絡み合っていたため,一部を改造するとしばらくコンパイルエラーのみならずロジックエラーを誘発していた。)。

Rover Mini ECU(MEMS) Monitor Screen Shot
2019年5月の Rover Mini ECU(MEMS) Monitor スクリーンショット

これは2019年5月にとったスクリーンショット。数値表示だけでは一瞥したときに全体像が把握できないなと,アスタリスクによる各データのリアルタイム棒グラフをつけたもの。

試作したRover Mini ECUモニタの画面
開発が進んだRover Mini ECUモニタのスクリーンショット

そしてこちらは過去データや他のデータとの相関を見たいと思い,縦棒グラフを並べるようになったバージョン。

2019年9月現在の画面

そして現在は複数のデータを同一のグラフに描画しています。一通り走った後,エンジンを停止した状態(エンジンを切っても10秒くらいはECUが動作しています。おそらく冷却液用の冷却ファンをしばらくまわすため)での画面キャプチャ。画面右側は,テキスト表示でむりやり表現した温度や回転数など各種センサー値の重ね合わせグラフ。テキスト表示なのは,ラズパイなど超小型コンピュータで動作させる際に簡単に実現できそうだからです(GUIはメモリや処理能力に要求される水準がTUIに比べて圧倒的に高いが,超小型コンピュータにそれを求めるのは酷ですものね)。

ループ処理や例外処理を見直し,エンジンの稼働状況やECUと繋がれた信号線の状態に影響を受けにくくなり,安定して稼働するようにしました。

こちらのログは岡崎から名古屋に帰る道すがら記録したものです。時々接続が切れて再接続しています(再接続に1秒近くかかっているのはあえて待ち時間を1000m秒入れているから)。路面の凸凹やアクセルオフ時の振動に連動(?)して接続が切れているので,コネクタかセンサ固定に何か問題がありそう。

Rover Mini ECU(MEMS) Monitor CSV Data
Rover Mini ECU(MEMS) Monitor CSV Data

得られた学び

前回の報告から進展したHaskellの学び,Haskell中級編といったところでしょうか。

モナドを作れるようになった

モナド,Haskell初心者のつまづきの石です。わかってしまえばなんてことはない概念ですが,RealWorldHaskellとかでゆっくりまなびつつ,試しにECUとのコミュニケーションモジュールで自作のモナドを作ってみました。裏で動く仕組みが理解できたため,ソースを見ても動作に検討がつくようになりましたし,liftとか融合とか,避けていた知識を身に着けたら,いろんなことがより簡素に表現できるようになりました。結局,ECUとのコミュニケーションモジュールは,出来合いの ReaderT を活用しています。ちなみに,モナドはRealWorldHaskellの記載内容から変わったところ(変わるところ)があるので,要注意。

Haskellでの例外処理を理解した

関数やIOモナド,スレッド間通信などがからむので,”Parallel and Concurrent Programming in Haskell”を電子書籍で購入して並行プログラミング関係だけ読み,初歩はマスターできました。このプロジェクトではマルチスレッド間の資源の取り合いはほとんどないので,できるだけ例外をマスクして,Eitherなどで把握・対処するようにしています。STMを利用したチャンネルで,スレッド間の通信をおこなうようにしました。

Haskell用TUIライブラリを使ってみた

Brickを使ってみました。GUIの基礎概念は知ってはいましたが,使ってみたのはほぼ初めて。プログラミングをよくやっていたのは学生時代で,まだGUIが一般的でない時代にPascalやModula II でPOSシステム,パソコン通信プログラム(端末エミュレータ)などを作っていました。まだオブジェクト指向という考えが広まる前で,インタフェースもGUI普及前。ユーザーとしては,まわりがワープロを使っている時代にMacintosh Plusで卒業論文を書いていたのでまさにエバンジェリストといった感じでしたが,イベント処理とか,GUIやオブジェクト指向でのクラスとかいった概念は,Smalltalkでちょっと触ったくらい。学び直しました。とはいえ,Brickのドキュメントを読むと一通り書いてあるので,それで済ませましたが。

グラフの作成

TextPlotというそのものズバリの名前の,テキスト文字によるグラフ作成ライブラリを使ってみました。ライブラリのソースを読んでみたのですが,仕組みとしては事前に考えていた内容そのものであったものの,その表現が関数プログラミングの利点を活用してすごく簡素に書かれていてびっくり。ただ,機能がシンプルで,随分前に進化が止まっているようなので,カラー化とか凡例表示とか,Vector化とか,いろいろ改造していきたい。

今後の計画

ラズパイでの稼働

本来はMacBookAirなどノートパソコンではなく,ラズパイなど超小型コンピュータで稼働させたいところですが,大型ライブラリBrickを使うために,ラズパイで直接コンパイルすることは難しそう。Docker と QEMU でクロスコンパイル環境を用意しましたが,stack を利用してのコンパイルはまだ完了していません。これをなんとかしたい。

グラフ表示の改善

表示要素が多いと,グラフの把握が難しくなります。カラー機能自体は既に使っていますが,TextPlot側が対応していないので,要改造。
また,凡例表示や,X軸時刻表示(今は単なる相対時系列番号)も課題。

終わりに向かって

ハードの監視というきわめてHaskell向きではない分野で手続き的な表現を多用していましたが,少しづつ関数プログラミングらしい表現を取り入れています(FunctorやAplicativeFunctorな演算子の導入とか)。抽象化が進むので,機能を増やしてもそれほどソースの行数が増えず,実行速度もあまり遅くならないことに感動。

OLYMPUS DIGITAL CAMERA

MEMSプロトコルのページ

MEMS Monitor作成の際に参考にしているMEMS のプロトコルが記載されているサイト内でのURLが変更されていた1。サイトのリニューアルにともなうものらしい。

新URL http://www.bearinghead.com/car_stuff/mems_interface/

MEMSとは

MEMSとは, Modular Engine Management System のことで,Roverグループが自社の車の車載制御システムとしてモトローラグループと開発し,1990年代に使用していたもの。魚野が1992年に新車で購入していまだに乗り続けているRover Mini Cooper 1.3iも搭載している。

MEMS Monitorの現状

関数型言語Haskellの学習を兼ねて作成していたMEMSデータの常時読み出し・表示プログラムは,概ね動作するようになった。実装済みの機能としては,1)ECUデータやエラーデータの読み出しと表示(概ね0.4秒サイクル),2)ECUのエラーリセットコマンドの発行,3)ECUコマンド(アクチュエータ操作)の発行の3つ(ただし,3)についてはすべてのコマンドを実装したわけではなく,動作確認のためいくつか実装したのみ)。

(ミニが修理が終わってもどってきたら,動作中の画面を撮影して掲載します)

実装計画中の機能

  • 重ね合わせグラフでの表示
  • 冷却液温度急上昇などの異常検出と警告表示
  • IoT用のSIMで走行中のデータを順次クラウドに送信

動作環境としてはmacOS(High Sierra, Catalina),Haskell(stack)を利用して検証しており,現在,Raspberry Pi(Paspberian)環境下でも動作させられるかの実験中。実験が成功すれば,ラズパイを車載し,モバイルバッテリーあるいは12V電源の変圧で走行時は常時データを表示・採取できるようにしたい。

読み出しているECUデータ

ただし,うちのECU(型式不明)は,駐車またはニュートラルの信号がエアコンオンオフの信号になっている。

    engineSpeed :: Int   -- Engine speed in RPM (16 bits)
  , coolantTemp :: Int   -- Coolant temperature in degrees C with +55 offset and 8-bit wrap
  , ambientTemp :: Int   -- Computed ambient temperature in degrees C with +55 offset and 8-bit wrap
  , intakeATemp :: Int   -- Intake air temperature in degrees C with +55 offset and 8-bit wrap
  , fuelTemp    :: Int   -- Fuel temperature in degrees C with +55 offset and 8-bit wrap. This is not supported on the Mini SPi, and always appears as 0xFF.
  , mapSensor   :: Int   -- MAP sensor value in kilopascals
  , battVoltage :: Float -- Battery voltage, 0.1V per LSB (e.g. 0x7B == 12.3V)
  , throttlePot :: Float -- Throttle pot voltage, 0.02V per LSB. WOT should probably be close to 0xFA or 5.0V.
  , idleSwitch  :: Bool  -- Idle switch. Bit 4 will be set if the throttle is closed, and it will be clear otherwise.
  , unknown0B   :: Word8 -- Unknown. Probably a bitfield. Observed as 0x24 with engine off, and 0x20 with engine running. A single sample during a fifteen minute test drive showed a value of 0x30.
  , pnClosed    :: Int   -- Park/neutral switch. Zero is closed, nonzero is open.
                         -- Fault codes. On the Mini SPi, only two bits in this location are checked:             
  , faultCode1  :: Bool  -- : Coolant temp sensor fault (Code 1)
  , faultCode2  :: Bool  -- : Inlet air temp sensor fault (Code 2)
  , faultCode10 :: Bool  -- : Fuel pump circuit fault (Code 10)
  , faultCode16 :: Bool  -- : Throttle pot circuit fault (Code 16)
  , unknown0F   :: Word8 -- Unknown
  , unknown10   :: Word8 -- Unknown
  , unknown11   :: Word8 -- Unknown
  , idleACMP    :: Int   -- Idle air control motor position. On the Mini SPi's A-series engine, 0 is closed, and 180 is wide open.
  , idleSpdDev  :: Int   -- Idle speed deviation (16 bits)
  , unknown15   :: Word8 -- Unknown
  , ignitionAd  :: Float   -- Ignition advance, 0.5 degrees per LSB with range of -24 deg (0x00) to 103.5 deg (0xFF)
  , coilTime    :: Float   -- Coil time, 0.002 milliseconds per LSB (16 bits)
  , unknown19   :: Word8  -- Unknown
  , unknown1A   :: Word8  -- Unknown
  , unknown1B   :: Word8  -- Unknown
  , lambda_voltage:: Int  -- This lambda value is a calculated value (if it is the same as the British emissions test).     And a value of, say, 1.05, suggests it is 5% too lean.   But, if your oxygen (and CO and HC) readings are all good, then it suggests your high lambda reading is because of a leak in the exhaust wgich pulls in fresh air (and oxygen).     You could try starting your car when it is cold and put your hand over the exhaust pipe and look underneath to see if water is leaking from any if the joints. 
  , closed_loop'  :: Int  -- 0 : Open Loop, others : Closed Loop  
  , fuel_trim'    :: Int  

  1. 著作者の表記が当該サイトにはないので,誰がメンテナンスしているかは不明。当初は某大学のサイトに掲載されていたので,その大学の卒業生が運営しているのではないかと推測。 

そして午後は別の事業者さんを訪問

そして午後は別の事業者さんのところへ新商品開発の状況聴取と経営相談に行ったのですが,先程ご紹介したとおり,途中でコンビニに立ち寄って停車しようとしたら突然のラジエータ液噴出でびっくり。ちょっと皮膚が赤くなったくらいで幸い火傷もなかったですし,周りの方が心配して見に来たり車を押していただいたりしてありがたかったです。

水を継ぎ足して事業者さんのところまで移動はしましたが,漏れがかなりひどいので,ビショビショになった車内をしばし乾かしつつ,経営戦略会議。

冷却水漏れを起こしたミニ車内を乾燥中
冷却水漏れを起こしたミニ車内を乾燥中

車内の電線がやたら多いのは,開発中のミニのECUからデータをひろうモニタープログラムのため(ブレブレの画面が開発中のテキスト文字表示バージョン)。今回の一件を教訓に,冷却液温度の警告表示機能なんかも追加しなければ。

試作したRover Mini ECUモニタの画面
試作したRover Mini ECUモニタの画面

帰りは気晴らしに映画か外食かと迷いましたが,パスタに惹かれて外食に。

夕食のパスタ 大府駅前にて
夕食のパスタ 大府駅前にて

さて,栄養もとったので,帰宅します。映画は明日以降に。

 

きれいに制御されている

Rover MEMSからのデータの読み出し,ちょこちょこと作り込みの甘い部分はあるものの,データは収集できるようになったので,今日の遠出の往復の際のデータを記録し,手作業で視覚化してみた。

これは豊田から名古屋へ移動した際のデータの抜粋。

灰色の幅ひろいデータは酸素濃度センサ値。数値で見たときはかなりばらついているんじゃないかと思ったが,グラフ化してみたらきれいに一定幅に収まっている。青はエンジン回転数,橙色は蓄電池電圧。一箇所,異常値(20V)がある。定電圧装置が故障しかかっているのかなと思ったが,その瞬間のエンジン回転数は863rpmなので,発電電圧がそれほど上がっているとも思えない。コイルタイムなるものも記録をとったが,みると,蓄電池電圧の上下に反比例して変動している。MEMSの解説文書によれば,インジェクタ方式の制御ではエンジン回転数とバッテリ電圧に応じて点火装置の通電時間を制御しているとのことなので,このことなのだろう。但し,その文書では3.0から3.5ミリ秒の範囲で制御しているとのことであったが,手元のデータでは4.58から6.17ミリ秒となっている。謎。

ちなみにエンジンルームでのコネクタと電線はこんな処理。

車内側は基盤むき出しです。

ひっかけて短絡しないようエポキシ樹脂で適当にかばってあります。

ECUデータ読み出しその後

手が空いたときにちょこちょこと進めてきたRover Mini 1.3i のECUからどデータ読み出しプログラム,一段落しました。macOSで動かす IoT アプリを関数プログラミング言語Haskellで作るというかわった取り組みです。

これまでの経緯

もともとは,自分のMini 1.3i で出ている不具合の原因究明の参考情報をとりたいがためにはじめました。不具合は,具体的に はアイドリング中にエンジン停止する不具合が時々発生している他,アクセルを踏み込むと,特に上り坂で1800rps付近でエンジンが瞬停(?ノッキング?)するような現象が雨の日や標高の高い山間地でよく発生するような状況です。

  • 下記のCollin Bourassa氏のページで掲載されていた情報をもとに,自分のMini 1.3iに搭載されているECU接続用のUSB-シリアル変換ケーブルを作成した。変換チップ付きUSBケーブルは電子工作ではおなじみ秋月から購入し,自分で電線をはんだ付け。またECU側からの信号線はコネクタは通販で大垣の某事務用品店から購入,電線は大須の電気街で耐熱電線を購入して,自分ではんだ付け。
  • 上記接続ケーブルを使い,MacBook Airにのせてある仮想ソフト上のWindows XP/10 にてMEMS Gaugeを動作させることができた。
  • とりあえず,この環境で,しばらくログを取ってみた。上記の不具合との関連はわからないが,時々,各センサの値がおかしな値となるほか,バッテリ電圧も降下する様子。また,突然コネクトが切れ,再接続をしなければならない現象も発生。かなり電装系にトラブルを抱えている模様。
  • まずは,しばらくテスタを車内に持ち込み,シガレットプラグで電圧をモニタリング。当初は特に不具合はなかったが,そのうちエンジンの回転数に合わせて電圧が比例して変化する現象が発生。修理業者さんに見てもらったところ,発電機の定電圧化装置が壊れていたので修理。
  • エンジン停止が頻発したため,一時期,修理業者さんに長期入院させる。この頃,業者さんも発電機交換やECU点検・交換など様々な取り組みをしていただいたが,現象はおさまらなかった。鉄製の部品に穴の空いた場所を電線が走っており,その部分の被覆が剥けているのを見つけていただき,補修していただいた折はしばらく現象はおさまったが,その後復活。
  • また,ECUのコネクタ部分の接触が悪くなっているかもと爪をおこしていただいたりした後,やはりしばらく現象はおさまったが,その後復活。
  • 修理業者さんいわく,動力系に不具合はなく,この年式にしては状態が良いとのこと。
  • 毎回,車中にMBAを持ち込み,仮想ソフトを立ち上げ,Windowsを走らせ,USBポートをWindows側に接続し,MEMS Gaugeを立ち上げ,接続させ,ログをとる,という一連の作業をだんだんわずらわしく思うようになり,macOSのTerminal.appで直接動くものを作ることに。macOSで動けば,Raspberry Piに簡単に移植できるだろうから,気軽に使えるようになるだろうという目論見。
  • どうせやるなら新しいことに挑戦ということで,関数型言語Haskellで作ることにする。IoTと抽象化・遅延評価などというHaskellの特徴はあまり相性が良いというわけではないが,だからこそ誰もそんなにやらないだろうということで挑戦。
  • HaskellでUSB−シリアル変換ケーブルの通信をするのにOSのシステムコールを使うかとも思ったが,serialportというライブラリをHackageで見つけ,これを使うことに。まだHaskell環境に慣れていなかったため,当初はうまく自動で組み込めず,ソースを自分のプログラムのソースに移して動作させ始めた(その後,パッケージ管理の仕組みを学んで,外部ライブラリとして管理できるようになった)。
  • 時間の合間合間を見てMEMS Gaugeのソースを参考にしながら接続アプリを開発。当初は初期化コマンドは通ったが,コマンドに対する反応をうまく拾えなかった(4バイト読み込み指定でも2バイトしか拾えないなど。ECU側が数10MHzで動いているし,9600bpsという速度なので,タイムアウトの設定かといろいろ変えてみたが,結局,1バイトずつ読み込むことで解決)。
  • コマンド7Dで得られるデータ数が,ずいぶん少ない14バイトであることが判明(MEMS Gaugeは32バイトを設定している)。MEMS Gaugeのサイトはある程度年式の新しいモデルに対応していたが,こちらは1992年に買った,クーラー付きの日本モデルであり,別のサイトで見るとECUのモデル番号も桁数からして違っている(うちのMiniのECUモデルを表す4バイトの値は39 00 00 5Cという値であり,おそらく部品番号 MNE10078 の, Manual  SPI – Japan – Cooper 向け)。

ECUのログを見ると2016年4月3日のものが残っていたので,遅くともその頃から実際に試行錯誤していたはずだが,記事として出てくるのは2016年から。Amazonの注文履歴では2013年に入門Haskellを,2014年にはReal World Haskellを,2016年にはRaspberry Pi 2Bとディスプレイを発注した記録が残っている。MEMS Gaugeのタイムスタンプは2016年2月。また,非公開の書きかけ記事で関数型言語プログラミングのデザインパターンに関するものが2015年5月2日付けで見つかった。HaskellをECUデータ読み出し用に使おうとしだしたのは2015年から2016年にかけてか。

以下,魚野のサイト内ページです。

Androidで動くPDAのGeminiや,Windows10で動くGPD Pocket でありもののソフトを動かしてもよいのだけれど,ログを解析するのにやっぱりmacでやりたいのと,日本仕様ECUの対応を組み込むのが楽という点で,自作を続けます。

今後の予定

  • パフォーマンス計測と改善。現在は80と7Dのデータを読み込んで表示する1周期に400ミリ秒程度。非同期IO・マルチスレッドにしてもよいのだが,どうせデータを待っている間にmac側がすることもないので,シングルスレッドの基本線は変えない予定。改修はHaskellのチューニングの勉強として,読みづらい表現の変更や例外処理の改善(ByteStringでindexの指定を間違うとHaskellといえど実行時エラーで止まってしまう—止まってしまうのは黙って意図しない処理が行われるよりよっぽどマシなのだが—のでその対策をきちんとする)など。
  • 上記と関連するが,ちゃんとHaskellらしい構造に。今はファイルハンドル情報(を含んだSerialPort型の情報)をあちこち持ち回っているが,本来,カプセル化すべき。文字列の++演算も遅いだろうし,メモリリークの現状も把握できていない。たかだか1回あたり数十バイトの情報を保持するのにByteStringを多用してループをまわしているので,かなり効率の悪い構造になっていてガベージコレクションの時間もかなりとなれているのではと想像する。
  • 出力はcsv形式なので,これをもとに別途GUIを使った表示の仕組みを用意する。本体がHaskellなのでElmを活用?FRPを使ってGUIにもHaskellを使う?昔ながらのcursesなどにしてしまう?
  • Raspberry Pi と得体の知れない互換ワンボードが用意してあるので,そちらで動くようにHaskell環境,OS環境,ディスプレイ環境を整え,車内に常時備え付けられるようにする。ケーブルは今の半自作USBシリアル変換ケーブルをそのまま転用。
  • 広域低電力WANなどの利用で1992年式Miniをコネクティッドカーにする?
  • 関数型言語でのIoT対応について,何かしら発展の方向性を考えてみる(たくさんのセンサからいろんなデータが来て,それを処理していく。また,センサからデータを拾う頻度がまちまちになるだろう。そして,データの処理について,おそらくは柔軟にユーザーに変更できるようにしたくなるだろう。
  • モナドなどは概念をある程度理解し,使えるようにはなった(作れるまでには至っていない)ので,Haskellでのモナド,並行並列処理,GUI,DSL,FRPを使いこなせるように。
  • また,関数型言語プログラミングでの抽象化やモナドなどの考え方は,生物の意識という問題と何かしら関係がありそうな気がするので,それを検討してみる。

参考にした資料など

ECUとの情報のやりとりのプロトコル等

きっかけは忘れましたが,このプロジェクトを始めるに当たり,大いに参考になったのは,独自解析でRover MiniのECUからの情報を読み出すプログラムを公表していたColin Bourassa氏のページ。

  • Rover MEMS 1.6 diagnostic Protocol以前はとある大学のサイトに掲載されていたColin Bourassa氏によるRover MEMSの診断プロトコルに関するページ。今はbearinghead.comというドメインに掲載されている(記事の掲載日時は2014-04-21となっているが,2015年6月と12月に追記されている)。オープンソースで無料の診断情報ソフト(MEMSGauge)やライブラリ(librosco)が紹介されている他,接続用のシリアルケーブルの作り方(利用するUSBシリアルチップやコネクタの規格・入手先情報を含む),ECUのプロトコルなどの詳細が紹介されている。このページがなければ,今回のプロジェクトはなかった。
  • MEMS Diagnostics (Google Group) … 上記サイトからリンクされている。2015年に開設された模様。
  • MG Rover MEMS Modular Engine Management Explained (ビデオ)…最近見つけた,おそらく販売店向けなどのために作られた技術解説ビデオ。ECUがどんな情報をもとに何を制御しているかを簡単に解説している。
  • Display/diagnostics utility for Rover MEMS 1.6 ECU…github内にあるプロジェクト
  • MEMS 1.6/1.9 ECU diagnostics…android用の診断ソフトを紹介している。androidは興味の対象外なので一応あるということだけ知っておく。

シリアル通信について

かつて学生時代,パソコン通信華やかりし頃の1980年代後半,PC-9800シリーズなどのDOS上でTurbo Pascalや,Pascalを開発したWirthが後継として開発した言語,Modula-2を使って端末エミュレーションプログラムなどを作っていました。ですのでシリアル通信の大枠は理解しているのですが,今回はmacOSというUnix系のOSで,しかもUSBポートを通じてのシリアル通信ですので,いろいろよくわからない点があります。そこでまずはLinux Serial HOWTOなどであらためて基礎から勉強してみました。

その他見つけた情報

車のSNSサイトみんカラや自動車販売・修理業者さんのサイトに,Androidoのソフトと自作ケーブルを使った接続事例,市販されているらしい簡易モニタでの診断事例が時々紹介されている。

そろそろガソリンエンジン車の終焉も近いでしょうし,カーシェアリングなども東京ほどではないですが名古屋でも充実してきつつありますので,いつまでMiniを所有し続けるのかはわかりません。そもそもデータを吸い出しても400ミリ秒単位では,現在出ているような瞬停みたいな現象や前触れのない回転数の低下の原因究明に役立つものでもなさそうですが…。まぁ工学部出身の元エンジニアとしては,こういう技術探求がしたくなるのです。

 

 

Haskellメモ というか,High Sierra と FTDI USB Serial メモ

以前からぼちぼち開発しているRoverMiniコンピュータデータ取扱用のプログラム,ので本日はその原因究明と対策実施。

現象

  • macOS X を High Sierra にしたら,FTDIのUSBシリアル変換機がマック上ではttyデバイスとして認識されなくなった。
  • 同じハードで仮想マシン上のWindows10では同変換器を検出し,正常にECUと通信できるので,マック上のドライバの問題と想定。
  • メーカー(FTDI社)の最新ドライバなどをインストールしてみたが,状況は変わらなかった。
  • High Sierra ではセキュリティ強化のため,場合によっては「システム環境設定」のセキュリティとプライバシー設定で,明示的に権限許可を与えないと動作しない機能拡張があるが,現時点では許可催促の表示は出ていない(ただし,当該催促は最初にその機能拡張が動作しようとしてから一定の時間以内にのみ表示され,その後は消えてしまうとのことなので,OSアップデート後にケーブルを初めて挿入した際,これを見逃した可能性はある)。

原因探索

ネットで検索した所,以下のことがわかり,ドライバが複数あって,衝突して不具合となっている可能性があるものと思われた。

  • Appleは,しばらく前(少なくとも Marverics )から,自社のFTDIチップ用ドライバを mac OS に含めて提供している。
  • 幾つかのサイトでは,FTDI社のドライバとApple社のドライバの切り替えを行って問題が解決したことを報告している。(例1例2例3例4
  • 両ドライバとも,kext形式で提供されている。
  • kextとは,加除可能なOS機能追加モジュールであり,sudo kextstatで現在使われているモジュールの確認ができる他,sudo kextload xx.kext でモジュールを追加することができる。
  • 当該ハードには,OSバージョンアップ前からFTDI社のドライバが入れてあり,機能していたが,こうした場合,High Sierraのインストールでは,(クリーンインストールであっても?)サードパーティー提供のドライバが新たな権限許可を与えずとも動作するようになっている模様。

対策

ドライバを一つにする。Apple社提供のものでまずは実験してみて,その上で,FTDI社のものを実験してみるかを判断することにした。実際の作業としては,以下の通り。

  • 存在しているドライバの確認。→/System/Library/Extentions にAppleUSBFTDI.kext 2017/08/25 14:20 6.0.0 がある。また,Library/Extentions に FTDI社のドライバ D2xxHelper.kext 2015/11/09 2.0.0 があった。
  • kextstat | grep FTDI で動作している機能拡張を確認。今回の場合はなかった(両方共読み込み失敗の様子)。
  • FTDI社のドライバを削除の上,マックを再起動。
  • 手動でAppleのドライバを読み込み(cd /System/Library/Extentions  -> sudo kextload AppleUSBFTDI.kext)
  • kextstat で機能拡張が読み込まれているかを確認。この時点では読み込まれていない。
  • ケーブルを接続。kextstatで状況確認→ドライバが読み込まれている。
  • /dev/ を確認。無事,認識され,/dev/tty.usbserial-DJ0… として表示された。

まとめ

  • 今回のトラブルの原因は複数の機能拡張(ドライバ)を設置したことによる競合。
  • 純正とメーカー製の二種類のドライバで機能・性能が違いそうなので,今後,機能・性能で不審な点があった場合,ドライバを変えてみるという策をとってみる必要がある。

以上

 

Haskell メモ MyECU

Haskell の習作として Rover Mini の ECU (MEMS)モニタソフトを作りかけている。以下はそのために試行錯誤した際のメモ。順次追記予定。

  1. 16進数表記の文字コードを入力し,文字を得る。
    
     do
       charcode <- readLn :: IO Int
       let command = chr charcode
     

    ECUコマンド発行用。ECUコマンドは基本的に1バイト文字。符号なし1バイト整数を意味する Word8 をこの時点から使おうかと思ったが,chr 関数にWord8を引数とさせる方法を調べるのが面倒だった(多分,こちらの記事が役に立つ。あとで調べる。)ので,とりあえず Int で入力させることを決め打ちにしてこのようなコードに。コンパイラオプション({-# LANGUAGE OverloadedStrings #-}ghc -XOverloadedStrings )を活用する方法を使わなかったのは,単に使うオプション類をできるだけ少なくしたいというコーディングスタイルの趣味の問題。

  2. macOS 機または Raspberry Pi での動作を前提とし,USBシリアル変換ケーブル経由のデータのやりとりをデバイスファイル経由で行う。
    
    result 

    ByteString 内の hPut や hPutNoBuffring では,文字を書き込んでも制御が戻ってこない。下層の Unix システムコールを Haskell で使う Posix.IO の wirteFd あたりを使う必要があるか。Haskell の問題というよりは Unix の使い方の知識の問題。
    【2017.05.30 追記】結局,serialPortモジュールを使うことで解決。初期化やデータのやりとりができるようになった。protocol.c では初期化コマンド送出の途中に ping を入れているので,この仕組も取り入れた。

  3. コンソールで入力した16進の文字コードをECU側に発行し,その反応を,時刻付きでコンソールに表示する。
  4. コンソールに表示した時刻と反応のセットを,第二引数で指定したファイルに書き込む。
  5. シリアル通信が途切れたときのための例外処理の追加。

Miniの現状

ECUにモニターをつなげてセンサーデータなどを見られるようにしたうちの1992年式 Rover Mini Cooper 1.3i , かかりつけの修理工場さんにいろいろ修理や改造をしてもらっている。

  • スロットルポテンションメータ,O2センサの交換
    ECUからのデータで,たびたびエラーが出ていたので,交換。ポテンションメータは既に交換してあり,その際は出てくる値はおかしくないとのことだったのだが,ECUのデータをエンジニアにお見せして,値がおかしいことを納得してもらい,交換していただいた。交換時,モニターの値を確認し,正常状態であることを互いに確認。
  • 配線(ハーネス))の被覆交換。
    アイドリング時,突然回転数が落ち,甚だしきはエンジンが止まるという状態がここ数年でていたが,ECUデータで,電圧降下があった一方で,電装以外の機関故障が見当たらないとのことだったため,漏電を疑い,点検するということに。この年式は,配線ケーブルがECUに入る際,かなり急なカーブがあったり,サブフレームリブ?に開いている穴を通っているのだが,今回は後者の穴のところで結構,被覆が溶けていたので,漏電箇所と思われる。当該箇所を切り落として全体被覆を再度巻き,元の位置に。まだ,エンジン下部のほうに通っている所は点検していないが,いずれまた。修理直後はまだ降下現象があったが,このところ発生していないという謎現象。
  • 増設電源ソケットを常時電源配線からに
    増設電源ソケットのカスケード接続をしていたものを直結に。ここには電圧計,MacBookAir の充電用アダプタをつないでいたのだが,電圧計で,走行中でもしばしば出ていた電圧降下(11v台に下がっていた)が出にくくなった(ひょっとしたら上記の箇所の漏電の影響による電圧降下があったのかもしれないが,電圧表示が数秒毎なので委細不明。現在は,クーラー,ハイビーム,MBAの充電など過酷な使い方をすると,電圧降下は認められるが,まぁ小型車なので,こんなものでしょう)。
  • 方向指示器部品の交換
    方向指示器のストッパーが効かなくなったり,ハイビームの固定ができなくなったので,中古部品で調子の良い物に交換。交換して2度ほど,方向指示器を使うと異音がして戻らないという症状が出たが,簡単に直してもらえた。
  • キーレス受信機の固定
    妙にハイテク機器を揃えているうちのミニはワイヤレスで鍵の開け閉めが出来る(荷物の出し入れが面倒なのと,積雪時に鍵穴が凍結で使えなくなったいるするのでつけてもらった。初号機はすぐに故障したため,今は別のメーカーの二代目。)この受信機が,先日,突然落っこちてきて足元に。幸い,ペダルにひっかかるようなことはなかったが,固定してもらった。
    キーレスの開閉は便利ですが,同乗者がいる時は,ちゃんと助手席側から鍵で開けるようにしています。
  • ドライブレコーダーの設置
    前述のエンジン回転数降下時の状況記録と,自分自身の安全意識向上のため,通販でレコーダーを購入,自分で設置。ETC,USB対応オーディオとならび,購入時に比べて格段にハイテクになったなぁという小さな満足感。
  • 電装系の改造
    結構前に,前照灯の配線をリレー式にしてもらった。また,かなりのフューズを管式から縦型にしてもらった。その他,アーシングなどもやってもらっているらしい。おかげで,初期は毎年梅雨時期に飛んでいたフューズがまったくとばなくなった。

ECUのモニター接続は修理工場さんの意見も聞きながら自分で調べて部品製作やソフトの設定などをやりました(かかった費用は部品代の数千円のみ)が,エンジニアさんも興味を持たれた様子。あるものは活用しよう,大切にしようと言うことで,まだしばらくは,乗り続けられそうです。

それにしても,50年以上前の設計,20年以上前に購入した機械がちゃんと動き,修理もできる。ありがたいことです。

2012/06/02 の魚野のつぶやき

  • すでにサービス業が逆輸入されていますね。先日現地視察した香港シティースーパー,百貨店が目指す未来のひとつかな,日本スタイルの経営だなと思ったのですが,西武出身者の方が起こされたんですね。 → http://t.co/qAbW6LNw 11:14:30, 2012-06-02
  • 逆輸入というのは,日本にも支店ができているからです。 11:15:06, 2012-06-02
  • そうそう,普段,小売業はコトを売るサービス業にならなければといっているのでサービス業と言いましたが,シティースーパーは一般的分類では小売業。 11:39:50, 2012-06-02
  • 代車。miniは個性が強い車です。個体差も結構あるのでたまに別ミニに乗るだけでもものすごく新鮮。 http://t.co/bhrYY1yp 14:49:09, 2012-06-02
  • カゴメが企業買収防衛策として買い付け説明書の言語は日本語でという文言を明記した。KGMの報道発表→ http://t.co/Swisps91 海外からの事態を以前から想定はしていたでしょうが,公式に対策を打ったのでしょうね。原料調達以外の部分もだんだん国際化していくなぁ。 18:45:05, 2012-06-02
  • ここ何年か,愛知県診断士協会(診断協会愛知県支部)の理論政策更新研修講師を担当させていただいている。今年は7/26の6次産業化支援で話をさせて頂きます。申込はネット受付 ( http://t.co/U0xSQ71a のみ,7/2から(非会員は7/10から)とのこと。 20:05:47, 2012-06-02
  • せっかくなのでfb上の事務所ページも更新していくことにしました。一般(fb会員以外)の方も見られますがコメント等はfb会員のみ。魚野剣太郎中小企業診断士事務所 http://t.co/nQKMyyuI 23:52:05, 2012-06-02