調べているうちにわかったことだが Raspberry Pi を使って IoT (internet of things) いわゆる物をインターネットを介して制御するには WebIOPi が定番になっている事だった。WebIOPi はスマホやコンピュータのブラウザーとラズパイの GPIO の間を取り持つシステムで、スマホが見ている index.html スクリプトが例えば LED を点けるとか消すとかの指令を受け取り、Python で書かれたスクリプトに従って GPIO を操作する。従ってラズパイに WebIOPi をインストール必要がある。そして WebIOPi を次のように起動させてやる。 sudo webiopi -d -c /etc/webiopi/config
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/WebIOpi をスタート、ストップするには、
sudo wget https://raw.githubusercontent.com/doublebind/raspi/master/webiopi.service
cd ~
sudo systemctl start webiopi
sudo systemctl stop webiopi
http://172.16.1.92:8000/ をブラウザーに指定すると次の画面が現れる。
home
- pi
- myproject
- python
- html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">一方、script.py は次のようになっている。操作はGPIO-17 につないだ LED を ON/OFF することであるから、前にGPIO-17 にセットした RGB LED がそのまま使える。
<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>
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行を書き込む。
...config ファイルの中で [HTTP] を見つけ次の1行を書き込む。
[SCRIPTS]
myproject = /home/pi/myproject/python/script.py
...
...config ファイルの中で [REST] を見つけ次の3行を書き込む。
[HTTP]
doc-root = /home/pi/myproject/html
...
...これだけの準備が出来たら WebIOPi を起動する。
[REST]
gpio-export = 17
gpio-post-value = true
gpio-post-function = false
...
cd ~
sudo systemctl start webiopi
としてプログラムを起動してやって、WiFi の傘下にあるパソコンあるいはスマホで Raspberry Pi の IP アドレスを使って、私の場合 http://172.16.1.92:8000/ をブラウザーに打ち込んでやると次の画面が現れる。LIGHT のところをタッチしてやると背景の色が黒から青に変わり、青色の LED が点滅する。これでチュートリアルの Lチカが実現できたことになる。
目指すは遠隔操作のできるRaspberry Pi で作るラジコン戦車である。自動操縦でなく台車に装着したビデオカメラで映像を見ながら運転することである。 Arduino では難しかったビデオカメラを簡単に使えるのはさすがRaspberry Piである。SainSmart Camera Module Board 5MP Webcam Video 1080p 720p for Raspberry Pi CD$ 25.99 を買いました。
$ sudo raspi-configを起動してカメラを有効にして
$ vcgencmd get_cameraによって有効になったことを確認する。カメラが動作しているかどうかを静止画像と動画で次のコマンドを用いて確認した。
$ raspistill -o raspi-camera-1.jpgビデオ・ストリーマーを行うのには「Raspberry Pi 3 の標準カメラで撮影した動画をブラウザに配信する方法まとめ」https://qiita.com/okaxaki/items/72226a0b0f5fab0ec9e9 を参照した。プログラムのインストールから実行までは次のコマンドを使った。
$ raspivid -o raspi-video-1.h264 -t 5000
$ omxplayer ./Videos/raspi-video-1.h264
$ uname -aこれでビデオ・ストリーマーはインターネットにビデオ配信を始めるから、同じ WiFi ネットワークにある PC やスマートホーンのブラウザーを通してみることができる。これに先立って、Raspberry Pi の IP アドレスを調べておく必要がある。次のコマンドで調べる。
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"
$ ip addr showブラウザーの URL は
$ /sbin/ifconfig
http://[ラズパイのIP]:8080/である。同じ WiFi ネットワークにある Windows コンピュータで受信したビデオ・ストリーマーからくるページは次の写真である。
もう一つの問題もハードウエアがらみのものである。ラズパイそのものの問題かもしれない。 前回、ボタン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ピンのパッケジに変えてみた。アナログとディジタルのグラウンドがアイソレートされているのを期待したが結果的には何ら変わらなかった。
#!/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)
5月に日本に行ったとき目についた本「ラズパイとスマホでラジコン戦車を作ろう!」を買いおまけにキット1式も買った。親子で電子工作とか書いてあるのですぐ作りすぐ動かせると思った。私には難しすぎた。親はラズパイのプロでないと分からない。子供は一度開いて見るだけで終わるだろう。何を作ってどう動かすのかと云う全体像がどこまでページをめくっても出てこない。ラズパイのGPIOを使ってLチカは成功させただけの新米には歯が立たない。しばらく放っておいたが、ラズパイもハードウエアも1式そろっているので、もったいないから私なりに1歩1歩分からないことを調べてラジコン戦車を作ってみることにした。
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番号を使うことを意味する。
この戦車ロボットではタミヤのツインモーターを使う。モーターのコントロールは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)になります。
6. ボタンSWによる割込み
Raspberry Pi でGPIOを使った戦車ロボットのプログラムを実行しているときに、ローカルに戦車ロボットにスタート/ストップなどの指令を与えるのにボタンSWなどを使いたくなる。ボタンSWを押すことでプログラムの流れを変えることをLチカのプログラムに対して行ってみた。2個のLEDを交互に点滅するプログラムの点滅の早さをボタンSWを押すことで変えてみた。
#!/usr/bin/env python2.7このプログラムのなかでGPIO17につないだボタンSWの割り込みの定義が
# 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()
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 settingmod.py:
import configmain.py:
config.x = 1
import configという具合に3つのPythonファイルを作り、同じディレクトリに置くとよい。
import mod
print(config.x)
8. 起動時に自動的に実行する
ラズベリーパイが起動したときに何かのプログラムを自動的に実行したいときは、/etc/rc.localファイルに記述する。エディタ nano(矢印キーでカーソル移動、保存はCtrl+O、終了はCtrl+Xだけ憶えておけば大丈夫)を使って、
$ sudo nano /etc/rc.localexit 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
群ロボットに何をさせようかという目標が個々のロボットの仕様を決める。「ねずみ」ロボットの出来る運動は2つの車輪を使った2次元の移動であるから、出来ることにおのずと制約がある。その上で、どんな運動を想定するかでセンサーの種類とマイコンの性能が決まる。マスゲームのようなある秩序のあるグループとしての動き、鬼ごっこのような追跡をすること、相撲ロボットのような争い格闘のようなもの、集合と離反のような行動、通信を使ったチームどおしのゲームなど、単純なものから人工知能 AI の助けがいるものまで、群ロボットの目的が考えられる。
まだ下等な初期段階であるから、障害物を検知するセンサーとして、正面には超音波の US-020 レンジセンサーを置き、側面には赤外線 IR のPSDセンサーGP2Y0A21YK Sharp を置いた。もう1個のPSDセンサーGP2Y0A21YK Sharp を後ろ向きに置き、そこからの光 (IR) を後続のロボットが検知して仲間だと判断できるようにした。障害物の検知はかなり出来るが、仲間の認識はごく低レベルの能力しかない。インパクト音のセンサーでその強度で相手の近さ具合を知る方法を考えているがまだ実装していない。ビーコンはシステムが複雑になるので対象外にした。
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 に直接つないでプログラムしてもよい。どちらでも同じくらいの時間でスケッチを書き込める。
初期テスト用のスケッチ
// 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)
}