ネットワークカメラの製作 2012.8.29


    1.はじめに
    カメラモジュール
    FIFO付きカメラモジュール

     トランジスタ技術2012年3月号で、「始めよう!チョコッとカメラ」という特集があり、それを読んで、これは面白いと、直ちに、特集の中で紹介されていたカメラモジュールを購入した。手持ちのマイコンは、PIC24FとdsPIC30Fの低速マイコンなので、接続が容易なFIFOメモリの付いたモジュールを購入した。

     このカメラモジュールに、ラジコン用サーボモーターを組み合わせ、パン・チルトが制御可能なネットワークカメラを製作した。ネットワークカメラと呼ぶからには、LAN接続が必須であり、TCP/IP内蔵のLANモジュールを使った。

     ネットワークカメラは、自宅サーバーのWebページを通じて制御できるようにした。これにより、自宅以外のどこからでもインターネットにアクセス出来る環境があれば、カメラ画像を取得したり、カメラを制御することが出来る。


    2.製作概要

     製作したネットワークカメラ。
    パン用のサーボはタッパーの中にある。

     使用した主な部品は、PICに「dsPIC30F2012」、カメラモジュールは、トラ技の特集で紹介があったOV7670カメラチップにAL422のメモリチップが載ったもの。それとTCP/IP内蔵LANモジュール。さらに、ラジコン模型用のサーボモーター2個である。

     PICは、SPIやI2CインタフェースがあることとデジタルI/Oが最低でも10端子はあるものという条件で、手持ちのマイコンの中から「dsPIC30F2012」を使った。カメラモジュールについては、トラ技の特集や、販売元の日昇テクノロジーの商品サイトを見て頂ければよい。

     LANモジュールは、IP電話機を製作した時に使ったWIZ812MJの後継廉価版であるWIZ820ioを採用した。WIZ820ioは、チップにW5200を使っており、ソケットが最大8ソケット(W5100は4ソケット)使える優れ物だが、マイコンとのインタフェースは、SPIのみ。

     SPI以外にパラレル接続などがあっても端子数の小さなマイコンでは、おのずとSPI接続を選択することになるから、これはこれで納得。WIZ812MJと同様、ストロベリーリナックスから購入した。

     カメラモジュールを左右、上下に首振りさせるためのサーボモーターは、ロボット製作に使うようなハイトルクの物は必要なく、以前に通信販売で安く手に入れたQuickの「e-STD Servo」という物を使った。

    dsPIC30F2012
    WIZ820io
    W5200
     カメラモジュールとチルト用サーボモータ

    3.設計と製作

    図1 ネットワークカメラ制御回路
     設計といっても大したことは何もない。各部品を決められたインタフェースで接続するだけだ。設計した制御回路を図1に示す。

    カメラモジュールの接続

     OV7670は、I2Cに似たSCCBというプロトコルで制御する。そこで、カメラモジュール単体の動作確認では、dsPIC内蔵のI2Cインタフェースで接続したが、LANモジュールとの接続でSPIを使うと、dsPIC30F2012では、I2CとSPIの端子が競合してしまう。そこで、OV7670の制御はI2Cではなく、デジタルI/OでSCCBプロトコルを処理することにした。

     また、カメラモジュールのFIFO制御のためにも、I/O端子が数端子必要であり、dsPIC30F2012のI/O端子が足らなくなった。そこで、FIFOから読み込むデータは、本来8ビット必要なのだが、下位2ビットを省略してしまった。FIFOメモリの出力であるDB0からDB7の内、下位のDB0,DB1はマイコンに接続していない。また、HREF、XCKの端子は使用していない。

     画像データの下位2ビットを省略したので、RGB888の24ビットで読み込んでも、実質18ビットであり画質低下を起こすことになるが、RGB565などのフォーマットがあることを考えると特に問題ないはずである。

     実際、完成後の取得画像を見る限り、カメラの精度がそれ程でないことも相まって不自然さは全然感じられない。

    サーボモータの接続

     サーボモーターの制御には、PWM信号が必要であり、PIC内蔵の出力比較モジュール(OC1とOC2)をPWMモードで動かして、マイコン出力をサーボの制御信号とした。

     カメラモジュールやLANモジュールは、電源電圧が3.3V仕様となっており、これに合わせてマイコンも3.3Vで動かすことにしたが、 サーボモーターの電源は、仕様どおり5Vを使った。 マイコンからのPWMの出力電圧が3.3Vとサーボの電源電圧より低いのが心配であったが特に問題なく動作した。

     なお、マイコンは3.3V動作のため、CONFIGでクロックを29.48Mhzから14.74MHzに下げている。

    LANモジュールの接続

     LANモジュールは、素直にマイコンのSPI信号端子と接続するだけである。LANモジュールには、リセットやパワーダウンの制御端子、パケット受信時の割り込み信号端子などが備わっているが、これらはマイコンとは接続していない。リセット端子は電源に、パワーダウン端子はグラウンドに接続している。

    その他

     プログラム開発途中の動作確認用に、UARTの端子を引き出している。基板実装後のプログラム変更のために、PICkit接続用のICSP端子も基板に引き出しておいた。

     先にも書いたが、電源は5VのACアダプタから3端子レギュレータで3.3Vを作成し、マイコンとLAN・カメラの各モジュールに供給している。

     完成した制御回路の基板写真を右に示す。


    4.ソフトウェアの作成

    カメラモジュールの制御(ov7670.c)

     カメラチップのOV7670は、デフォルト状態では使い物にならず、SCCBインタフェースによる初期設定が必要になる。初期設定するパラメータは、トラ技の特集で紹介されていた物を使ったが、FIFO付きのモジュールを使う場合には、一点注意が必要だ。

     FIFO付きカメラモジュールの回路図を良くみると判るが、OV7670のVSYNC出力は、 正論理でなく負論理に設定しないと駄目だ。正論理のままだと、FIFOメモリに書き込みリセットがかかったままとなり、メモリに画像データが書き込まれない。 これに気付くまで、うまく画像が取得出来ず、大いに悩んでしまった。

     画像フォーマットについては、VGAサイズ、BAYERフォーマットで取得するようにした。OV7670からFIFOメモリへの画像書込は、FIFOのWENの制御だけで出来る。

     VSYNCの立ち上がりでWENを1にセットし、VSYNCの立下りで、WENを0にすれば、1フレーム分の画像データが、FIFOメモリに書き込まれている。後は、マイコン側から読み出し用のクロックを与えると読み出すことが出来る。


    LANモジュールの制御(W5200.c)

     LANモジュールWIZ820ioのチップであるW5200は、IP電話機の製作で使ったW5100の後継チップであり、チップを制御するプログラムはW5100のものを少し手直しするだけでよい。以前に作成したW5100.cを元にW5200.cを作成した。アプリケーションからは、ソケットインタフェース関数(socket(), sendto(), revfrom() etc)を使ってLANモジュールを呼び出せるようにしている。

     LAN接続に必要な、IPアドレスやゲートウェイアドレスなどは、自宅のサーバーネットワーク環境に合わせて、プログラム(main.c)内部で固定設定した。変更する場合には、プログラムの変更が必要だ。


    サーボモーターの制御(main.c)

     2個のサーボモータを制御するOC1、OC2は、PWMモードで動作させ、クロックにTMR2を使った。TMR2のPR2の設定で、PWMのパルス周期を20msecに設定し、パルスの正レベル幅は、OC1RS/OC2RSで、1.0msecから2.0msecまで 可変できるようにした。サーボの中立位置は、1.5msecで初期設定した。


    ネットワークカメラとしての制御(main.c)

     カメラモジュール、LANモジュール、サーボの初期化の後、ネットワークカメラとしての動作を行う。

     UDPにより、リモート端末(パソコンやサーバー等)からのコマンドパケットの受信を待ち、コマンドパケットを受信したらコマンドに応じた動作を行う。コマンドパケットと動作内容は次のとおり。

      コマンド文字列動作内容
       UPチルトサーボを上方向に1ステップ回転する
       DOWNチルトサーボを下方向に1ステップ回転する
       RIGHTパンサーボを右方向に1ステップ回転する
       LEFTパンサーボを左方向に1ステップ回転する
       GETカメラから1フレーム分の画像を取得し、リモートに送信する。

     コマンド文字列は、受信パケットの先頭の文字列のみチェックしている。改行コードが含まれていても良い。5つのコマンド文字列以外のコマンドを受け取った時は、"ERROR"を返す。

     サーボは、上下、左右最大振れ角を約6等分した角度を1ステップとした。ステップ値は、完成後、動作確認しながら適当に設定した。最大値以上には振れないようにリミットをかけている。 サーボの制御は、"OK"または、"LIMIT"の結果応答を返送する。

     フレーム画像の送信は、FIFOメモリから、512バイトを読み出す毎に、シーケンス番号を付加し、UDPパケットにてリモートに送信する。1パケット送信毎に、リモートからの"OK"または"NG"の応答を待ってから次に進む。600回(640X480/512=600)これを繰り返す。

     画像データの送信処理は、開発当初、シーケンス番号を付加していなかった。自宅のローカルネットワークでは、パソコンと製作したネットワークカメラは、HUB1個を経由して接続しており、この小さなネットワーク環境では、パケットロスが起きることはまず考えられない。ところが、カメラ側は送信を完了しているのにリモートのパソコン側では、ずっと受信待ちの状態が続く。そしてこれが頻発する。

     双方でパケット数のカウントが合っていない。どこかでパケットロスしているようだ。調べて見ると、W5200が、異様に熱い。電源投入直後の冷えた状態では、パケットロスは発生せず、通電後、暫くしてW5200が熱くなってくるとパケットロスが発生する。

     W5100はそんなに熱くならなかったがW5200は結構熱くなる。廉価版であるが故に熱設計に不備があるのかも知れない。UDPで転送しているだけにパケットロスに対する考慮は、必要なのだが、チップ内部でパケットロスするとは思ってもいなかった。

     そこで、対策として、パケットの先頭にシーケンス番号を付加するとともに、同一パケットを再送する処理を追加した。その内容を次に示す。

      ・パケットを順次送信している途中で、カメラ側の送信したパケットがパケットロスしてリモート側に届かなくなると、リモート側からの応答パケットが受信できなくなる。そこで、パケット送信後、100msec以内にリモートからの応答が無い時には、もう一度同じ内容のパケットを送信する。再度パケットロスが続き、これを10回繰り返すと、システムエラーとして転送処理を中断する。

      ・カメラ側からのパケットがリモート側に正常に届き、リモート側から送信した応答がパケットロスした場合には、前項の処理により100msec後に、前に受信したと同じシーケンス番号を持ったデータパケットが、カメラ側から送られてくる。リモート側では、受信したパケットは受信済みとして破棄するとともにカメラ側に応答を送信する。

      ・カメラ側からは、最大でも100msec後には、次のパケットを送信してくるので、リモート側では、300msecの受信待ちタイムアウト処理(受信処理打ち切り)を行うのが望ましい。また、何らかの原因で受信したデータパケットのシーケンス番号が、次に期待しているシーケンス番号を追い越してしまった場合には、転送異常として、受信処理を打ち切るのが望ましい。受信済みパケットは、破棄するだけでよい。

     この対策により、画像データの受信処理は、問題なく実行できるようになった。

     シーケンス確認や再送をするならUDPでなくTCPで通信するようにプログラムした方が良かったかも知れないが、チップ内部でのパケットロスだけに、よけいに問題を複雑化させるかも知れないと思いこのようにした。(チップ内部でTCPの処理自体が不具合を起こす可能性がある)

     ネットワークカメラは、MPLABの上で作成した。プロジェクト名は、NetCamera としている。


    5.ネットワークカメラのテスト

     製作したネットワークカメラを制御するリモート端末側のテストプログラム(netcamera.c)を作成した。テストプログラムは、Linux用となっている。
     コンパイルは、cc -o netcamera -Wall netcamera.c -lgd として、gdlib を必ずリンクする。

      netcamera は、次のように、取得画像を保存するファイル名を指定して起動する。

      #netcamera test.jpg


     プログラムが起動すると、次のようなカメラ制御メニューが表示される。

      *** Net Camera Control Test Program ***
      U: Camera Tilt to Up.
      D: Camera Tilt to Down.
      L: Camera Panning to Left.
      R: Camera Panning to Right.
      F: Camera One Frame Capture.
      E: test end.
      command ==>

     Fをタイプしエンターキーを押すとカメラから画像を取得する。U/D/L/R でカメラの首振りが出来る。

     IPアドレスやポート番号は、自宅の環境に合わせて次のように設定した。

       ネットワークカメラLinux端末
      IPアドレス
      192.168.1.20
      192.168.1.10
      ネットワークアドレス
      192.168.1.0
      ネットマスク
      255.255.255.0
      UDPポート番号
      18000


    6.ネットワークカメラをWebから制御する

     テストプログラムによりネットワークカメラの動作が確認できたので、自宅サーバーからWebページを通してカメラ制御が出来るようにした。

     PCや携帯電話、スマートフォンのWebブラウザから、自宅のサーバーにアクセスすると、次のようなページが表示される。

     これで、どこからでもカメラ画像を見ることができるようになった。