我們已經設法打造了一個能夠處理語音命令的機器手臂。人們說出要求後,該手臂會找到目標物體並將其交給指定人物(它可以區分不同的人)。此外,它還可以播放線上音樂或告訴您當前的天氣情況。
該應用程式的軟體部分用Visual Studio 2015完成。Visual Studio簡單易用,並且提供了很多功能。其中一個功能就是Emgu CV—一個用於調用OpenCv函數的包裝函數公用程式。此功能通過Visual Studio Windows Forms實現,在處理圖像時非常重要。
如果想啟動項目,您只需在電腦上安裝Emgu CV即可。具體步驟如下:
1. 下載 EmguCV
您可以點擊 本頁“構建範例” 下方的超連結下載Emgu CV專案:
2. 添加文件
由於您需要使用添加公用程式,因此應將它們包含在Visual Studio中。OpenCV基於C/C++語言開發,如果您想在C#中使用,那麼需要添加DLL(動態連結公用程式)檔——處理視頻時必須包含DLL檔。參考檔位於Visual Studio菜單的Solution Explorer處。
如果您想添加更多檔案,請點擊References -> Add references,然後從下載的檔中選擇以下內容:
更多資訊可以參考以下連結:http://www.emgu.com/wiki/index.php/Setting_up_EMGU_C_Sharp
3. 範例
在下載的公用程式中,您可以找到更多使用影片處理(動態偵測、人臉辨識和相機擷取)的程式碼示例。
4. Arduino 程式
Arduino代碼具有4個命令:up/down負責控制伺服器;reset是指在出現問題時重置機器手臂位置;某個部件沒有動作時則使用do nothing 。程式具有四個自由度:
每個伺服馬達都被下達一個控制指令去使用不同的引腳:Elbow使用引腳7;Base使用引腳8;Circle使用引腳9;Wrist使用引腳10。對於伺服器控制,C#應用程式通過序列傳輸發送4個字母,每個狀態對應於一個具體的馬達控制指令:
if(cmd == ‘A’) state = 1; → control(1, posCircle);
if(cmd == ‘B’) state = 2; →control(2, posBase);
if(cmd == ‘C’) state = 3; → control(3, posElbow);
if(cmd == ‘D’) state = 4; →control(4, posGH);
根據伺服馬達的運動角度,代碼分為控制和命令指令。
在case 1中,Circle(旋轉)運動的命令為left/right(左/右)。
Case 1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
switch (cmd) { case '0': Left(); Break; case '1': //do nothing break; case '2': Right(); break; case '3': posCircle = 0; break; } state = 0; break; |
在case 2 和 case 3中,我們考慮基座和肘部的伺服馬達,這意味著他們可以上/下(up/down) 引導手臂;遇到錯誤時,機器手臂會把自己設置為posBase = 50; 或 posElbow = 50;
Case 2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
switch (cmd) { case '0': downBase(); break; case '1': //do nothing break; case '2': upBase(); break; case '3': posBase = 50; break; } state = 0; break; |
Case 3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
switch (cmd) { case '0': downElbow(); break; case '1': //do nothing break; case '2': upElbow(); break; case '3': posElbow = 50; break; case '4': posElbow = 10; break; } state = 0; break; |
在case 4中,我們需要控制爪鉗,這個非常簡單—將其初始位置設置為posGH = 50;
請將以下代碼添加到Arduino UNO中,以進行機器手臂控制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
// States for the RoboticArm: //0 Down on the left //1 Pause //2 Top on the right //3 Reset #include <Servo.h> Servo Circle; //1 Servo Base; //2 Servo Elbow; //3 Servo Wrist; //4 int posCircle = 0; int posBase = 50; int posElbow = 50; int posGH = 50; int state = 0; void setup() { Serial.begin(9600); Elbow.attach(7); Base.attach(8); Circle.attach(9); Wrist.attach(10); delay(1000); control(1, posCircle); control(2, posBase); control(3, posElbow); control(4, posGH); } void loop() { if(Serial.available() > 0) { char cmd = Serial.read(); switch (state) { case 0: if(cmd == 'A') state = 1; if(cmd == 'B') state = 2; if(cmd == 'C') state = 3; if(cmd == 'D') state = 4; break; case 1: switch (cmd) { case '0': Left(); break; case '1': //do nothing break; case '2': Right(); break; case '3': posCircle = 0; break; } state = 0; break; case 2: switch (cmd) { case '0': downBase(); break; case '1': //do nothing break; case '2': upBase(); break; case '3': posBase = 50; break; } state = 0; break; case 3: switch (cmd) { case '0': downElbow(); break; case '1': //do nothing break; case '2': upElbow(); break; case '3': posElbow = 50; break; case '4': posElbow = 10; break; } state = 0; break; case 4: switch (cmd) { case '0': break; case '1': break; case '2': break; case '3': posGH = 50; break; } state = 0; break; } } } void control(int motor, int angle) { switch (motor) { case 1: if(angle >= 0) if(angle <= 140) Circle.write(angle + 10); break; case 2: if(angle >= 0) if(angle <= 60) Base.write(140 - angle); break; case 3: if(angle >= 0) if(angle <= 70) Elbow.write(80 - angle); break; case 4: if(angle >= 0) if(angle <= 65) Wrist.write(75 - angle); break; } } void Left() { if(posCircle <= 136) { posCircle = posCircle + 4; } else posCircle = 140; control(1, posCircle); } void Right() { if(posCircle >= 4) { posCircle = posCircle - 4; } else posCircle = 0; control(1, posCircle); } /////////////////////////////////// void downElbow() { if(posElbow >= 4) { posElbow = posElbow - 4; } else posElbow = 0; control(3, posElbow); } void upElbow() { if(posElbow <= 66) { posElbow = posElbow + 4; } else posElbow = 70; control(3, posElbow); } ////////////////////////////////////// void downBase() { if(posBase >= 4) { posBase = posBase - 4; } else posBase = 0; control(2, posBase); } void upBase() { if(posBase <= 56) { posBase = posBase + 4; } else posBase = 60; control(2, posBase); } |