Raspberry Pi Zeroを使った模型コントローラ(Ver.2)の作成
はじめに
前回作成したEdisonによる模型コントローラ(Ver.1) よりも、小型のコントローラをRaspberry Pi Zeroを利用して作成しました。スペックは以下の通りです。
Ver.1のコントローラーを作成した後になってから、Raspberry Pi Zeroと新しいモータードライバの存在を知りまして、これを使えばもっと簡単に作れるじゃないか、ということに気づいたので作りました。
回路図
非常に簡単な回路構成で、買ってきたモジュール同士を線で繋いだだけで作れてしまいます。 必要なモジュールは以下の通り。
Pololu Step-Down Voltage Regulator D15V35F5S3
Pololu TB6612FNG Dual Motor Driver Carrier
Raspberry Pi Camera module v2.1
電源は、外部から6V~13Vの直流電源を接続します。これはそのままモータードライバへ入力されます。モータードライバTB6612FNGは、TA7291Pのように電圧の調整機能がなく、入力したモーター用電源電圧がそのままモーターに出力されるので、外部電源の電圧はモーターにかける電圧と一致させておきます。モータードライバは1つのICで2チャネル、基盤全体で合計4チャネルあります。
Raspberry Pi Zeroへの電源を供給するために、5V/3.5AのDC-DCコンバータを使っています。USBに無線LANドングルを挿したり、デバッグ時にはキーボードなども繋ぐため、少々大きめの電源にしています。D15V35F5S3という電源は、今回使う部品の中で2番目に高価なものです。(1番高いのはカメラモジュール)
ADコンバータは、ポテンショメーターからの位置取得用に利用されます。MCP3008は8チャネルありますが、今回は3チャネル分しかコネクタを取り付けていません。SPI通信でRaspberry Pi Zeroと接続します。このADコンバータはRaspberry Piとの組み合わせでよく使われるようで、検索すれば使い方を説明しているサイトが多く出てきます。
モータードライバの制御用電源とADコンバータの電源は、Raspberry Pi Zeroの基板上で作られている3.3Vの電圧を利用します。GPIOの電圧と一致させて、ロジックレベルの変換を不要とするためです。何mAくらい使っていいのかよく分かりませんでしたが、この回路構成で問題なく動いています。
以前(Ver.1)の基盤では、ドライバへの入力がプルダウンされておらず、OSが起動するまで不定値となってしまい、電源投入後にモーターが動いてしまうという問題がありました。このモータードライバはIC内部でプルダウンされているので、外付けでプルダウンを追加する必要はありません。
このモータードライバは、正転・反転・停止・ブレーキの4種類の動作があります。停止というのは、単に電源供給を停止してモーター端子の間に電流を流れなくします。この場合、モーターは慣性で回り続け、徐々に止まっていきます。一方、ブレーキというのは、モーター端子を短絡させた状態とさせることを意味しており、この場合はモーターは発電機として働き、その回転は電気エネルギーとして端子間を流れて熱に変換されて消費されていきます。そのため、停止にするよりも即時に完全停止します。ブレーキ状態のときにモーターの軸を外部から回転させようとしても、発電機として働いて非常に大きな負荷が接続されている状態なので、非常に回しにくくブレーキの効いた状態になります。
モータードライバとDC-DCコンバータは、スイッチサイエンス社から通販で購入できます。Raspberry Pi Zeroは日本ではまだ売ってないため、Pimoroni社から通販で購入します。海外からですが2週間程度で届きました。
Raspberry Pi Zeroと作成した基盤は、GPIO用40ピンヘッダーで接続します。40ピンヘッダーから電源のやりとりも行えます。5V電源の供給は2,4番ピンから行って問題ないようです。
基盤はTNF34-124というのをカッターで切断して利用しました。Raspberry Pi Zeroの基盤の大きさとほぼ同じ大きさに詰め込めました。
モータードライバのピッチ変換基盤の下に配線を入れてしまったので、いったんモータードライバ基盤をはんだ付けしてしまうと、間違っていた時に修正がめんどくさくなる構成になってしまいました。取り付け前に配線が間違っていないか念入りに確認しておきます。
実は基盤が完成した後で、規格外のモーターを接続してモータードライバを壊してしまいまして、そのときは修理が大変でした。ピッチ変換基盤を取り外そうとしましたが、基盤がスルーホールではんだを完全に取るのが大変だったのであきらめました。その代わりに、SOPのTB6612FNGをカッターナイフで取り外し、単体で購入してはんだ付けしなおしました。SOPのICは、足を壊していいなら取り外すのは結構簡単です。カッターで切断して取り外し、残った足は、はんだごてとはんだ吸収線で簡単に除去できます。
ソフトウェア
無線LANドングル
左がWLI-UC-GNM、右がOfficial Raspberry Pi WiFi dongle
Raspberry Pi Zeroを無線LANに接続するのは、けっこうハマりました。いろいろ必要な部品がセットになっていたので、Pi Zero CCTV Kit (Little Bro) - Pimoroniというセットを買ったのですが、これに付属していたOfficial Raspberry Pi WiFi dongleが、どうやっても自宅の無線LANルーターと接続できませんでした。ハードウェアは正しく認識されて、ルータのSSIDは表示され、パケットも少しはやり取りできているはずなのに、DHCPのアドレスが取得できず通信できませんでした。固定IPにしても無理でした。そこで、ネット上で動作報告のあった、バッファローのWLI-UC-GNMを試しに買ってきて接続してみたら、一発で動作しました。無線LANに詳しくないので原因はさっぱりわからずじまいでしたが、この件で2日ほど無駄にしました。
カメラからの動画取得
最初は、CCTVキットを動作させる方法を説明している「Make a Raspberry Pi CCTV security system | Expert Reviews」の通りにすれば、すぐに画像が出ると思っていたのですが、motion-mmalcamを動作させるためのライブラリがインストールできないものがあり、すぐに暗礁に乗り上げてしまいました。
OSには、Raspbian JessieのVersion May 2016を使っていたのですが、この環境だとうまくいかないのかもしれません。検索してみると、以下のサイトで書いてあるのと全く同じ状況になっており、mjpg-streamerを使うと動いたと書いてありましたので、その通りにしたらすんなり動きました。大変感謝です!
ソフトウェアPWM
ソフトウェアPWMには、最初はpigpio libraryを利用しようとしましたが、うまく動きませんでした。PWMだけでなく、普通のIO制御も全くできませんでした。ライブラリにはZeroでも対応していると書いてあるため、Raspbian Jessieだと、現時点で正常に動かないだけなのかもしれません。代わりに、RPi.GPIOでもソフトウェアPWMに対応しているようだったので、使ったらすんなり動きました。
ただし、ソフトウェアPWMはCPUの負荷が高いようなので、mjpg-streamerと同時に動かすとモーターの音が乱れます。Zeroはシングルコアなので余計に負荷の影響を受けるのかもしれません。対策として、動画のフレームレートを落とすと影響が少なくなるようなので、画像サイズ640x480にて5~10FPSに設定しています。
Ver1.0のコントローラ基盤との大きさ比較
奥のものがVer1.0の基盤です。部品点数が大幅に減って小型化しました。また、配線が楽になって大幅に作りやすくなりました。コスト的には、高かったEdisonが安いRaspberry Pi Zeroに置き換わったうえ、部品点数も減ったのでトータルでは少し安くなっていますが、海外からの送料などもあるので、大幅に安くなってはいないです。
ちなみに、Pimoroniで売っているPibow Zero Case for Raspberry Pi Zero version 1.3に入れると以下の写真のようになります。webに組み立て図があるのを知らずにパズルのように部品を組み立てたら、どの層のパーツなのか分からなくて迷って結構大変でした。取り付けると結構大きくなってしまうので残念ながら取り外し予定。
PC側の操作アプリケーション
以上によって、無線LAN経由でカメラとモーターと位置センサの情報が取得できるようになりましたので、次は操作するクライアントアプリケーションを作成します。前回(Ver.1)ではpythonでTornado(webサーバ)を起動させて、webブラウザから制御できるようにしたため、webブラウザさえあれば操作できました。この方法ではスマホ等からでも操作できるという利点はあったのですが、スクロールバーで操作するのは使いにくかったため、今回は専用のWindowsアプリケーションを作成することにしました。
クライアントアプリ(操作アプリ)は、.Net Framework (C#)で作成します。ユーザーインターフェイスはWPFを使うことにしました。通信はソケットを利用した文字列によるコマンド/データの送受信を行います。メインスレッドからインターバルタイマーによる一定周期にてRaspberry Piへのコマンド送信を行い、別スレッドにてRaspberry Piからの受信を行います。別スレッドからWPFのUI描画を直接行う際には、Dispatcher.BeginInvoke()を利用するのを忘れてはなりません。
(※画像はデザイン時用のハメコミです)
ジョイスティックによる操作
ジョイスティックによるモーター操作をできるようにしました。X,Y軸の倒れとPoVボタンの上下方向をZ軸として使っています。写真のジョイスティックではZ軸の回転も取得できるのですが、これは用途が思い付かなかったので利用していません。
ジョイスティックを使うのはDirectInputを使えばいいことは分かっていたのですが、.Netからどのように使うのか分かりませんでした。調べたところ、DirectXのmanagedラッパークラスライブラリである「SharpDX.DirectInput」を使えば楽なようです。(これは個人の方が開発されたものです。Microsoftが提供しているライブラリは探したけどありませんでした。)NugetのPackage Manager Consoleから「Install-Package SharpDX.DirectInput」と打ち込むだけでOKです。DirectX SDKのインストールは必要ありません。具体的な利用方法は、「Taking input from a joystick with C# .NET - Stack Overflow」のページに書かれています。基本的な使い方として、定期的にジョイスティックログを読みだして、注目する種類のログのタイムインデックスにおける最新の値のみを適用します。過去のタイムインデックスは、おそらく操作の速度を知りたい場合などに必要となりそうです。
Motion JPEG (mjpg)ストリームの表示
mjpeg-streamerには、画像スナップショットをhttpで1枚1枚読み出す方法が提供されているので、それ経由で画像を取得してからWPFのImageに表示させて、DownloadCompletedのタイミングでまた次の画像を取りに行く(javascriptではそうやって表示させている)という方法を最初に試しましたが、画像の更新が遅すぎて断念しました。検索してみると、「MJPEG Decoder」というライブラリを見つけたので、使ったらすんなりと滑らかに画像が表示されました。使い方はこちらのページなどに書かれています。
ソースコード/インストール方法
ここで公開予定です。
履歴
2016/9/3 初版
2016/9/19 PC側アプリを追加
2016/9/23 Pibow Zero Caseの写真を追加