hbolanos2001
Published © CERN-OHL

Rubik's Cube Solver Robot DIY - V.3.0

My third Rubik's Cube Solver Robot - As simple as possible (Budget: 30US$)

IntermediateProtip10,357
Rubik's Cube Solver Robot DIY - V.3.0

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
SG90 Micro-servo motor
SG90 Micro-servo motor
×3
Jumper wires (generic)
Jumper wires (generic)
×12
5V 2.5A Switching Power Supply
Digilent 5V 2.5A Switching Power Supply
×1

Hand tools and fabrication machines

Multitool, Screwdriver
Multitool, Screwdriver
Drill / Driver, Cordless
Drill / Driver, Cordless

Story

Read more

Schematics

Schematics

Schematics-servo + arduino- source:hac4kernaren

Code

Cube_Solver_No_GUI_Koc_chen.ino

Arduino
/* 
 *  Developed and integrated by: Hernando Bolanos
 *  
 *  code lines and sOurces:
 *  1.Sweep by BARRAGAN <http://barraganstudio.com>
 * modified 8 Nov 2013
 * 2. by Scott Fitzgerald
 * http://www.arduino.cc/en/Tutorial/Sweep


* 3. Instructables -Matt2Yu -ALGORTIHM, CONCEPT FOR CFOP METHOD
* Version 1- 16-AGOSTO-2020
* 

* Best calibration settings: -move speed 6-push 146- take into account the servos orientation- if it is not  the same you have to adapt all the calibration angles and timing
* Is must to use PWM outputs- This was implmented with a nodemcu
*/


#include <Servo.h>
//#include <Solver.h>
 
// servo objects
Servo rotate_servo;
Servo push_servo;
 
int move_speed = 6 ; //6 - CALIBRATION -PUSH 146
int buffer_time = 105; // time between moves
int rotate_pos = 90;
int push_pos = 110;
int hold_progress = 3;
int offset_degrees = 3;
bool slow_push = false;
String kociemba_sol = "";
 
//////// cube move variables:
bool sim_only = false;
 
// test function:
bool test_ongoing = true;
 
                    

 
////////////////////// Serial Communication (receive arrays or kociemba solution from any .py script)
 
 
void accept_string()
{
        
        char ready_signal = 'ready';
        char received_signal = 'received';
 
        for (int piece_num = 0; piece_num <5; piece_num++)
        {       
                // send ready signal
                Serial.println(ready_signal);
                delay(100);
        }
        // receive string
        while(kociemba_sol == "")
        {
                char character;
                while(Serial.available())
                {
                    character = Serial.read();
                        kociemba_sol.concat(character);
                }
        }
       

        
        delay(10);
        Serial.print("String Aceptado: ");
       Serial.print(kociemba_sol);
 
        // send color confirmed signal
        Serial.println("arduino dice:");
        Serial.println(received_signal);
        Serial.println(kociemba_sol);
        delay(10);
}
 

 

///////// Cube movement functions: ////////////

int move_servo(int start, int finish, int servo_pin)
{
        int pos;
        if (start - finish < 0)
        {
                for(pos = start; pos <= finish; pos += 1)
                {
                        if (servo_pin == 6) 
                        {
                                push_servo.write(pos);
                                
                                delay(move_speed);
                        }
                        else if (servo_pin == 9)
                        {
                                rotate_servo.write(pos);
                                delay(move_speed);
                        }
                }
        }
        else
        {
                for(pos = start; pos >= finish; pos -= 1)
                {
                        if (servo_pin == 6)
                        {
                                push_servo.write(pos);
                                
                                delay(move_speed);
                        }
                        else if (servo_pin == 9)
                        {
                                rotate_servo.write(pos);
                                delay(move_speed);
                        }
                }
        }
        // use a swich case next time
        if (servo_pin == 9)
        {
                rotate_pos = pos;
        }
        if (servo_pin == 6)
        {
                push_pos = pos;
        }
        delay(buffer_time);
}
///////// Cube movement functions: ////////////
void push_cube(int num_of_pushes = 1)
{
        if (num_of_pushes == 1)
                {
                        if (slow_push == false)
                        {
                                move_servo(push_pos, 146, 6);//72
                                delay(buffer_time);
                                release_cube();
                                delay(buffer_time);
                        }
                        else // on rotate one
                        {
                                move_servo(push_pos, 146, 6);//72
                                delay(buffer_time+200);
                                release_cube();
                                delay(buffer_time);
                        }
                }
        else
        {
                while (num_of_pushes != 0)
                {
                        if (slow_push == false)
                        {
                                move_servo(push_pos, 146, 6);//72
                                delay(buffer_time+50);
                                move_servo(push_pos, 110, 6);//original 120
                                delay(buffer_time);
                                num_of_pushes--;
                        }
                        else // on rotate one
                        {
                                move_servo(push_pos, 110, 6);//72
                                delay(buffer_time+200);
                                move_servo(push_pos, 146, 6);//original 130
                                delay(buffer_time);
                                num_of_pushes--;
                        }      
                }
        release_cube();
        }
}
void hold_cube()
{
        move_servo(push_pos, 133, 6);//
        hold_progress = 1;
}
void release_cube()
{
        move_servo(push_pos, 105, 6);
        hold_progress = 3;
}
void rotate_one()
{
        slow_push = true;
        int rotate_finish = -5;//11-4
        if (hold_progress == 1) // hold progress 1 = hold
        {
                // from rotate_two
                if (rotate_pos < 140)
                {
                        // initial turn
                        move_servo(rotate_pos, rotate_finish-2, 9);
                        move_servo(rotate_pos, rotate_finish+5, 9);
                        // release and turn some more
                        release_cube();
                        move_servo(rotate_pos, 101, 9);
                        hold_cube();
                        move_servo(rotate_pos, 75, 9);//82original/72 /75
                        move_servo(rotate_pos, 92, 9); // prevent pulling
                        release_cube();
                        move_servo(rotate_pos, rotate_finish, 9);
                }
 
                // from rotate_three
                else if (rotate_pos > 140)
                {
                        // initial turn
                        move_servo(rotate_pos, rotate_finish-5, 9);
                        move_servo(rotate_pos, rotate_finish+10, 9);
                        // release and turn some more
                        release_cube();
                        move_servo(rotate_pos, 108, 9);
                        hold_cube();
                        move_servo(rotate_pos, 83, 9);//83 origial
                        move_servo(rotate_pos, 93, 9); // prevent pulling
                        release_cube();
                        move_servo(rotate_pos, rotate_finish, 9);
                }
 
 
 
 
                hold_progress = 2;
        }
        else if (hold_progress == 2) // hold progress 2 = release, but offset still there
        {
                hold_progress = 3;
                move_servo(rotate_pos, rotate_finish, 9);
        }
        else if (hold_progress == 3) // hold progress 3 = release, offsets reconciled
        {
                // do nothing
                move_servo(rotate_pos, rotate_finish, 9);
        }
}
void rotate_two()
{
        slow_push = false;
        int rotate_finish = 90;
        if (hold_progress == 1) // hold progress 1 = hold
        {
                // rotate from rotate_one
                if (rotate_pos < 50)
                {
                        // initial turn
                        move_servo(rotate_pos, rotate_finish+3, 9);
                        move_servo(rotate_pos, rotate_finish-5, 9);
 
                        // release and turn some more
                       
                        release_cube();
                        move_servo(rotate_pos, 0, 9);
                        hold_cube();
                        move_servo(rotate_pos, 18, 9);//original 18/25/20
                        move_servo(rotate_pos, 12, 9); // prevent pulling/original 8/2
                        release_cube();
                       
                        move_servo(rotate_pos, rotate_finish, 9);
                }
                // rotate from rotate_three
                else if (rotate_pos > 150)
                {
                        move_servo(rotate_pos, rotate_finish-1, 9);
                        move_servo(rotate_pos, rotate_finish+1, 9);
 
 
                        // release and turn some more
                        release_cube();
                        move_servo(rotate_pos, 179, 9);
                        hold_cube();
                        move_servo(rotate_pos, 170, 9);//orignal 170
                        move_servo(rotate_pos, 178, 9); // prevent pulling
                        release_cube();
                        move_servo(rotate_pos, rotate_finish, 9);
                }
                hold_progress = 2;
        }
        else if (hold_progress == 2) // hold progress 2 = release, but offset still there
        {
                hold_progress = 3;
                move_servo(rotate_pos, rotate_finish, 9);
        }
        else if (hold_progress == 3) // hold progress 3 = release, offsets reconciled
        {
                // do nothing
                move_servo(rotate_pos, rotate_finish, 9);
        }
}
void rotate_three()
{
        slow_push = false;
        int rotate_finish = 179;
        if (hold_progress == 1) // hold progress 1 = hold
        {
                // from rotate_two
                if (rotate_pos > 40)
                {
                        move_servo(rotate_pos, rotate_finish+10, 9);
                        move_servo(rotate_pos, rotate_finish-1, 9); // prevent pulling
 
                        // fix: cube not fully turned
                        release_cube();
                        move_servo(rotate_pos, 90, 9);
                        hold_cube();
                        move_servo(rotate_pos, 105, 9);// original 110
                        move_servo(rotate_pos, 106, 9); // prevent pulling-100
                        release_cube();
                        move_servo(rotate_pos, rotate_finish, 9);
                }
 
                // from rotate_one
                if (rotate_pos < 40)
                {
                        move_servo(rotate_pos, rotate_finish+5, 9);
                        move_servo(rotate_pos, rotate_finish-3, 9); // prevent pulling
 
                        // fix: cube not fully turned
                        release_cube();
                        move_servo(rotate_pos, 80, 9);
                        hold_cube();
                        move_servo(rotate_pos, 110, 9);//original 100/110
                        move_servo(rotate_pos, 90, 9); // prevent pulling
                        release_cube();
                        move_servo(rotate_pos, rotate_finish, 9);
                }
 
                hold_progress = 2;
        }
        else if (hold_progress == 2) // hold progress 2 = release, but offset still there
        {
                hold_progress = 3;
                move_servo(rotate_pos, rotate_finish, 9);
        }
        else if (hold_progress == 3) // hold progress 3 = release, offsets reconciled
        {
                // do nothing
                move_servo(rotate_pos, rotate_finish, 9);
        }
}
 
 
///////////////////// Cube Move Notation ///////////////////////////
// They print, simulate and call the physical functions
 
void right_inverted()
{
        Serial.println("R', ");
 
        if (sim_only == false)
        {
                rotate_three();
                push_cube();
                hold_cube();
                rotate_two();
                release_cube();
                rotate_one();
                push_cube();
                rotate_two();
                push_cube(3);
        }
 
}
void right()
{
        Serial.println("R, ");
 
        if (sim_only == false)
        {
                rotate_three();
                push_cube();
                rotate_two();
                hold_cube();
                rotate_three();
                release_cube();
                rotate_one();
                push_cube();
                rotate_two();
                push_cube();
        }
 }
void left_inverted()
{
        Serial.println("L', ");
 
        if (sim_only == false)
        {
                rotate_one();
                push_cube();
                rotate_two();
                hold_cube();
                rotate_one();
                release_cube();
                rotate_three();
                push_cube();
                rotate_two();
                push_cube();
        }
 
}
void left()
{
        Serial.println("L, ");
 
        if(sim_only == false)
        {
                rotate_one();
                push_cube();
                hold_cube();
                rotate_two();
                release_cube();
                rotate_three();
                push_cube();
                rotate_two();
                push_cube(3);
        }
 
}
void down_inverted()
{
        Serial.println("D', ");
 
        if (sim_only == false)
        {
                hold_cube();
                rotate_one();
                release_cube();
                rotate_two();
                push_cube();
                rotate_one();
                push_cube();
                rotate_two();
                push_cube(3);
        }
 
}
void down()
{
        Serial.println("D, ");
 
        if (sim_only == false)
        {
                hold_cube();
                rotate_three();
                release_cube();
                rotate_two();
                push_cube();
                rotate_three();
                push_cube();
                rotate_two();
                push_cube(3);
        }
 
}
void up_inverted()
{
        Serial.println("U', ");
 
        if (sim_only == false)
        {
                push_cube(2);
                hold_cube();
                rotate_one();
                release_cube();
                rotate_two();
                push_cube();
                rotate_one();
                push_cube();
                rotate_two();
                push_cube();
        }
 
}
void up()
{
        Serial.println("U, ");
 
        if (sim_only == false)
        {
                push_cube(2);
                hold_cube();
                rotate_three();
                release_cube();
                rotate_two();
                push_cube();
                rotate_three();
                push_cube();
                rotate_two();
                push_cube();
        }
 
}
void front_inverted()
{
        Serial.println("F', ");
 
        if (sim_only == false)
        {
        push_cube(3);
        hold_cube();
        rotate_one();
        release_cube();
        rotate_two();
        push_cube();
        rotate_one();
        push_cube();
        rotate_two();
        }
 
}
void front()
{
        Serial.println("F, ");
 
        if (sim_only == false)
        {
                push_cube(3);
                hold_cube();
                rotate_three();
                release_cube();
                rotate_two();
                push_cube();
                rotate_three();
                push_cube();
                rotate_two();
        }
}
void back_inverted()
{
        Serial.println("B', ");
        if (sim_only == false)
        {
                push_cube();
                hold_cube();
                rotate_one(); // ccw
                release_cube();
                rotate_two();
                push_cube(3);
                rotate_three(); //cw
                push_cube();
                rotate_two();
        }
 
}
void back()
{
        Serial.println("B, ");
 
        if (sim_only == false)
        {
                push_cube();
                hold_cube();
                rotate_three();
                release_cube();
                rotate_two();
                push_cube(3);
                rotate_one();
                push_cube();
                rotate_two();
        }
 
}    

// insert top layer edges

// miscellaneous algorithms
void warm_up() // do it six times to get back to the original position
{
        Serial.println();
        Serial.print("Warmup: ");
        Serial.print("R', D', R, D");
        //r'
        rotate_one();
        push_cube();
        hold_cube();//
        rotate_two();
        release_cube();
        rotate_three();
        push_cube();
        rotate_two();
        push_cube(3);
 
        //d'
 
        hold_cube();//
        rotate_three();
        release_cube();
 
        //r start here
 
        rotate_two();
        push_cube();
        rotate_three();
        hold_cube();
        rotate_two();
        release_cube();
 
        // d
 
        rotate_three();
        push_cube();
        hold_cube();
        rotate_two();
        release_cube();
        push_cube();
        rotate_one();
        push_cube();
        rotate_two();
        push_cube(3);
}
void superflip() // all edges are opposite (checkered pattern)
{
        Serial.println();
        Serial.println("Superflip: ");
        up();
        up();
        down();
        down();
 
        left();
        left();
        right();
        right();
 
 
        front();
        front();
        back();
        back();
}
 
                                                                                                                                                                                // test it
void scramble() // random 25 moves - if you need continuos solve-scramble and resolution this part of code would be usefull
{
        Serial.println();
        Serial.println("Scramble: ");
        int move;
        for(int j = 0; j < 25; j++)
        {
                move = random(1, 12);
                //Serial.println(move);
                switch(move)
                {
                        case 1:
                                right();
                                break;
                        case 2:
                                right_inverted();
                                break;
                        case 3:
                                left();
                                break;
                        case 4:
                                left_inverted();
                                break;
                        case 5:
                                up();
                                break;
                        case 6:
                                up_inverted();
                                break;
                        case 7:
                                down();
                                break;
                        case 8:
                                down_inverted();
                                break;
                        case 9:
                                front();
                                break;
                        case 10:
                                front_inverted();
                                break;
                        case 11:
                                back();
                                break;
                        case 12:
                                back_inverted();
                                break;
                }
        }
}
 

 

void run_kociemba(){

//"L2 D' R' L2 D2 R F' D2 F2 R' B' L2 D R2 L2 D L2 B2 U' B2 U2"


kociemba_sol= "B L' F' B R F2 U2 D R2 F D F2 U R2 F2 L2 B2 R2 D2 R2";
//"L U' L B2 U2 F' D R2 F L F2 R2 F2 U2 D B2 L2 D2 B2 U'";

// Length (with one extra character for the null terminator)
int str_len = kociemba_sol.length() + 1; 


//Serial.println("arduino : STRINGS RECEIVED:");
//Serial.println((str_len-1));

for(int i = 0; i <= (str_len-1); i++){     //recorre

//Serial.print(i);


if ((kociemba_sol.charAt(i)) =='R'){


if ((kociemba_sol.charAt(i+1)) == '2') {
      right();
      right();}


if ((kociemba_sol.charAt(i+1)) == '\'') {
      right_inverted();}

if (((kociemba_sol.charAt(i+1))!= '2') and((kociemba_sol.charAt(i+1)) != '\'')) {
      right();}

}

else { // DO NOTHING
      
}

if ((kociemba_sol.charAt(i)) =='L'){


if ((kociemba_sol.charAt(i+1)) == '2') {
      left();
      left();}


if ((kociemba_sol.charAt(i+1)) == '\'') {
      left_inverted();}

if (((kociemba_sol.charAt(i+1))!= '2') and((kociemba_sol.charAt(i+1)) != '\'')) {
      left();}

}

else { //DO NOTHING
      
}

if ((kociemba_sol.charAt(i)) =='U'){


if ((kociemba_sol.charAt(i+1)) == '2') {
      up();
      up();}


if ((kociemba_sol.charAt(i+1)) == '\'') {
      up_inverted();}

if (((kociemba_sol.charAt(i+1))!= '2') and((kociemba_sol.charAt(i+1)) != '\'')) {
      up();}

}

else { //DO NOTHING
      
}



if ((kociemba_sol.charAt(i)) =='D'){


if ((kociemba_sol.charAt(i+1)) == '2') {
      down();
      down();}


if ((kociemba_sol.charAt(i+1)) == '\'') {
      down_inverted();}

if (((kociemba_sol.charAt(i+1))!= '2') and((kociemba_sol.charAt(i+1)) != '\'')) {
      down();}

}

else { //DO NOTHNIG
      
}





if ((kociemba_sol.charAt(i)) =='F'){


if ((kociemba_sol.charAt(i+1)) == '2') {
      front();
      front();}


if ((kociemba_sol.charAt(i+1)) == '\'') {
      front_inverted();}

if (((kociemba_sol.charAt(i+1))!= '2') and((kociemba_sol.charAt(i+1)) != '\'')) {
      front();}

}

else { //DO NOTHING
      
}




if ((kociemba_sol.charAt(i)) =='B'){


if ((kociemba_sol.charAt(i+1)) == '2') {
      back();
      back();}


if ((kociemba_sol.charAt(i+1)) == '\'') {
      back_inverted();}

if (((kociemba_sol.charAt(i+1))!= '2') and((kociemba_sol.charAt(i+1)) != '\'')) {
      back();}

}

else { //DO NOTHING
      
}

}
   
                
        //warm_up();
        //scramble();
}
 
void show_off_cube()
{
        rotate_one();
        rotate_three();
        push_cube(2);
        rotate_one();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////// PROGRAM START ///////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
 
void setup()
{
        rotate_servo.attach(12);  // attaches the servo on pin 9 to the servo object
        push_servo.attach(14);  // attaches the servo on pin 6 to the servo object
        push_servo.write(push_pos);
        rotate_servo.write(rotate_pos);
        delay(1000);
        Serial.begin(9600);
        while (! Serial);
        
}
 
/////////////// Se recibe por puerto serial la solucion  //////////////////

void loop()
{      
//activate accept string when you want to receive solution from PY script


//accept_string();


 //Warming up 

Serial.println("Warming Up: will back to the original position and start ");


push_cube();
push_cube();
push_cube();
push_cube();

delay(2000);


Serial.println("Arduino dice:Inicia a correr la solucion:");


 run_kociemba(); //corre el string recibido
        
Serial.println("Arduino : Finish-check all the cube face solved");

//show all the cube solved

show_off_cube();


Serial.println("Arduino :Finish- send a new kocoemba solution");
  
        
        while(true){}

  
 
}

Credits

hbolanos2001
11 projects • 33 followers

Comments