Components and supplies
PCA9685 16 Canali 12 bit Modulo I2C Driver di Motore Servo PWM per Robot Arduino
RGB LCD Shield Kit, 16x2 Character Display
Jumper wires (generic)
Remote Control IR 38 Khz and receiver HX1838
MG966R Servo
Arduino Due
Robotic Arm 6dof model ROT3U
Project description
Code
Robotic arm code
arduino
This is the Arduino code
1 2 3#include <Wire.h> 4#include <Adafruit_PWMServoDriver.h> 5#include <IRremote2.h> 6#include <LiquidCrystal.h> 7 8/* ---------- TRIS VARIABLE ---------- */ 9#define INT_MIN -2147483648 10#define INT_MAX +2147483647 11char Tris[3][3]; 12int TrisPos[3][3][4] = {{{-55,280,70,105},{0,280,60,90},{65,280,70,75}}, //x,y,z,x5 {0,0},{0,1},{0,2} 13 {{-60,210,50,110},{0,215,50,90},{60,220,50,70}}, // {1,0},{1,1},{1,2} 14 {{-65,150,45,115},{0,155,45,90},{55,160,45,65}} // {2,0},{2,1},{2,2} 15 }; 16int TakePos[6][4] = {{20,-140,40,100},{15,-205,60,95},{10,-240,90,90},{-75,-230,80,75},{-70,-175,70,70},{-65,-120,50,65}}; 17int pawn=0; 18int choice; 19 20/* ---------- IR VARIABLE ---------- */ 21// RECV_PIN = 52; 22IRrecv irrecv(52); 23decode_results results; 24 25/* ---------- LIQUIDCRYSTAL VARIABLE ---------- */ 26// pin lcd: rs = 8, en = 9, d4 = 4, d5 = 5, d6 = 6, d7 = 7; 27LiquidCrystal lcd(8, 9, 4, 5, 6, 7); 28 29/* ---------- ROBOTIC ARM VARIABLE ---------- */ 30Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); 31#define BASE_HGT 115 //base height 32/*#define HUMERUS 105 shoulder-to-elbow "bone" 33 #define ULNA 100 elbow-to-wrist "bone" 34 #define GRIPPER 170 wrist-to-gripper "bone" */ 35#define SERVO1 1 36#define SERVO2 2 37#define SERVO3 3 38#define SERVO4 4 39#define SERVO5 5 40#define SERVO6 6 41 42#define SERVOMIN1 130 43#define SERVOMAX1 430 44#define SERVOMIN2 120 45#define SERVOMAX2 365 46#define SERVOMIN3 150 47#define SERVOMAX3 430 48#define SERVOMIN4 130 49#define SERVOMAX4 435 50#define SERVOMIN5 100 51#define SERVOMAX5 380 52#define SERVOMIN6 200 53#define SERVOMAX6 325 54unsigned int ServoMinMax[6][2] = {{SERVOMIN1,SERVOMAX1}, 55 {SERVOMIN2,SERVOMAX2}, 56 {SERVOMIN3,SERVOMAX3}, 57 {SERVOMIN4,SERVOMAX4}, 58 {SERVOMIN5,SERVOMAX5}, 59 {SERVOMIN6,SERVOMAX6}}; 60 61float x1,x2,x3,x4,x5,x6 = 90; // servo position 62float oldx1,oldx2,oldx3,oldx4,oldx5,oldx6 = x1; // old servo position 63 64float xaxis = 0; 65float yaxis = 150; 66float zaxis = 100; 67 68bool checkmin = true; 69bool checkmax = true; 70 71/* ---------- setup ---------- */ 72void setup() { 73 Serial.begin(115200); 74 randomSeed(analogRead(A0)); 75 lcd.begin(16, 2); 76 lcd.clear(); 77 lcd.print(">>> T R I S <<<"); 78 lcd.setCursor(0,1); 79 lcd.print(" by Danny003"); 80 delay(2000); 81 pwm.begin(); 82 pwm.setPWMFreq(50); 83 MyServoWrite(SERVO2,90); 84 delay(1000); 85 Set_Arm(xaxis,yaxis,zaxis); 86 irrecv.enableIRIn(); 87} 88 89/* ---------- loop ---------- */ 90void loop() { 91 choice = 0; 92 for(int i=0;i<3;i++) { 93 for(int j=0;j<3;j++) { Tris[i][j]=' '; } 94 } 95 pawn = 0; 96 lcd.clear(); 97 lcd.print("Choose Who Start"); 98 lcd.setCursor(0,1); 99 lcd.print("CH-=Comp CH+=You"); 100 choice=Read_RC(); 101 while(choice==10 ) { 102 Computer_Move(); 103 if(Check_Win('O')) { 104 Show_Win(Check_Win('O')); 105 Set_Arm( xaxis = 0.0, yaxis = 130.0 , zaxis = 200.0 ); 106 lcd.clear(); 107 lcd.print(" Computer "); 108 lcd.setCursor(0,1); 109 lcd.print(" W I N S "); 110 delay(2000); 111 break; 112 } 113 if(End_Game()) { 114 lcd.clear(); 115 lcd.print(" Nobody wins "); 116 lcd.setCursor(0,1); 117 lcd.print(" F L A P "); 118 delay(2000); 119 break; 120 } 121 Player_Move(); 122 if(Check_Win('X')) { 123 lcd.clear(); 124 lcd.print(" Player "); 125 lcd.setCursor(0,1); 126 lcd.print(" W I N S "); 127 delay(2000); 128 break; 129 } 130 if(End_Game()) { 131 lcd.clear(); 132 lcd.print(" Nobody wins "); 133 lcd.setCursor(0,1); 134 lcd.print(" F L A P "); 135 delay(2000); 136 break; 137 } 138 } 139 while(choice==11) { 140 Player_Move(); 141 if(Check_Win('X')) { 142 lcd.clear(); 143 lcd.print(" Player "); 144 lcd.setCursor(0,1); 145 lcd.print(" W I N S "); 146 delay(2000); 147 break; 148 } 149 if(End_Game()) { 150 lcd.clear(); 151 lcd.print(" Nobody wins "); 152 lcd.setCursor(0,1); 153 lcd.print(" F L A P "); 154 delay(2000); 155 break; 156 } 157 Computer_Move(); 158 if(Check_Win('O')) { 159 Show_Win(Check_Win('O')); 160 Set_Arm( xaxis = 0.0, yaxis = 130.0 , zaxis = 200.0 ); 161 lcd.clear(); 162 lcd.print(" Computer "); 163 lcd.setCursor(0,1); 164 lcd.print(" W I N S "); 165 delay(2000); 166 break; 167 } 168 if(End_Game()) { 169 lcd.clear(); 170 lcd.print(" Nobody wins "); 171 lcd.setCursor(0,1); 172 lcd.print(" F L A P "); 173 delay(2000); 174 break; 175 } 176 } 177 Tidy(); 178} 179 180 181/* -------------------- ROBOTIC ARM FUNCTION -------------------- */ 182 183/* ---------- MyServoWrite ---------- */ 184/* This funciont is used to move a singular servo*/ 185void MyServoWrite(int servo, float gradi) { 186 pwm.setPWM( servo, 0, MapNew(gradi, 0.0, 180.0, ServoMinMax[servo-1][0], ServoMinMax[servo-1][1] )); 187} 188 189/* ---------- MyServoWriteAll ---------- */ 190/* This funciont is used to move the first 4 servo, it has been created to avoid to repeat the funciont MyServoWrite 4 times */ 191void MyServoWriteAll(float y1,float y2,float y3,float y4) { 192 pwm.setPWM( SERVO1, 0, MapNew(y1, 0.0, 180.0, ServoMinMax[SERVO1-1][0], ServoMinMax[SERVO1-1][1] )); 193 pwm.setPWM( SERVO2, 0, MapNew(y2, 0.0, 180.0, ServoMinMax[SERVO2-1][0], ServoMinMax[SERVO2-1][1] )); 194 pwm.setPWM( SERVO3, 0, MapNew(y3, 0.0, 180.0, ServoMinMax[SERVO3-1][0], ServoMinMax[SERVO3-1][1] )); 195 pwm.setPWM( SERVO4, 0, MapNew(y4, 0.0, 180.0, ServoMinMax[SERVO4-1][0], ServoMinMax[SERVO4-1][1] )); 196} 197 198/* ---------- MyServoWriteGradual ---------- */ 199/*This function is similar to MyServoWriteAll; but to avoid too rapid movement, 200 in particular when the robotic arm goes from a position to another one,this function creates 201 a smooth and simultaneous movement of the 4 servo, whose time depends on the variation of the bigger angle*/ 202void MyServoWriteGradual( float newpos1, float newpos2, float newpos3, float newpos4 ) { 203 float oldpos1 = oldx1; 204 float oldpos2 = oldx2; 205 float oldpos3 = oldx3; 206 float oldpos4 = oldx4; 207 float differ1 = newpos1 - oldpos1; 208 float differ2 = newpos2 - oldpos2; 209 float differ3 = newpos3 - oldpos3; 210 float differ4 = newpos4 - oldpos4; 211 float largest = max(abs(differ1),max(abs(differ2), max(abs(differ3),abs(differ4)))); 212 for ( int i = 0; i <= largest; i++ ) { 213 oldpos1 += (differ1/largest); 214 oldpos2 += (differ2/largest); 215 oldpos3 += (differ3/largest); 216 oldpos4 += (differ4/largest); 217 MyServoWriteAll(oldpos1,oldpos2,oldpos3,oldpos4); 218 delay(10); 219 } 220 MyServoWriteAll(newpos1,newpos2,newpos3,newpos4); 221} 222 223/* ---------- Set_Arm ---------- */ 224/* This function is the most important for the movement of the robotic arm, 225 because it calculates the postions of the first 4 servo from the three coordinates x,y,z(taken from TakePos and TrisPos). 226 The following code is specific to the configuration of MY robotic arm, so if you want to use it, you have to adapt it to your arm.*/ 227void Set_Arm( float x, float y, float z) { 228 oldx1 = x1; 229 oldx2 = x2; 230 oldx3 = x3; 231 oldx4 = x4; 232 z=z-BASE_HGT; 233 float dist_y_z = sqrt( sq(z) + sq(x) + sq(y) ); 234 if ( dist_y_z < 120.0 ) { checkmin=false; } 235 else { checkmin=true; } 236 if ( dist_y_z > 370.0 ) { checkmax=false; } 237 else { checkmax=true; } 238 if ( checkmin && checkmax ) { 239 float alfa = 180.0-(degrees(acos((-27500 + sqrt( sq(27500) - 71400*(14225 - sq(dist_y_z))))/71400))); 240 float gamma = degrees(acos((27875 -sq(dist_y_z) - (34000*cos(radians(alfa))))/(-210*dist_y_z))); 241 float omega = degrees(acos(sqrt(sq(x)+sq(y))/dist_y_z)); 242 x1 = 90.0-degrees(atan2(-x,abs(y))); 243 if ( z > 0.0 ) { x2=180.0-(gamma+omega); } 244 else { x2=180.0-(gamma-omega); } 245 if ( y < 0.0) { x3=x4=(alfa-90.0); } 246 else { 247 x3=x4=(270.0-alfa); 248 x2=180.0-x2; 249 x1=180.0-x1; 250 } 251 if ((abs(oldx1-x1)+abs(oldx2-x2)+abs(oldx3-x3)+abs(oldx4-x4)) > 20.0) { MyServoWriteGradual(x1,x2,x3,x4); } 252 else { MyServoWriteAll(x1,x2,x3,x4); } 253 } 254} 255 256/* ---------- Reach_Position ---------- */ 257/*Through this function, the Robotic Arm grabs a pawn from a position and it leaves the pawn in another position */ 258void Reach_Position ( float fromx, float fromy, float fromz, float fromangle, float tox, float toy, float toz, float toangle ) { 259 Set_Arm( fromx, fromy, fromz+50 ); 260 delay(300); 261 MyServoWrite( SERVO6, 0 ); 262 MyServoWrite( SERVO5, fromangle ); 263 delay(1000); 264 Set_Arm( fromx, fromy, fromz ); 265 delay(300); 266 MyServoWrite( SERVO6, 130 ); 267 delay(500); 268 Set_Arm( fromx, fromy, fromz + 100 ); 269 delay(500); 270 Set_Arm( tox, toy, toz+150); 271 delay(1000); 272 MyServoWrite( SERVO5, toangle ); 273 delay(300); 274 Set_Arm( tox, toy, toz ); 275 delay(300); 276 MyServoWrite( SERVO6, 0 ); 277 delay(1000); 278 Set_Arm( xaxis = 0.0, yaxis = 130.0 , zaxis = 200.0 ); 279 MyServoWrite( SERVO5, 90 ); 280 } 281 282/* ---------- MapNew ---------- */ 283/*This function has been created because the Arduino map() has not the funciont constrain() and it does not return a int value */ 284int MapNew( float x, float in_min, float in_max, float out_min, float out_max ) { 285 return round((constrain(x,in_min,in_max) - in_min) * (out_max - out_min) / (in_max - in_min) + out_min); 286} 287 288/* ---------- Show_Win ---------- */ 289/*Through this function, if computer wins, the Robotic Arm moves over the tris to show to the player that it have just won */ 290void Show_Win(int triscase) { 291 MyServoWrite(SERVO6,150); 292 switch(triscase){ 293 case 1: 294 Set_Arm( TrisPos[0][0][0],TrisPos[0][0][1],TrisPos[0][0][2]+100); 295 Set_Arm( TrisPos[2][2][0],TrisPos[2][2][1],TrisPos[2][2][2]+100); 296 break ; 297 case 2: 298 Set_Arm( TrisPos[2][0][0],TrisPos[2][0][1],TrisPos[2][0][2]+100); 299 Set_Arm( TrisPos[0][2][0],TrisPos[0][2][1],TrisPos[0][2][2]+100); 300 break ; 301 case 3: 302 Set_Arm( TrisPos[0][0][0],TrisPos[0][0][1],TrisPos[0][0][2]+100); 303 Set_Arm( TrisPos[0][2][0],TrisPos[0][2][1],TrisPos[0][2][2]+100); 304 break ; 305 case 4: 306 Set_Arm( TrisPos[1][0][0],TrisPos[1][0][1],TrisPos[1][0][2]+100); 307 Set_Arm( TrisPos[1][2][0],TrisPos[1][2][1],TrisPos[1][2][2]+100); 308 break ; 309 case 5: 310 Set_Arm( TrisPos[2][0][0],TrisPos[2][0][1],TrisPos[2][0][2]+100); 311 Set_Arm( TrisPos[2][2][0],TrisPos[2][2][1],TrisPos[2][2][2]+100); 312 break ; 313 case 6: 314 Set_Arm( TrisPos[0][0][0],TrisPos[0][0][1],TrisPos[0][0][2]+100); 315 Set_Arm( TrisPos[2][0][0],TrisPos[2][0][1],TrisPos[2][0][2]+100); 316 break ; 317 case 7: 318 Set_Arm( TrisPos[0][1][0],TrisPos[0][1][1],TrisPos[0][1][2]+100); 319 Set_Arm( TrisPos[2][1][0],TrisPos[2][1][1],TrisPos[2][1][2]+100); 320 break ; 321 case 8: 322 Set_Arm( TrisPos[0][2][0],TrisPos[0][2][1],TrisPos[0][2][2]+100); 323 Set_Arm( TrisPos[2][2][0],TrisPos[2][2][1],TrisPos[2][2][2]+100); 324 break ; 325 326 } 327 MyServoWrite(SERVO6,0); 328} 329 330 331/* -------------------- TIC TAC TOE FUNCTION -------------------- */ 332//The following functions are taken from : http://www.pierotofy.it/pages/sorgenti/browse/17648/3447/ 333 334/* ---------- Possible ---------- */ 335/*This function check if position i,j is free. */ 336bool Possible(int i, int j) { return Tris[i][j]==' '; } 337 338/* ---------- End_Game ---------- */ 339/*This function check if all position are occupied by a pawn. */ 340bool End_Game(){ 341 for(int i=0;i<3;i++) { 342 for(int j=0;j<3;j++) { 343 if(Possible(i,j)){return false;} 344 } 345 } 346 return true; 347} 348 349/* ---------- Check_Win ---------- */ 350/*This function check all the 8 possible combinations to win at tris. */ 351int Check_Win(char wnr) { 352 int returnvalue=0; 353 if(Tris[0][0]==wnr&&Tris[1][1]==wnr&&Tris[2][2]==wnr) {returnvalue = 1;} 354 if(Tris[2][0]==wnr&&Tris[1][1]==wnr&&Tris[0][2]==wnr) {returnvalue = 2;} 355 if(Tris[0][0]==wnr&&Tris[0][1]==wnr&&Tris[0][2]==wnr) {returnvalue = 3;} 356 if(Tris[1][0]==wnr&&Tris[1][1]==wnr&&Tris[1][2]==wnr) {returnvalue = 4;} 357 if(Tris[2][0]==wnr&&Tris[2][1]==wnr&&Tris[2][2]==wnr) {returnvalue = 5;} 358 if(Tris[0][0]==wnr&&Tris[1][0]==wnr&&Tris[2][0]==wnr) {returnvalue = 6;} 359 if(Tris[0][1]==wnr&&Tris[1][1]==wnr&&Tris[2][1]==wnr) {returnvalue = 7;} 360 if(Tris[0][2]==wnr&&Tris[1][2]==wnr&&Tris[2][2]==wnr) {returnvalue = 8;} 361 return returnvalue; 362} 363 364/* ---------- Computer_Move ---------- */ 365/* This function consider which position is better and move the robotic arm */ 366void Computer_Move() { 367 long maxvalue=INT_MIN,mi=1,mj=1,t; 368 lcd.clear(); 369 lcd.print(" I Am Thinking"); 370 lcd.setCursor(0,1); 371 lcd.print(" Wait"); 372 if( choice == 10 && pawn == 0 ) { 373 mi = int(random(0,3)); 374 mj = int(random(0,3)); 375 } 376 else { 377 for(int i=0;i<3;i++) { 378 for(int j=0;j<3;j++) { 379 if(Possible(i,j)) { 380 Tris[i][j]='O'; 381 t=Consider_Move('X', 20); 382 if(t>maxvalue) { 383 maxvalue=t; 384 mi=i; 385 mj=j; 386 } 387 Tris[i][j]=' '; 388 } 389 } 390 } 391 } 392 Tris[mi][mj]='O'; 393 Reach_Position(TakePos[pawn][0],TakePos[pawn][1],TakePos[pawn][2],TakePos[pawn][3],TrisPos[mi][mj][0],TrisPos[mi][mj][1],TrisPos[mi][mj][2],TrisPos[mi][mj][3]); 394 pawn++; 395} 396 397/* ---------- Consider_Move ---------- */ 398/* This function uses minimax algoritm */ 399long Consider_Move(char wnr, int deep) { 400 int i, j, res, tmp; 401 if(Check_Win('O')) { return INT_MAX; } 402 if(End_Game()) { return 0; } 403 if(wnr=='X') { 404 res=1; 405 for(i=0;i<3;i++) { 406 for(j=0;j<3;j++) { 407 if(Possible(i,j)) { 408 Tris[i][j]='X'; 409 if(Check_Win('X')) { 410 if(deep==20) { 411 Tris[i][j]=' '; 412 return INT_MIN; 413 } 414 else {res-=2;} 415 } 416 else if((tmp=Consider_Move('O', deep - 1))<res) { res=tmp; } 417 Tris[i][j]=' '; 418 } 419 } 420 } 421 } 422 else { 423 res=-1; 424 for(i=0;i<3;i++) { 425 for(j=0;j<3;j++) { 426 if(Possible(i,j)) { 427 Tris[i][j]='O'; 428 if(Check_Win('O')) {res+=2;} 429 else if((tmp=Consider_Move('X', deep - 1))>res) {res=tmp;} 430 Tris[i][j]=' '; 431 } 432 } 433 } 434 } 435 return res; 436} 437 438/* ---------- Player_Move ---------- */ 439/* This function, depending on which button you pressed, update the position of your pawns */ 440void Player_Move() { 441 int i=0; 442 lcd.clear(); 443 lcd.print(" Insert your "); 444 lcd.setCursor(0,1); 445 lcd.print(" M O V E "); 446 do { 447 i=Read_RC(); 448 if ((i==9)&&Possible(0,0)) { Tris[0][0]='X'; } 449 else if ((i==8)&&Possible(0,1)) { Tris[0][1]='X'; } 450 else if ((i==7)&&Possible(0,2)) { Tris[0][2]='X'; } 451 else if ((i==6)&&Possible(1,0)) { Tris[1][0]='X'; } 452 else if ((i==5)&&Possible(1,1)) { Tris[1][1]='X'; } 453 else if ((i==4)&&Possible(1,2)) { Tris[1][2]='X'; } 454 else if ((i==3)&&Possible(2,0)) { Tris[2][0]='X'; } 455 else if ((i==2)&&Possible(2,1)) { Tris[2][1]='X'; } 456 else if ((i==1)&&Possible(2,2)) { Tris[2][2]='X'; } 457 else { 458 i=0; 459 lcd.clear(); 460 lcd.print(" I N V A L I D "); 461 lcd.setCursor(0,1); 462 lcd.print(" M O V E ");} 463 }while(i<1||i>9); 464} 465 466/* ---------- Read_RC ---------- */ 467/* This function read the button you pressed */ 468int Read_RC(){ 469 int returnvalue=99; 470 while (returnvalue==99){ 471 while (!irrecv.decode(&results)) {}; 472 switch(results.value){ 473 case 0xFFA25D: // CH- 474 returnvalue=10; 475 break; 476 case 0xFFE21D: //CH+ 477 returnvalue=11; 478 break; 479 case 0xFF30CF: // 1 480 returnvalue=1; 481 break ; 482 case 0xFF18E7: // 2 483 returnvalue=2; 484 break ; 485 case 0xFF7A85: // 3 486 returnvalue=3; 487 break ; 488 case 0xFF10EF: // 4 489 returnvalue=4; 490 break ; 491 case 0xFF38C7: // 5 492 returnvalue=5; 493 break ; 494 case 0xFF5AA5: // 6 495 returnvalue=6; 496 break ; 497 case 0xFF42BD: // 7 498 returnvalue=7; 499 break ; 500 case 0xFF4AB5: // 8 501 returnvalue=8; 502 break ; 503 case 0xFF52AD: // 9 504 returnvalue=9; 505 break ; 506 } 507 irrecv.resume(); 508 } 509 return returnvalue; 510} 511 512/* ---------- Tidy ---------- */ 513/*Through this function, the Robotic Arm tidies the pawns so they are in position for the next game */ 514void Tidy() { 515 for(int i=0;i<3;i++) { 516 for(int j=0;j<3;j++) { 517 if(Tris[i][j]=='O') { pawn--; 518 Reach_Position(TrisPos[i][j][0],TrisPos[i][j][1],TrisPos[i][j][2],TrisPos[i][j][3],TakePos[pawn][0],TakePos[pawn][1],TakePos[pawn][2]+10,TakePos[pawn][3]); } 519 } 520 } 521} 522
Robotic arm code
arduino
This is the Arduino code
1 2 3#include <Wire.h> 4#include <Adafruit_PWMServoDriver.h> 5#include 6 <IRremote2.h> 7#include <LiquidCrystal.h> 8 9/* ---------- TRIS VARIABLE ---------- 10 */ 11#define INT_MIN -2147483648 12#define INT_MAX +2147483647 13char Tris[3][3]; 14int 15 TrisPos[3][3][4] = {{{-55,280,70,105},{0,280,60,90},{65,280,70,75}}, //x,y,z,x5 16 {0,0},{0,1},{0,2} 17 {{-60,210,50,110},{0,215,50,90},{60,220,50,70}}, 18 // {1,0},{1,1},{1,2} 19 {{-65,150,45,115},{0,155,45,90},{55,160,45,65}} 20 // {2,0},{2,1},{2,2} 21 }; 22int TakePos[6][4] 23 = {{20,-140,40,100},{15,-205,60,95},{10,-240,90,90},{-75,-230,80,75},{-70,-175,70,70},{-65,-120,50,65}}; 24int 25 pawn=0; 26int choice; 27 28/* ---------- IR VARIABLE ---------- */ 29// RECV_PIN 30 = 52; 31IRrecv irrecv(52); 32decode_results results; 33 34/* ---------- LIQUIDCRYSTAL 35 VARIABLE ---------- */ 36// pin lcd: rs = 8, en = 9, d4 = 4, d5 = 5, d6 = 6, d7 37 = 7; 38LiquidCrystal lcd(8, 9, 4, 5, 6, 7); 39 40/* ---------- ROBOTIC ARM VARIABLE 41 ---------- */ 42Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); 43#define 44 BASE_HGT 115 //base height 45/*#define HUMERUS 105 shoulder-to-elbow "bone" 46 47 #define ULNA 100 elbow-to-wrist "bone" 48 #define GRIPPER 170 wrist-to-gripper 49 "bone" */ 50#define SERVO1 1 51#define SERVO2 2 52#define SERVO3 3 53#define 54 SERVO4 4 55#define SERVO5 5 56#define SERVO6 6 57 58#define SERVOMIN1 130 59#define 60 SERVOMAX1 430 61#define SERVOMIN2 120 62#define SERVOMAX2 365 63#define SERVOMIN3 64 150 65#define SERVOMAX3 430 66#define SERVOMIN4 130 67#define SERVOMAX4 435 68#define 69 SERVOMIN5 100 70#define SERVOMAX5 380 71#define SERVOMIN6 200 72#define SERVOMAX6 73 325 74unsigned int ServoMinMax[6][2] = {{SERVOMIN1,SERVOMAX1}, 75 {SERVOMIN2,SERVOMAX2}, 76 77 {SERVOMIN3,SERVOMAX3}, 78 {SERVOMIN4,SERVOMAX4}, 79 80 {SERVOMIN5,SERVOMAX5}, 81 {SERVOMIN6,SERVOMAX6}}; 82 83float 84 x1,x2,x3,x4,x5,x6 = 90; // servo position 85float oldx1,oldx2,oldx3,oldx4,oldx5,oldx6 86 = x1; // old servo position 87 88float xaxis = 0; 89float yaxis = 150; 90float 91 zaxis = 100; 92 93bool checkmin = true; 94bool checkmax = true; 95 96/* ---------- 97 setup ---------- */ 98void setup() { 99 Serial.begin(115200); 100 randomSeed(analogRead(A0)); 101 102 lcd.begin(16, 2); 103 lcd.clear(); 104 lcd.print(">>> T R I S <<<"); 105 lcd.setCursor(0,1); 106 107 lcd.print(" by Danny003"); 108 delay(2000); 109 pwm.begin(); 110 pwm.setPWMFreq(50); 111 112 MyServoWrite(SERVO2,90); 113 delay(1000); 114 Set_Arm(xaxis,yaxis,zaxis); 115 116 irrecv.enableIRIn(); 117} 118 119/* ---------- loop ---------- */ 120void loop() 121 { 122 choice = 0; 123 for(int i=0;i<3;i++) { 124 for(int j=0;j<3;j++) { Tris[i][j]=' 125 '; } 126 } 127 pawn = 0; 128 lcd.clear(); 129 lcd.print("Choose Who Start"); 130 131 lcd.setCursor(0,1); 132 lcd.print("CH-=Comp CH+=You"); 133 choice=Read_RC(); 134 135 while(choice==10 ) { 136 Computer_Move(); 137 if(Check_Win('O')) { 138 139 Show_Win(Check_Win('O')); 140 Set_Arm( xaxis = 0.0, yaxis = 130.0 , zaxis 141 = 200.0 ); 142 lcd.clear(); 143 lcd.print(" Computer "); 144 lcd.setCursor(0,1); 145 146 lcd.print(" W I N S "); 147 delay(2000); 148 break; 149 } 150 151 if(End_Game()) { 152 lcd.clear(); 153 lcd.print(" Nobody wins "); 154 155 lcd.setCursor(0,1); 156 lcd.print(" F L A P "); 157 delay(2000); 158 159 break; 160 } 161 Player_Move(); 162 if(Check_Win('X')) { 163 lcd.clear(); 164 165 lcd.print(" Player "); 166 lcd.setCursor(0,1); 167 lcd.print(" 168 W I N S "); 169 delay(2000); 170 break; 171 } 172 if(End_Game()) 173 { 174 lcd.clear(); 175 lcd.print(" Nobody wins "); 176 lcd.setCursor(0,1); 177 178 lcd.print(" F L A P "); 179 delay(2000); 180 break; 181 } 182 183 } 184 while(choice==11) { 185 Player_Move(); 186 if(Check_Win('X')) { 187 188 lcd.clear(); 189 lcd.print(" Player "); 190 lcd.setCursor(0,1); 191 192 lcd.print(" W I N S "); 193 delay(2000); 194 break; 195 } 196 197 if(End_Game()) { 198 lcd.clear(); 199 lcd.print(" Nobody wins "); 200 201 lcd.setCursor(0,1); 202 lcd.print(" F L A P "); 203 delay(2000); 204 205 break; 206 } 207 Computer_Move(); 208 if(Check_Win('O')) { 209 Show_Win(Check_Win('O')); 210 211 Set_Arm( xaxis = 0.0, yaxis = 130.0 , zaxis = 200.0 ); 212 lcd.clear(); 213 214 lcd.print(" Computer "); 215 lcd.setCursor(0,1); 216 lcd.print(" 217 W I N S "); 218 delay(2000); 219 break; 220 } 221 if(End_Game()) 222 { 223 lcd.clear(); 224 lcd.print(" Nobody wins "); 225 lcd.setCursor(0,1); 226 227 lcd.print(" F L A P "); 228 delay(2000); 229 break; 230 } 231 232 } 233 Tidy(); 234} 235 236 237/* -------------------- ROBOTIC ARM FUNCTION -------------------- 238 */ 239 240/* ---------- MyServoWrite ---------- */ 241/* This funciont is used to 242 move a singular servo*/ 243void MyServoWrite(int servo, float gradi) { 244 pwm.setPWM( 245 servo, 0, MapNew(gradi, 0.0, 180.0, ServoMinMax[servo-1][0], ServoMinMax[servo-1][1] 246 )); 247} 248 249/* ---------- MyServoWriteAll ---------- */ 250/* This funciont 251 is used to move the first 4 servo, it has been created to avoid to repeat the funciont 252 MyServoWrite 4 times */ 253void MyServoWriteAll(float y1,float y2,float y3,float 254 y4) { 255 pwm.setPWM( SERVO1, 0, MapNew(y1, 0.0, 180.0, ServoMinMax[SERVO1-1][0], 256 ServoMinMax[SERVO1-1][1] )); 257 pwm.setPWM( SERVO2, 0, MapNew(y2, 0.0, 180.0, 258 ServoMinMax[SERVO2-1][0], ServoMinMax[SERVO2-1][1] )); 259 pwm.setPWM( SERVO3, 260 0, MapNew(y3, 0.0, 180.0, ServoMinMax[SERVO3-1][0], ServoMinMax[SERVO3-1][1] )); 261 262 pwm.setPWM( SERVO4, 0, MapNew(y4, 0.0, 180.0, ServoMinMax[SERVO4-1][0], ServoMinMax[SERVO4-1][1] 263 )); 264} 265 266/* ---------- MyServoWriteGradual ---------- */ 267/*This function 268 is similar to MyServoWriteAll; but to avoid too rapid movement, 269 in particular 270 when the robotic arm goes from a position to another one,this function creates 271 272 a smooth and simultaneous movement of the 4 servo, whose time depends on the variation 273 of the bigger angle*/ 274void MyServoWriteGradual( float newpos1, float newpos2, 275 float newpos3, float newpos4 ) { 276 float oldpos1 = oldx1; 277 float oldpos2 278 = oldx2; 279 float oldpos3 = oldx3; 280 float oldpos4 = oldx4; 281 float differ1 282 = newpos1 - oldpos1; 283 float differ2 = newpos2 - oldpos2; 284 float differ3 285 = newpos3 - oldpos3; 286 float differ4 = newpos4 - oldpos4; 287 float largest 288 = max(abs(differ1),max(abs(differ2), max(abs(differ3),abs(differ4)))); 289 for 290 ( int i = 0; i <= largest; i++ ) { 291 oldpos1 += (differ1/largest); 292 oldpos2 293 += (differ2/largest); 294 oldpos3 += (differ3/largest); 295 oldpos4 += (differ4/largest); 296 297 MyServoWriteAll(oldpos1,oldpos2,oldpos3,oldpos4); 298 delay(10); 299 300 } 301 MyServoWriteAll(newpos1,newpos2,newpos3,newpos4); 302} 303 304/* ---------- 305 Set_Arm ---------- */ 306/* This function is the most important for the movement 307 of the robotic arm, 308 because it calculates the postions of the first 4 servo 309 from the three coordinates x,y,z(taken from TakePos and TrisPos). 310 The following 311 code is specific to the configuration of MY robotic arm, so if you want to use it, 312 you have to adapt it to your arm.*/ 313void Set_Arm( float x, float y, float z) 314 { 315 oldx1 = x1; 316 oldx2 = x2; 317 oldx3 = x3; 318 oldx4 = x4; 319 z=z-BASE_HGT; 320 321 float dist_y_z = sqrt( sq(z) + sq(x) + sq(y) ); 322 if ( dist_y_z < 120.0 ) 323 { checkmin=false; } 324 else { checkmin=true; } 325 if ( dist_y_z > 370.0 ) 326 { checkmax=false; } 327 else { checkmax=true; } 328 if ( checkmin && checkmax 329 ) { 330 float alfa = 180.0-(degrees(acos((-27500 + sqrt( sq(27500) - 71400*(14225 331 - sq(dist_y_z))))/71400))); 332 float gamma = degrees(acos((27875 -sq(dist_y_z) 333 - (34000*cos(radians(alfa))))/(-210*dist_y_z))); 334 float omega = degrees(acos(sqrt(sq(x)+sq(y))/dist_y_z)); 335 336 x1 = 90.0-degrees(atan2(-x,abs(y))); 337 if ( z > 0.0 ) { x2=180.0-(gamma+omega); 338 } 339 else { x2=180.0-(gamma-omega); } 340 if ( y < 0.0) { x3=x4=(alfa-90.0); 341 } 342 else { 343 x3=x4=(270.0-alfa); 344 x2=180.0-x2; 345 x1=180.0-x1; 346 347 } 348 if ((abs(oldx1-x1)+abs(oldx2-x2)+abs(oldx3-x3)+abs(oldx4-x4)) > 20.0) 349 { MyServoWriteGradual(x1,x2,x3,x4); } 350 else { MyServoWriteAll(x1,x2,x3,x4); 351 } 352 } 353} 354 355/* ---------- Reach_Position ---------- */ 356/*Through this 357 function, the Robotic Arm grabs a pawn from a position and it leaves the pawn in 358 another position */ 359void Reach_Position ( float fromx, float fromy, float fromz, 360 float fromangle, float tox, float toy, float toz, float toangle ) { 361 Set_Arm( 362 fromx, fromy, fromz+50 ); 363 delay(300); 364 MyServoWrite( SERVO6, 0 ); 365 MyServoWrite( 366 SERVO5, fromangle ); 367 delay(1000); 368 Set_Arm( fromx, fromy, fromz ); 369 370 delay(300); 371 MyServoWrite( SERVO6, 130 ); 372 delay(500); 373 Set_Arm( fromx, 374 fromy, fromz + 100 ); 375 delay(500); 376 Set_Arm( tox, toy, toz+150); 377 delay(1000); 378 379 MyServoWrite( SERVO5, toangle ); 380 delay(300); 381 Set_Arm( tox, toy, toz 382 ); 383 delay(300); 384 MyServoWrite( SERVO6, 0 ); 385 delay(1000); 386 Set_Arm( 387 xaxis = 0.0, yaxis = 130.0 , zaxis = 200.0 ); 388 MyServoWrite( SERVO5, 90 ); 389 390 } 391 392/* ---------- MapNew ---------- */ 393/*This function has been created 394 because the Arduino map() has not the funciont constrain() and it does not return 395 a int value */ 396int MapNew( float x, float in_min, float in_max, float out_min, 397 float out_max ) { 398 return round((constrain(x,in_min,in_max) - in_min) * (out_max 399 - out_min) / (in_max - in_min) + out_min); 400} 401 402/* ---------- Show_Win ---------- 403 */ 404/*Through this function, if computer wins, the Robotic Arm moves over the 405 tris to show to the player that it have just won */ 406void Show_Win(int triscase) 407 { 408 MyServoWrite(SERVO6,150); 409 switch(triscase){ 410 case 1: 411 Set_Arm( 412 TrisPos[0][0][0],TrisPos[0][0][1],TrisPos[0][0][2]+100); 413 Set_Arm( TrisPos[2][2][0],TrisPos[2][2][1],TrisPos[2][2][2]+100); 414 415 break ; 416 case 2: 417 Set_Arm( TrisPos[2][0][0],TrisPos[2][0][1],TrisPos[2][0][2]+100); 418 419 Set_Arm( TrisPos[0][2][0],TrisPos[0][2][1],TrisPos[0][2][2]+100); 420 break 421 ; 422 case 3: 423 Set_Arm( TrisPos[0][0][0],TrisPos[0][0][1],TrisPos[0][0][2]+100); 424 425 Set_Arm( TrisPos[0][2][0],TrisPos[0][2][1],TrisPos[0][2][2]+100); 426 break 427 ; 428 case 4: 429 Set_Arm( TrisPos[1][0][0],TrisPos[1][0][1],TrisPos[1][0][2]+100); 430 431 Set_Arm( TrisPos[1][2][0],TrisPos[1][2][1],TrisPos[1][2][2]+100); 432 break 433 ; 434 case 5: 435 Set_Arm( TrisPos[2][0][0],TrisPos[2][0][1],TrisPos[2][0][2]+100); 436 437 Set_Arm( TrisPos[2][2][0],TrisPos[2][2][1],TrisPos[2][2][2]+100); 438 break 439 ; 440 case 6: 441 Set_Arm( TrisPos[0][0][0],TrisPos[0][0][1],TrisPos[0][0][2]+100); 442 443 Set_Arm( TrisPos[2][0][0],TrisPos[2][0][1],TrisPos[2][0][2]+100); 444 break 445 ; 446 case 7: 447 Set_Arm( TrisPos[0][1][0],TrisPos[0][1][1],TrisPos[0][1][2]+100); 448 449 Set_Arm( TrisPos[2][1][0],TrisPos[2][1][1],TrisPos[2][1][2]+100); 450 break 451 ; 452 case 8: 453 Set_Arm( TrisPos[0][2][0],TrisPos[0][2][1],TrisPos[0][2][2]+100); 454 455 Set_Arm( TrisPos[2][2][0],TrisPos[2][2][1],TrisPos[2][2][2]+100); 456 break 457 ; 458 459 } 460 MyServoWrite(SERVO6,0); 461} 462 463 464/* -------------------- 465 TIC TAC TOE FUNCTION -------------------- */ 466//The following functions are taken 467 from : http://www.pierotofy.it/pages/sorgenti/browse/17648/3447/ 468 469/* ---------- 470 Possible ---------- */ 471/*This function check if position i,j is free. */ 472bool 473 Possible(int i, int j) { return Tris[i][j]==' '; } 474 475/* ---------- End_Game 476 ---------- */ 477/*This function check if all position are occupied by a pawn. */ 478bool 479 End_Game(){ 480 for(int i=0;i<3;i++) { 481 for(int j=0;j<3;j++) { 482 if(Possible(i,j)){return 483 false;} 484 } 485 } 486 return true; 487} 488 489/* ---------- Check_Win ---------- 490 */ 491/*This function check all the 8 possible combinations to win at tris. */ 492int 493 Check_Win(char wnr) { 494 int returnvalue=0; 495 if(Tris[0][0]==wnr&&Tris[1][1]==wnr&&Tris[2][2]==wnr) 496 {returnvalue = 1;} 497 if(Tris[2][0]==wnr&&Tris[1][1]==wnr&&Tris[0][2]==wnr) {returnvalue 498 = 2;} 499 if(Tris[0][0]==wnr&&Tris[0][1]==wnr&&Tris[0][2]==wnr) {returnvalue = 500 3;} 501 if(Tris[1][0]==wnr&&Tris[1][1]==wnr&&Tris[1][2]==wnr) {returnvalue = 4;} 502 503 if(Tris[2][0]==wnr&&Tris[2][1]==wnr&&Tris[2][2]==wnr) {returnvalue = 5;} 504 if(Tris[0][0]==wnr&&Tris[1][0]==wnr&&Tris[2][0]==wnr) 505 {returnvalue = 6;} 506 if(Tris[0][1]==wnr&&Tris[1][1]==wnr&&Tris[2][1]==wnr) {returnvalue 507 = 7;} 508 if(Tris[0][2]==wnr&&Tris[1][2]==wnr&&Tris[2][2]==wnr) {returnvalue = 509 8;} 510 return returnvalue; 511} 512 513/* ---------- Computer_Move ---------- 514 */ 515/* This function consider which position is better and move the robotic arm 516 */ 517void Computer_Move() { 518 long maxvalue=INT_MIN,mi=1,mj=1,t; 519 lcd.clear(); 520 521 lcd.print(" I Am Thinking"); 522 lcd.setCursor(0,1); 523 lcd.print(" Wait"); 524 525 if( choice == 10 && pawn == 0 ) { 526 mi = int(random(0,3)); 527 mj = int(random(0,3)); 528 529 } 530 else { 531 for(int i=0;i<3;i++) { 532 for(int j=0;j<3;j++) { 533 534 if(Possible(i,j)) { 535 Tris[i][j]='O'; 536 t=Consider_Move('X', 537 20); 538 if(t>maxvalue) { 539 maxvalue=t; 540 mi=i; 541 542 mj=j; 543 } 544 Tris[i][j]=' '; 545 } 546 } 547 548 } 549 } 550 Tris[mi][mj]='O'; 551 Reach_Position(TakePos[pawn][0],TakePos[pawn][1],TakePos[pawn][2],TakePos[pawn][3],TrisPos[mi][mj][0],TrisPos[mi][mj][1],TrisPos[mi][mj][2],TrisPos[mi][mj][3]); 552 553 pawn++; 554} 555 556/* ---------- Consider_Move ---------- */ 557/* This function 558 uses minimax algoritm */ 559long Consider_Move(char wnr, int deep) { 560 int i, 561 j, res, tmp; 562 if(Check_Win('O')) { return INT_MAX; } 563 if(End_Game()) { 564 return 0; } 565 if(wnr=='X') { 566 res=1; 567 for(i=0;i<3;i++) { 568 for(j=0;j<3;j++) 569 { 570 if(Possible(i,j)) { 571 Tris[i][j]='X'; 572 if(Check_Win('X')) 573 { 574 if(deep==20) { 575 Tris[i][j]=' '; 576 return 577 INT_MIN; 578 } 579 else {res-=2;} 580 } 581 else 582 if((tmp=Consider_Move('O', deep - 1))<res) { res=tmp; } 583 Tris[i][j]=' 584 '; 585 } 586 } 587 } 588 } 589 else { 590 res=-1; 591 for(i=0;i<3;i++) 592 { 593 for(j=0;j<3;j++) { 594 if(Possible(i,j)) { 595 Tris[i][j]='O'; 596 597 if(Check_Win('O')) {res+=2;} 598 else if((tmp=Consider_Move('X', 599 deep - 1))>res) {res=tmp;} 600 Tris[i][j]=' '; 601 } 602 } 603 604 } 605 } 606 return res; 607} 608 609/* ---------- Player_Move ---------- */ 610/* 611 This function, depending on which button you pressed, update the position of your 612 pawns */ 613void Player_Move() { 614 int i=0; 615 lcd.clear(); 616 lcd.print(" 617 Insert your "); 618 lcd.setCursor(0,1); 619 lcd.print(" M O V E "); 620 621 do { 622 i=Read_RC(); 623 if ((i==9)&&Possible(0,0)) { Tris[0][0]='X'; 624 } 625 else if ((i==8)&&Possible(0,1)) { Tris[0][1]='X'; } 626 else if 627 ((i==7)&&Possible(0,2)) { Tris[0][2]='X'; } 628 else if ((i==6)&&Possible(1,0)) 629 { Tris[1][0]='X'; } 630 else if ((i==5)&&Possible(1,1)) { Tris[1][1]='X'; } 631 632 else if ((i==4)&&Possible(1,2)) { Tris[1][2]='X'; } 633 else if ((i==3)&&Possible(2,0)) 634 { Tris[2][0]='X'; } 635 else if ((i==2)&&Possible(2,1)) { Tris[2][1]='X'; } 636 637 else if ((i==1)&&Possible(2,2)) { Tris[2][2]='X'; } 638 else { 639 640 i=0; 641 lcd.clear(); 642 lcd.print(" I N V A L I D "); 643 lcd.setCursor(0,1); 644 645 lcd.print(" M O V E ");} 646 }while(i<1||i>9); 647} 648 649/* ---------- 650 Read_RC ---------- */ 651/* This function read the button you pressed */ 652int 653 Read_RC(){ 654 int returnvalue=99; 655 while (returnvalue==99){ 656 while (!irrecv.decode(&results)) 657 {}; 658 switch(results.value){ 659 case 0xFFA25D: // CH- 660 returnvalue=10; 661 662 break; 663 case 0xFFE21D: //CH+ 664 returnvalue=11; 665 break; 666 667 case 0xFF30CF: // 1 668 returnvalue=1; 669 break ; 670 case 671 0xFF18E7: // 2 672 returnvalue=2; 673 break ; 674 case 0xFF7A85: 675 // 3 676 returnvalue=3; 677 break ; 678 case 0xFF10EF: // 4 679 returnvalue=4; 680 681 break ; 682 case 0xFF38C7: // 5 683 returnvalue=5; 684 break 685 ; 686 case 0xFF5AA5: // 6 687 returnvalue=6; 688 break ; 689 case 690 0xFF42BD: // 7 691 returnvalue=7; 692 break ; 693 case 0xFF4AB5: 694 // 8 695 returnvalue=8; 696 break ; 697 case 0xFF52AD: // 9 698 returnvalue=9; 699 700 break ; 701 } 702 irrecv.resume(); 703 } 704 return returnvalue; 705} 706 707/* 708 ---------- Tidy ---------- */ 709/*Through this function, the Robotic Arm tidies 710 the pawns so they are in position for the next game */ 711void Tidy() { 712 for(int 713 i=0;i<3;i++) { 714 for(int j=0;j<3;j++) { 715 if(Tris[i][j]=='O') { pawn--; 716 717 Reach_Position(TrisPos[i][j][0],TrisPos[i][j][1],TrisPos[i][j][2],TrisPos[i][j][3],TakePos[pawn][0],TakePos[pawn][1],TakePos[pawn][2]+10,TakePos[pawn][3]); 718 } 719 } 720 } 721} 722
GeoGebra Simulation
javascript
this is the 3D simulation of the arm
1inary file (no preview
Downloadable files
Basic wired
Basic wired
Basic wired
Follow the following wiring diagram to connect Arduino.
Basic wired
Basic wired
Basic wired
Basic wired
Follow the following wiring diagram to connect Arduino.
Basic wired
Comments
Only logged in users can leave comments
Anonymous user
2 years ago
Hello You can download directly in the code section file Geogebra Simulation
Anonymous user
3 years ago
Congrats! This is an awesome project. I have a question. I dont quite understand the last line in the geometry calculations which states δ=CD/CH. can you please elaborate that.
Anonymous user
4 years ago
Hello I am Deiver Fab Good night, Please could you pass the geogebra to deivermurcia@gmail.com I find the cinematics very interesting, you are a genius. Geogebra Simulation of a robotic arm
Anonymous user
2 years ago
Hello You can download directly in the code section file Geogebra Simulation
dfilannino03
1 Followers
•3 Projects
8
5
Anonymous user
2 years ago
Hello I am Deiver Fab Good night, Please could you pass the geogebra to deivermurcia@gmail.com I find the cinematics very interesting, you are a genius. Geogebra Simulation of a robotic arm