[PYTHON] Obstacle (black) I made an automatic avoidance caterpillar.

What I made

A caterpillar that uses a Raspberry Pi 3b + and a Pi camera to classify photos taken with SVM into real-time "forward", "right turn", "left turn", and "backward". IMG_1029.JPG

Please see here because a picture is worth a thousand words. YouTube: Obstacle Avoidance Caterpillar Test Run Using Raspberry Pi

Reference books

[Color illustration Learn electronic work with the latest Raspberry Pi Make and move to understand how it works (Blue Bucks)](https://www.amazon.co.jp/%E3%82%AB%E3%83%A9%E3% 83% BC% E5% 9B% B3% E8% A7% A3-Raspberry-Pi% E3% 81% A7% E5% AD% A6% E3% 81% B6% E9% 9B% BB% E5% AD% 90% E5% B7% A5% E4% BD% 9C-% E4% BD% 9C% E3% 81% A3% E3% 81% A6% E5% 8B% 95% E3% 81% 8B% E3% 81% 97% E3 % 81% A6% E3% 81% 97% E3% 81% 8F% E3% 81% BF% E3% 81% 8C% E3% 82% 8F% E3% 81% 8B% E3% 82% 8B-% E3% 83% 96% E3% 83% AB% E3% 83% BC% E3% 83% 90% E3% 83% 83% E3% 82% AF% E3% 82% B9 / dp / 4062579774 / ref = sr_1_3? __mk_ja_JP = % E3% 82% AB% E3% 82% BF% E3% 82% AB% E3% 83% 8A & keywords =% E3% 83% A9% E3% 82% BA% E3% 83% 99% E3% 83% AA% E3% 83% BC% E3% 83% 91% E3% 82% A4% E3% 81% A7% E5% AD% A6% E3% 81% B6% E9% 9B% BB% E5% AD% 90% E5% B7% A5% E4% BD% 9C & qid = 1561894984 & s = hobby & sr = 1-3-catcorr)

For hardware, see Chapter 10 + Just attach the Pi camera. For software, refer to Chapter 8 + Preprocessing + svm (Scikit-learn) + Image saving for re-learning

Ingenuity

Hard: The camera only shoots in front of me. If the background is reflected, it seems that it can not be classified, so enter the image only in front of the caterpillar.

Software ①: Input to svm is 28x28 pixels / photo (grayscale) The Pixel camera shot was reduced to 64x64 pixels (color) and preprocessed to 28x28 pixels (grayscale). If the preprocessing takes time, there will be a time lag in the transmission to the motor. At this resolution, I didn't really notice the delay. By the way, the 64x64 (color) image looks like this 1291.jpg

28x28 (grayscale) 1292_1_93784.jpg

Software ②: I made a mode to run while collecting data for re-learning If SavePics is set to 1, the captured image is saved for re-learning while proceeding. The saved image moves forward while labeling the file name as to which of "forward", "right turn", "left turn", and "backward" was judged. After driving, people can easily relearn images with the wrong label by dividing them into folders and moving camera_car_preprocess.py. It takes about 3 minutes for pre-processing with about 200 sheets x 4 classification, and learning is completed in an instant, so it is easy to make adjustments locally.

Soft ③: Turn right when retreating If you go straight back, you will enter an infinite loop, so I try to turn to the right.

circuit diagram

IMG_1030.JPG

code

camera_car_preprocess.py


from PIL import Image
import numpy as np
import glob
from sklearn import svm, metrics
from sklearn.model_selection import train_test_split
import pickle

ModelName = "model_20191102_9.pickle"#As you wish.

def main():
    Path = '/home/pi/document/camera_car/Train/'
    Left_L = glob.glob(Path + '1_Left/*.jpg')
    Right_L = glob.glob(Path + '2_Right/*.jpg')
    Center_L = glob.glob(Path + '0_Center/*.jpg')
    Back_L = glob.glob(Path + '3_Back/*.jpg')
    X_L = Preprocess(Left_L)
    Y_L = np.ones(int(len(X_L)/784))
    X_R = Preprocess(Right_L)
    Y_R = np.full(int(len(X_R)/784),2)
    X_C = Preprocess(Center_L)
    Y_C = np.zeros(int(len(X_C)/784))
    X_B = Preprocess(Back_L)
    Y_B = np.full(int(len(X_B)/784),3)
    
    X = np.r_[X_L, X_R, X_C, X_B]#concatinate all preprocessed pics.All pre-processed photo combination
    X = X.reshape([int(len(X)/784),784])#make array.Matrix
    y = np.r_[Y_L, Y_R, Y_C, Y_B]#teacher data addition.Teacher data addition
    print(X.shape)
    print(y.shape)
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=42)

    clf = svm.SVC(kernel='linear')
    clf.fit(X_train, y_train)
    pre = clf.predict(X_test)    
    ac_score = metrics.accuracy_score(y_test, pre)
    print(ac_score)#print score.Accuracy display

    with open(ModelName, mode='wb') as fp:
        pickle.dump(clf, fp)#save model.Model output


def Preprocess(files):
    size = [28,28]
    array = np.empty([size[0]*size[1],0],int)
    print(array.shape)
    print(files)
    for i, file in enumerate(files):
        img = Image.open(file).convert('L')
        img = img.resize(size, Image.ANTIALIAS)
        print(img.format, img.size, img.mode,img.getextrema())
        img_arr = np.asarray(img)
        print("OD"+str(img_arr.ravel().shape))
        array = np.append(array,img_arr.ravel())
        print(array.shape)
    return array

if __name__ == '__main__':
    main()

camera_car_main.py


# -*- coding: utf-8 -*-
from picamera import PiCamera
import RPi.GPIO as GPIO
from time import sleep
from PIL import Image
import numpy as np
import os
import glob
import pickle
import shutil
import random

def Preprocess(i,SaveP):
    size = [28,28]
    array = np.empty([size[0]*size[1],0],int)
    print(array.shape)
    FullPath = glob.glob('/home/pi/document/camera_car/Predict/*.jpg')
    print(FullPath)
    #Preprocessing
    img = Image.open(FullPath[0]).convert('L')
    img = img.resize(size, Image.ANTIALIAS)
    print(img.format, img.size, img.mode,img.getextrema())
    #Make one dimention array
    img_arr = np.asarray(img)
    print("OneDimention"+str(img_arr.ravel().shape))
    if SaveP:
        os.remove(FullPath[0])
    else:#saving pics for re-training the model.Photo save for Dewa
        shutil.move(FullPath[0],'/home/pi/document/camera_car/Predict/done/%s.jpg' % i)
    return img_arr.ravel(), img


PickleName = "model_20191102_9.pickle"#indicate trained model(pickle)
SavePics = 0
with open(PickleName, mode='rb') as fp:
    clf = pickle.load(fp)

camera = PiCamera()
#camera.rotation = 180#if camera is upside down If the camera is upside down
camera.resolution = (64,64)

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

p0 = GPIO.PWM(25, 50)#RH
p1 = GPIO.PWM(24, 50)#RH
p2 = GPIO.PWM(23, 50)#LH
p3 = GPIO.PWM(22, 50)#LH

p0.start(0)
p1.start(0)
p2.start(0)
p3.start(0)
print("start moving...")
sleep(10)
i = 0
duty = 70


#At first go forward
p0.ChangeDutyCycle(20)
p1.ChangeDutyCycle(0)
p2.ChangeDutyCycle(20)
p3.ChangeDutyCycle(0)
try:
    while True:
        #Take a pic and save to indicated folder.Take a photo and save it in the specified folder
        i += 1
        camera.capture('/home/pi/document/camera_car/Predict/%s.jpg' % i)
        #preprocessing at indicated folder.Preprocess photos in a specified folder
        X_pred, img = Preprocess(i, SavePics)
        #predict estimate
        pred = clf.predict(X_pred)
        #change duty ratio.Duty ratio change
        if pred[0] == 0:#Advance
            print("Forward")
            p0.ChangeDutyCycle(duty)
            p1.ChangeDutyCycle(0)
            p2.ChangeDutyCycle(duty)
            p3.ChangeDutyCycle(0)
            sleep(0.8)
        elif pred[0] == 1:#left turn left
            print("Left")
            p0.ChangeDutyCycle(duty-20)
            p1.ChangeDutyCycle(0)
            p2.ChangeDutyCycle(0)
            p3.ChangeDutyCycle(20)
            sleep(0.3)
        elif pred[0] == 2:#right turn right
            print("Right")
            p0.ChangeDutyCycle(0)
            p1.ChangeDutyCycle(20)
            p2.ChangeDutyCycle(duty-20)
            p3.ChangeDutyCycle(0)
            sleep(0.3)
        elif pred[0]  == 3:#backward backward
            p0.ChangeDutyCycle(0)
            p1.ChangeDutyCycle(duty-10)
            p2.ChangeDutyCycle(0)
            p3.ChangeDutyCycle(duty-40)
            print("Backing...")
            sleep(1)
            print("finish backing")
        #save preprocessed pic Save preprocessed photo
        if SavePics:
            pass
        else:#collect preprocessed pics with pred number.Save re-learning photo (with estimated value)
            rand = random.randint(0,100000)
            img.save('/home/pi/document/camera_car/Train/'
                     +str(i)+'_'+str(int(pred[0]))+
                     '_'+str(rand)+'.jpg')

except KeyboardInterrupt:
    pass

p0.stop()
p1.stop()
GPIO.cleanup()

The folder structure is

│ camera_car_main.py │ camera_car_preprocess.py │ model_20191102_8_best.pickle │ model_20191102_9.pickle ├─Predict │ └─done └─Train ├─0_Center ├─1_Left ├─2_Right └─3_Back

Please. By the way, there are two pickles, but 8 was the best. 9 is a re-learning version of 8, but since it is not actually running, the ability is unknown.

Impressions

It was interesting because I was able to think about various things from hardware to logic and implement it, and I learned about logic by thinking about re-learning. The improvement is that people have to annotate in order to relearn, so the drawback is that you can't relearn on the spot without a large display.

Recommended Posts

Obstacle (black) I made an automatic avoidance caterpillar.
I made an Ansible-installer
I made an Xubuntu server.
I made an Anpanman painter discriminator
I made an Angular starter kit
I made an online frequency analysis app
I made an alternative module for japandas.DataReader
I made a browser automatic stamping tool.
I made an extenum package that extends an enum
I made an Amazon Web Service Dash button
I wrote an automatic kitting script for OpenBlocks IoT
I wrote an automatic installation script for Arch Linux
I made an Android application that displays Google Map
I made an action to automatically format python code