WebIOPi で遠隔操作(サーボモータ制御編)!




前回、ブラウザから raspberry pi の GPIO を操作するための、

WebIOPi

をインストールするところまで記載した。

その後、

いざサーボモータを制御しよう!

としてみたが、見事にハマった。

いろんなサイトを参考にしたものの、いずれの方法でも失敗。

正直断念しかけたが、代替策を思いつき、試してみた結果、ようやく成功!

ということで、今回は、

・WebIOPi を使ってブラウザから raspberry pi のサーボモータを制御する方法

について記載する。

また、

・その過程で起こったいろんなトラブルと解決法

についてもまとめておきたいと思う。

なお、本記事は

Raspbian Stretch に WebIOPi がインストールされている

という前提で書く。

インストール方法は、

WebIOPi で遠隔操作(インストール編)

を見ていただきたい。



  1. 実現したいこと
  2. サーボモータの制御
  3. まとめ

■実現したいこと

実現したいことは、

1. 以下のような画面を作る

2. 各方向ボタンをクリックすると、その方向にちょっとずつ動く

3. 戻ボタンをクリックすると、初期位置に戻る

ということ。

以下、これを実現するための方法を書いていく。



■サーボモータの制御

WebIOPi を使ってブラウザからサーボモータを使うためには、

・プログラム等を格納するディレクトリを準備する
・使う(思い通りに動かす)ためのプログラムを作成する
・操作するためのブラウザ上の画面を作る
・自分でいじった各種ファイルの置き場を WebIOPi サーバに教える

という四つのステップを実行する必要がある。

以下、これらについて、

  1. プロジェクトの作成
  2. 制御プログラムの作成
  3. html の作成
  4. Config ファイルの修正

という形で一つ一つ説明していく。



プロジェクトの作成

プロジェクトの作成、と大げさに言っているが、何のことはない。

ただ単に、

・自分が作ったプログラムや html を格納するディレクトリを作る

というだけの話である。

だったら別に作らなくても、とも思う。

が、後の工程で、

・プログラムや html の在り処かを WebIOPi サーバ側に教えてあげる

というとが必要となる。

なので、素直に作っておいた方がよかろうと思う。

ということで、以下の通り、

・python ディレクトリ
・html ディレクトリ

を作っていく。

自分の好きな所に作ればよいのだが、私は行儀悪く root で作業しているので、

/root/

以下に、iot というディレクトリを作り、その下に作るものとする。

普通は /home/pi/ 以下等だと思うので、自分の環境に適宜置き換えて欲しい。

root@raspi-03:~/# mkdir -p ~/iot/python/
root@raspi-03:~/# mkdir -p ~/iot/html/

これでプロジェクトの作成は完了。



制御プログラムの作成

続いて、サーボモータを意図どおりに動かすためのプログラムを作成する。

今回は、大体どのサイトでも採用している python で作成する。

この際、普通は webiopi パッケージを使って作成する。

いろんなサイトを拝見したが、皆さんそうされている。

が・・・、だ。

全く同じプログラムを使っても、私の場合、意図どおりに動かせなかった。

信号は伝わっているっぽいのだが、意図どおりに操作できない。

Jessie じゃなくて、Stretch だから?

正直なぜダメなのか、は今もって分かっていない。

この辺で起こったトラブルについては、

できたぁ! – WebIOPi によるサーボモータ制御 –

に記載しているので、うまく行かなかったら参考にしてもらいたい。
*いずれちゃんとまとめたいとおもうが・・・。

で、色々考えた結果、根本解決ではないのだけれど、

・webiopi パッケージは、ブラウザとの連携部分にのみ使う
・肝心のサーボモータの操作は、pigpio パッケージを使う

という対応をすることで、無事意図どおりに動かせるようになった。

よってここではそのプログラムを記載する。

      import webiopi
      import pigpio

      GPIO = webiopi.GPIO
      pi = pigpio.pi()

      pin_pan = 18  # 左右方向の GPIO
      pin_tilt = 17 # 上下方向の GPIO

      pos_pan_def = 1500
      pos_tilt_def = 1300

      pos_pan_current = pos_pan_def
      pos_tilt_current = pos_tilt_def

      pos_pan_max = 2300
      pos_tilt_max = 2200
      pos_pan_min = 700
      pos_tilt_min = 700

      def setup():
      GPIO.setFunction(pin_pan, GPIO.PWM)
      GPIO.setFunction(pin_tilt, GPIO.PWM)
      pi.set_servo_pulsewidth(pin_pan, pos_pan_def)
      pi.set_servo_pulsewidth(pin_tilt, pos_tilt_def)

      def loop():
      webiopi.sleep(0.5)

      @webiopi.macro
      def defaultPosition():
      pi.set_servo_pulsewidth(pin_pan, pos_pan_def)
      pi.set_servo_pulsewidth(pin_tilt, pos_tilt_def)
      pos_pan_current = pos_pan_def
      pos_tilt_current = pos_tilt_def
  
      @webiopi.macro
      def right():
      global pos_pan_current
      if pos_pan_current > pos_pan_min:
      pos_pan_current -= 100
      pi.set_servo_pulsewidth(pin_pan, pos_pan_current)
    
      @webiopi.macro
      def left():
      global pos_pan_current
      if pos_pan_current < pos_pan_max: 
      pos_pan_current += 100
      pi.set_servo_pulsewidth(pin_pan, pos_pan_current)

      @webiopi.macro def up(): 
      global pos_tilt_current
      if pos_tilt_current > pos_tilt_min:
      pos_tilt_current -= 100
      pi.set_servo_pulsewidth(pin_tilt, pos_tilt_current)
    
      @webiopi.macro
      def down():
      global pos_tilt_current
      if pos_tilt_current < pos_tilt_max:
      pos_tilt_current += 100
      pi.set_servo_pulsewidth(pin_tilt, pos_tilt_current)
    
      def destroy():
      GPIO.setup(pin_pan,  GPIO.IN)
      GPIO.setup(pin_tilt, GPIO.IN)



一応、何をしたいのか、を上から簡単に記載しておく。

      import webiopi
      import pigpio

モジュールとして、webiopi と pigpio を使いますよ、という宣言。

ちなみに、pigpio は Raspbian Jessie/Stretch ともに初めからある。

が、もしない場合は、

root@raspi-03:~/# apt-get update
root@raspi-03:~/# apt-get install pigpio -y

でインストールできる(はず)。

続いての二行、

      GPIO = webiopi.GPIO
      pi = pigpio.pi()

は、GPIO とか pi っていったらこれのことですよ、ということ。

まぁおまじないで書いておく。

その次は各種変数と初期値の定義。

      pin_pan = 18  # 左右方向の GPIO
      pin_tilt = 17 # 上下方向の GPIO

      pos_pan_def = 1500
      pos_tilt_def = 1300

      pos_pan_current = pos_pan_def
      pos_tilt_current = pos_tilt_def

      pos_pan_max = 2300
      pos_tilt_max = 2200
      pos_pan_min = 700
      pos_tilt_min = 700

最初の二行は、サーボの制御用信号線に繋がる GPIO のピン番号。

私の場合は左右方向のサーボは 18 に、上下方向は 17 に接続している。

続いての二行は、デフォルト位置の値設定。

サーボモーターを動かす!

でも書いたが、今回利用しているサーボモーターの場合、基本は、

・1500 が 0 度相当
・±1000 で ±90 度相当

という形になる。

が、サーボ自体の個性等により、この値はサーボ毎に微妙に異なる。

なので、私の場合、まずはコンソールから

root@raspi-03:~/# python3
>>> import pigpio
>>> pi = pigpio()
>>> pi.set_servo_pulsewidth(18, 1500)

などとして、1500 の部分を微妙に変えつつ、0 度となる位置を探った。
*その結果が 1300 と 1500 という値。

さらに次の二行は、サーボの現在角度を表す値の宣言と初期値設定。

初期値は中心となるように設定している。

最後の四行は、各々上下左右の最大角度設定。

『この値を越えないように』操作するための値を、

前述したように実際に動かしながら探っておき、決める。



で、いよいよ関数定義部分。

def setup():
      GPIO.setFunction(pin_pan, GPIO.PWM)
      GPIO.setFunction(pin_tilt, GPIO.PWM)
      pi.set_servo_pulsewidth(pin_pan, pos_pan_def)
      pi.set_servo_pulsewidth(pin_tilt, pos_tilt_def)

は、最初に起動した時に実行される関数。

WebIOPi のお作法では、

・setup() 多分起動時に実行される関数
・loop() 何も操作されない時の処理用関数
・destroy() プログラムの終了時の処理用関数

という三つの関数は必要みたいなので、ここを定義している。

内容的には、二行目と三行目で、GPIO の pin を PWM 信号用に設定。

こちらは webiopi モジュールの関数。

次の二行は、サーボの位置を初期位置に設定している。

こっちは pigpio モジュールの関数。

ちなみに、

pi.set_servo_pulsewidth(引数 1, 引数 2)

は、

引数 1 で指定された pin に、引数 2 の信号幅のパルスを送る

というもの(だと認識している)。

続いては、

def loop():
      webiopi.sleep(0.5)

の部分。

まぁ操作指示がなければ何もしないから、sleep を入れているだけ。

で、いよいよ肝心な操作部分。

@webiopi.macro
      def defaultPosition():
      pi.set_servo_pulsewidth(pin_pan, pos_pan_def)
      pi.set_servo_pulsewidth(pin_tilt, pos_tilt_def)
      pos_pan_current = pos_pan_def
      pos_tilt_current = pos_tilt_def

後述する html 側で、戻る、ボタンが押された際の処理を記載。

@webiopi.macro

という宣言は、

『html 側から呼ばれる関数ですよ』

ということの模様。

これがないと、多分 html 側から call しても動かないと思われる。

二行目は関数定義の宣言。

三、四行目は setup() と同じで、0 度位置にするための処理。

五、六行目は現在角度を 0 度に戻すための変数クリア処理。

結構簡単。

お次はサーボモータを右にちょっとだけ動かす関数。

@webiopi.macro
      def right():
      global pos_pan_current
      if pos_pan_current > pos_pan_min:
      pos_pan_current -= 100
      pi.set_servo_pulsewidth(pin_pan, pos_pan_current)

三行目は関数内で使う変数の宣言、なのかな?

他のプログラムとかを見てるとこうしているようなので、真似た。

四行目で、現在角度が最小値より大かどうかを確認。
*あんまり行き過ぎると壊れちゃうので。

大なら、角度をちょっと小さくし、(五行目)

サーボの角度をちょっと小さくした値に設定する(六行目)

ということをやっている。

まぁ超簡単な話。

あとはこれと同じような処理を、左、上、下、と書いているだけ。

そしていよいよ最後。

def destroy():
      GPIO.setup(pin_pan,  GPIO.IN)
      GPIO.setup(pin_tilt, GPIO.IN)

GPIO の pin を IN に戻す、ということをやっている。

まぁおまじない見たいなもの。

ということで、プログラムの作成は終了。

作成したプログラムを、仮に camera_servo.py とでもする。

これを、プロジェクトの作成で作った python ディレクトリに保存。

これでコードの作成は終了。



html の作成

プログラムを無事作成し終えた所で、次は html。

ブラウザの画面上に表示され、さっき作ったプログラムを呼び出すのに使う。

で、元々作りたかった形とほぼ同じものが、

1ban.yoka.to
http://1ban.yoka.to/?p=48

というサイトで公開されていた。

誠に持ってありがたい話である。

よって、今回はひとまずこちらの index.html を使わせて頂いた。
*そのため、プログラムの関数名等はこちらに合わせている

なお、ちょっとだけ手を加えてもいるので、魚拓的な意味で一応載せる。

<!DOCTYPE html>
<html>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>
<meta name=”viewport” content=”width=550, initial-scale=1″>
<title>Raspberry Pi ライブ(監視)カメラ操作</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”, “戻”, function(){
console.log(“JS:Default”)
webiopi().callMacro(“defaultPosition”,[], callBack);
});
$(“#control-def”).append(defaultBtn);
var rightBtn = webiopi().createButton(“rightBtn”, “右”, function(){
console.log(“JS:Right”)
webiopi().callMacro(“right”,[], callBack);
});
$(“#control-r”).append(rightBtn);
var leftBtn = webiopi().createButton(“leftBtn”, “左”, function(){
console.log(“JS:Left”)
webiopi().callMacro(“left”,[], callBack);
});
$(“#control-l”).append(leftBtn);
var upBtn = webiopi().createButton(“upBtn”, “上”, function(){
console.log(“JS:Up”)
webiopi().callMacro(“up”,[], callBack);
});
$(“#control-u”).append(upBtn);
var downBtn = webiopi().createButton(“downBtn”, “下”, function(){
console.log(“JS:Down”)
webiopi().callMacro(“down”,[],callBack);
});
$(“#control-d”).append(downBtn);
webiopi().refreshGPIO(true);
});
</script>
</head>
<body>
<div align=”center”>
<table border=0 cellspacing=”10″ cellpadding=”0″>
<tbody>
<tr>
<td>&nbsp;</td>
<td><div id=”control-u”></div></td>
<td>&nbsp;</td>
</tr>
<tr>
<td><div id=”control-l”></div></td>
<td><div id=”control-def”></div></td>
<td><div id=”control-r”></div></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><div id=”control-d”></div></td>
<td>&nbsp;</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>

これで html の作成は完了。

作った html ファイルは、index.html として、

~/iot/html/

以下に保存しておく。



Config ファイルの修正

プログラム、html と順調に出来た所で、最後の仕上げ。

折角作ったのも、webIOPi サーバが読めないと意味が無い。

このため、作ったファイル群の場所を教えてあげることにする。

まず、/etc/webiopi/config をエディタ等で開く。

最初に、プログラムの位置を教えてあげるため、

25 行目の # を外し、以下のような形で path を設定する。

具体的には、

[SCRIPTS]
  # Load custom scripts syntax :
  # name = sourcefile
  #   each sourcefile may have setup, loop and destroy functions and macros
  #myscript = /home/pi/webiopi/examples/scripts/macros/script.py

における myscript = の部分を

[SCRIPTS]
  # Load custom scripts syntax :
  # name = sourcefile
  #   each sourcefile may have setup, loop and destroy functions and macros
  myscript = /root/iot/python/camera_servo.py

と、# を外すとともに、さっき作ったプログラムへのパスに変える。

続いて、42 行目の

# Use doc-root to change default HTML and resource files location
#doc-root = /home/pi/webiopi/examples/scripts/macros

# Use doc-root to change default HTML and resource files location
doc-root = /root/iot/html

と、こちらも # を外すとともに、今度は html ディレクトリへのパスに変える。

これらの設定が完了したら、

root@raspi-03:~/# webiopi -d -c /etc/webiopi/config

で webiopi を起動する。

その後、ブラウザで URL 部分に

http://<IP address>:8000

を入力、実行する。

この際、ログインが要求される。

ログイン ID とパスワードは各々以下の通り。

ログイン ID : webiopi
パスワード : raspberry

ログイン後、ブラウザ上の各ボタンを押してみる。

無事、サーボモータが各方向にちょびっとずつ動いてくれた。



■まとめ

いやぁ、長かった。

ブラウザでサーボ制御を出来るようになるまで、まさかこんなにかかるとは。

己れの無能さにつくづく呆れる。

が、出来てしまえば超楽しい。

何度も諦めかけたが、続けてよかった!

ということで、簡単におさらい。

Point!・まずはディレクトリを作る!
・次に、python でサーボ操作用のプログラムを書く。
・webiopi モジュールの関数だけでだめなら、pigpio が代替になる!
・その後、関数を呼び出すための html を書く!
・最後に /etc/webiopi/config を修正する!

これで、ブラウザからの遠隔操作はほぼ完了といってよい。

後はカメラからの映像を見ながら操作出来るようにすればよい。

その方法は多分色々あるので、次回以降いくつか記載する予定。

ラズパイで遠隔操作できるライブ(監視)カメラの完成まで、後一息だ!




Copyright (c) 2017 Webmaster of this site All Rights Reserved.
カテゴリー: ラズパイで電子工作 タグ: , パーマリンク

コメントを残す

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

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください