You are on page 1of 27

ĐẠI HỌC CÔNG NGHỆ -ĐẠI HỌC QUỐC GIA HÀ NỘI

==== *** ====

BÀI TẬP LỚN


Đề tài: Điều khiển cánh tay robot 4 bậc tự do bằng xử lý ảnh bàn
tay và bằng bàn phím

GIÁO VIÊN HƯỚNG DẪN: Đỗ Trần Thắng


SINH VIÊN THỰC HIỆN:
Họ và tên Mã sinh viên
Nguyễn Văn Sơn 20020599
Mục lục

I. GIỚI THIỆU CHUNG..........................................................................................2


II. Cơ sở lý thuyết........................................................................................................2
1. Hand tracking trong thư viện Mediapipe (Module tri thức)..................................................................2
2. Thực hiện tính toán để điều khiển cánh tay robot (Module suy luận)...................................................3
III. Tổng quan...............................................................................................................4
1. Cấu tạo....................................................................................................................4
1.1. Khung cánh tay.............................................................................................................................4
1.2. Động cơ servo SG90.....................................................................................................................4
1.3. Camera..........................................................................................................................................6
2. Các thiết bị điều khiển..........................................................................................................................6
2.1. Arduino UNO R3..........................................................................................................................6
2.2. Python trên ứng dụng Visual Studio Code....................................................................................8
IV. Thiết lập phần cứng...............................................................................................8
V. Lập trình.................................................................................................................9
1. Truyền dữ liệu từ python sang Arduino bằng cổng serial.....................................................................9
3. Lập trình trên Arduino........................................................................................................................11
4. Lập trình trên Python..........................................................................................................................14
4.1. Xây dựng công tắc chuyển giữa chế độ điều khiển bằng phím và điều khiển bằng hình ảnh...........14
4.2. Xây dựng giao diện điều khiển bằng nút bằng thư viện pygame.................................................16
4.3. Điều khiển cánh tay robot bằng xử lý ảnh...................................................................................20
VI. Kết luận.................................................................................................................26
VII. Tài liệu tham khảo........................................................................................26

1
I. GIỚI THIỆU CHUNG
Xử lý ảnh sử dụng trí tuệ nhân tạo (AI) là một lĩnh vực nghiên cứu phát triển nhanh
chóng trong thời gian gần đây, cho phép máy tính "nhìn" và "hiểu" hình ảnh một cách tự
động. Sử dụng các thuật toán học máy và mạng nơ-ron sâu, các hệ thống xử lý ảnh AI có
khả năng phát hiện, phân tích và nhận dạng các đối tượng, hình dạng và chủ đề trong ảnh
một cách tự động và chính xác.

Trong bài báo cáo này, em sử dụng tính năng hand tracking trong thư viện mediapipe
trên python để điều khiển cách tay robot 4 bậc tự do. MediaPipe là một thư viện mã nguồn
mở của Google, cung cấp các công cụ cho phép phát hiện và theo dõi các đối tượng, chẳng
hạn như khuôn mặt, tay, vật thể và các hành động. Trong đó, hand tracking là một kỹ thuật
được sử dụng để phát hiện và theo dõi vị trí và hành động của tay và ngón tay của con người
trong không gian 3D.

Việc điều khiển cánh tay robot 4 bậc bằng hand tracking sẽ yêu cầu một mô hình hand
tracking chính xác để xác định vị trí và hành động của tay và ngón tay của người dùng. Sau
đó, các thông tin về vị trí và hành động này sẽ được chuyển đến Arduino thông qua cổng
serial để điều khiển robot. Ngoài ra em có làm thêm phần điều khiển bằng bàn phím để điều
khiển trong các trường hợp đòi hỏi tính chính xác cao.

Một số ứng dụng của việc điều khiển cánh tay robot bằng hand tracking có thể là trong
lĩnh vực y tế, giúp người khuyết tật có thể điều khiển các bộ phận của robot để thực hiện các
hoạt động hàng ngày, hoặc trong lĩnh vực công nghiệp, giúp người lao động tránh được các
tình huống nguy hiểm hoặc vượt qua những khó khăn trong việc điều khiển robot, ...

II. Cơ sở lý thuyết
1. Hand tracking trong thư viện Mediapipe (Module tri thức)
Bộ mô hình Hand Landmark phát hiện các điểm đánh dấu trên bàn tay bao gồm 21 tọa
độ khớp ngón tay trong các khu vực bàn tay được phát hiện. Mô hình được huấn luyện trên
khoảng 30.000 hình ảnh thực tế và một số mô hình bàn tay tổng hợp được áp dụng trên
nhiều nền khác nhau.

2
Hình 1: 21 tọa độ trên tay được xác định

Bộ mô hình Hand Landmark chứa một mô hình phát hiện lòng bàn tay và một mô hình
phát hiện các điểm đánh dấu trên bàn tay. Mô hình phát hiện lòng bàn tay xác định vị trí của
bàn tay trong hình ảnh đầu vào, và mô hình phát hiện các điểm đánh dấu trên bàn tay nhận
dạng các điểm đánh dấu cụ thể trên hình ảnh bàn tay đã được cắt bởi mô hình phát hiện lòng
bàn tay.

Vì mô hình phát hiện lòng bàn tay mất thời gian, khi chạy trong chế độ video hoặc live
stream, Hand Landmarker sử dụng hộp giới hạn được xác định bởi mô hình điểm đánh dấu
trên bàn tay trong một khung hình để xác định khu vực bàn tay cho các khung hình tiếp
theo. Hand Landmarker chỉ kích hoạt lại mô hình phát hiện lòng bàn tay nếu mô hình điểm
đánh dấu trên bàn tay không còn nhận ra sự hiện diện của bàn tay hoặc không thể theo dõi
các bàn tay trong khung hình. Điều này giảm số lần Hand Landmarker kích hoạt mô hình
phát hiện lòng bàn tay.

2. Thực hiện tính toán để điều khiển cánh tay robot (Module suy luận)
Ta điều khiển cánh tay 4 bậc bằng 4 servo (x, y, z, t). Chạy mô hình trên thực tế ta xác
định các góc của các bậc cánh tay robot có thể di chuyển được tương ứng với các góc của
servo được thống kê theo bảng sau:

Servo Vùng hoạt động


servo_x 0-180 deg
servo_y 0-80 deg
servo_z 50-120 deg
servo_t 60-130 deg
Bảng 1: Vùng hoạt động được của các servo

Góc quay của servo_x và servo_y phụ thuộc vào tọa độ của [x,y] của điểm 5 (được thể
hiện tại hình 1) trên bàn tay.

3
Với góc quay của servo_z ta dựa vào khoảng cách giữa đầu ngón tay cái và ngón tay
trỏ tương ứng với điểm 4 và 8. Nhận thấy khoảng cách giữa 2 điểm 5 và 17 gần như không
đổi trên bàn tay khi chuyển động. Nội suy giá trị tỷ lệ giữa khoảng cách giữa 2 điểm 4 và 8,
5 và 17 từ khoảng [20,220] sang khoảng hoạt động của servo_z [50,120] ta thu được góc
quay của servo_z.

Tương tự servo_z, nội suy giá trị tỷ lệ giữa khoảng cách giữa 2 điểm 16 và 0, 5 và 17
từ khoảng [20,220] sang khoảng hoạt động của servo_t [60,130] ta thu được góc quay của
servo_t.

III. Tổng quan


1. Cấu tạo
Cánh tay robot được xây dựng bao gồm có các thành phần:

1.1. Khung cánh tay


Khung cánh tay robot được chế tạo từ các chi tiết nhỏ được in 3D bằng nhựa PLA với
độ chính xác tương đối cao.

Hình 2: Khung cánh tay robot

1.2. Động cơ servo SG90


Cánh tay robot sử dụng 4 động cơ servo SG90 (servo_x, servo_y, servo_z, servo_t)
tương ứng với 4 bậc của cánh tay. Động cơ servo SG90 180 độ có tốc độ phản ứng nhanh,
có tích hợp sẵn Driver điều khiển động cơ bên trong nên có thể dễ dàng điều khiển góc quay
bằng phương pháp điều độ rộng xung PWM.

4
Thông số kỹ thuật:
Điện áp hoạt động : 4.8~5VDC
Tốc độ: 0.12 sec/60 deg (4.8VDC)
Lực kéo: 1.6 Kg.cm
Kích thước: 21x12x22mm
Trọng lượng: 9g
Phương pháp điều khiển PWM:
Độ rộng xung 0.5ms ~ 2.5ms
tương ứng 0 -180 độ
Tần số 50HZ, chu kỳ 20ms

Hình 3: Động cơ servo SG90

Mỗi servo điều khiển 1 bậc được biểu diễn ở trên hình:

Hình 4: Vị trí các động cơ servo


5
Servo_x Điều khiển cánh tay quay trái/phải.
Servo_y Điều khiển trục cánh tay đi lên/xuống.
Servo_z Điều chỉnh bộ phận đóng/mở gắp
Servo_t Điểu khiển lên/xuống trục đỡ bộ phận gắp
Bảng 2: Bảng điều khiển các động cơ servo

1.3. Camera
Trong nghiên cứu này em sử dụng camera laptop có độ phân giải 720p tương ứng với khung
hình 1280x720 pixel để xử lý ảnh bàn tay.

Hình 5: Camera laptop

2. Các thiết bị điều khiển


2.1. Arduino UNO R3

Hình 6: Bo mạch Arduino Uno R3

Thông số kĩ thuật

Điện áp hoạt động 5V DC (chỉ được cấp qua cổng USB)

6
Tần số hoạt động 16 MHz

Dòng tiêu thụ khoảng 30mA

Điện áp vào khuyên dùng 7-12V DC

Điện áp vào giới hạn 6-20V DC

Số chân Digital I/O 14 (6 chân hardware PWM)

Số chân Analog 6 (độ phân giải 10bit)

Dòng tối đa trên mỗi chân I/O 30 mA

Dòng ra tối đa (5V) 500 mA

Dòng ra tối đa (3.3V) 50 mA

32 KB (ATmega328) với 0.5KB dùng bởi


Bộ nhớ flash
bootloader

SRAM 2 KB (ATmega328)

EEPROM 1 KB (ATmega328)

Arduino là một nền tảng mã nguồn mở được sử dụng để xây dựng các ứng dụng điện
tử tương tác với nhau hoặc với môi trường được thuận lợi hơn.

Arduino giống như một máy tính nhỏ để người dùng có thể lập trình và thực hiện các
dự án điện tử mà không cần phải có các công cụ chuyên biệt để phục vụ việc nạp code.
Arduino tương tác với thế giới thông qua các cảm biến điện tử, đèn, và động cơ.

Arduino gồm:

- Phần cứng gồm một board mạch mã nguồn mở (thường gọi là vi điều khiển): có thể
lập trình được.
- Các phần mềm hỗ trợ phát triển tích hợp IDE (Integrated Development Environment)
dùng để soạn thảo, biên dịch code và nạp chương cho board.

7
2.2. Python trên ứng dụng Visual Studio Code
Báo cáo sử dụng Python trên Visual Studio Code để lập trình và gửi tín hiệu từ máy
tính sang Arduino. Visual Studio Code là một ứng dụng mã nguồn mở được phát triển bởi
Microsoft. Nó là một trình soạn thảo mã hoàn toàn miễn phí và hỗ trợ nhiều ngôn ngữ lập
trình khác nhau như C++, C#, Java, Python, JavaScript, HTML, CSS và nhiều ngôn ngữ
khác. Visual Studio Code cung cấp cho người dùng một giao diện thân thiện, linh hoạt và có
tính tùy biến cao.

Hình 7: Python trên Visual Studio Code

IV. Thiết lập phần cứng


- 4 động cơ servo có Vcc, GND được nối với nguồn 5v và GND của Arduino thông
qua Test Board.

- Các chân tín hiệu của 4 động cơ servo (servo_x, servo_y, servo_z, servo_t) lần lượt
được nối với các chân 9, 10, 5, 6 của Arduino.

- Arduino được kết nối với laptop thông qua dây serial.

8
Hình 8: Sơ đồ nối mạch

V. Lập trình
1. Truyền dữ liệu từ python sang Arduino bằng cổng serial
Để truyền dữ liệu từ Python sang Arduino ta sử dụng thư viện serial. Ta sẽ gửi góc của
4 servo dưới dạng chuỗi ký tự có dạng “x-y-z-t\r” với x, y, z, t lần lượt là 4 góc của 4 servo,
“\r” là ký tự để phân tách các chuỗi.

import serial #khai báo thư viện serial

ser = serial.Serial('COM5', 9600) #Mở cổng kết nối với Arduino


#Giá trị cần gửi
pos_x = 90
pos_y = 40
pos_z = 85
pos_t = 95
#Chuyển dữ liệu cần gửi sang dạng string
stringX = str(pos_x)
stringY = str(pos_y)

9
stringZ = str(pos_z)
stringT = str(pos_t)
#Chuyển các dữ liệu cần gửi thành 1 chuỗi cách nhau bằng dấu "-"
#Ký tự "\r" để phân cách chuỗi
string1 = stringX + "-" + stringY + "-" + stringZ + "-" + stringT + "\r"
ser.write(string1.encode()) # Mã hóa sang dạng Byte để gửi sang Arduino
Như ví dụ trên Arduino sẽ nhận được chuỗi ký tự có dạng “90-40-85-95\r”.

Với Arduino: Mở cổng giao tiếp với Baudrate là 9600, nếu có tín hiệu từ Python gửi
sang sẽ đọc đến kí tự ‘\r’.

Arduino sẽ nhận được chuỗi ký tự là “90-40-85-95”. Để chuyển chuỗi này thành 4 giá
trị số nguyên và lưu vào mảng num ta thực hiện:

10
- Đầu tiên ta sẽ tách một chuỗi có định dạng "số-số-số-số" thành các số nguyên và lưu
vào mảng num:
 Chuỗi cần được tách theo dấu "-" bằng cách sử dụng biến delimiter.
 Một biến pos được sử dụng để lưu vị trí của dấu "-" đầu tiên được tìm thấy trong
chuỗi. Nếu không tìm thấy dấu "-" nào, pos sẽ được gán giá trị -1.
 Biến token được sử dụng để lưu trữ phần tử con chuỗi giữa các dấu "-" được tìm
thấy. Phương thức substring() được sử dụng để trích xuất phần tử con này từ vị trí 0
đến vị trí pos-1.
 Số nguyên được chuyển đổi từ chuỗi thành số nguyên bằng cách sử dụng phương
thức toInt() và được lưu vào mảng num bằng cách sử dụng biến i.
 Sau đó, chuỗi được cắt bớt từ vị trí pos + chiều dài của delimiter để loại bỏ phần tử
con vừa được tìm thấy. Việc này được thực hiện bằng cách sử dụng phương thức
substring() một lần nữa trên chuỗi còn lại.
- Tiếp đó chuyển đổi một chuỗi số thành một số nguyên.
 Vòng lặp for được sử dụng để lặp lại từng ký tự trong chuỗi rpi.
 Giá trị số nguyên của mỗi ký tự được tính bằng cách trừ đi mã ASCII của ký tự '0'.
 Kết quả được tính bằng cách nhân 10 kết quả hiện tại với 10 và cộng thêm giá trị số
nguyên của ký tự hiện tại.
Cuối cùng ta sẽ thu được các giá trị của các servo x, y ,z, t được lưu vào mảng num
với các giá trị num[0] = 90, num[1] = 40, num[2] = 85, num[3] = 95.

3. Lập trình trên Arduino


Sơ đồ khối:

11
Hình 9: Sơ đồ khối code trên Arduino

Code:
Khai báo các chân kết nối và
các biến dùng trong bài.

Sau khi khai báo chân, mở


cổng baudrate 9600, ta setup
chức năng của các chân và
khai báo các giá trị ban đầu
cho các servo.

12
Trong vòng loop, với các giá
trị nhận được từ Python,
Arduino sẽ điều khiển các
servo.

13
4. Lập trình trên Python

Hình 10: Sơ đồ khối chương trình điều khiển

4.1. Xây dựng công tắc chuyển giữa chế độ điều khiển bằng phím và điều khiển bằng
hình ảnh
Code:

from tkinter import *


is_on = False
window=Tk()
window.title('Chương trình điều khiển cánh tay robot')
window.geometry('600x300+400+100')
my_label = Label(window,
text="Hình ảnh - Bằng tay",
fg="green",
font=("Helvetica", 32))
my_label.pack()

# tải hỉnh ảnh nút ấn


on = PhotoImage(file="images/on.png")
off = PhotoImage(file="images/off.png")
def switch():
global is_on
if is_on:
on_button.config(image=off)
is_on = False
#code điều khiển bằng hình ảnh

else:
on_button.config(image=on)
14
is_on = True
#code điều khiển bằng nút bấm

on_button = Button(window, image=off, bd=0,command=switch)


on_button.pack(pady=50)
window.mainloop()

Em sử dụng thư viện tkinter của Python để tạo một giao diện đơn giản cho việc điều khiển
cánh tay robot. Cụ thể:

- Dòng đầu tiên sử dụng từ khóa import để nhập toàn bộ module tkinter.
- Biến is_on được khởi tạo với giá trị False.
- Dòng window=Tk() tạo một đối tượng Tk (cửa sổ chính) để tạo ra giao diện.
- window.title() được sử dụng để đặt tiêu đề cho cửa sổ chính.
- window.geometry() được sử dụng để thiết lập kích thước cửa sổ chính (600x300) và
vị trí của cửa sổ trên màn hình (400, 100).
- my_label=Label(window, text="Hình ảnh - Bằng tay", fg="green",
font=("Helvetica", 32)) tạo một nhãn (label) để hiển thị một dòng văn bản trên cửa
sổ. Dòng văn bản này có màu xanh lá cây và được sử dụng font "Helvetica" với kích
thước 32.
- my_label.pack() đưa nhãn vào cửa sổ.
- Dòng on = PhotoImage(file="images/on.png") tạo một đối tượng hình ảnh từ tập
tin "on.png" trong thư mục "images".
- Tương tự, dòng off = PhotoImage(file="images/off.png") tạo một đối tượng hình
ảnh từ tập tin "off.png" trong thư mục "images".
- Hàm switch() được định nghĩa để thay đổi trạng thái của nút bấm và thực hiện các
hành động tương ứng với mỗi trạng thái. Biến is_on được sử dụng để lưu trữ trạng
thái hiện tại của nút.
- on_button = Button(window, image=off, bd=0,command=switch) tạo một nút
bấm trên cửa sổ chính, được thiết lập bằng hình ảnh "off.png" và được đặt tên là
on_button. Tham số bd=0 được sử dụng để loại bỏ khung viền xung quanh nút.
- on_button.pack(pady=50) đưa nút bấm vào cửa sổ chính, với một khoảng cách 50
pixel giữa nút và nhãn.
- window.mainloop() là vòng lặp chính của chương trình, giúp hiển thị cửa sổ và chờ
đợi người dùng tương tác với giao diện. Khi người dùng đóng cửa sổ sẽ kết thúc
vòng lặp.

Kết quả chạy:

15
Hình 11: Kết quả chạy công tắc chuyển đổi chế độ

4.2. Xây dựng giao diện điều khiển bằng nút bằng thư viện pygame

Hình 12: Sơ đồ khối điều khiển bằng nút bấm

Code:
import pygame
import serial
import time

# Khởi tạo kết nối với Arduino


ser = serial.Serial('COM5', 9600)

# Khởi tạo giao diện đồ họa


pygame.init()
screen = pygame.display.set_mode((400, 400))
16
pygame.display.set_caption('Robot Arm Control')

#Khai báo giá trị góc quay của các servo ban đầu
pos_x = 90
pos_y = 40
pos_z = 85
pos_t = 95

# Vòng lặp chính


while True:
# Xử lý các sự kiện từ bàn phím và chuột
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()

# Xử lý các sự kiện từ bàn phím


keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
if pos_y <= 80:
pos_y = pos_y + 10
elif keys[pygame.K_DOWN]:
if pos_y >= 0:
pos_y = pos_y - 10

if keys[pygame.K_LEFT]:
if pos_x >= 0:
pos_x = pos_x - 10
elif keys[pygame.K_RIGHT]:
if pos_x <= 180:
pos_x = pos_x + 10

if keys[pygame.K_s]:
if pos_t >= 60:
pos_t = pos_t - 10
elif keys[pygame.K_w]:
if pos_t <= 130:
pos_t = pos_t + 10

if keys[pygame.K_a]:
if pos_z >= 50:
pos_z = pos_z - 10
elif keys[pygame.K_d]:
if pos_z <= 120:
pos_z = pos_z + 10
if keys[pygame.K_q]:
pygame.quit()

break

# Vẽ giao diện đồ họa


17
screen.fill((255, 255, 255))
pygame.draw.line(screen, (255, 0, 0), (200, 0), (200, 400), 2)
pygame.draw.line(screen, (255, 0, 0), (0, 200), (400, 200), 2)
pygame.display.update()

# Gửi tín hiệu sang Arduino


stringX = str(pos_x)
stringY = str(pos_y)
stringZ = str(pos_z)
stringT = str(pos_t)
string1 = stringX + "-" + stringY + "-" + stringZ + "-" + stringT + "\r"
ser.write(string1.encode())
time.sleep(0.1)

Sau khi khởi tạo giao diện bằng thư viện pygame. Với các giá trị nhập vào từ bàn phím
thì ta có các góc quay của servo tương ứng được biển diễn thông qua sơ đồ khối.

Kết quả chạy:

Hình 12: Giao diện chạy điều khiển bằng nút thư viện Pygame
Video chạy:

18
Nếu thầy không xem được thì thầy có thể vào theo link sau ạ:
Điều khiển cánh tay robot 4 bậc bằng bàn phím - Nhập môn điều khiển thông
minh - YouTube

19
4.3. Điều khiển cánh tay robot bằng xử lý ảnh

Hình 13: Sơ đồ khối điều khiển bằng hình ảnh bàn tay
Code:

import cv2
import mediapipe as mp
import numpy as np
import math
import serial

#Mở cổng kết nối với Arduino


ser = serial.Serial('COM5', 9600)

#Định nghĩa hai đối tượng mpHand và mpDraw, được sử dụng để nhận dạng bàn tay và vẽ
đường bản tay trong ảnh hoặc video.
mpHand = mp.solutions.hands
mpDraw = mp.solutions.drawing_utils

#Tạo ra đối tượng "hands" (bàn tay) dựa trên lớp Hand của mpHand và đặt
min_detection_confidence=0.8 để đảm bảo rằng chỉ có những bàn tay có độ tin cậy
trên 80% mới được phát hiện.
hands = mpHand.Hands(min_detection_confidence=0.8)
20
#Thiết lập video capture từ camera mặc định với kích thước khung hình là 1280x720
pixel
cap = cv2.VideoCapture(0)
ws, hs = 1280, 720
cap.set(3, ws)
cap.set(4, hs)

min_rat, max_rat = 20, 220 #tỷ lệ


min_per, max_per = 0, 100 #phần trăm

#Giới hạn góc quay của các servo


min_outx, max_outx = 0, 180
min_outy, max_outy = 0, 80
min_outz, max_outz = 50, 120
min_outt, max_outt = 60, 130

#Hàm tính toán khoảng cách


def calculateDistance(pos_1, pos_2):
length = math.hypot(pos_1[0] - pos_2[0], pos_1[1] - pos_2[1])
return length

while cap.isOpened():
success, img = cap.read() #Đọc hình ảnh
img = cv2.flip(img, 1) #Lật ảnh
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) #Chuyển đổi định dạng ảnh từ BGR
sang RGB
results = hands.process(img)
img = cv2.cvtColor(img,cv2.COLOR_RGB2BGR)

multiHandDetection = results.multi_hand_landmarks #Hand Detection


xList, yList, lmList = [], [], []

if multiHandDetection:
# Trực quan hóa bàn tay bằng cách vẽ các đường đặc trưng và đường nối giữa
chúng trên ảnh
for id, lm in enumerate(multiHandDetection):
mpDraw.draw_landmarks(img, lm, mpHand.HAND_CONNECTIONS,
mpDraw.DrawingSpec(color=(0, 255,255), thickness=4,
circle_radius=7),
mpDraw.DrawingSpec(color=(0, 0, 0), thickness = 4))

#Hand Tracking
singleHandDetection = multiHandDetection[0] # Xác định 1 bàn tay
#Lấy tọa độ các điểm trên bàn tay
for lm in singleHandDetection.landmark:
h, w, c = img.shape
lm_x, lm_y = int(lm.x*w), int(lm.y*h)
lmList.append([lm_x, lm_y])
xList.append(lm_x)

21
yList.append(lm_y)
x_min, y_min = min(xList), min(yList)
x_max, y_max = max(xList), max(yList)
w_box, h_box = x_max - x_min, y_max - y_min

#Vẽ khung bao bàn tay


cv2.rectangle(img, (x_min - 20, y_min - 20), (x_min + w_box + 20, y_min +
h_box + 20),(0, 0, 0), 4)
cv2.rectangle(img, (x_min - 22, y_min - 20), (x_min + w_box + 22, y_min -
60),(0, 0, 0), cv2.FILLED)

# Vẽ điểm 5
myLP5 = lmList[5]
px5, py5 = myLP5[0], myLP5[1]
cv2.circle(img, (px5, py5), 15, (255, 0, 255), cv2.FILLED)

# Vẽ điểm 8
myLP8 = lmList[8]
px8, py8 = myLP8[0], myLP8[1]
cv2.circle(img, (px8, py8), 15, (255, 0, 255), cv2.FILLED)

# Vẽ điểm 4
myLP4 = lmList[4]
px4, py4 = myLP4[0], myLP4[1]
cv2.circle(img, (px4, py4), 15, (255, 0, 255), cv2.FILLED)

# Vẽ điểm 17
myLP17 = lmList[17]
px17, py17 = myLP17[0], myLP17[1]
cv2.circle(img, (px17, py17), 15, (255, 0, 255), cv2.FILLED)

# Vẽ điểm 16
myLP16 = lmList[16]
px16, py16 = myLP16[0], myLP16[1]
cv2.circle(img, (px16, py16), 15, (255, 0, 255), cv2.FILLED)

# Vẽ điểm 0
myLP0 = lmList[0]
px0, py0 = myLP0[0], myLP0[1]
cv2.circle(img, (px0, py0), 15, (255, 0, 255), cv2.FILLED)

#Vẽ đường nối


cv2.line(img,myLP4, myLP8, (0, 0, 0), 4)
cv2.line(img,myLP16, myLP0, (0, 0, 0), 4)

#Tính toán khoảng cách


length_ver = calculateDistance(myLP8, myLP4)
length_ver1 = calculateDistance(myLP16, myLP0)
length_hor = calculateDistance(myLP5, myLP17)
length_rat = int((length_ver/length_hor)*100)

22
length_rat1 = int((length_ver1/length_hor)*100)
length_per = int(np.interp(length_rat, [min_rat, max_rat], [min_per,
max_per]))
length_per1 = int(np.interp(length_rat1, [min_rat, max_rat], [min_per,
max_per]))

# Xác định góc quay servo z,t


servoZ = int(np.interp(length_rat, [min_rat, max_rat], [min_outz,
max_outz]))
servoT = int(np.interp(length_rat1, [min_rat, max_rat], [min_outt,
max_outt]))

# Chuyển từ vị trí sang độ


servoX = int(np.interp(px5, [0, ws], [min_outx, max_outx]))
servoY = int(np.interp(py5, [0, hs], [min_outy, max_outy]))

#Vẽ khung chứa giá trị servo x, y, t


cv2.rectangle(img, (40, 20), (350, 160), (0, 255, 255), cv2.FILLED)
cv2.putText(img, f'Servo X: {servoX} deg', (50, 50),
cv2.FONT_HERSHEY_PLAIN, 2, (255, 0, 0), 2)
cv2.putText(img, f'Servo Y: {servoY} deg', (50, 100),
cv2.FONT_HERSHEY_PLAIN, 2, (255, 0, 0), 2)
cv2.putText(img, f'Servo T: {servoT} deg', (50, 150),
cv2.FONT_HERSHEY_PLAIN, 2, (255, 0, 0), 2)
cv2.putText(img, f'Servo Z: {servoZ} deg', (x_min - 10, y_min - 27),
cv2.FONT_HERSHEY_PLAIN,2, (0, 255, 255), 3)

# Vẽ value bar
length_bar = int(np.interp(length_per, [min_per, max_per], [x_min - 20,
x_min + 300]))
length_bar1 = int(np.interp(length_per1, [min_per, max_per], [y_min - 20,
y_min + 300]))
cv2.rectangle(img, (x_min - 20, y_min - 110), (length_bar, y_min - 80), (0,
255, 255), cv2.FILLED)
cv2.rectangle(img, (x_max + 40, y_min - 20), (x_max + 70, length_bar1), (0,
255, 255), cv2.FILLED)
cv2.rectangle(img, (x_min - 20, y_min - 110), (x_min + 300, y_min - 80),
(0, 0, 0), 4)
cv2.rectangle(img, (x_max + 40, y_min - 20), (x_max + 70, y_min + 300), (0,
0, 0), 4)
cv2.putText(img, f'{length_per}%', (x_min + 310, y_min -
85),cv2.FONT_HERSHEY_PLAIN, 2, (0, 0, 0), 3)
cv2.putText(img, f'{length_per1}%', (x_max + 35, y_min +
330),cv2.FONT_HERSHEY_PLAIN, 2, (0, 0, 0), 3)

#Gửi tín hiệu sang Arduino


stringX = str(servoX)
stringY = str(servoY)
stringZ = str(servoZ)
stringT = str(servoT)

23
string1 = stringX + "-" + stringY + "-" + stringZ + "-" + stringT + "\r"
ser.write(string1.encode())

cv2.imshow("Image", img)
key = cv2.waitKey(1)
if key == ord('q'): # Ấn "q" để thoát
break
cv2.destroyAllWindows()

Đầu tiên, code bao gồm các import cần thiết:


 cv2: thư viện OpenCV để xử lý ảnh
 mediapipe: thư viện dùng để xử lý thông tin về tay người dùng
 numpy: thư viện để tính toán trên các mảng số
 math: thư viện để tính toán các phép toán toán học cơ bản
 serial: thư viện để kết nối với Arduino thông qua cổng COM.

Tiếp theo, chương trình tiến hành tạo một đối tượng mediapipe hands để xử lý thông
tin về tay người dùng. Sau đó, chương trình mở camera và cấu hình kích thước ảnh đầu vào
là 1280x720 (phụ thuộc vào cam của laptop).
Ta khai báo các khoảng giá trị tỷ lệ và phần trăm cùng với khoảng quay của các
servo.
Sau đó hàm calculateDistance được định nghĩa để tính toán khoảng cách giữa 2
điểm
Cuối cùng, chương trình tiến hành đọc ảnh từ camera và xử lý các thông tin về tay
người dùng. Các bước tiến hành là:
 Đọc ảnh và đảo ngược chiều ảnh.
 Chuyển đổi ảnh từ định dạng BGR sang RGB.
 Xử lý các thông tin về tay người dùng bằng mediapipe hands.
 Chuyển đổi ảnh từ RGB sang BGR.
 Vẽ các đường và điểm trên ảnh để hiển thị thông tin về tay người dùng.
 Từ dữ liệu từ hình ảnh trả về các góc của các servo và gửi về Arduino
 Cuối cùng, chương trình kết thúc vòng lặp while và giải phóng tài nguyên.
Kết quả chạy:

24
Hình 15: Giao diện chạy điều khiển bằng xử lý ảnh
Video chạy:

Nếu thầy không xem được thì thầy có thể vào theo link sau ạ:
25
Điều khiển cánh tay robot 4 bậc bằng xử lý ảnh - YouTube

VI. Kết luận


Qua quá trình tìm hiểu và nghiêm cứu, mặc dù có một số khó khăn trong việc tìm hiểu,
nghiên cứu, làm quen với đề tài, nhưng kết quả cho thấy được tính khả thi của đề tài, có thể
thực hiện được với thời gian vầ điều khiện cho phép.

Những điều đạt được:

- Áp dụng được xử lý ảnh AI vào điều khiển thiết bị ở đây là xử lý ảnh bàn tay
điều khiển cánh tay robot.
- Hiểu được các truyền thông giữa Python và Arduino.
- Xây dựng được giao diện điều khiển trên Python.

Hạn chế:

Độ chính xác còn thấp cần áp dụng các thuật toán để giảm thiểu sai số.

VII. Tài liệu tham khảo

Serial Communication between Python and Arduino - Hackster.io

Hand landmarks detection guide | MediaPipe | Google Developers

Python Tkinter On-Off Switch - Python Guides

How to get keyboard input in PyGame ? - GeeksforGeeks

26

You might also like