とかげ備忘録

IT系の備忘録です。

AWSのまだ動いていたサービスを調べて削除する

はじめに

AWSにて、 使用していたサービスを覚えているものは片っ端から削除したが、 1か月経って、まだ課金されているサービスがあったので、調べた。

内容

使用をやめるときにAWSのアクティブなサービスを削除していくのだが、 いざ削除しようと思ったときに、 何のサービスを使ったか、何に紐づけられているか把握しておくのは、きつい。

なのでその使用サービス一覧を見て対処していくのがよい?

AWS Systems Managerで使用しているサービス一覧を調べる

公式ドキュメント docs.aws.amazon.com

ナビゲーションメニューより、 ▼変更管理 → 自動化 に遷移

オートメーション実行で AWSSupport-ListEC2Resources を検索して →  それを選択して次へ

f:id:ttokage2233:20210411234739p:plain

f:id:ttokage2233:20210411234802p:plain

シンプルな実行

タグでフィルタリングできるみたいだが、 個人でそんなにサービス立ち上げていたわけではないので、

そのまま「シンプルな実行」で実行する。

実行結果を見る

「出力」を確認。

私の中ではすべてサービス終了させていたはずなので、 ほぼ、No Resources Foundが出力されたが、 一か所Elastic IPで動いているサービスが残っていた。

このアドレスを開放するには、このURLからできますよ。という案内も出力してくれるので 助かる。

そこのサービスを見に行って、削除した。めでたし

おわりに

これで来月は請求がなくなるはず。

UnityでVRアプリをビルドして試してみる

はじめに

UnityでOculus Quest 2向けの環境設定を行って、VRアプリをビルドして実機で確認するまでの流れ

  • Unity:2019.4.15.f1
  • VR機器:Oculus Quest 2

手順

1.アセットストアからOculus Integrationを導入

assetstore.unity.com

これを入れる。

2.Build SettingsでPlatformをAndroidにする。

[Texture Compression (テクスチャー圧縮)]を[ASTC]に設定します。

3.Project Settingsより、XRSettings → Virtual Reality Supportedにチェックを入れる

入れ子になった下の方のチェックは勝手に付いていた。よくわからん。)

f:id:ttokage2233:20210411230011p:plain

4.Graphics APIsの「Vulkan」を消してね。とのエラーが出たので。これも消す。

Error building Player: BuildFailedException: XR is currently not supported when using the Vulkan Graphics API. Please go to PlayerSettings and remove 'Vulkan' from the list of Graphics APIs.

f:id:ttokage2233:20210411230529p:plain

5.Oculus Quest 2を接続してRun Deviceでデバイスを指定する。

f:id:ttokage2233:20210411230956p:plain

6.ビルドシーンについて

アセット付属のDemoシーンをビルドしてもいいし、 自作のシーンをビルドしてもいい。(←自作の場合は、とりあえずアセット付属のVR用のカメラをシーンに配置しておけばOK)

7.Build and Runを押す

ビルド後、実機確認ができる。

8.もう一度そのアプリを確認するには

Oculus Quest 2起動後のホーム画面で、 右手のコントローラーのOculusのマーク?を押して、 メニュー画面 → アプリを押す。 アプリ画面の右上のところの「すべて」を 「提供者不明」に変えると、先ほど実機で実行したアプリが表示される。

9.実機確認したやつ

10.おわりに

はい終わり

【光回線】おてがる光契約したよ。の話

はじめに

2020/09/25現在
契約して2週間くらい経ちました。
こういうのって情報あんまり出てないと思ったから書いておこうと思う。

使用感は良い。

オプション

付けたオプションは2つ。そのうち1つはぶっちゃけ強制だけど。

↑契約前の問い合わせで確認済み。

速度

テキトーに計測

wifi

土日のお昼過ぎ頃

f:id:ttokage2233:20200925005631p:plain:w300 f:id:ttokage2233:20200925005645p:plain:w300

有線LAN

ケーブルはCAT7のLANケーブル使用。

平日の夜中0時過ぎころ
f:id:ttokage2233:20200925005724p:plain f:id:ttokage2233:20200925005731p:plain

以上。

アセットストアのアセットのダウンロード先フォルダを変更する

割と記事は出ているけど自分用にメモ

目的

Cドライブが圧迫されていたので、保存先をDドライブの方に変更したい。
Cドライブの容量を少しでも軽くしてあげたい。

やること

1.CドライブにあるアセットのフォルダをDドライブに移動

f:id:ttokage2233:20200925000754p:plain
CドライブのアセットフォルダをDドライブに変更

2.Cドライブから、Dドライブの方へジャンクションを作成する。

コマンドプロンプト開いて 、ジャンクションを作成する。

mklink /j "C:\Users\<user_name>\AppData\Roaming\Unity\Asset Store-5.x" "D:\Unity\Asset Store-5.x"

f:id:ttokage2233:20200925002728p:plain
ジャンクション作成

はいできた。

MagicOnionを使ってリアルタイム通信を試す。【Unity】

はじめに

1年ほど前に使ったことがあったので、 久しぶりに導入してみたら躓いたので、 記録として残しておきます。

とりあえず覚えながら作ってみたやつ

MagicOnionについて

Web API ライクな通信や、リアルタイム通信ができるフレームワーク

特徴

サーバー側もクライアント側もC#で書ける。
gRPCを使用。(HTTP/2や、Protocol Buffersを使っていて、高速)
MessagePack for C#を使用。(LZ4で圧縮されてサイズが小さく、高速)
フィルタ機能を持ち、多段に重ねて処理を行うことができる。 ←この様子がMagicOnionの由来だとか
(↑通信の前後に追加の処理を行うことができる。)


色々調べていたら、チャットとか、マルチプレイを実現できそうなものとして、下記のようなものもありました。

  • SignalR

  • Photon(PUN2)

MagicOnionを選んだ理由は、1度勉強会で扱ったことがあるからです。

使うイメージ

クライアント側とサーバー側が共有するインターフェースを用意して、 それぞれ実装します。 互いのメソッドを呼び出してあげれば通信できます。

f:id:ttokage2233:20200425235331p:plain

準備

  • Unity

2018.4.2f1

各種ダウンロード

ダウンロードファイルの***.zipファイルですが、MagicOnionをIL2CPP環境で使う場合に使用します。 この対応については、最後の方に後述します。

MagicOnion

https://github.com/cysharp/MagicOnion/releases

バージョン

3.0.11

取得するファイル

  • MagicOnion.Client.Unity.unitypackage

  • moc.zip

gRPC

https://packages.grpc.io/

バージョン

2.26.0


https://packages.grpc.io/archive/2019/11/b5e0d5e0443e229841225a8727f5fb268544953f-18403aac-451d-4f74-8850-c2747419fe76/index.xml

取得するファイル

  • grpc_unity_package.2.26.0-dev.zip


その時最新だった2.29.0で試したが、VisualStudioでプロジェクト作成して作業しようとしたら、「予期せぬエラーです。」と表示されてしまった。
分からなかったので、このバージョンに落とした。

もしかしたら、System.Memory.dllバージョンが噛み合ってないからだろうか・・・。
https://github.com/grpc/grpc/issues/21908

↑2.26.0で動いたというコメントがあったので、このバージョンを使用した。

MessagePack for C#

https://github.com/neuecc/MessagePack-CSharp/releases

バージョン

2.1.90

取得するファイル

  • MessagePack.Unity.2.1.90.unitypackage

  • mpc.zip

導入

Unityの設定変更

「File」→「Build Settings」から、 「Player Settings...」 を押す。

ビルド対象OSの 「Other Settings」項目 → 「Configuration」項目の

Api Compatibility Level」 → .NET 4.x 「Allow 'unsafe' Code」 → チェック

に設定する。

f:id:ttokage2233:20200426000150p:plain

用意したファイルのインポート

Unityプロジェクトを立ち上げ、**.unitypackageのファイルをインポートします。

  • MagicOnion.Client.Unity.unitypackage

  • MessagePack.Unity.2.1.90.unitypackage

f:id:ttokage2233:20200426000713p:plain f:id:ttokage2233:20200426000725p:plain

ファイルの競合

導入時に、Assets/Plugins/ 直下の

System.Buffers
System.Memory
System.Runtime.CompilerServices.Unsafe
System.Threading.Tasks.Extensions

上記のファイルが競合するので、
名前を変えて、競合を回避する。
なんか消すのが怖かったので、実際どうなんだろう・・・。

これらを行えば、とりあえずUnity Editor上のエラーは消えた。

ひとまずテキトーにスクリプトを開いてVisual Studioを立ち上げる。

VisualStudioの設定

VisualStudioに.Net Core SDKとランタイムをインストールしていない場合は、インストールしておきます。 私の環境だと入っていたので、多分この辺りを確認すればよいと思います。

f:id:ttokage2233:20200426010710p:plain

f:id:ttokage2233:20200426010421p:plain f:id:ttokage2233:20200426010441p:plain

クライアント側の用意

特になし

サーバー側の用意

Unityのソリューションから右クリックで、
新規のプロジェクトを作成する。

f:id:ttokage2233:20200426013314p:plain f:id:ttokage2233:20200426013646p:plain

サーバー側にパッケージをインストールする。

  • MagicOnion.Hosting

  • MessagePack.UnityShims

f:id:ttokage2233:20200426012156p:plain f:id:ttokage2233:20200426012356p:plain 図:パッケージインストール例

(今思えば、これらのパッケージを参考にクライアント側のバージョンを合わせてダウンロードすればよかったのでは?と思う自分であった。)

クライアント - サーバー間の共有ファイルの設定

サーバー側のプロジェクトファイルを編集して、共有するフォルダの設定を行います。

  • クライアント側

f:id:ttokage2233:20200426014214p:plain

  • サーバー側

サーバー用プロジェクトの設定に、
Unityプロジェクトの共有用フォルダのパスを指定します。
f:id:ttokage2233:20200426015506p:plain

クイックスタートをやってみる

GitHubに載ってたクイックスタートを参考にやってみる。
https://github.com/cysharp/MagicOnion

サーバーのスタート処理

  • Program.cs(サーバー側)
using System;
using Grpc.Core;
using MagicOnion.Server;

namespace MagicOnionDemoServer
{
    class Program
    {
        static void Main(string[] args)
        {
            GrpcEnvironment.SetLogger(new Grpc.Core.Logging.ConsoleLogger());

            // setup MagicOnion and option.
            var service = MagicOnionEngine.BuildServerServiceDefinition(isReturnExceptionStackTraceInErrorDetail: true);

            var server = new global::Grpc.Core.Server
            {
                Services = { service },
                Ports = { new ServerPort("localhost", 12345, ServerCredentials.Insecure) }
            };

            // launch gRPC Server.
            server.Start();

            // and wait.
            Console.ReadLine();
        }
    }
}

API通信

コーディング

共有するインターフェースを作成する。

  • IMyFirstService.cs
using Grpc.Core;
using MagicOnion;
using MagicOnion.Server;
using System;

namespace ServerShared.Services {
    public interface IMyFirstService : IService<IMyFirstService>
    {
        /// <summary>
        /// 足し算を行う
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        UnaryResult<int> SumAsync(int x, int y);
    }
}

サーバー側実装

  • MyFirstService.cs
using System.Collections.Generic;
using System.Text;
using Grpc.Core;
using MagicOnion.Hosting;
using MagicOnion;
using MagicOnion.Server;
using ServerShared.Services;

    class MyFirstService : ServiceBase<IMyFirstService>, IMyFirstService
    {
        public async UnaryResult<int> SumAsync(int x, int y)
        {
            Logger.Debug($"Received:{x}, {y}");
            return x + y;
        }
    }

クライアント側実装

  • ApiConnectionTest.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Grpc.Core;
using MagicOnion.Client;
using ServerShared.Services;

public class ApiConnectionTest : MonoBehaviour
{
        async void Start() {
        // standard gRPC channel
        var channel = new Channel("localhost", 12345, ChannelCredentials.Insecure);

        // get MagicOnion dynamic client proxy
        var client = MagicOnionClient.Create<IMyFirstService>(channel);

        // call method.
        var result = await client.SumAsync(100, 200);
        Debug.Log("Client Received:" + result);
    }
}

動作確認

サーバー側のプロジェクトをスタートアッププロジェクトに設定し、
プログラムを実行します。

f:id:ttokage2233:20200426025149p:plain f:id:ttokage2233:20200426030111p:plain

クライアント側は、 空のGameObjectを作成して、ApiConnectionTest.csをアタッチして実行します。

f:id:ttokage2233:20200426025857p:plain

f:id:ttokage2233:20200426030230p:plain

通信できました。

リアルタイム通信

コーディング

インターフェースを作成

  • IGamingHub.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MagicOnion;
using ServerShared.MessagePackObjects;
using UnityEngine;

namespace ServerShared.GamingHub
{
    /// <summary>
    /// クライアント → サーバー 処理
    /// </summary>
    public interface IGamingHub : IStreamingHub<IGamingHub, IGamingHubReceiver>
    {
        /// <summary>
        /// 入室処理
        /// </summary>
        /// <param name="roomName"></param>
        /// <param name="userName"></param>
        /// <param name="position"></param>
        /// <param name="rotation"></param>
        /// <returns></returns>
        Task<Player[]> JoinAsync(string roomName, string userName, Vector3 position, Quaternion rotation);

        /// <summary>
        /// 退出処理
        /// </summary>
        /// <returns></returns>
        Task LeaveAsync();

        /// <summary>
        /// 移動処理
        /// </summary>
        /// <param name="position"></param>
        /// <param name="rotation"></param>
        /// <returns></returns>
        Task MoveAsync(Vector3 position, Quaternion rotation);
    }

    /// <summary>
    /// サーバー → クライアント 処理
    /// </summary>
    public interface IGamingHubReceiver
    {
        /// <summary>
        /// 入室を接続クライアント全員に通知
        /// </summary>
        /// <param name="player"></param>
        void OnJoin(Player player);

        /// <summary>
        /// 退出を接続クライアント全員に通知
        /// </summary>
        /// <param name="player"></param>
        void OnLeave(Player player);

        /// <summary>
        /// 移動したことを接続クライアント全員に通知
        /// </summary>
        /// <param name="player"></param>
        void OnMove(Player player);
    }
}

サーバー側実装

  • GamingHub.cs
using System;
using System.Collections.Generic;
using System.Text;
using MagicOnion;
using MagicOnion.Server.Hubs;
using Grpc.Core;
using ServerShared.MessagePackObjects;
using ServerShared.GamingHub;
using System.Threading.Tasks;
using UnityEngine;
using System.Linq;

namespace MagicOnionDemoServer
{
    public class GamingHub : StreamingHubBase<IGamingHub, IGamingHubReceiver>, IGamingHub
    {
        IGroup room;
        Player self;
        IInMemoryStorage<Player> storage;

        public async Task<Player[]> JoinAsync(string roomName, string userName, Vector3 position, Quaternion rotation)
        {
            self = new Player() { Name = userName, Position = position, Rotation = rotation };

            // Group can bundle many connections and it has inmemory-storage so add any type per group. 
            (room, storage) = await Group.AddAsync(roomName, self);

            // Typed Server->Client broadcast.
            Broadcast(room).OnJoin(self);

            return storage.AllValues.ToArray();
        }

        public async Task LeaveAsync()
        {
            await room.RemoveAsync(this.Context);
            Broadcast(room).OnLeave(self);
        }

        public async Task MoveAsync(Vector3 position, Quaternion rotation)
        {
            self.Position = position;
            self.Rotation = rotation;
            Broadcast(room).OnMove(self);
        }

        /// <summary>
        /// 切断処理
        /// </summary>
        /// <returns></returns>
        protected override ValueTask OnDisconnected()
        {
            // on disconnecting, if automatically removed this connection from group.
            return CompletedTask;
        }
    }
}

クライアント側実装

  • GamingHubClient.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Grpc.Core;
using MagicOnion.Client;

using ServerShared.GamingHub;
using ServerShared.MessagePackObjects;
using UnityEngine;

public class GamingHubClient : IGamingHubReceiver
{
    Dictionary<string, GameObject> players = new Dictionary<string, GameObject>();

    IGamingHub client;

    public async Task<GameObject> ConnectAsync(Channel grpcChannel, string roomName, string playerName)
    {
        client = StreamingHubClient.Connect<IGamingHub, IGamingHubReceiver>(grpcChannel, this);

        var roomPlayers = await client.JoinAsync(roomName, playerName, Vector3.zero, Quaternion.identity);
        
        /* 今いるプレイヤーの生成(自分も含めて生成される)
        foreach (var player in roomPlayers)
        {
            (this as IGamingHubReceiver).OnJoin(player);
        }
        */

        return players[playerName];
    }

    // methods send to server.

    public Task LeaveAsync()
    {
        return client.LeaveAsync();
    }

    public Task MoveAsync(Vector3 position, Quaternion rotation)
    {
        return client.MoveAsync(position, rotation);
    }

    // dispose client-connection before channel.ShutDownAsync is important!
    public Task DisposeAsync()
    {
        return client.DisposeAsync();
    }

    // You can watch connection state, use this for retry etc.
    public Task WaitForDisconnect()
    {
        return client.WaitForDisconnect();
    }

    // Receivers of message from server.

    void IGamingHubReceiver.OnJoin(Player player)
    {
        Debug.Log("Join Player:" + player.Name);

        var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
        cube.name = player.Name;
        cube.transform.SetPositionAndRotation(player.Position, player.Rotation);
        players[player.Name] = cube;
    }

    void IGamingHubReceiver.OnLeave(Player player)
    {
        Debug.Log("Leave Player:" + player.Name);

        if (players.TryGetValue(player.Name, out var cube))
        {
            GameObject.Destroy(cube);
        }
    }

    void IGamingHubReceiver.OnMove(Player player)
    {
        Debug.Log("Move Player:" + player.Name);

        if (players.TryGetValue(player.Name, out var cube))
        {
            cube.transform.SetPositionAndRotation(player.Position, player.Rotation);
        }
    }
}
  • RealTimeConnectionTest.cs

テキトーなGameObjectを作成して、アタッチします。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using Grpc.Core;
using ServerShared.GamingHub;

public class RealTimeConnectionTest : MonoBehaviour
{
    public static GamingHubClient gamingHubClient;
    Channel channel;
    async void Start()
    {

        this.channel = new Channel("localhost:12345", ChannelCredentials.Insecure);

        RealTimeConnectionTest.gamingHubClient = new GamingHubClient();

        await gamingHubClient.ConnectAsync(channel, "SampleRoom", "tarou");
    }

}

動作確認

API通信と同様、サーバー側を実行しておいて、 クライアント側を実行します。

うまくいけば、四角いプレイヤーオブジェクトが生成されます。 これに、プレイヤーを動かすスクリプトを実行中にアタッチして、 確認してみます。

  • PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{

    float speed = 3f;
    Vector3 pos, currentPos;

    void Update()
    {
        Move();
    }
    
    void Move()
    {
        pos = transform.position;
        currentPos = pos;

        if (Input.GetKey("left"))
        {
            pos.x -= speed * Time.deltaTime;
        }
        if (Input.GetKey("right"))
        {
            pos.x += speed * Time.deltaTime;
        }
        if (Input.GetKey("up"))
        {
            pos.y += speed * Time.deltaTime;
        }
        if (Input.GetKey("down"))
        {
            pos.y -= speed * Time.deltaTime;
        }

        if (currentPos == pos) //値が変わらなかったら何もしない
        {
            return;
        }
        //サーバーを通して移動できるか確認したいので、コメントアウト
        //transform.position = pos;

        //移動情報送信
        RealTimeConnectionTest.gamingHubClient.MoveAsync(pos, transform.rotation);
    }

}

f:id:ttokage2233:20200426141854j:plain ↑*静止画です
移動はガタガタですが、情報のやりとりができました。

IL2CPP対応

MagicOnionをIL2CPP環境で使う場合は、事前のコードジェネレートが必要になります。
mpc.zipとmoc.zipファイルの中にコードジェネレートのための実行ファイルがあるので、
それを設定します。

minamiさんの記事が参考になりました。

  • Unity+.NET Core+MagicOnionの環境構築ハンズオン

https://qiita.com/_y_minami/items/c7899fdf1db505c06ba2

その中のMenuItems.csを、こちらが使うファイルパスに変更して、InitialSettings.csは下記のように設定してみました。
(このあたりのインスタンス登録処理は手探り状態で、どれを登録したらよいか、よくわかっていない。)

  • InitialSettings.cs
using MagicOnion.Resolvers;
using MessagePack.Resolvers;
using MessagePack.Unity;
using MessagePack;
using UnityEngine;

class InitialSettings
{
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    static void RegisterResolvers()
    {

        StaticCompositeResolver.Instance.Register(

                UnityResolver.Instance,
                MagicOnionResolver.Instance,
                GeneratedResolver.Instance,
                BuiltinResolver.Instance,
                PrimitiveObjectResolver.Instance
        );

        var options = MessagePackSerializerOptions.Standard.WithResolver(StaticCompositeResolver.Instance);

        MessagePackSerializer.DefaultOptions = options;

    }
}

MagicOnionResolver.Instance、GeneratedResolver.Instanceあたりは、
はじめは参照エラーだったが、
コードジェネレートした後に確認したら、参照エラーが解決していた。

さいごに

Taskや、await/asyncなどの理解をもう少し深めようと思った。
設計って難しい。
ここの処理はクライアント側orサーバー側に持たせる。とか
レスポンス速度これくらいで大丈夫かな。とか
通信が途中で切断したときどうしよう。とか
そういうところ意識しないとな。

参考

  • MagicOnion入門

https://www.slideshare.net/torisoup/magiconion-174973732

https://tech.cygames.co.jp/archives/3181/

  • Unity+.NET Core+MagicOnionの環境構築ハンズオン

https://qiita.com/_y_minami/items/c7899fdf1db505c06ba2

「やる気が上がる8つのスイッチ」を読んだので、自己分析する。

「やる気が上がる8つのスイッチ」という本があったので、読んでみました。
せっかくなので、自己分析しました。

アフィなしリンク:
https://www.amazon.co.jp/dp/B07ZCZYW2Y/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

3つの軸

まず、3つの軸の情報だけ書いておきます。

マインドセット

◆証明マインドセット
概要

自分の能力を相手に見せて、認めさせたい。
すごい人と思われたい。

特徴

ミスを恐れる
他人と比べる
助けを求めない

問題点

不安に押しつぶされる
物事を諦める

◆成長マインドセット
概要

自分のスペックを上げるために能力を高める。
新しいことを学んでいく。
すごい人になりたい。

特徴

他人をあまり気にしない
否定されてもやると思ったことをやる
壁があっても粘り強く続ける

問題点

特に書かれてなかったと思う。

②フォーカス

◆獲得フォーカス

革新的なイメージ
能動的で何かに向かって突き進む。
多くのことに手を出す。

特徴

物事を達成し、称賛を得る。
情熱
仕事を先延ばししがち
抽象的

やる気を上げる有効な手段

肯定的なフィードバック
確信や称賛
物事の達成

◆回避フォーカス

保守的なイメージ
安定と信頼を重視する。
やり始めたことは最後までやろうとする。

特徴

損失を抑え、批判を避ける。
自衛
作業の時間を多めに見積もる、期限までにやる
具体的

やる気を上げる有効な手段

否定的なフィードバック
自省
批判

③自身の有無

・自信有無について 自信はどんな人にもあったほうがよい。

自信とは

俺様最強 ×
俺には目標に向かってやり遂げる力がある 〇

タイプ診断

自分の場合

僕は下記のような感じでした。
両極端ではない結果となってしまった。

  • マインドセット
    成長寄り
  • フォーカス
    獲得、回避 5分くらい
  • 自信
    普通より ちょっと下くらい

タイプ診断結果

  • やる気の空回り →必要な能力をつけましょう

  • まじめな見習い →必要な能力をつけましょう

なんと単純明快な解答をいただきました。

さいごに

いろいろと勉強頑張ります(笑)

YoctoでRaspberry Pi 4 64bitのOSイメージを作成する。(動作確認 未)

1.Yocto Project とは

(1)IoTって何?

IoT(Internet of Things)モノのインターネット。 私たちの身近にあるもの(車、自販機、家電製品など)が インターネットと紐づいている仕組みのことです。 モノが通信をしてくれるおかげで、
遠隔で冷蔵庫の中身をチェックできたり、
自販機のドリンクの在庫状況をチェックして、補充作業が効率的になっています。

(2)組込みボードって何?

この説明では、家電製品や、カーナビ、スマートメーターなどの中に入っている、
小型コンピュータのことをこう呼んでおきます。

(3)どんなボードがあるの?

電子工作分野では、
Arduinoや、Raspberry Piが有名でしょうか。
比較的に安価なので、学生さんにも手に入りやすく、
学習や遊びで使えると思います。

産業用だと、


社のボードなどがあります。

そんな各種ボードに対応したOSイメージを このツールひとつで、手軽に作れるというわけですね。

2.Raspberry Pi用のOSイメージを作ってみる

個人でラズパイを持っていない(笑)ので、とりあえず構築までの手順をやってみようと思います。

(1)作業の準備

仮想環境を作ってやります。

  • 環境、スペックなど
    • 容量:80GB  ←(大きい方が良いです)
    • CPU:corei5の2コア分  ←(性能が高い方が良いです)
    • メモリ:4GB ←(大きい方g(ry))

今回は、普段使っているノートPCからやったので、低スペックです。
ビルドはものすごく時間がかかるので、スペックは高い方がいいです。
(実際、上記のリソースを使ってビルドしたら、最小イメージで5時間くらいはかかったと思います。)

f:id:ttokage2233:20200120232356p:plain

  • VMware Workstation Player をダウンロード

https://www.vmware.com/jp/products/workstation-player/workstation-player-evaluation.html

  • Ubuntu16.04をダウンロード

OSはUbuntu16.04を使いました。
https://www.ubuntulinux.jp/News/ubuntu1604-ja-remix

(2)とりあえず、インストール

Ubuntu16.04をインストールしました。 この辺りは、画面の指示通りに進めていっただけなので、割愛します。

f:id:ttokage2233:20200120232524p:plain

(3)リファレンスマニュアルに沿ってYocto導入

下記URLの導入部分を読み、必要なパッケージをインストールします。
Yocto Project Reference Manual

$ sudo apt-get install gawk wget git-core diffstat unzip texinfo gcc-multilib \
     build-essential chrpath socat cpio python python3 python3-pip python3-pexpect \
     xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev \
     pylint3 xterm
$ sudo apt-get install make xsltproc docbook-utils fop dblatex xmlto

(4)Pokyのダウンロード

Yoctoで使われているビルドツールPokyをダウンロードします。

$ git clone git://git.yoctoproject.org/poky

(リビジョン:ecbf203e34484731dcb6acc5e75df79cb86e55dc)

(5)ラズパイ用の必要パッケージをダウンロード

ラズパイのBSP(Board Support Package)

$ git clone https://github.com/agherzan/meta-raspberrypi.git

(リビジョン:e7c856ee7bcfd7878853b55310957f0b9a990fd2)


依存レイヤーのmeta-openembeddedを指定してみたら、
そのレイヤー直下に conf/layer.confが無いらしく、エラーとなりました。
バージョンが古いのだろうか・・・。
$ git clone git://git.openembedded.org/meta-openembedded
これが無くてもビルドは通りました。なのでスキップしておきます。

(6)Yoctoビルド環境の設定

$ source oe-init-build-env

ビルド用のディレクトリ(build)が作成され、 Yoctoビルド用の環境変数なども設定されます。

(7)bblayer.confの編集

先ほどダウンロードしたレイヤー(meta-***)の設定をします。

~/poky/build$ vi conf/bblayers.conf
-----------
~~
  /home/tasky/poky/meta-yocto-bsp \
  /home/tasky/poky/meta-raspberrypi \   ←追加
  "
~~
-----------

(8)local.confの編集

実際にOSイメージを使うターゲットボード(マシン名)を指定します。
マシン名は、各ボードのリファレンスマニュアルに書いてあれば、
すぐに指定できるのですが、見つからない場合は、レイヤー(meta-***)から探します。
docs/layer-contents.md の中身とか、
conf/以下のディレクトリあたりで・・・。

-----------
~/poky$ cd meta-raspberrypi/
~/poky/meta-raspberrypi$ ls conf/machine/
include               raspberrypi0-wifi.conf  raspberrypi3.conf
raspberrypi-cm.conf   raspberrypi0.conf       raspberrypi4-64.conf
raspberrypi-cm3.conf  raspberrypi2.conf       raspberrypi4.conf
raspberrypi.conf      raspberrypi3-64.conf
-----------

ありました。では、今回は raspberrypi4-64をお試しで指定してみます。

~/poky/build$ vi conf/local.conf
-----------
~~
MACHINE ?= "raspberrypi4-64"    ←追加
~~
BB_NUMBER_THREADS = '2'     ←ビルド時のスレッド指定(CPUがマルチコア対応なら2倍の数でよい)
PARALLEL_MAKE = '-j 2'      ←ビルド時に使うスレッドの最大数(CPUがマルチコア対応なら2倍の数でよい)
-----------


↑*スレッド指定の例
使用CPU(4コア、8スレッド)の場合、下記のようにしておくと、ビルドが早いです。
BB_NUMBER_THREADS = '8'
PARALLEL_MAKE = '-j 8'

(9)ビルド

今回は最小構成のOSイメージを作ります。

$ bitbake core-image-minimal

(とても時間がかかる)
(本来なら、ガチガチの高スぺPCを使います(笑))

(10)成果物の確認

うまくビルドができていれば、
ビルドディレクトリ(build)から
tmp/deploy/images/(マシン名) に、作成されているはずです。

実際の確認画面
----------
~/poky/build$ ls tmp/deploy/images/raspberrypi4-64/
Image
Image-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.bin
Image-raspberrypi4-64.bin
at86rf233-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
at86rf233-raspberrypi4-64.dtbo
at86rf233.dtbo
bcm2711-rpi-4-b-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtb
bcm2711-rpi-4-b-raspberrypi4-64.dtb
bcm2711-rpi-4-b.dtb
bcm2835-bootfiles
core-image-minimal-raspberrypi4-64-20200119105629.rootfs.ext3
core-image-minimal-raspberrypi4-64-20200119105629.rootfs.manifest
core-image-minimal-raspberrypi4-64-20200119105629.rootfs.rpi-sdimg
core-image-minimal-raspberrypi4-64-20200119105629.rootfs.tar.bz2
core-image-minimal-raspberrypi4-64-20200119105629.testdata.json
core-image-minimal-raspberrypi4-64.ext3
core-image-minimal-raspberrypi4-64.manifest
core-image-minimal-raspberrypi4-64.rpi-sdimg
core-image-minimal-raspberrypi4-64.tar.bz2
core-image-minimal-raspberrypi4-64.testdata.json
dwc2-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
dwc2-raspberrypi4-64.dtbo
dwc2.dtbo
gpio-key-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
gpio-key-raspberrypi4-64.dtbo
gpio-key.dtbo
hifiberry-amp-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
hifiberry-amp-raspberrypi4-64.dtbo
hifiberry-amp.dtbo
hifiberry-dac-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
hifiberry-dac-raspberrypi4-64.dtbo
hifiberry-dac.dtbo
hifiberry-dacplus-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
hifiberry-dacplus-raspberrypi4-64.dtbo
hifiberry-dacplus.dtbo
hifiberry-digi-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
hifiberry-digi-raspberrypi4-64.dtbo
hifiberry-digi.dtbo
i2c-rtc-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
i2c-rtc-raspberrypi4-64.dtbo
i2c-rtc.dtbo
iqaudio-dac-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
iqaudio-dac-raspberrypi4-64.dtbo
iqaudio-dac.dtbo
iqaudio-dacplus-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
iqaudio-dacplus-raspberrypi4-64.dtbo
iqaudio-dacplus.dtbo
mcp2515-can0-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
mcp2515-can0-raspberrypi4-64.dtbo
mcp2515-can0.dtbo
modules-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.tgz
modules-raspberrypi4-64.tgz
pi3-disable-bt-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
pi3-disable-bt-raspberrypi4-64.dtbo
pi3-disable-bt.dtbo
pi3-miniuart-bt-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
pi3-miniuart-bt-raspberrypi4-64.dtbo
pi3-miniuart-bt.dtbo
pitft22-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
pitft22-raspberrypi4-64.dtbo
pitft22.dtbo
pitft28-capacitive-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
pitft28-capacitive-raspberrypi4-64.dtbo
pitft28-capacitive.dtbo
pitft28-resistive-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
pitft28-resistive-raspberrypi4-64.dtbo
pitft28-resistive.dtbo
pitft35-resistive-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
pitft35-resistive-raspberrypi4-64.dtbo
pitft35-resistive.dtbo
pps-gpio-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
pps-gpio-raspberrypi4-64.dtbo
pps-gpio.dtbo
rpi-ft5406-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
rpi-ft5406-raspberrypi4-64.dtbo
rpi-ft5406.dtbo
rpi-poe-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
rpi-poe-raspberrypi4-64.dtbo
rpi-poe.dtbo
vc4-fkms-v3d-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
vc4-fkms-v3d-raspberrypi4-64.dtbo
vc4-fkms-v3d.dtbo
vc4-kms-v3d-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
vc4-kms-v3d-raspberrypi4-64.dtbo
vc4-kms-v3d.dtbo
w1-gpio-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
w1-gpio-pullup-1-4.19.93+git0+3fdcc814c5-r0-raspberrypi4-64-20200119105629.dtbo
w1-gpio-pullup-raspberrypi4-64.dtbo
w1-gpio-pullup.dtbo
w1-gpio-raspberrypi4-64.dtbo
w1-gpio.dtbo
----------

生成されていました。

(11)ブート用SDカードの作成(動作未確認)

動作確認ができないため、以下エアプです。
参考程度にしてもらえればと思います。

出来上がったOSイメージを、SDカードに書き込みます。

  • SDカードの確認 SDカード挿入後
$ dmesg | tail
$ mount

などのコマンドでSDカードが認識されているか確認します。
(SDカード認識例:/dev/sdb)

(もしマウントされていたら、アンマウントしておきます)

$ sudo umount /dev/sdb*
  • OSイメージの書き込み
~/poky/build/$ cd tmp/deploy/images/raspberrypi4-64
$ sudo dd if=core-image-minimal-raspberrypi4-64.rpi-sdimg of=/dev/sdb bs=1M

3.まとめ

Yoctoはカスタムlinuxが作れるツールです。
全体のOSイメージの構築の流れを紹介しました。

4.参考URL

  • Yoctoリファレンスマニュアル

https://www.yoctoproject.org/docs/latest/ref-manual/ref-manual.html

  • ラズパイBSP

https://git.yoctoproject.org/cgit/cgit.cgi/meta-raspberrypi/about/

  • Yoctoのクイックスタートガイド

https://www.yoctoproject.org/docs/2.4.2/yocto-project-qs/yocto-project-qs.html