文書の過去の版を表示しています。
Grove Beginner Kit for Arduino
Seeed社から販売されているこのキットはArduinoの初学に以下の点で優れています.
- 温度や加速度センサ,マイクや照度センサなどたくさんのセンサが一つにまとまっている
- ケーブルとgroveケーブルが最初から付属している
- パッケージに入れながら使える
- 安い
- 使い方になれてきたらGroveモジュールを個別に使ってプロトタイプ開発も始められる
- マニュアルが充実( wikiがあって,一つひとつ丁寧に作られている)
- arduino自体は最も一般的なarduino UNOとして利用できる
一方で,サーボモータやBLEがないなど,惜しいところもありますが,初学用としては十分だと言えます. 購入先はamazonやswitchscienceで購入できます.
このページでは実際にseeed社が提供しているwikiに従って入門を行った場合に必要な補足すべき情報をまとめておきます.まずは以下の公式リンクから進めていきましょう
Groveとは
Seeed社が昔から販売しているArduinoなどのオープンソースハードウェアで利用可能なセンサモジュールの商品名です.特徴としてはセンサとの接続はGroveコネクタと呼ばれる一般的な4芯の基盤実装コネクタを利用することで,ブレッドボードやはんだ付けを不要としている点です.今回のbeginner kitに含まれるモジュール以外にも多くの種類があります.以下のリンクから現在販売されている種類が確認できます.
国内だとスイッチサイエンスのgroveカテゴリで探すとよいでしょう.
入門
1. LED
void setup() { pinMode(4, OUTPUT); // 4番ピンを出力モードに } void loop() { digitalWrite(4, HIGH); // 4番ピンをHIGH(5V)にする delay(1000); // 1秒待つ digitalWrite(4, LOW); // 4番ピンをLOW(0V)にする delay(1000); // 1秒待つ }
2. Buzzer
// 何ヘルツの音がなっていますか? void setup() { pinMode(5, OUTPUT); } void loop() { digitalWrite(5, HIGH); delay(10); digitalWrite(5, LOW); delay(10); }
// ド(523Hz),ソ(783Hz)を鳴らすサンプル void setup() { pinMode(5, OUTPUT); } void loop() { tone(5, 523, 100); delay(1000); tone(5, 783, 100); delay(1000); }
delay()のパラメータを変更することで任意の周波数の波形を出力することができました。ただし、決められた周波数を鳴らすために上記のようなコードを使っていると、たくさんの音を鳴らす場合少し面倒になります。そのため、Arduinoにはtone()関数が用意されています。
tone(pin, frequency) tone(pin, frequency, duration)
1つ目の引数にはスピーカーにつながっている制御ピン番号を。2つ目の引数には鳴らしたい周波数を指定します。もし鳴らす音の長さ(音長)を指定したい場合、3番目の引数にmilli second単位で値を指定します。例えば次のようなコードで二種類の異なる周波数を順番に鳴らすことが簡単にできます。
これは有名なドラマで使われていた効果音になります.なんだか分かる人はどのくらいいるでしょうか?
void setup() { pinMode(5, OUTPUT); } void loop() { tone(5, 2217, 70); delay(1000); tone(5, 1991, 70); delay(1000); }
// Reference: http://arms22.blog91.fc2.com/blog-entry-276.html void setup() { pinMode(5, OUTPUT); } void loop(void) { tone(5,690,25); delay(50); tone(5,690,30); delay(168); tone(5,690,23); delay(48); tone(5,690,30); delay(360); tone(5,970,25); delay(50); tone(5,970,30); delay(50); tone(5,970,30); delay(50); tone(5,970,30); delay(50); tone(5,487,30); delay(55); tone(5,487,30); delay(55); tone(5,487,30); delay(55); tone(6,487,30); delay(55); tone(5,487,30); delay(55); tone(5,487,30); delay(55); tone(5,487,30); delay(55); tone(5,487,30); delay(55); delay(1500); }
音階で音を鳴らしてみる
ON/OFFの感覚を狭くすることで、高い音が、広くすることで低い音がなることが確認できました。また、任意の周波数であればtone()関数を利用して簡単に音を鳴らすことができるのも確認できました。ではこれをもう少しわかりやすく、所謂ドレミファソラシド…といった音程にて再現できるようにしてみましょう。
まず最初の周波数と音高の関係ですが、ピアノの真ん中辺りの「ド」の音を鳴らし、一オクターブ上の「ド」を鳴らした場合を考えます。 最初に鳴らしたドの周波数を $f_1$とした場合、一オクターブ上のドは $f_2 = 2f_1$として表されます。つまり一オクターブ上の音は下の音の倍の周波数になっているわけです。このような関係をより数学的に表現したものが、十二平均律になります。オクターブ間に12の音程を均等に配置するものです。
ベースやギターの開放弦を利用した調律では440Hzを利用しますが、この音を基準(ピアノのラ)として、次の式で表すことで、440Hzのオクターブ上(12音上)は $ 440 \times 2^{\frac{12}{12}} = 880 $となります。
\[ f = 440 \times 2^{(n/12)} \]
ただし基準となる440Hzのラはノート番号では69番としているので、nが69のときに440Hzになるように式を下記のようにしておきます。 \[ f = 440 \times 2^{\frac{n-69}{12}} \]
ではここまでの準備を利用して、有名なNokia Tuneを鳴らしてみましょう。下記サイトを参考にします。
float getFreq(int n) { return 440.0*pow(2, (n-69)/12.0); } void setup() { pinMode(6, OUTPUT); } int interval = 250; void loop() { tone(6, getFreq(76), interval/2); delay(interval/2); tone(6, getFreq(74), interval/2); delay(interval/2); tone(6, getFreq(66), interval); delay(interval); tone(6, getFreq(68), interval); delay(interval); tone(6,getFreq(73), interval/2); delay(interval/2); tone(6, getFreq(71), interval/2); delay(interval/2); tone(6, getFreq(62), interval); delay(interval); tone(6, getFreq(64), interval); delay(interval); tone(6, getFreq(71), interval/2); delay(interval/2); tone(6, getFreq(69), interval/2); delay(interval/2); tone(6, getFreq(61), interval); delay(interval); tone(6, getFreq(64), interval); delay(interval); tone(6, getFreq(69), interval*2); delay(interval*4); delay(interval*4); }
余談
鳴らしたいノート番号を指定することでその周波数を計算することができますが、その逆である「鳴らしたい周波数が決まっている場合、それはピアノの鍵盤でいうところのどの位置になるのか?」を計算するには、方程式をnについてとけば良いです。
上記式を両辺に自然対数とることで簡単にnについて解くことができます。みなさんも実際に計算して確かめてみましょう。 \[ n = \frac{12 \times log_e(\frac{f}{440})}{log_e(2)} + 69 \]
3. OLED Display 0.96
Arduino Library Managerから U8g2 をインストールしてから,以下のコードを実行
#include <Arduino.h> #include <U8g2lib.h> #ifdef U8X8_HAVE_HW_SPI #include <SPI.h> #endif #ifdef U8X8_HAVE_HW_I2C #include <Wire.h> #endif U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // High speed I2C // U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); //Low spped I2C void setup(void) { u8g2.begin(); } void loop(void) { u8g2.clearBuffer(); // clear the internal memory u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font u8g2.drawStr(0,10,"Hello World!"); // write something to the internal memory u8g2.sendBuffer(); // transfer internal memory to the display delay(1000); }
4. Button
一般にスイッチにはいくつかの種類がありますが,まずは具体的に見てみます. もっとも安価なものに,タクタイルスイッチという部品があります.これは一般的にモーメンタリスイッチ と呼ばれるもので,押している間だけ内部の回路が通電する,というものです.下の回路図で試してみます. 一般的にタクタイルスイッチには電極が4つあります.内部的には単純に通電するかしないかなので,実際には 2本あれば十分です.これはタクタイルスイッチが様々な電子部品で利用される際,マトリクススキャン等の スイッチセンシングにおいて,電極がそれぞれ2つづつあると基盤的に都合が良いことが多いからです.
void setup() { pinMode(4, OUTPUT); pinMode(6, INPUT); } void loop() { int d = digitalRead(6); if( d == HIGH){ digitalWrite(4, HIGH); } else{ digitalWrite(4, LOW); } }
5. Rotary Potentiometer
ロータリーポテンショメーターとは回転式可変抵抗器のことを指します.つまみを回すと内部の接触点が代わり抵抗値が変化する部品です.A0ピンに接続されているので,この値を読み出してみます.ここではシリアルモニタ,シリアルプロッタの使い方も学習します.
void setup() { Serial.begin(9600); } void loop() { int a = analogRead(0); Serial.println(a); delay(33); }
6. Light
void setup() { Serial.begin(9600); } void loop() { int a = analogRead(6); Serial.println(a); delay(33); }
7. Sound
void setup() { Serial.begin(9600); } void loop() { int a = analogRead(2); Serial.println(a); delay(33); }
FFT
#include <arduinoFFT.h> #define SAMPLES 64 // サンプル数(2の累乗数) #define SAMPLING_FREQUENCY 1000 // サンプリング周波数 unsigned int sampling_period_us; unsigned long microseconds; double vReal[SAMPLES]; // 複素数の実部 double vImag[SAMPLES]; // 複素数の虚部 arduinoFFT FFT = arduinoFFT(); void setup() { Serial.begin(9600); sampling_period_us = round(1000000*(1.0/SAMPLING_FREQUENCY)); } void loop() { /* サンプリング */ for(int i=0; i<SAMPLES; i++) { microseconds = micros(); // サンプリング開始時間を取得 vReal[i] = analogRead(2); vImag[i] = 0; // 次のサンプリング時間まで待つ while(micros() - microseconds < sampling_period_us){ // wait } } /* FFT */ FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD); FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD); FFT.ComplexToMagnitude(vReal, vImag, SAMPLES); double peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY); /* 結果を出力 */ Serial.println(peak); // delay(1000); // 1秒間隔で解析 }
8. Temperature & Humidity Sensor
//Temperature and Humidity Sensor #include "DHT.h" #include <Arduino.h> #include <U8x8lib.h> #define DHTPIN 3 // what pin we're connected to #define DHTTYPE DHT11 // DHT 11 DHT dht(DHTPIN, DHTTYPE); U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); void setup(void) { Serial.begin(9600); Serial.println("DHTxx test!"); dht.begin(); u8x8.begin(); u8x8.setPowerSave(0); u8x8.setFlipMode(1); } void loop(void) { float temp, humi; temp = dht.readTemperature(); humi = dht.readHumidity(); u8x8.setFont(u8x8_font_chroma48medium8_r); u8x8.setCursor(0, 33); u8x8.print("Temp:"); u8x8.print(temp); u8x8.print("C"); u8x8.setCursor(0,50); u8x8.print("Humidity:"); u8x8.print(humi); u8x8.print("%"); u8x8.refreshDisplay(); delay(200); }
9. Air Pressure Sensor
Barometer Sensor BMP280 を追加する
//Air pressure detection #include "Seeed_BMP280.h" #include <Wire.h> BMP280 bmp280; void setup() { Serial.begin(9600); if (!bmp280.init()) { Serial.println("Device not connected or broken!"); } } void loop() { float pressure; //get and print temperatures Serial.print("Temp: "); Serial.print(bmp280.getTemperature()); Serial.println("C"); // The unit for Celsius because original arduino don't support speical symbols //get and print atmospheric pressure data Serial.print("Pressure: "); Serial.print(pressure = bmp280.getPressure()); Serial.println("Pa"); //get and print altitude data Serial.print("Altitude: "); Serial.print(bmp280.calcAltitude(pressure)); Serial.println("m"); Serial.println("\n");//add a line between output of different times. delay(1000); }