Xamarin.iOS/Android から F# PCL プロジェクトを使う方法

ちょっとトリッキーなので、後から Xamarin Studio 側が修正するような気もしますが、現状の回避策として。

■Xamarin.Forms を F# で使う

Xamarin.Forms は、PCL版とShared版があります。C# では “Mobile Apps” から どちらかのプロジェクトを選びますが、F# のプロジェクトにはこれがありません。じゃあ、F# では作れないのかというとそうではなくて、単純に、

– F# で PCL プロジェクトを作成する
– F# で iOS/Android プロジェクトを作成する
– iOS/Android プロジェクトから PCL プロジェクトを参照させる

という手順で Ok なハズです。PCL プロジェクト自体は、Xamarin Studio では作れないので、Visual Studio のほうで作りますが、後で述べるようにどっち作っても構わなそうです。
それぞれのプロジェクトに NuGet から Xamarin.Formss を入れてビルドが通る状態にしておきます。

iOS/Android プロジェクトから、PLC プロジェクトを参照設定したいところですが、参照設定ができません。この現象は、Visual Studio でも同じで…というか、Visual Studio では F# の iOS/Android プロジェクトが開けないので、Xamarin Studio 上でしかできません。

ひとつの方法としては、

F#のPCLプロジェクトをC#から参照するときにunable to add a reference to project… – omanuke-ekunamoの日記
http://d.hatena.ne.jp/omanuke-ekunamo/20140108/1389171418

のように、アセンブリの方を参照します。が、Xamarin.Forms の場合は、PCL 自体にロジックが入ることが多く、デバッグが結構手間なので、プロジェクト参照をさせます。

ちなみに、
– F# で作った PCL を C# プロジェクトから参照する。
– C# で作った PCL を F# プロジェクトから参照する。

ということは可能なのですが、なぜか F# から F# PCL だけが参照できません。

■ *.fsproj を開いて直接編集する

参照元(iOS/Android プロジェクト)の *.fsproj を開いて以下を追加します。

  <ItemGroup>
    <ProjectReference Include="../../WebBrickClientFs/WebBrickClientFs/WebBrickClientFs.fsproj">
      <Project>571E0A3B-E069-4B46-BBAC-B0F060351904</Project>
      <Name>WebBrickClientFs</Name>
    </ProjectReference>
  </ItemGroup>

ProjectReference に参照先のプロジェクト(PCLプロジェクト)fsprojを設定して、Project にプロジェクトGUIDを設定します。この部分は、C#からF# PCLを参照したときと同じものです。

そうして、Xamarin Studio で開くと、警告が出た状態ではありますが、参照ができるようになります。この状態でビルドも通ります。

■ビルドの警告はなぜでるのか?

ビルドをすると、こんな風な警告が出ます。

C:/Program Files (x86)/MSBuild/12.0/bin/Microsoft.Common.CurrentVersion.targets(5,5): Warning MSB3277: 同じ依存アセンブリの異なるバージョン間で、解決できない競合が見つかりました。 これらの参照上の競合は、ログの詳細度が詳細に設定されている場合にビルド ログにリストされます。 (MSB3277) (WebBrickClientFs.Android)

これは、それぞれのプロジェクトに入っている FSharp.Core のバージョンが異なるからなんですね。

Visual Stuido で作った F# PCL では、Reference Assemblies/Microsoft/FSharp/.NETCore/$(TargetFSharpCoreVersion)/FSharp.Core.dll を参照していますが、Android のほうでは、Reference Assemblies/Microsoft/Framework/MonoAndroid/v1.0/FSharp.Core.dll を参照しています。
.NETCoreのほうは、3.3.1 なのですが、MonoAndroid のほうは 2.3.1 なんですよね。これがずれてしまっているようです。ちなみに MonoTouch にあるのは 2.9.9 なのでこれもバージョンが違っています。おそらく、このバージョンが揃わない限り、先の警告が出てしまうようです。

■バージョンを揃えることができるのか?

試しに Xamarin.Forms.Core のバージョンを見ると PCL/Android/iOS ともに 1.1.1.0 になっています。おそらく、これを揃えればいいのでしょうが、現状の配布状況(Nuget にもいくつかの Fsharp.Core があります)をみると、揃えるのは難しそうですね。自前でビルドをすると、バージョンが揃うのかなと。このあたりは別途調べてみます。せめて、F# 3.0 なのか F# 3.1 なのかがわかるといいんだけど。

カテゴリー: F#, Xamarin | Xamarin.iOS/Android から F# PCL プロジェクトを使う方法 はコメントを受け付けていません

BrickPi + LOGO Mindstorms EV3 をゲームコントローラーでコントロールする(後編)

手っ取り早く動かすには、先の あしがらがらくた研究所 by いしわたむねお さんのところから、RPi_DualShock3.c を取得してビルドをします。動作確認ができたら、BrickPiNet をインストールして試します。.NET版なので、apt-get install Mono をしないとダメなんですよね…というか、RasPi のレポジトリに 4.5 の Mono が入っていたか確認してないので、これはあとで確認。手元のものは 12時間かけてビルドをしたものなので、ちょっとお試しという訳にはいかないので。そのうち、パッケージを作りましょう(つーか、パッケージの作り方から学ばないとダメなんだけど)。

■C# からジョイススティックを操作する

C言語でIOCTLしないと駄目かと思ったんですが、Linuxでは /dev/input/js0 にアクセスさえすれば、ボタンやジョイスティックの状態が取れることを知りました linux/joystick.h に詳しい情報があります。
このデバイスは、そのまま C# のファイルストリームでも使えるので、こんな感じに書けます。

Raspberry Pi Series ? Mono C# USB Joystick Handlermpolaczyk | software, robotics, engineering & geeky stuff… | mpolaczyk | software, robotics, engineering & geeky stuff…
http://mpolaczyk.pl/raspberry-pi-mono-c-joystick-handler/
C# で joystick を利用する
https://gist.github.com/moonmile/7c44e5130617c7a76a87

自前のほうは、Dualshock3 専用になっています。どうやら各社のジョイスティック/ゲームパッド事に番号が異なっていて、実地で検証しないとだめなそうです。アプリケーションのほうが対応するというパターンらしいです。

public struct js_event
{
    public UInt32 time;    /* event timestamp in milliseconds */
    public Int16 value;    /* value */
    public byte type;      /* event type */
    public byte number;    /* axis/button number */
    public override string ToString()
    {
        return string.Format("time:{0} val:{1} type:{2} num:{3}", time, value, type, number);
    }
}

type でボタン(0x01)かジョイスティック(0x02)をチェックして、number でボタンの位置を調べます。ジョイステックの場合は0がニュートラル(中央)で、スティックを倒すとそれぞれ +/- に振れます。
ここでは、まだ作っていないのですが、Dualshuck3 ではコントローラ自体の傾き検知が入っています。23,24,25,26番にデータが入って来るのですが、どの軸なんだろう、ってのは後で調べましょう。

public bool SELECT { get { return Button0; } }
public bool LeftStick { get { return Button1; } }
public bool RightStick { get { return Button2; } }
public bool START { get { return Button3; } }
public bool Up { get { return Button4; } }
public bool Right { get { return Button5; } }
public bool Down { get { return Button6; } }
public bool Left { get { return Button7; } }
public bool L2 { get { return Button8; } }
public bool R2 { get { return Button9; } }
public bool L1 { get { return Button10; } }
public bool R1 { get { return Button11; } }
public bool Triangle { get { return Button12; } }
public bool Circle { get { return Button13; } }
public bool Cross { get { return Button14; } }
public bool Square { get { return Button15; } }

public int LeftAxisX { get { return Axis0; } }
public int LeftAxisY { get { return Axis1; } }
public int RightAxisX { get { return Axis2; } }
public int RightAxisY { get { return Axis3; } }

■BrickPiNet.dll を使う

そんな訳で、BrickPiNet https://github.com/moonmile/BrickPiNet を作成中です。

/dev/input/js0 を read して、ちまちまと調べていけばジョイスティックの操作はできるのですが、ボタンを離したタイミングとか、同時押しの状態とかが面倒ですよね。
そのあたり、状態が変かしたときにイベントを発生するのが、BPiJoystick です。

using System;
using Moonmile.BrickPiNet;

namespace Sample
{
    class simplebot_joystick
    {
        BPiMotor motor1, motor2;
        BPiJoystick js;

        public void main()
        {
            BPi.Setup();
            BPi.AutoUpdate = true;
            this.motor1 = new BPiMotor() { Port = BrickPi.PORT_B, Enabled = true };
            this.motor2 = new BPiMotor() { Port = BrickPi.PORT_C, Enabled = true };

            js = new BPiJoystick();
            js.OnJoystickChanged += js_OnJoystickChanged;
            js.Setup();

            BPi.Timeout = 5000;
            this.Go();
        }

        void js_OnJoystickChanged(object sender, JoystickEventArgs e)
        {
            int ly = e.Joystick.LeftAxisY;
            int ry = e.Joystick.RightAxisY;
            Console.WriteLine("joystick {0} {1}", ly, ry);
	    int sp1 = ly/(32767/200);
	    int sp2 = ry/(32767/200);
	    move_bot( sp1, sp2 );

        }

        void move_bot(int sp1, int sp2)
        {
            this.motor1.Speed = sp1;
            this.motor2.Speed = sp2;
        }
        void Go()
        {
            var k = Console.ReadKey();
        }
    }
}

BPiJoystick を new して、OnJoystickChanged を登録すれば、ジョイスティックが変化したときだけイベントが発生します。現在のところ、ジョイスティックとボタンの状態変化が一緒になって飛んでくるので、ボタンだけ使いたいときに不便なのですが…まあ、ひとまず、これでジョイスティックを使ったロボットが簡単に作れます。

■さらに、もうひとつのモーターを使うために

これは次の課題ですが、BrickPi/LEGO mindstorms EV3 には、モーター用のポートが4つついています。現在、車輪用に2つ使っていますが、他にもモーターを使えばクレーン用とかに使えます。これはあとで実験してみましょう。他に接触センサーとかカラーセンサーもついているので、それも確認して実装していきます。

また、GPIO を直接操作することでサーボも動かせます。このあたりは、wiringPi http://wiringpi.com/ を利用して BrickPiNet から制御できるようにしていきます。

カテゴリー: RaspberryPi | BrickPi + LOGO Mindstorms EV3 をゲームコントローラーでコントロールする(後編) はコメントを受け付けていません

BrickPi + LOGO Mindstorms EV3 をゲームコントローラーでコントロールする(前編)

Raspberry Pi + BrickPi + LOGO Mindstorms EV3 をジョイスティックコントローラで遠隔制御します。まあ、単純に Raspberry Pi に Bluethooth を接続して、これを Dualshock3 で使えるようにするだけなのですが。

image

工作と小物のがらくた部屋: Raspberry Pi で Dualshock3 (Bluetooth接続ゲームコントローラ)
http://junkroom2cyberrobotics.blogspot.jp/2013/03/raspberry-pi-dualshock3-bluetooth.html
RapiroをPS3のDUALSHOCK3で動かしてみる | Makuake(マクアケ)NOTE クラウドファンディングブログ
http://www.makuake.com/blog/crowdfunding/rapiro-dualshock/

USB 接続すれば簡単なのですが、遠隔操作をするとなると2つの方法があります。Bluetooth を使う方法と WiFi を使う方法ですね。ワイヤレスコントローラ (DUALSHOCK3) は 4千円ちょっとと結構な値段がするのですが(RasPi 以上という噂もw)、まあ初回の実験だし確実につなげておきたいのでこれにしました。SBDBTのPSコントローラ用ファーム更新!凄いですよ!いろいろなゲームパッドで無線・有線による操作が可能になりました: ROBOMIC(ブログ) を見ると SBDBT というのを使えば、普通のコントローラも無線化できそうなのでが、これは今度の課題で。

Bluethooth での接続手順は、先の2つのブログに書いてあるのですが、自分用に書き写しておきます。Bluetooth は PLANEX Bluetooth USBアダプター Ver.4.0+EDR/LE(省エネ設計)対応 BT-Micro4 を使っています。最初は他の人が RasPi で動作確認できたものを使うのが無難ですね。たぶん、大抵のものは動くとは思うのですが、無線LAN で失敗したので、先のブログの人が使っているものと同じものを購入しました。

■Bluethooth の準備

apt-get で bluethooth パッケージをインストールします。

sudo apt-get install bluetooth bluez-utils bluez-compat bluez-hcidump
sudo apt-get install libusb-dev libbluetooth-dev

うまく認識ができていると

/etc/init.d/bluetooth status

で確認ができます。

image

usb の状態は lsusb で確認が可能です。

lsusb 

image

Bus 001 Device 005: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode) ってのが、Bluetooth の USB ドングルです。 Bus 001 Device 004 のほうは WiFi の USB ドングルです。ゲームコントローラで遠隔制御はするのですが、ログ出力は初期制御のために WiFi をつなげています。電流的にどうなんだろうなぁ、という心配もありますが。一応、問題なく動いています。

■QtSixA のインストール

QtSixA is the Sixaxis Joystick Manager をインストールします。Sixaxis/DualShock3 を Linux に割り当てられるそうなので、RasPi でも OK です。SourceForge からダウンロードするのですが、http://sourceforge.net/projects/qtsixa/files/QtSixA%201.5.1/ にある QtSixA-1.5.1-src.tar.gz が最新です(といえ、2011年10月に開発が止まっていますが)。

tar -xvf QtSixA-1.5.1-src.tar.gz
cd QtSixA-1.5.1/sixad
make
sudo make install

すると、Dualshock3 を受け入れる sixad ってのがビルド&インストールされます。QtSixA-* 直下で make をすると pyuic4 コマンドがないというエラーが出るので、sixad フォルダでビルドします。Raspberry Pi 用の Debian に qgis, python-qgis がないからみたいですね。これは特に不要で、sixad とペアリング用の sixpair のみが必要です。

cd QtSixA-1.5.1/utils
make
sudo make install

■Dualshock3 とペアリングする

Daulshock3 と Raspberry Pi を USB コードで接続して、sixpair を動かします。

sudo sixpair

image

うまくいくと Bluethooth の MAC IDが取れます(たぶん USB のほう)。初回だけ USB ケーブルをつないで、あとからは Dualshock3 コントローラの「PS」ボタンでペアリングができます。

■動作させる

sixad で bluetooth の待ち受けをして、Dualshock3 で PS ボタンを押します。

sixad -start

image

(たぶん)Dualshock3 の MAC が表示されて接続状態になります。

動作確認自体は、/dev/input/js0 を表示させることで、確認ができます。

sudo cat /dev/input/js0

image

ボタンを押したり、ジョイスティックを動かしたりすると信号が流れていくのがわかります。

動作確認自体は、意外に簡単! LinuxでジョイスティックをC++から使う方法 – akihiko’s tech note からサンプルコードをビルドして動かしています。/dev/input/js0 をオープンして中身を表示させます。

image

■sixad の終了

sixad 自体は Ctrl+C で終わらせるのですが、そのままでは bluetooth が解放されないようです。

image

sixad -stop で終了させると、Bluetooth が解放されます。

ただし、cat /dev/input/js0 を見ると、いつまでもデータが送られてくる(Dualshock3を傾けるとデータが入っているのがわかる)のでペアリング自体は続いてしまっているようです。仕方がないので、Bluetooth の USB ドングルを抜いて止めるのですが、なんかいい方法はないですかね?

で、お次は、/dev/input/js0 を読み込んで、EV3 のモーターを動かすプログラムを書きます。

カテゴリー: RaspberryPi | BrickPi + LOGO Mindstorms EV3 をゲームコントローラーでコントロールする(前編) はコメントを受け付けていません

QEMU で Raspberry Pi をエミュレートする

Raspberry Pi は CPU が ARM なので、クロスコンパイラ環境が必須なのですが結構手間なので、エミュレータ環境を使って、その中で Mono や OpenCV をビルドすると良い。

QEMU – Emulating Raspberry Pi the easy way (Linux or Windows!)
http://xecdesign.com/qemu-emulating-raspberry-pi-the-easy-way/

そんな訳で、上記からエミュレータをダウンロードして解凍すると、あっさりと動きます。「QEMU Raspberry Pi」で検索するとぼろぼろと出てくるので、これが定番だったんだ。

■初期環境を作る

Raspberry PiをQEMUでエミュレートする方法 | 意識低い開発者のBlog
http://blog.ymyzk.com/2013/12/raspberry-pi-qemu/
Raspberry Pi のイメージファイルを拡張する | 意識低い開発者のBlog
http://blog.ymyzk.com/2013/12/raspbian-image-resize/

にある手順に従って、

  • /etc/ld.so.preload を開いて #/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so のようにコメントアウトする。
qemu-system-arm -kernel kernel-qemu ^
    -cpu arm1176 -m 256 -M versatilepb -no-reboot ^
    -serial stdio ^
    -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw init=/bin/bash" ^
    -hda D:isoRaspberryPi2014-06-20-wheezy-raspbian.img
vi /etc/ld.so.preload
  • RasPi のイメージファイルが 2GB 程度なので +16G 程度追加しておく。
qemu-img resize 2014-06-20-wheezy-raspbian.img +16GB

こうすると、ひとまず QEMU 上で Raspberry Pi が動作します。

■ネットワークを構築する

単純にコンパイルするだけならば上記の設定で十分なのですが、今回は apt-get をして Mono や OpenCV の環境を構築するので、外部ネットワークの接続が必須です。これは、TAP 型で外部接続させます。

オープンギャラリー:QEMUゲスト間ネットワーク接続環境
http://www.os-museum.com/qemutapnet/qemutapnet.htm

Windows環境の場合は、

OpenVPN をインストール http://www.openvpn.jp/

  • ネットワーク接続の名前を「TAP32」のように設定しやすいものに変更。
  • 「ネットワークと共有センター」→「アダプターの設定の変更」で「ブリッジ接続する」
    私の環境では Hyper-V が入っているため vEthernet とブリッジしていますが、普通はイーサネット(PCが接続しているLANポート)を使うと思われます。

image

起動時に -net tap.iframe=TAP32 の様に設定

qemu-system-arm -kernel kernel-qemu ^
	-cpu arm1176 -m 1012 -M versatilepb -no-reboot ^
	-serial stdio ^
	-append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" ^
	-net nic -net tap,ifname=TAP32 ^
	-hda 2014-06-20-wheezy-raspbian.img

■制限

  • メモリが -m 256 で 256MB しか設定できません。それ以上を設定しても無視される。QEMU の制限かも
  • OpenVPN の接続スピードが 10Mpbs になっている。今となっては相当遅いので、何か別のローカルネットワークの手段を考えたほうがいいかも(方法が分からん)。git などからソースダウンロードすると非常に遅いので、別途 Debian でダウンロードしたものをコピーすると良い。
  • 実行速度は、実機とほとんど変わらない。Mono をビルドすると10時間程度かかりました。まあ、ビルドしている間に実機がふさがれるのを防ぐのとバックアップがとりやすい(*.img ファイルそのまま保存すればOK)ので、これはこれで使い勝手がよいかと。
カテゴリー: RaspberryPi | 2件のコメント

Raspberry Pi 用のクロス環境を考察する

Mono を Raspberry Pi でビルドすると、12時間かかってしまうので非常に手間。考えてみれば、Raspberry Pi の CPU は ARM なのだから、Android のクロスコンパイル環境を持ってくれば動くのでは?と思ったのが発端です。

まだ調査中なので、どの環境がよいかは後でまとめます。

■方法

最初は、Linux 上にクロスコンパイラ環境を用意して、ビルドした後に Raspberry Pi にもっていけば、と思ったのですが、いくつか方法が選べることに思い至りました。

  • Linux Debian wheezy のクロスコンパイラ環境で Mono をビルドして、Raspberry Pi にインストール
  • Linux 上の ARM 仮想環境を作って、ビルドしたのち、Raspberry Pi にインストール
  • Android 実機を使ってビルドしたのち、Raspberry Pi にインストール
  • Raspberry Pi 自体をエミュレートする環境を作る

Android の実機を使うのは、ARM 仮想環境(エミュレータ)よりもスピードが速いだろう、って思いつきなのですが、手元の CPU スピードからいけば多少 ARM エミュレーターが遅くても RasPi よりは断然早いだろう、という想像です。Android 実機/エミュレータ に対しては adb で shell を動かすことができるから gcc さえ入れ込めば、とも思ったのですが、Android 上でこれができるのか?というのと Mono から配布されているソースパッケージを Android の環境に合わせるのは結構手間ではないか?との想定から、現実的なところは、Debian 上のクロスコンパイラか、Raspberry Pi のエミューレター環境ですね。エミュレーター環境とはいえ、IO をエミュレートしたいわけではなくて、Raspberry Pi の Debian 環境にそろえたいだけなので、単純に ARM CPU で動作する Linux 環境を作ればよいだけです。

■クロスコンパイラ環境を Debian 上に作る

debian wheezy 上でのクロスコンパイラのビルド を参考にして、クロスコンパイル環境を構築。

GCC_TARGET=armel
dpkg-buildpackage -b -uc -us

のところで、Error になってしまったので、後で調査。

■Scratchbox を使う

Mono:ARM – Mono を見ると、ScratchBox を使う方法が示されている。Scratchbox – ARMクロス開発環境 を見ると仮想環境を作る方法らしい。./configure を直すのは確かに大変なので、直接 ARM の仮想環境を作って、其の中に Gcc の入れ込んでしまうのがよい。

ここの環境に Raspberry Pi の Debian が入ればいいのだが?これができるかどうか分からない。

■qemuを使う

と、ここまで書いて

Raspberry Pi • View topic – Re: Emulating Raspberry Pi in Windows the easy way
http://www.raspberrypi.org/forums/viewtopic.php?f=26&t=5743 

のところに RasPi のエミュレーターがあった。http://sourceforge.net/projects/rpiqemuwindows/ qemu-system-arm.exe を使うらしい。QEMU は Linux 上で動くものが多いけど、Windows 上で動くのであれば、これでいいかも。

と、あっけなく起動できた w これでいいかも。RasPi の ディスクイメージをそのまま使っているので 2GB に制限されているけど、8GB 程度のイメージを作ればそれで使えるのでは?ちょっと試してみよう。

image

 

 

■参考

日記/2014-03-28/debian wheezy 上でのクロスコンパイラのビルド – BAK
http://jr0bak.homelinux.net/~imai/pukiwiki/pukiwiki.php?%C6%FC%B5%AD%2F2014-03-28%2Fdebian%20wheezy%20%BE%E5%A4%C7%A4%CE%A5%AF%A5%ED%A5%B9%A5%B3%A5%F3%A5%D1%A5%A4%A5%E9%A4%CE%A5%D3%A5%EB%A5%C9
Mono:ARM – Mono
http://www.mono-project.com/Mono:ARM
Scratchbox – cross compile enviroument
http://homepage2.nifty.com/SECS/scratchbox/index.html
QEMUでARM環境を手にいれる | 團長の小部屋
http://wwwdantyo.wordpress.com/qemu%E3%81%A7arm%E7%92%B0%E5%A2%83%E3%82%92%E6%89%8B%E3%81%AB%E3%81%84%E3%82%8C%E3%82%8B/

カテゴリー: RaspberryPi | 6件のコメント

Xamarin の FormsGallery を XAML で書き直してみる

Xamarin.Forms のサンプルに FormsGallery があります。Xamarin.Forms で使っているひと通りのコントロールが載っているので、どんなものがあるのか見るのに便利なのです。ただ、中のコードは、C# でひとつひとつのコントロールを作るスタイルになっているので、XAML で作る場合にはどうするのか、いまひとつ解りづらい…ので、コンバートしてみました。

https://github.com/moonmile/XFormsGallery

ところどころ未完成なところがあるのですが、ひとまず1日で出来上がったところまで。
共通プロジェクトは PCL を使っています。XAML を素直に共通化するだけであれば PCL で良いでしょう。WinStore/WinPhone のユニバーサルプロジェクトのようにコードビハイドに手を加える場合には、共有プロジェクトを使うと良いかと。

■注意

現時点の Xamarin.Formsのバージョンは「1.1.1.6206」になっているのですが、Visual Stuido 2013 に含まれているテンプレートでは、「1.0.6186」になっています。ほとんど変わらないですが TableView の概観がちょっと違うので、Xamarin の Sample のように、最新のバージョンに合わせています。プロジェクトごとに NuGet で最新にしてください。

以下、ざっと XAML にするときに手順を書き下しておきます。

■App.cs を書き換える

プロジェクトテンプレートで作ると、PCL プロジェクトの App.cs にページを作るコードがあります。ここをごっそり削って、Page クラスのインスタンスを返します。ただし、サンプルの場合には特殊でナビゲーションを使っています。この場合は特別に NavigationPage のインスタンスを作成します。

public class App
{
    public static Page GetMainPage()
    {
        return new NavigationPage(new HomePage());
    }
}

■簡単な LabelDemoPage を作る

ラベルだけが表示されるページはこんな感じです。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
					   xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
					   x:Class="XFormsGallery.LabelDemoPage">
	<ContentPage.Padding>
		<OnPlatform x:TypeArguments="Thickness">
			<OnPlatform.iOS>10,20,10,5</OnPlatform.iOS>
			<OnPlatform.Android>10,0,10,5</OnPlatform.Android>
			<OnPlatform.WinPhone>10,0,10,5</OnPlatform.WinPhone>
		</OnPlatform>
	</ContentPage.Padding>
	<StackLayout>
		<Label Text="Label" Font="50" HorizontalOptions="Center"></Label>
		<Label Font="Large" VerticalOptions="CenterAndExpand">
			<Label.Text>Xamarin.Forms is a cross-platform natively backed UI toolkit abstraction that allows developers to easily create user interfaces that can be shared across Android, iOS, and Windows Phone.</Label.Text>
		</Label>
	</StackLayout>						
</ContentPage>

OnPlatform のところは、OSによってコードを切り替えらるところで、元のサンプルの Device.OnPlatform にあたります。Top だけ切り替えられるような気もするのですが、うまくいかなかったので Thickness まるごと切り替えます。iOS だけ 20 ドット広げてあるのは、iPhone のステータスバー用です。ただし、ナビゲーターの場合は自動でステータスバーに対応しているらしく、これはあまり意味がありません。全画面表示するページを作るときに使う技ですね。

元ネタの LabelDemoPage を見ると、次のようになるので、解りやすいような解りにくいような。

    class LabelDemoPage : ContentPage
    {
        public LabelDemoPage()
        {
            Label header = new Label
            {
                Text = "Label",
                Font = Font.BoldSystemFontOfSize(50),
                HorizontalOptions = LayoutOptions.Center
            };

            Label label = new Label
            {
                Text =
                    "Xamarin.Forms is a cross-platform natively " +
                    "backed UI toolkit abstraction that allows " +
                    "developers to easily create user interfaces " +
                    "that can be shared across Android, iOS, and " +
                    "Windows Phone.",

                Font = Font.SystemFontOfSize(NamedSize.Large),
                VerticalOptions = LayoutOptions.CenterAndExpand
            };

            // Accomodate iPhone status bar.
            this.Padding = new Thickness(10, Device.OnPlatform(20, 0, 0), 10, 5);

            // Build the page.
            this.Content = new StackLayout
            {
                Children = 
                {
                    header,
                    label
                }
            };
        }
    }

XAML 自体は、Xamarin Studio 上で手書きをします。Visual Studio 上でも書けないことはないのですが、タグのコード補完が効かないので、非常にやりにくいです。本当はデザイナが欲しいところでしょうが、スマートフォンのような小さな画面の場合には自由度が少ないので、ほとんど StackLayout か Grid を使ってしまうのであまり関係ないでしょう。ですが、iPad や Surface のようなタブレットPC のレイアウトをするときにはデザイナは必須ですよね。このあたりは、今後どうするのか不明です。

Windows Phone(SilverLightですが)の XAML に直す時に ConvertPageToUIElement メソッドを呼び出しているので、この逆変換ができれば Visual Studio 上で XAML のデザインができるようになるかもしれません。

■HomePage ページを作る

トップページは、メニュー用のページです。
TableView でリスト表示をしているのですが、この親子関係が解りづらいところです。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
				xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
				x:Class="XFormsGallery.HomePage"
				Title="XAML Forms Gallery">
	<TableView Intent="Menu">
		<TableView.Root>
			<TableSection Title="Views for Presentation">
				<TextCell Text="Label" x:Name="cellLabel" ></TextCell>
				<TextCell Text="Image" x:Name="cellImage"></TextCell>
				<TextCell Text="BoxView" x:Name="cellBoxView"></TextCell>
				<TextCell Text="WebView" x:Name="cellWebView"></TextCell>
				<TextCell Text="Map" x:Name="cellMap"></TextCell>
			</TableSection>
			<TableSection Title="Views that Initiate Commands">
				<TextCell Text="Button" x:Name="cellButton" ></TextCell>
				<TextCell Text="SearchBar" x:Name="cellSearchBar"></TextCell>
			</TableSection>
...

ただし、元ネタの HomePage.cs を覗いてみると、TableView <- TableView.Root <- TableRoot <- TableSection <- TextCell <- TextCell の関係が解るので、そのまま書き写しています。XAML では TableRoot を省略しても動作するようです(TableView.Rootのほうは省略できないんですよね。ここは Children にして欲しかった)。

this.Title = "Forms Gallery";
this.Content = new TableView
    {
        Intent = TableIntent.Menu,
        Root = new TableRoot
        {
            new TableSection("Views for Presentation")
            {
                new TextCell
                {
                    Text = "Label",
                    Command = navigateCommand,
                    CommandParameter = typeof(LabelDemoPage)
                },

                new TextCell
                {
                    Text = "Image",
                    Command = navigateCommand,
                    CommandParameter = typeof(ImageDemoPage)
                },

タップなどの操作は非常に制限されています。労力を減らすたか、これから実装するのか解りませんが、TextCell の場合は Command パターンで呼び出しをしています。ただし、主要なボタンコントロールなどには Clicked イベントが用意されているので、そのままコードビハイドで書くことができます。


WPFやWinStoreで XAML を手書きしたことがある人ならば、デザイナがなくても大体想像して書けるかなという感じですね。Xamarin.Forms の DTD は無いようなので、親子関係はマニュアル http://iosapi.xamarin.com/?link=N%3aXamarin.Forms を見る必要があるのですが、まあ元ネタを見比べていけば、これも想像で書ける範囲かと思います。

カテゴリー: C#, Xamarin | Xamarin の FormsGallery を XAML で書き直してみる はコメントを受け付けていません

F# を使ってRaspberryPi+BrickPi+LOGO Mindstorms EV3 を動かす

F# に限らないのですが、試しにモーター制御の部分だけ .NET 版の BrickPi を作りました。

https://github.com/moonmile/BrickPiNet

– BrickPi.h と brickpinet.c で .NET に公開可能なインターフェースを作る
– BrickPi.cs と BPi.cs で .NET で包む
– sample.cs、sampleF.fs のように C#/F# で制御する

というパターンです。BrickPi_Python などを見ると、それぞれの言語でシリアルポートに直接アクセスしているのですが、C# からポートアクセスは面倒だし、BlickPi.h 自体で十分なインターフェースになっているのでこれをそのまま使います。BrickPi.h 自体は C言語で掛かれているので、そのまま shared で公開して、これを BrickPi.cs で DllImport するというスタイルになっています。

sample.cs と sampleF.fs の場合は、ほとんど生の BrickPi クラスを使っているので他のプログラム言語との対応が取りやすくなっています。が、そのままでオブジェクト指向的に扱いにくいので、BPi クラスを作ってオブジェクト化しています。複数のモーター制御のところで MVVM パターンを使っているのはお試しです。BrickPi の場合は、ポート呼び出しの後に戻りがないので、INotifyPropertyChanged と相性がよいかもしれません。次はセンサーから入って来る操作なので、event 的に作るか、reactive 的に作るか、といったところです。

以下、ざっとファイルの解説を。

■Makefile

Raspberry Pi 上でビルドする必要があるので、Makefile を作っています。先のブログにも書きましたが、RasPi の現状のレポジトリにある mono では F# 3.1 が動かないので、mono のビルドが必須になります。それだと相当大変なので、単に試したい方は、F# のほう(fshaprcのところ)は削除して、apt-get install mono-complete の後、ビルドを試してみてください。

all: sample.exe 
	sampleF.exe 
	libbrickpinet.so 
	sampleCs.exe 
	sampleF2.exe

sample.exe: libbrickpinet.so BrickPi.dll sample.cs
	gmcs /out:sample.exe -sdk:4.5 /r:BrickPi.dll sample.cs 
sampleCs.exe: libbrickpinet.so BrickPi.dll sampleCs.cs
	gmcs /out:sampleCs.exe -sdk:4.5 /r:BrickPi.dll sampleCs.cs 
sampleF.exe: libbrickpinet.so BrickPi.dll
	fsharpc /out:sampleF.exe /r:BrickPi.dll sampleF.fs 
sampleF2.exe: libbrickpinet.so BrickPi.dll
	fsharpc /out:sampleF.exe /r:BrickPi.dll sampleF2.fs 

libbrickpinet.so: brickpinet.o 
	gcc -fPIC -shared -o libbrickpinet.so brickpinet.c -lrt -lm -L/usr/local/lib -lwiringPi
BrickPi.dll: BrickPi.cs 
	gmcs /target:library /out:BrickPi.dll 
	-sdk:4.5 
	BindableBase.cs  
	BrickPi.cs 
	BPi.cs

■brickpinet.c

libbrickpinet.so で BrickPi API を公開させています。BrickPi 構造体へのアクセスがいちいち書いてるのは、C# から C言語の構造体の手間を省くためです。box してもよいのですが、Mono の場合 box は使えるのか?とか調べるのが面倒だったので。

/*
 * BrickPi Interface for .NET 
 */
#include "tick.h"
#include "BrickPi.h"

void SetTimeout(int time) {
	BrickPi.Timeout = time;
}
int GetTimeout() {
	return BrickPi.Timeout;
}
/*
  Motors
*/
void SetMotorSpeed(int motor, int speed) {
	BrickPi.MotorSpeed[motor] = speed;
}
int GetMotorSpeed(int motor) {
	return BrickPi.MotorSpeed[motor];
}
void SetMotorEnable(int motor, int b) {
	BrickPi.MotorEnable[motor] = b == 0 ? 0 : 1;
}
int GetMotorEnable(int motor) {
	return BrickPi.MotorEnable[motor] == 0 ? 0 : 1;
}
...

■BrickPi.cs

単純な.NET版のラッパークラスです。他のプログラム言語との対応がとりやすい形にします。

namespace BrickPiNet
{
    public class BrickPi
    {
        public const int PORT_A = 0;
        public const int PORT_B = 1;
        public const int PORT_C = 2;
        public const int PORT_D = 3;

        public const int PORT_1 = 0;
        public const int PORT_2 = 1;
        public const int PORT_3 = 2;
        public const int PORT_4 = 3;

        public const int MASK_D0_M = 0x01;
        public const int MASK_D1_M = 0x02;
        public const int MASK_9V = 0x04;
        public const int MASK_D0_S = 0x08;
        public const int MASK_D1_S = 0x10;

~~~
        [DllImport("libbrickpinet", EntryPoint = "BrickPiSetup")]
        public static extern int Setup();
        [DllImport("libbrickpinet", EntryPoint = "BrickPiSetupSensors")]
        public static extern int SetupSensors();
        [DllImport("libbrickpinet", EntryPoint = "BrickPiUpdateValues")]
        public static extern void UpdateValues();
        [DllImport("libbrickpinet", EntryPoint = "BrickPiSetTimeout")]
        public static extern void InitTimeout();

■BPi.cs

いちいち関数を呼び出すのは面倒なので、オブジェクト指向っぽく直したのが BPi クラスです。
値を設定した後に、BrickPi.UpdateValues() を呼び出さなくてもよいようにしてあります。ただ、プロパティの変更にセンシティブなのは MVVM の欠点で、このあたりは別なところで回避しようかなと思ってます。例えば、2つのモーターの向きを同時に変える、というようなパターンがそれに相当します。

public class BPi
{
    public ObservableCollection<BPiMotor> Motors;
    public bool AutoUpdate { get; set; }

    private int _timeout = 3000;
    public int Timeout
    {
        get { return _timeout; }
        set
        {
            if (_timeout != value)
            {
                _timeout = value;
                BrickPi.SetTimeout(value);
                BrickPi.InitTimeout();
            }
        }
    }

    /// <summary>
    /// Constructor
    /// </summary>
    public BPi()
    {
        this.Motors = new ObservableCollection<BPiMotor>();
        this.Motors.CollectionChanged += Motors_CollectionChanged;
        this.AutoUpdate = false;
    }
    public void Setup()
    {
        int res = BrickPi.Setup();
        if (res != 0)
        {
            Console.WriteLine("");
            throw new Exception(string.Format("Error: BrickPi.Setup: {0}", res ));
        }
    }

    void Motors_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        // var m = sender as BPiMotor;
        switch ( e.Action ) {
            case NotifyCollectionChangedAction.Add:
                foreach (BPiMotor it in e.NewItems)
                {
                    it.PropertyChanged += it_PropertyChanged;
                    BrickPi.SetMotorEnable(it.Port, it.Enabled);
                }
                break;
            case NotifyCollectionChangedAction.Remove:
                foreach (BPiMotor it in e.OldItems)
                {
                    it.PropertyChanged -= it_PropertyChanged;
                    BrickPi.SetMotorEnable(it.Port, false);
                }
                break;
            case NotifyCollectionChangedAction.Reset:
                break;
        }
        int res = BrickPi.SetupSensors();
        if (res != 0)
        {
            Console.WriteLine("");
            throw new Exception(string.Format("Error: BrickPi.SetupSensors: {0}", res));
        }
    }

    void it_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (this.AutoUpdate == true) 
            Update();
    }

    /// <summary>
    /// call UpdateValues
    /// </summary>
    public void Update()
    {
        BrickPi.UpdateValues();
        System.Threading.Thread.Sleep(10);
    }
}
public class BPiMotor : BindableBase
{
    public int Port { get; set; }

    private bool _enabled = false;
    public bool Enabled
    {
        get { return _enabled; }
        set
        {
            BrickPi.SetMotorEnable(this.Port, value);
            this.SetProperty(ref this._enabled, value);
        }
    }

    private int _speed = 0;
    public int Speed
    {
        get { return _speed; }
        set
        {
            BrickPi.SetMotorSpeed(this.Port, value);
            this.SetProperty(ref this._speed, value );
        }
    }
}

実際に制御するサンプルコードです。

■sampleCs.cs

設定部分がちょっとオブジェクト指向っぽい感じですね。最終的には、Xamarin.iOS/Android を使って、iPad から制御できるようにします。通信部分は、.NET で簡易HTTPサーバー作ってRESTでやり取りするという感じです。

class Program2
{
    void main()
    {
        int speed = 200;
        var bpi = new BPi();
        // initialize 
        bpi.Setup();
        bpi.AutoUpdate = true;
        var motor1 = new BPiMotor() { Port = BrickPi.PORT_B, Enabled = true };
        var motor2 = new BPiMotor() { Port = BrickPi.PORT_C, Enabled = true };
        bpi.Motors.Add(motor1);
        bpi.Motors.Add(motor2);
        bpi.Timeout = 3000;

        Console.WriteLine("start");
        bool loop = true;
        while (loop)
        {
            var k = Console.ReadKey();
            switch (k.Key)
            {
                case ConsoleKey.W:
                    motor1.Speed = speed;
                    motor2.Speed = speed;
                    break;
                case ConsoleKey.A:
                    motor1.Speed = speed;
                    motor2.Speed = -speed;
                    break;
                case ConsoleKey.D:
                    motor1.Speed = -speed;
                    motor2.Speed = speed;
                    break;
                case ConsoleKey.S:
                    motor1.Speed = -speed;
                    motor2.Speed = -speed;
                    break;
                case ConsoleKey.X:
                    motor1.Speed = 0;
                    motor2.Speed = 0;
                    break;
                case ConsoleKey.Q:
                    loop = false;
                    break;
            }
            // bpi.Update();
        }
    }
    static void Main(string[] args)
    {
        var pro = new Program2();
        pro.main();
    }
}

■sampleF2.fs

F# の場合も C# とほぼ同じですが、括弧がない分だけ若干短く書けます。これも HTTP 経由で制御できるようにする予定です。

module sampleF2
open System
open BrickPiNet 

let speed = 200
// main
let bpi = new BPi()
bpi.Setup()
bpi.AutoUpdate <- true
let motor1 = new BPiMotor( Port = BrickPi.PORT_B, Enabled = true )
let motor2 = new BPiMotor( Port = BrickPi.PORT_B, Enabled = true )
bpi.Motors.Add(motor1)
bpi.Motors.Add(motor2)
bpi.Timeout <- 3000 
Console.WriteLine("start")
let mutable loop = true
while loop do
    let key = Console.ReadKey()
    match key.Key with
        | ConsoleKey.W -> 
            motor1.Speed <- speed 
            motor2.Speed <- speed 
        | ConsoleKey.A -> 
            motor1.Speed <- speed 
            motor2.Speed <- -speed 
        | ConsoleKey.D -> 
            motor1.Speed <- -speed 
            motor2.Speed <- speed 
        | ConsoleKey.S -> 
            motor1.Speed <- -speed 
            motor2.Speed <- -speed 
        | ConsoleKey.X -> 
            motor1.Speed <- 0
            motor2.Speed <- 0
        | ConsoleKey.Q -> 
            loop <- false
        | _ -> ()

F# の場合、面白いのはインタープリタ(fsharpi)でも動くことです。Raspberry Pi 上のターミナルで、fsharpi でインタープリタを起動した後で、以下を一気に通します。シリアルポートアクセスのため sudo で root 権限で動かしてください。

#r "BrickPi.dll" ;;
open System ;;
open BrickPiNet ;;
let speed = 200 ;;
// main
let bpi = new BPi() ;;
bpi.Setup() ;;
bpi.AutoUpdate <- true ;;
let motor1 = new BPiMotor( Port = BrickPi.PORT_B, Enabled = true ) ;;
let motor2 = new BPiMotor( Port = BrickPi.PORT_B, Enabled = true ) ;;
bpi.Motors.Add(motor1) ;;
bpi.Motors.Add(motor2) ;;
bpi.Timeout <- 3000 ;;

その後、

motor1.Speed <- 200 ;;

のように F# のコードを書くとそのまま車輪が動き出します。このあたりの流れは F# インタープリタならではのところです。制御コマンドっぽい形で動かせるので、テストとか試行錯誤のときに便利そうです。

カテゴリー: C#, F#, RaspberryPi | F# を使ってRaspberryPi+BrickPi+LOGO Mindstorms EV3 を動かす はコメントを受け付けていません

BrickPi でモーターの動作確認まで

Raspberry Pi で F# が動かせたので、今度は BrickPi の設定です。

image

BrickPi Image Setup: Setting up your SD Card For the BrickPi
http://www.dexterindustries.com/BrickPi/getting-started/pi-prep/

にある Modify your own image にしたがって、BrickPi パッケージをインストールしていきます。

git clone https://github.com/DexterInd/BrickPi.git

から始まって、ちまちまと設定をしないといけないので、Download and use our modified Raspbian image on your own SD Card のほうから、BrickPi インストール済みの OS をダウンロードしたほうが良さそうです。今回は、mono, fsharp のインストールが大変なので、ちまちまと modify していきました。sudo nano /etc/inittab のあたりとか、既に Raspberry Pi 配布の Debian では設定済みのところがあるので、あれ?と思うところもありあますが、そのまま進んで完了です。

■サンプルを動かして動作確認する

サンプルは Progam メニューの中に色々あります。グラフィカルにプログラミングができる Scratch も魅力的ではあるのですが、最終的には F# で動かしたいのでここは飛ばし、

Scratch

C ← BrickPi
http://www.dexterindustries.com/BrickPi/program-it/c/

でビルドをします。

BrickPi のボードの MB と MC に EV3 のモーターをつなげて

cd BrickPi_C/Project_Examples/simplebot/
cp ../../Drivers/*.h .
gcc -o sbot simplebot_simple.c -lrt -lm -L/usr/local/lib -lwiringPi
sudo ./sbot

でモーターが動きます。Drivers ディレクトリからコピーしているのは、BrickPi.h と tick.h とい2つのファイルです。

最初、sbot のようにユーザーモードで動かして、なんか BrickPiSetup で -1 を返すし変だなーと思っていたのですが、どうやら root 権限じゃないと動かないようです。シリアルポート ttyAMA0 を読み書きするのでルート権限が必要なようです。

ソース自体は実に単純で https://github.com/DexterInd/BrickPi_C/blob/master/Project_Examples/simplebot/simplebot_simple.c を見ると、

  • BrickPiSetup で初期化
  • BrickPi.Address に通信アドレス設定
  • BrickPi.MotorEnable[motor1] のモーターの設定
  • BrickPiSetupSensors() でセンサーに設定
  • BrickPi.MotorSpeed[motor1] にモーターのスピードを設定
  • BrickPiUpdateValues() で設定をアップロード

のようなパターンでできます。C# のサンプルはないので、適宜 API を DllImport する必要がありそうですが、まあなんとかなるかな。

■WiFi と電源供給の関係

image

モーターの駆動は上の 9V 電池から、WiFi などの動作は下の mini USB から取ってきているようです。BrickPi の 9V 電源を指しただけでも Raspberry Pi は動作するのですが、WiFi を差し込むと電圧が足りないのか止まってしまうんですよね。手元にあるのが、Logitec の Skylink LAN-W300n/U2S というものなのですが、消費電力が多いのかもしれません。

ちなみに、新しく買ってきた elecom WDC-150U2MBK は Raspberry Pi が認識しないというパターンに陥っているので、慎重に選んだほうがよさそうです。いくつかのサイトを見ると、Logitec か bufferlo の製品を使っている場合が多そうです。たしか、基盤は一緒なので、ドングルの名前さえうまく設定してやれば Raspberry Pi で認識するようになったハズなのですが。

■参考

工作と小物のがらくた部屋: BrickPi を入手しました。
http://junkroom2cyberrobotics.blogspot.jp/2014/02/brickpi.html

このサイトを見ると Planex の BT-micro3H2X が高いですがよさそうです。WiFi と Bluetooth が一緒になっているのでよさそうです。

カテゴリー: RaspberryPi | BrickPi でモーターの動作確認まで はコメントを受け付けていません

Raspberry Pi で F# を動かすまで(まとめ)

手元にあるのが Raspberry Pi のメモリが 256MB タイプのためか F# をビルドするときに失敗します。が、別途の Debian でビルドした DLL を install することで回避しています。
手持ちの SD カードは 8GB です。

■下準備

画面は使わずにターミナルだけで作業をします。初期状態で ssh が使える状態になっているので、起動したときの IP だけわかれば OK。初回のみ HDMI でディスプレィをつなげて固定 IP にしておけばよいでしょう。DHCP でも自宅の場合はそう変わらないので、そのままでもいいかなと。

  1. Raspbian Debian Wheezy をインストール
  2. sudo respi-config して Expand Filesystem を実行。こうすると SD カード一杯まで容量を増やしていくれる。
  3. sudo passwd root でパスワードを設定しておく。
  4. adduser でユーザを作る。
  5. visudo で sudo できるようにしておく。
  6. sudo apt-get update する。
  7. sudo apt-get upgrade する。
  8. sudo apt-get install avahi-daemon する。ホスト名を公開するため。
  9. sudo apt-get install samba する。Windows からファイルを送るため

■ビルドの準備

Mono と F# を git から持ってきてビルドします。mono 自体は sudo apt-get mono-complete で持ってこれるのですが、何故か F# 3.1 で使おうとするこけます。また、Rasberry Pi のレポジトリには fsharp パッケージがないので、自前でビルドする必要があります。が、Raspberry Pi 上で F# のコードをビルドしようとすると、途中でテストのエラーでこけます。

という状態なので、Mono 3.2.8 + F# 3.1 の組み合わせの場合は、

  • Mono を Raspberry Pi でダウンロードしてビルド、インストール
  • F# を別の Debian でダウンロードしてビルド
  • 出来上がった F# を Raspberry Pi にコピーしてインストール

という手順になります。F# を別の環境で make install するので、ビルドするディレクトリ名は揃えたほうが無難です(異なる場合は、ln -s すれば ok)。可能ならば ARM 環境で Mono をビルドすればいいんでしょうが。Visual Studio を使えばできるかも。

■ビルドする

http://fsharp.org/use/linux/ にある Option 2: Build and install the F# 3.1 runtime, compiler and tools に従って Mono をビルドします。うちの環境では 12 時間以上かかりました。出来上がったバイナリは大事にとっておきましょう。

sudo make install すると無事 mono が使える状態になります。

image

お次は、F# をビルドするのですが、これは別の Debian でやります。git clone https://github.com/fsharp/fsharp  からダウンロードしてビルドします。これは普通の PC(私の場合は Hyper-V 上の Debian)なのであっという間です。ちなみに、Mono のビルドも結構なスピードで出来上がりますが、中身が ARM ではないので、Raspberry Pi にはコピーできません…と思うのですがどうなんでしょうね?私の場合は 12 時間かけて Raspberry Pi 上でビルドしたのですが。

できあがった F# のバイナリを tar で固めて、Raspberry Pi 上に持っていきます。そして sudo make install すれば、無事 F# が使えるようになります。

■F# を動かす

インタープリタは fsharpi です。コンパイラは fsharpc ですね。Scala の fsc とバッティングしたので名前が長くなっています。つーか、Scala 入れてないから、fsc で ln -s してもいいですね。

image

コマンドラインから fsharpi を打った後にしばらく待たされます。更に let a = … と打った後にしばらく待たされます。どうやら mono ががんばっている模様で、ある程度ライブラリのロードが終わったら早くなります。top でみると結構上に貼りついてしまうのでなかなか大変そうです。

image

ビルドした後は分からないのですが、センサー取り込みのような素早い処理には向かないけど、ロボット制御のようなコマンド送信には十分使えるかなと思っています。まあ、それで BrickPi を購入したわけですが。de:code で MS太田さんが .NET Micro Framework で EV3 を操作できたそうなので、MF のほうでも試してみたいですね。つーか、動くのか? F#
ちょっと古いですが、2010年ごろのブログに Managed、Native、.NET Framework? – デバイスとITの架け橋 – Site Home – MSDN Blogs の冒頭「参加されていたのは組込み業界の皆さんだったにも拘らず、F#を使っている方が何人かいらっしゃって」とあるので、制御系にはうけがいいかもしれません。コンピュテーション式なんてのは、DSL 的に有用ですからね。RSNP あたりでしたっけ?

そんな訳で、お次は BrickPi のセットアップです。

カテゴリー: F#, RaspberryPi | Raspberry Pi で F# を動かすまで(まとめ) はコメントを受け付けていません

Raspberry Pi で F# を動かす(陽性かくにん版)

F# ビルドの続きです。

■fsharp のビルドでこける

正確には F# proto(F# 3.1 をビルドするための F# 3.0)のテストでこけます。

image_thumb

ガベージコレクションのテスト(かな?)をしているところで、alloc 出来なくてこけているので おそらく RasPi のメモリ不足ですね。手元の Raspberry Pi って初期型なので、メモリが少なくって USB が 2 つついているけど 256MB しかないんですよね。

image_thumb[1]

おそらく、ここの GC チェックを外してしまえばビルドできると思うのですが、どうも手軽ではない。そもそも Mono 3.2.7 のメモリでこける件もテスト自体でこけているので実害はないかもしれない。

■Debian でビルドした F# をインストールする

で、そもそもが「 FSharp.Core は環境依存していないだろう」という想定のもとに、別の Debian でビルドした FSharp.Core 等を Raspberry Pi のほうにインストールしてしまいます。これでいいのかっどうか不明なのですが(Debian 構築のほうは Hyper-V 上で x64)、同じ Linux 上だしなんとかなるかもしれません。

Debian でビルドした fsharp を tar で固めて、Raspberry Pi へコピー。その後、フォルダ名を合わせてから sudo make install します。ビルド環境のパスをあわせるのは、makefile 等にビルド環境が書き込まれているからです。

無事インストールして fsharpi します。

image

fsharpi を動かすと30秒ぐらい待たされますが、一応動きます。元ネタは 大事なことは全部MLが教えてくれた ~ Apple の Swift の mutability 周りの件を理解する – Oh, you `re no (fun _ → more) です。どうやら mono の読み込みの時にかなりパワーを使っているらしく、新しい文法を使うたびに動作が重いです。一度、読み込むと動きがスムースになるのでキャッシュあたりですかね。

という訳で例の FsRandom で陽性かくにん! も動かしてみましょう。Windows の NuGet で持ってきた FsRandom.dll を Raspberry Pi にコピーして

fsharpc -r:FsRandom.dll stap.fs

すると、無事 stap.exe が出来上がります。これを実行すると…無事 198599 番目に(でよかったのかな?)陽性かくにんできます。

image

このプログラム自体は結構なスピードで動くので、初回の mono のロードだけ重たいみたいです。

カテゴリー: F#, RaspberryPi | 1件のコメント