作為最熱門的技術領域,機器人技術正在徹底改變產業,并推動全球的創新。為了滿足這個快速發展的領域對技術人才日益增長的需求,開發了一個開創性的機器人教育解決方案。這個創新的解決方案將自動化水果采摘機的模擬與水果分揀和運送的自動化復合機器人結合起來,為學生提供了一個在最受歡迎和最有趨勢的技術領域中的全面學習經驗。
在本文中我們將詳細為你介紹水果采摘和分揀機器人場景。我們將會從套裝的介紹和使用的場景介紹,到套裝功能機械臂的實現。
智慧農業套裝
圖中所展示的就是我們的智慧農業套裝,它是由以下的內容組成。
mechArm 270 M5Stack | *2 |
---|---|
傳送帶 | *1 |
3D攝像頭/深度攝像頭 | *2 |
仿真模擬果樹 | *1 |
結構件 | 若干 |
你肯定很好奇這個套裝是怎么運轉的,接下來我將為你介紹這個套裝的運作流程。
首先你可以看到我們有兩臺機械臂,他們分別執行不同的功能,離果樹最近的那一臺機械臂是采摘機器人下面簡稱R1;中間那臺機械臂是分揀機器人下面簡稱是R2。從他們的名字上就可以知道它們分別做的是什么工作,R1負責將果樹上的果實采摘下來放置在傳送帶上,R2則是將傳送帶上不合格的水果分揀出來。
流程:
采摘:R1通過深度攝像頭對果樹上果實的識別然后對果子進行定位,將果實的坐標發送給R1去采摘。
運輸:通過R1的采摘,果實被放置在傳送帶上。傳送帶經過運轉將果實運輸到R2可識別的范圍內進行果實好壞的判斷。
分揀:R2上方的攝像頭將視線范圍內的果實進行識別算法的判斷,判斷為好果實的話,果實將隨著傳送帶傳輸到果實收集區;判斷為壞果實的話,將壞果實的坐標信息傳遞給R2,R2將壞果實目標進行抓取出來,放置在特定區域。
持續循環上面的流程:采摘->運輸->分揀->采摘->運輸
產品介紹
下面將簡要介紹套裝中的產品。
Robotic Arm - mechArm 270 M5Stack
這是一款小六軸機械臂,以M5Stack-Basic為核心控制,ESP32為輔助控制,結構是中心對稱結構(仿工業結構)。mechArm 270-M5本體重量1kg, 負載250g,工作半徑270mm,設計緊湊便攜,小巧但功能強大,操作簡單,能與人協同、安全工作。
傳送帶
傳送帶是一種用于運輸物品的機械設備,通常由一個帶狀物體和一個或多個滾動軸組成。它們可以運輸各種物品,例如包裹、箱子、食品、礦石、建筑材料等等。傳送帶的工作原理是將物品放置在運動的帶子上,然后將其移動到目標位置。傳送帶通常由電機、傳動系統、帶子和支撐結構組成。電機提供動力,傳動系統將動力傳遞給帶子,使其移動。
目前市面上可以根據用戶的需求定制各種傳送帶,例如傳送帶的長寬高,履帶的材質等。
深度攝像頭
隨著使用場景的多樣性,普通的2D攝像頭無法滿足我們使用的需求。在場景中我們使用到的是深度攝像頭。深度攝像頭是一種能夠獲取場景深度信息的相機。它不僅能夠捕捉場景的顏色和亮度信息,還能夠感知物體之間的距離和深度信息。深度攝像頭通常使用紅外線或其他光源來進行測量,以獲取物體和場景的深度信息。
它可以獲取很多信息,例如深度的畫面,彩色的畫面,紅外線的畫面,點云畫面。
有了深度相機,我們就可以精準的獲取到果樹上果實的位置,以及顏色信息。
自適應夾爪-機械臂末端執行器
自適應夾爪是一種用來抓取、握取或夾持物體的末端執行器,它由兩個可移動的爪子組成,可以通過機械臂的控制系統來控制其開合程度和開合速度。
項目功能的實現
我們先要準備好編譯的環境,該場景是用Python語言來進行編寫的。在使用和學習的時候得安裝好環境。
編譯環境:
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
項目的功能點我們主要分為三部分:
● 機器視覺識別算法,深度識別算法
● 機械臂的控制,路徑的規劃
● 多臺機器之間通信和邏輯的處理
我們先從機器視覺識別算法介紹:
機器視覺識別算法
使用深度攝像頭之前需要進行相機標定。相機標定的教程(https://docs.opencv.org/4.x/dc/dbb/tutorial_py_calibration.html)
相機標定:
相機標定是指通過對攝像機進行一系列測量和計算,確定攝像機內部參數和外部參數的過程。攝像機內部參數包括焦距、主點位置、像素間距等,而攝像機外部參數則包括攝像機在世界坐標系中的位置和方向等。相機標定的目的是為了使攝像機能夠準確地捕捉并記錄世界坐標系中物體的位置、大小、形狀等信息。
我們的目標物體是果實,它顏色不一,形狀也不一定,有紅的,橙的,黃的。想要準確的抓取且不傷害到果實,就需要獲取果實的各個信息,寬度,厚度等,智能的進行抓取。
我們看一下目標果實,它們目前較大的區別就是顏色的不一樣,我們設定紅色和橙色的目標將被選中,這里就要用到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"