Về phần xử lý ảnh Góc của camera
+ Góc của camera cần phải cốđịnh để có thể tính toán chính xác được tọa độ vật thể. Tuy nhiên trong nhiều điều kiện thực tế rất khó để thực hiện được.
+ Đề xuất phương pháp sử dụng gimbal cho camera để đảm bảo góc của camera luôn được cốđịnh kể cảtrong trường hợp địa hình gồ ghề. Đồng thời hệ thống khung máy sẽ cần thêm hệ thống xy lanh, nhằm đảm bảo cho khung máy ổn định trong quá trình di chuyển trên thực địa.
Vấn đề chiều cao quả dứa.
+ Hiện tại tọa độ trục Z của quả dứa (chiều cao của quá dứa so với mặt đất) vẫn đang được tính phụ thuộc vào chiều cao của camera đến mặt đất. Tuy nhiên trong điều kiện thực tế, chiều cao của camera đến mặt đất là không cốđịnh do bề mặt địa hình không bằng phẳng.
+ Đề xuất phương án cải tiến: sử dụng thêm 1 camera đặt tại trục Y của khung xe để kết hợp với camera trục X dựng lại ảnh 3D của các quả dứa trong khung máy, qua đó sẽxác định được trục Z mà không phải dựa vào chiều cao của camera đến mặt đất.
64
TÀI LIỆU THAM KHẢO
[1] R. Girshick, “Fast R-CNN”, in Proc. IEEE Int. Conf. Comput. Vis., Dec. 2015, pp. 1440–1448. Stein, M., Bargoti, S., Underwood, J., “Image Based Mango Fruit Detection, Localisation and Yield Estimation Using Multiple View Geometry”, 2016.
[2] Halstead, M., McCool, C., Denman, S., Perez, T., Fookes, C., “Fruit Quantity and Quality Estimation using a Robotic Vision System”, 2018.
[3] Chen, S. W., Shivakumar, S. S., Dcunha, S., Das, J., Okon, E., Qu, C., Kumar, V., “Counting Apples and Oranges With Deep Learning: A Data-Driven Approach”, IEEE Robotics and Automation Letters, Vol. 2, Issue 2, 2017.
[4] Trần Trọng Minh, Giáo trình điện tử công suất, Nhà xuất bản Giáo Dục Việt Nam, 2015.
[5] R. Krishnan, Switched Reluctance Motor Drives, CRC Press LLC, 2001.
[6] Husain, I. and M. Ehsani, “Torque ripple Minimization in Switched Reluctance Motor Drives by PWM Control”, IEEE Trans. on Power Electronics, Vol. 11, No. 1, 1996, pp. 83-88.
[7] T.J.E. Miller, Switched Reluctance Motors and Their Control, Magna Physics, Oxford, 1992.
65
PHỤ LỤC
Đầu vào ra cho PLC điều khiển cánh tay 1
Phân bố đầu vào tín hiệu cho PLC FX3U-64M phụ trách điều khiển tay máy số 1
Tín hiệu
vào
Tên thiết bị kết nối với đầu
vào PLC Mô tả chức năng
X0 Cảm biến CB11 Tín hiệu truyền về của cảm biến tay máy 1 tại gốc tọa độ trục X X3 Cảm biến CB12 Tín hiệu truyền về của cảm biến tay máy 1 tại gốc tọa độ trục Y. X4 Nút ấn ST1 (Start 1) Tín hiệu truyền về của nút ấn khởi động tay máy 1. Sử dụng tiếp điểm thường mở (NO).
X5 Nút ấn SP1 (Stop 1)
Tín hiệu truyền về của nút ấn dừng tay máy 1. Sử dụng tiếp điểm thường đóng (NC).
X6 Nút ấn E1 (Emergency 1)
Tín hiệu truyền về của nút ấn dừng khẩn cấp tay máy 1. Sử dụng tiếp điểm thường đóng có duy trì.
X7 Tín hiệu cảm biến báo vị trí xi lanh. Cảm biến XL11 Tín hiệu truyền về của cảm biến điện từbáo xi lanh đã thu về hết.
X10 Cảm biến
XL14
Tín hiệu truyền về của cảm biến điện từbáo xi lanh đã hạ xuống vịtrí dưới cùng. X12 Cảm biến XL13 Tín hiệu truyền về của cảm biến điện từ báo xi lanh đã hạ xuống vị trí giữa. X11 Cảm biến XL12 Tín hiệu truyền về của cảm biến điện từ báo xi lanh đã hạ xuống vị trí trên cùng. X13 Tín hiệu cần đặt vị trí xi lanh. Cần điều khiển J1L Tín hiệu truyền về từ cần đặt vị trí xi lanh xuống thấp nhất. X14 Cần điều khiển J1H Tín hiệu truyền về từ cần đặt vị trí xi lanh xuống tầm giữa. X15 Tín hiệu cần đặt. Cần điều khiển VANG Tín hiệu truyền về từ cần đặt điều khiển thu hoạch dứa chín.
66 X17 Cần điều khiển VANG_XANH Tín hiệu truyền về từ cần đặt điều khiển thu hoạch cả dứa chín và dứa xanh.
Phân bố đầu ra tín hiệu cho PLC FX3U-64M phụ trách điều khiển tay máy số 1
Đầu ra Y
Tên thiết bị kết nối với
đầu vào PLC Mô tả chức năng
Y0
Cấp tín hiệu cho cổng PUL- của Driver 1, 2 (Driver 1,2 điều khiển hai động cơ bước của trục X)
Tín hiệu đưa tới chân PUL- của Driver 1, 2. Có chức năng đặt tốc độ và vị trí cho động cơ.
Y1
Cấp tín hiệu cho cổng PUL- của Driver 3 (Driver 3 điều khiển động cơ bước của trục Y)
Tín hiệu đưa tới chân PUL- của Driver 3. Có chức năng đặt tốc độ và vị trí cho động cơ.
Y2 Cấp tín hiệu cho cổng ENA- của Driver 1, 2
Tín hiệu chạy cho động cơ 1, 2. Y2 = 0 động cơ 1, 2 dừng; Y2 = 1 động cơ 1, 2 chạy.
Y3 Cấp tín hiệu cho cổng ENA- của Driver 3
Tín hiệu chạy cho động cơ 3. Y3 = 0 động cơ 3 chạy; Y3 = 1 động cơ 3 dừng.
Y4 Cấp tín hiệu cho cổng DIR- của Driver 1, 2
Tín hiệu đảo chiều cho động cơ 1,2. Y4= 0 động cơ chạy thuận (cánh tay di chuyển theo trục X+); Y4=1 động cơ chạy ngược (cánh tay di chuyển theo trục X-).
Y5 Cấp tín hiệu cho cổng DIR- của Driver 3
Tín hiệu đảo chiều cho động cơ 3. Y5=0 động cơ 3 chạy ngược (cánh tay di chuyển theo trục Y-); Y5=1 động cơ 3 chạy thuận (cánh tay di chuyển theo trục Y+)
Y10
Cấp tín hiệu cho rơ le trung gian điều khiển van phân phối cho xi lanh khí nén 11
Xilanh khí nén 11 có chức năng dịch chuyển tay máy theo trục Z, hướng đi lên.
67 Y11
Cấp tín hiệu cho rơ le trung gian điều khiển van phân phối cho xi lanh khí nén 12
Xilanh khí nén 12 có chức năng dịch chuyển tay máy theo trục Z, hướng đi xuống.
Y12
Cấp tín hiệu cho rơ le trung gian điều khiển van phân phối cho xi lanh khí nén 21
Xilanh khí nén 21 có chức năng đóng mở bàn tay gắp dứa.
Y14
Cấp tín hiệu cho rơ le trung gian điều khiển van phân phối cho động cơ khí nén 31
Xilanh khí nén 31 có chức năng bật tắt cưa khí nén.
Y15 Cấp tín hiệu cho đèn xanh Đèn xanh báo hiệu chế độ hoạt động của tay máy (chếđộ RUN)
Y16 Cấp tín hiệu cho đèn đỏ Đèn đỏ báo hiệu chếđộ hoạt động của tay máy (chếđộ STOP).
Đầu vào ra cho PLC điều khiển cánh tay 2
Phân bố đầu vào tín hiệu cho PLC FX3U-64M phụ trách điều khiển tay máy số 2
Tín hiệu
vào
Tên thiết bị kết nối với
đầu vào PLC Mô tả chức năng
X0 Cảm biến CB21 Tín hiệu truyền về của cảm biến tay máy 2 tại gốc tọa độ trục X. X3 Cảm biến CB22 Tín hiệu truyền về của cảm biến tay máy 2 tại gốc tọa độ trục Y. X4 Nút ấn ST2 (Start 2) Tín hiệu truyền về của nút ấn khởi động tay máy 2. Sử dụng tiếp điểm thường mở (NO).
X5 Nút ấn SP2 (Stop 2)
Tín hiệu truyền về của nút ấn dừng tay máy 2. Sử dụng tiếp điểm thường đóng (NC).
X6 Nút ấn E2 (Emergency 2)
Tín hiệu truyền về của nút ấn dừng khẩn cấp tay máy 2. Sử dụng tiếp điểm thường đóng có duy trì. X7 Tín hiệu cảm biến Cảm biến XL21 Tín hiệu truyền về của cảm biến điện từbáo xi lanh đã thu về hết.
68 X10 báo vị trí xi lanh. Cảm biến XL24 Tín hiệu truyền về của cảm biến điện từ báo xi lanh đã hạ xuống vị trí dưới cùng. X12 Cảm biến XL23 Tín hiệu truyền về của cảm biến điện từbáo xi lanh đã hạ xuống vị trí giữa. X11 Cảm biến XL22 Tín hiệu truyền về của cảm biến điện từ báo xi lanh đã hạ xuống vị trí trên cùng. X13 Tín hiệu cần đặt vị trí xi lanh. Cần điều khiển J2L Tín hiệu truyền về từ cần đặt vị trí xi lanh xuống thấp nhất. X14 Cần điều khiển J2H Tín hiệu truyền về từ cần đặt vị trí xi lanh xuống tầm giữa. X15 Tín hiệu cần đặt. Cần điều khiển VANG Tín hiệu truyền về từ cần đặt điều khiển thu hoạch dứa chín. X17 Cần điều khiển VANG_XANH Tín hiệu truyền về từ cần đặt điều khiển thu hoạch cả dứa chín và dứa xanh.
Phân bố đầu ra tín hiệu cho PLC FX3U-64M phụ trách điều khiển tay máy số 2
Đầu ra
Y
Tên thiết bị kết nối với
đầu vào PLC Mô tả chức năng
Y0
Cấp tín hiệu cho cổng PUL- của Driver 1, 2 (Driver 1,2 điều khiển hai động cơ bước của trục X)
Tín hiệu đưa tới chân PUL- của Driver 1, 2. Có chức năng đặt tốc độ và vịtrí cho động cơ.
Y1
Cấp tín hiệu cho cổng PUL- của Driver 3 (Driver 3 điều khiển động cơ bước của trục Y)
Tín hiệu đưa tới chân PUL- của Driver 3. Có chức năng đặt tốc độ và vị trí cho động cơ.
Y2 Cấp tín hiệu cho cổng ENA- của Driver 1, 2
Tín hiệu chạy cho động cơ 1, 2. Y2 = 0 động cơ 1, 2 dừng; Y2 = 1 động cơ 1, 2 chạy.
Y3 Cấp tín hiệu cho cổng ENA- của Driver 3
Tín hiệu chạy cho động cơ 3. Y3 = 0 động cơ 3 chạy; Y3 = 1 động cơ 3 dừng.
Y4 Cấp tín hiệu cho cổng DIR- của Driver 1, 2
Tín hiệu đảo chiều cho động cơ 1,2. Y4= 1 động cơ chạy thuận (cánh tay di chuyển theo trục X+); Y4=0 động cơ chạy ngược (cánh tay di chuyển
69 theotrục X-).
Y5 Cấp tín hiệu cho cổng DIR- của Driver 3
Tín hiệu đảo chiều cho động cơ 3. Y5=0 động cơ 3 chạy ngược (cánh tay di chuyển theo trục Y-); Y5=1 động cơ 3 chạy thuận (cánh tay di chuyển theo trục Y+)
Y10
Cấp tín hiệu cho rơ le trung gian điều khiển van phân phối cho xi lanh khí nén 21
Xilanh khí nén 21 có chức năng dịch chuyển tay máy theo trục Z, hướng đi lên.
Y11
Cấp tín hiệu cho rơ le trung gian điều khiển van phân phối cho xi lanh khí nén 22
Xilanh khí nén 22 có chức năng dịch chuyển tay máy theo trục Z, hướng đi xuống.
Y12
Cấp tín hiệu cho rơ le trung gian điều khiển van phân phối cho xi lanh khí nén 22
Xilanh khí nén 22 có chức năng đóng mở bàn tay gắp dứa.
Y14
Cấp tín hiệu cho rơ le trung gian điều khiển van phân phối cho động cơ khí nén 32
Xilanh khí nén 32 có chức năng bật tắt cưa khí nén.
70
Thiết kế mạch nguyên lí cho cấp điều khiển
Đầu vào của PLC Mitsubishi FX3U-64M (1)
71 Hệ thống xilanh và động cơ khí nén của robot (1)
72 Hệthống Driver điều khiển và động cơ Stepper (1)
73
74 Đầuvào của PLC Mitsubishi FX3U-64M (2)
75 Hệ thống xi lanh và động cơ khí nén của robot (2)
76 Hệ thống Driver điều khiển và động cơ Stepper (2)
77
79
Chương trình điều khiển viết bằng SFC cho tay máy 1
80
81
82
// Chương trình trong khối chức năng S12
// Chương trình trong khối chức năng S13
83
//Chương trình trong khối chức năng S15
84
//Chương trình trong khối chức năng S18
85
86
Chương trình điều khiển viết bằng SFC cho tay máy 2
87
//Chương trình trong khối chức năng S10
88
89
90
Chương trình điều khiển giám sát trên ngôn ngữ Python
import tkinter import cv2
import pyrealsense2 as rs import operator
import time
from threading import Thread from yolo import YOLO
from utils.PLC_IO import PLC_IO
from utils.realSenseDepth import realSenseStream from utils.DepthTool import DepthTool
import utils.image2coordc as i2c from time import sleep
from PIL import Image, ImageDraw, ImageFont, ImageTK from PLC.PLCASync import PLCASync
import queue
import numpy as np
from tkinter import messengebox import tensorflow as tf
from keras.backend.tensorflow_backend import set_session threads = []
teststr = '1'
class App: #Giao dien hien thi
def__init__(self, window, window_title): self.window = window
self.window.title(window_title) self.window.geometry("1920x1080") self.testThread = None
self.realSenseStream = realSenseStream()
self.background_label = tkinter.Label(window, bg='grey') self.background_label.place(relx=0, rely=0, relheight=1, relwidth=1)
self.recipe = 0 self.input_str = "
# open video souce (by default this will try to open the computer webcam) # Creat a canvas that can fit the above video source size
91 self.canvas.place(relx=0.003, rely=0.1, relheight=0.7,
relwidth=0.498)
self.canvas1 = tkinter.Canvas(self.background_label) self.canvas1.place(relx=0.052, rely=0.1, relheight=0.7, relwidth=0.497)
# Button that lets the user take a snapshot self.btn_snapshot =
tkinter.Button(self.background_label,bg='salmon3',text="Start",fg='black',font=(" helvetica",25),command=self.snapshot)
self.btn_snapshot.place(relx=0.77, rely=0.85, relheight=0.09, relwidth=0.2)
self.btn_update =
tkinter.Button(self.background_label,bg='salmon3',text="Update",fg='black',font =("helvetica",25),command=self.btn_update)
self.btn_update.place(relx=0.53, rely=0.85, relheight=0.09, relwidth=0.2)
# After it is called once, the update method will be automatically called every delay milliseconds
self.label1 =
tkinter.Label(self.background_label,bg='salmon3',text="Camera Angle",font=("helvetica",25))
self.label1.place(relx=0.05, rely=0.85, relheight=0.09, relwidth=0.25)
self.label2 =
tkinter.Label(self.background_label,bg='salmon3',text="Pineapples Harverting Machine",fg='white',font=("helvetica",60))
self.label2.place(relx=0.003, rely=0.001, relheight=0.09, relwidth=0.996) self.entry1 = tkinter.Entry(self.background_label,bg='white') self.entry1.place(relx=0.35, rely=0.87) self.delay = 15 self.update() def_delete_window(self) print("delete_window") self.testThread.isstop = True self.testThread.join() try # self.testThread.join() self.window.destroy() except Exception as e:
92 print(e) pass def btn_update(self) teststr = self.entry1.get() if teststr == ":
messengebox.showerror("Error","Hay nhap thong so")
self.recipe = int(teststr)
self.testThread.recipe = self.recipe def snapshot(self)
# Get a frame from the video source teststr = self.entry1.get()
if teststr == ":
messengebox.showerror("Error","Hay nhap thong so") print(teststr) elif teststr!= ": flame1 = self.realSenseStream.get_flame() self.photo1 = ImageTK.PhotoImage(image=Image.fromarray(flame1)) self.canvas1.creat_image(0, 0, image=self.photo1, anchor=tkinter.NW) self.testThread = PLCASync1(self.realSenseStream) self.testThread.start() self.testThread.recipe = self.recipe print(self.testThread.recipe) threads.append(self.testThread) print(len(threads)) self.btn_snapshot.config(state = 'disable') def update(self)
# Get a frame from the realsense
frame = self.realSenseStream.get_flame() self.photo = ImageTK.PhotoImage(image=Image.fromarray(frame)) self.canvas.creat_image(0, 0, image=self.photo, anchor=tkinter.NW) self.testThread.image = self.testThread.image.resize((956, 756), Image.ANTIALIAS)
93 self.photo1 = ImageTK.PhotoImage(image=self.testThread.image) self.canvas1.creat_image(0, 0, image=self.photo1, anchor=tkinter.NW) super().__init__()
self.ready = False # flag tay cat dua self.take = False # flag chup anh
self.realSenseStream = realSenseStream self.isstop = False self.image = None self.imageUpdate = False self.systemready = False self.recipe = 1 self.parameter = 0 def run(self): gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.5)
config = tf.ConfigProto(gpu_options = gpu_options) sess = tf.Session(config = config)
detect = YOLO().raw_detect_image take_image = self.realSenseStream.take_image font = ImageFont.truetype('Pillow/Tests/fonts/FreeMono.ttf',size=32) hand_queue = queue.Queue(0) boxList1 = [] boxList2 = [] # PLC 1 plc1 = PLC_IO("PLC1",'/dev/ttyUSB0') plcThread1 = PLCASync(plc1) plcThread1.start() # PLC 2 plc2 = PLC_IO("PLC2",'/dev/ttyUSB1') plcThread2 = PLCASync(plc2)
# B2: Camera chup anh va detect
# B3: Chuyen sang toa do Cam va gui len PLC # B4: Quay lai vong lap
while True:
94 plcThread1.isstop = True plcThread2.isstop = True return plcThread1.ready = False plcThread1.take = False plcThread2.ready = False plcThread2.take = False plcThread1.mode1 = False plcThread2.mode2 = False plcThread1.RESET = False plcThread1.finish = False plcThread2.finish = False print("Wait") plc1.ser.flushOutput() plc1.serialOutready(1,1) plc1.ser.flushInput() self.systemready = True
while plcThread1.take == False: if self.isstop: plcThread1.isstop = True plcThread2.isstop = True print("Stop PLC Test") return continue plcThread1.RESET = False
# wait for pulse for i in range(2)
if plcThread1.RESET == True: break
if i == 1:
while plcThread1.ready == False or plcThread2.ready == False: if plcThread1.RESET == True: break continue if plcThread1.RESET == True: break
95 boxList1.clear()
boxList2.clear()
print("Taking image...")
path, dataPath, _ = take_image() #chup anh image = Image.open(path)
draw = ImageDraw.Draw(image) #khoi tao anh de luu
print("Tsh! Detecting...")
data = detect(image) #nhan dien qua dua print("Detected.") count_dua = 0 depthTool = DepthTool() depthTool.readCord(dataPath) bias = 0.1 gridSize = 10
for box in data['objects']:
if plcThread1.mode2 == True: if box['class'] == 2 count_dua += 1 depth =
depthTool.getDepthBoundingBox([box['box']['left'], box['box']['top'], box['box']['right'], box['box']['buttom']], gridSize, bias) * 100
x = (box['box']['left'] + box['box']['right'])/2 y = box['box']['buttom'] rx, ry = i2x.to_coord_from_depth(x,y,depth) draw.rectangle([box['box']['left'], box['box']['top'], box['box']['right'], box['box']['buttom']], outline=(255,0,0), width=10)
campov = str(rx)+''+str(ry) draw.text((box['box']['left'], box['box']['top'] -35 ), campov, fill = (255,0,0), font = font)
print(box['score'], box['box']['left'], box['box']['top']-35)
# xep toa do cho 2 tay cat if rx>0: #PLC1
boxList1.append({'x':rx, 'y':ry, 'box':box}) #them vao danh sach cat PLC 1
96 else
boxList2.append({'x':rx, 'y':ry, 'box':box}) #them vao danh sach cat PLC 1
pass if plcThread1.mode1 == True: if box['class'] == 3 or box['class'] == 2 count_dua += 1 depth = depthTool.getDepthBoundingBox([box['box']['left'], box['box']['top'], box['box']['right'], box['box']['buttom']], gridSize, bias) * 100
x = (box['box']['left'] + box['box']['right'])/2 y = box['box']['buttom'] rx, ry = i2x.to_coord_from_depth(x,y,depth) draw.rectangle([box['box']['left'], box['box']['top'], box['box']['right'], box['box']['buttom']], outline=(255,0,0), width=10)
campov = str(rx)+''+str(ry) draw.text((box['box']['left'], box['box']['top'] -35 ), campov, fill = (255,0,0), font = font)
print(box['score'], box['box']['left'], box['box']['top']-35)
# xep toa do cho 2 tay cat if rx>0: #PLC1
boxList1.append({'x':rx, 'y':ry, 'box':box}) #them vao danh sach cat PLC 1
else
boxList2.append({'x':rx, 'y':ry, 'box':box}) #them vao danh sach cat PLC 2
pass
if plc2.serialOut(obj['x'],obj['y']) == True #xuat toa do
plcThread2.ready = False
plcThread2.finish = False #reset tay
97 if i==1:
while plcThread2.finish == False or plcThread1.finish == False: if plcThread1.RESET == True: break if self.isstop: plcThread1.isstop = True plcThread2.isstop = True return continue # Create a window and pass it to the Application object App(tkinter.Tk(),"PINEAPPLE")