Đề tài “Thiết kế và thi công mô hình phân loại hàng hóa dựa vào AI và mã QR” là mô hình phân loại hộp hàng có còn nguyên vẹn hay bị hư, cân trọng lượng hộp hàng và quét mã QR. Dựa trên ngôn ngữ Python với thư viện hỗ trợ chính là OpenCV và mô hình để training là YOLO được thực hiện trên máy tính và PLC Simens. Sử dụng thuật toán train YOLO v8 để học sâu về các đặc điểm hình dáng, màu sắc của hộp hàng với dữ liệu tương đối ổn định và màu vàng cát đặc trưng của thùng hàng để đi nhận dạng và sau đó phân loại hộp hàng nguyên vẹn hay bị hỏng. Kết quả thực hiện của đề tài đã nhận dạng được những hộp hàng nguyên, những điểm bị rách trên hộp hàng và đọc mã QR, phân loại đến những vị trí mà thùng hàng sẽ được vận chuyển song song với việc đếm số lượng hộp hàng, lưu dữ liệu vào Excel theo 2 ca làm việc trong 1 ngày rồi hiển thị lên giao diện Tkinter.
BỘ GIÁO DỤC VÀ ĐÀO TẠO TRƯỜNG ĐẠI HỌC NGUYỄN TẤT THÀNH KHOA KỸ THUẬT - CƠNG NGHỆ KHỐ LUẬN TỐT NGHIỆP THIẾT KẾ VÀ THI CƠNG MƠ HÌNH PHÂN LOẠI HÀNG HÓA DỰA VÀO AI VÀ MÃ QR Giảng viên hướng dẫn: TS TRẦN QUANG HUY Giảng viên hướng dẫn: TS TRẦN QUANG HUY Sinh viên thực hiện: TRẦN QUỐC BẢO 1900006121 Sinh viên thực hiện: TRẦN QUỐC BẢO - 1900006121 NGUYỄN VĂN ĐỒNG 1900006916 NGUYỄN VĂN ĐỒNG - 1900006916 HUỲNH HOÀI NAM 1900005832 HUỲNH HOÀI NAM - 1900005832 Khoá: 2019 – 2023 Khoá: 2019 – 2023 TP HỒ CHÍ MINH, THÁNG 6/2023 BỘ GIÁO DỤC VÀ ĐÀO TẠO TRƯỜNG ĐẠI HỌC NGUYỄN TẤT THÀNH KHOA KỸ THUẬT – CƠNG NGHỆ KHỐ LUẬN TỐT NGHIỆP THIẾT KẾ VÀ THI CƠNG MƠ HÌNH PHÂN LOẠI HÀNG HĨA DỰA VÀO AI VÀ MÃ QR Giảng viên hướng dẫn: TS TRẦN QUANG HUY Sinh viên thực hiện: TRẦN QUỐC BẢO Khoá: NGUYỄN VĂN ĐỒNG - 1900006916 HUỲNH HOÀI NAM - 1900005832 2019 – 2023 - TP HỒ CHÍ MINH, THÁNG 6/2023 1900006121 TRƯỜNG ĐẠI HỌC NGUYỄN TẤT THÀNH CỘNG HOÀ XÃ HỘI CHỦ NGHĨA VIỆT NAM KHOA KỸ THUẬT – CÔNG NGHỆ Độc lập - Tự - Hạnh phúc Bộ mơn Cơ điện tử NHIỆM VỤ ĐỒ ÁN/ KHỐ LUẬN TỐT NGHIỆP Sinh viên thực hiện: TRẦN QUỐC BẢO MSSV: 1900006121 NGUYỄN VĂN ĐỒNG MSSV: 1900006916 HUỲNH HOÀI NAM MSSV: 1900005832 Ngành: Công nghệ kĩ thuật điện tử Tên đề tài khố luận: THIẾT KẾ VÀ THI CƠNG MƠ HÌNH PHÂN LOẠI HÀNG HĨA DỰA VÀO AI VÀ MÃ QR Nội dung khố luận: - Tổng quan xử lý ảnh; Tổng quan trí tuệ nhân tạo; - Tìm hiểu phương pháp nhận dạng phân loại sản phẩm; - Tìm hiểu ngơn ngữ Python thuật toán train YOLO; - Viết chương trình máy tính để ứng dụng triển khai mơ hình; - Viết chương trình PLC Simens S7-1200; Kết đạt Đề tài lên ý tưởng thiết kế thi cơng hồn chỉnh Hệ thống phân loại hoạt động ổn định, đồng với cảm biến động Có kiến thức thực tiễn sau thực đề tài Ngày giao: ……………… … Ngày nộp: …………………… Kết luận: Nội dung yêu cầu Đồ án/ Khoá luận tốt nghiệp thông qua bởi: Họ tên người hướng dẫn Ký tên 1/…………………………………………… ………………………………… Tp Hồ Chí Minh, ngày……tháng……năm…… TRƯỞNG BỘ MƠN GIẢNG VIÊN HƯỚNG DẪN CHÍNH (Ký, ghi rõ họ tên) (Ký, ghi rõ họ tên) i LỜI CAM KẾT Đề tài “Thiết kế thi công mơ hình phân loại hàng hóa dựa vào AI mã QR” nhóm tơi tự thực dựa vào tham khảo số tài liệu trước khơng chép từ tài liệu có trước (Sinh viên thực hiện) Trần Quốc Bảo Nguyễn Văn Đồng Huỳnh Hồi Nam Tp.Hồ Chí Minh, ngày tháng năm 2023 ii LỜI CẢM ƠN 🙚🙚 Để thực hoàn thành đề tài này, nhóm chúng em xin gửi lời chân thành cảmơn thầy cô Khoa Kỹ Thuật - Công Nghệ tạo điều kiện tốt cho em hoàn thành đề tài Những kiến thức bổ ích mà Thầy Cơ dạy, áp dụng vào đề tài Khóa Luận Tốt Nghiệp nhiều, từ kiến thức nhỏ nhặt học lớn Ngồi cố gắng nhóm chúng em khơng thể không nhắc đến công lao vạch hướng cho đề tài hướng dẫn yêu cầu đề tài mà thầy TS Trần Quang Huy truyền đạt cho nhóm em kiến thức bổ ích ứng dụng thực tế Thầy TS Trần Quang Huy tận tình giải giải thích rõ ràng chỗ mà nhóm em chưa hiểu cịn thiếu sót Mặc dù nhóm em cố gắng hồn thành tốt đề tài cách hoàn chỉnh nhất, khơng thể tránh sai sót định công tác nghiên cứu, tiếp cận thực tế, hạn chế kiến thức lẫn thời gian thực Rất mong nhận góp ý quý thầy cô bạn để đề tài hồn chỉnh Nhóm em xin chân thành cảm ơn! iii TĨM TẮT KHỐ LUẬN THIẾT KẾ VÀ THI CƠNG MƠ HÌNH PHÂN LOẠI HÀNG HĨA DỰA VÀO AI VÀ MÃ QR Đề tài “Thiết kế thi công mơ hình phân loại hàng hóa dựa vào AI mã QR” mơ hình phân loại hộp hàng có nguyên vẹn hay bị hư, cân trọng lượng hộp hàng quét mã QR Dựa ngôn ngữ Python với thư viện hỗ trợ OpenCV mơ hình để training YOLO thực máy tính PLC Simens Sử dụng thuật tốn train YOLO v8 để học sâu đặc điểm hình dáng, màu sắc hộp hàng với liệu tương đối ổn định màu vàng cát đặc trưng thùng hàng để nhận dạng sau phân loại hộp hàng nguyên vẹn hay bị hỏng Kết thực đề tài nhận dạng hộp hàng nguyên, điểm bị rách hộp hàng đọc mã QR, phân loại đến vị trí mà thùng hàng vận chuyển song song với việc đếm số lượng hộp hàng, lưu liệu vào Excel theo ca làm việc ngày hiển thị lên giao diện Tkinter iv MỤC LỤC NHIỆM VỤ KHOÁ LUẬN TỐT NGHIỆP i LỜI CAM KẾT ii LỜI CẢM ƠN iii TĨM TẮT KHỐ LUẬN iv MỤC LỤC v DANH MỤC SƠ ĐỒ, HÌNH VẼ ix DANH MỤC TỪ VIẾT TẮT xi CHƯƠNG 1: TỔNG QUAN ĐỀ TÀI 1.1 Đặt vấn đề 1.2 Mục tiêu đề tài: 1.3 Đối tượng phạm vi nghiên cứu: 1.3.1 Đối tượng nghiên cứu: .2 1.3.2 Phạm vi nghiên cứu: 1.4 Phương thức nghiên cứu: 1.4.1 Cơ sở phương pháp luận: 1.4.2 Các phương pháp nghiên cứu: .2 CHƯƠNG : CƠ SỞ LÝ THUYẾT 2.1 Tổng quan YOLO v 2.1.1 Giới thiệu YOLO .3 2.1.2 Lịch sử YOLO 2.1.3 Thuật toán YOLO 2.1.4 Quá trình train YOLO .7 2.2 Tổng quan PLC S7-1200 .7 2.2.1 PLC ? 2.2.2 Lịch sử hình thành 2.2.3 Ứng dụng PLC 10 2.3 Tổng quan mạng truyền thông công nghiệp 11 2.3.1 Mạng truyền thông công nghiệp ? 11 2.3.2 Vai trị truyền thơng cơng nghiệp 12 2.3.3 Truyền thông Modbus TCP/IP công nghiệp 12 2.4 Tổng quan Opencv – Open Source Computer Vision 13 2.4.1 Giới thiệu OpenCV 13 2.4.2 Các ứng dụng OpenCV 14 2.5 Lưu đồ giải thuật 15 2.5.1 Lưu đồ hệ thống 15 2.5.2 Sơ đồ hệ thống điện 15 2.6 Tính tốn tải trọng băng tải, cơng suất động số xung cấp cho steps 16 2.7 Visual Studio Code ? 17 vi 2.7.1 Giới thiệu Visual Studio Code 18 2.7.2 Ưu điểm nhược điểm việc sử dụng Visual Studio Code 18 2.8 Lập trình Tkiner Python 18 2.9 Tia Portal ? 20 2.9.1 Giới thiệu Tia Portal 20 2.9.2 Ưu điểm nhược điểm việc sử dụng Tia Portal 21 2.10 Phần mềm Solidworks 22 2.10.1 Giới thiệu phần mềm Solidworks 22 2.10.2 Ưu điểm nhược điểm việc sử dụng Solidworks 22 CHƯƠNG : GIỚI THIỆU SƠ LƯỢC VỀ CÁC THIẾT BỊ ĐIỆN 24 3.1 PLC S7-1200 1214DC/DC/DC 24 3.2 Động giảm tốc GA25-370 25 3.3 Webcam Rapoo C260 26 3.4 Cảm biến khoảng cách E3F-DS30P1 27 3.5 Cảm biến cân nặng Loadcell 1kg 24Bit HX711 28 3.6 Động Step 17HD4401S 29 3.7 Driver Step Motor TB6600 30 3.8 Nguồn tổ ong 24V 32 3.9 Relay trung gian MY2-J 24V (52P-24V) 33 vii 3.10 Mạch khuếch đại JY-S60 33 CHƯƠNG 4: THIẾT KẾ TRÊN PHẦN MỀM VÀ THI CƠNG MƠ HÌNH 35 4.1 Thiết kế mơ hình phần mềm Solidworks 35 4.2 Vật liệu khí 35 4.2.1 Nhơm định hình 35 4.2.2 Mica 36 4.3 Lắp đặt thiết bị 36 CHƯƠNG 5: KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN ĐỀ TÀI 39 5.1 Kết đạt được: 39 5.1.1 Ưu điểm đề tài 40 5.1.2 Hạn chế đề tài 40 5.2 Hướng phát triển đề tài: 40 5.3 Năng suất hệ thống: 40 TÀI LIỆU THAM KHẢO… 42 PHỤ LỤC 43 PHỤ LỤC 56 viii my_tree_1.column("Mã Sản Phẩm", width=100) my_tree_1.column("Tên Sản Phẩm", width=160) my_tree_1.column("Khu Vực", width=80) my_tree_1.column("Khối Lượng Thật", width=100) my_tree_1.column("Thời Gian Nhận", width=120) my_tree_1.column("Tình Trạng", width=80) def Tu_Dong_Luu(): # Tạo thư mục liệu (nếu chưa tồn tại) global directory = "DuLieu" os.makedirs(directory, exist_ok=True) # Tạo tên tệp dựa ngày filename = pathlib.Path(f"{directory}/{ngay}.xlsx") data = [] for item in my_tree_1.get_children(): values = my_tree_1.item(item, 'values') data.append(values) df_1 = pd.DataFrame(data, columns=['ID', 'Mã Sản Phẩm', 'Tên Sản Phẩm', 'Khu Vực', 'Khối Lượng Thật', 'Thời Gian Nhận', 'Tình Trạng']) # Lưu DataFrame vào tệp Excel df_1.to_excel(filename, index=False) def open_image(image_path): img = cv2.imread(image_path) # Kiểm tra xem hình ảnh có tồn hay không if img is not None: cv2.imshow("Hinh Anh", img) cv2.waitKey(0) cv2.destroyAllWindows() else: return def get_selected_row(event): selection = my_tree_1.selection() if selection: values = my_tree_1.item(selection)['values'] col_2_value = values[1] print(col_2_value) image_path = f"{Tep_Luu_Anh}/MV_{col_2_value}.jpg" 74 # Tạo thread để mở hình ảnh thread = threading.Thread(target=open_image, args=(image_path,)) thread.start() my_tree_1.bind("", get_selected_row) ##################################################################### ########### def open_image_2(image_path): img_2 = cv2.imread(image_path) # Kiểm tra xem hình ảnh có tồn hay khơng if img_2 is not None: cv2.imshow("Hinh Anh", img_2) cv2.waitKey(0) cv2.destroyAllWindows() else: return def get_selected_row_2(event): selection_2 = my_tree_2.selection() if selection_2: values_2 = my_tree_2.item(selection_2)['values'] col_2_value_2 = values_2[1] print(col_2_value_2) image_path_2 = f"{Tep_Luu_Anh}/MV_{col_2_value_2}.jpg" # Tạo thread để mở hình ảnh thread_2 = threading.Thread(target=open_image_2, args=(image_path_2,)) thread_2.start() def save_as(): if MoEX == and MoEX_1 == 1: global file_path file = filedialog.asksaveasfile(mode='wb', defaultextension=".xlsx") if file: file_path = file.name shutil.copy("BanNhap.xlsx", file_path) # Tạo thư mục chọn file.close() messagebox.showinfo("Thông báo", "Xuất file thành công!") else: messagebox.showinfo("Cảnh Báo","Bạn Chưa Mở Excel") def clear_tree(): 75 my_tree_1.delete(*my_tree_1.get_children()) def ThemSP(): global MoEX if MoEX == 1: global e_1 global e_2 global e_3 global e_4 global e_7 y=e_1.get() z=e_2.get() y1=e_3.get() z1=e_4.get() y2=e_7.get() if y=="" or z=="" or z1=="" or y1=="" or y2=="": messagebox.showinfo("Cảnh Báo","Bạn Chưa Nhập Đủ Dữ Liệu") else: global Ten_Excel file = openpyxl.load_workbook(Ten_Excel) sheet = file.active column_a_1 = sheet["A"] column_b_1 = sheet["B"] y_Trung = False z_Trung = False for cell_1 in column_a_1: if y == cell_1.value: y_Trung = True messagebox.showinfo("Cảnh Báo","Số ID bị trùng") break for cell_1 in column_b_1: if z == cell_1.value: z_Trung = True messagebox.showinfo("Cảnh Báo","Số Mã Vạch bị trùng") break if not y_Trung: if not z_Trung: sheet.cell(column=1, row=sheet.max_row + 1, value=str(y)) sheet.cell(column=2, row=sheet.max_row, value=str(z)) sheet.cell(column=3, row=sheet.max_row, value=str(z1)) sheet.cell(column=4, row=sheet.max_row, value=str(y1)) 76 sheet.cell(column=5, row=sheet.max_row, value=str(y2)) file.save(Ten_Excel) e_1.delete(0, END) e_2.delete(0, END) e_3.delete(0, END) e_4.delete(0, END) e_7.delete(0, END) file_open() elif MoEX == 0: messagebox.showinfo("Cảnh Báo","Bạn Chưa Mở Excel") def thanhtimkiem(): if MoEX == and MoEX_1 == 1: global Ten_Excel search_term = e_6.get() data_0 = pd.read_excel(Ten_Excel, dtype=str) data_1 = pd.read_excel("BanNhap.xlsx", dtype=str) if not search_term: # Trường hợp tìm kiếm rỗng, thêm dịng liệu vào Treeview my_tree_0.delete(*my_tree_0.get_children()) for index, row in data_0.iterrows(): my_tree_0.insert('', 'end', text=index, values=row.tolist()) my_tree_1.delete(*my_tree_1.get_children()) for index, row in data_1.iterrows(): my_tree_1.insert('', 'end', text=index, values=row.tolist()) # Trường hợp tìm kiếm khơng rỗng, lọc liệu theo cột Name data_0['Mã Sản Phẩm'] = data_0['Mã Sản Phẩm'].astype(str) data_1['Mã Sản Phẩm'] = data_1['Mã Sản Phẩm'].astype(str) search_result_0 = data_0[data_0['Mã Sản Phẩm'].str.contains(search_term, case=False)] search_result_1 = data_1[data_1['Mã Sản Phẩm'].str.contains(search_term, case=False)] # Xóa liệu cũ Treeview my_tree_0.delete(*my_tree_0.get_children()) my_tree_1.delete(*my_tree_1.get_children()) # Thêm liệu vào Treeview for index, row in search_result_0.iterrows(): my_tree_0.insert('', 'end', text=index, values=row.tolist()) for index, row in search_result_1.iterrows(): 77 my_tree_1.insert('', 'end', text=index, values=row.tolist()) else: messagebox.showinfo("Cảnh Báo","Bạn Chưa Mở Excel") def Nhan_enter_TK(event): thanhtimkiem() e_6.bind('', Nhan_enter_TK) def thanhtimkiem_window_2(): global Ten_Excel global e_8 global Mo_Thong_Ke global selected_date if Mo_Thong_Ke == 0: file_1 = pathlib.Path("ThongKe.xlsx") if Mo_Thong_Ke == 1: folder_path = pathlib.Path("DuLieu") file_1 = folder_path / pathlib.Path(selected_date + ".xlsx") if not file_1.exists(): messagebox.showerror("Lỗi","Ngày chọn khơng có liệu!") return search_term = e_8.get() data_0 = pd.read_excel(file_1, dtype=str) if not search_term: # Trường hợp tìm kiếm rỗng, thêm dịng liệu vào Treeview my_tree_2.delete(*my_tree_2.get_children()) for index, row in data_0.iterrows(): my_tree_2.insert('', 'end', text=index, values=row.tolist()) # Trường hợp tìm kiếm không rỗng, lọc liệu theo cột Name data_0['Mã Sản Phẩm'] = data_0['Mã Sản Phẩm'].astype(str) search_result_0 = data_0[data_0['Mã Sản Phẩm'].str.contains(search_term, case=False)] # Xóa liệu cũ Treeview my_tree_2.delete(*my_tree_2.get_children()) # Thêm liệu vào Treeview for index, row in search_result_0.iterrows(): my_tree_2.insert('', 'end', text=index, values=row.tolist()) def Nhan_enter_TK_2(event): 78 thanhtimkiem_window_2() def Chon_Bang_0(event): global e_1 global e_2 global e_3 global e_4 global e_7 e_1.delete(0, END) e_2.delete(0, END) e_3.delete(0, END) e_4.delete(0, END) e_7.delete(0, END) selected_item = my_tree_0.focus() values = my_tree_0.item(selected_item, "values") if values: e_1.delete(0, tk.END) e_1.insert(0, values[0]) # ID e_2.delete(0, tk.END) e_2.insert(0, values[1]) # MSP e_3.delete(0, tk.END) e_3.insert(0, values[3]) # Khu Vực e_4.delete(0, tk.END) e_4.insert(0, values[2]) # Tên sản phẩm e_7.delete(0, tk.END) e_7.insert(0, values[4]) # khối lượng # thêm phương thức bind để gọi hàm show_selected_item dòng Treeview chọn my_tree_0.bind("", Chon_Bang_0) def Sua_GT(): # Lấy dòng chọn selected_item = my_tree_0.focus() # Lấy giá trị Entry new_value1 = e_1.get() # ID new_value2 = e_2.get() # MSP new_value3 = e_3.get() # Khu Vực new_value4 = e_4.get() # Tên sản phẩm new_value5 = e_7.get() # Khối lượng 79 my_tree_0.item(selected_item, values=(new_value1, new_value2, new_value4, new_value3, new_value5)) e_1.delete(0, END) e_2.delete(0, END) e_3.delete(0, END) e_4.delete(0, END) e_7.delete(0, END) Luu_Khung() file_open() def Xoa_Dong(): selected_items = my_tree_0.selection() if len(selected_items) == 0: messagebox.showerror("Lỗi", "Vui lòng chọn dịng để xóa!") return Xoa = messagebox.askquestion("Thơng Báo", "Bạn có muốn xóa dịng chọn khơng!") if Xoa == "yes": e_1.delete(0, END) e_2.delete(0, END) e_3.delete(0, END) e_4.delete(0, END) e_7.delete(0, END) for selected_item in selected_items: my_tree_0.delete(selected_item) Luu_Khung() else: return def Bang_moi(): Xoa_Het = messagebox.askquestion("Cảnh Báo","Chưa hết ngày, bạn tạo liệu lưu ngày mất?") if Xoa_Het == "yes": my_tree_1.delete(*my_tree_1.get_children()) Luu_Khung_1() Thong_Ke() else: return def Xuat_File_Excel(): global Mo_Thong_Ke global selected_date 80 if Mo_Thong_Ke == 0: file_1 = pathlib.Path("ThongKe.xlsx") if Mo_Thong_Ke == 1: folder_path = pathlib.Path("DuLieu") file_1 = folder_path / pathlib.Path(selected_date + ".xlsx") file = filedialog.asksaveasfile(mode='wb', defaultextension=".xlsx") if file: file_path = file.name shutil.copy(file_1, file_path) # Tạo thư mục chọn file.close() messagebox.showinfo("Thông báo", "Xuất file thành công!") def Bieu_Do(): global Mo_Thong_Ke global selected_date if Mo_Thong_Ke == 0: file_1 = pathlib.Path("ThongKe.xlsx") if Mo_Thong_Ke == 1: folder_path = pathlib.Path("DuLieu") file_1 = folder_path / pathlib.Path(selected_date + ".xlsx") df=pd.read_excel(file_1, dtype=str) clear_tree_2() my_tree_2["column"] =list(df.columns) my_tree_2["show"] ="headings" for column in my_tree_2["column"]: my_tree_2.heading(column,text=column) df_rows = df.to_numpy().tolist() for row in df_rows: my_tree_2.insert("","end",values=row) my_tree_2.pack() my_tree_2.column("ID", width=40) my_tree_2.column("Mã Sản Phẩm", width=100) my_tree_2.column("Tên Sản Phẩm", width=160) my_tree_2.column("Khu Vực", width=80) my_tree_2.column("Khối Lượng Thật", width=100) my_tree_2.column("Thời Gian Nhận", width=120) my_tree_2.column("Tình Trạng", width=80) 81 order_counts = df['Khu Vực'].value_counts() fig, ax = plt.subplots(facecolor='#EEEEEE') patches, _ = ax.pie(order_counts, labels=order_counts.index, radius=0.3) for wedge, count in zip(patches, order_counts): angle = (wedge.theta2 - wedge.theta1) / + wedge.theta1 radius = 0.5 * wedge.r x = wedge.center[0] + radius * math.cos(math.radians(angle)) y = wedge.center[1] + radius * math.sin(math.radians(angle)) ax.text(x, y, str(count), ha='center', va='center') BD_KVuc = Canvas(window_2, width=260, height=150) BD_KVuc.place(x=740, y=45) # Nhúng biểu đồ vào Tkinter canvas chart = FigureCanvasTkAgg(fig, master=BD_KVuc) chart.draw() chart_widget = chart.get_tk_widget() BD_KVuc.create_window(130, 80, window=chart_widget) ##################################################################### ####################################################### order_counts_1 = df['Khối Lượng Thật'].value_counts() fig_1, ax_1 = plt.subplots(facecolor='#EEEEEE') patches_1, _ = ax_1.pie(order_counts_1, labels=order_counts_1.index, radius=0.6) for wedge_1, count_1 in zip(patches_1, order_counts_1): angle_1 = (wedge_1.theta2 - wedge_1.theta1) / + wedge_1.theta1 radius_1 = 0.5 * wedge_1.r distance_from_center = 0.2 # Điều chỉnh khoảng cách từ tâm đường tròn x_1 = wedge_1.center[0] + (radius_1 + distance_from_center) math.cos(math.radians(angle_1)) y_1 = wedge_1.center[1] + (radius_1 + distance_from_center) math.sin(math.radians(angle_1)) ax_1.text(x_1, y_1, str(count_1), ha='center', va='center') BD_KLuongThat = Canvas(window_2, width=260, height=220) BD_KLuongThat.place(x=740, y=260) # Nhúng biểu đồ vào Tkinter canvas chart_1 = FigureCanvasTkAgg(fig_1, master=BD_KLuongThat) chart_1.draw() 82 * * chart_widget_1 = chart_1.get_tk_widget() BD_KLuongThat.create_window(130, 110, window=chart_widget_1) ##################################################################### ####################################################### order_counts_2 = df['Tình Trạng'].value_counts() BD_TTrang = Canvas(window_2, width=230, height=230, bg="#EEEEEE") BD_TTrang.place(x=1030, y=70) # Vẽ trục x x_2 = 10 y_2 = 200 BD_TTrang.create_line(x_2, y_2, x_2 + 155, y_2) BD_TTrang.create_text(x_2 + 185, y_2 - 10, text="Trạng thái", anchor=N) # Vẽ trục y BD_TTrang.create_line(x_2, y_2, x_2, y_2 - 170) BD_TTrang.create_text(x_2 + 40, y_2 - 180, text="Số lượng", anchor=E) # Vẽ biểu đồ cột bar_width = 40 x_2 += 25 # Dịch chuyển vị trí bắt đầu cột để tránh việc chồng chéo với trục y max_height = 180 # Giới hạn chiều cao tối đa cột for i, (order_type_2, count_2) in enumerate(order_counts_2.iteritems()): x_22 = x_2 + i * (bar_width + 30) y_bottom = y_2 y_top = max(y_bottom - count_2 * 5, y_bottom - max_height) # Giới hạn chiều cao cột BD_TTrang.create_rectangle(x_22, y_bottom, x_22 + bar_width, y_top, fill='blue') BD_TTrang.create_text(x_22 + bar_width // 2, y_top - 15, anchor=N, text=str(count_2)) BD_TTrang.create_text(x_22 + bar_width // 2, y_bottom + 5, anchor=N, text=order_type_2, angle=0) def Chon_Ngay(): global selected_date global Lich selected_date = Lich.selection_get().strftime("%d %b %Y") print(selected_date) # Thực xử lý với ngày chọn Kho_Theo_Ngay() 83 Bieu_Do() def Kho_Theo_Ngay(): global Mo_Thong_Ke Mo_Thong_Ke = def Kho_Tong(): global Mo_Thong_Ke Mo_Thong_Ke = Bieu_Do() def reset(): client.write_register(6, 1, unit=UNIT) client.write_register(6, 0, unit=UNIT) def Chay_code(): client.write_register(0, 1, unit=UNIT) client.write_register(0, 0, unit=UNIT) def Dung_code(): global So_Thuc client.write_register(1, 1, unit=UNIT) client.write_register(1, 0, unit=UNIT) def Nut_Nhan(): Run = customtkinter.CTkButton(window,width=20 ,text="Chạy", text_color='black',fg_color="green",corner_radius=10,command = Chay_code) Run.place(x=10, y=730) Stop = customtkinter.CTkButton(window,width=20 ,text="Dừng", text_color='black',fg_color="red",corner_radius=10, command = Dung_code) Stop.place(x=80, y=730) nut_reset = customtkinter.CTkButton(window,width=20 ,text="Reset", text_color='black',fg_color="orange",corner_radius=10,command = reset) nut_reset.place(x=150, y=730) Them = customtkinter.CTkButton(window,width=15 ,text="Thêm Sản Phẩm", text_color='black',fg_color="#85cbf8", image= HIcon_3,corner_radius=10,command=ThemSP) Them.place(x=680, y=730) Sua = customtkinter.CTkButton(window,width=15 84 ,text="Sửa Sản Phẩm", text_color='black',fg_color="#f16953", HIcon_5,corner_radius=10,command=Sua_GT) Sua.place(x=850, y=730) image= Xoa = customtkinter.CTkButton(window,width=5 ,text="Xóa Sản Phẩm", text_color='black', fg_color="#f16953",image= HIcon_6,corner_radius=10,command=Xoa_Dong) Xoa.place(x=1010, y=730) Xoa_all = customtkinter.CTkButton(window,width=5 ,text="Tạo Bảng Mới", text_color='black', fg_color="#c3e2f8",image= HIcon_3,corner_radius=10,command=Bang_moi) Xoa_all.place(x=1250, y=730) TimKiem = customtkinter.CTkButton(window,text="Tìm",width= 10,command=thanhtimkiem,image= HIcon_2,text_color="black", fg_color="#85cbf8",corner_radius=10) TimKiem.place(x=1305, y=418) Mo_Tep_Excel = customtkinter.CTkButton(window,text="Mở Tệp Excel",command = open_excel, image= HIcon_1, fg_color= "#f8da61",corner_radius=10,text_color="black") Mo_Tep_Excel.place(x=1395,y=125) Xuat_Tep_Excel = customtkinter.CTkButton(window,text="Xuất Tệp Excel",command = save_as, image= HIcon_4, fg_color= "#28be7d",corner_radius=10,text_color="black") Xuat_Tep_Excel.place(x=1395,y=160) Thong_Ke_CT = customtkinter.CTkButton(window,text="Chi Tiết",command = Mo_TKCT, image= HIcon_7, fg_color= "#c3e2f8",corner_radius=10,text_color="black") Thong_Ke_CT.place(x=1395,y=195) Nut_Nhan() running = True def GT_PLC(): global Thanh_ghi_8 while running: # Các lệnh đọc giá trị từ PLC Thanh_ghi_8 = client.read_holding_registers(8, 1, unit=UNIT) # Đẩy Miền Trung 85 # Tạo đối tượng Thread thực thi GiaoTiep_PLC = threading.Thread(target=GT_PLC) GiaoTiep_PLC.start() class CameraApp: def init (self, window): self.window = window self.cap = cv2.VideoCapture(1) self.canvas = tk.Canvas(window, width=630, height=470,bg='black',highlightthickness=1, highlightbackground='black') self.canvas.place(x=10,y=150) self.update() def update(self): global thoigian global NTN = date.today() #ngày tháng = NTN.strftime("%d %B %Y") t = time.localtime() #phút giây thoigian = time.strftime("%H:%M:%S", t) ret, frame = self.cap.read() result = model(frame)[0] detections = sv.Detections.from_yolov8(result) detections = detections[detections.class_id >= 0] global dem global MaVach global MaVach_1 global Chup global MoEX global Tep_Luu_Anh if (detections.class_id == 1).any(): global Bi_Rach Bi_Rach = elif (detections.class_id != 1).any(): Bi_Rach = if (detections.class_id == 0).any(): for barcode in decode(frame): #nhận diện mã vạch MV = barcode.data.decode('utf-8') pts = np.array([barcode.polygon], np.int32) 86 pts = pts.reshape((-1, 1, 2)) cv2.polylines(frame, [pts], True, (255, 0, 255), 5) MaVach = MV Lay_GT() Chup = if Chup == 1: filename = f"{Tep_Luu_Anh}/MV_{MV}.jpg" cv2.imwrite(filename, frame) MaVach_1 = MV Chup = Tu_Mo_Excel() labels = [ f"{model.model.names[class_id]}{confidence:0.2f}" for _, confidence, class_id, _ in detections ] frame = box_annotator.annotate(scene=frame, labels=labels) detections=detections, cv2.putText(frame,str(MaVach),(10,30),cv2.FONT_HERSHEY_SIMPLEX,1,(0, 0, 255),1) if ret: self.photo ImageTk.PhotoImage(image=Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))) self.canvas.create_image(0, 0, anchor=tk.NW, image=self.photo) HNT = Label(window,text='',bg='white',font=("Times Roman",16),fg='black') HNT.place(x=300, y=730) = New TG = Label(window,text='',bg='white',font=("Times New Roman",16),fg='black') TG.place(x=500,y=730) HNT.configure(text=ngay) TG.configure(text=thoigian) global Bac global Trung global Nam global BiRach global Hang_loi 87 if BiRach == 1: client.write_register(2, 1, unit=UNIT) client.write_register(2, 0, unit=UNIT) BiRach = if Hang_loi == 1: client.write_register(2, 1, unit=UNIT) client.write_register(2, 0, unit=UNIT) Hang_loi = if Bac == 1: client.write_register(3, 1, unit=UNIT) client.write_register(3, 0, unit=UNIT) Bac = if Trung == 1: client.write_register(4, 1, unit=UNIT) client.write_register(4, 0, unit=UNIT) Trung = if Nam == 1: client.write_register(5, 1, unit=UNIT) client.write_register(5, 0, unit=UNIT) Nam = self.window.after(15, self.update) def del (self): if self.cap.isOpened(): self.cap.release() app = CameraApp(window) window.mainloop() 88