Spresense Header CodeSpresense Header Code

Spresense - エッジコンピューティングを低消費電力で

Spresense で乾電池でも動く本格的なエッジコンピューティングを体験してみませんか?

Spresense Arduino Library の使い方

こちらは旧ドキュメントです。ドキュメントは以下のサイトに移行されました。 https://developer.sony.com/develop/spresense/docs/arduino_set_up_ja.html

この章では、Spresense Arduino Library の入手から、LEDを光らせる簡単なアプリケーションの開発まで習得することができます。 

Arduino では、アプリケーションプログラムをスケッチと呼びます。

1. Spresense Arduino Library のインストールの仕方

1.1. サポートしているプラットフォーム

Spresense Arduino Library は以下のプラットフォームで動作を確認しています。

  • Windows 8.1/10

  • 64bit版 Linux Ubuntu 16.04

  • Mac OSX 10.12 Sierra

32bit版 Linux には対応していません。

1.2. 事前準備

Arduino IDE バージョンは、1.8.x 以降を使用してください。
Windows 10 環境では、上記 URL より v10.1.3 をダウンロードしてお使いください。 最新ドライバ (v10.1.4) を使用した場合、ターミナル起動直後の送信データが欠落する等の問題が発生することがあります。
  • 64bit版 Linux Ubuntu 16.04 ではシリアルポートをArduino IDEで利用できるように次の設定をします。

    1. Ubuntuのユーザを dialout のグループに追加します。

      $ sudo adduser <user-name> dialout
    2. Ubuntuを再起動します。

    3. Spresense ボードのUSBを接続し直したら完了です。

接続し直すことでこの設定が反映されます。
この設定を行わない場合Arduinoで作成したソフトウェアをSpresense ボードにアップロードできません。

1.3. Spresense Arduino board package のインストール

Spresense Arduino board package のインストールの仕方について記述しています。

この方法以外にも git clone やダウンロードしたパッケージをマニュアルでインストールする方法もあります。
  1. Arduino IDEを起動します。

  2. 環境設定を開きます。

    arduino borad manager preference ja
    図 1. Arduino IDE環境設定
  3. 追加のボードマネージャのURLに下記URLを入力し OK をクリックします。

    https://github.com/sonydevworld/spresense-arduino-compatible/releases/download/generic/package_spresense_index.json
    arduino borad manager add json url ja
    図 2. ボードマネージャ jsonファイル指定
  4. ツールボードボードマネージャ を選択してボードマネージャを開きます。

    tutorial arduino open boardmanager ja
    図 3. ボードマネージャの開き方
  5. Spresense を検索し インストール をクリックすればインストールは完了します。

    インストール中約 150MB のダウンロードを行いますので、パケット定額サービスなどの環境でインストールを行いください。
    パッケージ検索にてエラーが発生する場合は ファイル > 環境設定 > ネットワーク でプロキシの設定をご確認ください。
    tutorial arduino boardmanager spresense install ja
    図 4. Spresenseを検索&インストール
    ボードマネージャでは表示されるパッケージを一度クリックしないとインストールボタンは現れません。

2. Spresense Arduino Library のプログラミング環境の設定

2.1. USBシリアルポートの確認

事前準備を参照の上USBドライバをインストール後、USBケーブルをSpresenseメインボードに接続してください。

下の画像のように青いLEDが点灯されていればPCと接続されています。

spresense musb connect
図 5. Connection to the Spresense main board USB connector with power LED on

プラットフォーム毎のUSBポートの確認方法は下記をご確認ください。

2.1.1. Windows上でのUSBシリアルドライバの確認

  1. デバイスマネージャー を開きます。

  2. Silicon Labs CP210x USB to UART Bridge のCOMポートの番号を確認します。

    tutorial arduino windows device manager find port
    図 6. デバイスマネージャーでCOMポートを確認

    この例の場合 COM9 に接続されていることになります。

    Spresense メインボードは Silicon Labs CP210x USB to UART Bridge としてデバイスマネージャに表示されます。

2.1.2. Ubuntu 64bit上でのUSBシリアルドライバの確認

Spresense ボードが接続されているCOMポートを探し出します。

  1. ターミナルを開きます。

  2. ターミナル上で次のコマンドを入力してください。

    $ dmesg | grep "cp21.*attached"
    [12220.625979] usb 1-1: cp210x converter now attached to ttyUSB0

    この例の場合 ttyUSB0 に接続されていることになります。

2.1.3. Mac OSX上でのUSBシリアルドライバの確認

Spresense ボードが接続されているCOMポートを探し出します。

  1. ターミナルを開きます。

  2. ターミナル上で次のコマンドを入力してください。

    $ ls /dev/{tty,cu}.*
    /dev/cu.SLAB_USBtoUART  /dev/tty.SLAB_USBtoUART

    この例の場合 cu.SLAB_USBtoUART に接続されていることになります。

2.2. Spresenseローダーのインストール

ボードを使う前に、ローダーをボードにインストールする必要があります。以下の手順にしたがって、ローダーをインストールしてください。

Spresense Arduino board package のインストールが完了していることが必要です。

Spresense ボードは出荷状態ではローダーはインストールされていません。
Spresense メインボードとPCが micro USB ケーブルで接続されていることが必要です。
  1. Arduino IDEを起動します。

  2. Spresense ボードを ツール > ボード> Spresense の順に選択します。

    tutorial arduino boardsmanager menu ja
    図 7. Spresense ボードの選択
  3. USBケーブルをSpresense メインボードUSBコネクタに接続し、 ツール > シリアルポート で、COMポートを選択します。

    Spresense ボードが接続されている COMポートを選択してください。

    接続されているCOMポートが分からない場合は、 USBシリアルポートの確認を参照してください。

    tutorial arduino select port ja
    図 8. Spresense ボードに接続されているCOMポートの選択
  4. ツール > 書き込み装置Spresense Firmware Updater を選択します。

    tutorial arduino select programmer ja
    図 9. Spresense Firmware Updater の選択
  5. ツール > ブートローダーを書き込む を選択します。これでブートローダーとバイナリライブラリがインストールされます。

    tutorial arduino tools menu do burn ja
    図 10. 'ブートローダーを書き込む' の選択
  6. End User License Agreement のダイアログ内にあるライセンス文を確認し、 I Accept the terms in the license agreement にチェックを付けたのち OK ボタンをクリックしてください。

    tutorial arduino eula dialog
    図 11. End User License Agreementのダイアログ
    Spresenseのローダーを利用するためにはEnd User License Agreementの同意が必要です。
    次回以降ボードマネージャの更新をしない限り再度表示されることはありません。
  7. 次のメッセージがArduino IDE(下記画像の赤枠)に表示されればインストール完了です。

    ブートローダの書き込みが完了しました。
    
    updater# Restarting the board ...
    reboot
    tutorial arduino fw update done ja
    図 12. インストール完了時に Arduino IDE に表示されるメッセージ

3. Spresense でLEDのスケッチ動かしてみる

以上でSpresense Arduino board package の準備が整いました。環境が正しくセットアップされたか確認するために、LEDサンプルスケッチを動かしてみます。

  1. 以下のLEDサンプルスケッチをArduino IDE にコピーしてください。

    void setup() {
        pinMode(LED0, OUTPUT);
        pinMode(LED1, OUTPUT);
        pinMode(LED2, OUTPUT);
        pinMode(LED3, OUTPUT);
    }
    
    void loop() {
        digitalWrite(LED0, HIGH);
        delay(100);
        digitalWrite(LED1, HIGH);
        delay(100);
        digitalWrite(LED2, HIGH);
        delay(100);
        digitalWrite(LED3, HIGH);
        delay(1000);
    
        digitalWrite(LED0, LOW);
        delay(100);
        digitalWrite(LED1, LOW);
        delay(100);
        digitalWrite(LED2, LOW);
        delay(100);
        digitalWrite(LED3, LOW);
        delay(1000);
    }
  2. Upload ボタンをクリックして、スケッチのコンパイルとアップロードを行ってください。

    tutorial arduino upload ja
    図 13. Upload のクリック
  3. スケッチのアップロード完了するまで待ちます。

    tutorial arduino sketch done uploading ja
    図 14. アップロードの正常完了時のメッセージ
  4. スケッチが動作するか確認します。正常にアップロードされていると、Spresenseボード上のLEDが点滅をします。

    スケッチのアップロードが完了すると自動でSpresenseボードがリセットされます。
  5. 以上で環境が正しくセットアップできました。

4. Spresense GPS を動かしてみる

こちらは旧ドキュメントです。ドキュメントは以下のサイトに移行されました。 https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_tutorial_gps

このチュートリアルではサンプルスケッチをベースに Spresense GPS 機能を使った簡単なアプリケーションや、 サンプルをカスタマイズして機能を追加・拡張する方法について解説します。

4.1. GPS トラッカーを使ってみよう

4.1.1. 概要

GNSS ライブラリの Examples にある GPS トラッカーのサンプルスケッチ gnss_tracker を動かしてみます。
このスケッチは、いわゆる GPS データロガーと呼ばれるもので、 定期的に GPS から取得した位置情報を SD カードに記録していきます。 SD カードに保存されたファイルを後から取り出し、パソコン等の専用ツールを使うことによって、 移動の軌跡を地図上に重ねて閲覧表示することができます。

4.1.2. 動作環境

本スケッチの動作に必要な環境を以下に示します。

  • Spresense メインボード

  • Spresense 拡張ボード

  • microSD カード

4.1.3. 動作手順

Spresense のメインボードと拡張ボードを接続し、拡張ボードに microSD カードを挿入してください。
Arduino IDE メニューから File → Examples → GNSS → gnss_tracker (ファイル → スケッチ例 → GNSS → gnss_tracker) スケッチを開きます。

gnss tracker1
gnss tracker2

このスケッチを Spresense ボードに書き込みます。

gnss tracker3

シリアルモニタを開くと、はじめにアプリケーションの設定情報を出力した後に、測位結果の出力を開始します。

gnss tracker4

4.1.4. 動作仕様

電源が供給されるとまず初めに microSD カード内の tracker.ini ファイルに書かれた設定を読み込みます。 このファイルに書かれた設定にしたがってアプリケーションの初期設定をした後に、GPS 測位動作を開始します。 動作中は、メインボード上の LED によってアプリケーションの動作状態を表します。

  • LED 仕様

    アプリケーションの動作が開始するときに 4 つの全ての LED が一回だけ点滅します。
    測位停止中は 全ての LED が消灯します。個別の LED に関する動作仕様は以下の通りです。

    LED 説明

    LED0

    測位動作中に点灯/消灯を繰り返します

    LED1

    現在の位置情報が取得(FIX)できたら点灯します

    LED2

    ファイルアクセス中に点灯します

    LED3

    microSD カードにアクセスできないなど、何かしらのエラーが発生したときに点灯します

  • microSD カード内のファイル構成

    microSD カード内のファイル構成を以下に示します。ファイルが存在しない場合は、プログラム内でファイルを新規に作成するので、事前にファイルを用意しておく必要はありません。

    ファイル名 説明

    tracker.ini

    アプリケーションの設定情報が書かれたテキストファイルです。各設定値については後述します。このファイルが存在しないときは、デフォルトの設定値をもつファイルが新規に作成されます。

    index.ini

    インデックス番号が書かれたテキストファイルです。この番号は GPS データ出力先のファイル名を表します。例えば “00000018” と書かれている場合は、ファイル名 “00000018.txt” に GPS データを出力します。繰り返し動作させたときに既存のファイルを上書きしないように、この数字は 1 ずつインクリメントされていきます。ファイルが存在しない場合は、“00000001” と書かれた新規ファイルが作成されます。

    00000001.txt
    00000002.txt
      :

    GPS データが書き込まれるテキストファイルです。このファイルにはNMEA 0183 フォーマットの GPGGA センテンスが格納されます。 ユーザはこのファイルをパソコン等に取り込んで GPS トラッキングデータを生成します。

  • tracker.ini 設定情報

    ここで定義される設定パラメータを変更することでアプリケーションの動作を切り替えることができます。デフォルトのままでも動作するため、まず動かしてみるという場合はここを読み飛ばして頂いて構いません。

    変数 説明 設定例

    SatelliteSystem

    (GPS/GLONASS/SBAS/QZSS_L1CA/QZSS_L1S)
    衛星システム(の組み合わせ)を下記から選択します。
    GPS+GLONASS+QZSS_L1CA
    GPS+QZSS_L1CA+QZSS_L1S
    GPS+QZSS_L1CA
    GPS+GLONASS
    GLONASS
    GPS+SBAS
    GPS

    SatelliteSystem=GPS+GLONASS+QZSS_L1CA

    NmeaOutUart

    (TRUE/FALSE)
    NMEA 出力をシリアルモニタに表示するかどうかを選択します。

    NmeaOutUart=TRUE

    NmeaOutFile

    (TRUE/FALSE)
    NMEA 出力をファイルに保存するかどうかを選択します。ここは TRUE を指定してください。

    NmeaOutFile=TRUE

    BinaryOut

    (TRUE/FALSE)
    GNSSバイナリデータを保存するかどうかを選択します。通常、FALSE のままで構いません。

    BinaryOut=FALSE

    IntervalSec

    (1-300)
    測位間隔[秒]を設定します。

    IntervalSec=1

    ActiveSec

    (60-300)
    測位の有効期間[秒]を設定します。ActiveSec秒間だけ測位した後に、SleepSec秒間は測位を停止する、という動作を周期的に繰り返します。

    ActiveSec=60

    SleepSec

    (0-240)
    測位を停止する期間[秒]を設定します。ActiveSec秒間だけ測位した後に、SleepSec秒間は測位を停止する、という動作を周期的に繰り返します。Sleep 期間を設けず、常時測位し続ける場合は 0 を指定してください。

    SleepSec=240

    UartDebugMessage

    (NONE/ERROR/WARNING/INFO)
    シリアルモニタへ出力するデバッグレベルを設定します。

    UartDebugMessage=NONE

4.1.5. GPS ロガーデータの確認手順

GPS ロガーデータを確認する方法は様々ありますが、ここでは NMEA を KML 形式へ変換して、Google Earth を使って地図上に表示します。

  • Google Earth のインストール

    Google Earthのダウンロードページから Google Earth プロをダウンロードしてインストールしてください。

  • NMEA から KML/KMZ へ変換する

    microSD カード上に保存された 00000001.txt ~ 99999999.txt ファイルの中身は、NMEA フォーマット (GPGGA センテンスのみ) で書かれています。これを Google Earth で扱うことができる KML/KMZ 形式へ変換します。変換元のデータが複数のテキストファイルに分かれている場合は、ファイルを結合して一つのファイルにしてください。

    1. https://www.h-schmidt.net/NMEA/ を開く

    2. “ファイルを選択” に入力ファイルを指定して “送信” ボタンを押す

    3. KML に変換されたファイルをダウンロードすることができます

      gnss nmea2kml1
      gnss nmea2kml2
      他にも https://www.gpsvisualizer.com サイトでも Google Earth やその他のファイルフォーマットへ変換することができます。また、Webサイト上で変換するのではなく、NMEA to KMZ Utility など、PC 上で動作する変換ツールも世の中に各種あります。
  • KML ファイルを Google Earth で開く

    以下のように移動した軌跡が地図上にマッピングされ表示されます。

    gnss google earth

ここではサンプルコードをそのまま動作させる方法について説明しました。

以降の章で GPS トラッカーをカスタマイズして使用する応用編について解説していく予定です。

4.2. GPS トラッカーをメインボードだけで動かす

4.2.1. 概要

前章では、GPS トラッカーのサンプルスケッチ gnss_tracker.ino をそのまま動かしてみました。このサンプルは GPS ロガーデータを microSD カードに保存していましたが、これをメインボード上の Flash メモリに保存するように変更します。メインボードのみを使ってより小型で省電力な GPS トラッカーに改造してみます。

4.2.2. 動作環境

本スケッチの動作に必要な環境を以下に示します。

  • Spresense メインボード

4.2.3. 変更手順

gnss_tracker.ino のスケッチを開きます。

gnss tracker1
gnss tracker2

Arduino IDE メニューから File → Save as…​ (ファイル → 名前を付けて保存) を選択して、スケッチを任意のフォルダに保存します。サンプルスケッチがコピーされて編集が可能になります。

gnss tracker5

gnss_file.cpp を開いて、以下の変更を行います。

  • #include <Flash.h> 行の追加

  • SDClass theSD; の削除

  • “theSD” → “Flash” へ一括置換

    • Flash を使用するように変更します。Flash ライブラリは SD と同一のインターフェース構成になっているのでオブジェクト名を変更するだけで使用可能です。

    • 参考までに変更例を以下に示します。

      gnss tracker7

4.2.4. 動作手順

動作手順は基本的に SD の場合と同じです。さきほど編集したスケッチを Spresense ボードに書き込んで実行してください。

4.2.5. GPS ロガーデータの確認手順

Flash メモリに保存された結果を取り出す方法はいくつかあります。(ここで紹介する方法以外にも Add-on ボードなどを利用してネットワークを介してファイルを転送する方法もあります)

  • ファイルダンプする方法

    GPS ロガーデータはテキストファイルとして Flash 内に保存されています。中身をシリアルターミナルにダンプし、その表示結果をファイルとして保存します。 とても原始的な方法ですが、手っ取り早く簡単に行うことができます。

    Arduino IDE のシリアルモニタにはシリアル表示結果をファイルに保存する機能が無いため、TeraTerm や minicom といった別のターミナルを使用することを推奨します。
    1. nuttx_shell スケッチをダウンロードしてください。

      スケッチを書き込んで実行すると、シリアルターミナルに NuttShell nsh> プロンプトが表示されます。

    2. ls コマンドで Flash 内のファイルリストを確認します。

      nsh> ls -l /mnt/spif
      gnss tracker8
    3. 対象となるログファイルを cat コマンドで表示します。
      コマンド実行前にログ結果をファイルに保存するように設定しておいてください。

      nsh> cat /mnt/spif/00000003.txt
      gnss tracker9

      GPS ロガーデータを取り出すことができました。
      Flash 内のファイルが不要になれば rm コマンドで削除することができます。

      nsh> rm /mnt/spif/00000003.txt
  • Flash → microSD カードにコピーして取り出す方法

    拡張ボードをもっている場合は、拡張ボードを使って Flash から microSD へコピーしてファイル取り出す方法もあります。

    1. ここでも nuttx_shell スケッチを使用します。

      スケッチを書き込んで実行すると、シリアルターミナルに NuttShell nsh> プロンプトが表示されます。

    2. ls コマンドで Flash 内のファイルリストを確認します。

      nsh> ls -l /mnt/spif
      gnss tracker8
    3. 対象となるログファイルを cp コマンドで microSD へコピーします。

      nsh> cp /mnt/spif/00000003.txt /mnt/sd0
      gnss trackerA

      microSD を介して GPS ロガーデータを取り出すことができました。
      Flash 内のファイルが不要になれば rm コマンドで削除することができます。

      nsh> rm /mnt/spif/00000003.txt
  • Zmodem ファイル転送を使用する方法

    Spresense SDK 環境を使って Zmodem 転送機能によりファイルを取り出す方法もあります。
    詳細は [TIPS] Zmodem 転送 を参照してください。

取り出した GPS ロガーデータをもとに地図上にマップする方法は こちら を参照してください。

4.3. GPS トラッカーを省電力化する

Coming Soon…​

4.4. GPS トラッカーでさらに多くの NMEA センテンスを出力する

Coming Soon…​

4.5. GPS 時計をつくる

Coming Soon…​

5. Spresense で Sensing ライブラリを動かしてみる

こちらは旧ドキュメントです。ドキュメントは以下のサイトに移行されました。 https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_tutorial_sensing

5.1. Step Counter を使ってみよう

5.1.1. Step Counter サンプルスケッチを動かす

Step Counter サンプルスケッチを動作させるために事前に準備が必要なものを以下に示します。

  • センサーボード SPRESENSE用3軸加速度・3軸ジャイロ・気圧・温度センサ アドオンボード BMP280 BMI160搭載

  • BMI160-Arduinoライブラリ

    • BMI160-Arduino のライブラリのインストール方法について

      1. 上記サイトより「Clone or download」→「Download ZIP」を選択し ZIP ファイルを保存します。

      2. Arduino IDE のメニューから スケッチ → ライブラリをインクルード → .ZIP形式のライブラリをインストール…​ を選択し、保存しておいた ZIP ファイルを選択します。

      3. Arduino IDE に「ライブラリが追加されました」と表示されればインストール成功です。

  • ソニー製行動認識アルゴリズムStep Counter (AESM)

Step Counter サンプルスケッチでは、BMI160 ライブラリを使用した物理センサクライアントと、AESM を使用した論理センサクライアントが連携して動作します。BMI160 から得られた加速度データを入力し、論理センサクライアントにて機械学習を用いた行動認識を行い、その認識結果を出力します。

AESM は、Arduino IDE メニューの ツール > ブートローダを書き込む 操作によりインストールされます。 詳細は、Spresenseローダーのインストール を参照してください。

Arduino IDE 上から ファイル → スケッチ例 → Spresense用のスケッチ例 Sensing → application → step_counter を選択してスケッチを起動します。

arduino stepcounter menu1
arduino stepcounter menu2

スケッチをコンパイルしてSpresenseボードに書き込みを行ってください。

シリアルモニタを開くと、歩数計及びその他の情報がリアルタイムに表示されます。

arduino stepcounter result
tempo

1秒当たりの歩数 [Hz]

stride

歩幅 [cm]
固定値を使用しています。

speed

動作速度 [m/s]

distance

動作距離 [m]
今後、GPS 測位結果をフュージョンして距離を算出するオプションを追加する予定です。
現在リリースしているソフトウエアでは GPS 結果は使用されていません。

step

歩数

move-type

行動認識結果 (stopping: 止まっている、walking: 歩いている、running: 走っている)

Spresense 基板を身に着けて歩いてみてください。

5.1.2. Step Counter の物理センサを変更してみる

ここでは Step Counter のサンプルスケッチで使用する物理センサを別のセンサへ変更してみます。

  • センサーボード ローム社製 SPRESENSE-SENSOR-EVK-701

  • KX122 Arduinoライブラリ

    • KX122 Arduinoライブラリのインストール方法について

      1. 上記サイトより「Clone or download」→「Download ZIP」を選択し ZIP ファイルを保存します。

      2. ダウンロードした ZIP ファイルを任意のフォルダに展開しておきます。

      3. Arduino IDE のメニューから スケッチ → ライブラリをインクルード → .ZIP形式のライブラリをインストール…​ を選択し、展開しておいたフォルダから KX122 フォルダを選択します。

      4. Arduino IDE に「ライブラリが追加されました」と表示されればインストール成功です。

step_counter.ino サンプルスケッチの変更箇所について説明します。

  • include ファイルの変更

    #include <BMI160Gen.h>

    を KX122 を include するように変更します。

    #include <Wire.h>
    #include <KX122.h>
    KX122 kx122(KX122_DEVICE_ADDRESS_1F);
  • setup() 関数の変更

    BMI160 の初期化について、

      /* Initialize device. */
    
      BMI160.begin(BMI160GenClass::I2C_MODE, i2c_addr);
    
      /* Set device setting */
    
      BMI160.setAccelerometerRange(accel_range);
      BMI160.setAccelerometerRate(accel_rate);

    KX122 の初期化へ変更します。KX122 ライブラリの accel_rate はデフォルトで 50Hz に設定されています。

      Wire.begin();
      kx122.init();
  • loop() 関数の変更

    加速度データ取得について、

      float x;
      float y;
      float z;
    
      /* Read raw accelerometer measurements from BMI160 */
    
      BMI160.readAccelerometerScaled(x, y, z);
    
      AccelSensor.write_data(x, y, z);

    KX122 からのデータ取得へ変更します。

      float acc[3];
    
      /* Read raw accelerometer measurements from KX122 */
    
      kx122.get_val(acc);
    
      AccelSensor.write_data(acc[0], acc[1], acc[2]);

上記の変更を行った後にスケッチをコンパイルして実行すると、KX122 を使った Step Counter が動作します。

5.1.3. Step Counterの独自論理センサを作ってみる

現在提供しているソニー製アルゴリズムのStep Counter(AESM) を使わずに、独自のStep Counterアルゴリズムを実装したい場合は、以下のように論理センサクライアントを作成します。

センサクライアントを継承した論理センサクラスを作成してください。

例えば、MyCounterClass をMyCounter.hに実装します。ヘッダファイルは必要に応じインクルードしてください。例えば、SensorClient.hは必要ですが、sensing/logical_sensor/step_counter.hはStepCounterの定義を使用したい場合のみ必要です。

また、例として、一般的に使われているライブラリの格納場所を下図に示します。

diag ee767dba3ab547a866a71ad95972601e
図 15. MyCounterコード格納場所の例

これはWindows環境の例です。Arduino ディレクトリは、Ubuntu環境であれば ~/Arduino 、macOS環境であれば ~/Documents/Arduino となります。

class MyCounterClass : public SensorClient

この MyCounterClass

bool begin(int id,
           uint32_t subscriptions,
           int      rate,
           int      sample_watermark_num,
           int      size_per_sample));

int publish(FAR void* data,
            uint32_t  size_per_sample,
            uint32_t  freq,
            uint32_t  sample_watermark_num,
            uint32_t  timestamp);

int subscribe(sensor_command_data_mh_t& data);

をMyCounter.cppに実装(オーバーライド)します。

  • begin() の実装 :

    MyCounterの初期設定を行います。publishされた加速度センサのデータを受け取るためのcallback関数の登録が必要です。callback関数からはMyCounterの subscribe() をコールしデータを渡します。

    実装例
    unsigned char mycounter_cb(sensor_command_data_mh_t &data)
    {
      return MyCounter.subscribe(data);
    }
    
    bool MyCounterClass::begin(int      id,
                               uint32_t subscriptions,
                               int      rate,
                               int      sample_watermark_num,
                               int      size_per_sample)
    {
      return SensorClient::begin(id,
                                 subscriptions,
                                 rate,
                                 sample_watermark_num,
                                 size_per_sample,
                                 mycounter_cb);
    }
  • subscribe() の実装 :

    加速度センサのデータをSubscribeし、独自のアルゴリズムで処理を行うことで、独自のStep Counterを作成することができます。

    今回、ライブラリが提供する AccelSensorClass を使う場合、送信されるデータは50Hz・50サンプルで、下記実装例中の st_accel_axis のように並んでいるx,y,z軸のデータになります。 このデータを取り出すために、ベースクラス( SensorClient ) の subscribe() を呼んでください。

    実装例
    int MyCounterClass::subscribe(sensor_command_data_mh_t& data)
    {
      struct st_accel_axis
      {
        float x;
        float y;
        float z;
      } *accel_axis;
    
      accel_axis = static_cast<accel_axis*>(SensorClient::subscribe(data));
      uint32_t  timestamp = data.time;
    
      SensorResultStepCounter output;
    
      /*
        独自のアルゴリズムを実装。
       outputに値を入れる。
       */
    
      publish(&output,
              sizeof(SensorResultStepCounter),
              1, /* 1Hz */
              1, /* 1sample */
             timestamp);
    }
    subscribeされたデータは、 sensor_command_data_mh_t になっています。このデータ構造は こちらを参照してください。
  • publish() の実装 :

    publish() では、MyCounterで算出された値を発行することになります。 その読み出しアプリケーションクライアントのサンプルとして StepCounterReader が提供されており、それをそのまま使用する場合はpublishするデータ構造は、

    SensorResultStepCounter

    で送る必要があります。

    上記のように SensorResultStepCounter の型で渡される場合は、 publish() は、ベースクラス( SensorClient )をそのまま使用して問題ありません。

SensorResultStepCounter 型は、以下になります。

/*--------------------------------------------------------------------------*/
/**
 * @struct StepCounterStepInfo
 * @brief the structure of STEP_COUNTER results.
 */
typedef struct {

  float    tempo;     /**< Indicates tempo of walking / jogging calculated
                       *   from the input acceleration data.
                       *   The unit is [Hz].
                       */
  float    stride;    /**< Indicates stride calculated
                       *   from input acceleration data.
                       *   The unit is [cm].
                       */
  float    speed;     /**< Indicates speed of walking / jogging calculated
                       *   from the input acceleration data.
                       *   The unit is [m/s].
                       */
  float    distance;  /**< Indicates cumulative travel distance calculated
                       *   from the input acceleration data.
                       *   The unit is [m].
                       */
  uint32_t step;      /**< Indicates the number of steps calculated
                       *   from the input acceleration data.
                       * The unit is [step].
                       */
  StepCounterMovementType  movement_type; /**<
                                    * Indicates the walking type calculated
                                    * from the input acceleration data.
                                    */
  uint64_t          time_stamp;    /**< Indicates latest timestamp of the
                                    *   acceleration sensor data used.
                                    */
} StepCounterStepInfo;

/*--------------------------------------------------------------------------*/
/**
 * @struct SensorResultStepCounter
 * @brief the structure of sensor result on step counter commands.
 */
typedef struct
{
  SensorExecResult exec_result; /**< Execute resule.  */

  union
    {
      StepCounterStepInfo steps;        /**< Step count.         */
      SensorAssertionInfo assert_info;  /**< Assert information. */
    };
} SensorResultStepCounter;

5.1.4. 自分の論理センサに合わせてデータを変えてみる

当然、独自の論理センサに合わせて、結果となるセンサデータの方を変えたいこともあるかもしません。その場合は、 MyCounterで、publishする際の、データ型を変更し、

int MyCounterClass::subscribe(sensor_command_data_mh_t& data)
{
  ..()..

  MyStepCounterResult output;

  publish(&output,
          sizeof(MyStepCounterResult),
          1, /* 1Hz */
          1, /* 1sample */
          timestamp);
}

読み出す側のApplication( StepCountReaderClass )で、

subscribe()
{
  MyStepCounterResult* steps = reinterpret_cast<MyStepCounterResult*>(ApplicationSensorClass.subscribe(data));
}

と変換してください。

5.2. 新しいセンサクライアントを作ってみる

5.2.1. 物理センサクライアントを作ってみる

prebuildされたSpresense SDK の中には、代表的なSensorのIDが割り当てられています。しかし、この定義されたSensorIDに該当しないような物理センサを作成したいというケースが、実際は大半になるかと思います。

ここでは、このように該当していない物理センサを使用するために、物理センサクライアントの実装例を示します。

今回は、BoschのセンサBME680を用いたガスセンサの物理センサクライアントを作成します。

BoschのBME680には、Arduinoのライブラリだけではなく、proprietaryなライブラリのコードが必要になっています。 こちら を参照してください。

BoschのサイトからZipファイルをダウンロードし、その中の

algo\bin\Normal_version\gcc\Cortex_M4F

にあるライブラリを、Arduinoライブラリの

BSEC\src\spresense

の下に配置してください。

2019年4月の段階では、ARM Coretex-M4Fのアーカイブ作成時にコンパイルオプションに間違いがあり、proprietaryなライブラリのコンパイルができない可能性があります。
その場合は、Boschサポートにお問い合わせください。
  • BME680 Arduinoライブラリのインストール方法について

    1. 上記サイトより「Clone or download」→「Download ZIP」を選択し ZIP ファイルを保存します。

    2. Arduino IDE のメニューから スケッチ → ライブラリをインクルード → .ZIP形式のライブラリをインストール…​ を選択し、保存しておいた ZIP ファイルを選択します。

    3. Arduino IDE に「ライブラリが追加されました」と表示されればインストール成功です。

このセンサは、3秒または5分に1回、温度・湿度・気圧・ガスなどの環境センシングが可能です。

ガスセンサの物理センサクライアントを作成することで、センサフュージョン・エッジAIが可能になります。そのため、ガスセンサ用の物理センサクライアントを作成します。

enum
{
  SEN_selfID        = SensorClientID00, /*  0 */
  SEN_accelID       = SensorClientID01, /*  1 */
  SEN_accel1ID      = SensorClientID02, /*  2 */
  SEN_magID         = SensorClientID03, /*  3 */
  SEN_pressureID    = SensorClientID04, /*  4 */
  SEN_lightID       = SensorClientID05, /*  5 */
  SEN_pulseID       = SensorClientID06, /*  6 */
  SEN_tempID        = SensorClientID07, /*  7 */
  SEN_gyroID        = SensorClientID08, /*  8 */
  SEN_gnssID        = SensorClientID09, /*  9 */
  SEN_stepcounterID = SensorClientID10, /* 10 */
  SEN_tramID        = SensorClientID11, /* 11 */
  SEN_gestureID     = SensorClientID12, /* 12 */
  SEN_compassID     = SensorClientID13, /* 13 */
  SEN_barometerID   = SensorClientID14, /* 14 */
  SEN_tramliteID    = SensorClientID15, /* 15 */
  SEN_vadID         = SensorClientID16, /* 16 */
  SEN_wuwsrID       = SensorClientID17, /* 17 */
  SEN_adcID         = SensorClientID18, /* 18 */
  SEN_reserve19ID   = SensorClientID19, /* 19 */
  SEN_app0ID        = SensorClientID20, /* 20 */
  SEN_app1ID        = SensorClientID21, /* 21 */
  SEN_app2ID        = SensorClientID22, /* 22 */
  SEN_app3ID        = SensorClientID23, /* 23 */
  SEN_ID_MAX        = NumOfGeneralSensorClientID,
};

予約されているSensorIDの中で使用しないもの、例えば以下のIDを使います。

SEN_pulseID       = SensorClientID06, /*  6 */

次のようにSensorIDを定義して使います。

#define SensorClientID06 GasSensorID

次に、ガスセンサークライアントを作成します。 SensorClientクラスをベースクラスにして、以下のようにGasセンサのクラスを GasSensor.h などに定義します。

  • Header例(GasSenser.h)

class GasSensorClass : public SensorClient
{
public:
  bool begin(int      id,
             int      rate,
             int      sample_watermark_num,
             int      size_per_sample = sizeof(struct bsec_virtual_sensor_t));

  /**
   * @brief 1 Sample data write.
   */

  int write_data(float temp, float humi, float pres, float gas);

private:
  bool begin(int      id,
             uint32_t subscriptions        = 0,
             int      rate                 = 0,
             int      size_per_sample      = 0);

  struct gas_sensor_s
    {
      float temp;
      float humi;
      float pres;
      float gas;
    };

  int                   m_cnt;                   /* private counter */
  unsigned long         m_previous_time;
  MemMgrLite::MemHandle m_mh;

};

論理センサに publish したいデータを

  struct gas_sensor_s
    {
      float temp;
      float humi;
      float pres;
      float gas;
    };

のように定義し、こちらを送るような実装を行います。

  int write_data(float temp, float humi, float pres, float gas);

write の関数で、必要なデータの書き込みインタフェースを用意します。

今回のセンサは3秒に1回のセンシングなので、毎回センシングデータを publish する例にしています。
また、サンプリングレートに相当する rate はセンシングのInterval間隔を入れています。

実際にセンシングしたいデータは適宜変更してください。
サンプリングも同様に適宜変更してください。

内部の処理は、 GasSensor.cpp などに、

  • 実装例(GasSenser.cpp)

#include <GasSensor.h>
#include "Arduino.h"

#define GAS_INTERVAL_THRESHOLD  10000  /* [10s] */

Includeと、センシングしているデータが不連続であると判断するデータの間隔 GAS_INTERVAL_THRESHOLD を定義します。

bool GasSensorClass::begin(int      id,
                             uint32_t subscriptions,
                             int      rate, /* Interval time */
                             int      sample_watermark_num,
                             int      size_per_sample)
{

  m_cnt           = 0;
  m_previous_time = millis();

  if (ERR_OK != m_mh.allocSeg(
                         SENSOR_DATA_BUF_POOL,
                         size_per_sample * sample_watermark_num))
    {
      /* Fatal error occured. */

      printf("Fail to allocate segment of memory handle.\n");
      return false;
    }
  return true;
}

bool GasSensorClass::begin(int id,
                             int rate,
                             int size_per_sample)
{
  return begin(id, 0, rate, 1, size_per_sample);
}

begin を定義します。このセンサの場合、3秒単位か5分単位のセンシング間隔ですので、 rate は間隔をmsで設定するように実装してみています。 size_per_sample は、取りたいデータにより決まります。

int write_data(float temp, float humi, float pres, float gas);
{
  /* Check reading cycle */

  long  now           = millis();
  int   read_duration = m_rate * 1000;  /* 3s */
  int   diff          = now - m_previous_time;

  if (diff <= read_duration)
    {
      /* Do not get data. Because the interval of the cycle is short.
       * Return as a normal end
       */

      return SENSORCLIENT_ECODE_OK;
    }

  if (diff >= GAS_INTERVAL_THRESHOLD)
    {
       /* Input interval exceeded threshold. Clear the buffer. */

       m_previous_time = now;
       printf("Input interval exceeded threshold!\n");
    }
  else
    {
      /* Update previous time */

       m_previous_time += read_duration;
    }

  /* Read raw accelerometer measurements from BME680 */

  FAR struct gas_sensor_s *p_src =
    reinterpret_cast<struct gas_sensor_s *>(m_mh.getPa());

  p_src.temp = temp;
  p_src.humi = humi;
  p_src.pres = pres;
  p_src.gas  = gas;

  /* Check if the sample for one process has accumulated */

  publish(m_mh,
          sizeof(struct gas_sensor_s),
          m_rate,
          m_sample_watermark_num,
          now);

      /* Create new memory buffer. */


  if (ERR_OK != m_mh.allocSeg(
                  SENSOR_DATA_BUF_POOL,
                  sizeof(struct gas_sensor_s))
        {
          /* Fatal error occured. */
          printf("Fail to allocate segment of memory handle.\n");
          assert(0);
        }
    }

  return SENSORCLIENT_ECODE_OK;
}

GasSensorClass GasSensor;

write_data を定義します。今回は、温度、湿度、気圧、ガスの4つの値を取ります。
前回データを取得した時刻に対して、 read_duration 以下の場合は、センシングしないで抜けます。 read_duration を超えている場合は、データを取得します。 GAS_INTERVAL_THRESHOLD 以上離れてしまった場合は異常があったとしてエラー処理をします。

取得した各データは、

  FAR struct gas_sensor_s *p_src =
    reinterpret_cast<struct gas_sensor_s *>(m_mh.getPa());

で取得した共有メモリエリアに、

  p_src.temp = temp;
  p_src.humi = humi;
  p_src.pres = pres;
  p_src.gas  = gas;

このように gas_sensor_s 型で書き込みます。 書き込んだら、

  publish(m_mh,
          sizeof(struct gas_sensor_s),
          m_rate,
          m_sample_watermark_num,
          now);

で、publishします。 pulishしたら、新しい共有メモリを以下で確保します。

  if (ERR_OK != m_mh.allocSeg(
                  SENSOR_DATA_BUF_POOL,
                  sizeof(struct gas_sensor_s))
        {
          /* Fatal error occured. */
          printf("Fail to allocate segment of memory handle.\n");
          assert(0);
        }
    }

以上にのように物理センサクライアントを作成したら、実際にアプリケーションからセンシングしたデータを書き込むスケッチを作成します。

BSEC/examples/basicbasic.ino を参考に作成してください。

まず、こちらのIncludeを追加してください。

#include <MemoryUtil.h>
#include <SensorManager.h>
#include <GasSensor.h>

setup() 関数の中に

#define SensorClientID06 GasSensorID

void setup(void)
{
  GasSensor.begin(GasSensorID,3,sizeof(struct gas_sensor_s));

を追記します。

loop()関数内のprintしている個所に、 write_data を記載することで、

void loop(void)
{

 

    output += ", " + String(iaqSensor.breathVocEquivalent);
    output += ", " + String(iaqSensor.rawTemperature);
    output += ", " + String(iaqSensor.rawHumidity);
    output += ", " + String(iaqSensor.gasResistance);
    Serial.println(output);

    );

    GasSensor.write_data(iaqSensor.temperature,iaqSensor.humidity,iaqSensor.pressure,iaqSensor.staticIaq);

Sensor Manager にpublishされます。

5.2.2. 論理センサクライアントを作ってみる

[T.B.D]

6. Spresense Arduino マルチコア環境を動かしてみる

こちらは旧ドキュメントです。ドキュメントは以下のサイトに移行されました。 https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_tutorial_multicore

Arduino IDE を使ったマルチコアプログラミング開発環境について説明します。

Arduino マルチコア環境では、MultiCore MP ライブラリを使用します。 アプリケーション CPU には、全部で 6 個のコアがあり、1 個の MainCore と 5 個の SubCore で構成されています。 通常のシングルコアアプリケーションでは、ユーザーは MainCore のみを使ってプログラミングします。 一方、ここで説明するマルチコア環境を用いることで、ユーザーは SubCore を含むすべてのコアに対して 任意のアプリケーションプログラムを書いて実行させることができるようになります。

MainCore

MainCore は電源投入時に必ず起動されます。

SubCore(s)

SubCore は MainCore からの制御によって起動されます。全部で 5 個の SubCore があります。

本チュートリアルでは、MultiCore MP ライブラリに付属の 2 種類の Example を動かします。

マルチコア Boot サンプル

4 個の SubCore を起動し、マルチコアを使って L チカを行います。
このサンプルを動作させることで、SubCore を起動するための手順を理解することができます。

マルチコア MessageHello サンプル

MainCore と SubCore 間でメッセージのやり取りを行います。
このサンプルを動作させることで、MainCore と SubCore との通信方法について理解することができます。

6.1. マルチコア Boot サンプルを動かしてみる

主な手順としては、

  1. Arduino IDE を使用してスケッチを開く

  2. コアを選択する

  3. コンパイル&アップロードする

これを動作させたいコアの数だけ繰り返します。

以下の手順にしたがって実行してみてください。

  • デスクトップから Arduino IDE を起動します
    (デスクトップにアイコンが無い場合はスタートメニュー等から起動してください)

    arduino multicore desktop
    マルチコアプログラミングで、複数の Arduino IDE ウィンドウを起動する際に注意事項があります。
    Arduino IDE のメニューから File → New (ファイル → 新規作成) でウィンドウを新規作成した場合、例えば、一つのウィンドウで Core 選択のメニューを切り替えると、その設定が連動して全てのウィンドウに反映されてしまいます。
    これを回避する方法として、Core ごとに複数の Arduino IDE ウィンドウを開くときは、毎回デスクトップ上のアイコンから Arduino IDE を起動してください。そうすることで、Core 選択などのメニュー設定が連動することなくウィンドウごとに独立して設定できるようになります。
  • MainCore プログラミング

    • Arduino IDE メニューから File → Examples → Examples for Spresense → MultiCore MP → Boot → Main (ファイル → スケッチ例 → Spresense用のスケッチ例 → MultiCore MP → Boot → Main) スケッチを開きます

      arduino multicore boot0
      arduino multicore boot1 main
    • Main.ino スケッチの解説

      MP.begin(subid) により、引数 subid で指定した SubCore を起動します。
      ここでは、SubCore1 ~ SubCore4 の計 4 個の SubCore を起動しています。

      arduino multicore boot4 main
    • Arduino IDE メニューから Tools → Core → MainCore (ツール → Core → MainCore) を選択します

      arduino multicore boot2 main

      下のステータスバーで MainCore が選択されていることを確認できます

      arduino multicore boot3 main
      Arduino IDE 1.8.9 ではメニューを切り替えたときに
      ステータスバーが正しく表示されないという不具合があります
    • Upload ボタンを押して、Compile & Upload を行います

      arduino multicore boot5 main
      複数ウィンドウから複数コアのプログラムを同時に Upload することはできません。
      Upload 動作が同時に実行されないようにコアごとに順番に行ってください。
    • Compile 結果のログに使用メモリサイズが表示されます

      MainCore は常に 768 KByte のメモリを使用します。

      arduino multicore boot6 main

      正常に Upload が完了すれば、MainCore プログラミングは完了です

      • 試しに SubCore プログラムがまだ存在しない状態でシリアルモニタを起動してみます。
        SubCore が存在しないので、MP.begin(1~4) の呼び出しがエラーで返ってきていることが分かります。

        arduino multicore boot7 serial err

        シリアルモニタを開いている状態だと、他のウィンドウからの Upload が正しく行えないことがあります。
        この確認を終えたら、シリアルモニタを閉じてください。

続いて SubCore のプログラミングを行います。

  • SubCore プログラミング

    • Arduino IDE メニューから File → Examples → Examples for Spresense → MultiCore MP → Boot → Sub1 (ファイル → スケッチ例 → Spresense用のスケッチ例 → MultiCore MP → Boot → Sub1) スケッチを開きます

      arduino multicore boot0
      arduino multicore boot1 sub1
    • Sub1.ino スケッチの解説

      setup() で MP.begin() を呼び出して、MainCore に起動完了を通知します。
      loop() では MPLog() によるログ表示と LED0 の点滅制御を行っています。

      arduino multicore boot4 sub1
    • Arduino IDE メニューから Tools → Core → SubCore 1 (ツール → Core → SubCore 1) を選択します

      arduino multicore boot2 sub1

      下のステータスバーで SubCore 1 が選択されていることを確認できます

      arduino multicore boot3 sub1
      Arduino IDE 1.8.9 ではメニューを切り替えたときに
      ステータスバーが正しく表示されないという不具合があります
    • Upload ボタンを押して、Compile & Upload を行います

      arduino multicore boot5 sub1
      複数ウィンドウから複数コアのプログラムを同時に Upload することはできません。
      Upload 動作が同時に実行されないようにコアごとに順番に行ってください。
    • Compile 結果のログに使用メモリサイズが表示されます

      ここで使用する SubCore サンプルスケッチは 128 KByte のメモリを使用することが分かります。
      このサイズは、ユーザープログラムに依存して増減します。

      arduino multicore boot6 sub1

      正常に Upload が完了すれば、SubCore 1 のプログラミングは終了です

  • SubCore 2, 3, 4 についても同様の手順で、Compile & Upload を行ってください

    • Sub2 スケッチを開き、SubCore 2 を選択して、Compile & Upload

    • Sub3 スケッチを開き、SubCore 3 を選択して、Compile & Upload

    • Sub4 スケッチを開き、SubCore 4 を選択して、Compile & Upload

  • 動作確認

    • Spresense メイン基板上の 4 個の緑 LED が点滅します

    • シリアルモニタを開くと、各コアからのログ出力が表示されます

      arduino multicore boot7 serial
  • まとめ

    • 簡単なサンプルスケッチを使って SubCore の起動方法について解説しました。
      既存のスケッチをマルチコア環境に移植するときは MP.begin() の呼び出しを追加してください。

    • Arduino IDE の Compile & Upload 方法など、基本的な使い方はマルチコア環境でも特に変わりはありません。 主な差分は、Tools → Core (ツール → Core) でコア選択のメニューが追加されていることです。

6.2. マルチコア MessageHello サンプルを動かしてみる

主な手順は、マルチコア Boot サンプルと同じです。
このサンプルでは、MainCore と SubCore(s) で共通のスケッチを使用します。

  1. Arduino IDE を使用してスケッチを開く(一度だけ)

  2. コアを選択する

  3. コンパイル&アップロードする

これを動作させたいコアの数だけ繰り返します。 このサンプルでは、全て (計 5 個) の SubCore を動かします。

以下の手順にしたがって実行してみてください。

  • デスクトップから Arduino IDE を起動します
    (デスクトップにアイコンが無い場合はスタートメニューから起動してください)

    arduino multicore desktop
    マルチコアプログラミングで、複数の Arduino IDE ウィンドウを起動する際に注意事項があります。
    Arduino IDE のメニューから File → New (ファイル → 新規作成) でウィンドウを新規作成した場合、例えば、一つのウィンドウで Core 選択のメニューを切り替えると、その設定が連動して全てのウィンドウに反映されてしまいます。
    これを回避する方法として、Core ごとに複数の Arduino IDE ウィンドウを開くときは、毎回デスクトップ上のアイコンから Arduino IDE を起動してください。そうすることで、Core 選択などのメニュー設定が連動することなくウィンドウごとに独立して設定できるようになります。
  • MainCore プログラミング

    • Arduino IDE メニューから File → Examples → MultiCore MP → Messsage → MessageHello (ファイル → スケッチ例 → Spresense用のスケッチ例 → MultiCore MP → Message → MessageHello) スケッチを開きます

      arduino multicore boot0
      arduino multicore hello1
    • MessageHello.ino スケッチの解説

      スケッチ内で #ifdef SUBCORE ~ #else ~ #endif を使って、MainCore, SubCore の実装を切り替えています。

      • MainCore ソースコードについて

        setup() で MP.begin(subid) により、5 つの SubCore を起動しています。
        setup() の最後に MP.RecvTimeout(MP_RECV_POLLING) により受信をポーリングモードに設定しています。
        このモードにすると MP.Recv() を呼び出したときに受信待ちに入らずポーリング動作を行います。
        loop() では、MP.Recv() で各 SubCore から packet のアドレスを受信し、packet 内の message を printf() 出力しています。

        arduino multicore hello4 main
      • SubCore のソースコードについて

        setup() で MP.begin() を呼び出して、MainCore に起動完了を通知します。
        loop() では、packet に "Hello" message を格納し、そのアドレスを MP.Send() で MainCore へ送信しています。

        arduino multicore hello4 sub
    • Arduino IDE メニューから Tools → Core → MainCore (ツール → Core → MainCore) を選択します

      arduino multicore hello2 main

      下のステータスバーで MainCore が選択されていることを確認できます

      arduino multicore boot3 main
      Arduino IDE 1.8.9 ではメニューを切り替えたときに
      ステータスバーが正しく表示されないという不具合があります
    • Upload ボタンを押して、Compile & Upload を行います

      arduino multicore hello5 main
      複数ウィンドウから複数コアのプログラムを同時に Upload することはできません。
      Upload 動作が同時に実行されないようにコアごとに順番に行ってください。
    • Compile 結果のログに使用メモリサイズが表示されます

      MainCore は常に 768 KByte のメモリを使用します

      arduino multicore boot6 main

      正常に Upload が完了していれば、MainCore プログラミングは終了です。

続いて SubCore のプログラミングを行います

  • SubCore プログラミング

    • Arduino IDE メニューから Tools → Core → SubCore 1 (ツール → Core → SubCore 1) を選択します

      arduino multicore hello2 sub1

      下のステータスバーで SubCore 1 が選択されていることを確認できます

      arduino multicore boot3 sub1
      Arduino IDE 1.8.9 ではメニューを切り替えたときに
      ステータスバーが正しく表示されないという不具合があります
    • Upload ボタンを押して、Compile & Upload を行います

      arduino multicore hello5 main
      複数ウィンドウから複数コアのプログラムを同時に Upload することはできません。
      Upload は同時に実行されないようにコアごとに順番に行ってください。
    • Compile 結果のログに使用メモリサイズが表示されます

      ここで使用する SubCore サンプルスケッチは 128 KByte のメモリを使用することが分かります。
      このサイズは、ユーザープログラムに依存して増減します。

      arduino multicore boot6 sub1

      正常に Upload が完了していれば、SubCore 1 のプログラミングは終了です

  • SubCore 2, 3, 4, 5 についても同様の手順で、Compile & Upload を行ってください

    • SubCore 2 を選択して、Compile & Upload

    • SubCore 3 を選択して、Compile & Upload

    • SubCore 4 を選択して、Compile & Upload

    • SubCore 5 を選択して、Compile & Upload

  • 動作確認

    • シリアルモニタを開いてください

    • 各 SubCore が送信したメッセージを MainCore が受信し、シリアルモニタ上に表示されます

      arduino multicore hello7 serial
  • まとめ

    • サンプルスケッチを使って SubCore との通信方法について解説しました。

    • コア間でメモリが共有されているので、アドレスを渡してメッセージ通信を行うことができます。

    • コアごとにスケッチを分けずに共通のスケッチを使用したマルチコアプログラミングも可能です。

6.3. 特記事項

  • MultiCore MP ライブラリについて、詳しくは 開発ガイド を参照してください。

  • Spresense 基板上に既にアップロード済みの SubCore バイナリがあり、それらを一括して消去したい場合は、Spresenseローダーのインストール を行ってください。ローダのインストール時に、一旦、すべての SubCore バイナリを削除してからローダのインストールが始まります。

    arduino multicore remove subcore

    なお、MainCore から MP.begin() を呼び出さない限り、勝手に SubCore が動作することはありません。 そのため、古い SubCore がアップロードされたまま残っていても特に問題はありません。

  • マルチコアプログラミングで、Core ごとに複数の Arduino IDE ウィンドウを開くときは、毎回デスクトップ上のアイコンから Arduino IDE を起動してください。そうすることで、Core 選択などのメニュー設定がウィンドウごとに独立して設定できるようになります。

  • Arduino IDE での複数起動や Core を切り替える操作が煩雑ですが、arduino-builder や arduino-cli といったコマンドラインツールを使用することも可能です。また、Upload についても、直接 flash_writer ツールを使用すれば、各コアのバイナリを一回のコマンドで一括してロードすることも可能です。コマンドラインを用いた方法について後日ドキュメントに掲載する予定です。