LoginSignup
18
17

More than 5 years have passed since last update.

[Unity] Intel Edison で Unity を実行する

Last updated at Posted at 2015-08-25

ただし グラフィクスは一切なし です。
使用した Unity のバージョンは 5.1.1.f1 personal です。

Edison をセットアップ

Switch Science さんの解説は各OSごとにまとめてあってすばらしいです。
Intel Edisonを手に入れたらやること
ただし現時点で、一部コマンドの使い方が異なっていました。
configure_edison --setup
の引数 --setup は必要なかったり。

また、そのままだと自動で Wifi に接続してくれないので、
[Intel Edison] 起動したら Wifi につながるようにする

をやっときます。

Unity プロジェクト準備

プロジェクトはなんでもいいですが、実験なので軽いものがよいですね。
とはいえグラフィクスは表示されないので、動作確認がむずかしい。できれば Edison にログインしなくても確認できるのが望ましいので、今回は UDP パケットを投げるサンプルを作りました。(たまたま最近似たようなのを作ったこともあり)。

1秒置きにUDPパケットを送り続けるサンプル

UdpSender.cs
using UnityEngine;
using System.Collections;
using System.Net.NetworkInformation;

public class UdpSender : MonoBehaviour {
    public int listenPort = 2002; // ポートはサーバ・クライアントで合わせる必要がある
    private static bool sent = false;
    private Coroutine coroutine_ = null;

    public static void SendCallback(System.IAsyncResult ar)
    {
        // System.Net.Sockets.UdpClient u = (System.Net.Sockets.UdpClient)ar.AsyncState;
        sent = true;
    }

    IEnumerator send(string server, string message)
    {
        Debug.Log("sending..");
        var u = new System.Net.Sockets.UdpClient();
        u.EnableBroadcast = true;
        u.Connect(server, listenPort);
        var sendBytes = System.Text.Encoding.ASCII.GetBytes(message);
        sent = false;
        u.BeginSend(sendBytes, sendBytes.Length, 
                    new System.AsyncCallback(SendCallback), u);
        while (!sent) {
            yield return null;
        }
        u.Close();
        coroutine_ = null;
        Debug.Log("done.");
    }

    IEnumerator sending()
    {
        for (;;) {
            if (coroutine_ == null) {
                NetworkInterface[] nicList = NetworkInterface.GetAllNetworkInterfaces();
                string sendMsg = "Edison";
                foreach( NetworkInterface nic in nicList ) {
                    IPInterfaceProperties ipInfo = nic.GetIPProperties();
                    foreach (var addr in ipInfo.UnicastAddresses) {
                        var bytes = addr.Address.GetAddressBytes ();
                        // RFC1918
                        if (bytes[0] == 10 ||
                            (bytes[0] == 172 && 16 <= bytes[1] && bytes[1] <= 31) ||
                            (bytes[0] == 192 && bytes[1] == 168)) {
                            sendMsg += string.Format (":{0}", addr.Address.ToString ());
                        }
                    }
                }
                string server = "192.168.0.1"; // 可能ならブロードキャストが楽
                coroutine_ = StartCoroutine(send(server, sendMsg));
                yield return new WaitForSeconds(1f);
            }
        }
    }

    void Start() {
        StartCoroutine(sending());
    }

    void Update() {
    }
}

このスクリプトを適当なオブジェクトにアタッチして、Hierarchy に置きます。
下のほうにある
string server = "192.168.0.1";
ここは適宜書き換えてください。自宅などサブネットを掌握している場合はブロードキャストアドレスを書いちゃうのが楽です。職場とか学校なら迷惑をかけないよう、自分の作業PCのアドレスを入れましょう。

パケットにはアドレスを文字列にして入れておきます。あとでこれが役に立つのです。検出したNICを列挙して、RFC1918 に規定してあるプライベートネットワークアドレスを抽出しています。

Unity でビルド

上記スクリプトの入ったシーンを保存して、BuildSettings Window から

  • Target Platform:Linux
  • Architecture: x86

でビルドします。吐き出し先のフォルダ名は linux にしておきます。(なんでもよいです)
linux という名前にしてあれば、プロジェクトの下に

  • linux.x86
  • linux_Data

というファイル&フォルダが現れています。これらを Edison に送るわけですが、
ディレクトリもあるので、tar で固めます。

$ tar -cvfz linux_Data.tar.gz linux.x86 linux_Data

Edison へ転送

上記のビルド結果を Edison の /var に送ります。(/var は例で、どこでもよいです)

$ scp linux_Data.tar.gz root@192.168.2.15:/var

Edison にログインして /var 以下を確認し、展開します。

root@yuji-edison:~# cd /var
root@yuji-edison:/var# tar -xvfz linux_Data.tar.gz

実行

実行してみましょう。

root@yuji-edison:/var# ./linux.x86
./linux.x86: error while loading shared libraries: libGL.so.1: cannot open shared object file: No such file or directory

エラーが出ますよね。これは予定通り。引数でグラフィクスを無効にすればよいのです。

root@yuji-edison:/var# ./linux.x86 -batchmode -nographics
./linux.x86: error while loading shared libraries: libGL.so.1: cannot open shared object file: No such file or directory

同じエラーが出ましたね。・・・だめじゃん!

ダミーso の作成

本当の戦いはここからです。

Unity のドキュメント見ても、-batchmode -nographics でグラフィクスの初期化しない、と書いてあります。初期化はしない。しないが、so だけ読む。んですね。ならば読み込みにさえ成功させればよいはず。なのでダミーを作ります。

/var で作業するのはなんなので、ホームに移動して、main.cpp というファイルを作成します。

main.cpp
void dummy()
{
}

清々しいコードです。include すらしないコードなんて滅多に書きませんね。
ビルドして、so を作ります。

root@yuji-edison:~/work/dummy# gcc -shared main.cpp -o libGL.so.1

できました。この libGL.so.1 を /usr/lib にコピーします。

root@yuji-edison:~/work/dummy# cp libGL.so.1 /usr/lib

さあ、どうだ。

root@yuji-edison:/var# ./linux.x86 -batchmode -nographics
./linux.x86: error while loading shared libraries: libX11.so.6: cannot open shared object file: No such file or directory

だめ。でも一歩前進。こんどは libX11.so.6 がない。
この調子でダミーを作っていくわけですが、結論からいいますと、ここには複数の関数定義も含める必要がありました。

main.cpp
extern "C" {
typedef void Display;

Display* XOpenDisplay(char* display_name)
{
  return 0;
}

typedef void* XIM;
typedef void* XrmDatabase;
XIM XOpenIM(Display*, XrmDatabase, char*, char*)
{
  return 0;
}

typedef void* XIC;
XIC XCreateIC(XIM im, ...)
{
  return 0;
}

}

これをビルドして、
root@yuji-edison:~/work/dummy# gcc -shared main.cpp -o libX11.so.6
コピーします。
root@yuji-edison:~/work/dummy# cp libX11.so.6 /usr/lib

これでも動きません。必要なダミーso はあと2つありました。
libXcursor.so.1
libXrandr.so.2
これらは空っぽでよいので、libGL.so.1 をコピーします。置き場所は同じく /usr/lib です。
root@yuji-edison:~# cd /usr/lib
root@yuji-edison:/usr/lib# cp libGL.so.1 libXcursor.so.1
root@yuji-edison:/usr/lib# cp libGL.so.1 libXrandr.so.2

さあ、動くかな?
root@yuji-edison:/var# ./linux.x86 -batchmode -nographics

Set current directory to /var
Found path: /var/linux.x86
Mono path[0] = '/var/linux_Data/Managed'
Mono path[1] = '/var/linux_Data/Mono'
Mono config path = '/var/linux_Data/Mono/etc'
PlayerConnection initialized from /var/linux_Data (debug = 0)
PlayerConnection initialized network socket : 0.0.0.0 55014
Multi-casting "[IP] 192.168.0.105 [Port] 55014 [Flags] 2 [Guid] 4221828501 [EditorId] 628846382 [Version] 1048832 [Id] LinuxPlayer(192.168.0.105) [Debug] 0" to [225.0.0.222:54997]...
PlayerConnection already initialized - listening to [192.168.0.105:55014]
displaymanager : trying .X11-unix
Using libudev for joystick management


Importing game controller configs

動いた!・・・のか?
確認するために受信側のプログラムを作成します。

受信プログラムの作成

Unity でプロジェクトを用意して、以下のスクリプトを用意します。

UdpReceiver.cs
using UnityEngine;
using System.Collections;

public class UdpReceiver : MonoBehaviour {
    public int listenPort = 2002; // ポートはサーバ・クライアントで合わせる必要がある
    private static bool received = false;

    private struct UdpState {
        public System.Net.IPEndPoint e;
        public System.Net.Sockets.UdpClient u;
    }

    public static void ReceiveCallback(System.IAsyncResult ar) {
        System.Net.Sockets.UdpClient u = (System.Net.Sockets.UdpClient)((UdpState)(ar.AsyncState)).u;
        System.Net.IPEndPoint e = (System.Net.IPEndPoint)((UdpState)(ar.AsyncState)).e;
        var receiveBytes = u.EndReceive(ar, ref e);
        var receiveString = System.Text.Encoding.ASCII.GetString(receiveBytes);

        Debug.Log(string.Format("Received: {0}", receiveString)); // ここに任意の処理を書く

        received = true;
    }

    IEnumerator receive_loop() {
        var e = new System.Net.IPEndPoint(System.Net.IPAddress.Any, listenPort);
        var u = new System.Net.Sockets.UdpClient(e);
        u.EnableBroadcast = true;
        var s = new UdpState();
        s.e = e;
        s.u = u;
        for (;;) {
            received = false;
            u.BeginReceive(new System.AsyncCallback(ReceiveCallback), s);
            while (!received) {
                yield return null;
            }
        }
    }

    void Start () {
        StartCoroutine(receive_loop());
    }
}

これを GameObject にアタッチして実行します。実行というかエディタの再生ですね。
Edison は先ほどのを実行させた状態です。

スクリーンショット 2015-08-25 20.58.06.png

見事、受信しています。これで動作確認ができました。めでたしめでたし。

Unity プログラムを Intel Edison で自動起動する

というエントリを近日アップします。こちらのほうが難易度が高いです実は。
これができると、本格的に何かに利用したくなってきます。


追記:書きました。
[Unity] Unity プログラムを Intel Edison で自動起動する

18
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
17