人気ブログランキング | 話題のタグを見る

Prof. Kunio Takaya, SK Canada

Raspberry Pi で作るラジコン戦車 (その4: スマホで制御 WebIOPi)

目次 Table of Contents

調べているうちにわかったことだが Raspberry Pi を使って IoT (internet of things) いわゆる物をインターネットを介して制御するには WebIOPi が定番になっている事だった。WebIOPi はスマホやコンピュータのブラウザーとラズパイの GPIO の間を取り持つシステムで、スマホが見ている index.html スクリプトが例えば LED を点けるとか消すとかの指令を受け取り、Python で書かれたスクリプトに従って GPIO を操作する。従ってラズパイに WebIOPi をインストール必要がある。そして WebIOPi を次のように起動させてやる。 sudo webiopi -d -c /etc/webiopi/config

Raspberry Pi で作るラジコン戦車 (その4: スマホで制御 WebIOPi)_c0159967_12503899.jpg
WebIOPi は config ファイルに記載された index.html と script.py を使ってブラウザーに java スクリプトなどで書かれた画面情報をブラウザーに送り、ブラウザーから送られてくるレスポンスを script.py に引き渡す。config ファイルには index.html と script.py のようなユーザー情報をあらかじめ書いておく必要がある。
Raspberry Pi で作るラジコン戦車 (その4: スマホで制御 WebIOPi)_c0159967_12505452.jpg
まずこの WebIOpi なるシステムをインストールすることから始めた。「WebIOPi のインストール」で検索するとたくさんの参考記事があるが、私は http://www.hiramine.com/physicalcomputing/raspberrypi3/webiopi_install.html に忠実に従ったら一発で成功した。WebIOPi をダウンロードするには、
wget https://sourceforge.net/projects/webiopi/files/WebIOPi-0.7.1.tar.gz
tar xvzf WebIOPi-0.7.1.tar.gz
修正プログラムのパッチには、
cd WebIOPi-0.7.1
wget https://raw.githubusercontent.com/doublebind/raspi/master/webiopi-pi2bplus.patch
patch -p1 -i webiopi-pi2bplus.patch
セットアップするには、
sudo ./setup.sh
サービスとしてプログラムを走らせるスクリプトをダウンロードして、
cd /etc/systemd/system/
sudo wget https://raw.githubusercontent.com/doublebind/raspi/master/webiopi.service
WebIOpi をスタート、ストップするには、
cd ~
sudo systemctl start webiopi
sudo systemctl stop webiopi
プログラムを起動してやって、WiFi の傘下にあるパソコンあるいはスマホで Raspberry Pi の IP アドレスを使って、私の場合
http://172.16.1.92:8000/ をブラウザーに指定すると次の画面が現れる。
Raspberry Pi で作るラジコン戦車 (その4: スマホで制御 WebIOPi)_c0159967_11150525.jpg
GPIO Header をクリックするとヘッダーの画面が現れる。
Raspberry Pi で作るラジコン戦車 (その4: スマホで制御 WebIOPi)_c0159967_11173296.jpg
WebIOpi がバックグラウンドでサービスとして走っていると、スマホの画面に表示されるこの画面はラズパイ GPIO のコネクターの状態を示している。四角のボタンはスマホからのタッチセンサーにもなっていて IN/OUT の切り替えを行うことができる。OUT の場合ピンの状態を HIGH/LOW に切り替えることができる。そこで GPIO-3 と GPIO-17 に LED を付けて ON/OFF してみた。
Raspberry Pi で作るラジコン戦車 (その4: スマホで制御 WebIOPi)_c0159967_03585112.jpg
GPIO-3 に青い LED、GPIO-17 にRGBの LED のRBのみを点灯するように配線した。
Raspberry Pi で作るラジコン戦車 (その4: スマホで制御 WebIOPi)_c0159967_04210795.jpg
これで WebIOpi の基本動作は確認できたことになる。任意の Pyton で書かれたプログラムを、自分でデザインしたスマホ画面から操作するにはもう一歩進まねばならない。この一連の手順が WrbIOpi のチュートリアルのページによくまとまって書いてある。http://webiopi.trouch.com/Tutorial_Basis.html を参照するとよい。全く同じものだが、 GPIO17(11番ピン)の LEDに対して「WebIOPiでIoT!(2)プログラミング基礎編〜Lチカボタンを作ろう」という記事があるからこれも参考になる。http://deviceplus.jp/hobby/raspberrypi_entry_031/ まずしなければならないことは次のようにフォールダを作っておくことである。
home
- pi
- myproject
- python
- html
スマホによる Raspberry Pi の GPIO を制御するためのシステム WebIOPi は2つのファイルを用いる。ブラウザー <=> WebIOPi 間のやり取りには index.html が必要であり、WebIOPi <=> Raspberry Pi GPIO 間のやり取りには script.py が必要となる。index.html は /home/pi/myproject/html/index.html のように、script.py は /home/pi/myproject/python/script.py のようにそれぞれ指定されたフォールダに入れておく。WrbIOpi のチュートリアルのページにある例題ファイルは index.html が次のスクリプトである。
<!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">
<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 17
var button = webiopi().createGPIOButton(17, "Light");

// Append button to HTML element with ID="controls" using jQuery
$("#controls").append(button);

// Refresh GPIO buttons
// pass true to refresh repeatedly of false to refresh once
webiopi().refreshGPIO(true);
});

</script>
<style type="text/css">
button {
display: block;
margin: 5px 5px 5px 5px;
width: 160px;
height: 45px;
font-size: 24pt;
font-weight: bold;
color: white;
}

#gpio17.LOW {
background-color: Black;
}

#gpio17.HIGH {
background-color: Blue;
}
</style>
</head>
<body>
<div id="controls" align="center"></div>
</body>
</html>
一方、script.py は次のようになっている。操作はGPIO-17 につないだ LED を ON/OFF することであるから、前にGPIO-17 にセットした RGB LED がそのまま使える。
import webiopi
import datetime

GPIO = webiopi.GPIO

LIGHT = 17 # GPIO pin using BCM numbering

HOUR_ON = 8 # Turn Light ON at 08:00
HOUR_OFF = 18 # Turn Light OFF at 18:00

# setup function is automatically called at WebIOPi startup
def setup():
# set the GPIO used by the light to output
GPIO.setFunction(LIGHT, GPIO.OUT)

# retrieve current datetime
now = datetime.datetime.now()

# test if we are between ON time and tun the light ON
if ((now.hour >= HOUR_ON) and (now.hour < HOUR_OFF)):
GPIO.digitalWrite(LIGHT, GPIO.HIGH)

# loop function is repeatedly called by WebIOPi
def loop():
# retrieve current datetime
now = datetime.datetime.now()

# toggle light ON all days at the correct time
if ((now.hour == HOUR_ON) and (now.minute == 0) and (now.second == 0)):
if (GPIO.digitalRead(LIGHT) == GPIO.LOW):
GPIO.digitalWrite(LIGHT, GPIO.HIGH)

# toggle light OFF
if ((now.hour == HOUR_OFF) and (now.minute == 0) and (now.second == 0)):
if (GPIO.digitalRead(LIGHT) == GPIO.HIGH):
GPIO.digitalWrite(LIGHT, GPIO.LOW)

# gives CPU some time before looping again
webiopi.sleep(1)

# destroy function is called at WebIOPi shutdown
def destroy():
GPIO.digitalWrite(LIGHT, GPIO.LOW)

最後に /etc/webiopi/config にある config というファイルに webIOPi に対する指示事項を書き留めておく。
config ファイルの中で [SCRIPTS] を見つけ次の1行を書き込む。
...
[SCRIPTS]
myproject = /home/pi/myproject/python/script.py
...
config ファイルの中で [HTTP] を見つけ次の1行を書き込む。
...
[HTTP]
doc-root = /home/pi/myproject/html
...
config ファイルの中で [REST] を見つけ次の3行を書き込む。
...
[REST]
gpio-export = 17
gpio-post-value = true
gpio-post-function = false
...
これだけの準備が出来たら WebIOPi を起動する。
cd ~
sudo systemctl start webiopi
としてプログラムを起動してやって、WiFi の傘下にあるパソコンあるいはスマホで Raspberry Pi の IP アドレスを使って、私の場合 http://172.16.1.92:8000/ をブラウザーに打ち込んでやると次の画面が現れる。LIGHT のところをタッチしてやると背景の色が黒から青に変わり、青色の LED が点滅する。これでチュートリアルの Lチカが実現できたことになる。
Raspberry Pi で作るラジコン戦車 (その4: スマホで制御 WebIOPi)_c0159967_11042508.jpg

# by Prof_Multimedia | 2018-02-16 11:48 | テクノロジー

Raspberry Pi で作るラジコン戦車 (その3: Video Streamer)

目次 Table of Contents

目指すは遠隔操作のできるRaspberry Pi で作るラジコン戦車である。自動操縦でなく台車に装着したビデオカメラで映像を見ながら運転することである。 Arduino では難しかったビデオカメラを簡単に使えるのはさすがRaspberry Piである。SainSmart Camera Module Board 5MP Webcam Video 1080p 720p for Raspberry Pi CD$ 25.99 を買いました。
Raspberry Pi で作るラジコン戦車 (その3: Video Streamer)_c0159967_04264045.jpg
Raspberry Pi で作るラジコン戦車 (その2: 台車テスト)で述べた Raspberry Pi 3 を搭載した台車を使いました。これにカメラモジュールをスタイロフォームの板で前方が見えるように取り付けました。
Raspberry Pi で作るラジコン戦車 (その3: Video Streamer)_c0159967_04265155.jpg

初期設定には 「Raspberry Pi カメラで写真・ビデオを撮影する」https://iotdiyclub.net/raspberry-pi-using-camera-1/ を参照しました。ラズパイのカメラモジュールを専用のソケットに装着したあとカメラを enable してやる。このためには
$ sudo raspi-config
を起動してカメラを有効にして
$ vcgencmd get_camera
によって有効になったことを確認する。カメラが動作しているかどうかを静止画像と動画で次のコマンドを用いて確認した。
$ raspistill -o raspi-camera-1.jpg

$ raspivid -o raspi-video-1.h264 -t 5000

$ omxplayer ./Videos/raspi-video-1.h264
ビデオ・ストリーマーを行うのには「Raspberry Pi 3 の標準カメラで撮影した動画をブラウザに配信する方法まとめ」https://qiita.com/okaxaki/items/72226a0b0f5fab0ec9e9 を参照した。プログラムのインストールから実行までは次のコマンドを使った。
$ uname -a
Linux raspberrypi 4.4.45-v7+ #954 SMP Fri Jan 27 19:06:40 GMT 2017 armv7l GNU/Linux

$ sudo apt-get install -y cmake libv4l-dev libjpeg-dev imagemagick
$ git clone https://github.com/jacksonliam/mjpg-streamer.git
$ cd mjpg-streamer/mjpg-streamer-experimental
$ make

$ ./mjpg_streamer -o "./output_http.so -w ./www" -i "./input_raspicam.so -x 640 -y 480 -fps 30 -q 10"
これでビデオ・ストリーマーはインターネットにビデオ配信を始めるから、同じ WiFi ネットワークにある PC やスマートホーンのブラウザーを通してみることができる。これに先立って、Raspberry Pi の IP アドレスを調べておく必要がある。次のコマンドで調べる。
$ ip addr show
$ /sbin/ifconfig
ブラウザーの URL は
http://[ラズパイのIP]:8080/
である。同じ WiFi ネットワークにある Windows コンピュータで受信したビデオ・ストリーマーからくるページは次の写真である。
Raspberry Pi で作るラジコン戦車 (その3: Video Streamer)_c0159967_03545743.jpg
おなじ WiFi ネットワーク上のスマートホーンで受信して、その画面をラズパイのカメラに向けると地祇のような繰り返し映る画像が得られる。ビデオストリーマーのコマンドの中に "-x 640 -y 480 -fps 30 -q 10" とある指定は、画素が (640x480) 毎秒30フレーム、画質は最高の10と指定してある。WiFiのルーターからかなり離れているのでRange Extenderを使っているが毎秒30枚の早さは確保された。

Raspberry Pi で作るラジコン戦車 (その3: Video Streamer)_c0159967_04080569.jpg
Raspberry Pi で作るラジコン戦車 (その3: Video Streamer)_c0159967_04081032.jpg



# by Prof_Multimedia | 2018-02-03 04:24 | テクノロジー

Raspberry Pi で作るラジコン戦車 (その2: 台車テスト)

目次 Table of Contents

前回の「Raspberry Pi で作るラジコン戦車 (その1: 準備) 」で学んだラズパイのテクニックを使ってラジコン戦車の台車を動かすテストプログラムを書いてみた。最初に描いたデザイン、構想はスマートフォン用のモバイルバッテリーを電源とするラズパイを乗せたラジコン戦車を単3バッテリー3本(4.5V)で駆動することであった。そのためのテストプログラムを書いて、試験をしているうちに、問題が2つ生じた。その一つはTAMIYAのキャタピラー型の戦車が4.5Vでは駆動できないことにあった。ツインモータが4.5V では十分な電流が得られないようだ。またキャタピラーのテンションがきつく回転が阻害されている。4.5V の単3電池3本を数分で使い切ってしまう。思い切って台車を交換した。2輪とキャスターによるものである。モーターはTAMIYAのツインモーターと同等品である。電池の電圧も4.5V から6V、単3、4本に増やした。

Raspberry Pi で作るラジコン戦車 (その2: 台車テスト)_c0159967_03441295.jpg
Raspberry Pi で作るラジコン戦車 (その2: 台車テスト)_c0159967_03433405.jpg

もう一つの問題もハードウエアがらみのものである。ラズパイそのものの問題かもしれない。 前回、ボタンSWによる割込みを述べた。Raspberry Pi でGPIOを使った戦車ロボットのプログラムを実行しているときに、ローカルに戦車ロボットにスタート/ストップなどの指令を与えるのにボタンSWなどを使いたくなる。ボタンSWを押すことでプログラムの流れを変えることをLチカのプログラムに対して行ってみた。2個のLEDを交互に点滅するプログラムの点滅の早さをボタンSWを押すことで変えてみた。この実験ではうまくいっていた割り込み動作が、モーターを回すことで動作不良をおこす。GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)としてGPIO 17につないだプッシュボタン・スイッチにより割り込みをGPIO.add_event_detect(17, GPIO.FALLING, callback=my_callback, bouncetime=500)によって定義してプログラムのコントロールに使おうというのが趣旨であった。

ところが、my_callbackの中のprint ("Falling edge detected on port 17, Flag = ", config.Flag)というメッセージがひっきりなしに出てしまうのです。Lチカではボタン・スイッチを押したときにだけメッセージがでますが、モーターを回すとひっきりなしにFalling Edge Detectedが検出される。ノイズのためと思われる。グラウンド・ループのためかと思い12ピンのパッケジから14ピンのパッケジに変えてみた。アナログとディジタルのグラウンドがアイソレートされているのを期待したが結果的には何ら変わらなかった。
Raspberry Pi で作るラジコン戦車 (その2: 台車テスト)_c0159967_09262354.jpg
このテストプログラムは前進-後進を0.5秒の停止をはさんで2秒行い、右折前進-後進を0.5秒の停止をはさんで2秒行い、さらに左折前進-後進を0.5秒の停止をはさんで2秒行なう。割り込みによるコントロールが効かないのでモーター電源にスイッチを入れて手動停止をできるようにした。


#!/usr/bin/env python2.7  
# script by Alex Eames http://RasPi.tv

import RPi.GPIO as GPIO
import config

from time import sleep
GPIO.setmode(GPIO.BCM)
GPIO.setup(19, GPIO.OUT) # GPIO19 as an output BENBL(PWM).
GPIO.setup(20, GPIO.OUT) # GPIO20 as an output AENBL(PWM).
GPIO.setup(24, GPIO.OUT) # GPIO24 as an output APHASE(dir).
GPIO.setup(25, GPIO.OUT) # GPIO25 as an output BPHASE(dir).

Aenbl = GPIO.PWM(20,100) #GPIO20 as PWM output, with 100Hz frequency
Benbl = GPIO.PWM(19,100) #GPIO19 as PWM output, with 100Hz frequency

# GPIO 17 set up as inputs.
# 17 will go to GND when button pressed.
#GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP) #, pull_up_down=GPIO.PUD_UP)
GPIO.setup(27, GPIO.OUT)

# now we'll define the threaded callback function
# this will run in another thread when our event is detected
def my_callback(channel):
GPIO.remove_event_detect(17)
if config.Flag == 1:
config.Flag = 0
GPIO.output(27, GPIO.LOW)
else:
config.Flag = 1
GPIO.output(27, GPIO.HIGH)
print ("Falling edge detected on port 17, Flag = ", config.Flag)
GPIO.add_event_detect(17, GPIO.FALLING, callback=my_callback, bouncetime=500)


#GPIO.add_event_detect(17, GPIO.FALLING, callback=my_callback, bouncetime=500)

#Aenbl.start(0)

try:
while(1): #GPIO.input(17) if GPIO.input(17) is HIGH
GPIO.output(27, GPIO.HIGH)

Aenbl.start(0) #Left
GPIO.output(24, GPIO.HIGH) #APHASE(dir) FORWARD
Aenbl.ChangeDutyCycle(75)
Benbl.start(0) #Right
GPIO.output(25, GPIO.HIGH)
Benbl.ChangeDutyCycle(75)
sleep(2)
Aenbl.stop()
Benbl.stop()
sleep(0.5)

Aenbl.start(0) #Left
GPIO.output(24, GPIO.LOW) #APHASE(dir) REVERSE
Aenbl.ChangeDutyCycle(75)
Benbl.start(0) #Right
GPIO.output(25, GPIO.LOW)
Benbl.ChangeDutyCycle(75)
sleep(2)
Aenbl.stop()
Benbl.stop()
sleep(0.5)

# Turn right

Aenbl.start(0) #Left
GPIO.output(24, GPIO.HIGH) #APHASE(dir) FORWARD
Aenbl.ChangeDutyCycle(75)
Benbl.start(0) #Right
GPIO.output(25, GPIO.HIGH)
Benbl.ChangeDutyCycle(50)
sleep(2)
Aenbl.stop()
Benbl.stop()
sleep(0.5)

Aenbl.start(0) #Left
GPIO.output(24, GPIO.LOW) #APHASE(dir) REVERSE
Aenbl.ChangeDutyCycle(75)
Benbl.start(0) #Right
GPIO.output(25, GPIO.LOW)
Benbl.ChangeDutyCycle(50)
sleep(2)
Aenbl.stop()
Benbl.stop()
sleep(0.5)

#Turn LEFT

Aenbl.start(0) #Left
GPIO.output(24, GPIO.HIGH) #APHASE(dir) FORWARD
Aenbl.ChangeDutyCycle(50)
Benbl.start(0) #Right
GPIO.output(25, GPIO.HIGH)
Benbl.ChangeDutyCycle(75)
sleep(2)
Aenbl.stop()
Benbl.stop()
sleep(0.5)

Aenbl.start(0) #Left
GPIO.output(24, GPIO.LOW) #APHASE(dir) REVERSE
Aenbl.ChangeDutyCycle(50)
Benbl.start(0) #Right
GPIO.output(25, GPIO.LOW)
Benbl.ChangeDutyCycle(75)
sleep(2)
Aenbl.stop()
Benbl.stop()
sleep(0.5)

except KeyboardInterrupt:
pass

GPIO.output(27, GPIO.LOW)

GPIO.cleanup()

このプログラムの中で次のコメントアウトが割り込み処理をしないようにした箇所である。
# GPIO 17 set up as inputs. 
# 17 will go to GND when button pressed.
#GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP) #, pull_up_down=GPIO.PUD_UP)

#GPIO.add_event_detect(17, GPIO.FALLING, callback=my_callback, bouncetime=500)

# by Prof_Multimedia | 2017-12-05 10:06 | テクノロジー

Raspberry Pi で作るラジコン戦車 (その1: 準備)

目次 Table of Contents

5月に日本に行ったとき目についた本「ラズパイとスマホでラジコン戦車を作ろう!」を買いおまけにキット1式も買った。親子で電子工作とか書いてあるのですぐ作りすぐ動かせると思った。私には難しすぎた。親はラズパイのプロでないと分からない。子供は一度開いて見るだけで終わるだろう。何を作ってどう動かすのかと云う全体像がどこまでページをめくっても出てこない。ラズパイのGPIOを使ってLチカは成功させただけの新米には歯が立たない。しばらく放っておいたが、ラズパイもハードウエアも1式そろっているので、もったいないから私なりに1歩1歩分からないことを調べてラジコン戦車を作ってみることにした。
Raspberry Pi で作るラジコン戦車 (その1: 準備)_c0159967_13585981.jpg
まず第一の問題は単純だが避けて通れない問題でした。私のRaspbery Pi 3Bは(多くの人が同じですが)USBにキーボードとマウスがつながり、HDMIのビデオにはモニターが接続されています。電源はUSBのアダプターからとっています。このラズパイをどうやって戦車に搭載するのかでした。電源は電池からとることにしても、キーボードとマウスとモニターを外して、どうやって自分のプログラム(戦車のコントロールの)を起動させるのだろうという初歩的な疑問です。
Raspberry Pi で作るラジコン戦車 (その1: 準備)_c0159967_03043455.jpg

1.電源
私のラズパイは今パソコンとしてmicro USBのアダプターを110Vに差し込んで使っているが、スマートフォン用のモバイルバッテリー(Buffalo BSMPB5201P2 52000mAh)に置き換えてみたらすんなり動いた。

2. モニター、キーボード、マウス
Arduino と違いPCのIDE(統合開発環境)でプログラムをUSBなどを通してダウンロードして動かすのではなく、Raspberry PiでPythonで開発したプログラムをラズパイの上で走らせるわけだから、これらの基本IOがないと何もできないので、当座このままにしておくことにした。

2. GPIO
Arduinoでは、Atmel AVR マイクロコントローラ(ATmega8, ATmega168, ATmega328P, ATMega644P, ATmega1280, SAM3X)に様々なIO回路(アナログ、ディジタルなど)がある。8MHzもしくは16MHzもしくは84MHzの水晶振動子がクロックとして時間の基準になっている。

一方、Raspberry Pi 3ではCPUに1.2GHz クアッドコアの64bit CPU・ARM Cortex-A53を採用しており、先代モデルのRaspberry Pi 2に比べて1.5倍、初代のRaspberry Pi 1と比較すると実に10倍という処理速度となっています。また、ユーザー待望の802.11n Wi-FiとBluetooth 4.1(BLE対応)がオンボードで搭載されており、本体だけでワイヤレスネットワークが利用できるようになっている。このCPUの持つIO回路がGPOIとして40ピンのコネクターに出ている。ただしアナログIOはなくA/D変換を必要とするなら外付けになる。

3. 2個のLED点滅
まずGPIOの基本動作を思い出し、確認する意味で2個のLEDでLチカをやってみることにした。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# GPIO24 & GPIO25 connected to LED

import RPi.GPIO as GPIO
from time import sleep

GPIO.setmode(GPIO.BCM)
GPIO.setup(24, GPIO.OUT)
GPIO.setup(25, GPIO.OUT)

try:
while True:
GPIO.output(24, GPIO.LOW)
GPIO.output(25, GPIO.HIGH)
sleep(0.5)
GPIO.output(24, GPIO.HIGH)
GPIO.output(25, GPIO.LOW)
sleep(0.5)

except KeyboardInterrupt:
pass

GPIO.cleanup()

おさらいの2点はimport RPi.GPIO as GPIOでライブラリーを指定すること、GPIO.setmode(GPIO.BCM)で"Broadcom SOC channel" つまりGPIO番号そのものを指定することでピン番号は使わないことをいみする。下の図の薄緑の四角のGPIO番号を使うことを意味する。
Raspberry Pi で作るラジコン戦車 (その1: 準備)_c0159967_03161119.png
4. PWMのテスト
この戦車ロボットではタミヤのツインモーターを使う。モーターのコントロールはPWMで行うので、PWMをLEDでテストしておく。
import RPi.GPIO as IO          #calling header file which helps us use GPIO
import time #calling time to provide delays in program
IO.setwarnings(False) #do not show any warnings
IO.setmode (IO.BCM) #we are programming the GPIO by BCM pin numbers.
IO.setup(20, IO.OUT) # initialize GPIO20 as an output.
IO.setup(17, IO.OUT) # initialize GPIO17 as an output.

p = IO.PWM(20,100) #GPIO20 as PWM output, with 100Hz frequency
p.start(0) #generate PWM signal with 0% duty cycle
while 1: #execute loop forever
for x in range (100): #execute loop for 50 times, x being incremented from 0 to 99.
p.ChangeDutyCycle(x) #change duty cycle for varying the brightness of LED (inc).
time.sleep(0.01) #sleep for 100m second
IO.output(17, True)

for x in range (100): #execute loop for 50 times, x being incremented from 0 to 99.
p.ChangeDutyCycle(100-x) #change duty cycle for changing the brightness of LED (dec).
time.sleep(0.01) #sleep for 100m second
IO.output(17, False)

GPIO20をPWMのポートとし、GPIO17につないだLEDをDuty Cycleを増やすときは消し、減らすときにはつけるぷろぐらむである。Pythonがインデント(段落)で終結するスクリプトであることを再確認した。

5. 2回路 DCモーター ドライバー DRV8835
この戦車ロボットのツインモーターを動かすのはArduinoで使ったDRV8835である。ただパッケジは日本のもので12ピンである。DRV8835デュアルモータードライバのブレイクアウト基板。チャンネルごとに1.2A(ピーク1.5A)で2つのDCモータを駆動できる。MODEピンにHIGHを入力すると、1つのピンでモータの方向を決め、もう1つのピンでその出力の強さを決めるモード(PHASE/ENABLE)になります。一方MODEピンにLOWを入力もしくは接続しない場合はより細かい制御の出来るモード(IN/IN)になります。
Raspberry Pi で作るラジコン戦車 (その1: 準備)_c0159967_03350457.jpg
Raspberry Pi で作るラジコン戦車 (その1: 準備)_c0159967_09231841.jpg
ここではMODEピンをHIGHにして(PHASE/ENABLE)のモードで使います。APHASE/AIN1 = GPIO24 (方向), BPHASE/BIN1 = GPIO25 (方向), AENBL/AIN2 = GPIO20 (PWM) , BENBL/BIN2 = GPIO19 (PWM), と指定しました。

6. ボタンSWによる割込み 
Raspberry Pi でGPIOを使った戦車ロボットのプログラムを実行しているときに、ローカルに戦車ロボットにスタート/ストップなどの指令を与えるのにボタンSWなどを使いたくなる。ボタンSWを押すことでプログラムの流れを変えることをLチカのプログラムに対して行ってみた。2個のLEDを交互に点滅するプログラムの点滅の早さをボタンSWを押すことで変えてみた。
#!/usr/bin/env python2.7  
# script by Alex Eames http://RasPi.tv

import RPi.GPIO as GPIO
import config

from time import sleep
GPIO.setmode(GPIO.BCM)

GPIO.setup(24, GPIO.OUT)
GPIO.setup(25, GPIO.OUT)
# GPIO 17 set up as inputs.
# 17 will go to GND when button pressed.
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(27, GPIO.OUT)

# now we'll define the threaded callback function
# this will run in another thread when our event is detected
def my_callback(channel):
GPIO.output(27, GPIO.HIGH)
sleep(0.5)
GPIO.output(27, GPIO.LOW)
if config.Flag == 1:
config.Flag = 0
else:
config.Flag = 1
print(config.Flag)
print "Falling edge detected on port 17\n"

GPIO.add_event_detect(17, GPIO.FALLING, callback=my_callback, bouncetime=300)

try:
while(1):
if config.Flag == 1:
GPIO.output(24, GPIO.LOW)
GPIO.output(25, GPIO.HIGH)
sleep(0.5)
GPIO.output(24, GPIO.HIGH)
GPIO.output(25, GPIO.LOW)
sleep(0.5)

else:
GPIO.output(24, GPIO.LOW)
GPIO.output(25, GPIO.HIGH)
sleep(0.1)
GPIO.output(24, GPIO.HIGH)
GPIO.output(25, GPIO.LOW)
sleep(0.1)

except KeyboardInterrupt:
pass

GPIO.cleanup()
このプログラムのなかでGPIO17につないだボタンSWの割り込みの定義が
GPIO.add_event_detect(17, GPIO.FALLING, callback=my_callback, bouncetime=300)
でなされている。これに対応する割り込みのcallbackルーチンが
def my_callback(channel): に記載されている。このプログラムで2個のLEDの点滅スピードを制御しているのがグローバル変数config.Flagである。

7. グローバル変数
一つのプログラムのモジュール間で情報を共有する正準な方法は、特別なモジュール (しばしば config や cfg と呼ばれる) を作ることです。単に設定モジュールをアプリケーションのすべてのモジュールにインポートしてください。このモジュールはグローバルな名前として使えます。それぞれのモジュールのただ一つのインスタンスがあるので、設定モジュールオブジェクトに対するいかなる変更も全体に反映されます。例えば:

config.py:
x = 0   # Default value of the 'x' configuration setting
mod.py:
import config
config.x = 1
main.py:
import config
import mod
print(config.x)
という具合に3つのPythonファイルを作り、同じディレクトリに置くとよい。

8. 起動時に自動的に実行する
ラズベリーパイが起動したときに何かのプログラムを自動的に実行したいときは、/etc/rc.localファイルに記述する。エディタ nano(矢印キーでカーソル移動、保存はCtrl+O、終了はCtrl+Xだけ憶えておけば大丈夫)を使って、
$ sudo nano /etc/rc.local
exit 0の手前に実行したい処理を記述をする。下のrc.localファイルに自動起動したいPythonプログラム、
sudo python /home/pi/GPIO-interrupt_FlashingLED.py
が記述されている。X-windowがモニターに現れると同時に2個のLEDを点滅する前述のプログラムが走り出す。
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi

printf "Hello, My name is Kunio Takaya\n"
sudo python /home/pi/GPIO-interrupt_FlashingLED.py

exit 0

# by Prof_Multimedia | 2017-10-22 13:32 | テクノロジー

群ロボット 「ねずみ」- My swarm robot "MICE"

目次 Table of Contents

群ロボット Swarm Robot に興味を持って Arduino に足を踏み込んだのが4,5年前である。それ以来 Arduino をあれこれ試して、数ある Sensors の中から使えそうなものを選んで調べ、通信用の XBee を勉強しているうちに時間が経ってしまった。 大体、機が到来したの感じなので群ロボットになりうるロボットを作ってみた。「ねずみ」ロボットである。タミヤの楽しい工作シリーズ No.198 の壁ずたいメカ工作セット(ねずみ)を用いた。左右の車輪を独立して駆動でき、ゼンリンはボールベアリングのキャスターである。車体の上にスタイロフォーム板のプラットフォームを載せて Arduino FIO とモータードライバーとセンサーを置いた。
群ロボット 「ねずみ」- My swarm robot \"MICE\"_c0159967_14090409.jpg
群ロボットの目的
群ロボットに何をさせようかという目標が個々のロボットの仕様を決める。「ねずみ」ロボットの出来る運動は2つの車輪を使った2次元の移動であるから、出来ることにおのずと制約がある。その上で、どんな運動を想定するかでセンサーの種類とマイコンの性能が決まる。マスゲームのようなある秩序のあるグループとしての動き、鬼ごっこのような追跡をすること、相撲ロボットのような争い格闘のようなもの、集合と離反のような行動、通信を使ったチームどおしのゲームなど、単純なものから人工知能 AI の助けがいるものまで、群ロボットの目的が考えられる。
群ロボット 「ねずみ」- My swarm robot \"MICE\"_c0159967_14092751.jpg
センサーおよびハードウエア
まだ下等な初期段階であるから、障害物を検知するセンサーとして、正面には超音波の US-020 レンジセンサーを置き、側面には赤外線 IR のPSDセンサーGP2Y0A21YK Sharp を置いた。もう1個のPSDセンサーGP2Y0A21YK Sharp を後ろ向きに置き、そこからの光 (IR) を後続のロボットが検知して仲間だと判断できるようにした。障害物の検知はかなり出来るが、仲間の認識はごく低レベルの能力しかない。インパクト音のセンサーでその強度で相手の近さ具合を知る方法を考えているがまだ実装していない。ビーコンはシステムが複雑になるので対象外にした。
群ロボット 「ねずみ」- My swarm robot \"MICE\"_c0159967_14105807.jpg
マイコン(マイクロコントローラー)は小型であること XBee を装着できることから Arduino FIO を採用した。リチューム電池 3.3V をスタイロフォームのプラットフォームにサンドウィッチしてあるのでコンパクトなコントローラーである。モーターの電源には AA(単3)電池3本 4.5V を使用し「ねずみ」の胴体に入れた。超音波レンジセンサー、IRのセンサーが両方とも 5V を必要とするので、3.3V の FIO とともに使うには注意が必要である。XBee はスケッチのローディングの他、司令塔からの命令を受け取るブロードキャスト・モードの通信を想定している。このためには Series 1 の XBee がより使いやすい。
群ロボット 「ねずみ」- My swarm robot \"MICE\"_c0159967_14110622.jpg
モーターのドライバーとしてはPololu Dual Motor Driver DRV8835 Carrier (2-11V 1.2A)を採用した。小さいが1.2Aの電流容量がとれる小型モーター用の dual H-bridge motor driver である。DRV8835をディジタル・アウト D3, D11を PWM に、D12, D13 を方向指定に使うことで統一した。
群ロボット 「ねずみ」- My swarm robot \"MICE\"_c0159967_09064398.jpg
群ロボット「ねずみ」に搭載したセンサーは上から超音波の US-020 レンジセンサー、赤外線 IR のPSDセンサーGP2Y0A21YK Sharp 、前面に取り付け後部につけた PSDセンサーGP2Y0A21YK の IR 光を検知する Infrared Sensor Module (TCRT5000) with Adjustable Reference である。
群ロボット 「ねずみ」- My swarm robot \"MICE\"_c0159967_13564548.jpg
XBee Series 1 の準備
XBee S1 のセットはスケッチのローディングをするためにはC:\Users\....\Documents\Processing\libraries\FioXBeeConfigTool の中にある FioXBeeConfigTool.pde を用いるのが一番簡単である。ただしProcessing を実行できる環境が必要である。XBee Explorer に乗せる XBee S1 は programming radio と呼ばる。FIO に搭載する XBee S1 は remote Arduino Fio unit と呼ばれる。Programmer か FIO Radio を選択すると次のように設定される。
The program configures the following parameters of an XBee series 1 radio:
BD - 4 (Atmega168) or 6 (Atmega328) =57600
ID - 1234 or user's preference
MY - 0000 (programmer), 0000 (Fio) or user's preference
DL - FFFF(programmer), 0000 (Fio) or user's preference
D3 - 3 (programmer) or 5 (Fio)
IC - 8 (programmer) or not set (Fio)
RR - 3 (programmer) or not set (Fio)
IU - not set (programmer) or 0 (Fio)
IA - not set (programmer) or FFFF (Fio)
RO - 10 (both)
このようにしてセットされた XBee の Baud Rate をブロードキャストなどで使うもの、例えば 9600 に変えるには X-CTU を用いて Baud Rate の項目 BD を所定のものに変更すればよい。

プログラムするにはこのようにセットした XBee S1 を使ってもよいが、FTDI を持っていれば FIO のUART のピンから USB に直接つないでプログラムしてもよい。どちらでも同じくらいの時間でスケッチを書き込める。

初期テスト用のスケッチ
Robot Mouse としてずっと前に紹介した時に書いたテスト・プログラム、スケッチを5台の「ねずみ」ロボットの基本動作試験のために入れてある。これによって5台の「ねずみ」が同じふるまいをすることを確認した。前後運動を繰り返すだけの単純なプログラムである。

// DRV8835_test2mouse.ino 「ねずみ」ロボットテスト

int pwm_a = 3; //PWM control for motor outputs 1 and 2 is on digital pin 3
int pwm_b = 11; //PWM control for motor outputs 3 and 4 is on digital pin 11
int dir_a = 12; //direction control for motor outputs 1 and 2 is on digital pin 12
int dir_b = 13; //direction control for motor outputs 3 and 4 is on digital pin 13
int val = 0; //value for fade

void setup()
{
pinMode(pwm_a, OUTPUT); //Set control pins to be outputs
pinMode(pwm_b, OUTPUT);
pinMode(dir_a, OUTPUT);
pinMode(dir_b, OUTPUT);

analogWrite(pwm_a, 100); //set both motors to run at (100/255 = 39)% duty cycle (slow)
analogWrite(pwm_b, 100);

}

void loop()
{
forw(); //Set Motors to go forward Note : No pwm is defined with the for function, so that fade in and out works
// fadein(); //fade in from 0-255
// delay(1000);
forward(); //continue full speed forward
delay(1000);
// fadeout(); //Fade out from 255-0
// delay(1000); //Wait one second

stopped(); // stop for 2 seconds
delay(1000);


back(); //Set motors to revers. Note : No pwm is defined with the back function, so that fade in and out works
// fadein(); //fade in from 0-255
// delay(1000);
backward(); //full speed backward
delay(1000);
// fadeout(); //Fade out from 255-0
// delay(1000);

stopped(); // stop for 2 seconds
delay(1000);
}


/* Let's take a moment to talk about these functions. The forw and back functions are simply designating the direction the motors will turn once they are fed a PWM signal.
If you only call the forw, or back functions, you will not see the motors turn. On a similar note the fade in and out functions will only change PWM, so you need to consider
the direction you were last set to. In the code above, you might have noticed that I called forw and fade in the same grouping. You will want to call a new direction, and then
declare your pwm fade. There is also a stop function.
*/

void forw() // no pwm defined
{
digitalWrite(dir_a, HIGH); //Reverse motor direction, 1 high, 2 low
digitalWrite(dir_b, HIGH); //Reverse motor direction, 3 low, 4 high
}

void back() // no pwm defined
{
digitalWrite(dir_a, LOW); //Set motor direction, 1 low, 2 high
digitalWrite(dir_b, LOW); //Set motor direction, 3 high, 4 low
}

void forward() //full speed forward
{
digitalWrite(dir_a, HIGH); //Reverse motor direction, 1 high, 2 low
digitalWrite(dir_b, HIGH); //Reverse motor direction, 3 low, 4 high
analogWrite(pwm_a, 255); //set both motors to run at (100/255 = 39)% duty cycle
analogWrite(pwm_b, 255);
}

void backward() //full speed backward
{
digitalWrite(dir_a, LOW); //Set motor direction, 1 low, 2 high
digitalWrite(dir_b, LOW); //Set motor direction, 3 high, 4 low
analogWrite(pwm_a, 255); //set both motors to run at 100% duty cycle (fast)
analogWrite(pwm_b, 255);
}

void stopped() //stop
{
digitalWrite(dir_a, LOW); //Set motor direction, 1 low, 2 high
digitalWrite(dir_b, LOW); //Set motor direction, 3 high, 4 low
analogWrite(pwm_a, 0); //set both motors to run at 100% duty cycle (fast)
analogWrite(pwm_b, 0);
}

void fadein()
{
// fade in from min to max in increments of 5 points:
for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5)
{
// sets the value (range from 0 to 255):
analogWrite(pwm_a, fadeValue);
analogWrite(pwm_b, fadeValue);
// wait for 30 milliseconds to see the dimming effect
delay(30);
}
}

void fadeout()
{
// fade out from max to min in increments of 5 points:
for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5)
{
// sets the value (range from 0 to 255):
analogWrite(pwm_a, fadeValue);
analogWrite(pwm_b, fadeValue);
// wait for 30 milliseconds to see the dimming effect
delay(30);
}
}

void astop() //stop motor A
{
analogWrite(pwm_a, 0); //set both motors to run at 100% duty cycle (fast)
}

void bstop() //stop motor B
{
analogWrite(pwm_b, 0); //set both motors to run at 100% duty cycle (fast)
}

# by Prof_Multimedia | 2017-02-25 03:55