i-stopキャンセラーをArduinoで自作する
i-stop(アイドリングストップ)とは
アイドリングストップは、その名の通り、不要なアイドリングを止めることにより燃料消費を抑えるためのものですが、私の車(アテンザ)に搭載されているディーゼルエンジンは再始動時のバッテリー負荷が高く、バッテリーの寿命が短くなると考えられます。
そうすると、せっかく燃料消費を抑えてもバッテリー交換が早まってしまえば、環境負荷的にも金銭的にもあまり意味がなくなってしまいます。
i-stopをオフにするには
i-stopは、エンジン始動後にスイッチクラスターのi-stopボタンを長押しする事で有効/無効を切り替えることができますが、状態が記憶されないため、車に乗ってエンジンを掛けるたびにボタンを長押しして無効に切り替える必要があります。
それでは面倒なのでエンジン始動後、自動的にi-stopボタンを長押ししたことにして無効にするのが、"i-stopキャンセラー"です。
i-stopキャンセラーは4000円~で市販もされていますが、たかが数秒後にボタン長押しをエミュレートする装置に4000円も出すのはなんかもったいないです。
ネットではボンネットスイッチを外す方法も紹介されていますが、この方法は完全に無効化してしまうため、ボタンで再度有効にすることができないのと、イモビアラームも無効になってしまうらしいという問題があります。
i-stopボタンの解析
次に、i-stopボタンの仕組みを解析します。
ボタンの代わりなんだから、フォトカプラでアイソレーションしてスイッチさせれば…と思いますが、調べてみると、どうやらスイッチクラスターのスイッチによって抵抗値を変えることでハーネスの本数を減らす仕組みになっているようです。
i-stopボタンは約85Ωにする必要がありますが、手元には330Ωの抵抗しかありません。しかし、4本並列にすることでなんと82.5Ωになります!
念のためブレッドボードに4本並列にしたものを、上記マニュアルを参考に、キーON後コネクタのB-Cにつなぐと、「ピピッ」と音がしたので大丈夫そうです。
Arduinoを使う
Arduinoは安価なマイコンで、プログラミングも簡単にできるため、ちょっとしたものを作るときにはよく使われます。
正規品のArduino Unoは3000円ほどしますが、クローン品は500円程度で入手可能です。さらに、今回はデジタルI/Oが一つあればいいので、より小さくシンプルな DigiSpark のクローン品を使います。
DigiSparkはさらに安く、Amazonでも300円程度です。 ここまでくると、555タイマーでディレイ・ワンショットを組むよりも、プログラムで解決した方が安く済みそうです。
また、DigiSparkはレギュレータも搭載しているため、直接12Vで駆動できるのもメリットです。
Arduinoのプログラミング
Arduinoの電源ON後、10秒経過後に2秒間出力をONにするプログラムを書きます。
1番の出力はボード上のLEDに接続されているため、これを動作確認用にして、フォトカプラは0番の出力で制御することにします。
動作後は無限ループに入って終了ですが、スリープモードにした方がいいのかもしれません。(そこまで消費電力は気にしなくてよいと思いますが…)
DigiSparkにプログラムを書き込むにはArduinoIDEにボード情報を追加したり、ドライバーをインストールする必要があり、また書き込みボタン押下後の特定のタイミングでUSBポートに差し込む必要がありますが、ネット上で既にたくさん紹介されているので割愛します。
プログラムが書き込めたら、USBポートに差しなおして10秒後に2秒間LEDが光ることを確認します。
電子工作
コントローラーは出来たので、次に、ユニバーサル基板にフォトカプラ、抵抗、DigiSparkを半田付けします。
車に組み込み
プラスはリアモニター用?に配線してあったものを利用。
マイナスはハンドル下にあったターミナルに接続
あとはスイッチクラスターの配線をエレクトロタップで分岐してそれぞれArduinoに接続して完成!
しばらく使ってみましたが、問題なく動作してます。
NuGetでインストールしたPrismはApplicationBarButtonCommandが機能しない
タイトルの通りです。
現在、NuGetでは「Prism Interactivity library for Windows Phone 7」が公開されており、
インストールできますが、これを使うとApplicationBarButtonCommandがうまく機能しないようです。
詳細(修正済み)
http://compositewpf.codeplex.com/workitem/8500
こちらから最新版がダウンロードできますので、こちらを素直に使うのが良さそうです。
しかし、ApplicationBarButtonCommandのターゲットの指定がボタンのTextってどーよ…
ローカライズするときは、両方ローカライズしてやればいいのかな…。
せめてNameで指定できるようになればいいのに。
ボタンを配列で扱いたい
ボタンを配列で扱いたい!という話が#wp7dev_jpで出ていたので、ちょっと試してみた。
<toolkit:WrapPanel Name="wrapPanel1"> <Button Content="Button" Height="71" Name="button1" Width="160" Click="button_Click" /> <Button Content="Button" Height="71" Name="button2" Width="160" Click="button_Click" /> <!-- あとButtonとかその他UIコンポーネント好きなだけ --> </toolkit:WrapPanel>
みたいなWrapPanelがあったとして、そこからButtonを引っ張り出して配列で扱いたい!
という場合。
…Buttonを配列で扱う良い例が思いつかないので、例えばボタンを押したらある一連のボタンのラベルがindex番号にしたい場合、
private void button_Click(object sender, RoutedEventArgs e) { // WrapPanelの中にある要素からButtonだけ抜き出す var buttons = wrapPanel1.Children.Where(x => { return x is Button; }); // foreachでContent書き換え int count = 0; foreach (Button item in buttons) { item.Content = count++; } }
というようにできます。
まず、wrapPanel1内にある子要素から、Buttonだけ抽出し、それをforeachでループさせてます。
それだけといえば、それだけですが…。
WrapPanel内の特定のボタンを引っ張り出したい場合は、そのボタンに特定のプリフィックスつけて、名前でフィルタリングしてやればいいでしょう。
上記処理を実際に組み込むと、
ボタンをタップすると
ラベルが変わる
ようになります
/* こういう意味じゃなかった…? */
画像をローカライズするテスト
AppHubに「画像のローカライズしたいんだけど」って質問があったので、方法を考えてみました。
アプリを国際化する
まずは、先人のノウハウをもとにアプリを国際化します。
参考 覚え書き:Windows Phoneアプリをローカライズする
http://darutk-oboegaki.blogspot.jp/2011/06/windows-phone_10.html
画像をローカライズする
言語環境ごとに画像をローカライズする方法を考えます。
- 言語リソースに画像を追加する
- ImageのUriを言語リソースに登録し、それをBindingで参照する
- 言語設定を取得し、コードビハインドからImageのSourceにセットする
1は試してみたところ、System.Drawing.Bitmap名前空間がWPでは使えないため×っぽいです。
3は確実に出来るのでいいのですが、画像ごとに処理を記述するのは面倒です。
というわけで、今回は2を試してみます。
まず、こんな感じでローカライズする画像を追加します。
次に、言語リソースに文字列として、
名前:TopImageUri
値:Images/other/other.png
というように、対応言語ごとに表示したい画像のUriを同じ名前で登録します。
<Image Source="{Binding Source={StaticResource AppResourcesProvider}, Path=AppResources.TopImageUri}"/>
そうすると、
英語環境
日本語(英語以外)環境
と、このように画像が環境によって変わりました。
が、デザイン画面ではこのように画像が表示されません。
これは困るのでちょっと良い方法がないか検討してみます&あったら教えてください。
NUnitを使ってみるテスト
WindowsPhoneはおろか、今までxUnitは使用したことがありませんでしたが、
開発効率を上げるためにも自動テスト(ユニットテスト?)とやらを勉強しようと思い、
ひとまずWindowsPhoneでNUnitを使ってみました。
使い方
テスト対象の用意
まずは、適当にテスト対象のアプリを作ります。
で、適当にテスト対象のクラスを作ります。
public class Tax { /// <summary> /// 消費税込の価格を返す /// </summary> /// <param name="price">税抜き価格</param> /// <returns>税込み価格</returns> public int AddExciseTax(int price) { return (int)(price * 1.05); } }
テストアプリを追加
次に、テスト用のアプリプロジェクトを追加します。
このプロジェクトに対して、NuGetでNUnitをインストールします。
・・・何をどうしていいか分からないので、まずはNUnit_Readme.txtを読んでみます。
Readmeによると、
UnitTest.cs と Test_Readme.txt はいらないから消していいよ。
例は NUnitTest.cs に書いてあるから。あと、MainPageのLoadedイベントのハンドラに
this.StartTestRunner(new Microsoft.Silverlight.Testing.UnitTesting.Metadata.NUnit.NUnitProvider());
って書いとけばおk
とのことなので、要らないファイルを消して、MainPageのLoadedに上記コードを記述します。
namespace TestApp { public partial class MainPage : PhoneApplicationPage { // コンストラクター public MainPage() { InitializeComponent(); this.Loaded += new RoutedEventHandler(MainPage_Loaded); } void MainPage_Loaded(object sender, RoutedEventArgs e) { this.StartTestRunner(new Microsoft.Silverlight.Testing.UnitTesting.Metadata.NUnit.NUnitProvider()); } } }
次に、Tax.cs のテストをするために、TestAppプロジェクトの参照にTargetAppを追加します。
そんで、NUnitTest.csのテストコードを書き換えます。
namespace TestApp { [TestFixture] public class NUnitTest { [Test] public void TaxTestPass() { Assert.AreEqual(105, TargetApp.Tax.AddExciseTax(100)); } [Test] public void TaxTestFail() { Assert.AreEqual(100, TargetApp.Tax.AddExciseTax(100)); } } }
この例では、100円の税込み価格が105円になるかチェックするテスト(成功例)と、
価格が変わらないテスト(失敗例)を記述しています。