激安ラジコン(RC)の自動運転化計画※プログラムは6/25掲載予定
目的:総計1万円でラジコンの自動運転化をすること
使ったもの
ハード
システムの概要
今回は言語をpython限定にした.
画像転送部分
モータ制御部分
- L298nによりモータの制御を行う.サーバ(PC)側の分類結果からそれに対応する制御信号をMQTTにより受信し,モータの駆動させる. *プログラム
学習・検証部分
- KerasによりCNN部分の実装を行う. *プログラム
- 使用したCNNモデル:vgg16(転移学習)
結果・考察
全体として1万円以内に収めることができた. しかし、画像の転送部分での課題があり,Picamera及びffmpeg等でストリーミングを行うことで解決する予定である.
L298Nを使ってモータの制御
L298Nとは
2つのモータを独立して駆動でき、正転逆転制御などに最適です。
制御は各モーターに対して、イネーブル(回転する/しない)と回転方向の指定を2線でおこないます。
マイコンでの制御のほか、スイッチなどによってマニュアル制御も簡単におこなえます。
L298N使用 2Aデュアルモーターコントローラー: マイコン関連 秋月電子通商 電子部品 ネット通販
http://akizukidenshi.com/catalog/g/gM-06680/
Pin Description
ENA Motor A Speed Control
IN1 Motor A Direction Pin 1
IN2 Motor A Direction Pin 2
IN3 Motor B Direction Pin 1
IN4 Motor B Direction Pin 2
ENB Motor B Speed Control
Terminal Description
VMS 5-35V Input
GND 0V
5V 5V input/output
OUT1 Motor A
OUT2 Motor A
OUT3 Motor B
OUT4 Motor B
RaspiとPythonによるモータ制御
import RPi.GPIO as gpio import time def init(): gpio.setmode(gpio.BCM) gpio.setup(17, gpio.OUT) gpio.setup(22, gpio.OUT) gpio.setup(23, gpio.OUT) gpio.setup(24, gpio.OUT) def forward(tf): init() gpio.output(17, True) gpio.output(22, False) gpio.output(23, True) gpio.output(24, False) time.sleep(tf) gpio.cleanup() def reverse(tf): init() gpio.output(17, False) gpio.output(22, True) gpio.output(23, False) gpio.output(24, True) time.sleep(tf) gpio.cleanup() print "forward" forward(4) print "backward" reverse(2)
#!/usr/bin/python3.4 #MKerbachi November 6th, 2015 #Python code to control two motors with Rpi A+ with the H bridge l298n import RPi.GPIO as GPIO # always needed with RPi.GPIO import time import curses # get the curses screen window screen = curses.initscr() # turn off input echoing curses.noecho() # respond to keys immediately (don't wait for enter) curses.cbreak() # map arrow keys to special values screen.keypad(True) #If the two GND (PI + l298n) are not interconnected that won't work ! #For all Keyboard symbols: #https://docs.python.org/2/library/curses.html GPIO.setmode(GPIO.BCM) # choose BCM or BOARD numbering schemes. I use BCM ################################################################# # Variables # ################################################################# #For Motor #1 GPIO.setup(18, GPIO.OUT)# set GPIO 01 as an output Enabler GPIO.setup(24, GPIO.OUT)# set GPIO 05 as an output. GPIO.setup(23, GPIO.OUT)# set GPIO 04 as an output. p24 = GPIO.PWM(24, 100) p23 = GPIO.PWM(23, 100) p18 = GPIO.PWM(18, 100) # create an object p for PWM on port 18 at 50 Hertz # you can have more than one of these, but they need # different names for each port # e.g. p1, p2, motor, servo1 etc. #For Motor #2 GPIO.setup(13, GPIO.OUT)# set GPIO 03 as an output Enabler GPIO.setup(27, GPIO.OUT)# set GPIO 02 as an output. GPIO.setup(17, GPIO.OUT)# set GPIO 0 as an output. p27 = GPIO.PWM(27, 100) p17 = GPIO.PWM(17, 100) p13 = GPIO.PWM(13, 100) # create an object p for PWM on port 18 at 50 Hertz # you can have more than one of these, but they need # different names for each port # e.g. p1, p2, motor, servo1 etc. LastKey = "" ################################################################# # Functions # ################################################################# def Stop(): p18.start(0) p23.start(0) p24.start(0) p13.start(0) p27.start(0) p17.start(0) time.sleep(0.3) #GPIO.cleanup() print ("Stop executed") #exit() def Left(): if LastKey != 'left' : Stop() p18.start(60) p23.start(0) p24.start(100) time.sleep(0.4) p13.start(60) p27.start(0) p17.start(100) # time.sleep(0.3) #Stop() def Right(): if LastKey != 'right' : Stop() p18.start(60) p23.start(100) p24.start(0) time.sleep(0.4) p13.start(60) p27.start(100) p17.start(0) # time.sleep(0.3) #Stop() def Up(): #if LastKey != 'up' : Stop() p18.start(60) p23.start(100) p24.start(0) time.sleep(0.3) p13.start(60) p27.start(0) p17.start(100) time.sleep(0.3) #Stop() def Down(): #if LastKey != 'down' : Stop() p18.start(60) p23.start(0) p24.start(100) time.sleep(0.3) p13.start(60) p27.start(100) p17.start(0) time.sleep(0.3) #Stop() try: while True: char = screen.getch() print ('you entred') print (char) if char == ord('q'): break #elif char == curses.KEY_ENTER: elif char == ord(' '): # print doesn't work with curses, use addstr instead #screen.addstr(0, 0, 'right') if not ( LastKey == "enter" ) : print ('Last key was not Enter, it was %s \n' % LastKey) LastKey="enter" print ('enter\n') Stop() elif char == curses.KEY_RIGHT: # print doesn't work with curses, use addstr instead #screen.addstr(0, 0, 'right') if not ( LastKey == "right" ) : print ('Last key was not right, it was %s \n' % LastKey) LastKey="right" print ('right\n') Right() elif char == curses.KEY_LEFT: #screen.addstr(0, 0, 'left ') if not ( LastKey == "left" ) : print ('Last key was not left, it was %s \n' % LastKey) LastKey="left" print ('left\n') Left() elif char == curses.KEY_UP: #screen.addstr(0, 0, 'up ') if not ( LastKey == "up" ) : print ('Last key was not up, it was %s \n' % LastKey) LastKey="up" print ('up\n') Up() elif char == curses.KEY_DOWN: #screen.addstr(0, 0, 'down ') if not ( LastKey == "down" ) : print ('Last key was not down t was %s \n' % LastKey) LastKey="down" print ('down\n') Down() else: print ('Nothing Entred!\n') finally: # shut down cleanly print ('In the finally section now') curses.nocbreak(); screen.keypad(0); curses.echo() curses.endwin() p13.stop() # stop the PWM output p17.stop() p27.stop() p23.stop() # stop the PWM output p24.stop() p18.stop() GPIO.cleanup() # when your program exits, tidy up after yours p13.stop() # stop the PWM output p17.stop() p27.stop() p23.stop() # stop the PWM output p24.stop() p18.stop() GPIO.cleanup() # when your program exits, tidy up after yours
メモ
アナログ出力では周波数とデューティ比を指定して、モータ制御などに使うPWM制御ができます。
まずピンに対して周波数を設定してpwmオブジェクトを取得します。
pwm = GPIO.PWM([チャンネル], [周波数(Hz)]) 次にpwmオブジェクトに対してデューティ比を指定して出力を開始します。
pwm.start([デューティ比]) 例えば、ピン18に周波数1KHz、デューティ比50%でPWM出力する場合は以下のように書きます。
pwm = GPIO.PWM(18, 1000) pwm.start(50) 途中で周波数を変更する場合は以下の関数を使用します。
pwm.ChangeFrequency([周波数(Hz)]) 途中でデューティ比を変更する場合は以下の関数を使用します。
pwm.ChangeDutyCycle([デューティ比]) PWM出力を停止する場合は以下の関数を実行します。
pwm.stop() スクリプト終了時にはちゃんと停止しておきましょう。
Intersection-over-Union(IoU)とは
Intersection-over-Union(IoU)とは
物体認識の分野で領域の一致具合を評価する手法である.
predicted bound box とground truth boxを合わせた領域bが, 目的となる領域g(ground truth box)がどれだけ含まれているかとなる.
IoU(b,g)=area(b∩g)/area(b∪g)
request python まとめ
what is request
requestsとはサードパーティ製のhttp通信を行うためのライブラリ これを使用すると、webサイトのデータのダウンロードやrestapiの使用が可能 install cmd pip install requests
example
ヤフーのニュース一覧ページのhtmlを取得 import requests url = "https://news.yahoo.co.jp/topics" r = requests.get(url) print(r.text)
urlから画像ダウンロード
import urllib.error import urllib.request headers = { "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0", }
def download_image(url, dst_path, headers): try: # request = urllib.request.Request(url=url, headers=headers) # data = urllib.request.urlopen(request)
data = urllib.request.urlopen(url,headers).read()
with open(dst_path, mode="wb") as f:
f.write(data)
except urllib.error.URLError as e:
print(e)
url = 'URL' dst_path = 'lena_square.png'
dst_dir = 'data/src'
dst_path = os.path.join(dst_dir, os.path.basename(url))
download_image(url, dst_path, headers)
urlからhtmlコンテンツダウンロード
coding:utf-8
import urllib.request
url = "URL" headers = { "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0", }
request = urllib.request.Request(url=url, headers=headers) response = urllib.request.urlopen(request) html = response.read().decode('utf-8') print(html)
参考
http://www.python.ambitious-engineer.com/archives/974#requests
imgaugライブラリを使った機械学習用のdata augmentation
install
通常版
sudo pip install imgaug
最新版
pip install git+https://github.com/aleju/imgaug
必要なもの
- six
- numpy
- scipy
- scikit-image (pip install -U scikit-image)
- OpenCV (i.e. cv2)
使い方
すべてのDA手法をお試しするならgenerate_example_images.pyを実行すればよし
DAの種類
kerasで実装できないものをまとめてみました。
ペッパー
ガウシアンノイズ
ソルト
ペッパー
ソルト&ペッパー
piece wise affine(区分積分アフィン?)
透視変換(perspective transform)
crop(トリミング)
平滑化フィルタ
median blur
gaussian blur
bilateral blur
averageblur
coarseシリーズ
coarse ソルト
coarse ペッパー
coarse Dropout
coarse ソルト&ペッパー
contrast normalization
frequency noisealpha
multiply (ピクセル演算)
参考
keras 学習済モデルの取り扱い全般まとめ
keras公式の学習済モデル読み込み方法
from keras.applications.inception_v3 import InceptionV3 InceptionV3 = InceptionV3(include_top=False, weights='imagenet', input_tensor=input_tensor)
kerasで利用可能なモデル
ImageNetで学習した重みをもつ画像分類のモデル:
- Xception
- VGG16
- VGG19
- ResNet50
- InceptionV3
- InceptionResNetV2
- MobileNet
- NASNet
参照 https://keras.io/ja/applications/
学習済モデルを利用した学習方法
- 重み読み込み版(finetuning) weights='imagenet'を指定
from keras.applications.inception_v3 import InceptionV3 InceptionV3 = InceptionV3(include_top=False, weights='imagenet', input_tensor=input_tensor)
- 重み読み込みなし版 weights='None'を指定
from keras.applications.inception_v3 import InceptionV3 InceptionV3 = InceptionV3(include_top=False, weights='None', input_tensor=input_tensor)
- オリジナルの学習済モデルの場合(finetuning)
model.load_weights("./weight.19-0.70.hdf5", by_name=True)
model.load_weights(filepath, by_name=False): (save_weightsによって作られた) モデルの重みをHDF5形式のファイルから読み込む
デフォルトはモデルの構造は不変であることが前提
(いくつかのレイヤーが共通した)異なる構造に対して重みを読み込む場合,by_name=Trueを使うことで,同名のレイヤーにのみ読み込み可能
学習モデルの保存方法
model.save_weights(os.path.join('PATH', 'InceptionV3_scratch2.h5'))
ModelCheckpointを使った各エポック終了後にモデルの保存のしかた
keras.callbacks.ModelCheckpoint(filepath, monitor='val_loss', verbose=0, save_best_only=False, save_weights_only=False, mode='auto', period=1)
引数
- filepath: モデルファイルを保存するパス.
- monitor: 監視する値.
- verbose: 冗長モード, 0 または 1.
- save_best_only: save_best_only=Trueの場合,監視しているデータによって最新の最良モデルが上書きされない.
- mode: {auto, min, max}の内の一つが選択されます.save_best_only=Trueならば,現在保存されているファイルを上書きするかは,監視されている値の最大化か最小化によって決定.
val_accの場合,この引数はmax
val_lossの場合はmin
autoモードでは,この傾向は自動的に監視されている値から推定します. * save_weights_only: Trueなら,モデルの重みが保存されます (model.save_weights(filepath)),そうでないなら,モデルの全体が保存されます (model.save(filepath)). * period: チェックポイント間の間隔(エポック数).
参考にしたもの
https://employment.en-japan.com/engineerhub/entry/2017/04/28/110000
ubuntu16.04でのTensorFlow環境構築でのメモ
TensorFlowのインストール
「libcupti-dev」を入れます。
sudo apt-get install libcupti-dev 「これはNVIDIA CUDAプロファイルツールインタフェースです。このライブラリは高度なプロファイリングのサポートを提供します。」だそうです。(TensorFlowより)
次にvirtualenvを入れます。これは入れといたほうがいいです(condaがあるならそれでいいですけど)。TensorFlowはバージョンアップするごとに仕様が少し変わるので、違うバージョンを試してみたいということは多々起こります。
一行目が2系用、二行目が3系用です。Pythonのバージョンに合わせて実行。
sudo apt-get install python-pip python-dev python-virtualenv sudo apt-get install python3-pip python3-dev python-virtualenv
インストール後は以下。こちらも一行目が2系、二行目が3系。
virtualenv --system-site-packages ~/tensorflow virtualenv --system-site-packages -p python3 ~/tensorflow
「~/tensorflow」のとこは別に自分の好きなディレクトリ名で結構ですが、まあ、これから変更する理由は特に無いと思います。
次に環境をアクティベートします。
source ~/tensorflow/bin/activate # bash, sh, ksh, or zsh source ~/tensorflow/bin/activate.csh # csh or tcsh
使っているターミナルに合わせて選んでください。ubuntuの入れたばかりならbashです。アクティベートされたらいよいよTensorFlowをインストール。
(tensorflow)$ pip install --upgrade tensorflow # for Python 2.7 (tensorflow)$ pip3 install --upgrade tensorflow # for Python 3.n (tensorflow)$ pip install --upgrade tensorflow-gpu # for Python 2.7 and GPU (tensorflow)$ pip3 install --upgrade tensorflow-gpu # for Python 3.n and GPU
TensorFlowが利用できるか確認 TensorFlowを利用するときはアクティベートが必要です。
以下のコマンドでできます。
source ~/tensorflow/bin/activate # bash, sh, ksh, or zsh source ~/tensorflow/bin/activate.csh # csh or tcsh
逆に終了する場合は
deactivate