We have mаnаged to build a robotic аrm that is capable of processing voice commаnds. When asked, it cаn find аnd grаb objects and give them to а certаin person (it cаn distinguish between people). In addition, it cаn also plаy online music or tell you the current weаther.
The software part of this app is made with Visual Studio 2015 because is simple to use and offers a lot of features. One of them is the Emgu CV – a library of wrapper function for calling OpenCv functions. This functions are made with Visual Studio Windows Forms and are essential when you are trying to work with image processing.
If you want to have a working project, all you need to do is to install Emgu CV on your PC. Please follow the following steps:
1. Download EmguCV
Under “Building the Examples” section of this page, you can click on the hyperlink to download Emgu CV project:
Figure 1: How to download the EmguCV
2. Add the files
Because you are working with an added library, you need to include them in Visual Studio. OpenCV is developed on C/C++ language, and if you want to use it in C# you need to add the DLL (Dynamic-Link Library) files – it MUST be included when you are working with video processing. The references are shown in the Visual Studio menu in the Solution Explorer.
Figure 2: Where to find references
If you want to add more files, all you need to do is to click on the References -> Add references and select the following from the file you downloaded:
Figure 3: Reference Manager
More information could be found on the following link: http://www.emgu.com/wiki/index.php/Setting_up_EMGU_C_Sharp
3. Examples
In the downloaded library, you can find code examples for more programs that use video processing (motion detection, face detection, and camera capture).
Figure 4: Example of OpenCV application
4. Arduino Program
The Arduino code has 4 commands: up/down for servo control, reset the position for the robotic arm when a problem occurs and do nothing when a certain part has no action on it. It has 4 degrees of freedom:
Every servomotor has given a command for control using different pins: Elbow on pin 7; Base on pin8; Circle on pin 9; and Wrist on pin 10. For controlling the servos – 4 letters sent from the C# application on the serial transmission and every state corresponds to a certain motor control instruction:
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);
The code is divided to control & command instructions for every servo motor, depending on their angle of movement.
In case 1, the commands available for the circle’s movement are 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; |
In case 2 and case 3, we are considering servomotors from the base and elbow, which means they can guide the arm up/down, and when errors are encountered the robotic arm sets itself to posBase = 50; or 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; |
In case 4 we need to control the claw, which can be very simple – setting the initial position on posGH = 50;
Add the following code to Arduino UNO for robotic arm control:
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); } |