作為最熱門的技術(shù)領(lǐng)域,機器人技術(shù)正在徹底改變產(chǎn)業(yè),并推動全球的創(chuàng)新。為了滿足這個快速發(fā)展的領(lǐng)域?qū)夹g(shù)人才日益增長的需求,開發(fā)了一個開創(chuàng)性的機器人教育解決方案。這個創(chuàng)新的解決方案將自動化水果采摘機的模擬與水果分揀和運送的自動化復(fù)合機器人結(jié)合起來,為學(xué)生提供了一個在最受歡迎和最有趨勢的技術(shù)領(lǐng)域中的全面學(xué)習(xí)經(jīng)驗。
在本文中我們將詳細為你介紹水果采摘和分揀機器人場景。我們將會從套裝的介紹和使用的場景介紹,到套裝功能機械臂的實現(xiàn)。
智慧農(nóng)業(yè)套裝
圖中所展示的就是我們的智慧農(nóng)業(yè)套裝,它是由以下的內(nèi)容組成。
mechArm 270 M5Stack | *2 |
---|---|
傳送帶 | *1 |
3D攝像頭/深度攝像頭 | *2 |
仿真模擬果樹 | *1 |
結(jié)構(gòu)件 | 若干 |
你肯定很好奇這個套裝是怎么運轉(zhuǎn)的,接下來我將為你介紹這個套裝的運作流程。
首先你可以看到我們有兩臺機械臂,他們分別執(zhí)行不同的功能,離果樹最近的那一臺機械臂是采摘機器人下面簡稱R1;中間那臺機械臂是分揀機器人下面簡稱是R2。從他們的名字上就可以知道它們分別做的是什么工作,R1負責(zé)將果樹上的果實采摘下來放置在傳送帶上,R2則是將傳送帶上不合格的水果分揀出來。
流程:
采摘:R1通過深度攝像頭對果樹上果實的識別然后對果子進行定位,將果實的坐標發(fā)送給R1去采摘。
運輸:通過R1的采摘,果實被放置在傳送帶上。傳送帶經(jīng)過運轉(zhuǎn)將果實運輸?shù)絉2可識別的范圍內(nèi)進行果實好壞的判斷。
分揀:R2上方的攝像頭將視線范圍內(nèi)的果實進行識別算法的判斷,判斷為好果實的話,果實將隨著傳送帶傳輸?shù)焦麑嵤占瘏^(qū);判斷為壞果實的話,將壞果實的坐標信息傳遞給R2,R2將壞果實目標進行抓取出來,放置在特定區(qū)域。
持續(xù)循環(huán)上面的流程:采摘->運輸->分揀->采摘->運輸
產(chǎn)品介紹
下面將簡要介紹套裝中的產(chǎn)品。
Robotic Arm - mechArm 270 M5Stack
這是一款小六軸機械臂,以M5Stack-Basic為核心控制,ESP32為輔助控制,結(jié)構(gòu)是中心對稱結(jié)構(gòu)(仿工業(yè)結(jié)構(gòu))。mechArm 270-M5本體重量1kg, 負載250g,工作半徑270mm,設(shè)計緊湊便攜,小巧但功能強大,操作簡單,能與人協(xié)同、安全工作。
傳送帶
傳送帶是一種用于運輸物品的機械設(shè)備,通常由一個帶狀物體和一個或多個滾動軸組成。它們可以運輸各種物品,例如包裹、箱子、食品、礦石、建筑材料等等。傳送帶的工作原理是將物品放置在運動的帶子上,然后將其移動到目標位置。傳送帶通常由電機、傳動系統(tǒng)、帶子和支撐結(jié)構(gòu)組成。電機提供動力,傳動系統(tǒng)將動力傳遞給帶子,使其移動。
目前市面上可以根據(jù)用戶的需求定制各種傳送帶,例如傳送帶的長寬高,履帶的材質(zhì)等。
深度攝像頭
隨著使用場景的多樣性,普通的2D攝像頭無法滿足我們使用的需求。在場景中我們使用到的是深度攝像頭。深度攝像頭是一種能夠獲取場景深度信息的相機。它不僅能夠捕捉場景的顏色和亮度信息,還能夠感知物體之間的距離和深度信息。深度攝像頭通常使用紅外線或其他光源來進行測量,以獲取物體和場景的深度信息。
它可以獲取很多信息,例如深度的畫面,彩色的畫面,紅外線的畫面,點云畫面。
有了深度相機,我們就可以精準的獲取到果樹上果實的位置,以及顏色信息。
自適應(yīng)夾爪-機械臂末端執(zhí)行器
自適應(yīng)夾爪是一種用來抓取、握取或夾持物體的末端執(zhí)行器,它由兩個可移動的爪子組成,可以通過機械臂的控制系統(tǒng)來控制其開合程度和開合速度。
項目功能的實現(xiàn)
我們先要準備好編譯的環(huán)境,該場景是用Python語言來進行編寫的。在使用和學(xué)習(xí)的時候得安裝好環(huán)境。
編譯環(huán)境:
numpy==1.24.3
opencv-contrib-python==4.6.0.66
openni==2.3.0
pymycobot==3.1.2
PyQt5==5.15.9
PyQt5-Qt5==5.15.2
PyQt5-sip==12.12.1
pyserial==3.5
項目的功能點我們主要分為三部分:
● 機器視覺識別算法,深度識別算法
● 機械臂的控制,路徑的規(guī)劃
● 多臺機器之間通信和邏輯的處理
我們先從機器視覺識別算法介紹:
機器視覺識別算法
使用深度攝像頭之前需要進行相機標定。相機標定的教程(https://docs.opencv.org/4.x/dc/dbb/tutorial_py_calibration.html)
相機標定:
相機標定是指通過對攝像機進行一系列測量和計算,確定攝像機內(nèi)部參數(shù)和外部參數(shù)的過程。攝像機內(nèi)部參數(shù)包括焦距、主點位置、像素間距等,而攝像機外部參數(shù)則包括攝像機在世界坐標系中的位置和方向等。相機標定的目的是為了使攝像機能夠準確地捕捉并記錄世界坐標系中物體的位置、大小、形狀等信息。
我們的目標物體是果實,它顏色不一,形狀也不一定,有紅的,橙的,黃的。想要準確的抓取且不傷害到果實,就需要獲取果實的各個信息,寬度,厚度等,智能的進行抓取。
我們看一下目標果實,它們目前較大的區(qū)別就是顏色的不一樣,我們設(shè)定紅色和橙色的目標將被選中,這里就要用到HSV色域來進行目標的定位。下面的代碼是用來檢測目標果實。
Code:
class Detector:
class FetchType(Enum):
FETCH = False
FETCH_ALL = True
"""
Detection and identification class
"""
HSV_DIST = {
# "redA": (np.array([0, 120, 50]), np.array([3, 255, 255])),
# "redB": (np.array([176, 120, 50]), np.array([179, 255, 255])),
"redA": (np.array([0, 120, 50]), np.array([3, 255, 255])),
"redB": (np.array([118, 120, 50]), np.array([179, 255, 255])),
# "orange": (np.array([10, 120, 120]), np.array([15, 255, 255])),
"orange": (np.array([8, 150, 150]), np.array([20, 255, 255])),
"yellow": (np.array([28, 100, 150]), np.array([35, 255, 255])), # old
# "yellow": (np.array([31, 246, 227]), np.array([35, 255, 255])), # new
}
default_hough_params = {
"method": cv2.HOUGH_GRADIENT_ALT,
"dp": 1.5,
"minDist": 20,
"param2": 0.6,
"minRadius": 15,
"maxRadius": 40,
}
def __init__(self, target):
self.bucket = TargetBucket()
self.detect_target = target
def get_target(self):
return self.detect_target
def set_target(self, target):
if self.detect_target == target:
return
self.detect_target = target
if target == "apple":
self.bucket = TargetBucket(adj_tolerance=25, expire_time=0.2)
elif target == "orange":
self.bucket = TargetBucket()
elif target == "pear":
self.bucket = TargetBucket(adj_tolerance=35)
def detect(self, rgb_data):
if self.detect_target == "apple":
self.__detect_apple(rgb_data)
elif self.detect_target == "orange":
self.__detect_orange(rgb_data)
elif self.detect_target == "pear":
self.__detect_pear(rgb_data)
def __detect_apple(self, rgb_data):
maskA = color_detect(rgb_data, *self.HSV_DIST["redA"])
maskB = color_detect(rgb_data, *self.HSV_DIST["redB"])
mask = maskA + maskB
kernelA = cv2.getStructuringElement(cv2.MORPH_RECT, (8, 8))
kernelB = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))
mask = cv2.erode(mask, kernelA)
mask = cv2.dilate(mask, kernelA)
targets = circle_detect(
mask, {"minDist": 15, "param2": 0.5,
"minRadius": 10, "maxRadius": 50}
)
self.bucket.add_all(targets)
self.bucket.update()
def __detect_orange(self, rgb_data):
mask = color_detect(rgb_data, *self.HSV_DIST["orange"])
targets = circle_detect(
mask, {"minDist": 15, "param2": 0.1,
"minRadius": 7, "maxRadius": 30}
)
self.bucket.add_all(targets)
self.bucket.update()
def __detect_pear(self, rgb_data):
mask = color_detect(rgb_data, *self.HSV_DIST["yellow"