Raspberry Piでサーボモータを制御

th_webiopi-2

今まで実はやっていなかった「Raspberry Piでサーボモータを制御」というのを、今更ですがやってみたいと思います。

サーボモータ自体はラピロでガンガン使っているのですが、サーボの制御自体はラピロのデフォルトのArduinoプログラムをそっくりそのまま利用していただけ(Raspberry PiからArduinoにコマンドを送っていただけ)だったので、自力でのサーボ制御は今までやったことがなかったのです。

まー、Raspberry Piでのサーボ制御は先人たちが山のようにいるハズなので、そんなにハマることはないだろう。。。と期待して、いざチャレンジです。なお、今回は手元に余っていたRaspberry Pi B+を使っています。最新のRaspberry Pi 2ではないので、あしからずです。

 

早速、自分のやりたいことをそっくりそのままやっておられる方がいました。

ということで、参照先で利用されている以下を購入。

サーボは5個で2000円弱とお手頃です。たくさんあって困るものでもなし。マウントの方は参考記事の通り、2〜3週間後ぐらいに届きました。

データシートを見ると、サーボの動作電圧は4.8V(〜5V)。モータ系は基本的に電流喰いなので、Raspberry Pi本体からの電力供給はやめといた方がよさそうです。配線はこんな感じかな。

Servo_ブレッドボード

上図には出ていませんが、サーボ用の電源の部分は別のUSB電源から5Vを取るようにしています。

 

さて、Raspberry Piでサーボをいじっているサイトを見てみると、RPIOというモジュールを使って制御していることが多いようなのですが、参考サイトでも述べられているとおり、RPIOモジュールの更新は2年前に止まってしまっており、Raspberry Pi 2にも対応していないのだそうな。

今回使うのはRaspberry Pi B+なので、別にRPIOで押しきってしまっても良いのかもしれませんが、色々探している内に、何やらWebIOPiとかいう、IoTフレームワークを謳うものを(今更)見つけました。これでもGPIO制御ができるとのことなので、今後のことも見据えて、今回はこれを使ってみることにします(と言っても、こちらも半年以上更新止まっているようですが。。。)。

まずはインストールから。適当なPCでこちらにアクセスしてダウンロード、scpでRaspberry Piのホームに持ってきたところからスタートです。

$ tar xzvf WebIOPi-0.7.1.tgz
$ cd WebIOPi-0.7.1
$ sudo ./setup.sh

インストールガイドほぼそのままです。

インストールの途中で”Do you want to access WebIOPi over Internet ? [y/n]”と聞かれたので調べてみると、どうやらWeavedというサービスを使って、宅外とかからでも家のRaspberry Piにアクセス可能にするための設定なのだそう。ちょっと調べてみると、制限ありなら無料で使えるのだそうだけれど、よくわからないので一旦”n”で進めます。間もなくインストール完了。

とりあえずフォアグラウンドで起動。

$ sudo webiopi

動きました。ブラウザで”http://raspberrypiのアドレス:8000/”にアクセスすると、以下のように表示されます。

webiopi-1

Ctrl + Cで終了して、次はサービスとして起動します。

$ sudo /etc/init.d/webiopi start
[....] Starting webiopi (via systemctl): webiopi.serviceFailed to start webiopi.service: Unit webiopi.service failed to load: No such file or directory.
 failed!

何故かわかりませんが失敗します。謎。

最後に、Raspberry Piの起動時にWebIOPiを自動起動設定。

$ sudo update-rc.d webiopi defaults
$ sudo reboot

再起動後、こちらはちゃんと動きました。謎。ブラウザでのアクセス時に認証を求められたので、ユーザ:webiopi, パスワード:raspberry で通過しました。

さて、これで単純なHigh/Lowならブラウザから操作できそうですが、今回はサーボを制御したいので、もう少し頑張らないといけません。

ありがたいことに、すでに上記サイトでトライしてくださっています。さっそく真似させていただきます。

まずはプロジェクト用のディレクトリを作ります。

$ mkdir -p ~/projects/sample-servo
$ cd ~/projects/sample-servo
$ mkdir html
$ mkdir js
$ mkdir css
$ mkdir python

今回はjsとcssのフォルダは使いませんが、基本はこの形になるハズなので、このようにしています。

次に、メインのPythonスクリプトを作成します。

$ vim python/sample-servo.py

内容はこんな感じです。

import webiopi

GPIO = webiopi.GPIO
SERVO_PAN  = 23
SERVO_TILT = 24

DEFAULT_PAN  = 0
DEFAULT_TILT = 0
CURRENT_PAN  = 0
CURRENT_TILT = 0

PAN_MAX  = 90
PAN_MIN  = -90
TILT_MAX = 90
TILT_MIN = -90

PAN_UNIT  = 10
TILT_UNIT = 10

def setup():
  GPIO.setFunction(SERVO_PAN,  GPIO.PWM)
  GPIO.setFunction(SERVO_TILT, GPIO.PWM)
  GPIO.pulseAngle(SERVO_PAN,  DEFAULT_PAN)
  GPIO.pulseAngle(SERVO_TILT, DEFAULT_TILT)
  webiopi.sleep(0.5)
  GPIO.pulseRatio(SERVO_PAN,  0)
  GPIO.pulseRatio(SERVO_TILT, 0)

def loop():
  webiopi.sleep(0.5)

@webiopi.macro
def defaultPosition():
  global CURRENT_PAN
  global CURRENT_TILT
  CURRENT_PAN  = DEFAULT_PAN
  CURRENT_TILT = DEFAULT_TILT
  GPIO.pulseAngle(SERVO_PAN,  DEFAULT_PAN)
  GPIO.pulseAngle(SERVO_TILT, DEFAULT_TILT)
  webiopi.sleep(0.5)
  GPIO.pulseRatio(SERVO_PAN,  0)
  GPIO.pulseRatio(SERVO_TILT, 0)

@webiopi.macro
def right():
  global CURRENT_PAN
  if CURRENT_PAN < PAN_MAX:
    CURRENT_PAN = CURRENT_PAN + PAN_UNIT
    GPIO.pulseAngle(SERVO_PAN, CURRENT_PAN)
    webiopi.sleep(0.5)
    GPIO.pulseRatio(SERVO_PAN, 0)

@webiopi.macro
def left():
  global CURRENT_PAN
  if CURRENT_PAN > PAN_MIN:
    CURRENT_PAN = CURRENT_PAN - PAN_UNIT
    GPIO.pulseAngle(SERVO_PAN, CURRENT_PAN)
    webiopi.sleep(0.5)
    GPIO.pulseRatio(SERVO_PAN, 0)

@webiopi.macro
def up():
  global CURRENT_TILT
  if CURRENT_TILT < TILT_MAX:
    CURRENT_TILT = CURRENT_TILT + TILT_UNIT
    GPIO.pulseAngle(SERVO_TILT, CURRENT_TILT)
    webiopi.sleep(0.5)
    GPIO.pulseRatio(SERVO_TILT, 0)

@webiopi.macro
def down():
  global CURRENT_TILT
  if CURRENT_TILT > TILT_MIN:
    CURRENT_TILT = CURRENT_TILT - TILT_UNIT
    GPIO.pulseAngle(SERVO_TILT, CURRENT_TILT)
    webiopi.sleep(0.5)
    GPIO.pulseRatio(SERVO_TILT, 0)

def destroy():
  GPIO.setup(SERVO_PAN,  GPIO.IN)
  GPIO.setup(SERVO_TILT, GPIO.IN)

WebIOPiを使うと、Pythonの書き方がArduinoライクになります。面白いですね。

続いて、HTMLの準備です。今回はJavaScriptもHTMLの中に書いてしまいます。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Servo Sample</title>
  <script type="text/javascript" src="/webiopi.js"></script>
  <script type="text/javascript">
    webiopi().ready(function(){
      var callBack = function(macro, args, response){

      }

      var defaultBtn = webiopi().createButton("defaultBtn", "Default", function(){
        console.log("JS:Default")
        webiopi().callMacro("defaultPosition",[], callBack);
      });
      $("#controls").append(defaultBtn);

      var rightBtn = webiopi().createButton("rightBtn", "Right", function(){
        console.log("JS:Right")
        webiopi().callMacro("right",[], callBack);
      });
      $("#controls").append(rightBtn);

      var leftBtn = webiopi().createButton("leftBtn", "Light", function(){
        console.log("JS:Left")
        webiopi().callMacro("left",[], callBack);
      });
      $("#controls").append(leftBtn);

      var upBtn = webiopi().createButton("upBtn", "Up", function(){
        console.log("JS:Up")
        webiopi().callMacro("up",[], callBack);
      });
      $("#controls").append(upBtn);

      var downBtn = webiopi().createButton("downBtn", "Down", function(){
        console.log("JS:Down")
        webiopi().callMacro("down",[],callBack);
      });
      $("#controls").append(downBtn);

      webiopi().refreshGPIO(true);
    });
  </script>
</head>
<body>
  <div id="controls">
  </div>
</body>
</html>

最後に、WebIOPiの設定ファイルをいじります。

$ sudo vim /etc/webiopi/config
...
[SCRIPTS]
...
myscript = /home/pi/projects/sample-servo/python/sample-servo.py
...
[HTTP]
...
doc-root = /home/pi/projects/sample-servo/html
...

書けたら、WebIOPiを実行してみます。

$ sudo webiopi -d -c /etc/webiopi/config

起動した状態で、ブラウザで”http://raspberrypiのアドレス:8000/”にアクセスすると、こんな感じの画面になります。表示が崩れていますが、今は気にしません。

webiopi-3

それぞれのボタンをクリックすると、時折不思議な挙動をしますが、一応動いてくれています。

WebIOPiはHTMLとJavaScriptとPythonをまとめて扱えるので便利ですね。ラピロの頃はPythonを切り分けるために、わざわざPython制御用のWebServerを別に立てていたので。

ちなみに、Pythonの記述にエラーがあるとWebIOPiの実行時点でエラーが出るのですぐ修正できますが、HTMLとJavaScriptのエラーはブラウザで表示するまで気づきません。ボタンが表示されない、ボタンをタッチしてもサーボが無反応とかだったりする場合は、FirefoxやChromeの開発者ツールでコンソールを確認してみてください。自分はJavaScript内での”webiopi()”の”()”を書き忘れたせいで無駄に時間を使ってしまいました。。。

というわけで、一応サーボが動くところまではきました。ただ、あくまで動いているだけで、サーボらしいキビキビした動きが実現できているわけではありません。細かい微調整は、マウントを組み立ててからにしようと思います。

(2015/11/21追記)

ちゃんと制御できるようにした記事をこちらにアップしました。