Arduino Uno Qの利用 ⑩ 入門編 従来のArduinoと互換性を保ち新しい機能を追加されたArduino Uno Q<サンプルUNO Q Pin Toggleの動作確認>

 今回は、サンプルのUNO Q Pin Toggleを動かして仕組みを確認します。

 Arduino Uno Qには、次に示すようなD0~D21の汎用のディジタル・ポート、そのうちD14~D19はA0~A5のアナログ6ポートとなっています。

 このほかに、オンボードの二つのカラーLEDの制御を行うためのRGB×2の6ポートのディジタル・ポートが用意されています。

 サンプルのUNO Q Pin Toggleでは、Webブラウザに表示されているトグル・スイッチをマウスでクリックすると、Uno QのポートがON/OFF(HIGH/LOW)と変化します。

 README.mdで表示される全体構成で、この仕組みを説明します。

 具体的なボードのポートの制御はスケッチが対応します。

 Webブラウザの表示、Webブラウザからの指示に従ってArduinoのポートの制御データをスケッチに渡す処理は、ArduinoのPython側で行います。

 Webブラウザとのやり取りはBrickのWebUIが担っています。

 次の図は、それらの関係を図示したものです。
  

スケッチの行っていること
 
 ピン名とピン番号の組み合わせの構造体の配列に、制御に必要となるArduino Uno Qのピン番号をセットします。

 関数 set_pin_by_name(String name, bool s)で、ピン名とON/OFFの状態を示すデータを受け取ります。指定されたピンの状態を、指示に従い設定します。

ArduinoとPythonの間はRouterBridg

  Arduinoとpythonの間の連携を図るためのライブラリを用意します。

#include <Arduino_RouterBridge.h>

 PinEntry型の配列 kPins[]でWebブラウザからArduinoの制御対象を示す構造体の定数を定義します。ピン名を示すnameとピン番号を組み合わせた構造体となります。

 Arduinoのプログラムのリファレンスには説明はありませんが、C++のリファレンスには説明があります。

struct PinEntry { const char* name; uint8_t pin; };

 対象のピンを指定するためにPinEntry型の配列を定義しています。

static const PinEntry kPins[] = {
  {"D21", D21}, {"D20", D20}, {"D13", D13}, {"D12", D12},
  {"D11", D11}, {"D10", D10}, {"D9",  D9 }, {"D8",  D8 },
  {"D7",  D7 }, {"D6",  D6 }, {"D5",  D5 }, {"D4",  D4 },
  {"D3",  D3 }, {"D2",  D2 }, {"D1",  D1 }, {"D0",  D0 },
  {"A0",  A0 }, {"A1",  A1 }, {"A2",  A2 }, {"A3",  A3 },
  {"A4",  A4 }, {"A5",  A5 },
  {"LED3_R", LED_BUILTIN}, {"LED3_G", LED_BUILTIN + 1}, {"LED3_B", LED_BUILTIN + 2},  {"LED4_R", LED_BUILTIN + 3}, {"LED4_G", LED_BUILTIN + 4}, {"LED4_B", LED_BUILTIN + 5},
};


ピン名から配列の番号を得る関数

 制御ピンのnameからピン番号を得るための関数findIndex()が用意されています。この関数の中で使われているstrcmp()関数は、二つの文字列を比較し一致を調べる関数です。Arduinoのリファレンスには記述はありませんが、C++などの標準ライブラリに用意されています。

 char*のポインタで示された文字列のピン名 nを渡し、同じ文字列が格納されている配列の番号が戻されます。

static inline int findIndex(const char* n) {

 配列 kPins[]について0から最終の配列まで格納されている名前とnの名称が一致するか調べます。一致したらその配列の戻り値として関数を抜け出します。

  for (size_t i = 0; i < sizeof(kPins)/sizeof(kPins[0]); ++i) {
    if (strcmp(kPins[i].name, n) == 0) return (int)i;
  }
  return -1;
}

 一致するものがなければ -1 が戻されます。


ピン名と設定値によりON/OFFを設定


 pythonから呼び出され、ピン名とON/OFFの状態を引数として設定します。


// Generic setter: name + bool
void set_pin_by_name(String name, bool s) {
  int idx = findIndex(name.c_str());  // nameから配列の指標を得る
  if (idx < 0) return;              // unknown name // -1 なら戻る
  digitalWrite(kPins[idx].pin, s ? HIGH : LOW);   // sの値でH,Lを決める
}
//この関数はmain.pyの Bridge.call("set_pin_by_name", name,  state_for_hw)から呼び出される。
void setup()
{
  // Arduino Uno Qの全ポートを出力に設定するfor文。 
   for (auto &e : kPins) pinMode(e.pin, OUTPUT);
    digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(LED_BUILTIN + 1, HIGH);
    digitalWrite(LED_BUILTIN + 2, HIGH);
    digitalWrite(LED_BUILTIN + 3, HIGH);
    digitalWrite(LED_BUILTIN + 4, HIGH);
    digitalWrite(LED_BUILTIN + 5, HIGH);
    Bridge.begin();           // Bridgeを起動する
    Bridge.provide("set_pin_by_name", set_pin_by_name);  // pythonからの呼び出しを待つ。
}
void loop() {} // 何もせず待機


 初期化処理(setup())の最初では、各ポートの入出力状態を格納している配列の全ポートを出力に設定しています。このfor文は全配列に対して処理を一括でに行うためのもので、通常のfor文よりシンプルに記述できます。

 auto &eは、配列kPinsの全要素を先頭から最終要素まで順番に処理することを指示しています。この命令の一般的な書式は次のようになります。例では実行文が1行ですので{}は省略され文の最後に;に付加されています。


  for (auto &e : 配列名) { // 各要素 e に対する処理 }
 
 その後、LEDに接続されているポートは消灯の初期設定値であるHIGHに設定します。
 Bridgeライブラリを開始し、Bridge.provideでpython側から起動する関数の設定を行い初期設定を終わります。

 loop()関数ではなにも行わず、python側から関数の呼び出しを待ちます。


プログラムが行っていること

Webブラウザの表示

 index.htmlでHTML表示画面の骨格を構成し、style.cssで表示の大きさ、色などの装飾を分担し、app.jsで表示内容の変化、クリックなどの対応などを分担します。

Arduinoの高機能マイコンの処理

 main.pyはプログラムのWebブラウザ、Arduino側のスケッチと連携し全体の司令塔の役割をはたしています。


従来のArduinoマイコンのスケッチ

 Webブラウザからの情報をもとにArduino Uno Qの各ポートの変更データをmain.pyが設定します。この設定データをsketch.inoが受け取り、ポートの状態を変更します。

Webブラウザ表示のindex.html

 Webブラウザのためのindex.htmlの中に28行目に、

  <!-- switches are injected here by app.js →


が記述されています。この記述部分にはプログラムが最初に展開されるときに各ポートのスイッチ部分はapp.jsプログラムの makeSwitch()関数で展開されます。

 次に示すD21からLED4_Bまでの28ポートの記述はソースにはありませんが、実行時の展開されたHTML文書は次のようになっています。
  

 D7のポートの記述を展開すると、次に示すように記述されています。


  D7のポートを例に内容を確認します。

 label要素のtitle=”D7”は、Webブラウザに表示されたArduino Uno Qのポートにマウスを載せたときに表示されるテキストです。このinput要素はcheckboxタイプで、クラス名はswitch-inputでこのクラスの表示についてはstyle.cssに .switch-inputのタイトルで記述されています。

 switch-iosはトグル・スイッチの土台部分です。::afterはトグル・スイッチの可動部分の指定です。style.cssには.switch-iosと .switch-ios::afterについて丸みのついた横長の四角と丸いボタンが左右に移動することが示されています。


Webブラウザのポートがクリックされると

 クリックされたトグル・スイッチのstyle.cssの該当するスイッチの表示が変化します。

 App.jsで設定されたui.send_message('pin_toggle', ...) を利用して、該当するポート名とスイッチの状態をmain.pyのon_pin_toggle()関数に渡します。この関数の中でBrige.call関数でArduinoのスケッチのポート出力を制御する関数を呼び出し、実際のボードの出力の状態をセットします。


Arduino Uno Qをフルに利用するには

 Arduino Uno R4まではArduinoを利用するには、わかりやすいスケッチだけを記述するだけで済んでいました。しかしUno Qからは、Webブラウザの利用のためHTML、javascript、CSSなど新しいツールを利用しなければなりません。pythonでのプログラムの作成も必要になります。

 しかし、このように画面回り、実際にハードを動かすプログラム、橋渡しをするプログラムなどを分離して構成しておくと、クラウドのAI、画像認識などの外部の強力な資源を容易に利用することができるようになります。

 この後、サンプルの動作確認からコピーをもとに追加修正を行うことを考えます。


神崎康弘

前へ

Arduino Uno Qの利用 ⑨ 入門編 従来のArduinoと互換性を保ち新しい機能を追加されたArduino Uno Q<Detect Object on Cameraで画像を確認>