ラベル 出入り検知器 の投稿を表示しています。 すべての投稿を表示
ラベル 出入り検知器 の投稿を表示しています。 すべての投稿を表示

2025年9月4日木曜日

出入り検知器をPCB化する(その26) インテグレーション3

 暫く作業をお休みしていたが、これまで作った基板を組み合わせて、人の通行を感知して挨拶する挨拶ロボットを作る。

そこで新たらしく必要になるのがロボットを制御する方法、即ちサーボモータによるロボットの動作とメロディ・音声を同期させる手法及びその記述法である。最初のステップとしてインテグレーション1で作ったサーボ制御ユニットのコマンドを次の様に整理した。

    <nn>A - Rotate Ch.1 to direction <nn>.(<nn>=-90..0..90)
    <nn>B - Rotate Ch.2 to direction <nn>.(<nn>=-90..0..90)
    <nn>C - Rotate Ch.3 to direction <nn>.(<nn>=-90..0..90)
    <nn>a - Rotate Ch.1 <nn>degrees.(<nn>=-90..0..90)
    <nn>b - Rotate Ch.2 <nn>degrees.(<nn>=-90..0..90)
    <nn>c - Rotate Ch.3 <nn>degrees.(<nn>=-90..0..90)
    <nn>x - Set Ch.1 speed to <nn>.(<nn>=1..253)
    <nn>y - Set Ch.2 speed to <nn>.(<nn>=1..253)
    <nn>z - Set Ch.3 speed to <nn>.(<nn>=1..253)
    <mm>s - Set all speed to <mm>.(<mm>=1..253)
     <m>S - Set all speed to level <m>. (<m>=0..9)
        Z - Rotate Ch.1,2,3 to origin(0,0,0).
        > - Wait Idle
        $ - Abort
        e - Echo OFF(default)
        E - Echo ON
        i - Idling OFF(default)
        I - Idling ON
        v - Show software version.
        V - Show configuration data.
 

これらのサーボの制御コマンドは制御モジュールに後置記法(逆ポーランド記法)で与える。つまり改行を待たずアルファベットや記号のコマンドを入力した時点で即動作する。いちいち改行を入れる必要が無いので連続的な指示が可能である。 


 メロディや音声に同期してサーボユニットへ指示を行うための記法を次の様にした。

    [A:B:C](D)E 

 ここでサーボへの指示は[]の中に記述し、メロディは()の中に記述する。つまりAはサーボの事前処理、Bがサーボの動きの記述、Cがサーボの終了処理、Dはメロディ、Eが音声メッセージである。例えば、

    "[200sZ>5s:90A90C>-90A-90C>:$Z>](@j)ohayo" 

と記述すると、

  1. スピード200で原点移動、 その後スピードを5に変更(A部)
  2. 「@j」で定義されるメロディを演奏(D部)
  3. その後「おはよう」と発声(E部)
  4. 2,3を行っている間にチャネル1とチャネル3のサーボモータを原点から+90度へ、次に-90度へ回転(B部)
  5.  発声が終了するとともにサーボの回転を停止し原点へ移動(C部)

 のように動作する。こういった1行をイベント毎に用意し、実行すればよい。

 (続く)

 

2025年4月30日水曜日

出入り検知器をPCB化する(その25) インテグレーション2


 アップグレードしたメインの基板はサーボコントローラより前に発注して昨年末に入手済みである。 前バージョンとの大きな違いは配線パターンの向きを表裏逆にした点である。ICのピン間(2.54mm)を通す配線を表側に配置した。昔、レジストを塗布していない基板ではこうしたものだが今はレジストがハンダのブリッジを防いでくれるのでうっかり逆にしていた。プロの仕事を見るとICのピン間には2本の配線を通せるようであるが、私は私はそこまで追い込むつもりは無い。

 

 さらに次のバージョンを発注し入手した。

最新バージョンの変更点はインターフェイスの都合上電源の5V系と3.3V系を分けた事である。 というのは電源を3.3V系で統一出来たら良かったんだけど超音波測距やサーボモータを使う上で(3.3V系では物足りなく)5Vを使いたく、一方ICによっては3.3Vでしか使えないものがあるからである。そのためI2Cレベルコンバータを追加した。

部品点数がだんだん増えてきて、組み立てに約半日を要した。特にSMDのハンダ付けにはいつも苦労する。 上手く繋がっていない場合もあるのでハンダ付け後は必ずテスターで導通具合をチェックする必要がある。あと、レベルコンバータのICには1番ピンを表す刻印が見付からず逆に付けて、取り外すときパターンを壊してしまった(仕方なく1号機は空中配線で凌いだ)。


こういう場合は、ICを文字が読める方向に置いて文字の下側の左端が1番ピンのようだ。

(続く)

 

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へ続く)


2024年6月12日水曜日

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

 ここで改めて何を作っているか要求項目を列挙すると、

  1. 人の出入りを検知して声でメッセージ(いらっしゃいませ、ありがとうございました、等)を出す。
  2. 電池で稼働できること(低消費電流)
  3. 専門知識が無くても使える事
  4. 気圧の変化を感じて何かのメッセージを喋る。
  5. 4.を処理するため時計が必要。
  6. 5. の機能を使って時刻に対応したメッセージを喋る。 
  7. 外部制御端子(発声時にONするなど)
  8. 電源電圧の監視と警告機能

といった ところであるが、これに付随して次のような機能を追加した。

  •  時刻、気圧(補正値)の設定
  •  喋る内容を設置環境に応じて変える(家庭用、店舗用など)。
  •  時刻、曜日を指定して喋る機能(毎日、週末、週末以外)
  • 定期的に時刻と気圧、気圧変化傾向を喋る機能
  •  夜間モード(夜間は発声抑止、LEDを暗くする、など)
  •  LEDの明るさを設定する機能
  •  

また次のような機能も実装を予定している

  •  時には声ではなくメロディを流す。

 これらを実現するため、コア部分には低消費電力のPICを使うが、PICに足りない機能は別途実装する。精密時計、気圧計、EEPROMなどである。

 これらのうち大部分はこれまで説明した内容であるが、LEDの明るさを制御するにはPWM(パルス幅変調)を使いデューティ比を変化させる。CLC(プログラム可能なロジックセル)を使ってこれとLEDのON信号とのANDをとったものをLEDに与える。この理屈は簡単であるが実際にこれをPICの機能を組み合わせて実現するには面倒臭いプログラミングが必要である。PIC18F27Q43には8つのCLCを内蔵するがそのうち4つをLED制御に使った。また3つ内蔵するPWM(パルス幅変調器)のうち2つを使って、1つを明るさの調整に、他をLEDのブリンク(点滅)に使った。

CLCを使う上での第一の関門はInput Data Selection on Gates である。ここではPIC内部の数十ある信号の中から4つ、及びその反転信号を選択して取り出すことが出来(つまり8つの入力信号ができる)、4つの出力はそれぞれ8つの入力信号の中から任意の信号を選んでORをとりその正論理又は負論理を取り出すことが出来る。つまりNAND、OR、それにロジック1の何れか及びその反転出力(AND,NOR,0)を実現できる。この出力が上図のkxg1~4である。

次にLogic Functionではあらかじめ設定された4入力の8つの回路(機能)のうちの1つを選択できる。そのうち4-AND、AND-OR、OR-XORを使った。それぞれ負論理で使うと4-OR、OR-AND、AND-XORとして機能させることもできる。次図は8つの機能の内の最初の4つである。

これらを使って赤LEDは次の様に点灯させている(図は分かり易いよう簡略化している)。

このなかのXOR(OR-XORを除く)の2つの入力は等価ではなく上が何らかの信号入力、下がソフトウェアでセットするビットである。即ち輝度はCLC2でBrightnessのPWMとANDを取っているが、警告信号は赤の連続点灯、電圧低下は赤のブリンクで示し、警告と電圧低下が重なった場合にはブリンクの明と暗の時間比を逆転させている。ここで信号名の前の「/」は負論理を表す。

(その6へ続く)

2024年6月10日月曜日

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

 その3に引き続き次のバージョンに向けた開発を進めている。SPIインターフェイスをUARTやI2Cインターフェイスに変更するため、基板を少し手改造した。具体的にはボイスシンセサイザはUART接続に、気圧計、時計、それに新たに追加するEEPROMはI2Cインターフェイス接続に変更した。

 また音階を出したいという要望があるので送信部と同じ8ピンのPIC16F18313を使いUARTで通信する事を前提に回路を設計した。音階はICを追加しないでPIC18F27Q43自体でも対応できると思うが割り込みを使っている関係上不規則に音にブツブツとノイズが入りそうなのでとりあえず安全策をとった。I2Cインターフェイスのデバッグでは安価(\1.5K程度)な中華製ロジックアナライザが活躍した。これはPulseViewというフリーソフトを使うと単にデジタル信号を見るだけでなくプロトコルの解析もできるので非常に便利で有効であった。次図は気圧センサー(LPS-25HB)の0x0F番目のレジスタにあるwho am i 値(0xBD)を読み出しているところ。

 I2Cインターフェイスで一番の問題だったのは時々クロックがローレベル(スレーブからの応答待ち)になったままハングアップする事である。一度ハングアップするとソフトの再起動では解決せず(I2Cデバイスにはリセット端子も無いため)一度電源を落とすしかない。 この点はスレーブからの応答待ちのないSPIが優れており、これに戻す事も検討した。そんな中でEEPROMの説明の中にソフト的にI2Cをリセットする方法が書かれていたのでこれを実装した(下図)。EEPROMはきちっとリセットしておかないと(内部状態が中途半端な時にコマンドを送ると)不正な書き込みが起こる事があるらしい。これでハングアップの問題が解決したのか分からないが必要な機能だろう。

 I2Cインターフェイスのデバッグが済んだ所でKiCADで3世代目のPCBの設計を始めたが、色気を出して最新の KiCAD 8.0 をインストールしたのが運の尽き。バージョン7.0で使っていたフットプリントの一部が使えなくなってしまった。が、いろいろ弄っているうちに何とか使えるようにできた。理由は不明。

 これを使って新しい基板を設計した。基板のサイズは前と同じである。

 前バージョンよりICが2個増えているのでこれらを詰め込めるか心配し、PICのピンの割り当てを配線がしやすいように変更したが実際にパターンを作ってみたらまだ面積に余裕があるようである。いざとなったら表面実装部品を裏面に配置する裏技もある。

 ボイスシンセサイザICにはこれまでATP3011を使っていたが、知らずに(ATP3011だと思って)ATP3012を買い、音が出なくて色々調べているうちにATP3012である事を知った。同時に両者が一部ピンコンパチブルではない事、またATP3012はサンプリング周波数が高く音質が良い事、外付けの発振子(セラミック発振子)が必要な事を知り、新しい基板は両者に対応できるよう設計しなおした(切り替え用のはんだジャンパーは基板裏面に配置した)。

 (その5へ続く)


2024年4月22日月曜日

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

  出入り検知器のソフトウェアであるが、最初はシリアルインターフェイスを通じてPCと対話する小さなモニターを作って、それを使ってPICの各ペリフェラルの機能を確認しながら次第に拡張していった。

 このやり方をこれからも続けるつもりである。昔、Intelの8ビットCPU(8080)のOS(Kernel)をアセンブラで書いたことがあり、PICでもOSを作った方が開発は楽だが、今更PICのアセンブラに手を出すつもりは無いのでKernelを作るのは無理だろう。

  現在のコンソール(モニター)コマンドは次の様になっている。


  そうこうしている内に次のバージョンのPCBの設計が終りに近づいている。それに合わせたソフトの設計も始めた。現バージョンで使っているSPIインターフェイスは設計やデバッグがやり易い反面PICの足(PIN)を多く使うのでPINが足りなくなる。新バージョンではそこをI2CやUARTに変えることで拡張性を担保するつもりである。またDMAやベクター割り込みを組み込めれば良いなと考えている。

 という事でソフトの説明はもう少し先送りする。

(続く)


2024年2月1日木曜日

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

 その1で説明したPCBであるが、必要な部品を搭載して次の様になった。

次はソフトウェアの番である。

1号機の場合、PICに16F15325を使い、メモリー容量やピン数の関係でモニターを搭載することが出来なかったが、今回の18F27Q43ではモニターを作って、動作を監視しながらプログラムを組み上げていくことができる。18F27Q43のブロック図を次に示す。使用したモジュールは赤で示した。18F27Q43はDMAを内蔵しているが、これを使いこなすところまでは行っていない。

18F27Q43ブロック図
 

 ソフトウェアといっても2023年末の段階でソースファイルが44個に分かれており(うち約半分はヘッダーファイル)簡単に説明できる内容ではないので、開発の概略を述べる。 なおソフトウェアの開発に伴ってハードウェアを修正した部分もあるので、その都度言及する。

プログラム開発の最初の段階では割り込みを使わないで、使う予定の個々のモジュールの設定と動作を確認した。18Fシリーズは機能が豊富で、16Fシリーズと同じモジュールよりも作りは複雑である。例えばPIC16F15325のSPI1とPIC18F27Q43のSPI1の制御レジスタは次の様に違っている。

PIC16F15325のSPI/I2C制御レジスタ構成

 PIC18F27Q43のSPI1制御レジスタ構成

16FシリーズではSPIモジュールはI2Cモジュールと共用になっていて、そのためのレジスタを含んでいる。16Fシリーズが1バイト毎に処理する必要があるが、18Fにはカウンタがあり、纏まった単位で転送できるようになっているようだ。ただし、この場合はDMAと併せて使う必要があろう。何が言いたいのかというと16Fシリーズのプログラムが18Fシリーズでは使えず、18Fシリーズの機能を調べて作り直す必要があるという事である。

信号に関わるプログラムを書くとき、その変更によって結果がどう変わるかを知りたい場合があるが、PIC内部にプローブを突っ込んで直接観測する手段はなく、PPSを使っていずれかのピンに取り出す必要がある。多くのデジタル信号はPPSでいずれかのピンに取り出すことが出来るが、PPSでのピンへのマッピングに制約がある。そこで全ての信号を扱うことが出来るCLCモジュールを使う事で任意の信号を1つのピンに選択的に取り出すことが出来るので、それをオシロスコープ等を使って観測する事ができ、このほ方法は初期のデバッグに役に立った。

 ・・・そうこうしているうちに、ソフトの開発に伴っていくつか変更点が生じたので次のバージョンの基板を発注した。この基板を最低要件の5枚発注して送料込みで3ドル以下である(基板は50%ディスカウント)。これなら毎週新バージョンを発注してもよいくらいである。

1週間ほど経って基板が届いたので早速部品を実装し動作を確認した。特に問題も無く、上手く出来たようである。


ソフトの話は次回以降に回す。

(続く)

 

 


 

 

2023年10月22日日曜日

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


前回の出入り検知器
で PIC16F5325では信号線数=足の数が足りなくなり、またメモリー不足となったので新しくPICを選びなおした。今回使うのは1つ上位のPIC18F27Q43である。このPICには2個のSPIインターフェンスと5個のUARTが搭載されており、さらにプログラムメモリーが128KB搭載(16F5325は14KBだった)されており今回の目的にぴったりである。さらに秋月で多くのPICが欠品になっている中で在庫があり価格も330円とお手頃である。一方難点としては足の数が28本あり基板上で2倍の面積を占めるためプロトタイプ用基板に乗らず製作がやや面倒である。

そこで今回は最初に専用の基板を起こす事とし、それと並行してソフトを開発することとした。

 受信部は次の2枚で構成される。赤外センサーを搭載する1枚目は更に2分割し、センサーを20cm離れて配置する。この基板にはVカットという手で割るための溝を入れてもらいたかったが、そうするためにはパネル化といい基板をm×n枚並べて面積を増やす操作をする必要があるが、今回はその数も必要無いし勉強不足もあり断念した。

2枚目が受診部の本体である。

 

送信部は特に変わっていない。前出の回路をそのままパターン化した。

 

これら3種の基板を各5枚ずつ発注し(発注数の最小要件が5である)、最も安い配送料も合わせて全部で11ドルでお釣りがくる(一部ディスカウントを含む)。 

基板の発注と並行してソフトを開発していたが、重大な問題に直面した。PIC18F27Q43の各信号とポートの間のマッピング(PPS)に、例えば次のように制約があるのである。例えばSPIのデータとクロックはポートAにマッピングできない。

入力

出力

基板は、全ての機能が任意のピンにマッピングできる事を前提に設計したのでこれには参った。配線のカットとジャンパー接続が必須になる!!!PIC18F27Q43のマニュアルは英文で千ページほどあるので細かい所は読み切れていない。

何処を切って何処にジャンパーを繋ぐかを知るために、実際に使う機能と足の関係を調べると、何と、ソフトの設計変更だけでジャンパー無しで済むことが分かった。 例えばUART3⇒UART4、UART5⇒UART3の変更で済む。これはUART毎に使えるポートが違うからである。

発注から1週間ほどで基板が届いたので、組み立てた。CADでは部品の密度をできるだけ上げたつもりでも、実際に基板を組み立てるとスカスカである。そして幾つかの問題を見付けた。1つはスイッチのフットプリントがインチサイズではなくmmサイズになっていて、挿入に少し無理があった。もう1点は回路図⇒基板の間はCADでチェックされているので問題はなかったが、大元の回路図が間違っていた。具体的には可変抵抗のピン番号が逆順であった。つまり可変抵抗は3つの端子が左利回りに1,2,3の筈であるが、私が使った製品は逆順であり(同じモデルで正順の製品もある)、右に回すほど音が小さくなる。あと、音声合成ICの通信モードの2つの選択ピンの番号が逆であった。いずれも基板のカットとジャンパーで修正した。

これらの誤りは次の発注ではで修正する。

(続く)

2023年5月9日火曜日

赤外線で通信する 出入り検知器(まとめ)


 これまで出入り検知器を作ってきて、3作品目で一応納得できるものに仕上がった。

【送信部】

 送信部の回路には特に変更はない。

 【受信部】

受信部にはフォトリレーを追加して発声時以外はオーディオアンプの電源を切るようにした。その結果10mAあった通常時の消費電流を3.0~3.5mAまで低下できた。さらにフォトリレーを追加した結果、発声に伴って外部の回路を制御できるようになった。

 

【その後】

これまでの回路に気圧計とRTC(リアルタイムクロック)を追加した。

しかしそのままではPICの足が足りないので、代償としてLEDを廃止した。追加回路は2段目の基板に組み込んだ。

 気圧計のプログラムを書いているうちにメモリーをほぼ使い切ったのでRTCの処理まで進めなかった。PICをもう少し足の数とメモリー容量の大きいものに変える必要がある。またLEDを廃止した事で内部の状態が分かり辛くなったので、LEDも復活したい所である。


2023年4月29日土曜日

赤外線で通信する 出入り検知器(その3)

 【受信部】 

今回PICとボイスシンセサイザとの間をI2Cインターフェイスで繋いだ。I2Cインターフェイスをデフォルトのピン割り当てで使う場合は素直に使えるが、一方他のピンに割り当てる場合は少しややこしい。PIC16F15325のマニュアル15.3項のNoteによると特定のピン(RC3,RC4)だけがI2Cの入力レベル(スレッショルド)に対応しており、他のピンを使う場合はその設定の追加が必要。I2Cはデータとクロックの2つの信号を使うがPICでは2つの信号とも入力に初期設定するだけでなくスレッショルドの変更が必要であり、さらにPPSでは入力だけでなく(当然であるが)出力としても設定する必要がある。今回は以下のように記述した。

     // 12:RA1 - I2C CLK - Bidirectional
    TRISAbits.TRISA1 = 1;   // set Abit1 to input
    ANSELAbits.ANSA1 = 0;   // set Abit1 to digital
    INLVLAbits.INLVLA1 = 1; // ST level instead of TTL
    WPUAbits.WPUA1   = ON;  // weak pull-up
    RA1PPS          = 0x15; // SCK1/SCL1
    SSP1CLKPPS      = 0x01;
    
    // 13:RA0 - I2C DAT - Bidirectional
    TRISAbits.TRISA0 = 1;   // set Abit0 to intput
    ANSELAbits.ANSA0 = 0;   // set Abit0 to digital
    INLVLAbits.INLVLA0 = 1; // ST level instead of TTL
    WPUAbits.WPUA0   = ON;  // weak pull-up
    RA0PPS          = 0x16; // SD1/SDA1
    SSP1DATPPS      = 0x00;
 

このI2Cインターフェイスを使ったボイスシンセサイザとの通信は、一見上手く行ったように見えていたが暫く使っているとI2CのSCK(クロック)がLowになったままハングアップした。電源を入れなおしても同じだ。調べると同じような事例もあり、I2Cはソフト的には結構ややこしくロジックアナライザ無しではデバッグも容易でないようだ。よって、I2Cに代えてSPIインターフェイスを使うように変更した。SPIインターフェイスは構造が簡単で送受を同時に行うのが特徴。ソフト的な扱いも単純だが4本も信号線を使うので(最初は/SSをL固定し、それ以外の3本で通信を試みたが上手く機能しなかった)I2Cの2本と比べてPICの足数から自由度が減る事が残念だ。

 受信部のプログラムは1000行にもなるのでここでこれ以上掲載するのは止めて、そこで使っているロジックについて概要を解説する。

受信部の最初のポイントは、2つのIRセンサーで赤外線信号を定常的に受信出来ている状態は無情報であり信号欠落した事が情報(イベント)となる事である。これは5ms毎の割込みとソフト的なカウンタで処理することができる。

2つ目のポイントは 2つのIRセンサーの前をどう横切った時どう判断してどんなメッセージを流すか、またノイズをどう排除するかである。

このプログラミングには条件を細かく設定して分岐で処理しても良いが、そうするとプログラムがスパゲティ状態になり天才でもない限り行き詰まるか保守できなく事は目に見えている。こういう場合はステートマシンを使うのが早道である。ステートマシンでは「状態」と「イベント」を定義し、イベントの発生に伴う「アクション」と「状態の遷移」を表形式でプログラミングすることでロジックの「穴」を防ぐことができる。ステートマシンは有向グラフや状態遷移表で表す事が出来る。

 今回使うイベントは、
    C0)2つのセンサーが信号を受けている
    C1)センサー1が遮られた
    C2)センサー2が遮られた
    CB)センサー1及びセンサー2が遮られた
    TO)タイマーが設定した時間を経過した
の5つとした。また状態としてはシンプルに、
    IDL) 初期状態
    SYN) 人がいない(2つのセンサーでデータを受信)
    EN1)人がセンサー1の前に入った
    OV1)人が両方のセンサーの前まで進んだ
    EX1)人がセンサー1を通り過ぎた
    EN2)人がセンサー2の前に入った
    OV2)人が両方のセンサーの前まで進んだ
    EX2)人がセンサー2を通り過ぎた

とした。これを使って人一人の基本的な動きをトレースするためのステートマシンは次の状態遷移表になろう。この遷移表で実線で囲まれた各升目には3つの欄があり、それぞれある状態にあるときに、あるイベントを受けたときの メッセージタイマー操作次の状態への遷移を表している。 

このステートマシンはTimer0で5ms毎に実行されるようにしている。

IDLが初期状態で、2つの赤外センサー両方で赤外線を感じる(C0)とSYN状態に移行する。SYN状態が赤外線が遮られていない定常状態である。遷移表で灰色の網掛けは同じ状態に留まることを表している。

人が入店する場合は、
SYN→(C1)→EN1→(C3)→OV1→(C2)→EX1→(C0)→SYN
と移行するはずである。逆に人が退店する場合は、
SYN→(C2)→EN2→(C3)→OV2→(C1)→EX2→(C0)→SYN
と移行するはずである。単純に考えればEX1→(C0)の時に「いらっしゃいませ(WELCOM)」、逆に
EX2→(C0)の時に「ありがとうございました(THANK)」と発声すればよい。

しかし、事はそう単純ではなくこの表には空欄が多い。つまりまだ振る舞いが定義されてない条件がある事が分かる。空欄を全て埋めてステートマシンは完成する。例えばEN1-(C0)は人がセンサー1まで来て引き返した場合である。この時どう反応すべきか。またSYN-(CB)等のようにオレンジで網掛けしている欄は人一人の移動としてはあり得ない状態であり、たぶん二人の人がすれ違った場合、或いはセンサーが赤外リモコン等ノイズを拾った場合か、または送信部がいきなり停止した場合などが考えられる。このような場合にどう振舞えばよいか、このシステムへの要請に応じて欄を埋める必要がある。

これを実際に埋めてみたのが次の遷移表である。INITは電源を入れた時一度だけ通る状態であり、2つの赤外線を最初に感知したときチャイムを鳴らすために設けた。なお、このステートマシンは人が一人の場合は正しく判断できるが二人が絡むと結果は予測できない。

ここでT+2は2秒のタイマーを設定、Toffはタイマーを止める事を表す。赤色で示した欄はこの状態になることは無く何らかの内部エラーが発生した事を表すので動作としてはエラーと叫んでIDL状態に戻す事とした。またオレンジの欄も一人の移動では発生しない状態なので、「今日も良い天気」「大谷がんばれ」「大吉」など幾つか用意したメッセージをランダムに選んで発声するとともにIDLやSYN状態に戻す事とした。なお実際のメッセージは次の様になっている。
    HELLO        こんにちわ
    WELCOM    いらっしゃいませ
    THANK        ありがとうございました
    CHM            チャイム音
    ERR            エラー
    RDM         (ランダムなメッセージ)

このほか、「送信機の電圧が低下しました」、「受信機の電圧が低下しました」なども必要に応じて喋るようにしている。 

このステートマシンをプログラミングし実際に動かしてみたら上手く動いているようだ。センサーの前を移動したとき簡略化した状態遷移は次のようになった。

ID-S1-ET
ID-S2-e0-S2-e0-S2-e0-S2-e3-o2-eT
ID-S2-e0-S2-e0-S2-e0-S2-e0-S1-ET
ID-S1-E0-S2-e0-S1-E0-S1-E0-S2-e0-S1-E0-S2-e0-S1-E3-OT-O1-E0-S1-E3-O2-X0-S2-e3-o1-x0-S1-E3-O2-X0-S2-e3-o1-x0-S1-E3-OT-O1-E0-S1-E3-O2-X0-S2-e3-o1-x0-S1-E3-O2-X3-O2-X0-S2-e3-oT
ID-S2-e3-o1-x0-S1-E3-O2-X0-S3

ここでIDがIDL状態、S1がSYN状態で1番のイベントが発生した事を表す、EOXの各文字はそれぞれEN1,OV1,EX1、eoxの各文字はそれぞれEN2,OV2,EX2、また0123Tの各文字はそれぞれC1,C2,C3,TOのイベントを表す。

このシーケンスを見てセンサーの前で何が起きており、どういうメッセージが発声されているか分かるだろうか。例えば最初の ID-S1-ET は人が入口からセンサー1まで移動し、その状態で2秒経過したので「こんにちわ」と発声した事を表す。

なおステートマシンが5ms毎に動くのに比べ発声には時間がかかるので発声要求はキュー(FIFO)に入れて順次喋るようにしている。

  このようなプログラミングの答えは1つとは限らない。もっと複雑な動作をさせたければセンサーを増やしたり状態の数を増やすのも良いだろう。目的に合ったステートマシンを構築すれば今回のように一人ではなく二人の動作を追跡できるかもしれない。昨今流行のAIに作らせる/DEEP LEARNINGで学習させることも出来るかもしれない。

話は変わるが、最近PICが品薄のようである。 今回使った16F15325は秋月で在庫なし。そのほか多くのPICが在庫なしで入荷予定も立たないという事であった。EUSARTを2個内蔵したPICで手頃なものはこれしかないので困ったものである。


2023年4月26日水曜日

赤外線で通信する 出入り検知器(その2)

【送信部】

  先ず、前回以降送信部のPICを同じペリフェラルを持って安価な16F18313(8ピン)に替えた。ピンの接続変更、及びソフトでのピンマッピング(PPS)の変更以外は何もせずそのまま動かすことができた。

この送信部はPIC16F18313を使って次の様に、秋月の片面ユニバーサル基板(47×36mm)の半分を使ってコンパクトに組み立てる事ができた。この大きさなら何かに組み込むことも容易だ。

送信部は一定間隔でひたすらデータを送信するのみで何も特別な事はしない。

さて、実際のプログラムであるが全体を説明しても冗長なのでキモの部分に絞って説明する。初期設定を終えた後のメインプログラムの主要部分は次の通り。

    INTCONbits.PEIE = ON;     // Enable Peripheral Interrupt
    INTCONbits.GIE  = ON;     // Enable Global Interrupt
    T0CON0          = 0x80;   // Enable Timer0, 8bit, post=1:1
    T0CON1          = 0x90;   // LFINTOSC, Async, Pre=1:1
    TMR0H           = 62;     // tick for every 2ms
    PIR0bits.TMR0IF = OFF;
    PIE0bits.TMR0IE = ON;     // Start Timer0 Interrupt
//main loop    
    while(TRUE){
        SLEEP();              // wake every 2ms and UART intr.
        // Show Battery Warning
        if(low_batt){
            if(--bl_blk_cnt==0){
                r_led_on = !r_led_on;
                R_LED(r_led_on);
                bl_blk_cnt  = (r_led_on) ? BL_BLNK_ON : BL_BLNK_OFF ;
            }
        }else{

            r_led_on = OFF;
            R_LED(
r_led_on);
        }
    }

つまり、Timer0の2ms毎の割込みをONにした後SLEEP()する。SLEEP()は2ms毎及びその他の割込みが起きると目覚めるので、もしその時電圧低下(low_batt)フラグが立っていれば赤色LEDを点滅させる。

 割込みサービスルーチンは次の通り。

void __interrupt() isr(){
    if(PIR1bits.TXIF && PIE1bits.TXIE) sendISR();
    if(PIE0bits.TMR0IE && PIR0bits.TMR0IF){
        Y_LED(ON);
        tickISR();    PIR0bits.TMR0IF = 0;
        Y_LED(OFF);
    }
}

もしUARTの送信可割込みであればsendISR()を呼び出す。Timer0割込みであればY-LEDをONにし、tickISR()を呼び出した後Y-LEDをOFFにする。これによって2ms毎の割込みが機能していることが分かる(黄色LEDが薄く点灯する)。

sendISR()は次の様に、送信データがあれば送信、データが無ければ割り込みをOFFとする。

byte        *bufp; 

void sendISR(void){
    byte d  = *bufp++;          // get next data
    if(d == 0){
        PIE1bits.TXIE = OFF;    // Disable Interrupt
        bufp--;                 // guard
    }else{
        TX1REG = (low_batt)? (d | 0x80): d; // send data
    }
}

ここで送信データのビット7は受信部に電圧低下を知らせるフラグとして使っている。

送信の起動は次の様にバッファにポインタをセットし割り込みを可とすることで行う。通常この行を実行した瞬間に割込みが発生する。

void sendUART(byte *buf){
    bufp            = buf;
    PIE1bits.TXIE   = ON;
}

tickISR()(タイマー割込み)ではカウンタを設けて40ms毎にデータを送信、及び30秒ごとにバッテリー電圧のチェックを行っている。

static int      cnt     = (TX_PERIOD/TICK_TIME);
static byte     key     = KEY_MIN;
static byte     dat[3]  = "  ";
static uint     bccnt   = BC_PERIOD/5;   // battery check counter

void tickISR(){
    // Send data, every 40ms
    if(--cnt==0){
        dat[0] = key;
        dat[1] = key ^ KEY_SWAP;       // toggle lower 7 bits
        sendUART(dat);
        key++; if(key>KEY_MAX) key = KEY_MIN;
        cnt = (TX_PERIOD/TICK_TIME);
    }
    // Battery Check, every 30sec
    if(--bccnt == 0){
        low_batt = is_bat_low();
        bccnt = BC_PERIOD;
    }
}

送信するデータはKEY_MINからKEY_MAXまでのデータを繰り返している。

 バッテリー電圧はA/Dコンバータでチェックする。10ビットA/Dコンバータは2つの参照電圧(Vref+、Vref-)間を1024(=2^10)段階でデジタル化してくれる。参照電圧に内蔵の2.048Vと0Vを選ぶと1ステップが2mVとなる。実際には精度が10ビットも必要ないので上位8ビットを使って1ステップ8mVとしている。さらに電源電圧は3.3Kと1.5Kで分割してA/Dコンバータに与えているので、その比率を加味すると1ステップ25.6mVに相当する。バッテリーの電圧チェックは次の通り。

#define BC_LEVEL        104     // Voltage Threshold, 0.0256V step

boolean is_bat_low(){
    ADCON0bits.GO   = 1;        // Start Conversion
    while(ADCON0bits.GO==1){}   // Wait until complete
    bt_data = ADRESH;
    return (bt_data < BC_LEVEL);
}

このA/D変換は数μsで終わるので実行時間に与える影響はほぼ皆無である。
最後に、A/Dコンバータの初期化は次の様に行っている。

void Init_AD(){
    // AD Converter
    ADCON0bits.CHS  = 4;    // CHS=ANA4,  A4 for input
    ADCON0bits.ADON = 1;    // AD ON
    ADCON1      = 0x53;     // Fosc/16(=1us), Vref+ is FVR
    ADACT       = 0x00;     // No auto conversion
    // FVR
    FVRCONbits.FVREN    = 1;    // Enable
    FVRCONbits.ADFVR    = 2;    // ADFVR=2.048V    
}

(その3)へ続く

2023年4月8日土曜日

赤外線で通信する 出入り検知器(その1)

 PICを使った 赤外線の送受信及びタイマーと割込みの扱いが理解出来たので、これを応用して人の移動を検知してアクションを起こす簡易なセンサー(入退出検出器)を作ってみる。

【概要】

 人の出入りを検知するには焦電素子を使った人感センサーを先ず思いつくが、これは指向性や反応速度が緩いうえに焦電センサーは赤外線輻射量の変化を検知するので前を通る車や風にも反応し条件が整わないと上手く反応できない。超音波やマイクロ波を使ったレーダー式は周囲に物を置いた状態では検知しずらい。カメラの画像解析は良さそうだが高価になりそうという事で、光電管式ネズミ捕りと同様な仕組みをこれまで試した赤外線を使って作ってみる事とした。

 基本的なアイデアは次の通り。


 送信部では赤外線をある短い間隔で水平に発信する。受信部では水平に離れた2点で赤外線を受信し、人が赤外線を横切った場合の赤外線の断を検知して人の移動を判断し何らかのアクションを行う。

【検討】

 赤外線の遮蔽を的確に検知するには短いパルス状の信号を連続的に送る事が好ましいがリモコン受光部の特性から100msの周期中に25msの休止も必要。ノイズの影響を排除するためには偽信号をチェックするカラクリも欲しい。一般にUARTの信号にはパリティを付加できるがPICのEUSARTにパリティの機能は無い。但しデータに9ビット目を付加できるのでソフト的にパリティビットを実現することは可能であるが面倒、という事でビット反転させた2つのデータを連続して送る事で到達チェックすることにした。これで最短34ms毎の検出が可能となる(実際には約40msに設定した)。ちなみに本装置の受光部はTV等のリモコンの赤外線にも反応するが、このやり方で誤検知を防ぐことができる。

 人の移動速度はせいぜい時速4Km(秒速1.1m)とし、人の前後の厚みを25cmと仮定すると1つのセンサーの前を人が通過するのに必要な時間は227msとなるので送信部で40ms毎に信号を出すと受光部で最低5回のパルスの欠落が発生し探知が可能である。

 では2つのセンサーの間隔はどれくらい必要だろうか。出来れば1回でも人が両方のセンサーを同時に遮蔽することが望ましいので20cmでトライしてみよう。20cmの間隔を秒速1.1mで進むと1つ目のセンサーを通過した後2つ目のセンサーに到達するのに180msかかり、その間40ms毎のパルスを4回は遮る事になる。これで検知区間の単独の通過とその進行方向を検知できる。

 さて2つのセンサーで人の出入りを監視するロジックであるが、単に出入りのチェックだけやるのであれば簡単であるが、途中で引き返したり、真ん中に長時間留まって多少左右に動いて作業したり、TV等のリモコンの赤外線に干渉されたり、実用に使うには様々な問題がある。それらを含めてどれだけだけ正確に検知できるか、がソフト作りの腕の見せ所である。

 とりあえずこれまでの経験をもとに次のようなハードウェアを作成した。

【送信部】 

 送信部は次の回路とした。回路で新しく追加したのはA/D変換器を使ってバッテリー電圧を監視できるようにしたところ。バッテリー電圧が概ね2.7Vまで下がると電圧低下の警告が出るようにし、また送信信号にもその情報を入れるようにして受信側で警告が出せるようにした。PICを使うとバラで組むより配線をかなり簡略化できるのが嬉しい。

 次の写真が実際に秋月の汎用基板に組み立てたところ。黄色LEDは割込み処理中に点灯し、赤色LEDはバッテリー電圧低下(2.7V位)で点灯させる。LEDごとにシリーズ抵抗が違うが、黄色はデューティ比が低い一方赤色は連続点灯なので、LEDの明るさを見て暗めの適当な明るさに調整した結果である。この回路全体の消費電流は2.5mA。単2電池二本で数ヶ月持つ事を想定してる。電池3本(4.5Vでも問題なく使える)。

 その後PICを同じペリフェラルを持つ16F18313(8ピン)に替えたがピンの接続変更、及びソフトでのピンマッピング(PPS)の変更以外は何もせずそのまま動いた。

【受信部】

 受信部は次の回路とし、新しく音声合成ICとスピーカを鳴らすためのオーディオアンプを追加した。PICと音声合成ICのインターフェイスはUARTも使えるがPICの2組のEUSARTを赤外線入力に使って余裕が無かったためI2Cを使った。音声合成ICのUARTインターフェイスはPCと繋ぎPCから音声データの発声テストを出来るようにしている。JP3は人の入退室方向を反転させるためのジャンパー、JP4はPICのUSART2をデバッグ用インターフェイスとして使う場合にショートする予定だったがこれまでの所出番はなかった。

  この回路の消費電流は定常時で10mA程度であるが音声発声時に大きく増えるためUSBで電源供給するようにした。また電池駆動も考え、電源電圧が約4.5Vまで低下すると警告を出すようにした。

 次の写真が実際にこの回路を秋月の汎用基板に組み立てたところ。28ピンの音声合成ICが大きな面積を占有している。

なお、PICから制御信号を出す事で音声合成ICやオーディオアンプをスタンバイ状態において更に消費電力を減らす事も可能なようなので後で検証したい。

 
(その2)へ続く