Up プログラム 作成: 2021-05-24
更新: 2021-05-29


    PC から ssh -X 接続
    $ source ./venv/bin/activate
    (venv) $ cd ~/Tensorflow-YOLOv3
    (venv) $ vi reach.py
    #!/usr/bin/env python ##### モデル tiny YOLO の設定 ################# from core.utils import load_class_names, load_image, draw_boxes, draw_boxes_frame from core.yolo_tiny import YOLOv3_tiny from core.yolo import YOLOv3 # object のクラス class_names, n_classes = load_class_names() iou_threshold = 0.1 confidence_threshold = 0.25 model = YOLOv3_tiny(n_classes=n_classes, iou_threshold=iou_threshold, confidence_threshold=confidence_threshold) import tensorflow as tf inputs = tf.placeholder(tf.float32, [1, *model.input_size, 3]) detections = model(inputs) saver = tf.train.Saver(tf.global_variables(scope=model.scope)) ##### ターゲット ################# target_class = 'bottle' # 配列 class_names における target object の番号 target_n を求める for n in range(len(class_names)): if class_names[n] == target_class: target_n = n break ##### カメラ取込画像 ########################## # ヨコ, タテ CAMERA_WIDTH = 640 CAMERA_HEIGHT = 480 # 中心 ImgCenter_x = CAMERA_WIDTH/2 ###### GPIO #################################### import RPi.GPIO as GPIO # Set the GPIO pins as numbering GPIO.setmode(GPIO.BOARD) ###### Sensor #################################### TrigPin = 22 EchoPin = 18 # Set the TrigPin's mode is output GPIO.setup(TrigPin,GPIO.OUT) GPIO.output(TrigPin, GPIO.LOW) # Set the EchoPin's mode is input, and ON→ HIGH GPIO.setup(EchoPin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) ###### Distance from obstacle where GoPiGo should stop : 20cm distance_to_stop = 30 ###### 距離計測 #################################### import time def dist_read(): # 10us pulse to TrigPin time.sleep(0.3) GPIO.output(TrigPin, GPIO.HIGH) time.sleep(0.00001) GPIO.output(TrigPin, GPIO.LOW) # 超音波発信 # EchoPin が LOW から HIGH に変わる時刻 signaloff while GPIO.input(EchoPin) == GPIO.LOW: signaloff = time.time() # EchoPin が HIGH から LOW に変わる時刻 signalon while GPIO.input(EchoPin) == GPIO.HIGH: signalon = time.time() # EchoPin が HIGH だった時間 timepassed = signalon - signaloff distance = timepassed * 17000 return round(distance) ##### GoPiGo motor ########################## from easygopigo3 import EasyGoPiGo3 egpg = EasyGoPiGo3() import time ## 前進・後退 ############### # go forward def go_fwd(dist): egpg.set_speed(100) egpg.drive_cm(dist, True) # go backward 2sec def go_bk(): egpg.set_speed(100) egpg.backward() time.sleep(2) egpg.stop() ## 回転 #################### def rotation(t): egpg.set_speed(50) if t > 0: print('turn left') egpg.left() time.sleep(t) else: print('turn right') egpg.right() time.sleep(-t) egpg.stop() # 左45°回転 Rot45 = 3.8 # 左120°回転 Rot120 = 10.5 ## カメラ映像画面の dx に対する GoPiGo 回転時間 t # 車輪モータの set_speed 値が 50 のとき def pixel2t( dx ): abs_dx = abs( dx ) if abs_dx < 60: return dx * 0.6 / 50 elif abs_dx < 110: return dx * 0.9 / 100 elif abs_dx < 160: return dx * 1.2 / 150 elif abs_dx < 210: return dx * 2.2 / 200 elif abs_dx < 310: return dx * 2.4 / 300 else: return 2.4 * dx / abs_dx ## サーボ ############### import gopigo3 gpg = gopigo3.GoPiGo3() def pan(t): gpg.set_servo(gpg.SERVO_1, t ) # カメラを正面に向ける Pan_Center = 1500 # pan +45° Pan45 = 400 # 初期位置 pan(Pan_Center) ##### exit プロセス ################# import cv2 import sys def bye(): input('キー入力で, プログラム終了...') egpg.stop() pan(Pan_Center) # Release resource GPIO.cleanup() egpg.reset_all() gpg.reset_all() #カメラキャプチャを停止 cap.release() #ストリーミングウインドを閉じる cv2.destroyAllWindows() #プログラムを終了 sys.exit() ##################################################### ##### Program starts from here ########################## ##################################################### with tf.Session() as sess: # モデル tiny YOLO の読み込み saver.restore(sess, './weights/model-tiny.ckpt') # カメラ映像の読み込み (カメラ番号は 0) cap = cv2.VideoCapture(0) ################################################### ######## SEARCH ################################## detected = False for i in range(3): # カメラを右45°に向ける pan_val = Pan_Center - Pan45 pan(pan_val) print('searching target') for j in range(3): if j==0: print('right') elif j==1: print('front') else: print('left') for k in range(20): # カメラ映像を読む ret, frame = cap.read() # object 検出枠 resized_frame = cv2.resize(frame, dsize=tuple((x) for x in model.input_size[::-1]), interpolation=cv2.INTER_NEAREST) result = sess.run(detections, feed_dict={inputs: [resized_frame]}) # その中に target 検出枠があるか? boxes_dict = result[0] boxes = boxes_dict[target_n] # target 検出枠があったら if( len(boxes) != 0): print('target detected !\n') camera_pan_last = j detected = True break if detected == True: break else: # カメラ pan if j < 2: pan_val += Pan45 pan(pan_val) if detected == True: break else: # GoPiGo 回転 print('target is not detected \nGoPiGo turns left 120 degree') rotation(Rot120) print('done\n') if detected == False: print('in the end, target is not detected !\n') bye() ################################################### ######## target を視界に据える ######################### if camera_pan_last != 1: if camera_pan_last == 0: print('GoPiGo turns right 45 degree') rotation(-Rot45) print('done\n') else: print('GoPiGo turns left 45 degree') rotation(Rot45) # 視界から外さないため,少し後退 go_bk() print('\n') # カメラを正面に向ける pan(Pan_Center) ################################################### ######## APPROACH ################################## # カメラ画像の更新を,target の x 座業の変化で判定する # あり得ない数値を初期値にセット target_center_x_last = 1000 # <画像が更新されていない>をカウント image_old = 0 while True: ### target を検出する (試行 20回) ### detected = False for k in range(20): # カメラ映像を読む ret, frame = cap.read() if ret == True: # カメラ画像のヨコ,タテ frame_size = (frame.shape[1], frame.shape[0]) # object 検出枠 resized_frame = cv2.resize(frame, dsize=tuple((x) for x in model.input_size[::-1]), interpolation=cv2.INTER_NEAREST) result = sess.run(detections, feed_dict={inputs: [resized_frame]}) boxes_dict = result[0] # その中に target 検出枠があったら boxes = boxes_dict[target_n] if( len(boxes) != 0): detected = True break # target が検出されなかったら,終了 if detected == False: print('target lost !\n') bye() ### target の位置 ### resize_factor = (frame_size[0] / model.input_size[1], frame_size[1] / model.input_size[0]) for box in boxes: coordinates = box[:4] coordinates = [int(coordinates[i] * resize_factor[i % 2]) for i in range(4)] # target の中心 target_center_x = round( (coordinates[0]+coordinates[2])/2 ) # 画像中心からの object 中心のズレ dx = target_center_x - ImgCenter_x # 残りの box は無視 break # カメラ画像が更新されていない場合 if abs(target_center_x - target_center_x_last) < 2: if image_old == 0: print('image is not refreshed') image_old += 1 #つぎの時間つぶしは必要 time.sleep(20) # 5分以上更新されてなければ,プログラム終了 if image_old > 15: bye() # カメラ画像が更新されていれば else: if image_old > 0: image_old = 0 print('image is refreshed\n') # つぎの表示は,動作チェック用 #print('target_center_x_last : ' + str(target_center_x_last) + ' -> ' + str(target_center_x)) target_center_x_last = target_center_x # object検出枠表示 draw_boxes_frame(frame, frame_size, result, class_names, model.input_size) cv2.imshow('frame', frame) ### target の位置に対し,action を決める ### if abs(dx) > 20: #### target の方向にターン #### print('direction adjusting : ' + str(dx)) rotation( pixel2t( -dx ) ) print('done\n') else: #### target に向かって前進 #### print('target is in front') print("apart from center:" + str(dx) + '\n') # target との距離を測る dist = dist_read() print('distance : ' + str(dist) + 'cm') if dist > 450: print('target lost !\n') bye() elif dist < distance_to_stop: print('Arrived !\n') bye() else: fdist = round(dist/3) print('move forward : ' + str(fdist) + 'cm') go_fwd( fdist ) print('done\n') ######## プログラムを途中終了する ############ if cv2.waitKey(10) & 0xFF == ord('q'): bye()

    $ chmod +x reach.py
    $ ./reach.py


      以下は,ターゲット到達に成功したときのログ:
        searching target right front left target is not detected GoPiGo turns left 120 degree turn left done right front left target detected ! GoPiGo turns left 45 degree turn left done direction adjusting : -142.0 turn left done image is not refreshed image is refreshed direction adjusting : 36.0 turn right done image is not refreshed image is refreshed target is in front apart from center:10.0 distance : 68cm move forward done image is not refreshed image is refreshed target is in front apart from center:20.0 distance : 48cm move forward done image is not refreshed image is refreshed direction adjusting : 80.0 turn right done image is not refreshed image is refreshed target is in front apart from center:6.0 distance : 34cm move forward done target is in front apart from center:-2.0 distance : 24cm Arrived ! キー入力で, プログラム終了...