2024年12月25日水曜日

出入り検知器をPCB化する(その21)・超音波測距1

 出入り検知器は元々20cm離れた2本の赤外線を人が横切る事を検知するよう考えていた。これは狭いゲートを通過する人を検知するような使い方を前提としていた。一方、目前の歩道を通り過ぎるような人の動きを検知して働くような機能の方がより汎用的に使えるだろうと、そのようなセンシングを考える事とした。

このような動きを捉えるには画像認識以外には次のような幾つかの方法が考えられる。それぞれ対象物との絶対的な距離を測れるものと、距離の変化を捉えるものがある。

  1. 焦電センサー
  2. 赤外測距センサー
  3. 超音波測距センサー
  4. ミリ波センサー 

これらのうち秋月で入手が容易な(比較的安価な)センサーについて特性を調べた。1.焦電センサーは人体から放射される赤外線を捉え、その量の変化が閾値を超えた場合に反応するが屋外では太陽光やその反射光、風が吹いても反応する事があり屋外での特に昼間の利用には不向きである。2.は自ら赤外線を発射し、その反射光を受信するまでの時間から対象物迄の距離を測定する。その例として秋月で売っているVL53L0X使用 レーザー測距モジュールを買ってみた。これは Arduino ではライブラリが使えるようだがモジュール自体の仕様は公開されておらずPICからは容易に使えないので今回は扱わない。3.は超音波を使って2と同様な事を行う。4.はミリ波を使って同様な事を行う。最近は車の人感センサーに応用され比較的入手が容易である。ただ電波法で規制されるため認証されたものを使う必要がある。


取り合えず安価で最も使い易そうな超音波センサーを使ってみる事とした。秋月では手頃な値段のUS-015とHC-SR04という見かけの似た2つの超音波センサーモジュールを販売している。

値段もあまり違わない。インターフェイスも同じGPIOで4ピンの信号割り当ても同じ。但し(マニュアルは中国語で分かり辛いが)HC-SR04はジャンパーを切り替える事でGPIO(PWM)のほかI2CまたはUARTインターフェイスを選ぶ事が出来るようである。汎用性を考え、とりあえずGPIOインターフェイスで使ってみる事にした。次図はGPIOのタイミングチャートである。


GPIOでは Trig端子に10μsのパルスを加えることで測距がスタートする。先ず40KHzの超音波パルスが8回発射され、それが対象物で反射されて帰ってきたエコーを受けてEcho端子に往復時間に対応する時間幅のパルスが出力される。もしエコーが検知されなかった場合は80msのパルスが出力されるとUS-015のマニュアルにあるが、HC-SR04にはそれに相当する記述はない(実際に測定したところでは50ms強であった)。Trig端子に与えるパルスの繰り返し周期は仕様上はUS-015で85ms程度、HC-SR04では200ms以上必要である。

音速を340m/sとし、最大測距距離4mとして試算すると往復時間(Echo端子への出力パルス幅)は23.5msである。厳密には大気中の音速の温度勾配が0.6m/s/T程度あるようであるが、今回の目的には補正は必要ないだろう。もし補正したいならPICに内蔵の温度センサーを使うと簡易な補正はできる。

測定にPIC16F18326を使う場合、カウンタをゲート制御できるTimer1を使うのが適当である。Echo端子の信号をカウンタのゲートに加える。カウンタに加えるクロックにLFINTOSC(31KHz)を使うと距離を(理論的には)約1.1cm単位で測定する事が出来る(往復だと0.55cm)。また無エコー時の80msパルスのカウント値は24,80カウントでありTimer1の16ビットの範囲に収まる。

・・・てな事を考えながら回路を考え基板を発注した(この回路では将来の拡張を考えてPIC16F18346を使っている)。


この基板では3方向の超音波センサーを使う事を想定している。センサーの指向性は±15度なので各センサーは角度の30度離して取り付けるのが良いと思われるが3つ併せても探知範囲は90度しかない。広い範囲を見るためにあと2個追加して探知範囲を150度としたいものである。

(続く)

 

2024年12月21日土曜日

出入り検知器をPCB化する(その20)サーボ・モータを動かす8

 サーボ・コントローラを語るうえで大事な事を忘れていた。

そもそもサーボモータの制御信号(PWM)には統一規格はあるのか、 それはTowerPro社のSG-90と同じで良いのか、或いはどんなものがあるのか、という点である。こういったサーボモータはラジコンで使われているようなので規格は統一されていそうなものである。実際にカタログには制御信号はPWMとだけ書いてある場合も多く、あたかも統一されているようである。そこで秋月で入手できるもの(360度回転の物を除く)を中心に市販品を調べてみた。全てを調べ切った訳ではないが、概要は次の通り。

  1.  TowerPro - このメーカーのサーボモータの制御信号(PWM)のパルス幅は180°回転の場合500μs~2400μsでセンターは1450μsである。
  2.  FEETECH - このメーカーのサーボモータの制御信号は180°回転の場合500μs~2500μsでセンターは1500μsである。回転角が120°の製品もあるがセンターのパルス幅は同じく1500μsである。またシリアルインターフェイス(1Mbps)のものも販売されているようだ。
  3.  GWS - このメーカーのサーボモータの制御信号は180°回転の場合800μs~2200μsでセンターは1500μsであり、120°回転の場合900μs~2100μsでセンターは同じく1500μsである。
  4. SAVOX - 製品の数が少ないが、回転角が164°のものの制御信号は800μs~2200μsでセンターは1500μsである。

 これらの値をもとに回転角1度当たりのパルス幅変化量を計算すると11μs前後の製品が多いが、中には6.7μsの製品もあった。

これらのメーカのパルス周期はいずれも20ms(50Hz)である。一方Amazonで売っている高トルクのサーボでは高パルス周期(50Hz~333Hz~800Hz)のものもあるようだ。ただ800Hzのパルスを出すとすればパルス幅はせいぜい1ms(1000μs)程度なので、これを使うつもりなら仕様を具体的に検討してみる必要がある。

さて、制御信号の時間的な仕様が分かったので今回作ったサーボ・コントローラで実際にこれが動くのか電気的特性を試してみた。テストに使ったのでは TowerPro の MG996Rである。

このサーボを選んだのはトルクが11Kg/cmもあるので(SG-90は1.8Kg/cm)大喰らいであり、その分だけ制御信号にもある程度パワーが必要かもしれないと考えたからである。つまり(データシートに明示されていない)サーボモータの制御信号の入力インピーダンスや閾値がPICで駆動できる範囲にあるかという事である。

結論から言うと問題なく動いた。最初は電源の電流を500mAに制限して動かしてみたらサーボはかすかに唸るが全く動いてくれなかった、そこで制限を1.5Aくらいに上げると普通に動いた。無負荷のSG-90なら100mAでも動くがMG996Rは無負荷でも1Aは必要である。仕様上は無負荷の電流は170mAとなっているが実際には突入電流が大きく最大電流1400mAの電源を用意しておく必要があるのだろう。やはり大喰らいである。

 以上の事から少なくともTowerPro社のサーボはPICで駆動できる事、またサーボ・コントローラで様々なサーボモータに対応させるためには少なくともPWMの細かい設定が必要な事が分かった(TowerPro社以外のサーボについては機会があれば試したい)。サーボモータを使う側から見ると、制御信号の統一規格は無く、使うサーボモータの仕様に合わせて制御信号のパラメータを変える必要があるという事である。

幸いこの程度の事ならプログラムの簡単な変更で済むのでサーボの仕様に合わせてパラメータを切り替えられようにする予定である。

 (続く)


2024年12月2日月曜日

出入り検知器をPCB化する(その19)サーボ・モータを動かす7

 サーボモータに与えている制御信号を測定してみると、周期が1%ほど短い。また一定している筈の制御パルスの幅にも若干の揺らぎが見られる。これらの原因を考えると、周期の元となっているLFINTOSCの周波数が若干ずれている事と、LFINTOSCとパルス幅を決める元となっているFosc/4(=HFINTOSC/8)の周波数の間に一種の唸り(エイリアシング)が発生して揺らぎが発生しているようだ。

このPICではLFINTOSCの周波数は固定で補正できないが、HFINTOSCのそれは±1%以上補正できるので LFINTOSCの使用を止め、ソースをHFINTOSCに一本化する事で唸りを防ぐ事とした。幸いFosc/4の2MHzから100Hzを取り出す事はこれまで通りTMR0で分周する事で可能だ。結局、次の回路に落ち着いた。また周波数の補正パラメータの値(OSCTUNE)はPIC内部のEEPROMに書き込み保存されるようにした。


これで、この回路を1つの周波数源で駆動する事となり、動作が安定するだろう。また周波数を補正する事でパルス周期をほぼ20msに追い込むことが出来たが発信器には温度特性(次図)もあるのでどこかで妥協が必要である。

電圧依存性は少ないようである。

サーボ・コントローラについては一先ずこれで終わりたい。

(続く)




2024年11月29日金曜日

出入り検知器をPCB化する(その18)サーボ・モータを動かす6

 タイマー0、タイマー1及びCLCを使うことでタイマー2の機能から来る制約から解放されたのでクロック(HFINTOSC)の周波数を4倍の16MHzに上げFoscを8MHz、Fosc/4を2MHzとした。これで処理に余裕も生まれる。

前回の回路を実装してみたが上手く動かない。問題点は2つあった。1つ目はデータシートの回路図上のT1GSPMの表記(1/0)が逆になっていて(本文は正しかった)、ゲートによってカウンタが制御できなかった。このバグを潰すのに数日を要した。もう1点はタイマー1のゲートが閉じているとカウンター1のオーバフローが1になったままリセットできない点であり、そのため2回目以降のタイマー割込みを発生できないうえにD-FFがリセットされたままなのでタイマーのゲートが開けない、いわゆるデッドロックの状態になっている事である。設定を色々試したがどうしてもタイマー1はリセットできなかった(強制的にゲートを開けて数クロック入れてやればリセットされるが美しくない)。この件をネットで検索すると「CCPと組み合わせて使え」とのアドバイスが見付かった。どうやらCCPからタイマーをリセットできるようである。

そこで次図のようにタイマー1をCCPと組み合わせて使うよう変更した。CCPはコンペア+パルス出力+タイマーリセットモードに設定し、タイマー1のオーバーフローではなくタイマー1のカウント値がCCPRの値とマッチするタイミングでパルスを出力するようにし、そのパルスでCLCのD-FFをリセットするとともに割り込みをかけるようにした。同じタイミングでタイマー1はリセットされるようである。

これで上手く行った。これでパルス幅をデッドバンド幅の1μs単位で設定できるので低速の動きもスムーズになった。

このサーボコントローラはシリアルインターフェイス経由で次のようなオンライン・コマンドを受け付ける。


  (続く)

 

2024年11月24日日曜日

出入り検知器をPCB化する(その17)サーボ・モータを動かす5

 これまで使ったTMR2+PWM5,6では大き目のデューティ比のパルスを細かくコントロールする事は苦手である。そこで改めてサーボモータを細かくコントロールする事を考える。サーボモータのデッドバンド幅が1μsだとするとパルス幅を1μs単位でコントロールしたい。1μsを最小単位とし、サーボモータに与える最大パルス幅を2.5msとすると2500倍であり、これを制御するには12ビット以上のカウンタが必要である。これに該当するのは16ビットカウンタを持つタイマー1である(タイマー1は次の回路構成)。またこれに与えるクロックは1MHz以上とする必要がある。

今回の目的にタイマー1を使うときの問題点は、タイマー1はワンショットで、タイマー2の様なフリーランではない事であり、カウントが終了する度に再度カウンターに初期値を設定する必要がある。幸いその時間的余裕は17.5ms以上あるので割り込み処理で間に合うだろう。またタイマー1自体には任意のパルス幅のパルスを生成する機能は無いため、他の機能(例えばCLC)と組み合わせて使うことになる。このアイデアをPIC16F18346を使って組み立てて次図のように構成した。

この図でTMR0の分周比を620とせず310としたのはCLC1とCLC3のCK端子の論理を逆にし、HとVのサーボに与えるパルスを半周期(10ms)ずらし突入電流を減らす事を狙っている為である。TMR0の出力はデユーティ比が50%ではないためCLC2で2分周し周期20ms、デユーティ比50%の方形波を作る。

この回路の動作は、D-FFのD端子が1になると次のCK端子の変化点でQが1となりパルスがスタートする。それと共にタイマーのゲートGが開きカウントがスタート。カウントが進みカウンタが0xffffから0x0へ変わる時オーバーフローが発生してOVFが1になり、その時点でD-FFがリセットされパルスが終わる。この時割込みを発生させ、ソフトで次のカウンタの初期値を設定する。もしD-FFのD端子が0の場合は次のパルスは発生しない。この方法なら制御の最初や最後で中途半端な幅のパルスを生成することは無い。

タイマー1(TMR1,TMR3)のクロック入力には2MHzを使いプリスケーラで2分周して1MHzのクロックとしてカウントする。SG90の性能は0.12sec/60度であるからパルス間隔20msでは10度回転し、これに相当するパルス幅の変化量は概ね110μsであるから、これ(110)が20ms毎のタイマーのカウント値の最大変化量とする。即ちこれ以上カウント値の変化量を大きくしてもサーボモータが追従できない。この値を基準に制御プログラムを作成する。

〔参考〕ここでPICのタイマーの表記が紛らわしいので改めて説明する。PICには3種類のタイマーがあり、それぞれタイマー0、タイマー1、タイマー2と呼ぶ。PICの種類毎にそれぞれのタイマーが何個ずつ実装されているかが異なり、PIC16F183x6ではタイマー0はTMR0、タイマー1はTMR1、TMR3、TMR5、タイマー2はTMR2、TMR4、TMR6が実装されている。

 (続く)



2024年11月22日金曜日

出入り検知器をPCB化する(その16)サーボ・モータを動かす4

 この回路は手動制御とリモート制御の両方を実現しており、双方で制御の仕方が違う。リモート制御では角度を±90度、回転速度は19段階で指示できるが、手動制御ではレバースイッチは回転方向を、回転速度はロータリーコードスイッチで10段階に指示する。この折り合いをどうするかが1つの課題であるが、全て後優先とした。つまり新しい指示が入ると、それに対応した実行中の動作をキャンセルし指示に従う。回転速度の違いはマッピングで吸収した。
 
 基板を発注した。 大きさは 57.2 mm×40.6 mm と試作基板より一回り小さくマッチ箱サイズにできた。そして1週間で納品され、組み立てた。

そして設計通り動いた。

しかし低速での動きがぎこちないのが気に入らない。このままでは3度単位でしか制御できないので仕方ない事であるが、出来ればもっと滑らかな動きにならないか。サーボのデッドバンド幅が1μsなので上手くやれば(機械的なガタが無ければ)0.1度(=180度/2000μs/1μs)単位まで追い込めるはずである。

(続く)


2024年11月21日木曜日

PIC16F18xxxのA5ポートが使えなかった件に関する情報

 PIC16F18313、PIC16F18326、PIC16F18346 など PIC16F18xxx シリーズのPICを使ってみたが A5 ポートが入力にも出力にも全く使えなかった。色々調べてみたが全く原因が分からない。チップの系統的な欠陥か、まがい物を掴まされたかとも考えたが秋月でまがい物を売っているとも思えない。

この事から、これまでA5端子(ポート)は使えないという前提で、使わないよう設計してきた。

これは何かおかしいと最近再度調べたら、マイクロチップ社のホームページのフォーラムの中に同様の投稿を探り当て、答えが分かった。

https://forum.microchip.com/s/topic/a5CV400000015P3MAI/t395592

原因はPICのコンフィグレーション情報のFEXTOSCがOFFになっていなかったのだ。

次の記述を見て、内部発信器を使うのでFEXTOSCは関係しないと無視してきたが、
 
FEXTOSCがOFFでないとA5ポートはクロック発信器関係の端子として強制的に割り当てられ通常の入出力には使えないようだ。ただ、この情報はPICのマニュアルを探しても明確な記述が見つからず、幾つかの記述から類推するしかない。

A5端子が使えない事で何度かTRY&FAIL⇒設計変更したが、答えがこんな事だったとは・・・。

 

2024年11月18日月曜日

久留米黒棒本舗

 黒棒は関東のスーパーで普通に売ってるので、たぶん全国のスーパーでも売ってるんだろうと思っているが、その工場(黒棒製菓)は久留米市(福岡県)にある。

工場に隣接して販売店(黒棒本舗)があって製品の他、工場で出た半端物を安く売っている。これが1袋に約400g入って312円と格安である。それに黒糖のコーティングが厚かったりしてなかなか美味い。(写真の下の硬貨は500円玉)

工場の近くを通る時に寄ってみると、いつもある訳ではないが50%以上の確率で入手できる(大量に買う人がいるらしく5袋を予め大袋に入れたものもある)。家族や身近な人はみんなこれを大好きなので、今回は6袋も買ってしまった。

同じくあいすまんじゅうや白くまを作っている丸永製菓も久留米市にあるが、こちらに寄った事はまだない、というか売店があるかも知らない。


2024年11月12日火曜日

出入り検知器をPCB化する(その15)サーボ・モータを動かす3

サーボモータのコントローラに手動スイッチを付ける事となった。そこで秋月で買っておいたレバースイッチを付ける事とした。これは左右に各2段階、プッシュスイッチも付いていて色々使えそうだ。

このレバースイッチを付けるためには8ピンのPIC16F18313では端子が足りない。水平用と垂直用の2つのスイッチを付ける事を考えると単純には12個の端子が欲しい。そこで手持ちの20ピンのPIC16F18346を使うこととした。これはPIC16F18326の20ピン版である。勿体ない気もするが増えたPICの12ピンを全てスイッチに割り当てた。そしてハードは次の様に組み上がった。


ソフトはPIC16F18313で作ったソフトを少し改造して使った。PIC16F18346になったのでプログラムメモリーが3.5KBから28KBに、RAMが256Bから2KBに大きく広がり使い易くなった。

このハードに乗せるソフトは最初にPIC16F18313用に作ったものを、いくつかの点を手直しして上手く動かすことが出来たが、レバースイッチの2段階の操作で速度を制御するのは使い勝手が悪そうだったので別に速度切り替えのスイッチを追加する事とした。ここはジョイスティックにすれば良かったかもしれない。

 そしてこんな回路になった。

この回路(実装基板)の隠れた機能は3つのPICに対応している点である。20ピンのPIC16F18346だとフルの機能を使えるが、14ピンのPIC16F18326だとロータリーコードスイッチが使えず、PIC16F18313 だとレバースイッチも使えずリモート制御のみになる。一方3つのPICに対して(メモリー容量が許せば)プログラムはほぼそのまま使える点である。

この回路ですでに基板の設計とプログラミングは済んでいるが、まだロータリーコードスイッチを入手していないので検証が出来ていない。機能が確認できたら基板を発注する予定である。

 そして、ロータリーコードスイッチを追加してこうなった。

ソフトも幾つか手直しして動くようになった。

 (続く)

 


2024年10月24日木曜日

出入り検知器をPCB化する(その14)サーボ・モータを動かす2

 サーボモータ(SG-90)をPIC16F18313で動かすための基本的な計算が出来たところで実際のプログラムを作る。サーボモータを動かすために必要なパルス波形は次のようなものである。

2つのパルスの周期(20ms)はTMR2で決める。2つのサーボモータの角度に対応する2つのパルス幅(0.5ms~2.4ms)はパルス幅変調器(PWM5及びPWM6)で決める。

 サーボモータがある角度にある時、突然別の角度を指示するとサーボモータは最速(仕様では0.12sec/60度=500度/秒)でこれに追従する。これが目的とする動作に合っているのか、またサーボモータの負荷を高め寿命を縮めることにならないか気になるところである。そこでTMR2+PWMで生成できる最小の分解能である3度毎にステップを進める事とする。もし20ms毎に割り込みをかけて3度進めると150度/秒となり、良さそうである。TMR2にはポストスケーラがあるので、これを使うとこの1倍から1/16倍までのスピード制御が可能であり、即ち9.4度/秒~150度/秒の速度制御が可能である。

ロジックとしてはTMR2(のポストスケーラ)により割込みがかかったときサーボが目的とする角度に達していない場合は要回転を意味するフラグを立てる。さらにパルスの立下りで(IOCの機能を使って)割り込みをかけ、要回転フラグが立っている場合は次のパルス幅に相当する値をPWMに書き込む。そのタイミングがパルスの立下り後である理由はパルスの立下り時に処理を始めると処理のための時間的余裕が十分あるからである。時間的には20ms以内に処理を終わらせればよいので問題は無いだろう。なおIOC(Interrupt On Change)とはPICのピンの信号の変化を捉えて割込みを起こす機能であり、立ち上がりと立下りを個別に捉え割り込みを起こす事ができる。通常は入力信号に対して使う機能だと思うが、ここでは出力信号に対して使っている。

ソフトの開発と並行して汎用基板にプロトタイプのハード(コントローラ)を作った。 大きさは概ね2cm×4cmに収まった。

基板に載っている部品はPIC16F18313と電源のパスコン、LEDと電流制限用抵抗だけで他に接続用に電源コネクタ、サーバモータ用3Pコネクタが2つ、ホストと繋ぐシリアル通信用コネクタが1つあるだけである。シリアルインターフェイスはUSBを介してTeraTermから文字ベースでテストできるようにした。

電源を入れると各部の初期化を行い、TME2やPWMを起動、1.45msのパルスを作ってサーボを中点まで移動、その後パルス幅を0としてサーボを休止、割り込み可としてSLEEPする。

RS-Kager2-Servo313-032 2024/10/23 for RS-Kager2 ver 0.27
 Copyright(C)2024 MYcrosLip
*** Init Servo.
*** Start Interrupt.
*** Start Servo.
*** Sleep Loop.

あとはシリアル通信で受信したコマンドを解釈してPWMを制御しサーボを3度ステップで動かす。目的の角度に達したらパルスを止める。3度進むのに必要な時間は7.5msであるから50Hzの1周期(20ms)以内に終わり、タイマーなどを使った遅延操作は不要である。

実装した主なコマンドは<nn>H、<nn>V、Z、<mm>Gである。Hは水平サーボ、Vは垂直サーボの軸を回転(指向)させるコマンドで<nn>は-90度~90度の範囲であり、Zは原点(0,0)に復帰、Gは速度制御(<mm>は引数で1~16)である。

次の実行例で、90Hは水平サーボを90度に向け、90Vは垂直サーボを90度に向け、Zで原点に戻っている。小文字のhやvは動作確認のため1ステップ進むごとに表示させている。

90Hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
90Vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
Zhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhvhv

 サーボの動作中でも次のコマンドを受け付ける。この場合、実行中のコマンドの終了を待たずにキャンセルし、後で来たコマンドを処理する。この動作を2つのサーボに対して各々独立して行う(逆に言えば処理待ちキューを作らずに済ませたという事)。

これで外部から文字ベースでサーボを制御できるようになった。

(続く)

 


 

2024年10月19日土曜日

出入り検知器をPCB化する(その13)サーボ・モータを動かす1

 出入り検知器にサーボ・モータを動かす機能を追加できないか相談を受けた。水平と垂直の2方向の動きをサーボで作る。そこでSG-90という最も安価なサーボを秋月で入手して動かしてみる事に。

SG-90にはSG90-HVという軸が360度回転するタイプもあるが、入手したSG-90は可動域が180度のタイプである。SG-90の角度を制御するには電源5Vを加え、次のような20ms周期のパルス幅変調の信号を制御端子に加え角度を制御する。

 角度は0.5ms~2.4msのパルス幅に対応して0度~180度に変化する。中点(90度)のパルス幅は1.45msである。パルスを0.05ms(50μs)単位で変化させると180度を39ステップ、即ち4.7度単位で制御する事ができる。SG-90のデッドバンド巾は1μs(本当?)なので問題にはならないだろう。

この幅のパルスを作る事は難しくない。問題は周期の50Hz(20ms)との関係である。ポイントは大きなデューティ比 0.5/20~1.45/20~2.4/20 を細かく制御する必要がある事である。これを整数比に直すと10/400~29/400~48/400 であり、20msの1/400である50μs単位で制御する事になるが、これは試算値であって実際のSG-90がこれをどれ程の精度で追従できるかは分からない。

8ピンのPIC16F18313には2個のPWM(パルス幅変調器)が内蔵されていて丁度良い。このPWMはタイマー2(TMR2)と組み合わせて使う。


TMR2はFosc/4のクロックで動く8ビットカウンタであり、1/1, 1/4, 1/16, 1/64 のプリスケーラが利用可能。これを使ってFosc/4=500KHz、プリスケーラ=1/64、カウンタの上限(PR2)を155に設定すると約50Hz(=500KHz/64/156)が取り出せる。なおTMR2のポストスケーラ(1/1~1/16)からは直接信号が取り出せず割り込み用にしか使えない。

TMR2と組み合わせて使うPWMのパルス幅は10ビットで指定する。つまり8ビットカウンタの1カウント値の1/4まで指定でき、これは約32μsステップ(=20ms/156/4)単位で指定できる事になる。これを使って改めてパルス幅の指定範囲を計算するとカウント値は 0.5ms÷32μs≒15、1.45ms÷32μs≒45、2.4ms÷32μs=75 という値となる。つまり90度で30カウント差だから1カウントが3度の回転に相当する。

(続く)


 

 

2024年10月15日火曜日

出入り検知器をPCB化する(その12)

 これまで作った歴代作品を並べてみた。残念ながら汎用基板を2段重ねした第1.5世代は部品を使い回ししたため残っていない。

当初は人の動きを捉えて喋るだけで良かったものが、それに加えてリアルタイムクロック(RTC)や気圧センサーを加え気圧変化を喋り、さらにメロディを奏でるまでになった。C言語で書いたプログラムもメロディ生成に2千行、本体は1万行程度になった。そして開発は今後も続く。本バージョンの締めとして若干の修正を加えた第4.2版を赤色のレジストで発注した。

これで終わりかと思ったが、更なるリクエストがあり、 開発は続く。

(続く)


 



 


2024年7月31日水曜日

出入り検知器をPCB化する(その11)

メロディ生成をPIC16F18326に変えたので、それに合わせて第4版のPCBを発注した。版を追うごとに基板の密度が上がっている。秋月で買える安い部品だけで作っているのでICのパッケージも様々である。これまでと同じ大きさの基板に収めるのはボチボチ限界かな。

1週間ほどで基板が出来上がってきたので早速秋月に走り部品を調達して組み立てた。

ソフトに幾つかの修正を加えてメロディIC(PIC16F18326)を接続できた。

RS-Kager2 Ver0.23 for RH-Kager2 Rev 0.40 2024/07/30-1
 StateMachine: 3.1 SpeakMessage: 0.4
 Copyright(C)2023,2024 by MYcrosLip. (DEBUG MODE)
... Checking Melody Player - Tone326-197:103
--- Melody Player is ready.

... Checking Voice Synthesizer -VF1a
--- Voice Synthesizer is ready.
--- I2C_INIT: I2C Bus is Ready.
--- Extend EEPROM OK.
... EEPROM-ID = RS-Kager2 Ver0.23 2024/07/30-1
... RTC RAW10: 02 80 08 22 23 09 31 03  07 24
--- RTC is active.
--- RTC: 24/07/31(WED) 09:23:22
--- Barom is active.
!!! Barom: FIFO is not full; Wait a dozen seconds.
--- Air Pressure: 996.0 hPa (Offset 9.2 hPa).
--- Power Supply : 5.09 V
--- Environment : OFFICE mode.
--- Speak air pressure 1 time(s) in an hour.
--- Speak the time before speak the pressure is ON
--- Speak random at S3 is : ON
--- Speak Battery Low is ON.
--- Current LED Brightness is 30 %
--- Start Interrupt Handling.
 

メロディが時々ハングアップしたが、これは暫定的に作っていたインターフェイスの中の待ち行列(QUE)がCでお決まりのNULLポインタを起こしていた。複数の曲をキューイングして演奏する状況は考えられないのでQUEの使用は止め、逆に曲の途中で別の曲を強制的に割り込ませる機能を追加した。これにはメロディICとPIC18F27Q43の間の連携が必要であるが、メロディICに予め演奏の強制停止コマンドを組み込んでおいたおかげですんなりと実現できた。

(その後)

第4版のPCBに若干の修正を加えて第4.1版を作った。変更点はPICのバグ回避のための変更1件と利用上の都合に伴う2件である。

 出来ればこれを最終版にし、あとはソフトに任せたい。

 (続く)

 

2024年7月18日木曜日

出入り検知器をPCB化する(その10)メロディ生成4

 次はテンポの処理である。

単音の場合は適当に遅延を挟むことでメロディを演奏することが出来たが和音の場合は各音符の長さが同一ではないため単純な遅延では処理できない。 そこで32分音符の長さを基準とした割り込みとソフトのカウンタで処理する事とした。

実際にはスタッカートやテヌートも処理したいので音符の長さを12分割した間隔で割り込みをかけ発音を制御する。最高のレートだとBPM=200の場合は約3ms毎に割り込む事になる。

割込みにはTimer6(TMR2)を使った。250KHzのクロックをプリスケーラで16分周するとポストスケーラを使わなくても丁度良い具合になる。 BPM=40で244分周、BPM=200で49分周と、8ビットの分周器に丁度収まるスケールだ。

ここまで出来たら、あとは譜面の記法を決めればよい。TeraTermで操作できるよう譜面は全て文字で表記するようにした。前に書いたように音の高さはMIDIの音階と同じコードを使うがメモリーを節約するため16進数で表記する。音の長さは次の様にした。

音符は音の高さ2文字と長さ1文字の3文字で表す(休符は音階=0とする)。更にチャネル指定を「:c:」で、BPMを「%hh」、音階のオフセットを「$±h」で表す。1音を3文字で表すよう数値は16進標記とした。3文字の間にはスペースや幾つかの区切り記号を挿入することが出来る。

譜面は改行で終わる1行の文字列である。譜面を最後まで読み込んだら内部でチャネル(音源)ごとの楽譜に変換し、32分音符の1/12の時間間隔の割込みに従って同時進行で演奏(音をON/OFF)する。

次のような4和音の譜面を1オクターブ上げてBPM=100で演奏してみた(この譜面はプログラム中にデータとして記述して分かり易いよう改行を入れている部分であるが、実際は「"」や改行を外し1行にする必要がある)。

       "%64$+c"
    ":1:43E 41E 46E 48G 4dG 4aE_48G 4dG 4aE 46E 48E 43E 413"
    ":3:3EE 3cE 3eE 45E     45E_45E     46E 43E 43E 3cE 3c3"
    ":2:3aE 39E 3aE 3cE     41E_3cE     41E 3eE 40E 37E 393"
    ":4:37E 35E 37E 35E     32E_35E     3aE 37E 30E 34E 353"


 これを解釈し内部で使う音源ごとの楽譜に変換したものは次のようなものである(各音源の最初の16バイトの16進ダンプ)。

  --1-- 54 43 54 41 54 46 74 48  74 4d 54 4a 74 48 74 4d
  --2-- 54 3a 54 39 54 3a 54 3c  54 41 54 3c 54 41 54 3e
  --3-- 54 3e 54 3c 54 3e 54 45  54 45 54 45 54 46 54 43
  --4-- 54 37 54 35 54 37 54 35  54 32 54 35 54 3a 54 37

これを演奏するとこのような音になる。

(その後)

3連符を表現したくて割込み頻度を3倍にして、32分音符の間に3×12回割り込むようにした。これで音符の長さを表すパラメータが3倍となり3で割り切れるようになる。表記も改訂した。

この機能を使って3連符のあるこんな演奏ができる。我ながら上出来である。 

(さらにその後)

音源3,4はパルス幅変調ができるので、試してみた。パルス幅を50%、25%、12.5%、…と半分ずつにしていくと、50%~6.25%までは音質が変わり、それを超えると音量が低下する。これは主旋律を目立たせる技として使えそうである。

(さらにその後)

オシロスコープを使って割り込み処理にどの程度時間を取られているか観測してみたところ約2msかかっていた。一方200BPMの時32分音符に費やされる時間は約37ms。実際にはそれを12分割して管理していたが、さらに3連符処理のためその1/3倍としている。つまり割込み処理を1ms以下で終える必要がある。一方実際には処理にその倍の時間がかかっており100BPM以上の演奏には追従できない事が分かる。 これを解決するためCPUクロック(Fosc)を4倍に引き上げて4MHzとした。これで1回の割込み処理が500μs程度で終わり時間に余裕が生まれた(実際には36回(或いはその倍数)に1回起こる音符の切り替え処理時にもっと多くの時間がかかるが聞いていても分からない)。またクロックの変更に伴って影響を受けるUARTの通信速度や音の高さに関係するパラメータを変更した。幸いにも音符の高さを表すパラメータはクロックを細工する事で再計算せずに当初の音域をカバーする事が出来た。詳しくは後述する。

(つづく)



2024年7月16日火曜日

出入り検知器をPCB化する(その9)メロディ生成3

 4チャネルのミキサーを作る。

4chの発振器の出力をPIC外で抵抗ネットワークでも組んで合成すれば済むわけだが、ここではデジタル的に行えないか。4つの信号のXORを取れば済むと考えCLCを3つ組み合わせてミキサーを構成してみた。しかしサッパリ動かない。かなり長期間悩んだが問題はPIC16F18326のデータシートの次の図であった。

図を見てAND-XOR回路とみてプログラムを組んだ。即ち1番目と3番目を入力としてXORとして出力させるために2番目と4番目の空き入力をHとした。しかし図は間違いで、実際には図上の記述の通りOR-XOR回路で2番目と4番目の空き入力をLとしなければ動かなかった。細かい字を読みたくない老眼の弊害が現れた訳だ。

これを使ってCやCmの和音を発生させたが歪が酷くて聞くに堪えない。方形波は奇数倍の高調波を多く含むのでこうなるのか。偶数倍の高調波の多いのこぎり波だったらまだマシだったかもしれないが・・・。

それだったらと、4つの波形をデジタル・サンプリングして合成する事に挑戦した。実際には各波形は1か0かの2値波形だし、16F18326のD/A変換器は5ビット(32値)なので、この間をどうマッピングするかが課題になる。単純に各波形に 8の重みを付けて足し合わせたらよいのか。或いはエネルギーは振幅の2乗に比例するから32の2乗を4等分した平方根の重み付けで良いのか。サンプリング周波数(割り込み)を4KHzで試してみた。インストラクションサイクルが250k/sなのでサンプリング当たり62命令しか実行できない。実際に動かしてみると割込みは1.8K回/秒程度が限界でとても追いついていない。サンプリング周波数を1KHzに落とすと500Hzまで再現できるはずであるが、やってみても音にならない。Fosc/4を少なくとも4倍の1MHzくらいまで上げる必要がありそうで、そうするとNCO1の精度が悪くなるし、全体的なパラメータの見直し・変更が必要になる。

そこでパラメータの大幅変更を伴うデジタル・サンプリングは後回しとし、とりあえず14ピンソケットを8ピンソケットに重ね、4つの発振器の信号をピンに取り出して抵抗ネットワークを空中に組んで音を出してみたところ、素人の耳で聞いた限りではまぁ使えそうである。


先ずはこれで進める事とした。

(その10へ続く)

 

2024年7月12日金曜日

出入り検知器をPCB化する(その8)メロディ生成2

メモリー容量の関係でPIC16F18313では単音しか発生できなかった。これをPIC16F18326に換えることで機能拡大ができそうである。とりあえず基板を改造してPIC16F18326とオーディオアンプが使えるテスト環境を作った。

14ピンのPIC16F18326はPIC16F18313用に用意した8ピンソケットに一部だけ挿し、残りは宙ぶらりんの状態にしている。

和音を発生させるためには複数の発振器が必要であり、そのためにNCO1以外に使えそうなのがTMR0、TMR1、及びTMR2であるが、TMR1は任意の分周比の連続波形が発生できないので除外する。 

TMR0は次のような構成である。

クロックは幾つか選択できるが、後の計算の結果HFINTOSC(16MHz)を選択した。プリスケーラは1/2^n(n=0..15)が選択できる。中央のカウンタ部には8ビットモードと16ビットモードがあるが、8ビットモードでないと任意の分周比が設定できない。8ビットの分周器を経た後はポストスケーラで1/1~1/16の分周比を選択できる。最後にD-FFで1/2に分周し方形波として出力する。クロック周波数、プリスケーラ、分周器をどう組み合わせれば目的とする周波数を発生できるかExcelで最も誤差の少ない組み合わせを求めた。その結果全音階に渡って誤差を数Hz以内に収めることが出来た。

TMR2(Timer2、Timer4、Timer6)は次のような構成である。

この回路をそのまま音階発生に使うには次の欠点がある。

  1. 入力のクロックがFosc/4固定である事。
  2. 分周比の設定が8ビットしかできない事。
  3. 音階発生にはポストスケーラが使えない(信号が取り出せない)。
  4. そのままではPIPで出力を取り出せない。
  5. 発生周波数(分周比)によってduty比が変化する。

1,のFoscは1MHzとしており、これは他のデバイスのパラメータとの関係で安易に変更できない。従ってクロックは250KHz固定になる。4,5,を解決するため次の様にCCPと組み合わせてPWM(パルス幅変調器)として使う。duty比は他に合わせて50%とするが、これを変化させて音量・音質に変化を持たせることもできるだろう。

プリスケーラと8ビットの分周器を組み合わせると最低音の2音階を除いて予定した全ての音を発生させることが出来る事が分かった(ただし最高音部は周波数誤差が50Hz以上に大きくなる)。何処まで使えるかは実際に耳で聞いて決めるが最高音部は周波数が高すぎて現実的には使わないだろう。

音階のパラメータと誤差を纏めると次表のようになる(一部省略)。NCO1はこういう目的には優れものだという事が分かる。

TMR2はTimer2、Timer4、Timer6の3個搭載されているので、後述のミキシングを考えてTimer2、Timer4の2個を使い、NCO1とTMR0と併せて全体で4音を発生できるようにした。

Timer6は テンポの作成に使う。

(その9に続く)

2024年7月5日金曜日

出入り検知器をPCB化する(その7)メロディ生成

 メインの基板が働く目途が立ったのでメロディ回路作成に取り組んだ。前回のメイン基板の写真で空いている8ピンICソケットにPIC16F18313を挿してURATインターフェイスを通じてメロディを発生させるようにする。

3声のシンセサイザを作りたかったが試したらPIC16F18313の少ないメモリー(プログラム=3.5KB、データRAM=256B)では1声の単音色が限界だった。 音階はクロックの1MHzを使ってNCO1(数値制御発信器、次図)で発生させた。

一般的には特定の周波数を発生させるには高い周波数のクロックを分周器で分周するのが普通であるが、分周器は整数分の1の分周しかできない(PLLを使った高級な分周器では分数の分周が出来るものもあるらしい)。一方音楽に使うためには12音階を数オクターブを発生させる必要がある。12音階は整数比ではない(1音階の周波数比は2の12乗根=約1.060)ため分周で正確に発生させることはできない。特に分周器を使って高い周波数を出す場合は分周比が少なくなり周波数精度が悪くなる。音楽では単に周波数精度だけでなく正しい音階からの絶対的な周波数のずれが唸りとなって聞こえるのでこれはいただけない。分周で精度を上げるにはクロック周波数を上げ分周比も大きくする必要があるが、Excelで計算してみるとA8まで周波数誤差を0.5Hz以内に収めるためにはPICのクロックが32MHzでも足りない。

一方NCO1は動作がやや複雑である。中心となる加算器で加算値を足し合わせ、加算器のオーバーフローを出力とする。NCO1では周波数が高くなるほど周波数精度が高くなる。それもクロックが低いほど加算数が大きくなり周波数精度も高くなる。クロックが1MHz、20ビット加算器を使うとA1の55Hzを出すための加算値は115、A8の7040Hzを出すための加算値は14764である。実際には出力を方形波とするためにオーバーフローを2分周して出力しており、その時の加算値が上の値である。周波数誤差で見るとNCO1では音階毎の周波数誤差の凸凹が少なく、全音階で0.4Hz以下に収まっており、高音になるほど周波数誤差が大きくなりがちな分周方式と違ってNCO1方式は音楽向きである。但しオーバーフロー毎に加算の余りが残るはずで、その分ビブラートがかかる筈であるが、その計算は後に回す。

NCO1の弱点は求める周波数を出すための加算数の計算がやや面倒な事であるが、これは予めExcel等で計算しておくことで対処できる。

結局、PIC18F27Q43からUARTで音階と音の長さを纏めた1行を送ることでメロディを奏でさせることとした。音階はMIDIの音階コードを流用して16進数で表す。音の長さは簡略化して1文字で表す。例えばA4(440Hz)の四分音符は「455」と表現する。1音を3バイトで表すのでRAMのうち141バイトを使って47音(休符を含む)まで演奏できる。

音階はNCO1で簡単に実現できた。音の長さはメモリー容量の関係でタイマー割込みは使わず1msの遅延を必要回数繰り返すことで実現した。この繰り返し回数は拍数(BPM)から簡単に算出できる。ON/OFFの割合を変えることでスタッカートやレガートも出来る。一応次の様に文字を割り当てた。i や j や l を使っていないのは視覚的に判別しにくいからである。

一方、使い慣れたはずのUARTインターフェイスが全く使い物にならず苦労した。送信は出来るが受信が全くできない。ソフトやハードをあれやこれやチェックしても全く動かない。さんざん悩んだ挙句に最終的に2番ピン(RA5)が死んでいることが分かり、これをPPSの機能で空いている6番ピン(RA1)に振り替える事で解決した。この事は、PICを交換しても駄目だったのでロット不良か或いはまがい物を買った可能性がある(このPICは秋月で買ったんだけど・・・※1)。

UARTインターフェイスは AquesTalk pico と似たようなものにした。

次のバージョンでは和音を出したいのでPIC16F18313の上位互換のPIC16F18326(14ピン、プログラム=28KB,データRAM=2KB)、或いは別のPICを使ってできないかあれやこれや検討している。しかしPICに搭載されているNCOはせいぜい1個であり和音には程遠い。(複数個ある)タイマー1は使えないか?またPWMを使ってエンベロープ機能も搭載できないか?PWNはタイマー2と組み合わせる必要があり、タイマー2のクロックにはシステムクロック/4しか使えないが要求を満たせるか、また音の合成はどうするか?など検討している。 

※1:後日別のPIC(16F18326)に変更したが、相変わらずRA5が使えないのでPIC16F18xxxのタイプのPICの欠陥かもしれない。

(その8へ続く)

2024年6月21日金曜日

出入り検知器をPCB化する(その6)

発注後1週間と1日で JLCPCB から3作目の基板が届いた。指定した最も安い配送方法 OCS NEP のうちOCS は ANA グループの会社名らしい。一方 NEP というサービスが何なのかはよく分からなかったが国内はネコポスでは配達された。毎度使って何も問題は無いので良しとしよう。

早速組み立ててデバッグ中のソフトを書き込んだ。

新しい部品を基板に押し込む面積を稼ぐためPIC(18F27Q43)のピンの割り当てを変更したが、それに伴うバグの侵入が幾つかあり、虫取りが進行中である。

 今回は音声合成ICにこれまでのATP3011ではなくATP3012を使った(半田ジャンパーを切り替えることで双方に対応するよう設計している)。しかしATP3012は上手く動かない。仕方がなくATP3011に戻すと問題なく動く。そこでテスト環境を作ってATP3012を単体でテストしたが特に問題ないようだ。怪しいのは16MHzのセラロックか?オシロスコープでセラロックを観測するとSLEEP状態では発振停止しておりSLEEPが解除されて発振が安定するまで1ms程度かかる事が分かった。即ちSLEEP解除後に数msの遅延を入れる事で問題は解決した。

 ここまで来て、一応前バージョンと同じ機能まで確認できたので、これから新しく追加したEEPROMを使ったソフトを開発する。

余談だが、半田ジャンパーが上手く繋がらなかったので半田ごての温度を270℃から260℃に変更したら簡単に繋がった。


10℃の差がハンダの粘性に大きく影響しているようだ。この半田ごて(PX-280)はなかなか優れものである。値段は高いが思い切って買ってよかった。

(その7へ続く)