今回はブラウザのスライダーでRaspberryPiのサーボモータを動かしてみたいと思います。
使用するサーボモータはMG996Rです。情報もなかなか少ないので、備忘録も兼ねて記事にしていきます。
参考サイト
今回はこちらの記事を参考にさせていただきました。
Raspberry Piでブラウザからサーボモータをちゃんと制御する
パルス幅についてはこちらの記事が分かりやすいです。
ラズパイ電子工作の基本① サーボモータを使って指さし温度計を作ってみよう
正確なPWMを出すためには「サーボモータドライバ」があったほうがよさそうですね。今回は使っていないので今後使ってみたいです。
ラズパイ電子工作の基本② サーボモータで制御できる輪ゴム鉄砲砲台を作る
インストール
RaspberryPiのGPIOをブラウザから操作するためにWebIOPIをあらかじめインストールしています。WebIOPIのインストール方法についてはこちらの記事をご参照ください。
WebIOPIをRaspberry Piにインストールする方法
また、PWM信号を生成するために「wiringPi」もインストールしておきます。
以下を実行してまずはビルドまで実施しておきます。適当にフォルダを作ってその中で実施します。(7/17訂正)
wiringPiはpipで普通にインストールします。
1 |
sudo pip3 install wiringpi |
PythonからwiringPiを操作するために「WiringPi2-Python」もインストールしておきます。
1 2 3 4 5 6 7 |
cd sudo apt-get update sudo apt-get install python-dev python-setuptools git clone https://github.com/Gadgetoid/WiringPi2-Python.git cd WiringPi2-Python sudo python setup.py install sudo python3 setup.py install |
これでインストールは完了です。
WebIOPIの設定とフォルダ構成
WebIOPiでブラウザにアクセスしたときのhtmlが読み込まれるディレクトリは”/etc/webiopi/config”内で「doc-root = /home/pi/iot/html」に設定しています。
また、同ファイルの中で実行されるスクリプトファイルの場所は「myscript = /home/pi/iot/python/script.py」としています。
これらを前提として今回は以下のようなフォルダ構成にしています。
iot
|-html
| |- index.html
|-python
|- script.py
ファイルの作成
index.htmlとscript.pyを用意していきます。
まずは「index.html」に以下のソースを用意します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width"> <title>Controller</title> <script type="text/javascript" src="/webiopi.js"></script> <script type="text/javascript"> </script> <style type="text/css"> </style> </head> <body> <div align="center"> <table> <tr> <td> <table> <tbody> <tr> <td> <div class="slidecontainer"> <input type="range" min="15" max="40" value="25" class="slider" id="myRange"> </div> </td> </tr> <tr> <td>slider value:<p id="out"></p></td> <td>output value:<p id="out2"></p></td> </tr> </tbody> </table> </td> </tr> </table> </div> <script> var division = 20; var commandID = 0; var slider = document.getElementById("myRange"); var output = document.getElementById("out"); var output2 = document.getElementById("out2"); output.innerHTML = slider.value; // Display the default slider value // Update the current slider value (each time you drag the slider handle) slider.oninput = function(){ output.innerHTML = slider.value; output2.innerHTML = slider.value/division; var outvalue = slider.value/division; webiopi().callMacro("setHwPWMforPan", outvalue); }; </script> </div> </body> </html> |
簡単に解説していきます。WebIOPIのスクリプトを実行するために「・・・ src=”/webiopi.js”」を指定しています。webiopiのインストールが済んでいれば使えると思います。
次にボディの中身にスライダーを用意します。
1 2 3 |
<div class="slidecontainer"> <input type="range" min="15" max="40" value="25" class="slider" id="myRange"> </div> |
最小値15、最大値40のスライダーを用意します。idはスライダーの値を取得するために後ほど使います。
実際に動かしてみると以下のような感じで動いてくれそうです。サーボホーンの角度を限定したいときはスライダーの最小値と最大値を変えてあげればよさそうですね。※ざっくりとなので参考値として捉えてください。
サーボホーン角度(度) | Safety zone | -90 | 0 | 90 | Safety zone |
slider value | 15 | 18 | 26 | 35 | 40 |
output value | 0.75 | 0.9 | 1.3 | 1.75 | 2 |
次にdocument.getElementByIdでHTMLの中身を操作していきます。スライダーは”myRange”で指定してsliderに格納しておきます。outputとoutput2は表示を出力するときに使います。
1 2 3 |
var slider = document.getElementById("myRange"); var output = document.getElementById("out"); var output2 = document.getElementById("out2"); |
以下がスライダーが操作されたときの処理となります。
1 2 3 4 5 6 |
slider.oninput = function(){ output.innerHTML = slider.value; output2.innerHTML = slider.value/division; var outvalue = slider.value/division; webiopi().callMacro("setHwPWMforPan", outvalue); }; |
スライダーが操作されると、idの”output”にスライダーの値が、”output2″にスライダーの値をdivisionで割ったものが表示されます。これをoutvalueとし、「webiopi().callMacro(・・・)」の部分でPythonの処理に渡しています。
次にPythonのファイルを用意していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
import webiopi import time import wiringpi as GPIO SERVO_PAN = 26 # SERVO_PAN (Left)90 ... 0 ... -90(Right) SERVO_PAN_TRIM = 12 # degree SERVO_PAN_LEFT_LIMIT = 60 # degree SERVO_PAN_RIGHT_LIMIT = -60 # degree ##### SERVO SPECIFICATION ##### SERVO_ANGLE_MIN = -90 # degree SERVO_ANGLE_MAX = 90 # degree SERVO_PULSE_MIN = 0.75 # ms SERVO_PULSE_MAX = 2.4 # ms SERVO_CYCLE = 50 # ms ############################### #### WIRINGPI SPECIFICATION #### PWM_WRITE_MIN = 0 PWM_WRITE_MAX = 1024 ################################ SERVO_DUTY_MIN = SERVO_PULSE_MIN/SERVO_CYCLE SERVO_DUTY_MAX = SERVO_PULSE_MAX/SERVO_CYCLE SERVO_PAN_DUTY_MIN = (SERVO_DUTY_MAX - SERVO_DUTY_MIN) / (SERVO_ANGLE_MAX - SERVO_ANGLE_MIN) * ((SERVO_PAN_LEFT_LIMIT +SERVO_PAN_TRIM) - SERVO_ANGLE_MIN) + SERVO_DUTY_MIN SERVO_PAN_DUTY_MAX = (SERVO_DUTY_MAX - SERVO_DUTY_MIN) / (SERVO_ANGLE_MAX - SERVO_ANGLE_MIN) * ((SERVO_PAN_RIGHT_LIMIT+SERVO_PAN_TRIM) - SERVO_ANGLE_MIN) + SERVO_DUTY_MIN SERVO_PAN_PWM_WRITE_MIN = PWM_WRITE_MAX * SERVO_PAN_DUTY_MIN SERVO_PAN_PWM_WRITE_MAX = PWM_WRITE_MAX * SERVO_PAN_DUTY_MAX def getServoPanPWMvalue(val): # This function returns 0 ... 1024 pwm_value = int((SERVO_PAN_PWM_WRITE_MAX - SERVO_PAN_PWM_WRITE_MIN) * val + SERVO_PAN_PWM_WRITE_MIN) return pwm_value webiopi.setDebug() def setup(): webiopi.debug("Script with macros - Setup") GPIO.wiringPiSetupGpio() GPIO.pinMode(SERVO_PAN,GPIO.OUTPUT) GPIO.softPwmCreate(SERVO_PAN,0,50) def loop(): webiopi.sleep(5) def destroy(): webiopi.debug("Script with macros - Destroy") @webiopi.macro def setHwPWMforPan(duty): GPIO.softPwmWrite(SERVO_PAN, getServoPanPWMvalue(float(duty))) |
Pythonのほうのファイルを解説していきます。
webiopiとwiringpiはインストール済みである前提とします。
ピンは今回26番を利用します。
まずはセットアップでGPIOの出力を設定していきます。
1 2 3 4 5 |
def setup(): webiopi.debug("Script with macros - Setup") GPIO.wiringPiSetupGpio() GPIO.pinMode(SERVO_PAN,GPIO.OUTPUT) GPIO.softPwmCreate(SERVO_PAN,0,50) |
GPIOにwiringPiをセットします。ピンモードは先程指定したピン(26)を出力に設定します。今回はPWM制御をwiringPiの「softPwmWrite」を使ってしたいので、「softPwmCreate」でピンのPWMを設定しておきます。周波数は50に設定しています。
1 2 3 |
@webiopi.macro def setHwPWMforPan(duty): GPIO.softPwmWrite(SERVO_PAN, getServoPanPWMvalue(float(duty))) |
ブラウザでスライダーが操作されたらマクロが実行されて上記のメソッドが呼ばれます。dutyを受け取りPWMを計算するために「getServoPanPWMvalue」に値を渡しています。
1 2 3 4 |
def getServoPanPWMvalue(val): # This function returns 0 ... 1024 pwm_value = int((SERVO_PAN_PWM_WRITE_MAX - SERVO_PAN_PWM_WRITE_MIN) * val + SERVO_PAN_PWM_WRITE_MIN) return pwm_value |
引数を受け取ったらPWMを計算していきます。各パラメータからPWMを計算して、計算結果を返却します。
角度やパルス幅はサーボモータの仕様に合わせて変更しておきます。Pythonの中身を変更したらリブートするか、WebIOPIを再起動してください。
WebIOPIを停止するとき↓
1 |
sudo systemctl stop webiopi |
WebIOPIを起動するとき↓
1 |
sudo systemctl start webiopi |
今回の回路
次に回路を用意していきます。サーボモータの電源はRaspberryPiとは別のところから取ってきます。
6Vの2A程度の電源を用意できるといいみたいです。私はたまたまアダプタがあったのでそれを使用しています。
ブラウザから操作してみる
上記まで用意ができたらブラウザからサーボモータを操作してみましょう。まずはWebIOPIを起動しておきます。
1 |
sudo systemctl start webiopi |
WebIOPIを起動したらブラウザで”http://(Raspberry PiのIPアドレス):8000/”にアクセスすると、以下のような画面になります。
このように表示されると思います。この状態でスライダーを操作するとピンの26に接続しているサーボモータを動かすことができます。
ここまで説明してきましたが、上記のスクリプトファイルの中身が訳わからん!!って方、僕と同じです。
スクリプトファイルをもっと簡単にしてみましたので、そのような方はこちらの記事を見てみてください。
ブラウザのスライダーでRaspberryPiのサーボモータを動かす(もっと簡単に!)
今回はソフトウェアPWMを使用しており、実行するとサーボがガタガタと振動してしまいました。振動させたくない場合はハードウェアPWMを使ったらよさそうでしたので、こちらの記事も作成しました。こちらのほうが振動しなくて全然良いことが分かりました。ただし、ハードウェアPWMは使えるPINが限られているのがデメリットです。
ブラウザのスライダーでRaspberryPiのサーボモータを動かす(ハードウェアPWM)
また、上記の方法を利用してロボットアームを動かしたりしています。そのときの記事も興味があれば読んでみてください。
RaspberryPiとサーボモータで5軸ロボットアームを動かしてみた
以上です。今回はブラウザのスライダーでRaspberryPiのサーボモータを動かす方法を紹介させていただきました。
コメントを残す