obnizでじゃんけん大会プログラムを作ってみた

この記事はObniz Advent Calendar 2018の17日目の記事です。

ときどき勉強会で、司会者と参加者でじゃんけんして勝ち残った人にプレゼントが贈呈されることがあります。このじゃんけんをobnizでやるプログラムを試作してみました。

作成のきっかけ

スイッチサイエンスの動画「micro:bitファンミーティングの話」を見ていたら、5分3秒ぐらいからmicro:bitを43台使って抽選を行った話が出てきました。obnizを使って似たようなことができないかなと思いました。

作成した物の動作

司会者と参加者が各1台ずつobnizを持ち、ダイアルスイッチを使ってじゃんけんの手(?)「グー」「チョキ」「パー」を入力します。司会者に勝った人だけが、次のじゃんけんに参加できます。

試作品なので最低限の情報しか画面に表示していません。

起動直後は、各obnizに親か子の情報が表示されています。

じゃんけんの手を全員が入力し終わると、子供には勝敗が表示されます。

勝敗決定後のブラウザ画面はこうなります。

2回戦に進んだ画面はこうなります。child  2は1回戦で負けたため2回戦には参加できません。

プログラムを書いて気づいたこと

複数台のobnizの制御

obnizサイトのドキュメントにある「obniz2つを連携」を真似して作り始めました。ここで解説されている方法は、obniz.onconnectに渡す関数を入れ子にする方法です。obnizAのonconnect関数内にobnizBのインスタンス作成とonconnect関数が記載されています。

var obnizA = new Obniz("0000-0000");
obnizA.onconnect = async function () {
  var obnizB = new Obniz("1234-5678");
  obnizB.onconnect = async function() {
    // integration here 
  }
}

この方法には次の点でじゃんけんプログラムには適しません。

  • 参加人数が多くなると入れ子がどんどん深くなる。
  • onlineにならないobnizがあると、それより先のobnizは接続できない。

そこで、入れ子にするのはやめて、単純にループで回すようにしました。

parent = new Obniz(parentID);
parent.onconnect = function () {
  parent.display.clear();
  parent.display.print("parent");
  parent.switch.onchange = parentSwitch;
}
for (var i = 0; i < childrenIDs.length; i++) {
  child = new Obniz(childrenIDs[i]);
  child.onconnect = createChildFunction(i, child);
  child.onclose = createChildOnCloseFunction(i,child) 
  children.push(child);
}

子供のonconnect関数内で、自分が何番目の子供であるかのインデックス番号と自分自身を表すobnizオブジェクトを使うので、それらが参照できるようにしなければなりません。そこで「関数を返す関数」を用意しました。

function createChildFunction(index,obniz) {
  return async function () {
    online[index]=true;
    updateBrowser();
    obniz.display.clear();
    obniz.display.print("child " + index);
    obniz.switch.onchange = createJogdialCallback(obniz, index);
  }
}

同様に、obniz.switch.onchangeも「関数を返す関数」を使って設定しています。

function createJogdialCallback(obniz, index) {
  return function (state) {
    if (state !== "none") {
      if (step == 'VOTING') {
        obniz.display.clear();
        obniz.display.print(""+index+" : "+handName[state]);
        childHands[index] = handName[state];
        updateBrowser();
      }
    }
  }
}

こういったコーディングをすることで、手持ちの4台のobnizでプログラムが動作するようになりました。ただ、よく考えてみると数十台のobnizとの接続は、OSやブラウザの限界を超えてしまう可能性があることに気づきました。

コールバックの並行実行の可能性

参加者がほぼ同時に手を入力した場合、obniz.switch.onchange( )関数が一斉に発火します。それらの関数が1個ずつ処理されるのか並行に処理されるのかは、obnizのJavaScriptライブラリの実装方法や、ブラウザのJavaScriptエンジンの実行方法に依存します。obnizのドキュメントを見た限りではその辺の解説は見つかりませんでした。今回は「逐次実行だ!」と信じて排他制御は考えませんでした。

状態遷移の設計

設計せずにいきなりコードを書き始めたのでかなり手戻りがありました。

最初は単純に次のような状態遷移を考えていました。

プログラムを書いて動かしてみたら、次のような問題があることに気がつきました。

  • 3の遷移はこんなに単純ではない
    • 手を入力しない人がいるかもしれない
    • 何らかの原因でオフラインになったobnizからは手が入力されない

この問題は、全員の入力を待つことなく強制的に「勝敗を判定」に遷移する方法を用意することで回避しました。obnizのオフライン判定は一定のタイムアウト時間後になるので即時性がないため自動判定にはしませんでした。複数台のobnizを制御するプログラムの難しさがここに潜んでいます。

  •  4の遷移はこんなに単純ではない。
    • 勝った人がいない場合は、同じ参加者でじゃんけんをやり直す
    • 賞品が3つあって勝者が2人の場合、勝った2人を除いた人達でじゃんけんを再開したい
    • 賞品をゲットした人は除いて次のじゃんけんをはじめたい
    • その他いろいろ

この問題の1つ目は単純な考慮漏れだったのですぐ直せましたが、2つ目以降はやりたいことが多岐にわたるので対応を諦めました。

おわりに

一応、それっぽく動くプログラムはできましたが、

  • 何台まで対応できるかわからない
  • 参加者全員のobniz IDを入力する必要があるが、現状ではプログラムに直書きしているため、実用には程遠い

という問題があります。また、複数のobnizを使う場合に注意すべき点もまだまだありそうです。修行を続けたいと思います。

(ソースコードは後日公開する予定です)

安いリレーをWROOM-02, WROOM-32につないでみた

水中ポンプ4台のOn/Offを制御したくてWROOMで動作しそうなリレーを探していたら、amazonでこんなのが見つかりました。たったの500円というお買い得商品です。

4連リレー

amazonで安い電子部品を買うと、中国からの発送になって1〜2週間かかることが多いのですが、こちらの商品はamazon倉庫からの発送で翌日に届きました。

箱の中身

箱の中にはリレーとコネクター用のネジ回しが入っていました。

端子

端子部分

右下に、電源と信号線を接続する端子と、リレー駆動電源を選択するジャンパー端子があります。ジャンパーを取り付けている状態では、VCCに供給した電源をリレー駆動に使います。ジャンパーを取り外してJD-VCCピンに別の電源を接続するとVCCとは違う電源でリレーを駆動できるようになります。

WROOMのGPIOは3.3VなのでVCCには3.3Vを供給します。リレーは5V仕様なので3.3Vだと動作が不安定になります。ジャンパーを外して5Vを供給すればしっかり動くようになります。

 

出力端子

出力端子は、1つのリレーに対して3つ用意されています。

中央と左側の端子に接続すると、リレーが動作していないときは回路が切断状態になり、リレーが動作しているときは回路が接続状態になります。

中央と右側の端子に接続すると、逆の動作になります。

Deep Sleepしたときの動作

このリレーはActive Lowです。信号線がHIGHのときリレーは動作せず、LOWのときリレーが動作します。wroomをdeep sleepさせたときGPIOの出力がLOWになってリレーが動いてしまうのではないかという心配があります。

実際にWROOM-02とWROOM-32で実験してみたところ、deep sleep時にはリレーはOffのままでした。実験に使用した開発ボードは下記のものです。

WROOM-02: スイッチサイエンスESPr Developer

WROOM-32: M5Stack Gray

M5StackにGrove SHT31温度湿度計をつないでみた

Grove SHT31温度湿度計をM5Stackにつないでみました。接続はGroveケーブルを使ってM5StackのGroveソケットに挿しました。

Groveソケット接続

プログラムはSeeed StudioのGrove WikiのSHT31のページにあるライブラリとサンプルコードを使いました。

#include <M5Stack.h>
#include <Arduino.h>
#include <Wire.h>
#include "SHT31.h"

SHT31 sht31 = SHT31();

void setup() {  
  // Initialize the M5Stack object
  M5.begin();

  Serial.begin(115200);
  while(!Serial);
  Serial.println("begin...");  
  sht31.begin();  
}

void loop() {
  float temp = sht31.getTemperature();
  float hum = sht31.getHumidity();
  Serial.print("Temp = "); 
  Serial.print(temp);
  Serial.println(" C"); //The unit for  Celsius because original arduino don't support speical symbols
  Serial.print("Hum = "); 
  Serial.print(hum);
  Serial.println("%"); 
  Serial.println();
  
  M5.Lcd.printf("Temp. = %f  Hum. = %f\n", temp, hum);
  
  delay(1000);
}

変更点は、

  • 1行目に #include <M5Stack.h> を追加
  • 10行目にM5.begin( ); を追加
  • 12行目のボーレートを115200に変更
  • 29行目にLCDへの表示を追加

だけです。LCD表示はスクロールのコードを書いていないので、画面最後の行まで到達したらそれ以降画面更新はありません。

Groveソケットを使わないで、GPIO端子に接続するのも試してみました。接続ケーブルはGrove-4ピン-ジャンパメスケーブルを使い、接続先は、

黄 → SCL(GPIO22)
白 → SDA(GPIO21)
赤 → 3.3V
黒 → GND

としました。

GPIO端子に接続

こちらも問題なく動作しました。

 

[Nefry BTとGrove接続実験] RGBバックライト液晶

RGBバックライト液晶モジュール

私が購入したGROVEスターターキットV3に入っていたRGBバックライト液晶モジュールは、LCD RGB Backlight v4.0というモジュールです。スイッチサイエンスさんの単体販売ページに掲載されているものと同じ製品だと思われますが、スイッチサイエンスの製品写真だとv2.0になっているので、バージョンが異なる可能性があります。

Grove RGBバックライト液晶モジュール
Grove RGBバックライト液晶モジュール(裏)

RGBバックライト液晶モジュールの動作

この液晶は、文字の色は黒しかありませんが背景の色を変えられます。表示文字数は16文字x2行です。このモジュールとIoTボード間の通信はI2Cを使います。

このモジュールは5Vを必要とします。Nefry BTのGroveソケットに接続した場合、3.3Vしか供給されないので正常に動作しません。

Nefry BTにはGPIOのピンソケットが搭載されていて、5V電源のピンも出ているので、ピンソケットに接続すればこのモジュールを使えます。

接続には一方がバラになっているGroveケーブルを使います。例えばスイッチサイエンスさんではこんなGroveケーブルが販売されています。

先バラのGroveケーブル

このケーブルはメス端子が取り付けられているので、Nefry BTのGPIOソケットに接続する場合は、オス-オスのジャンパーケーブルを継ぎ足して使うとこなります。

Seeed Studioのサイトには、オス端子が付いた先バラケーブルが売られていますが、国内では販売店を見つけられませんでした。

ピンが付いている先バラGroveケーブル

私は短いケーブルが欲しかったので、通常のGroveケーブルを2分割してピン端子を取り付けました。とても雑な工作なので写真を載せるのが恥ずかしいです。

自作ケーブル

Nefry BT R2の場合、先バラケーブルは下図のように接続します。

Nefry BT R2でのGroveケーブル接続先

Nefry BT無印の場合は、5Vのソケット位置が異なるので注意してください。

Nefry BT無印
ケーブルの色GPIOソケット名
D0
D1
5V
GND

プログラム

Seeed StudioのGrove Wikiページに掲載されているライブラリとサンプルプログラムを動かしてみます。

Grove Wikiページの中程のSoftwareという部分にある「Grove-LCD RGB Backlight Library」というリンクをクリックしてプログラム一式のzipファイルをダウンロードします。

Arduino IDEのメニューで

[スケッチ] -> [ライブラリをインクルード] -> [.ZIP形式のライブラリをインストール…]

を選んでインストールします。

ライブラリのインストール

Arduino IDEの

[ファイル] -> [スケッチ例] -> [Grove – LCD RGB Backlight] -> [HelloWorld]

を選択してサンプルプログラム「HelloWrold.ino」を開きます。

サンプルプログラム HelloWorldを開く

HelloWorld.inoの中身はこうなっています。

#include <Wire.h>
#include "rgb_lcd.h"

rgb_lcd lcd;

const int colorR = 255;
const int colorG = 0;
const int colorB = 0;

void setup() 
{
    // set up the LCD's number of columns and rows:
    lcd.begin(16, 2);
    
    lcd.setRGB(colorR, colorG, colorB);
    
    // Print a message to the LCD.
    lcd.print("hello, world!");

    delay(1000);
}

void loop() 
{
    // set the cursor to column 0, line 1
    // (note: line 1 is the second row, since counting begins with 0):
    lcd.setCursor(0, 1);
    // print the number of seconds since reset:
    lcd.print(millis()/1000);

    delay(100);
}

このままのプログラムで動作するはずですが、なぜか動作しませんでした。

setup( ) の1行目に Serial.println(“”) を追加したら、なぜか動きました。理由はまだ解明できていません。

プログラム変更点
動作状況
名称LCD RGB Backlight
RGBバックライトLCD
バージョンv4.0
Seeed社 Wikihttp://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/
スイッチサイエンス商品ページhttps://www.switch-science.com/catalog/1629/
Nefry BT無印 動作ソケットD0 (動作未確認)
Nefry BT R2 動作ソケットD0

 


「Nefry BTとGroveモジュール接続実験」 トップページ

 

[Nefry BTとGrove接続実験] サーボモータ

サーボモータモジュール

私が購入したGROVEスターターキットV3に入っていたサーボモータモジュールには、型番や定格が記載されていませんでした。しかし、形状や付属品はスイッチサイエンスさんの単体販売ページに掲載されているものと同じに見えます。

Groveサーボモータモジュール

サーボモータの動作

サーボモーターはPWMで指定された値に応じて軸の角度が変わる特殊なモーターです。通常180度程度の可動域があります。PWMについては別記事に解説を記載しているので参照してください。

サーボモータの可動域の例

サーボモータのPWMパラメータは、一般的には、周期は10〜20msでパルス幅は0.5ms〜2.5msぐらいのようですが、機種による差が大きく、また個体による差もあるようです。

筆者が持っているサーボモーターでは、次のようなパラメーターで動作するようです。

筆者が持っているサーボモータのPWMパラメータ

プログラム

Nefry BTに装備されているスイッチを押す度に、0°、90°、180°の位置へ移動を繰り返すプログラムです。

//Groveケーブルを接続するGroveコネクターを1つ選んで#define文に記載してください。
// Nefry BT無印の場合: D2, A0, A2 (注:D0は使えません)
// Nefry BT R2の場合: D0, D2, D5, A1  (注:A0を使うときはA1を記載します)
#define PIN D2

// LEDCのパラメータ設定
//   LEDC_CHANNEL        : チャンネル : 0
//   LEDC_RESOLUTION_BITS: 目盛数    : 10bit (0〜1023)
//   LEDC_FREQUENCY  : 周波数    : 50Hz (= 20ms周期)
#define LEDC_CHANNEL 0
#define LEDC_RESOLUTION_BITS 10
#define LEDC_FREQUENCY 50

//  30/1024*20ms = 0.59ms
//  77/1024*20ms = 1.50ms
// 122/1024*20ms = 2.38ms
uint32_t pulse[3] = {30, 77, 122};
int n = 0;

void setup() {
  ledcSetup(LEDC_CHANNEL, LEDC_FREQUENCY, LEDC_RESOLUTION_BITS);
  ledcAttachPin(PIN, LEDC_CHANNEL);
  Serial.println(pulse[n]);
  ledcWrite(0, pulse[n]);
  Nefry.enableSW();
}

void loop() {
  if (Nefry.readSW()) {
    n = (n+1) % 3;
    Serial.println(pulse[n]);
    ledcWrite(0, pulse[n]);
  }
}

配列宣言 pulse[3]で、0°、90°、180°のパルス幅を覚える配列を定義しています。
setup( )ルーチン内で ledcSetup(…) を実行して、チャンネル、周波数、目盛数を設定し、ledcAttachPin( )でGPIOピンとチャンネルを結びつけます。ledcWrite( )で0°のパルス幅をサーボモーターに設定しています。

次に、loop( )}ルーチン内では、スイッチが押される度に90°、180°、0°のパルス幅を順に設定しています。

諸元

名称Servo
サーボモータ
バージョン不明
Seeed社 Wikihttp://wiki.seeedstudio.com/Grove-Servo/
スイッチサイエンス商品ページhttps://www.switch-science.com/catalog/1858/
Nefry BT無印 動作ソケットD2, A0, A2
Nefry BT R2 動作ソケットD0, D2, D5, A0(プログラム上はA1)

「Nefry BTとGroveモジュール接続実験」 トップページ

 

ESP-WROOM-32(ESP32)のPWM

Arduino IDEを使ってESP-WROOM-32(ESP32)のPWMを制御するプログラムを書く方法を記載します。

PWMとは

PWM(Pulse Width Modulation)は、次の図のような周期的なパルス信号を生成し、1になっている時間と0になっている時間の比率(デューティー比)を変えることで送信する電力を変化させます。

PWMの仕組み

LEDの点灯にPWMを使うと、1になっている時間が短いと人間の目にはLEDが暗くなったように見え、時間が長いと明るく見えます。

PWMを使う場合、2つの値を指定します。

  • パルスの周期
  • デューティー比

ESP-WROOM-32をArduino IDEでプログラムする場合、LEDCライブラリを使ってPWMを制御します。LEDCでは上記2つの値を指定するために3つの値を使います。

  • パルスの周期(Hzで指定)
  •  1周期に含まれる目盛の数(ビット数で指定。10bitなら1024目盛。最大は16bit。)
  • 1になっている時間の長さ(上記の目盛で指定。10bit目盛の場合は0〜1023の値。)

また、LEDCではどのチャンネルを使うかを指定します。チャンネルは0〜15の16個あります。

LEDCライブラリのパラメータ

LEDの明るさを制御するプログラム例

LEDをだんだん明るくし、輝度が最大になったら、今度はだんだん暗くする動作を繰り返すプログラムです。setup( )関数内のledcSetup( )関数でパラメータを設定し、ledcAttachPin( )関数で使用するピンを指定しています。loop( )関数内では、ledcWrite( )関数でLEDの明るさを変更しています。

#define PIN 23

// LEDCのパラメータ設定
//   LEDC_CHANNEL        : チャンネル : 0
//   LEDC_RESOLUTION_BITS: 目盛数    : 10bit (0〜1023)
//   LEDC_FREQUENCY  : 周波数    : 50Hz (= 20ms周期)
#define LEDC_CHANNEL 0
#define LEDC_RESOLUTION_BITS 10
#define LEDC_FREQUENCY 50

const int32_t min = 0;
const int32_t max = 1023;
const int32_t delta = 32;
int32_t i;

void setup() {
  Serial.print("PIN = ");
  Serial.println(PIN);
  ledcSetup(LEDC_CHANNEL, LEDC_FREQUENCY, LEDC_RESOLUTION_BITS);
  ledcAttachPin(PIN, LEDC_CHANNEL);
}

void loop() {
  for (i = min; i < max; i += delta) {
    ledcWrite(LEDC_CHANNEL, (uint32_t)i);
    delay(50);
  }
  for (i = max; i > min; i -= delta) {
    ledcWrite(LEDC_CHANNEL, (uint32_t)i);
    delay(50);
  }
}

関連記事

[Nefry BTとGrove接続実験] LEDソケット+LED(赤、青、緑)

[Nefry BTとGrove接続実験] LEDソケット+LED(赤、青、緑)

LEDモジュール

私が購入したGROVEスターターキットV3に入っていたLEDモジュールは、LED Socket Kit v1.4というモジュールです。スイッチサイエンスさんの単体販売ページに掲載されているものとは、基板部分は同じですが、付属するLEDの個数に違いがあります。スイッチサイエンスさんで販売されているものはLEDが1個しかついていませんが、GROVEスターターキットV3には赤、青、緑の3種類のLEDが付いています。

Grove LEDモジュールとLED3種
GroveLEDモジュール

基板の右下にあるのがLEDを挿すソケットです。右上にあるの黄色いプラスチックが付いた箱はLEDの明るさを調整する可変抵抗です。黄色い部分をドライバで回して明るさを調整します。

Grove LEDモジュール(裏)

LEDモジュールの動作

1(HIGH)を送るとLEDが点灯し、0(LOW)を送るとLEDが消灯します。LEDの明るさは基板についている可変抵抗で調整できるようになっています。LEDが暗い時や点灯しない時は可変抵抗を回してみてください。

LEDをソケットに挿す際に、LEDの極性を合わせる必要があります。通常は足の長い方がプラスですが、足の長さが同じでどちらかわからない場合は LED の形状で判断します。

LEDの極性

円の一部分が欠けて直線になっている方がマイナスです。モジュールのLEDソケット部にも円が欠けている絵が描いてあるので、それに合わせてLEDを差し込みます。

プログラム

// Nefry BT無印の場合: D2, A0, A2 (注:D0は使えません)
// Nefry BT R2の場合: D0, D2, D5, A1  (注:A0を使うときはA1を記載します。)
#define PIN D2

void setup() {
  pinMode(PIN, OUTPUT);
  Serial.print("PIN = ");
  Serial.println(PIN);
}

void loop() {
  digitalWrite(PIN, HIGH);
  Serial.println(HIGH);
  delay(1000);

  digitalWrite(PIN, LOW);
  Serial.println(LOW);
  delay(1000);
}

1秒ごとに点灯、消灯を繰り返すプログラムです。digitalWrite(ピン, 設定値) を使ってHIGHとLOWを交互に設定しています。

LEDの明るさを変化させるプログラム

PWM(Pulse Width Modulation)を使って明るさを変化させます。Nefry BTでPWMを使う場合は、LEDCライブラリを使います。PWMとLEDCライブラリについては別記事に解説を書いていますので参照ください。

//GROVEケーブルを接続するGROVEコネクターを1つ選んで#define文に記載してください。
// Nefry BT無印の場合: D2, A0, A2 (注:D0は使えません)
// Nefry BT R2の場合: D0, D2, D5, A1  (注:A0を使うときはA1を記載します)
#define PIN D2

// LEDCのパラメータ設定
//   LEDC_CHANNEL        : チャンネル : 0
//   LEDC_RESOLUTION_BITS: 目盛数    : 10bit (0〜1023)
//   LEDC_FREQUENCY  : 周波数    : 50Hz (= 20ms周期)
#define LEDC_CHANNEL 0
#define LEDC_RESOLUTION_BITS 10
#define LEDC_FREQUENCY 50

const int32_t min = 0;
const int32_t max = 1023;
const int32_t delta = 32;
int32_t i;

void setup() {
  Serial.print("PIN = ");
  Serial.println(PIN);
  ledcSetup(LEDC_CHANNEL, LEDC_FREQUENCY, LEDC_RESOLUTION_BITS);
  ledcAttachPin(PIN, LEDC_CHANNEL);
}

void loop() {
  for (i = min; i < max; i += delta) {
    ledcWrite(LEDC_CHANNEL, (uint32_t)i);
    delay(50);
  }
  for (i = max; i > min; i -= delta) {
    ledcWrite(LEDC_CHANNEL, (uint32_t)i);
    delay(50);
  }
}

LEDをだんだん明るくし、輝度が最大になったら、今度はだんだん暗くする動作を繰り返すプログラムです。setup( )関数内のledcSetup( )関数でパラメータを設定し、ledcAttachPin( )関数で使用するピンを指定しています。loop( )関数内では、ledcWrite( )関数でLEDの明るさを変更しています。

諸元

名称LED Socket Kit
リレー
バージョンv1.4
Seeed社 Wikihttp://wiki.seeedstudio.com/Grove-LED_Socket_Kit/
スイッチサイエンス商品ページhttps://www.switch-science.com/catalog/1251/
Nefry BT無印 動作ソケットD2, A0, A2
Nefry BT R2 動作ソケットD0, D2, D5, A0(プログラム上はA1)

「Nefry BTとGroveモジュール接続実験」 トップページ

 

[Nefry BTとGrove接続実験] 温度センサ

温度センサモジュール

私が購入したGROVEスターターキットV3に入っていた温度センサモジュールは、Temperature Sensor V1.2というモジュールです。スイッチサイエンスさんの単体販売ページに掲載されているものと同じです。

Grove温度センサ
Grove温度センサ(裏)

温度センサモジュールの動作

温度センサモジュールはアナログモジュールです。温度の高い低いに応じて出力される電圧が変化します。analogRead(PIN)関数を使うと電圧の高さが0〜4095の数値として得られます。この数値だと何度かわからないので、数値を温度に変換するプログラムが必要になります。変換方法は、Groveモジュールの販売サイトや、Groveモジュールで使用している温度センサ部品のサイトに掲載されていますが、かなり難解です。Groveモジュールを使うだけなら、販売店サイトで公開されているプログラムを利用するのが手軽です。

プログラム

ここではSeeed Studio社の商品紹介ページにあるArduino用のプログラムを使ってみます。

#include <math.h>
const int B = 4275;           // B value of the thermistor
const int R0 = 100000;        // R0 = 100k
const int pinTempSensor = A5; // Grove - Temperature Sensor connect to A5

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  int a = analogRead(pinTempSensor);

  float R = 1023.0/a-1.0;
  R = R0*R;

  // convert to temperature via datasheet
  float temperature = 1.0/(log(R/R0)/B+1/298.15)-273.15;

  Serial.print("temperature = ");
  Serial.println(temperature);

  delay(100);
}

このプログラムをNefry BT用に変更します。

  1. pinTempSensorA5をNefry BT 無印の場合はA2に変更します。Nefry BT R2の場合はA1に変更してください。
  2. Serial.begin(9600); は不要なので削除します。
  3. pinMode( )関数がなくても動作しますが、念のためpinMode(pinTermpSensor, INPUT);を追加します。
  4. aanalogRead(pinTempSensor)で取得した値です。ArduinoのanalogRead( )関数は0〜1023の値を返しますが、Nefry BTのanalogRead( )関数は0〜4095の値を返すので、1023.0となっている部分を4095.0に変更します。

この変更を加えたプログラムは次のようになります。

#include <math.h>
const int B = 4275;           // B value of the thermistor
const int R0 = 100000;        // R0 = 100k
const int pinTempSensor = A1; // Grove - Temperature Sensor connect to A1

void setup()
{
  pinMode(pinTempSensor, INPUT);
}

void loop()
{
  int a = analogRead(pinTempSensor);

  float R = 4095.0/a-1.0;
  R = R0*R;

  // convert to temperature via datasheet
  float temperature = 1.0/(log(R/R0)/B+1/298.15)-273.15;

  Serial.print("temperature = ");
  Serial.println(temperature);

  delay(100);
}

 

このプログラムを動作させると、シリアルモニタに次のような結果が出力されます。

温度計測定値のシリアルモニタ出力例

なんとなくそれらしい温度が表示されていますが、Arduinoにこの温度センサーを接続した時より1〜2度低いようです。Arduinoのプログラムは5Vでの動作を前提としているので、3.3Vだと少し定数の変更が必要なのかもしれません。

諸元

名称Temperature Sensor
温度センサ
バージョンV1.2
Seeed社 Wikihttp://wiki.seeedstudio.com/Grove-Temperature_Sensor_V1.2/
スイッチサイエンス商品ページhttps://www.switch-science.com/catalog/806/
Nefry BT無印 動作ソケットA2
Nefry BT R2 動作ソケットA0(プログラム上はA1)

「Nefry BTとGroveモジュール接続実験」 トップページ

[Nefry BTとGrove接続実験] ボリューム

ボリュームモジュール(可変抵抗モジュール)

私が購入したGROVEスターターキットV3に入っていたボリュームは、Rotary Angle Sensor V1.2 というモジュールです。スイッチサイエンスさんの単体販売ページの中央に写っているものと同じです。同じページの右上の画像のモジュールはボリュームパーツが若干異なるようです。

Groveボリュームモジュール(表)
Groveボリュームモジュール(裏)

ボリュームモジュールの動作

ボリュームモジュールはアナログモジュールです。3.3Vの電源に接続している場合、ノブを回すと0Vから3.3Vまで電圧が連続的に変化します。ノブを時計回りにいっぱい回すと0Vで反時計回りにいっぱい回すと3.3Vが出力されます。なんとなく逆のイメージがありますが、このような動作になっています。

プログラム

ボリュームモジュールから読み込んだ値をシリアルコンソールに表示するプログラムです。値の読み込みはanalogRead(PIN)関数で行なっています。

#include <Nefry.h>
//Groveケーブルを接続するGroveソケットを1つ選んで#define文に記載してください。
// Nefry BT無印の場合: D0, D2, A0, A2
// Nefry BT R2の場合: D0, D2, D5, A1 (注:A0を使うときはA1を記載します。)
#define PIN A1

void setup() {
  pinMode(PIN, INPUT);
}

void loop() {
  Serial.println(analogRead(PIN));
  delay(300);
}

プログラムを動作させノブを左右に回すとこのように0〜4095の数字が表示されます。右にいっぱい回すと0、左にいっぱい回すと4095が表示されます。

コンソール出力例

 

Groveソケットごとの動作状況

4箇所のGroveソケットにボリュームモジュールを順に接続して、動作をテストしてみました。

Nefry BT 無印の場合はこうなります。

GROVEソケット名動作状況コメント
D0NOボリュームを接続した状態だとNefry BTが起動しない。起動してから接続すると、常に4095が表示される。
D2NO常に0が表示される。
A0NO常に4095が表示される。
A2OK

Nefry BT R2の場合はこうなります。

GROVEソケット名動作状況コメント
D0NO常に0が表示される。
D2NO常に0が表示される。
D5NO常に4095が表示される。
A0OKプログラムでは、A0ではなくA1を使う。

Nery BT無印ではA2だけ、Nefry BT R2ではA0だけ使えるという結果になりましたが、これには理由があります。

0〜3.3Vの電圧を0〜4095の数値に変換する作業はADC(Analog Digital Converter)が行います。Nefry BTのCPUであるESP-WROOM-32には2系統のADCがありADC1、ADC2と呼ばれています。ADCが使えるGPIOピンは決まっています。

GPIO番号無印 Groveソケット名無印 PIN名R2 Groveソケット名R2 PIN名ADC1ADC2
GPIO0ADC2_CH1
GPIO2ADC2_CH0
GPIO4ADC2_CH2
GPIO12ADC2__CH5
GPIO13A6D7ADC2_CH4
GPIO14A5D8ADC2_CH6
GPIO15ADC2_CH3
GPIO25A0A0D5D5ADC2_CH8
GPIO26A1D6ADC2_CH9
GPIO27A4T4(基板裏)ADC2_CH7
GPIO32A2A2A0A1ADC1_CH4
GPIO33A3A0ADC1_CH5
GPIO34ADC1_CH6
GPIO35A7ADC1_CH7
GPIO36A3ADC1_CH0
GPIO39A2ADC1_CH3

Nefry BT無印のGroveソケットでは、A2でADC1が、A0でADC2が使えることになりますが、A2は動作しますが、A0は動作しません。同様にNefry BT R2のGroveソケットでは、A0でADC1が、D5でADC2が使えることになりますが、A0は動作しますがD5は動作しません。これは、

Wifiが動作しているときはADC2は使えない

という制限がESP-WROOM-32にあるためです。詳しくはESP-IDF Programming GuideのADCの項を参照してください。

Wifiを止めればNefry BT無印のA0とNefry BT R2のD5も使えると思いますが、まだ実験していません。

ADC1は、Nefry BT無印のピンソケットA2、 A3、A7や、Nefry BT R2のピンソケットA0、A1、A2、A3にも接続されているので使えると思いますが、こちらもまだ実験していません。

諸元

名称Rotary Angle Sensor
ボリューム
バージョンv1.2
Seeed社 Wikihttp://wiki.seeedstudio.com/Grove-Rotary_Angle_Sensor/
スイッチサイエンス商品ページhttps://www.switch-science.com/catalog/805/
Nefry BT無印 動作ソケットA2
Nefry BT R2 動作ソケットA0(プログラム上はA1)

参考文献

ESP-IDF Programming Guide – ADC

スイッチサイエンスの記事 「ESP-WROOM-32に関するTIPS」のADCの項

 


「Nefry BTとGroveモジュール接続実験」 トップページ

[Nefry BTとGrove接続実験] ボタンとタッチセンサ

ボタンモジュール

私が購入したGROVEスターターキットV3に入っていたボタンは、Button V1.1というモジュールです。現在スイッチサイエンスさんで単体で販売されているボタンモジュールとは、使われているボタン部品が違ったり、ネジ止め用の穴に対する端子の位置が90度異なるなど違いがありますが、動作は同じだと考えられます。

Groveボタン
Groveボタン(裏)

タッチセンサモジュール

タッチセンサはTouch v1.1です。こちらもスイッチサイエンスさんで販売されているタッチセンサとは、ネジ止め用の穴に対する端子の位置が90度異なります。

Groveタッチセンサ
Groveタッチセンサ(裏)

ボタンとタッチセンサの働き

ボタンとタッチセンサはデジタルモジュールです。ボタンが押されていない(タッチセンサに触れていない)状態では0(LOW)を返し、押されている(触れている)状態では1(HIGH)を返します。

プログラム

シリアルモニタに、通常は0が表示され、ボタンを押している間(タッチセンサの場合は指で触れている間)だけ1が表示されるプログラムです。モジュールを接続するGroveソケットに合わせて、PINの#define文で指定してください。

//Groveケーブルを接続するGroveソケットを1つ選んで#define文に記載してください。
// Nefry BT無印の場合: D0, D2, A0, A2
// Nefry BT R2の場合: D0, D2, D5, A1 (注:A0を使うときはA1を記載します。)
#define PIN D2

void setup() {
  pinMode(PIN, INPUT);
  Serial.print("PIN = ");
  Serial.println(PIN);
}

void loop() {
  Serial.println(digitalRead(PIN));
  delay(300);
}

Nefry BT 無印のGroveソケットの名前は下記のようになっています。

Nefry BT無印のGroveソケット名

Nefry BT R2のGroveソケットの名前は下記のようになっています。

Nefry BT R2のGroveソケット名

A0ソケットを使う場合は、プログラム上ではA1を指定してください。これは、Nefry BT R2の配線がA0とA1が入れ違っているためです。

状態の取得は、digitalRead(PIN )関数で行います。ボタン(あるいはタッチセンサ)の状態が0あるいは1で返ってきます。

プログラムを動作させるとシリアルモニタにこのように表示されます。ボタンを押している間は1が表示されます。

シリアルモニタの出力例

Groveソケットごとの動作状況

4箇所のGroveソケットにボタンを順に接続して、動作をテストしてみました。タッチセンサの場合も同じ結果になります。

Nefry BT無印でのテスト結果はこうなりました。

GROVEソケット名動作状況コメント
I2C(D0)NO液晶ディスプレイとピンを共有しているため動作しません。またソケットにボタンモジュールをつないでいるとNefry BTが起動しません。
D2OK
A0OK
A2OK

 

Nefry BT R2でのテスト結果はこうなりました。

GROVEソケット名動作状況コメント
D0OK
D2OK
D5OK
A2OKプログラムではA0の代わりにA1を指定する

Nefry BT R2のGroveソケットA0は、実際にはA1が配線されているため、プログラムでピンを指定するときA1を指定します。

ピンソケットの利用

Nefry BTにはGroveソケット以外にピンソケットも用意されています。変換ケーブルを使うとGroveモジュールをピンソケットに接続できます。スイッチサイエンスさんにはこんな変換ケーブルがあります。

Grove先ばらケーブル

先端がメスになっているのでオス – オスのジャンパーケーブルを接続して使います。

ケーブルは4本の線があり、ボタンとタッチセンサでは次のように機能が割り振られています。

黒:GRD
赤;VCC
白:未接続
黄:信号

ピンソケットを使う場合は、赤を3.3V、黒をGND、黄色をGPIOソケットに接続します。

Nefry BT 無印のピンソケットの配置は下図のようになっています。

Nefry BT無印のピンソケット配置図

 

 

Nefry BT R2のピンソケットの配置は下図のようになっています。

Nefry BT R2のピンソケット配置図

ピンソケットの動作状況

ボタンを順に接続して、動作をテストしてみました。タッチセンサの場合も同じ結果になります。D0, D1以外のピンソケットで動作しました。

Nefry BT無印でのテスト結果はこうなりました。

ピンソケット動作状況コメント
D0NO液晶ディスプレイと共用のため
D1NO液晶ディスプレイと共用のため
D2OK
D3OK
D4OK
A0OK
A1OK
A2OK
A3OK
A4OK
A5OK
A6OK
A7OK

Nefry BT R2でのテスト結果はこうなりました。全てのピンソケットで動作しました。

ピンソケット動作状況コメント
D0OK
D1OK
D2OK
D3OK
D4OK
D5OK
D6OK
D7OK
D8OK
A0OK
A1OK
A2OK
A3OK

動作テストに使用したプログラムはこちらです。

// Nefry BT無印の場合: D0,D1,D2,D3,D4,A0,A1,A2,A3,A4,A5,A6,A7 
// Nefry BT R2の場合: D0,D1,D2,D3,D4,D5,D6,D7,D8,A0,A1,A2,A3 
#define PIN D2

void setup() {
  pinMode(PIN, INPUT);
  Serial.print("PIN = ");
  Serial.println(PIN);
}

void loop() {
  Serial.println(digitalRead(PIN));
  delay(300);
}

諸元

ボタンの諸元

名称Button
ボタン
バージョンv1.1
Seeed社 Wikihttp://wiki.seeedstudio.com/Grove-Button/
スイッチサイエンス商品ページhttps://www.switch-science.com/catalog/801/
Nefry BT無印 動作ソケットD2, A0, A2
Nefry BT R2 動作ソケットD0, D2, D5, A0(プログラム上はA1)

タッチセンサの諸元

名称Button
ボタン
バージョンv1.1
Seeed社 Wikihttp://wiki.seeedstudio.com/Grove-Touch_Sensor/
スイッチサイエンス商品ページhttps://www.switch-science.com/catalog/811/
Nefry BT無印 動作ソケットD2, A0, A2
Nefry BT R2 動作ソケットD0, D2, D5, A0(プログラム上はA1)

「Nefry BTとGroveモジュール接続実験」 トップページ