ラベル オシロ の投稿を表示しています。 すべての投稿を表示
ラベル オシロ の投稿を表示しています。 すべての投稿を表示

2014年2月9日日曜日

ハンディー踏切カンカンを作る(2/3):ArduinoのPWMで和音を出力

子どものクリスマスプレゼントに踏切カンカンのおもちゃを作ってあげるという記事が素敵だったので、自分でも同様のガジェットを作ってみることにしました。

※関連記事
ハンディー踏切カンカンを作る(1/3):まずは踏切の音程を調べる
ハンディー踏切カンカンを作る(2/3):ArduinoのPWMで和音を出力
ハンディー踏切カンカンを作る(3/3):市販のおもちゃにArduinoを内蔵させて完成

前回の記事では、西武線の踏切の音がドとミの和音であることを確認しました。今回はArduinoのPWMを使って、踏切の警報音を出力してみます。

Arduinoで音を出すには

Arduinoで音を鳴らすならtone関数が便利なのですが、tone関数は単一の周波数を出すだけなので、西武線の踏切のような和音は出力できません。そこで、和音を作ったうえでPWMを使って出力させることにしました。


音を出すための回路

Arduino Uno とブレッドボードを使って下記のような回路を組んでみました。なお、スピーカーの前にローパスフィルタ(抵抗とコンデンサ)を入れていますが、無くても音は変化しません。赤色LEDも入れていますが、本記事中ではまだ点灯させていません。




(備考) ローパスフィルタの部分はとりあえず手元にあった部品を使っています。カットオフ周波数 fc = 1/(2πRC) = 72kHzですから、PWM周波数の64kHzよりも大きく、パラメーターとしてはあまり良くないようです。※このあたりは現時点ではきちんと理解できていません。また後日に学びたいと思います。


和音を用意する

ド(523Hz)とミ(659Hz)の和音(2つの周波数を重ね合わせた波形)を作るために、それぞれの波形を矩形波(on-offの2値)と仮定しました。それぞれ波長としては約1900usecと約1500usec(だいたい 5:4)です。そこで、重ね合わせの波形は7600usec(=190usec×40)を単位として繰り返すと仮定することにしました。具体的に示すと下図のようになります。この和音(うなり)を基本単位とします。
和音:2つの波形を矩形波と仮定したときの「うなり」


Arduinoのプログラムを書くにあたって、上記の和音を配列として用意しておくことにします。
int kankan[]={2,2,2,2,1,0,0,0,1,1,2,2,1,1,1,0,1,1,1,1,1,1,1,1,2,1,1,1,0,0,1,1,2,2,2,1,0,0,0,0};

PWM (analogWrite関数) を使う

上記波形は単純なon-offの2値ではないので、中間の電圧を出力させるためにPWMを使うことにしました。しかし、デフォルトではPWMの周波数が500Hzなので、出力したい音よりも周波数が低く、音が出せません。そこでPWMの周波数を64kHz(または32kHz)に上げます。そのためには、Arduinoのプログラム内でsetupの中にPWMの設定を記入します(下記)。あとはanalogWrite関数を使うだけでPWM出力を使うことができます。

int speakerPin = 6;
int kankan[]={2,2,2,2,1,0,0,0,1,1,2,2,1,1,1,0,1,1,1,1,1,1,1,1,2,1,1,1,0,0,1,1,2,2,2,1,0,0,0,0};
//delayTimeは本当は190usec(5250Hz)程度になるはずだが、音程が合わないので適当に調整した。
int delayTime = 95;

void setup(){
  //スピーカーピンを出力モードにする
  pinMode(speakerPin, OUTPUT);
  //PWMを高速化する(今回は6番ピンを使った)
  TCCR0B = 0x01;   // PWM 6 & 5 @ 64 kHz
}

void loop(){
  // 警報音
  for(int i=0; i<64; i++){
    for(int j=0; j<40; j++){
      analogWrite(speakerPin, 120*kankan[j]);
      delayMicroseconds(delayTime);
    }
  }
  // 休み
  delay(10000);
}
ただし、上の波形をそのまま出力すると「カンカン」ではなく「ビービー」と聞こえます。これは、音の強弱がついていないためです。

音の強弱(エンベロープ)をつける

実際の踏切の警報音は、音の強弱(エンベロープ)があります。西武線の踏切音を録音して解析した結果、音の強弱は、(1)増大、(2)一定、(3)減衰、(4)ゆるやかに減衰、といったおおまかに4区間に分けられるようです(下記)。
踏切の警報音:音の強弱(エンベロープ)の様子

Arduinoのプログラムで上記の強弱(エンベロープ)を再現すると、下記のようになります。
//(これより上の部分は先ほどと同じ)

void loop(){
  //区間(1):増大
  for(int i=0; i<6; i++){
    for(int j=0; j<40; j++){
      analogWrite(speakerPin, (18*i+12)*kankan[j]);
      delayMicroseconds(delayTime);
    }
  }
  //区間(2):一定
  for(int i=0; i<10; i++){
    for(int j=0; j<40; j++){
      analogWrite(speakerPin, 120*kankan[j]);
      delayMicroseconds(delayTime);
    }
  }
  //区間(3):減衰
  for(int i=0; i<8; i++){
    for(int j=0; j<40; j++){
      analogWrite(speakerPin, (120-10*i)*kankan[j]);
      delayMicroseconds(delayTime);
    }
  }
  //区間(4):ゆるやかに減衰
  for(int i=0; i<40; i++){
    for(int j=0; j<40; j++){
      analogWrite(speakerPin, (40-i)*kankan[j]);
      delayMicroseconds(delayTime);
    }
  }
  // 休み
  delay(10000);
}
音の出力してみるとわかるのですが、エンベロープによって音の聞こえ方が全く変わってくるということを実感できます。


ふりかえり:本当に狙った出力になっているのか

ここでやったことをオシロスコープで確認します。オシロスコープはTektronixのTBS1022を使いました。まず、全体の波形は下記になります。黄色は6番ピンのPWM出力をそのまま表示、緑色はローパスフィルタを通過したあとの電圧変化です。緑色のほうに注目すると、音の強弱(エンベロープ)が確認できます。
「カン」の音全体 (横軸は1マスが50msec)

次に、拡大します。和音の基本単位が見えてきます。
音の立ち上がり部分 (横軸は1マスが10msec)

さらに拡大します。和音の基本単位がはっきり見えてきました。もともと設定した配列に対応していることがわかります。
「うなり」の基本単位 (横軸は1マスが10msec)

さらに拡大します。PWM(黄色)と出力波形(緑色)の対応が見えてきます。
PWMによる出力電圧変化 (横軸は1マスが100usec)

まとめ

  • 和音の「うなり」1つぶんを基本単位とした。
  • PWMを使った。ただし、PWMは高速化する必要がある。
  • 基本単位を元に、音の強弱(エンベロープ)をつけた。
この手順で、ある程度出したかった音が出せました。

最後に

先の記事のはじめの部分で
LED 2個を交互に点灯して「踏切チカチカ」にするのはビギナー過ぎるのですが、音をならして「踏切カンカン」にしようとすると、とたんにレベルが上がるような気がします。
と指摘されていたのですが、全くその通りだと思いました。これだけ苦労して踏切の「カンカン」という音を出せただけ、ですからね。

2014年1月26日日曜日

オシロスコープを使って赤外線リモコン信号を見る:受信波形と送信波形の違いについて

前回オシロスコープを購入したので、さっそく赤外線リモコンの信号を詳しく見てみることにしました。

使ったリモコン
EIZOのモニタについているリモコンを使用しました。とりあえず手元に一番近かったのでこれにしました。モニタの明るさ、入力切り替え、画質調整をするためのリモコンです。
EIZOのモニタとリモコン

赤外線受信時の波形
まず赤外線受信モジュールが載っている回路を作成(文献[1])したうえで、それぞれの電圧変化を計測することにしました。回路上の赤外線受信モジュールのGNDとVOUTにプローブを当てて、受信時の波形を計測しました。
赤外線受信モジュールの出力波形

信号の始まり(Leader部)に9msecと4.5msecのon-offがあるのが分かりました。こちらを参考にすると、この信号は「NECフォーマット」のようです。そのあとで01のビットが続いているということが分かりました。

赤外線発信時の波形
赤外線LEDが載っている回路を作成(文献[1])し、LEDの両端にプローブを当てて電圧変化を計測しました。受信モジュールの波形と大まかな外形は似ています。しかし、各波形の中に細かいon-offがあります(オレンジ色で塗りつぶされたように見える部分)。
赤外線送信用LEDの出力波形:横軸は1目盛りが5ミリ秒
(縦軸の電圧は正負が逆になっています)

次に、一つのビットを拡大して表示してみます(上画像の赤い四角の部分)。そうすると、一つのビットの中に38kHzの細かいパルスが見えてきました。
赤外線送信用LEDの出力波形:横軸は1目盛りが100マイクロ秒

なぜこのようにしているか、という疑問の答えはここにありました。送信波形を38kHzで出力することで消費電力を抑えながら感度を上げているということなんですね。

参考文献
[1] 『僕のArduino工作ノート』 鈴木哲哉著 ラトルズ (初版)p.212

2014年1月13日月曜日

Tekrtonixの格安オシロスコープ TBS1022 を購入しました

赤外線リモコンの信号が見たくなったので、オシロスコープを購入しました。購入したのはTektronix製のTBS1022です(スペックはこちら)。5万円弱という価格は、オシロスコープとしては格安です。ですが、趣味の電子工作に使うために購入するには、ちょっと勇気が要りますね。

前々から欲しいと思いつつ、躊躇していたのですが、思い切ってAmazonで買ってしまいました。計測器ランドさんから購入しましたが、注文から2日くらいで到着して、ちゃんと保証書もついてました。

内容物
説明書、Windows用のCDとプローブ2本が同梱されています。説明書は、英語、日本語、中国語で書かれています。※僕はMacBook Airしか持っていないので、残念ながらCDは使用できません。それでも、波形はUSBメモリに保存できる(後述)ので問題ないでしょう。
内容物一式:説明書とプローブ2本が同梱

とりあえず使ってみる
赤外線リモコン受信モジュールが出している信号をみるため、プローブをモジュール(今回使用したのはこちら)のOUTに接続しました。基準リードのワニ口クリップはGNDに接続します。
赤外線リモコン受信モジュールの信号を拾ってみる

赤外線リモコン受信モジュールは、未入光時は5V出力のようです。なので、トリガー設定をFallingに設定したほうがよさそうです。TrigMenuボタンで、Typeは"Edge"に設定、Slopeは"Falling"に設定しておきます。Triggerレベルは、Levelのつまみを回して、0〜5Vの間のどこか適当な値に設定しておきます。

その状態で、リモコンを発光させると、赤外線リモコン受信モジュールの信号が表示できました。
測定の様子

波形を画像で保存する
右上のSingleボタンを押してから、リモコンを発光させると、信号を表示したうえで、画面が停止します。Utillityボタンを押して、画面内の Options → Printer Setup → Print Button で"Saves Image To File"を選択しておきます。全面のUSB端子にUSBメモリを差して、Save(プリンタの絵がかかれている)ボタンを押すと、画像が保存されます。
測定結果:USBメモリ内に画像を保存できる

Arduinoで遊ぶ程度の工作なら、このオシロスコープで充分測定できそうです。これからどんどん使っていきたいと思います。