ここでは、簡単なロボットを作って、LEDランプのON/OFF、DCモータの制御、サーボモータの制御、Webカメラのストリーミング配信の基本機能を試して見ます。
また、Webとの連携ソフトを使ってスマートフォンで操作出来るようにします。
Webiopiインストールしていない場合は「Webブラウザからの遠隔制御(Webiopi)の設定」でインストールして下さい。
設定デイレクトリーは下記の通りとします。
ユーザディレクトリ/xxx ┣ script.py(pythonプログラムの処理) ┗ zzzz.html (HTMLプログラム)
個別プログラムと連動する場合は、Webiopi開始時のPythonスクリプトとHTMLドキュメントのディレクトリ及び
省略時のHTMLファイル名を「/etc/webiopi/config」ファイルに追記して指定します。
・・・・省略・・・・
[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 = /home/pi/xxx/script.py
#------------------------------------------------------------------------#
[HTTP]
# HTTP Server configuration
enabled = true
port = 8000
# File containing sha256(base64("user:password"))
# Use webiopi-passwd command to generate it
passwd-file = /etc/webiopi/passwd
# Change login prompt message
prompt = "WebIOPi"
# Use doc-root to change default HTML and resource files location
#doc-root = /home/pi/webiopi/examples/scripts/macros
doc-root = /home/pi/xxx
# Use welcome-file to change the default "Welcome" file
#welcome-file = index.html
welcome-file = zzzz.html
#------------------------------------------------------------------------#
・・・・省略・・・・
import webiopi
###################################################
# LED制御
###################################################
webiopi.setDebug()
GPIO = webiopi.GPIO
LIGHT = 23 # GPIO pin using BCM numbering
GPIO.setFunction(LIGHT, GPIO.OUT)
GPIO.digitalWrite(LIGHT, GPIO.HIGH)
@webiopi.macro
def lighton():
GPIO.digitalWrite(LIGHT, GPIO.HIGH)
@webiopi.macro
def lightoff():
GPIO.digitalWrite(LIGHT, GPIO.LOW)
# destroy function is called at WebIOPi shutdown
def destroy():
GPIO.digitalWrite(LIGHT, GPIO.LOW)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>RaspberryPi</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<script type="text/javascript" src="/webiopi.js"></script>
</head>
<body>
<H1 style="text-align:center;">RaspberryPi</H1>
<form name="form">
<table style="margin:0 auto;"><tr><td style="text-align:center;">
<input class="bt" type="button" value="ライトオン" onclick="webiopi().callMacro( 'lighton' );"></td><td>
<input class="bt" type="button" value="ライトオフ" onclick="webiopi().callMacro( 'lightoff' );"></td></tr>
</table>
</form>
<script>
webiopi().ready( initialize_webiopi );
function initialize_webiopi(){
// GPIOの状態を監視しない
webiopi().refreshGPIO(false);
}
</script>
</body>
</html>
| PIN 端子 |
名称 | 機能 |
| 1 | GND | GND |
| 2 | OUT1 | モーター出力端子1 |
| 3 | NC | 未接続 |
| 4 | VREF | 制御電源端子(0〜20V)※ |
| 5 | IN1 | ロジック入力端子1 |
| 6 | IN2 | ロジック入力端子2 |
| 7 | VM | モーター用電源 |
| 8 | RS | モーター出力電流検出用端子 |
| 9 | NC | 未接続 |
| 10 | OUT2 | モーター出力端子2 |
| IN1 | IN2 | モーター動作 |
| 0 | 0 | ストップ |
| PWM | 0 | 正転(PWM値に応じて可変) |
| 0 | PWM | 逆転(PWM値に応じて可変) |
| 1 | 1 | ブレーキ |
※ 制御電源端子「VREF」の接続は、モーター駆動用バッテリーから
抵抗(3k〜10kΩ)を介して配線します。
import webiopi
import time
#############################################################
#モータ制御
#############################################################
PIN_L1 = 27
PIN_L2 = 17
PIN_R1 = 11
PIN_R2 = 9
g_mode = 0
g_percentage = 50
GPIO.setFunction( PIN_L1, GPIO.PWM )
GPIO.setFunction( PIN_L2, GPIO.PWM )
GPIO.setFunction( PIN_R1, GPIO.PWM )
GPIO.setFunction( PIN_R2, GPIO.PWM )
def MotorDrive( iIn1Pin, iIn2Pin, percentage ):
if 100 < percentage:
percentage = 100
if -100 > percentage:
percentage = -100
if 10 > percentage and -10 < percentage:
GPIO.pwmWrite( iIn1Pin, 0.0 )
GPIO.pwmWrite( iIn2Pin, 0.0 )
elif 0 < percentage:
GPIO.pwmWrite( iIn1Pin, percentage * 0.01 )
GPIO.pwmWrite( iIn2Pin, 0.0 )
else:
GPIO.pwmWrite( iIn1Pin, 0.0 )
GPIO.pwmWrite( iIn2Pin, -percentage * 0.01 )
@webiopi.macro
def ChangeDriveMode( mode ):
if mode == "0":
webiopi.debug("ChangeDriveMode : Stop")
MotorDrive( PIN_L1, PIN_L2, 0 );
MotorDrive( PIN_R1, PIN_R2, 0 );
elif mode == "1":
webiopi.debug("ChangeDriveMode : Forward")
MotorDrive( PIN_L1, PIN_L2, g_percentage );
MotorDrive( PIN_R1, PIN_R2, g_percentage );
elif mode == "2":
webiopi.debug("ChangeDriveMode : Backward")
MotorDrive( PIN_L1, PIN_L2, -g_percentage );
MotorDrive( PIN_R1, PIN_R2, -g_percentage );
elif mode == "3":
webiopi.debug("ChangeDriveMode : CW")
MotorDrive( PIN_L1, PIN_L2, g_percentage );
MotorDrive( PIN_R1, PIN_R2, -g_percentage );
elif mode == "4":
webiopi.debug("ChangeDriveMode : CCW")
MotorDrive( PIN_L1, PIN_L2, -g_percentage );
MotorDrive( PIN_R1, PIN_R2, g_percentage );
global g_mode
g_mode = mode
@webiopi.macro
def ChangeVoltageLevel( level ):
webiopi.debug("ChangeVoltageLevel : %s" % (level))
global g_percentage
g_percentage = 1 * int(level)
ChangeDriveMode( g_mode )
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>RaspberryPi</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<script type="text/javascript" src="/webiopi.js"></script>
</head>
<body>
<H1 style="text-align:center;">RaspberryPi</H1>
<form name="form">
<table style="margin:0 auto;"><tr><td style="text-align:center;">
<input class="bt" type="button" value="前進" onclick="webiopi().callMacro( 'ChangeDriveMode',1 );"><br>
<input class="bt" type="button" value="左" onclick="webiopi().callMacro( 'ChangeDriveMode',4 );">
<input class="bt" type="button" value="停止" onclick="webiopi().callMacro( 'ChangeDriveMode',0 );">
<input class="bt" type="button" value="右" onclick="webiopi().callMacro( 'ChangeDriveMode',3 );"><br>
<input class="bt" type="button" value="後退" onclick="webiopi().callMacro( 'ChangeDriveMode',2 );"><br>レベル<br>
<input type="range" name="range1" min="1" max="100" step="1" value="1" onchange="vlevel(form.range1.value)"> <span id="inp">1</span>
</td></tr></table>
</form>
<script>
//****************************************
//モータ制御用
//****************************************
webiopi().ready( function() {
webiopi().callMacro( 'ChangeDriveMode',0 );
vlevel(1) ;
} ) ;
function vlevel(level) { inp.innerHTML = level ; webiopi().callMacro( "ChangeVoltageLevel", level); }
</script>
</body>
</html>
サーボを精度良く制御するために必要な、精度の高いPWM信号を生成するためのライブラリである”wiringPi”をインストールします。
GitHubからWiringPiをダウンロードします。
ダウンロードしたWiringPiディレクトリに移動してビルドします。
PythonからWiringPiを操作するための”WiringPi2-Python”をインストールします。
WebIOPiと連携させるために、Raspbyerry Pi標準のPython2.xに加え、Python3.xもインストールしています。
| 項目 | 仕様 |
| PWMサイクル | 20ms |
| 制御パルス | 0.5ms~2.4ms |
| 制御角 | ±約90°(180°) |
| 動作速度 | 0.1秒/60° |
| 動作電圧 | 4.8V(~5V) |
| 角度 | μs | Duty% | Duty Cycle ※ |
| -90 | 500 | 2.5 | 25.6 |
| -45 | 975 | 4.88 | 50.0 |
| 0 | 1450 | 7.25 | 74.2 |
| 45 | 1925 | 9.63 | 98.6 |
| 90 | 2400 | 12 | 122.9 |
※Duty Cycle = 100% のときに1024とした場合の値
import webiopi
import time
########################################################
# サーボ制御
########################################################
import wiringpi
def getServoDutyForWebIOPi(val):
val_min = 0.0
val_max = 1.0
servo_min = 25 # 50Hzで, 0.7ms
servo_max = 123 # 50Hzで, 2.0ms
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(19, wiringpi.GPIO.PWM_OUTPUT)
wiringpi.pwmSetMode(wiringpi.GPIO.PWM_MODE_MS) # 周波数固定
wiringpi.pwmSetClock(375) # 50 Hz
wiringpi.pwmWrite(18, getServoDutyForWebIOPi(0.5))
wiringpi.pwmWrite(19, getServoDutyForWebIOPi(0.5))
@webiopi.macro
def setHwPWM1(duty, commandID):
wiringpi.pwmWrite(18, getServoDutyForWebIOPi(float(duty)))
@webiopi.macro
def setHwPWM2(duty, commandID):
wiringpi.pwmWrite(19, getServoDutyForWebIOPi(float(duty)))
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>RaspberryPi</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<script type="text/javascript" src="/webiopi.js"></script>
</head>
<body>
<H1 style="text-align:center;">RaspberryPi</H1>
<form name="form">
<table style="margin:0 auto;"><tr><td style="text-align:center;">
<table style="margin:0 auto;"><tr><td>
右<input type="range" name="range21" min="0" max="20" step="1" value="10" onchange="sv1(form.range21.value)"><br>
左<input type="range" name="range22" min="0" max="20" step="1" value="10" onchange="sv2(form.range22.value)"><br>
</td></tr></table>
</form>
<script>
//*******************************************
//サーボ用
//*******************************************
webiopi().ready( initialize_webiopi );
// 命令送信ごとに増加するIDを作成(iOSのSafariでPOSTがキャッシュされることの対策)
var commandID=0;
function initialize_webiopi(){
// GPIOの状態を監視しない
// webiopi().refreshGPIO(false);
}
function sv1(z) {
ratio = z / 20 ;
webiopi().callMacro("setHwPWM1", [ratio, commandID++]);
}
function sv2(z) {
ratio = z / 20 ;
ratio = 1.0 - ratio;
webiopi().callMacro("setHwPWM2", [ratio, commandID++]);
}
</script>
</body>
</html>
120 万画素、ビデオ解像度(1280×720)、最大フレームレート30fps、内臓マイク付
次のコマンドでインストールします。
Webサーバーの起動(インプットをRaspberry Pi用に修正)コマンド。
下記のコマンドで開始します。画像サイズ、フレームレート(fps)は任意に設定してください。
/usr/local/bin/mjpg_streamer -i "input_raspicam.so -x 640 -y 480 -fps 15 -q 80"
-o "output_http.so -p 8080 -w /usr/local/share/mjpg-streamer/www"
Webサーバーを起動しています。
http://RaspberryPiのIPアドレス:8080/へアクセスするとサンプルスクリプトとストリーミングされた映像を見ることができます。
JavaScriptのサンプルスクリプトは必要に応じてストリーミングコンテンツの場所を変更します。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>RaspberryPi</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <script type="text/javascript" src="/webiopi.js"></script> </head> <body onload="createImageLayer();"> <H1 style="text-align:center;">RaspberryPi</H1> <div id="webcam" style="text-align:center;"> <!--noscript--><img src="http://192.168.0.10:8080/?action=snapshot" /><!--/noscript--> </div> <script> //********************************************* // Webカメラ //********************************************* /* Copyright (C) 2007 Richard Atterer, richard息atterer.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2. See the file COPYING for details. */ var imageNr = 0; // Serial number of current image var finished = new Array(); // References to img objects which have finished downloading var paused = false; function createImageLayer() { var img = new Image(); img.style.position = "absolute"; img.style.zIndex = -1; img.onload = imageOnload; img.onclick = imageOnclick; //img.src = "http://" + document.getElementById("ipa") + ":8080/?action=snapshot&n=" + (++imageNr); img.src = "http://192.168.0.10:8080/?action=snapshot&n=" + (++imageNr); var webcam = document.getElementById("webcam"); webcam.insertBefore(img, webcam.firstChild); } // Two layers are always present (except at the very beginning), to avoid flicker function imageOnload() { this.style.zIndex = imageNr; // Image finished, bring to front! while (1 < finished.length) { var del = finished.shift(); // Delete old image(s) from document del.parentNode.removeChild(del); } finished.push(this); if (!paused) createImageLayer(); } function imageOnclick() { // Clicking on the image will pause the stream paused = !paused; if (!paused) createImageLayer(); } </script> </body> </html>
下記のコマンドで開始します。画像サイズ、フレームレート(fps)は任意に設定してください。
$ /usr/local/bin/mjpg_streamer -i "input_uvc.so -r 320x240 -fps 15"
-o "output_http.so -p 8080 -w /usr/local/share/mjpg-streamer/www"
自動起動設定をsystemd 「/etc/systemd/system/mjpg_streamer.service」ファイルに、下記の様に作成します。
# /etc/systemd/system/mjpg_streamer.service
[Unit]
Description=mjpg-streamer
After=syslog.target
[Service]
Type=simple
WorkingDirectory=/usr/local/bin/
ExecStart=/usr/local/bin/mjpg_streamer -i "input_uvc.so -r 320x240
-fps 15"
-o "output_http.so -p 8080 -w /usr/local/share/mjpg-streamer/www"
TimeoutStopSec=5
StandardOutput=null
[Install]
WantedBy = multi-user.target
作成したファイルを読み込みます。
$ sudo systemctl daemon-reload
以下コマンドでサービスの自動起動を設定します。
$ sudo systemctl enable mjpg_streamer
自動起動を停止したい場合は以下のコマンド
$ sudo systemctl disable mjpg_streamer
サービスの起動と停止は以下のコマンド
$ sudo systemctl start mjpg_streamer $ sudo systemctl stop mjpg_streamer
サービスの自動起動を設定したら再起動して確認してください。