DSC00293
Raspberry Piを使って遠隔映像監視の実験をしました。当初ネットの情報をあさったのですが、以前購入した「Raspberry Piで学ぶ電子工作」の書籍をぱらぱらとめくっているとほぼそのままの例が載っていることに気づきました。今回はこちらを参考に、スマホ(iPhone)からのコントロール部分をスマホの姿勢センサーを使うように変更してみました。

ちなみにこの「Raspberry Piで学ぶ電子工作」はRaspberry Piの入門書として大変おすすめです。技術解説書なのにブルーバックスということでどうなのか?と最初は感じましたが、中身は非常にツボを押さえた説明でわかりやすくなっています。ひとにものを教えるコツを知っている方が書いているなあという印象です。

さて下記は今回使用した部品(機材)のリストです。全部そろえると結構なお値段になります。
・Raspberry Pi B+
・R-Pi Camera module
・Panasonic モバイルバッテリー QE-QL201-W
・BUFFALO USB2.0ハブ BSH4A01BK
・BUFFALO 無線LANドングル WLI-UC-GNM2
・カモン USB→DC(外径3.5mm内径1.3mm)電源供給ケーブル
・マイクロサーボ SG90 x2
・BUFFALO 無線LAN親機 WMR-300/S (Optional)
・サインスマート 4チャンネル 5V リレーモジュール (Optional)

スマホの動きに連動してカメラが上下左右に動くような仕様にしたためサーボは2個使います。サーボ用のPWM信号はGPIO18のみで出力可能と書かれているところが多いのですが、GPIO13からも出力することができます。
無線LAN親機は家庭の無線LANが届かない屋外で実験するときに必要です。最後のリレーモジュールは普通は不要です。今回、移動用の台車(ロボット)を間接的にスイッチをON/Offして動かすことになったために使ったものです。タミヤのラジコンキットなどを使う場合には書籍にあるようにモータードライバを接続します。
サーボの駆動電源はUSBハブから供給しています。

RasPi用のプログラムは書籍の追加情報サイトからダウンロードしたものを流用します。書籍ではコントロールはブラウザ上ですべて行うようになっています。これですとスマホの姿勢センサによる操縦ができませんので、ブラウザは映像を映すのみとし操縦はスマホアプリのボタン等から行うように変更します。以下にサンプルプログラムを変更する部分を示します。

・index.html

<body>
<div id="touchArea">
    <canvas id="canvas"></canvas>
    <!--<span id="slider_servo"></span>-->
</div>
<!--
<p>android、iPhone、iPadの場合: タッチしている間だけモーターは回転し、タッチを離すと静止します。</p>
<p>Windowsタブレットや通常のPCの場合: タッチ位置やマウスをクリックした位置により、モーターが回転を開始します。中央付近をタッチかクリックしないとモーターは止まりません。</p>
-->
</body>

スライダーと説明の文字を削除します。

・javascript.js

function initialize_webiopi(){
    // webiopiの準備が終わってからstyles.cssを適用する
    applyCustomCss('styles.css');

    // タッチエリアの設定
    var touchArea = $("#touchArea")[0];
/*
    // タッチイベントのイベントリスナーの登録
    touchArea.addEventListener("touchstart", touchEvent, false);
    touchArea.addEventListener("touchmove", touchEvent, false);
    touchArea.addEventListener("touchend", touchEndEvent, false);

    // クリックイベントのイベントリスナーの登録
    touchArea.addEventListener("click", clickEvent, false);
*/
    // GPIOの状態を監視しない
    webiopi().refreshGPIO(false);

    imageSetup();
}

ブラウザのイベントリスナーをコメントアウト

function imageSetup(){
  . . . . .
  mImg1.onload = function() {
    mImg2.src = URL1 + '&' + (mCount++);
    mCtx.drawImage(mImg1, 0, 0, mWidth, mHeight);
    //mCtx.drawImage(mImgArrow, 0, 0, mWidth, mHeight);
  };
  mImg2.onload = function() {
    mImg1.src =URL1 + '&' + (mCount++);
    mCtx.drawImage(mImg2, 0, 0, mWidth, mHeight);
    //mCtx.drawImage(mImgArrow, 0, 0, mWidth, mHeight);
  };
}

画面に操縦用の矢印を描かないようにする。

function contServo(pin, ang){
    var duty = ang/10;
    webiopi().callMacro("setMyPWM", [pin, duty, commandID++]);
}

function contDrive(pin, state){
    webiopi().callMacro("setGPIO", [pin, state]);
}

スマホから呼び出す関数2つを追加。

・script.py

def getServoDutyForWebIOPi(val):
    val_min = 0.0
    val_max = 1.0
    servo_min = 36
    servo_max = 102

    duty = int((servo_max-servo_min)*(val-val_min)/(val_max-val_min) + servo_min)
    return duty

wiringpi.wiringPiSetupGpio() # GPIO名で番号指定
wiringpi.pinMode(18, wiringpi.GPIO.PWM_OUTPUT)
wiringpi.pinMode(13, wiringpi.GPIO.PWM_OUTPUT)
wiringpi.pwmSetMode(wiringpi.GPIO.PWM_MODE_MS) # 周波数固定
wiringpi.pwmSetClock(375) # 50 Hz
wiringpi.pwmWrite(18, getServoDutyForWebIOPi(0.5))
wiringpi.pwmWrite(13, getServoDutyForWebIOPi(0.5))

servo_minとservo_maxは使用するサーボの特性にあわせて変更します。また追加のサーボ用にGPIO13も出力に設定します。

def setup():
    webiopi.debug("Script with macros - Setup")
    # GPIOのセットアップ
    GPIO.setFunction(27, GPIO.OUT)
    GPIO.digitalWrite(27, GPIO.LOW)
    GPIO.setFunction(22, GPIO.OUT)
    GPIO.digitalWrite(22, GPIO.LOW)
    GPIO.setFunction(23, GPIO.OUT)
    GPIO.digitalWrite(23, GPIO.LOW)
    GPIO.setFunction(24, GPIO.OUT)
    GPIO.digitalWrite(24, GPIO.LOW)

この部分はリレー用のGPIOの設定です。書籍と同じようにモータードライバを使う場合は変更不要です。

@webiopi.macro
def setMyPWM(pin, duty, commandID):
    wiringpi.pwmWrite(int(pin), getServoDutyForWebIOPi(float(duty)))

@webiopi.macro
def setGPIO(pin, state):
    if(int(state)==1):
        GPIO.digitalWrite(int(pin), GPIO.HIGH)
    else:
        GPIO.digitalWrite(int(pin), GPIO.LOW)

サーボにPWMを送る関数とGPIOをON/Offする関数を追記します。

次回iPhone側のプログラムについて書く予定です。