引言
我是一名專注于機(jī)器學(xué)習(xí)和機(jī)器人技術(shù)自由者。我的熱情始于大學(xué)期間的人工智能課程,這促使我探索人機(jī)交互的新方法。尤其對(duì)于機(jī)械臂的操作,我一直想要簡(jiǎn)化其復(fù)雜性,使之更加直觀和易于使用。
這個(gè)項(xiàng)目的靈感源自于我對(duì)創(chuàng)新技術(shù)的熱愛以及對(duì)改善人機(jī)互動(dòng)方式的追求。我的目標(biāo)是開發(fā)一個(gè)基于手勢(shì)的機(jī)械臂控制系統(tǒng),使非專業(yè)人士也能輕松操作。為此,我選擇了Google的MediaPipe庫進(jìn)行手勢(shì)識(shí)別,并以myCobot 320 m5作為實(shí)驗(yàn)平臺(tái)。
技術(shù)概述
Google MediaPipe
MediaPipe是由Google開發(fā)的一個(gè)開源跨平臺(tái)框架,專門用于構(gòu)建各種感知管道。這個(gè)框架提供了豐富的工具和預(yù)先構(gòu)建的模塊,使得開發(fā)者能夠輕松地構(gòu)建和部署復(fù)雜的機(jī)器學(xué)習(xí)模型和算法,尤其在圖像和視頻分析方面。
MediaPipe的一個(gè)顯著特點(diǎn)是它對(duì)實(shí)時(shí)手勢(shì)和面部識(shí)別的支持。它能夠高效地處理視頻流,并實(shí)時(shí)識(shí)別和追蹤人的手勢(shì)、面部特征等。這種能力使其在交互式應(yīng)用程序、增強(qiáng)現(xiàn)實(shí)(AR)、虛擬現(xiàn)實(shí)(VR)以及機(jī)器人技術(shù)中變得極其有用。
你可以嘗試試用一下手勢(shì)識(shí)別在線功能,無需安裝。
https://mediapipe-studio.webapps.google.com/home
它的簡(jiǎn)單易用的API和豐富的文檔使得更容易集成這個(gè)框架,非常適合使用在機(jī)器學(xué)習(xí)和計(jì)算機(jī)視覺領(lǐng)域當(dāng)中。
pymycobot
pymycobot 是一個(gè)用于與 mycobot 機(jī)械臂進(jìn)行串行通信和控制的 Python API。這個(gè)庫是為了方便開發(fā)者使用 Python 語言控制 mycobot 機(jī)械臂而設(shè)計(jì)的。它提供了一系列的函數(shù)和命令,讓用戶可以通過編程方式控制機(jī)械臂的動(dòng)作和行為。例如,用戶可以使用該庫獲取機(jī)械臂的角度、發(fā)送角度指令來控制機(jī)械臂的移動(dòng),或者獲取和發(fā)送機(jī)械臂的坐標(biāo)信息。
使用這個(gè)庫唯一的標(biāo)準(zhǔn)是,得使用mycobot 系列的機(jī)械臂,這是專門為mycobot進(jìn)行適配的一款機(jī)械臂。
產(chǎn)品介紹
myCobot 320M5 stack
myCobot 320 M5 是大象機(jī)器人開發(fā)的一款面向用戶的六軸協(xié)作機(jī)械臂。它具有350mm的工作半徑和最大1000g的負(fù)載能力。該機(jī)械臂適用于開放的ROS仿真開發(fā)環(huán)境,并包含運(yùn)動(dòng)學(xué)正逆解算法。它支持多種編程語言,包括Python、C++、Arduino、C# 和 JavaScript,且兼容Android、Windows、Mac OSX和Linux平臺(tái)。myCobot 320 M5的多功能性使其適用于多種開發(fā)和集成應(yīng)用。
2D 相機(jī)
一個(gè)能夠安裝在mycobot320末端的2D相機(jī),用USB數(shù)據(jù)線進(jìn)行通信。能夠呈現(xiàn)機(jī)械臂末端所看到的視野。
開發(fā)過程
項(xiàng)目架構(gòu)
我將該項(xiàng)目主要分為三個(gè)木塊功能:
Gesture Recognition: 主要用來處理手勢(shì)的識(shí)別,能夠返回信息當(dāng)欠手勢(shì)是什么,比如說豎大拇指等等。
Robotic Arm Control:主要功能用于設(shè)置機(jī)械臂的運(yùn)動(dòng)控制,例如坐標(biāo)控制,角度控制等等。
Program logic:用來處理程序運(yùn)行的邏輯,設(shè)置確認(rèn)手勢(shì)時(shí)間,重置識(shí)別時(shí)間等,后續(xù)將一一詳細(xì)介紹。
編譯環(huán)境
操作系統(tǒng):windows 11
編程語言:Python3.9+
使用的庫:opencv,mediapipe,pymycobot,time
手勢(shì)的識(shí)別
做識(shí)別首先得獲得到相機(jī)的一個(gè)畫面,這里我們就用到了opencv庫來獲取相機(jī)的畫面
import cv2 # 獲取相機(jī)流,默認(rèn)的攝像頭-0 外接的攝像頭按照順序往上- 1,2,3 cap = cv2.VideoCapture(1) # 持續(xù)獲取相機(jī)畫面 while cap.isOpened(): #獲取當(dāng)前圖像畫面 ret, frame = cap.read() # 將BGR圖像轉(zhuǎn)換為RGB rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 在電腦中顯示畫面 cv2.imshow('gesture control',frame) # 按下 'q' 鍵退出,避免死循環(huán) if cv2.waitKey(1) & 0xFF == ord('q'): break
到這里圖像畫面就獲取成功了,接下來我們用mediapipe手勢(shì)進(jìn)行識(shí)別。
import mediapipe as mp # 初始化MediaPipe Hands模塊 mp_hands = mp.solutions.hands hands = mp_hands.Hands() mp_draw = mp.solutions.drawing_utils # 處理圖像并檢測(cè)手部 result = hands.process(rgb_frame) if result.multi_hand_landmarks: for hand_landmarks in result.multi_hand_landmarks: mp_draw.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
這是識(shí)別手勢(shì)之后的輸出的結(jié)果,它能夠精準(zhǔn)的識(shí)別出手上的每個(gè)關(guān)節(jié),并且將每個(gè)關(guān)節(jié)的點(diǎn)都命名。MediaPipe Hands 提供了21個(gè)手部關(guān)鍵點(diǎn)(landmarks),這些關(guān)鍵點(diǎn)共同描繪了手的結(jié)構(gòu),包括手腕、各個(gè)手指的各個(gè)關(guān)節(jié)。以大拇指舉例子,一共有四個(gè)關(guān)節(jié),從下往上分別是CMC,MCP,IP,TIP.
cmc: Carpometacarpal Joint mcp:Metacarpophalangeal Joint ip:Interphalangeal Joint tip:tip
有了這些還不夠,我們要讓他識(shí)別特定的手勢(shì),要需要去設(shè)定一個(gè)方法,來確定這個(gè)手勢(shì),比如說我想要一個(gè)手勢(shì)是豎大拇指,那么我們分析在豎大拇指的時(shí)候,拇指的指尖的位置是在整個(gè)手掌的最上方,這樣就容易多了。只要確定在畫面中大拇指的指尖是高于其他所有手指頭的都指尖,那么這個(gè)手勢(shì)就是豎大拇指。(也可以通過別的進(jìn)行分析)
一般情況下,我們可以獲取到某個(gè)關(guān)節(jié)的X,Y,Z的三個(gè)屬性,表示改關(guān)節(jié)在圖像中的位置。
#獲取大拇指指尖的屬性 thump_tip = hand_landmarks.landmark[mp.hands.HandLandmark.THUMB_TIP] #獲取大拇指指尖的高度 thump_tip.y #判斷豎大拇指手勢(shì) def is_thump_up(hand_landmarks): thumb_tip = hand_landmarks.landmark[mp_hands.HandLandmark.THUMB_TIP] index_tip = hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP] # 判斷那個(gè)關(guān)節(jié)比較高。 if thumb_tip.y < index_tip.y: return True return False
如果想要?jiǎng)e的手勢(shì)的話,也可以根據(jù)手型的特點(diǎn)來設(shè)定一個(gè)專門的辨別方法。到這里手勢(shì)的識(shí)別就完成了。
機(jī)械臂運(yùn)動(dòng)控制
我一開始的想法是,當(dāng)相機(jī)識(shí)別到手勢(shì)的時(shí)候就會(huì)給機(jī)械臂發(fā)送一條控制命令,這里我們先簡(jiǎn)單的設(shè)置一個(gè)讓機(jī)械臂點(diǎn)頭的動(dòng)作。
pymycobot 這個(gè)功能庫,開放了很多功能在控制機(jī)械臂的時(shí)候非常的方便。
from pymycobot.mycobot import Mycobot import time #鏈接機(jī)械臂 mc = Mycobot(port,baud) #以關(guān)節(jié)角度控制機(jī)械臂運(yùn)動(dòng) mc.send_angles([angles_list],speed) #以坐標(biāo)控制機(jī)械臂進(jìn)行運(yùn)動(dòng) mc.send_coords([coords_list],speed,mode) #點(diǎn)頭動(dòng)作 def ThumpUpAction(self): self.mc.send_angles([0.96, 86.22, -98.26, 10.54, 86.92, -2.37], 60) time.sleep(1.5) for count in range(3): self.mc.send_angles([0.79, 2.46, (-8.17), 4.3, 88.94, 0.26], 70) time.sleep(1) self.mc.send_angles([(-3.6), 30.32, (-45.79), (-46.84), 97.38, 0.35], 70) time.sleep(1) self.mc.send_angles([0.79, 2.46, (-8.17), 4.3, 88.94, 0.26], 70) time.sleep(1) self.mc.send_angles([0.96, 86.22, -98.26, 10.54, 86.92, -2.37], 60)
為了讓整體代碼看起來可讀性高,可修改性高,創(chuàng)建機(jī)械臂類方便進(jìn)行調(diào)用和修改
class RobotArmController: def __init__(self,port): #初始化鏈接 self.mc = MyCobot(port, 115200) self.init_pose = [0.96, 86.22, -98.26, 10.54, 86.92, -2.37] self.coords = [-40, -92.5, 392.7, -92.19, -1.91, -94.14] self.speed = 60 self.mode = 0 def ThumpUpAction(self): ... def OtherAction(self): ...
程序邏輯的處理
在調(diào)試的過程中,出現(xiàn)了一些問題,在識(shí)別收拾的時(shí)候,它是一直識(shí)別,這就意味著如果在1s中內(nèi)識(shí)別了10次的話,會(huì)給機(jī)械臂發(fā)送10個(gè)命令,這樣肯定不是我一開始所設(shè)想的。
所以在邏輯上就要有所處理,下面是我處理的方式。
# 設(shè)置一個(gè)2S的時(shí)間來確定這個(gè)手勢(shì),當(dāng)豎大拇指出現(xiàn)2s的時(shí)候才進(jìn)行下發(fā)機(jī)械臂控制的命令,用控制變量的方式來進(jìn)行。 #初始化變量 #檢測(cè)手勢(shì)是否存在的變量 gesture_detected = False #確定手勢(shì)出現(xiàn)后計(jì)時(shí)的變量 gesture_start_time = None # 設(shè)定手勢(shì)出現(xiàn)2s后的變量 gesture_confirmation_time = 2 后續(xù)的處理邏輯: 當(dāng)特定手勢(shì)出現(xiàn)的時(shí)候,gesture_start_time就開始計(jì)時(shí),這個(gè)時(shí)候在不停的做判斷如果時(shí)間到達(dá)了2S之后,確定手勢(shì)接下來執(zhí)行相對(duì)應(yīng)手勢(shì)的機(jī)械臂運(yùn)動(dòng)。 current_time = time.time() if current_gesture: if not gesture_detected: gesture_detected = True gesture_start_time = current_time elif current_time - gesture_start_time > gesture_confirmation_time and not action_triggered: # 根據(jù)手勢(shì)執(zhí)行相應(yīng)動(dòng)作 if current_gesture == "thumb_up": robotic arm action()
但是這樣還不夠,因?yàn)槭秩绻霈F(xiàn)超過2s后也會(huì)持續(xù)發(fā)送機(jī)械臂的指令,這里我們需要在設(shè)置一個(gè)冷卻的時(shí)間,有充足的時(shí)間讓機(jī)械臂完成運(yùn)動(dòng)。
#冷卻時(shí)間的變量 #機(jī)械臂是否完成動(dòng)作的變量 action_triggered = False #冷卻時(shí)間計(jì)時(shí)的變量 cooldown_start_time = None #固定2s冷卻時(shí)間 cooldown_period = 2
這樣就能夠滿足需求了。完整的邏輯代碼處理如下
# 處理手勢(shì) current_time = time.time() if current_gesture: if not gesture_detected: gesture_detected = True gesture_start_time = current_time elif current_time - gesture_start_time > gesture_confirmation_time and not action_triggered: # 根據(jù)手勢(shì)執(zhí)行相應(yīng)動(dòng)作 if current_gesture == "thumb_up": print('good good') mc.thum_up() elif current_gesture == "palm_open": print('forward') mc.increment_x_and_send() # 可以添加更多手勢(shì)和對(duì)應(yīng)動(dòng)作的判斷 action_triggered = True cooldown_start_time = current_time else: gesture_detected = False gesture_start_time = None if action_triggered and current_time - cooldown_start_time > cooldown_period: print('can continue') action_triggered = False cooldown_start_time = None
演示
https://youtu.be/9vOPKO_IG9M
總結(jié)
這個(gè)項(xiàng)目展示了使用手勢(shì)識(shí)別控制myCobot 320的方法,開創(chuàng)了人機(jī)互動(dòng)的新形式。盡管目前僅實(shí)現(xiàn)了有限的幾個(gè)手勢(shì)與機(jī)械臂動(dòng)作的對(duì)應(yīng),但它為未來更廣泛的機(jī)械臂應(yīng)用奠定了基礎(chǔ)。結(jié)合手勢(shì)與機(jī)械臂的創(chuàng)新嘗試不僅提升了我的編程技能,還鍛煉了我的問題解決能力,為未來的相關(guān)項(xiàng)目提供了寶貴經(jīng)驗(yàn)。
審核編輯 黃宇
-
手勢(shì)識(shí)別
+關(guān)注
關(guān)注
8文章
222瀏覽量
47738 -
人工智能
+關(guān)注
關(guān)注
1789文章
46324瀏覽量
236496 -
開源
+關(guān)注
關(guān)注
3文章
3182瀏覽量
42240 -
python
+關(guān)注
關(guān)注
54文章
4758瀏覽量
84287 -
機(jī)械臂
+關(guān)注
關(guān)注
12文章
504瀏覽量
24412
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論