張興華
(廣東白云學院智能制造工程學院,廣東 廣州 510450)
第七屆全國大學生工程訓練綜合能力競賽智能+賽道試題,要求智能物流搬運機器人能夠通過掃描二維碼、條碼或通過Wi-Fi 網絡通信等方式領取搬運或放置任務,在指定的工業場景內行走、避障,具有物料位置和顏色識別、物料抓取與載運、路徑規劃等功能,應按任務要求將物料搬運至指定地點并精準擺放。
任務執行過程描述如下:將機器人放置在出發區,抽簽確定物料的搬運順序任務碼和在原料區的擺放順序。任務編碼被設置為1(紅)、2(綠)、3(藍)三個數字的組合,兩組三位數之間以+號連接,如213+321。同一場次的任務相同。
機器人移動到二維碼顯示板前讀取二維碼,獲得所需要搬運物料的搬運順序(例如:213+321)。這是機器人在最后一個工位的物料擺放樣式,如圖1所示。

圖1 物料擺放樣式任務碼
機器人到達原料區,從原料區取料,如果看到了如圖2 所示的原材料擺放樣式,要按照2、1、3 的順序,即按照綠色、紅色、藍色的順序取貨和擺貨。機器人行駛至粗加工區,將攜帶的物料按照任務碼的順序放置到對應的色環上,即按綠、紅、藍的順序放置在粗加工區。然后再按綠、紅、藍的順序將物料依次擺放在半成品區的上層。

圖2 原材料擺放樣式
機器人3D 圖如圖3 所示。車輪采用MECANAM輪,這種車輪可以通過控制車輪的轉動方向與轉速實現水平左右移動車體的動作[1-10]。整個系統包含了5 個部分:電源部分、主控板模塊、OpenMV4 視覺模塊、舵機驅動模塊、直流電動機驅動部分。機器人使用Arduino Mega 2560 單片機作為主控電路板,使用的OpenMV4 視覺模塊如圖4 所示。實現視覺追蹤與距離檢測,由Mega 2560 擴展板(圖5)按照Mega 2560 接線圖(圖6),分別接在兩個直流電機驅動模塊TB6612FNG(圖7)的AIN1、AIN2 和BIN1、BIN2。16 路舵機驅動板PCA9685(圖8)驅動4 個舵機的關節型機械臂,實現目標物體的抓取和放置,用兩個電壓轉換模塊將電源電壓7.4 V轉換為5 V和3.3 V。

圖3 麥克納姆輪四輪驅動機器人

圖4 OpenMV4 視覺模塊

圖5 Mega 2560擴展板實物圖

圖6 Mega 2560單片機接線圖

圖7 TB6612FNG電機驅動模塊接線圖

圖8 16路舵機驅動板PCA9685
搬運場地如圖9 所示,機器人從右上角出發向前行駛,機器人底部前沿的光電傳感器尋找到第三條黑線,暫停行走,攝像頭右轉90°,掃描二維碼,如果二維碼的第一個數字為2,就要先搬運綠色物料,向前行進三條線即900 mm 到達原材料區,攝像頭尋找綠色物料,此時可能有三種情況:

圖9 搬運場地圖
1)如果攝像頭看到的綠色物料在鏡頭左邊,機械臂左轉30°,下去取料。
2)如果攝像頭看到的綠色物料在鏡頭中間,機械臂直接下去取料。
3)如果攝像頭看到的綠色物料在鏡頭右邊,機械臂右轉30°,下去取料。
然后機器人向左平移,小車底盤下中心位置的傳感器如果檢測到第三條黑線,說明小車已經左移了900 mm, 到達粗加工區。攝像頭左轉90°,機械臂左轉90°,因為此時搬運的是綠色物料,所以機械臂腰關節右轉30°。把綠色物料放下,然后機械臂復位。小車繼續向左平移2 格黑線即600 mm 的距離,然后小車后退3 格的距離,來到半成品區,機械臂和攝像頭左轉90°,把綠色物料擺放在上層左邊位置。然后小車前進3 格的距離,再向右平移6 格的距離,到達原料區,攝像頭和機械臂右轉90°。尋找第二個目標工件藍色物料,此時可能有三種情況:
1)如果攝像頭看到的藍色物料在鏡頭左邊,機械臂左轉30°,下去取料。
2)如果攝像頭看到的藍色物料在鏡頭中間,機械臂直接下去取料。
3)如果攝像頭看到的藍色物料在鏡頭右邊,機械臂右轉30°,下去取料。
然后搬運1 號物料,即紅色物料,完成后搬運3號物料,即藍色物料,完成后,重復執行以上算法,就可以完成6 個物料在原料區的取料、粗加工區的放置、半成品區的擺放。
麥克納姆輪機器人編寫的運動控制函數如下:
char inverse_left = 1; char inverse_right = 0; char
inverse_left2 = 1; char inverse_right2 = 0;
int left_speed; int right_speed; int left_speed2; int
right_speed2;
#define PWMA 12 //A電機轉速
#define DIRA1 34
#define DIRA2 35 //A電機方向
#define PWMB 8 //B電機轉速
#define DIRB1 37
#define DIRB2 36 //B電機方向
#define PWMC 9 //C電機轉速
#define DIRC1 43
#define DIRC2 42 //C電機方向
#define PWMD 5 //D電機轉速
#define DIRD1 A4 //26 V1.0 版本
#define DIRD2 A5 //D 電機方向27 V1.0版本
#define MOTORA_FORWARD(pwm)
do{digitalWrite(DIRA1,LOW);
digitalWrite(DIRA2,HIGH);analogWrite(PWMA,p
wm);}while(0)
#define MOTORA_STOP(x)
do{digitalWrite(DIRA1,LOW);
digitalWrite(DIRA2,LOW);
analogWrite(PWMA,0);}while(0)
#define MOTORA_BACKOFF(pwm)
do{digitalWrite(DIRA1,HIGH);digitalWrite(DIRA2,L
OW); analogWrite(PWMA,pwm);}while(0)
#define MOTORB_FORWARD(pwm)
do{digitalWrite(DIRB1,HIGH);
digitalWrite(DIRB2,LOW);analogWrite(PWMB,p
wm);}while(0)
#define MOTORB_STOP(x)
do{digitalWrite(DIRB1,LOW);
digitalWrite(DIRB2,LOW);
analogWrite(PWMB,0);}while(0)
#define MOTORB_BACKOFF(pwm)
do{digitalWrite(DIRB1,LOW);digitalWrite(DIRB2,HI
GH); analogWrite(PWMB,pwm);}while(0)
#define MOTORC_FORWARD(pwm)
do{digitalWrite(DIRC1,LOW);
digitalWrite(DIRC2,HIGH);analogWrite(PWMC,p
wm);}while(0)
#define MOTORC_STOP(x)
do{digitalWrite(DIRC1,LOW);
digitalWrite(DIRC2,LOW);
analogWrite(PWMC,0);}while(0)
#define MOTORC_BACKOFF(pwm)
do{digitalWrite(DIRC1,HIGH);digitalWrite(DIRC2,L
OW); analogWrite(PWMC,pwm);}while(0)
#define MOTORD_FORWARD(pwm)
do{digitalWrite(DIRD1,HIGH);
digitalWrite(DIRD2,LOW);analogWrite(PWMD,p
wm);}while(0)
#define MOTORD_STOP(x)
do{digitalWrite(DIRD1,LOW);
digitalWrite(DIRD2,LOW);
analogWrite(PWMD,0);}while(0)
#define MOTORD_BACKOFF(pwm)
do{digitalWrite(DIRD1,LOW);digitalWrite(DIRD2,HI
GH); analogWrite(PWMD,pwm);}while(0)
int pwm_a = 0; int pwm_b = 0; int pwm_c = 0; int
pwm_d = 0;
void run(int left_speed, int right_speed) {
if (inverse_left == 1) left_speed = (-left_speed);
if (inverse_right == 1) right_speed = (-right_speed);
if (left_speed < 0) {
pwm_a = abs(left_speed);
MOTORA_FORWARD(pwm_a);
}
else {
pwm_a = abs(left_speed);
MOTORA_BACKOFF(pwm_a);
}
if (right_speed < 0) {
pwm_b = abs(right_speed);
MOTORB_BACKOFF(pwm_b);
}
else {
pwm_b = abs(right_speed);
MOTORB_FORWARD(pwm_b);
}
}
void run2(int left_speed2, int right_speed2) {
if (inverse_left2 == 1) left_speed2 = (-left_speed2);
if (inverse_right2 == 1) right_speed2 = (-right_
speed2);
if (left_speed2 < 0) {
pwm_c = abs(left_speed2);
MOTORC_FORWARD(pwm_c); }
else {
pwm_c = abs(left_speed2);
MOTORC_BACKOFF(pwm_c); }
if (right_speed2 < 0) {
pwm_d = abs(right_speed2);
MOTORD_BACKOFF(pwm_d); }
else {
pwm_d = abs(right_speed2);
MOTORD_FORWARD(pwm_d);
}
}
Void strafe_left() { run(-32, 32);
run2(32, -32);}
void strafe_right() { run(32, -32);
run2(-32, 32);}
OpenMV 串口通信程序:
import sensor, image, time
import json
from pyb import UART
sensor.reset() # Initialize the camera sensor.
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA)
sensor.skip_frames(10) # Let new settings take #affect.
sensor.set_auto_whitebal(False) # turn this off.
clock = time.clock() # Tracks FPS.
uart = UART(3, 19200)
while(True):
clock.tick() # milliseconds snapshots().
img = sensor.snapshot() # Take a picture
img.lens_corr(1.5)
for code in img.find_qrcodes():
message = code.payload()
uart.write(message)
print(code)
else:print(“not found!”)
Mega 2560端的串口通信程序設計:
void setup( ) { Serial.begin(19200);
pinMode(7, OUTPUT);}
void loop( ){
if(Serial.available()){
Serial.write(Serial.read()); }}
經實際測試,搬運機器人能高質量地完成搬運任務。