Project in progress
Tic-Tac-Toe Board Game with Robotic Arm

Tic-Tac-Toe Board Game with Robotic Arm © GPL3+

Play tic-tac-toe against a robotic arm controlled by an Arduino Mega 2560.

  • 2,242 views
  • 3 comments
  • 9 respects

Components and supplies

4 x 4 Matrix Array 16 Key Membrane Switch Keypad Keyboard for Arduino
×1
Connector - DB9 Male Socket
×1
Female Header 4 position 0.1" spacing
This mates with the X-Arm Serial port header
×1
Connector DB9 - Female Plug
×1
Enclosure Plastic 5.5" (L) x 3.25" (W) x 1/5" (H)
Any plastic enclosure to house the Mega2560 and room to mount the DB-9 Socket. Punch or drill out holes for socket and connectors of Mega2560, and mount the Keypad on top panel of enclosure.
×1
Robotic Arm with 6DOF - Lewansoul model X-Arm
×1
BSIRI TicTacToe Classic Board Games Noughts and Crosses
×1
Nylon spacers (for board mounting)
×4
Nylon screws 4-40 size (for mounting board)
×1
Nylon nuts (for mounting board)
×4
Ardgen mega
Arduino Mega 2560 & Genuino Mega 2560
Substituted Elegoo LYSB01H4ZDYCE-ELECTRNCSMEGA 2560 R3 Board
×1

Necessary tools and machines

09507 01
Soldering iron (generic)

About this project

I wanted to use the Lewansoul's robotic arm (X-arm) ( www.lewansoul.com ) to play a real board version of tic-tac-toe to illustrate the movement of the arm to pickup and place pieces into positions in a game environment. The robotic arm is controlled by the Arduino Mega 2560 and input from the player ("X") is confirmed by a membrane keypad using keys 1-9 to represent each of the board positions 1-9. I used an existing tic-tac-toe sketch (see contributor) from GitHub, that uses the MinMax algorithm to determine which move the computer should make after the player makes each move. I added to this program the code to control the X-arm position using the stored action groups in the X-arm controller for each possible position 1-9 of the board. So for a specific move by the computer to play the next position, say, position 4, the x-arm would be sent an action group command "4" to pick up the computer piece (in this case, the computer is "O") and place it in the number 4 position on the tic-tac-toe game board. see video below:

Player is "X" and Robotic Arm is "O"

Code

tic-tac-toe sketch with robotic arm and keypad inputArduino
//
//BobN2Tech 03-22-18 add Xarm code for robotic control and Keypad input code
//Thanks to https://github.com/klauscam/ArduinoTicTacToe for the tic-tac-toe algorithm
//this code requires mega2560 which uses serial port 3 (serial3) to control the Lewansoul xarm
//note: actiongroups 0-8 must be downloaded to the xarm controller prior
//to using this program. Action group numbers 0 to 8 represent the board positions that
//will be placed the moved piece. Initially has to be done manually (train the x-arm) to determine each board position
//where the xarm will place the computer move piece.
//action group 100 is preloaed for the initial position of the arm (recommend standing up)
//action group 9 is for moving the arm as computer winning game - does some fancy gyration
//optional action group 10 is for a draw - does some gyration
//optional action group 11 is for a losing - does some humble gesture. 
//action group 12 is places arm into position where it will get the "O" pieces
//The computer will never lose!
//
int difficulty=8;
//xarm
#include <LobotServoController.h>
//Not using software serial
//#define rxPin 2  //software serial
//#define txPin 3 //software serial


//SoftwareSerial mySerial(rxPin, txPin);
//LobotServoController myse(mySerial);

//hardware serial - use only if not using serial0 ow it conflicts
 LobotServoController myse(Serial3);
 
 const int speed = 100; //percent of action speed set in group. 100 = 100% = same speed as programmed, 50 = 1/2 speed, 200 = twice speed
 int lastComputerMove = -1;
 bool xarmConnected = false;

//keypad
#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the cymbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 4, 3, 2}; //connect to the column pinouts of the keypad
char customKey;
//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 
//
 
void setup(){
  Serial.begin(9600);
   while(!Serial);
     digitalWrite(13,HIGH);
  Serial3.begin(9600); 
   while(!Serial3);
 //xarm code
//
 int moveNo = 0;
  pinMode(13,OUTPUT);
 // mySerial.begin(9600);
 //  while(!mySerial);
  //   digitalWrite(13,HIGH);


//check if xarm is connected - send the initial positon
    myse.runActionGroup(100,1);
 
   if(myse.waitForStopping(5000))  //Waiting for the action group is completed, or be stopped or timeout. The unit of the parameter(timeout) is milliscond. finish or stop, you will get a true. timeout, you will get a false
     {
       Serial.println("Xarm is connected");
       digitalWrite(13, LOW);
       xarmConnected = true;
     }
     else
      Serial.println("X-Arm not connected"); 
  
  //test - change to loop for 9 positions
 
  if (xarmConnected)
  {
  
  
  for (int i = 0;i <9; i++)
  {
      myse.setActionGroupSpeed(i,speed); //Set the running speed of i action group at % speed of programmed
      delay (1000);
   //optional test all action groups are working
   //   Serial.println("xarm move to position " + String(i));       
   //  myse.runActionGroup(i,1);
   // delay(3000);
 
  }
  //optional
   // myse.setActionGroupSpeed(100,speed); //Set the running speed of No.100 action group at 1 sec
   // delay(1000);
  
  //put arm back into stand up as initial position (assume group 100)

  //  myse.runActionGroup(100,1);

 //  delay(2000);

     xarmMove (12);   //put arm into position for getting the pieces

   delay (5000);
//
 }
}



char displayChar(int c) {
    switch(c) {
        case -1:
            return 'X';
        case 0:
            return ' ';
        case 1:
            return 'O';
    }
}

void draw(int board[9]) {
    Serial.print(" ");Serial.print(displayChar(board[0])); Serial.print(" | ");Serial.print(displayChar(board[1])); Serial.print(" | ");Serial.print(displayChar(board[2])); Serial.println(" ");
    Serial.println("---+---+---");
    Serial.print(" ");Serial.print(displayChar(board[3])); Serial.print(" | ");Serial.print(displayChar(board[4])); Serial.print(" | ");Serial.print(displayChar(board[5])); Serial.println(" ");
    Serial.println("---+---+---");
    Serial.print(" ");Serial.print(displayChar(board[6])); Serial.print(" | ");Serial.print(displayChar(board[7])); Serial.print(" | ");Serial.print(displayChar(board[8])); Serial.println(" ");
}

int win(const int board[9]) {
    //list of possible winning positions
    unsigned wins[8][3] = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6}};
    int winPos;
    for(winPos = 0; winPos < 8; ++winPos) {
        if(board[wins[winPos][0]] != 0 && board[wins[winPos][0]] == board[wins[winPos][1]] && board[wins[winPos][0]] == board[wins[winPos][2]])
            return board[wins[winPos][2]];
    }
    return 0;
}

int minimax(int board[9], int player, int depth) {
    //check the positions for players
    int winner = win(board);
    if(winner != 0) return winner*player;

    int move = -1;
    int score = -2;
    int i;
    for(i = 0; i < 9; ++i) {
     
        if(board[i] == 0) {
            board[i] = player;
            int thisScore=0;
            if (depth<difficulty){
              thisScore = -minimax(board, player*-1,depth+1);
            }
            
            if(thisScore > score) {
                score = thisScore;
                move = i; 
    
                
            }
            //choose the worst move for opponent
            board[i] = 0;
        }
    }
    if(move == -1) return 0;
    return score;
   
}

void computerMove(int board[9]) 
  {
    int move = -1;
    int score = -2;
    int i;
    for(i = 0; i < 9; ++i) {
        if(board[i] == 0) {
            board[i] = 1;
            int tempScore = -minimax(board, -1, 0);
            board[i] = 0;
            if(tempScore > score) {
                score = tempScore;
                move = i;
                lastComputerMove = i;
            }
        }
    }
    //returns a score based on minimax tree at a given node.
    board[move] = 1;
}

void playerMove(int board[9])
  {
    int move = 0;
    int bmove =0;
    String smove;
    
    do {


        
      // Get value from custom keypad but start with keypad 1 = board 0;
       Serial.println("\nInput move ([1..9]): ");
       while ((customKey = customKeypad.getKey())== NO_KEY)
       {delay(100);} 
      
      Serial.println(customKey);
      //convert to string so can convert char to integer -  
      smove = (String)customKey;
      bmove = smove.toInt()-1; //use keypad so will start with numbers 1-9 to correspond to physical board layout   
      move = bmove;
	//
	
     Serial.println("\n");
    } while ((move >= 9 || move < 0) || board[move] != 0);
    board[move] = -1;
}

void xarmMove (int action)
{
    if (!xarmConnected)
      return;
   
    myse.runActionGroup(action,1);  //run action group once for each move
 
//test to get status while its running and do other things
   Serial.println("Start RUNNING at " + String(millis()));  //show total time
   
   while (myse.isRunning()) //RAC 
   {
    
   // Serial.println("IS STILL RUNNING" + String(millis()));  //show total time
     myse.receiveHandle();       //must include this, otherwise will never leave this loop
     
   }

    Serial.println("Action Completed at " + String(millis()));  

 
     
     Serial.println("FINISH XARM MOVE");

}


void loop(){
    int board[9] = {0,0,0,0,0,0,0,0,0};
  //x-arm Play only 1, playing 2 does not work correctly
   // Serial.println("Would you like to play X(1) or O(2)?");
    Serial.println("Press 1 to start playing - you are 'X' and Computer is 'O'");  
/*  get input from computer keyboard
     while(Serial.available()==0)
    {
    delay(100);
     }

      
     int player=Serial.parseInt();
     Serial.println(player);
*/
    

    // Get value from custom keypad ;
       int player;
       String s;
       while ((customKey = customKeypad.getKey())== NO_KEY)
       {delay(100);} 
      
      Serial.println(customKey);
      //convert to string so can convert char to integer  
      s  = (String)customKey;
      player = s.toInt();
  //

    
    unsigned turn;
    for(turn = 0; turn < 9 && win(board) == 0; ++turn) {
        if((turn+player) % 2 == 0)
        {
            computerMove(board);
            
            
           Serial.println("xarm move is " + String(lastComputerMove));  
                         
           if (lastComputerMove != -1 & lastComputerMove < 9) 
              xarmMove (lastComputerMove);  //action groups index start at 0
        }
        else 
        {
            draw(board);
            playerMove(board);
        }
    }
    switch(win(board)) {
        case 0:
            Serial.println("It's a draw.\n");
            //send the initial positon
             xarmMove (12);
            break;
        case 1:
            draw(board);
            Serial.println("You lose.\n");
             xarmMove (9);
             break;
        case -1:
            Serial.println("You win!\n");
            xarmMove (11);
            break;
    }
}

Schematics

Tic-tac-toe schematic
Tic tac toe game sketch schem loe9gbcmfw
Tic-Tac-toe Breadboard
Tic tac toe game sketch bb yjndllxes8

Comments

Author

Default
bobn2tech
  • 1 project
  • 1 follower

Additional contributors

  • Sketch for playing tic-tac-toe with pc input/monitor by Klauscam

Published on

April 16, 2018

Members who respect this project

AdambenzTron k1mbb0vyrf1511688087658 9ayltl93s4PhotoDefaultDsc 0430 1ivpa3fapi

and 4 others

See similar projects
you might like

Similar projects you might like

Robotic Arm Controlled by Human Arm

Project showcase by zezarandrade

  • 3,687 views
  • 0 comments
  • 5 respects

Local and Remote Programmable Robotic Arm

Project tutorial by MJRoBot

  • 17,969 views
  • 7 comments
  • 54 respects

Nunchuk Controlled Robotic Arm (with Arduino)

Project tutorial by Igor Fonseca Albuquerque

  • 4,613 views
  • 5 comments
  • 36 respects

Gesture Controlled Robotic Arm Using Kinect & Arduino

Project showcase by Avinash Baranitharan and Karthikeyan

  • 8,329 views
  • 0 comments
  • 27 respects

6DOF Robotic Arm

Project showcase by Danny Van den Heuvel

  • 6,673 views
  • 1 comment
  • 18 respects
Add projectSign up / Login