Pythonロボティクスコース レッスン 16 *
テーマ.4-3 電子ギターの制作
赤外線フォトリフレクタとカラーセンサーを使って電子楽器をつくろう
チャプター1
このレッスンで学ぶこと
このレッスンでは、「赤外線フォトリフレクタ」と「カラーセンサー」の2つのセンサーの使用してブザーを制御する電子ギターを制作します。
チャプター2
新しいPython文法の学習
今回の電子ギターの制作で新しく学習するPythonの文法はありません。
チャプター3
電子ギターの組み立て
組立説明書を開き、手順に沿って電子ギターを組み立てましょう。
3. 1 組み立てに必要なパーツ
- Studuino:bit×1
- ロボット拡張ユニット×1
- 電池ボックス×1
- 赤外線フォトリフレクタ×1
- カラーセンサー×1
- センサー接続コード(3芯15cm)×1
- センサー接続コード(4芯30cm)×1
- ブロック基本四角(白)×2
- ブロック基本四角(黒)×2
- ブロック基本四角(グレー)×4
- ブロック基本四角(赤)×4
- ブロックハーフC(白)×4
- ブロックハーフD(白)×5
- ステー×3
【 アーテックブロックの形状 】
【 電子ギターの組み立て説明書 】
チャプター4
電子ギターのプログラム作成
これから製作する電子ギターは次の機能を備えています。
- スライダーを動かして、鳴らす音の高さを決める
- ピックに見立てたカラーブロックを弾くように動かすと1で決めた高さで音が鳴る
これらの機能を順番に実装して、電子ギターのプログラムを完成させましょう。
4. 1 スライダーの位置で鳴らす音の高さを決める機能の作成
はじめに、スライダーを動かして、ブザーから鳴らす音の高さを決めるところまでのコードを書きましょう。
■ スライダーの位置をセンサーで調べる
スライダーの位置は赤外線フォトリフレクタで調べます。テーマ.3-1で赤外線フォトリフレクタが赤外線の反射光の強さを検出していることを学びましたが、この強さを表す値から正面の物体とのおおよその距離も判断することができます。
※超音波距離センサーと違い、直接クラスのメソッドでcm単位付きの距離が取得できるわけではないことに注意してください。
実際に以下のコードを実行して、スライダーの位置と赤外線フォトリフレクタの値の関係を調べます。また、調べた値は後で使うため、ノートなどにメモを取っておきましょう。
from pyatcrobo2.parts import IRPhotoReflector
import time
ir = IRPhotoReflector('P0')
while True:
print(ir.get_value())
time.sleep_ms(1000)
スライダーの位置は、赤外線フォトリフレクタ側の面を基準にして、次の7つの区間に分け、それぞれの区間に対して音を割り当てます。それぞれの区間の境界にスライダーを移動させ、値を確認しましょう。
【 区間1と区間2の境界の値 】
【 区間2と区間3の境界の値 】
【 区間3と区間4の境界の値 】
【 区間4と区間5の境界の値 】
【 区間5と区間6の境界の値 】
【 区間6と区間7の境界の値 】
■ スライダーの位置で音の高さを決める
上で調べた境界値で条件を分け、各区間に音を割り当てます。赤外線フォトリフレクタの値を引数に取り、対応する音を返す次の関数get_tone(value)
を作成しましょう。
※赤外線フォトリフレクタの値は個体によって差があるため、必ずしも下のサンプルコードと同じ条件分けでうまく動作するわけではないことに注意してください。
変更・追加【6行目~21行目】
from pyatcrobo2.parts import IRPhotoReflector
import time
ir = IRPhotoReflector('P0')
def get_tone(value):
if value > 1230: #区間1と区間2の境界の値
tone = 'B4'
elif value > 770: #区間2と区間3の境界の値
tone = 'A4'
elif value > 550: #区間3と区間4の境界の値
tone = 'G4'
elif value > 415: #区間4と区間5の境界の値
tone = 'F4'
elif value > 340: #区間5と区間6の境界の値
tone = 'E4'
elif value > 130: #区間6と区間7の境界の値
tone = 'D4'
else:
tone = 'C4'
return tone
while True:
print(ir.get_value())
time.sleep_ms(1000)
次に、赤外線フォトリフレクタの値を取得し、関数get_tone()
から返ってきた音名をLEDディスプレイに表示するコードを追加します。LEDディスプレイには1文字しか表示できないため、音名の先頭のアルファベットだけを表示します。
【 サンプルコード 4-1-1 】
変更・追加【1行目~2行目、25行目~26行目】
from pystubit.board import display
from pyatcrobo2.parts import IRPhotoReflector
import time
ir = IRPhotoReflector('P0')
def get_tone(value):
if value > 1230:
tone = 'B4'
elif value > 770:
tone = 'A4'
elif value > 550:
tone = 'G4'
elif value > 415:
tone = 'F4'
elif value > 340:
tone = 'E4'
elif value > 130:
tone = 'D4'
else:
tone = 'C4'
return tone
while True:
tone = get_tone(ir.get_value())
display.show(tone[0], delay=0, clear=False)
# 文字列もタプルやリストと同様にインデックスを指定して要素を取得することができます。
# そのため、tone[0]で音名の先頭文字を取得できます。
ここまでのプログラムを実行し、スライダーの位置を変えたとき、LEDディスプレイに表示された音名が意図した通りになっていることを確認しましょう。
4. 2 ピックを弾くように動かすと音を鳴らす機能の作成
青色のブロックをギターピックに見立てて弾くように動かし、カラーセンサーの前を通過させると、ブザーから音が鳴るようにコードを追加していきます。
■ カラーセンサーの値を調べる
まず、青色のブロックが正面にあるときのカラーセンサーの値を調べましょう。
カラーセンサーはLEDディスプレイの光の影響を受けてしまいます。そのため、LEDの明るさはできるだけ抑えておく必要があります。次のようにコードを追加して、実行してみましょう。
変更・追加【2行目、6行目、27行目~29行目】
from pystubit.board import display
from pyatcrobo2.parts import IRPhotoReflector, ColorSensor
import time
ir = IRPhotoReflector('P0')
cs = ColorSensor('I2C')
def get_tone(value):
if value > 1230:
tone = 'B4'
elif value > 770:
tone = 'A4'
elif value > 550:
tone = 'G4'
elif value > 415:
tone = 'F4'
elif value > 340:
tone = 'E4'
elif value > 130:
tone = 'D4'
else:
tone = 'C4'
return tone
while True:
tone = get_tone(ir.get_value())
display.show(tone[0], delay=0, clear=False, color=(5, 0, 0)) # LEDの明るさを抑えるために、color=(5, 0, 0)を追加しています。
print(cs.get_values())
time.sleep_ms(500)
テーマ.3-1では、カラーセンサーで取得する情報は(R値, G値, B値, 明るさ値)からなるタプルで表されることを説明しました。ターミナルに表示されたデータから青色のブロックが正面にあると判断するための基準値を決めておきましょう。
【 正面に青色のブロックがあるとき 】
[43, 32, 44, 31]
【 正面になにもないとき 】
[31, 15, 10, 56]
例えば上記のような結果となった場合、10~44の範囲の中間を基準値として定めると、青色のブロックがセンサーの正面を通過したことが検知できます。この決めた基準値を使い、青色のブロックが通過すると、そのときのスライダーの位置で決められた高さの音を600ミリ秒間鳴らすようにコードを変更しましょう。
変更【1行目、28~30行目】
from pystubit.board import display, buzzer
from pyatcrobo2.parts import IRPhotoReflector, ColorSensor
import time
ir = IRPhotoReflector('P0')
cs = ColorSensor('I2C')
def get_tone(value):
if value > 1230:
tone = 'B4'
elif value > 770:
tone = 'A4'
elif value > 550:
tone = 'G4'
elif value > 415:
tone = 'F4'
elif value > 340:
tone = 'E4'
elif value > 130:
tone = 'D4'
else:
tone = 'C4'
return tone
while True:
tone = get_tone(ir.get_value())
display.show(tone[0], delay=0, clear=False, color=(5, 0, 0))
cs_values = cs.get_values()
if cs_values[2] > 30: # 決めた基準値で条件式をつくります。
buzzer.on(tone, duration=600)
これで最初に挙げた2つの機能が入ったプログラムができました。しかし、このプログラムには1つだけ落とし穴があります。それは、StuduinoBitDisplayクラスのshow()
メソッドやscrollメソッド()
は他のクラスのメソッドやPythonの標準関数と比べて、処理が重く、高速で何度も繰り返し実行すると大きな負荷がかかることです。この理由で、以下のようなプログラムを組むと、センサーの値の取得に遅れが発生します。
from pystubit.board import display, lightsensor
while True:
display.show('C', delay=0)
value = lightsensor.get_value()
そこで、前の時点から音名が変更された場合のみ、LEDディスプレイの表示を変えるようにプログラムを改善します。
新たに変数current_tone
を用意し、現在選択されている音名を記録します。この変数current_tone
と現在の赤外線フォトリフクタの値で選ばれた音名が入っている変数tone
を比較し、異なっている場合だけ、StuduinoBitDisplayクラスのshow()メソッド
を呼び出すようにします。
【 サンプルコード 4-2-1 】
変更・追加【26行目、30~32行目】
from pystubit.board import display, buzzer
from pyatcrobo2.parts import IRPhotoReflector, ColorSensor
import time
ir = IRPhotoReflector('P0')
cs = ColorSensor('I2C')
def get_tone(value):
if value > 1230:
tone = 'B4'
elif value > 770:
tone = 'A4'
elif value > 550:
tone = 'G4'
elif value > 415:
tone = 'F4'
elif value > 340:
tone = 'E4'
elif value > 130:
tone = 'D4'
else:
tone = 'C4'
return tone
current_tone = '' # currentは英語で「現在の」という意味を表します。
# 始めは空の文字列を入れておきましょう。
while True:
tone = get_tone(ir.get_value())
if current_tone != tone: # 現在選択されている音名と現在の赤外線フォトリフレクタの値から選ばれている音名を比較します。
display.show(tone[0], delay=0, clear=False, color=(5, 0, 0))
current_tone = tone # 変更があった場合は、これを現在の音名として記録しておきます。
cs_values = cs.get_values()
if cs_values[2] > 30:
buzzer.on(tone, duration=600)
これでプログラムの完成です。実行して動作を確認しましょう。
チャプター5
課題:電子ギターの傾きによって鳴る音の長さを変える
テーマ.4-1で制作した電子マラカスで、ボタンを押すと曲のテンポが変わる機能を作成しましたが、ここでは課題として、電子ギターの傾きで鳴らす音の長さを変える機能を追加してみましょう。
電子ギターの傾きは、加速度センサーのY軸の値で判別できます。このY軸の値がそれぞれ次の範囲にあるときに、対応した長さで音を鳴らすようにします。この加速度センサーのY軸方向の値は、StuduinoBitAccelerometerクラスのget_y()
メソッドで取得できます。
- 「Y軸方向の加速度 < -8.5」: 150ミリ秒
- 「Y軸方向の加速度 >= -8.5」 and 「 Y軸方向の加速度 < -4.9」: 300ミリ秒
- 「Y軸方向の加速度 >= 4.9」: 600ミリ秒
5. 1 プログラムの作成例
変数length
を用意して、buzzer.on()
で鳴らす音の長さを指定します。そして、この変数length
の値は、Y軸方向の加速度から決めるようにします。この2点を【 サンプルコード 4-2-1 】に書き加えると、上記の機能が実現できます。
変更・追加【1行目、34~40行目、44行目】
from pystubit.board import display, buzzer, accelerometer
from pyatcrobo2.parts import IRPhotoReflector, ColorSensor
import time
ir = IRPhotoReflector('P0')
cs = ColorSensor('I2C')
def get_tone(value):
if value > 1230:
tone = 'B4'
elif value > 770:
tone = 'A4'
elif value > 550:
tone = 'G4'
elif value > 415:
tone = 'F4'
elif value > 340:
tone = 'E4'
elif value > 130:
tone = 'D4'
else:
tone = 'C4'
return tone
current_tone = ''
while True:
tone = get_tone(ir.get_value())
if current_tone != tone:
display.show(tone[0], delay=0, clear=False, color=(5, 0, 0))
current_tone = tone
accel_y = accelerometer.get_y()
if accel_y < -8.5:
length = 150 # 変数lengthを用意して、音の長さを記録します。
elif accel_y < -4.9:
length = 300
else:
length = 600
cs_values = cs.get_values()
if cs_values[2] > 30:
buzzer.on(tone, duration=length) # 数値を直接入れる代わりに変数lengthで時間を指定します。
チャプター6
おわりに
6. 1 このレッスンのまとめ
このレッスンでは新たに次のことを学習しました。
- 赤外線フォトリフレクタの値からおおよその距離(位置)を調べる方法
- カラーセンサーを利用して物体の通過を検知する方法
ただし、赤外線フォトリフレクタを利用した距離の計測は、赤外線を反射しにくい黒色の物体が対象となる場合は行えないこと、また、計測できる範囲が短く、およそ0.5cm~10cm程度であることを覚えておいてください。
6. 2 次のレッスンについて
次のレッスンでは、コンピュータでランダムに数字を発生させる乱数機能について学び、確率を利用して遊べるかみつきワニゲームを制作します。