Raspberry Piでサーボコントロール、Part2 WebカメラをWebブラウザ経由で上下左右・ズームさせる

Webブラウザ経由でRaspberry Piにつないだ3つのサーボをコントロールして、
Webカメラを上下・左右、そしてズームインとズームアウトさせます。


webIOPiからとりあえずサーボを動かす

まず最初に前回書いたサーボプログラムをwebIOPiに組み込んでみます。

2015年2月28日現在、RPIOがRaspberry Pi 2に対応していないためPi2を使っている場合は下記のコードは動きません。Raspberry Piでサーボコントロール、Part3 Raspberry Pi 2に対応でRPIOなしでサーボをコントロールできるようにしてあるので、そこを合わせて参考にしてみてください。

sudo vim /home/username/myproject/python/my-servo.py
import webiopi
from RPIO import PWM
import time

GPIO = webiopi.GPIO
servo = PWM.Servo()
SERVO_X = 23
SERVO_Y = 24

def setup():
    GPIO.output(SERVO_X, GPIO.LOW)
    GPIO.output(SERVO_Y, GPIO.LOW)

servo.set_servo(SERVO_X, 1500)
time.sleep(1)
servo.set_servo(SERVO_X, 1100)
time.sleep(1)

servo.set_servo(SERVO_Y, 1400)
time.sleep(1)
servo.set_servo(SERVO_Y, 1800)
time.sleep(1)

def destroy():
        GPIO.digitalWrite(SERVO_X, GPIO.LOW)
        GPIO.digitalWrite(SERVO_Y, GPIO.LOW)

webIOPiのconfigにサーボプログラムを追加します。
sudo vim /etc/webiopi/config
[SCRIPTS]
myservos = /home/username/myproject/python/servo-script.py

webiopiを起動します。
sudo webiopi -d -c /etc/webiopi/config
WebIOPi - ERROR - No module named RPIO

WebブラウザでRaspberry PiのGPIOを操作するのにwebIOPiを使っています。ただ、webIOPiはpython3で動いているらしく、サーボをコントロールするためのプラグインであるRPIOはpython2にしかインストールされてませんでした。

python3.2にRPIOをインストールします。
git clone https://github.com/metachris/RPIO.git
Cloning into 'RPIO'...
remote: Counting objects: 2013, done.
Receiving objects:  16% (332/2013), 1.26 MiB | 5 KiB/s

cd RPIO
sudo python3 setup.py install
少し時間がかかるけど、これでRPIOをpython3にインストールできました。

もう一度webiopiを起動します。
sudo webiopi -d -c /etc/webiopi/config
WebIOPi - ERROR - [Errno 98] Address already in use
socket.error: [Errno 97] Address family not supported by protocol
socket.error: [Errno 98] Address already in use

webiopiが人知れず動き続けていたようです。
一旦webiopiを停止して、デバッグできる形でwebiopiを起動します。
sudo /etc/init.d/webiopi stop
sudo webiopi -d -c /etc/webiopi/config
これで前回書いたサーボプログラムをwebIOPiから動かすことができました。

webIOPiを使ってWebブラウザのボタンを使って3つのサーボを動かす

Webブラウザ経由で3つのサーボをコントロールして、Webカメラを上下左右そしてズームさせます。

ここまでくるとLEDコントロールと今まで書いたサーボコントロールの合わせ技だけなので、別段新しいことはやりません。端的にコードだけ載せておきます。よくわからない場合は、下記の記事を読みましょー。

Raspberry PIでLED点灯コントロール、Part3 ネット経由(WebIOPi)でコントロールする
Raspberry PIでLED点灯コントロール、Part4 水槽ライトを設置する
Raspberry Piでサーボコントロール、Part1 上下・左右の2軸を動かす

まずはサーボコントローラを3つのサーボを使って左右上下・ズーム(前後)させるプログラムに修正します。
sudo vim /home/username/myproject/python/servo-script.py
import webiopi
from RPIO import PWM
import time

GPIO = webiopi.GPIO
servo = PWM.Servo()
SERVO_X = 22
SERVO_Y = 24
SERVO_Z = 25
DEFAULT_X = 1500
DEFAULT_Y = 1180
DEFAULT_Z = 1500
CURRENT_X = DEFAULT_X
CURRENT_Y = DEFAULT_Y
CURRENT_Z = 0

time_stamp = time.time()

def setup():
    GPIO.output(SERVO_X, GPIO.LOW)
    GPIO.output(SERVO_Y, GPIO.LOW)
    GPIO.output(SERVO_Z, GPIO.LOW)

def loop():
   global time_stamp
   if (time_stamp <= time.time() - 20):
       defaultPosition()
   webiopi.sleep(0.5)

@webiopi.macro
def defaultPosition():
    global time_stamp
    if time_stamp <= time.time() - 0.2 and (CURRENT_X != DEFAULT_X or CURRENT_Y != DEFAULT_Y or CURRENT_Z != 0):
        time_stamp = time.time()
        global CURRENT_X
        global CURRENT_Y
        global CURRENT_Z
        CURRENT_X = DEFAULT_X
        CURRENT_Y = DEFAULT_Y
        servo.set_servo(SERVO_X, DEFAULT_X)
        webiopi.sleep(0.5)
        servo.set_servo(SERVO_Y, DEFAULT_Y)
        webiopi.sleep(0.5)
        servo.set_servo(SERVO_Z, 1400)
        webiopi.sleep(CURRENT_Z)
        servo.stop_servo(SERVO_Z)
        CURRENT_Z = 0
        time_stamp = time.time()

@webiopi.macro
def forward():
    global CURRENT_Z, time_stamp
    if CURRENT_Z < 18 and time_stamp <= time.time() - 0.2:
        time_stamp = time.time()
        CURRENT_Z = CURRENT_Z + 1
        servo.set_servo(SERVO_Z, 1550)
        webiopi.sleep(1)
        servo.stop_servo(SERVO_Z)
        time_stamp = time.time()

@webiopi.macro
def backward():
    global CURRENT_Z, time_stamp
    if CURRENT_Z > 0 and time_stamp <= time.time() - 0.2:
        time_stamp = time.time()
        CURRENT_Z = CURRENT_Z - 1
        servo.set_servo(SERVO_Z, 1400)
        webiopi.sleep(1)
        servo.stop_servo(SERVO_Z)
        time_stamp = time.time()

@webiopi.macro
def down():
    global CURRENT_Y, time_stamp
    if CURRENT_Y < DEFAULT_Y + 50*10 and time_stamp <= time.time() - 0.2:
        time_stamp = time.time()
        CURRENT_Y = CURRENT_Y + 50
        servo.set_servo(SERVO_Y, CURRENT_Y)
        webiopi.sleep(0.5)
        time_stamp = time.time()

@webiopi.macro
def up():
    global CURRENT_Y, time_stamp
    if CURRENT_Y > DEFAULT_Y - 50*10 and time_stamp <= time.time() - 0.2:
        time_stamp = time.time()
        CURRENT_Y = CURRENT_Y - 50
        servo.set_servo(SERVO_Y, CURRENT_Y)
        webiopi.sleep(0.5)
        time_stamp = time.time()

@webiopi.macro
def left():
    global CURRENT_X, time_stamp
    if CURRENT_X < DEFAULT_X + 50*10 and time_stamp <= time.time() - 0.2:
        time_stamp = time.time()
        CURRENT_X = CURRENT_X + 50
        servo.set_servo(SERVO_X, CURRENT_X)
        webiopi.sleep(0.5)
        time_stamp = time.time()

@webiopi.macro
def right():
    global CURRENT_X, time_stamp
    if CURRENT_X > DEFAULT_X - 50*10 and time_stamp <= time.time() - 0.2:
        time_stamp = time.time()
        CURRENT_X = CURRENT_X - 50
        servo.set_servo(SERVO_X, CURRENT_X)
        webiopi.sleep(0.5)
        time_stamp = time.time()

servo.set_servo(SERVO_X, DEFAULT_X)
webiopi.sleep(0.5)
servo.set_servo(SERVO_Y, DEFAULT_Y)
webiopi.sleep(0.5)

def destroy():
    GPIO.digitalWrite(SERVO_X, GPIO.LOW)
    GPIO.digitalWrite(SERVO_Y, GPIO.LOW)
    GPIO.digitalWrite(SERVO_Z, GPIO.LOW)

GPIO22は左右を動かすサーボをコントロールします。
GPIO24は上下を動かすサーボをコントロールします。
GPIO25は前後(物理的にズームさせる)に動かすサーボをコントロールします。

GPIO23は別のところでLEDをコントロールしているので、ここでは使いません。

loop()にwebiopi.sleep(0.5)を入れていますが、これがないとCPUの使用率が100%になってしまうので注意しましょう。


続いて、htmlファイルを修正します。
vim /home/username/myproject/html/index.html
<html>
<head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>WebIOPi | Light Control</title>
        <script type="text/javascript" src="/webiopi.js"></script>
        <script type="text/javascript">
        webiopi().ready(function() {
                // Create a "Light" labeled button for GPIO 23
                var upButton = webiopi().createButton("upButton", "Up", function(){
                    webiopi().callMacro("up");
                });

                var downButton = webiopi().createButton("downButton", "Down", function(){
                    webiopi().callMacro("down");
                });

                var leftButton = webiopi().createButton("leftButton", "Left", function(){
                    webiopi().callMacro("left");
                });

                var rightButton = webiopi().createButton("rightButton", "Right", function(){
                    webiopi().callMacro("right");
                });

                var forwardButton = webiopi().createButton("forwardButton", "Forward", function(){
                    webiopi().callMacro("forward");
                });

                var backwardButton = webiopi().createButton("backwardButton", "Backward", function(){
                    webiopi().callMacro("backward");
                });

                var defaultPositionButton = webiopi().createButton("defaultPositionButton", "Default", function(){
                    webiopi().callMacro("defaultPosition");
                });

                // Append button to HTML element with ID="controls" using jQuery
                $("#controls").append(upButton);
                $("#controls").append(downButton);
                $("#controls").append(leftButton);
                $("#controls").append(rightButton);
                $("#controls").append(forwardButton);
                $("#controls").append(backwardButton);
                $("#controls").append(defaultPositionButton);

        });
        </script>
        <style type="text/css">
                body{
                        margin:0;padding:0;
                }
                button {
                        width: 140px;
                }
        </style>
</head>
<body>
        <div id="controls"></div>
</body>
</html>

あとは物理的にWebカメラとサーボを組み合わせて、
上下左右・ズームできるようにします。

Logicool C270にグレードアップで購入したWebカメラの要らない部分をドリルで破壊してヤスリをかけて、カメラマウントに接着剤で貼り付けます。そしてS35サーボ(900円)と車輪(ホームセンターで1つ90円くらい)と薄い木の板、そしてカメラマウントを組み合わせると・・・



こんな感じになります。電池は単なるオモリです。
オモリがないとちょっとしたことで木のレールに乗り上げてしまいます。

S35サーボで前進・後進させます。
丸いサーボホーンに両面テープをつけて滑らなくします。
あと、長細いヒノキの棒を使ってレールを敷いて進む方向を固定します。



後ろから見るとこんな感じです。

全体図





線が車輪にからまらないように上に引っ張ってます。


最後にブラウザでアクセスしてボタンをクリックしてサーボを動かしてみます。
http://192.168.0.122:8000

複数のボタンが出てきて、そのボタンを押すとサーボが前進したり、後進したり、Webカメラが右を向いたり左を向いたり、上を向いたり下を向いたりします。


今回のサーボコントロールは金魚の金太郎で使っています。ライブ映像の下にあるボタン、Up, Down, Left, Right, Forward, Backward等を押すとライブ映像に使っているWebカメラが動いて右のほうを映したり、左のほうを映したり等などをしてくれます。

コメントを残す

メールアドレスが公開されることはありません。