張興華
(廣東白云學院智能制造工程學院,廣東 廣州 510450)
第七屆全國大學生工程訓練綜合能力競賽智能+賽道試題,要求智能物流搬運機器人能夠通過掃描二維碼、條碼或通過Wi-Fi 網(wǎng)絡通信等方式領取搬運或放置任務,在指定的工業(yè)場景內(nèi)行走、避障,具有物料位置和顏色識別、物料抓取與載運、路徑規(guī)劃等功能,應按任務要求將物料搬運至指定地點并精準擺放。
任務執(zhí)行過程描述如下:將機器人放置在出發(fā)區(qū),抽簽確定物料的搬運順序任務碼和在原料區(qū)的擺放順序。任務編碼被設置為1(紅)、2(綠)、3(藍)三個數(shù)字的組合,兩組三位數(shù)之間以+號連接,如213+321。同一場次的任務相同。
機器人移動到二維碼顯示板前讀取二維碼,獲得所需要搬運物料的搬運順序(例如:213+321)。這是機器人在最后一個工位的物料擺放樣式,如圖1所示。
圖1 物料擺放樣式任務碼
機器人到達原料區(qū),從原料區(qū)取料,如果看到了如圖2 所示的原材料擺放樣式,要按照2、1、3 的順序,即按照綠色、紅色、藍色的順序取貨和擺貨。機器人行駛至粗加工區(qū),將攜帶的物料按照任務碼的順序放置到對應的色環(huán)上,即按綠、紅、藍的順序放置在粗加工區(qū)。然后再按綠、紅、藍的順序將物料依次擺放在半成品區(qū)的上層。
圖2 原材料擺放樣式
機器人3D 圖如圖3 所示。車輪采用MECANAM輪,這種車輪可以通過控制車輪的轉動方向與轉速實現(xiàn)水平左右移動車體的動作[1-10]。整個系統(tǒng)包含了5 個部分:電源部分、主控板模塊、OpenMV4 視覺模塊、舵機驅動模塊、直流電動機驅動部分。機器人使用Arduino Mega 2560 單片機作為主控電路板,使用的OpenMV4 視覺模塊如圖4 所示。實現(xiàn)視覺追蹤與距離檢測,由Mega 2560 擴展板(圖5)按照Mega 2560 接線圖(圖6),分別接在兩個直流電機驅動模塊TB6612FNG(圖7)的AIN1、AIN2 和BIN1、BIN2。16 路舵機驅動板PCA9685(圖8)驅動4 個舵機的關節(jié)型機械臂,實現(xiàn)目標物體的抓取和放置,用兩個電壓轉換模塊將電源電壓7.4 V轉換為5 V和3.3 V。
圖3 麥克納姆輪四輪驅動機器人
圖4 OpenMV4 視覺模塊
圖5 Mega 2560擴展板實物圖
圖6 Mega 2560單片機接線圖
圖7 TB6612FNG電機驅動模塊接線圖
圖8 16路舵機驅動板PCA9685
搬運場地如圖9 所示,機器人從右上角出發(fā)向前行駛,機器人底部前沿的光電傳感器尋找到第三條黑線,暫停行走,攝像頭右轉90°,掃描二維碼,如果二維碼的第一個數(shù)字為2,就要先搬運綠色物料,向前行進三條線即900 mm 到達原材料區(qū),攝像頭尋找綠色物料,此時可能有三種情況:
圖9 搬運場地圖
1)如果攝像頭看到的綠色物料在鏡頭左邊,機械臂左轉30°,下去取料。
2)如果攝像頭看到的綠色物料在鏡頭中間,機械臂直接下去取料。
3)如果攝像頭看到的綠色物料在鏡頭右邊,機械臂右轉30°,下去取料。
然后機器人向左平移,小車底盤下中心位置的傳感器如果檢測到第三條黑線,說明小車已經(jīng)左移了900 mm, 到達粗加工區(qū)。攝像頭左轉90°,機械臂左轉90°,因為此時搬運的是綠色物料,所以機械臂腰關節(jié)右轉30°。把綠色物料放下,然后機械臂復位。小車繼續(xù)向左平移2 格黑線即600 mm 的距離,然后小車后退3 格的距離,來到半成品區(qū),機械臂和攝像頭左轉90°,把綠色物料擺放在上層左邊位置。然后小車前進3 格的距離,再向右平移6 格的距離,到達原料區(qū),攝像頭和機械臂右轉90°。尋找第二個目標工件藍色物料,此時可能有三種情況:
1)如果攝像頭看到的藍色物料在鏡頭左邊,機械臂左轉30°,下去取料。
2)如果攝像頭看到的藍色物料在鏡頭中間,機械臂直接下去取料。
3)如果攝像頭看到的藍色物料在鏡頭右邊,機械臂右轉30°,下去取料。
然后搬運1 號物料,即紅色物料,完成后搬運3號物料,即藍色物料,完成后,重復執(zhí)行以上算法,就可以完成6 個物料在原料區(qū)的取料、粗加工區(qū)的放置、半成品區(qū)的擺放。
麥克納姆輪機器人編寫的運動控制函數(shù)如下:
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()); }}
經(jīng)實際測試,搬運機器人能高質量地完成搬運任務。