วันจันทร์ที่ 17 กันยายน พ.ศ. 2561

โปรเจค หุ่นยนต์อ่านตัวเลข TensorFlow + Keras



โปรเจคหุ่นยนต์อ่านตัวเลข TensorFlow + Keras โปรเจคนี้จะใช้ การสร้างโครงข่ายประสาทเทียม CNN ด้วย Keras ในการอ่านค่าตัวเลขในกระดาษ และแยกแยะตัวเลขว่าเป็นเลขอะไร เมื่ออ่านค่าได้แล้ว จึงไปสั่งควบคุมหุ่นยนต์ โดย 2 ให้เดินหน้า ,  3 ให้ถอยหลัง , 4 ให้เลี้ยวซ้าย ,  5 ให้เลี้ยวขวา และ 8 ให้หยุด



อุปกรณ์ที่ใช้











ขั้นตอนการทำงาน


1.
 การติดตั้ง Linux ให้กับ Raspberry โดยใช้ไฟล์ image


2. การใช้งาน GPIO ใน Raspberry Pi ด้วย Python



3. การประกอบหุ่นยนต์ Raspberry Pi


4. วิธีเปิดใช้งาน Remote Desktop ไปยัง Raspberry Pi


5. ทดสอบการเคลื่อนที่ของหุ่นยนต์ Raspberry Pi



10.1 สร้างไฟล์ build_model.py

เป็นการสร้างโครงข่ายประสาทเทียมขนาดใหญ่สำหรับ MNIST

โดยมีขั้นตอนดังนี้
เปิดโปรแกรม เทอมินอล (Root Terminal)

สร้างโฟลเดอร์ number_robot โดยใช้คำสั่ง


mkdir number_robot


เปิดโปรแกรม Python 3 (IDLE) เขียนโค้ดดังนี้


# Larger CNN for the MNIST Dataset
import numpy
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Flatten
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.utils import np_utils
from keras import backend as K
K.set_image_dim_ordering('th')

# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)

# load data
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# reshape to be [samples][pixels][width][height]
X_train = X_train.reshape(X_train.shape[0], 1, 28, 28).astype('float32')
X_test = X_test.reshape(X_test.shape[0], 1, 28, 28).astype('float32')
# normalize inputs from 0-255 to 0-1
X_train = X_train / 255
X_test = X_test / 255
# one hot encode outputs
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
num_classes = y_test.shape[1]

# define the larger model
def larger_model():
# create model
model = Sequential()
model.add(Conv2D(30, (5, 5), input_shape=(1, 28, 28), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(15, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(50, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
# Compile model
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
return model


# build the model
model = larger_model()

# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=20, batch_size=200)

# Save entire model to a HDF5 file
model.save('my_model.h5')
print ("Finished")




หรือดาวน์โหลดโค้ดจากลิงค์ด้านล่าง


https://drive.google.com/open?id=1h1I8IXJAN64-OihiThKmMXjah5THVcMa


Save ไปที่ โฟลเดอร์ number_robot และตั้งชื่อเป็น build_model.py


ทดสอบการทำงาน Run Module




ตัวอย่างเช่นความแม่นยำในการฝึกอบรมและการทดสอบการตรวจสอบจะถูกพิมพ์ในแต่ละรอบและเมื่อสิ้นสุด เพื่อความแม่นยำ จึงใช้ epochs 20 รอบ  จึงใช้เวลานานประมาณ 6-7 ชั่วโมง ในการทำงานและรอจนขึ้นคำว่า Finished



และ จะเซฟไฟล์ HDF5 ชื่อ my_model.h5 เพิ่มเข้ามาในโฟลเดอร์ number_robot ซึ่งเราจะใช้ไฟล์นี้ในการทำงานในขั้นตอนต่อไป


ไฟล์ HDF5 คือ

HDF เป็นไฟล์รูปแบบข้อมูลลำดับชั้นไฟล์โดยที่พวกเขาเป็นรูปแบบแฟ้มมาตรฐานสำหรับการจัดเก็บข้อมูลทางวิทยาศาสตร์ ไฟล์เหล่านี้มีการแบ่งประเภท ส่วนใหญ่ที่ใช้ในการทดสอบ การใช้งานการบินและอวกาศวิทยาศาสตร์สิ่งแวดล้อม ไฟล์ HDF สามารถจัดการมองวิเคราะห์มองเห็นเช่นเดียวกับการแปลงเป็นข้อมูลทางวิทยาศาสตร์ที่มีความสัมพันธ์ระหว่างข้อมูลที่ซับซ้อนและยังมีรูปแบบที่มีความยืดหยุ่นมาก


10.2 แก้ไขไฟล์ 
/etc/default/motion

ถ้าเคยทำ "การติดตั้ง Motion และ ดูภาพกล้องผ่านทางหน้าเว็บเพจ" มาก่อน เพราะจะมีการแก้ค่าจาก no เป็น yes เอาไว้ (ถ้าไม่เคยทำก็ไม่ต้องแก้ไข) โดยแก้ไขให้กลับมาเป็น 
start_motion_daemon=no เหมือนเดิม

เปิดไฟล์ /etc/default/motion มาแก้ไข โดยใช้คำสั่ง


sudo nano /etc/default/motion



ค่าเดิม start_motion_daemon=yes แก้เป็น start_motion_daemon=no


จากนั้นบันทึก Ctrl + O แล้วตามด้วย Enter เพื่อบันทึกข้อมูลใหม่ แล้ว 
กด Ctrl + X เพื่อออกจากโปรแกรม
-เมื่อทำการอัพเดตเรียบร้อยต้องทำการรีบูทเครื่องใหม่


sudo reboot




10.3 ทดสอบการอ่านค่าตัวเลขของหุ่นยนต์ 


เสียบสาย USB ของ Power Bank ต่อเข้ากับ 5V  Micro USB ของบอร์ด Raspberry Pi

ให้ภาพตัวเลขอยูห่างจากหุ่นยนต์ประมาณ 12 -13 เซนติเมตร




ความสูงของตัวเลขห่างจากพื้นประมาณ 1.5 -2 เซนติเมตร




สร้างไฟล์ test_model.py
 เพื่อทดสอบการอ่านค่าตัวเลขของหุ่นยนต์


เปิดโปรแกรม Python 3 (IDLE) เขียนโค้ดดังนี้




from time import sleep
from picamera import PiCamera

camera = PiCamera()
camera.resolution = (800, 800)
camera.start_preview()

sleep(2)
camera.capture('/home/pi/number_robot/image.jpg')

from skimage.io import imread
import numpy as np


im = imread("image.jpg")

from skimage.transform import resize
# resize to 28 x 28
im_resize = resize(im,(28,28), mode='constant')
from skimage.color import rgb2gray
# turn the image from color to gray
im_gray = rgb2gray(im_resize)
# the color of the original set are inverted,so we invert it here
im_gray_invert = 255 - im_gray*255
#treat color under threshold as black
im_gray_invert[im_gray_invert<=90] = 0

from keras.models import load_model

model=load_model('my_model.h5')
im_final = im_gray_invert.reshape(1,1,28,28)

# the below output is a array of possibility of respective digit
ans = model.predict(im_final)
print(ans)

ans = ans[0].tolist().index(max(ans[0].tolist()))
print("the predicted digit is",ans)




หรือดาวน์โหลดโค้ดจากลิงค์ด้านล่าง



Save ไปที่ โฟลเดอร์ number_robot และตั้งชื่อเป็น  test_model.py


ทดสอบการทำงาน Run Module


เริ่มที่ภาพตัวเลข 2 -> Run Module , ภาพตัวเลข 3 -> Run Module , ภาพตัวเลข 4 -> Run Module ,  ภาพตัวเลข 5 -> Run Module

จะแสดงค่าตัวเลขที่อ่านได้ ถ้าอ่านได้ตามภาพที่ให้ถ่าย แสดงว่า หุ่นยนต์สามารถอ่านค่าได้ถูกต้องแล้ว รอทำในขั้นตอนต่อไป



เมื่อเข้าไปตรวจสอบที่ File Manager  ในโฟลเดอร์ number_robot จะพบไฟล์  image.jpg เพิ่มเข้ามา

สามารถดูภาพที่ถ่าย โดยให้คลิกขวาที่ไฟล์  image.jpg เลือก Chromium Web Browser



จะแสดงภาพที่หุ่นยนต์ถ่ายไว้



10.4 ทดสอบการทำงาน 



สร้างไฟล์ robot_number.py โดย

เปิดโปรแกรม Python 3 (IDLE) เขียนโค้ดดังนี้




import RPi.GPIO as GPIO

#set GPIO numbering mode and define output pins
GPIO.setmode(GPIO.BOARD)
GPIO.setup(11,GPIO.OUT)
GPIO.setup(13,GPIO.OUT)
GPIO.setup(35,GPIO.OUT)
GPIO.setup(37,GPIO.OUT)

from time import sleep
from picamera import PiCamera

camera = PiCamera()
camera.resolution = (800, 800)
camera.start_preview()

sleep(2)
camera.capture('/home/pi/number_robot/image.jpg')

from skimage.io import imread
import numpy as np


im = imread("image.jpg")

from skimage.transform import resize
# resize to 28 x 28
im_resize = resize(im,(28,28), mode='constant')
from skimage.color import rgb2gray
# turn the image from color to gray
im_gray = rgb2gray(im_resize)
# the color of the original set are inverted,so we invert it here
im_gray_invert = 255 - im_gray*255
#treat color under threshold as black
im_gray_invert[im_gray_invert<=90] = 0

from keras.models import load_model

model=load_model('my_model.h5')
im_final = im_gray_invert.reshape(1,1,28,28)

# the below output is a array of possibility of respective digit
ans = model.predict(im_final)
print(ans)

ans = ans[0].tolist().index(max(ans[0].tolist()))
print("the predicted digit is",ans)

if ans == 8:
    GPIO.output(11,False)
    GPIO.output(13,False)
    GPIO.output(35,False)
    GPIO.output(37,False)
elif ans == 2:
    GPIO.output(11,True)
    GPIO.output(13,False)
    GPIO.output(35,True)
    GPIO.output(37,False)
    sleep(0.3)
    GPIO.output(11,False)
    GPIO.output(13,False)
    GPIO.output(35,False)
    GPIO.output(37,False)
elif ans == 3:
    GPIO.output(11,False)
    GPIO.output(13,True)
    GPIO.output(35,False)
    GPIO.output(37,True)
    sleep(0.4)
    GPIO.output(11,False)
    GPIO.output(13,False)
    GPIO.output(35,False)
    GPIO.output(37,False)
elif ans == 4:
    GPIO.output(11,True)
    GPIO.output(13,False)
    GPIO.output(35,False)
    GPIO.output(37,False)
    sleep(0.4)
    GPIO.output(11,False)
    GPIO.output(13,False)
    GPIO.output(35,False)
    GPIO.output(37,False)
elif ans == 5:
    GPIO.output(11,False)
    GPIO.output(13,False)
    GPIO.output(35,True)
    GPIO.output(37,False)
    sleep(0.4)
    GPIO.output(11,False)
    GPIO.output(13,False)
    GPIO.output(35,False)
    GPIO.output(37,False)
else:
    GPIO.output(11,False)
    GPIO.output(13,False)
    GPIO.output(35,False)
    GPIO.output(37,False)            

GPIO.cleanup()



หรือดาวน์โหลดโค้ดจากลิงค์ด้านล่าง



https://drive.google.com/open?id=1IgsAd5Utat5Nhptxw4qU2C67Hg9I0r4s



Save ไปที่ โฟลเดอร์ number_robot และตั้งชื่อเป็น  robot_number.py


เสียบสาย USB ของ Power Bank ต่อเข้ากับ 5V  Micro USB ของบอร์ด Raspberry Pi

เปิด เพาเวอร์สวิตซ์ จะมีไฟสีแดงติดที่ Motor Driver

ให้ภาพตัวเลขอยูห่างจากหุ่นยนต์ประมาณ 12 -13 เซนติเมตร


ความสูงของตัวเลขห่างจากพื้นประมาณ 1.5 -2 เซนติเมตร

ทดสอบการทำงาน Run Module

เริ่มที่ภาพตัวเลข 2 -> Run Module , ภาพตัวเลข 3 -> Run Module , ภาพตัวเลข 4 -> Run Module ,  ภาพตัวเลข 5 -> Run Module


วีดีโอผลลัพธ์การทำงานของ โปรเจคหุ่นยนต์อ่านตัวเลข TensorFlow + Keras



.....

ไม่มีความคิดเห็น:

แสดงความคิดเห็น