Upgrade to Pro — share decks privately, control downloads, hide ads and more …

mruby on IoT devices.

Y_uuu
February 18, 2023

mruby on IoT devices.

Fukuoka RubyistKaigi 03
2023.02.18 Sat. 13:30-13:55
https://regional.rubykaigi.org/fukuoka03/index.html

Y_uuu

February 18, 2023
Tweet

More Decks by Y_uuu

Other Decks in Programming

Transcript

  1. 2023-02-18(Sat) 岡嵜雄平
    mruby on IoT devices.

    View Slide

  2. 自己紹介

    View Slide

  3. 岡嵜雄平 @Y_uuu


    株式会社Fusic IoTクラウドエンジニア


    フィヨルドブートキャンプ メンター

    View Slide

  4. 本日のお話
    • mrubyとIoT


    • mruby-esp32


    • 課題1: ESP-IDFの最新バージョン(v5.0)に追従できていない


    • 課題2: MQTT通信クライアントがない


    • まとめ
    4

    View Slide

  5. mrubyとIoT

    View Slide

  6. mruby
    • 組込みシステムをターゲットに開発されたRubyの処理系


    • 現在もMatzを中心に開発が続けられている


    • mrubyをさらに軽量化したmruby/cというOSSも存在する
    6

    View Slide

  7. • IoT開発(特にPoCフェーズ)で頻発するチューニングに柔軟に対応しやすい


    • Web/クラウドと同じRubyで開発ができる
    IoT開発におけるmrubyの可能性
    7
    クラウド
    デバイス
    センサー
    収集 加工 分析 可視化
    インターネット
    センサーの値を送信
    7
    別のセンサーを


    使いたい
    送信データの


    形を変えたい
    送信周期を


    変えたい
    機能を拡張


    したい

    View Slide

  8. mruby-esp32

    View Slide

  9. ESP32
    • Espressif Systems社によって開発されたマイクロコントローラ(マイコン)


    • 低消費電力かつWi-Fi・Bluetoothも内蔵しているためIoTとの親和性が高い


    • M5Stackに搭載されているマイコンもESP32
    9
    https://ja.wikipedia.org/wiki/ESP32

    View Slide

  10. ESP32-DevKitC
    • ESP32を搭載した評価基盤


    • 1600円で買える(送料・手数料は別)


    • mrubyを動かすために十分なスペック(RAM: 512KB, ROM: 4MB)
    10

    View Slide

  11. mruby-esp32
    • ESP32上でmrubyを動かすためのOSSプロジェクト


    • ESP-IDFというフレームワークを使ってmrubyをコンパイル・リンクしている
    11
    ESP-IDF
    Project
    Component


    Main
    Component


    mruby
    Toolchain
    mruby-esp32.bin
    コンパイル・リンク

    View Slide

  12. mruby-esp32
    • binファイルをROMに書き込むことで起動


    • FreeRTOS(組込み向けのリアルタイムOS)上でmrubyが動作
    12
    ESP-IDF
    Project
    Component


    Main
    Component


    mruby
    Toolchain
    mruby-esp32.bin
    ESP32-DevKitC
    FreeRTOS
    アプリケーション
    mruby
    MrubyTask
    コンパイル・リンク
    アップロード


    (ROMに書き込み)
    Library

    View Slide

  13. 使い方1. ESP-IDFをインストール
    • インストール手順はESP-IDF Programming Guide > Get Startedを参照
    13
    https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html

    View Slide

  14. 使い方2. mruby-esp32をgit clone
    • mrubyがSubmoduleとなっているので注意
    14
    https://github.com/mruby-esp32/mruby-esp32

    View Slide

  15. 使い方3. Rubyのプログラムを書く
    • main/spiffs/main.rb に任意のプログラムを記述します
    15

    View Slide

  16. 使い方4. ビルド
    • Idf.py build コマンドでビルドします(初回は1分ほどかかります)
    16

    View Slide

  17. 使い方5. デバイスとPCを接続
    • /dev/tty.usbserial-xxx のようなデバイスファイル(PORT)を確認
    17

    View Slide

  18. 使い方6. 書き込み・起動
    • idf.py -p (PORT) flash monitor コマンドで書き込み・起動します
    18
    LEDと反対側のボタンを押して、
    モードを切り替える


    実機での出力を


    シリアル通信で確認

    View Slide

  19. 応用編: AWS IoT CoreにMQTTSでPublish
    • わずか10行のコードでAWSにデータを送信できます
    19

    View Slide

  20. 簡単にデバイス上でmrubyを動かせる🎉
    • 「簡単に」というイメージを、今日はぜひ持ち帰ってください


    • ここから先は諸々の課題が解決する前(2ヶ月前)に時を戻します…
    20

    View Slide

  21. IoTでの活用を想定したとき、2つの課題に直面
    1. mruby-esp32がESP-IDFの最新バージョン(v5.0)に追従できていない


    • デバイスのライフタイムを考えると、最新バージョンに対応したい


    2. mruby-esp32で使用できるMQTT通信クライアントがない


    • IoTシステムにおいてよく使われるプロトコルであり、必要不可欠
    21

    View Slide

  22. 2つの課題をどう解決したか?
    • これからお話していきます
    22

    View Slide

  23. 課題1: ESP-IDFの最新バージョン(v5.0)に


    追従できていない

    View Slide

  24. プロジェクトの構成を理解する
    • 2つのコンポーネント、それぞれにcomponent.mk (Makefile)が配置


    • Mrubyのコンポーネントの中にmrubyのソース一式がある
    24
    mruby_component
    main_component
    mrubyのソースコード一式


    (サブモジュール)

    View Slide

  25. ESP-IDF v5.0を使ってビルドしてみる
    • いろいろな問題が起こる💣
    25

    View Slide

  26. • project.mkがない、というエラーが出力される
    問題1: ビルドが始まらない
    26

    View Slide

  27. • ビルドシステムがMake→cmakeに変わっている


    • v4.4のドキュメントでは存在していたMakeへの言及がv5.0では消滅
    問題1: ビルドが始まらない
    27
    https://docs.espressif.com/projects/esp-idf/en/v4.4.4/esp32/api-guides/build-system.html https://docs.espressif.com/projects/esp-idf/en/v5.0/esp32/api-guides/build-system.html
    v5.0のドキュメントには


    Makeへの言及がない

    View Slide

  28. 問題1: ビルドが始まらない
    • ESP-IDFの他OSSやドキュメントを参考にCMakeLists.txtを記述


    • Mrubyのビルドはカスタムコマンドとしてrakeを実行
    28
    https://github.com/mruby-esp32/mruby-esp32/pull/27
    カスタムコマンドとして


    mrubyのrakeを実行

    View Slide

  29. 問題2: Legacy event loopでコンパイルエラー
    • mruby-esp32-wifiでコンパイルエラーが発生
    29

    View Slide

  30. 問題2: Legacy event loopでコンパイルエラー
    • Wi-Fi接続やIP取得といったイベントを検知するために使用


    • v5.0ではLegacy event loopが消滅している
    30
    V5.0にLegacy event loopの


    ドキュメントは存在しない
    https://docs.espressif.com/projects/esp-idf/en/release-v4.4/esp32/api-reference/system/esp_event_legacy.html

    View Slide

  31. 問題2: Legacy event loopでコンパイルエラー
    • 後継のEvent Loop Libraryを使って処理を置き換える
    31
    https://github.com/mruby-esp32/mruby-esp32-wifi/pull/3

    View Slide

  32. 問題3: mrubyのコンパイルでたくさんエラーが起こる
    • mrbgemでincludeしている、ESP-IDFが提供するヘッダファイルでエラー
    32

    View Slide

  33. 問題3: mrubyのコンパイルでたくさんエラーが起こる
    • ESP-IDFの通常のプロジェクトをコンパイルするときとの

    オプションの違いを見比べる


    • 通常のプロジェクトでは-std=gnu17というオプションが付いている
    33
    Project
    Component


    Main
    Component


    mruby
    Toolchain
    ESP-IDFでビルド


    C17
    Rakeでビルド


    C99
    Toolchain内のソースコードが
    C17を前提としている
    esp_macros.h

    View Slide

  34. 問題3: mrubyのコンパイルでたくさんエラーが起こる
    • mrubyもC17でビルドするよう、オプションを付けることで解決
    34
    https://github.com/mruby-esp32/mruby-esp32/pull/27
    オプションを追加

    View Slide

  35. 問題4: Error: app partition is too small for 〜 が出る
    • ビルドの終盤でエラーが発生
    35

    View Slide

  36. 問題4: Error: app partition is too small for 〜 が出る
    • パーティション=ROMの構成情報
    36
    ブートローダー
    パーティションテーブル
    nvs: 24KB
    phy_init: 4KB
    factory: 1MB
    空き
    0x00000000
    0x00001000
    0x00009000
    0x0000f000
    0x00010000
    0x00110000

    View Slide

  37. 問題4: Error: app partition is too small for 〜 が出る
    • デフォルトのパーティションテーブルではapp領域は1MBしかない
    37
    ブートローダー
    パーティションテーブル
    nvs: 24KB
    phy_init: 4KB
    factory: 1MB
    空き
    ここがapp領域
    0x00000000
    0x00001000
    0x00009000
    0x0000f000
    0x00010000
    0x00110000

    View Slide

  38. 問題4: Error: app partition is too small for 〜 が出る
    • パーティションテーブルをカスタマイズして1.5MBまで拡げて対策
    38
    ブートローダー
    パーティションテーブル
    nvs: 24KB
    phy_init: 4KB
    factory: 1.5MB
    空き
    0x00000000
    0x00001000
    0x00009000
    0x0000f000
    0x00010000
    0x00180000
    ここには後々

    ファイルシステムを構築予定
    一部のESP32はROMが2MBしか

    ないため、全体を2MB以内としたい
    https://github.com/mruby-esp32/mruby-esp32/pull/30

    View Slide

  39. ESP-IDF v5.0でビルド→起動までこぎ着けた🎉
    • 実際には1つの問題に数日を要することもあり、それなりに大変だった
    39

    View Slide

  40. ポーティングのポイント
    • 組込みソフトウェアがどういった仕組みで動作するか前提知識をつけること


    • MCU/ROM/RAMといったH/W構成要素を理解する


    • リアルタイムOS(ex: FreeRTOS)について知る


    • エラーメッセージから何が起こっているのか正しく理解すること


    • Webとは違い、H/Wが関連するエラーもしばしば起こるので注意
    40

    View Slide

  41. ポーティングのポイント
    • 開発環境(ex: ESP-IDF)のドキュメントをよく読むこと


    • バージョンごとの変遷を追う


    • カスタマイズできること・できないことを把握する


    • 情報が集まるコミュニティ(ex: ESP-IDFのissues)を見つける


    • Webの世界に比べて、情報は少ない


    • 類似する問題を探す・質問する
    41

    View Slide

  42. 課題2: MQTT通信クライアントがない

    View Slide

  43. MQTT
    • TCP/IPによるPub/Sub型データ配信を行う、軽量データ配信プロトコル


    • ヘッダーサイズが最小2byte、プロトコルシーケンスがシンプル


    • 1つのクライアントがPublisherとSubscriberを兼ねることもできる
    43
    Broker
    Publisher
    Publisher
    Subscriber
    Subscriber

    View Slide

  44. ESP-MQTT
    • ESP32上で動作するMQTTクライアント


    • これをラッピングしたmrbgemを作れば良い
    44
    https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/protocols/mqtt.html

    View Slide

  45. 参考: mrbgem
    • RubyでいうところのRubygemにあたる、mrubyの拡張ライブラリ


    • RubyまたはC言語を用いて実装できる


    • 今回はESP-IDFが提供するAPIを利用したいのでC言語で実装
    45
    アプリケーション
    mruby
    MrubyTask wifi mqtt
    .c
    ・・・
    FreeRTOS
    Library
    .c mrbgems

    View Slide

  46. クラス設計(mruby-mqttを参考)
    • 当初、mruby-mqttを元に検討した


    • 全体的に非同期的であり、コールバックを多用する仕様に懸念
    46
    https://github.com/hiroeorz/mruby-mqtt
    接続時や送受信時に


    yieldされる

    View Slide

  47. • on_connect等によるコールバックが別タスク(別コンテキスト)となる


    • mruby VMはシングルタスクでの動作が前提のため、避けたい
    クラス設計(mruby-mqttを参考)
    47
    Rubyアプリケーション
    connect
    mruby-esp32-mqtt
    on_connect
    ESP-MQTT
    mruby VM
    connect
    Main Task
    MQTT Task
    block
    event handler
    別のタスク


    (別コンテキスト)


    View Slide

  48. クラス設計(ruby-mqttを参考)
    • ruby-mqttの設計を参考にした


    • いずれのメソッドも同期的であり、処理が完了してから次の処理へ進む
    48
    https://github.com/njh/ruby-mqtt
    connect, getどちらも


    同期的

    View Slide

  49. • シングルタスクでmruby VMを動かす


    • 別タスクからのイベントを受信後、元のメソッドをreturn
    クラス設計(ruby-mqttを参考)
    49
    Rubyアプリケーション
    connect
    mruby-esp32-mqtt
    ESP-MQTT
    queue
    connect
    Main Task
    MQTT Task
    event handler
    wait_for_event
    イベントの情報を


    エンキュー
    同期的にreturn

    View Slide

  50. mrb_mruby_esp32_mqtt_gem_init
    50
    • mrbgemのお作法に則って実装
    https://github.com/mruby-esp32/mruby-esp32-mqtt/blob/master/src/mrb_esp32_mqtt.c
    MQTTクラスを定義
    各種メソッドを定義

    View Slide

  51. mrb_mqtt_client_connect
    • 接続後に mqtt_wait_for_event で接続完了を待っている
    51
    https://github.com/mruby-esp32/mruby-esp32-mqtt/blob/master/src/mrb_esp32_mqtt.c
    Queueにイベントが


    来るまで待つ
    MQTT接続開始

    View Slide

  52. Rubyアプリケーション
    • わずか10行足らずで、MQTT Publish可能に🎉
    52
    https://github.com/mruby-esp32/mruby-esp32/blob/master/main/examples/mqtt_publish.rb

    View Slide

  53. mruby-esp32/mruby-esp32-mqtt として公開中
    • mruby-esp32のOrganization配下で公開 🎉
    53
    https://github.com/mruby-esp32/mruby-esp32-mqtt

    View Slide

  54. まとめ

    View Slide

  55. 所感
    • デバイス上でmrubyを動かすのは一苦労


    • 一度動いてしまえば使い慣れた言語でデバイスを制御できる


    • 比較的コントリビュートしやすい


    • UART通信, SPI通信, タイマー, RTCといったAPIをmrbgem化


    • ドキュメントの整備
    55

    View Slide

  56. おわりに
    • 今日の話を聞いて「デバイス難しそう…」と感じた人がいるかもしれません


    • 実際、Webシステムの開発とは別のハードルがたくさんあります
    56

    View Slide

  57. おわりに
    • 少なくとも、今日話した内容は全て解決済みなのでご安心ください


    • ぜひお手元にESP32-DevKitCをご用意の上、mrubyを動かしてみてください
    57

    View Slide

  58. ご清聴ありがとうございました

    View Slide

  59. Appendix

    View Slide

  60. 参考: IoTシステム
    • モノのインターネット


    • よくある事例: センサーの値をクラウドに送信して可視化・分析
    60
    クラウド
    デバイス
    センサー
    収集 加工 分析 可視化
    インターネット
    センサーの値を送信

    View Slide

  61. 参考: リアルタイム性とmruby
    • IoTシステムで求められるリアルタイム性がそこまで高くない


    • 組込みシステムの中でも、mrubyが敬遠される要素が少ない
    61
    時間の流れ
    タスクA タスクB
    イベントが発生
    レイテンシ
    タスクA
    イベントが発生
    レイテンシ
    タスクB
    ハードリアルタイム


    例: 自動車のブレーキ、緊急停止装置
    ソフトリアルタイム


    例: GUI、環境測定、データ配信
    mrubyはソフトリアルタイム
    処理期限

    View Slide

  62. • FreeRTOSにおけるタスク間でのデータ送受信や同期を行う仕組みの一つ


    • 別タスクに対してデータを送信できる


    • 送受信が完了するまで、タスクを待ち状態にできる
    参考: FreeRTOS Queue API
    62
    queue sender_task
    reveiver_task
    Queueにメッセージが


    来るまで待ち状態に


    View Slide

  63. 参考: MQTT Publishの動作確認
    • mosquittoというツールでSubscribeし、Publishできていることを確認
    63

    View Slide