 # SpinnerCube - Rubik's cube solver robot -18 seconds © CC BY-NC

Using the legacy of brilliant mathematicians, this robot solve the cube in 18 seconds or less.

• 3,554 views
• 9 respects

## Necessary tools and machines

### Scope of work

This project use arduino, python and opencv to solve the rubik´s cube. The main goal was to obtain one cheap robot wich could solve the rubik´s cube in less than one minute.

However I need to mention that my additional idea was to desgin a T-shirt with some ideas to talk about with other people-so this project need to understand some fundamental maths and train yourself in Python and opencv.

Technical Motivation

I was checking some rubik´s cube solver robot and I got captived by the ingenious of the LEGO's robot named SpinnerCube.

### Operation

This robot use 3 stepper motors to perform all the moves of the cube's faces URFLDB. The stages are:

• To capture sticker's color face by face, according to a sequence
• To processing each face, using python and establish the scrambled initial position of the cube
• To solve the cube by Kociemba algorithm
• To send solution from python to Arduino throught serial port
• From arduino to perform all the moves as soon as accurate and as repetable as possible!!!

Best Time reached

In order to obtain good time record, one trick easy to perform with these robots based on stepper motors is an inverse sequence, however is easy to identify if the solution is real because Kociemba normally solve the cube with 20 to 27 moves, and other methods as Fridrich, CFOP, normally solve in more moves. By the way I am not interested in a Record as my main goal, I am interested in learning, but look for physical limits, without tricks, is a good exercise to go with patient in the calibration process - Fine Tunning.

Consequently, depending on robot model, there is a physical limit ; in this case on the stepper motors is adequate torque to move the faces and maximum speed and acceleration associated. However the delays between moves and the spins for U(up),D(down),B(back) moves are constrains.

I have seen working Spinner Cube robots, based on Servos, and speed to solve is better. In the near future, I will share with all of you my project with this model based on servos.

In this case, playing with calibration settings, I got 18 seconds as my minimal time, and to avoid

In this video you can see how after iterations, I got 18 seconds ( different scrambled positions-same calibration parameters):

Developer

I can share with you my complete software development, this is open source.

An application was developed with Arduino and Python to integrate program, solve the cube and control the robot. This help us to test and make more efficient the input of cube state and to take pictures.

This APP use programming strategies from other open source developers and was tuned for weeks in order to teach the system to watch and extract sticker's color.

What for?

The answer to this question will be given to the readers in the near future; now this answer could be to develop a product for a niche of people who likes rubik's cube . Let's see what happen.

## Code

##### Arduino Code Arduino
Receive from Python the solution and run the moves
```/*
*  by hernando Bolaños
*
*  Piece of code from, Matt2Yu, VER instructables
*/

//////////////////////////////////////////////////////////////////////////////////////////////////////
////WARNING: PROTOTYPE BASED ON CUBESPINNER ////
/////////////////////////////////////////////////////////////////////////////////////////////////////

#define STEP_L 4      // pin STEP de A4988 a pin 4 PWM- manejando la cara down del cubo
#define DIR_L 5     // pin DIR de A4988 a pin 5  PWM-manejandola cara down del cubo
#define STEP_R 6      // pin STEP de A4988 a pin 4 PWM-manejando la cara right del cubo
#define DIR_R 7     // pin DIR de A4988 a pin 5  PWM-manejando la cara righ delcubo

#define STEP_F 8      // pin STEP de A4988 a pin 4- manejando la cara "up" del cubo
#define DIR_F 9     // pin DIR de A4988 a pin 5  -manejandola cara "up" del cubo

int pasos = 200/4;    // LATERALES pasos   90 grados con motor Hanpose 17HS3430 : 1.8 grados por paso en condicion Full step- Se probo comportamiento en otras configuraciones de pasos
int Fpasos1=274/4;    //FRENTE Pasos para angulo de front avanzar la cara
int Fpasos2=74/4;    //FRENTE Pasos para angulo de front quedar en posicion esperando nuevo movimiento
int Fpasos3=268/4;    //FRENTE Pasos para angulo de front inv quedar en posicion esperando nuevo movimiento-front inv
int Fpasos4=70/4;     //FRENTE Pasos para angulo de front inv quedar en posicion esperando nuevo movimiento-front inv
int pasosr=3*pasos;
String kociemba_sol = "";

int tiempo_step= 600; //microseconds -segun DS minimo tiempo permitido del step de motores 1 microsegundo
int tiempo_stepF= 1400; //microseconds- tiempo para usar en el frente con los demas andando en tiempo_step

int espera=200; //tiempo de espera despues de un movimiento

int esperaT=50;

void setup()
{

pinMode(STEP_L, OUTPUT);  // pin 4 como salida
pinMode(DIR_L, OUTPUT);   // pin 5 como salida

pinMode(STEP_R, OUTPUT);  // pin 6 como salida
pinMode(DIR_R, OUTPUT);   // pin 7 como salida

pinMode(STEP_F, OUTPUT);  // pin 8 como salida
pinMode(DIR_F, OUTPUT);   // pin 9 como salida

delay(7000);

Serial.begin(9600);

while (! Serial); // Wait untilSerial is ready
//assign_to_current(yellow_side);
//print_cube(current_side);

}

void loop()
{

//recibir la solucion de kociemba por puerto serial

//accept_string();

//calentando 5 segundos

Serial.println("Calentando para fotos: volvera a la posicion inicial");

//right();
//right_inv();
//front();
//front_inv();
//left();
//left_inv();

delay(2000);

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

run_kociemba(); //corre el string recibido

Serial.println("Arduino dice: Finaliza tiempo solucion");

//mostrar el cubo resuelto

show_off_cube();

Serial.println("Arduino dice:Finalizado enviar nueva solucion de Kociemba");

while(true){}
}

void accept_string()   ////Se comunica el Arduino con el PC le confirma que esta listo para recibir la solucion en un STRING-la recibe/////
{

for (int piece_num = 0; piece_num <5; piece_num++)
{
delay(100);
}
while(kociemba_sol == "")
{
char character;
while(Serial.available())
{
kociemba_sol.concat(character);
}
}
delay(10);
Serial.print(kociemba_sol);

// Se envia confirmacion de recibido al PC con el STRING para reconfirmar
Serial.println("arduino dice:");
Serial.println(kociemba_sol);
delay(10);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////Aqui se recibe de python la solucion de kociemba y se convierte en movimientos de los stepper motors"///////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void run_kociemba(){

//steppers en posicion inicial- home

kociemba_sol="U B U' RR D L' D F' L U F LL U LL BB U' BB U' FF RR LL";

//Solved from Python for test

//"U B U' RR D L' D F' L U F LL U LL BB U' BB U' FF RR LL";

//"L' U B' DD L DD F' R D R L' UU FF LL BB RR U RR LL FF D";

//"RR FF U' L UU BB D B' D R' F U RR U FF U' LL BB RR LL";

//"R F' B' L' U D' BB R' DD R' F' BB LL FF DD BB U BB RR U DD";

//"FF B' UU RR UU B D' R' F' L' U' BB UU LL D' FF U' FF BB D'";

//"D R FF BB U RR LL B' R D F LL BB LL DD FF D FF BB LL D";
//"R D' LL BB U F BB U F U RR U LL FF U' FF UU D' RR":

//" FFFFBRRRRRRRR'R'R' RRRRLLLLLLLL'L'";

//kociemba_sol= "F'F'F'F'F'FFFFFFFFFFFFFF";

//kociemba_sol="U L' U DD B DD FF B' L' U' B' U' LL U LL U' RR UU RR BB U'";

//"RR U RR B' U F' D BB U' B L' DD RR UU D FF D LL U' FF BB";

//"U BB L U' F' L' B UU R' D' B' D RR U DD BB RR D LL FF D";

//"U F' BB U' F UU F R' U' LL F' L U RR U FF RR UU RR BB DD RR";

//"U R BB DD F' U' F' R F' B' U B DD RR FF U' RR U' BB DD RR FF";

//"FF UU F LL D BB U' RR F' R' U D BB D FF LL D' RR UU LL";

//"UU D' BB DD F' R L F' BB U' L' D' BB U BB LL U FF LL BB UU";

//"U R UU B U' F' U FF BB RR U L U DD LL UU RR D' FF RR D LL";

//"D' RR DD B' RR L' FF D' FF R' D FF RR FF LL BB DD BB D BB";

//"R' D' R' D' F U R BB D' FF R' D FF RR FF LL BB DD BB D BB";

//"F R F L B' RR F' LL D' F L FF UU LL D' LL BB UU FF";

//"B' D' L' U F RR LL F L' F' U' RR U' FF RR LL FF DD FF U'";

//"F' RR U L' U F' D' RR U' DD F' U' BB RR FF U LL U' BB LL";
//"RRRRR'RFBLlU'RLFD'F L BB U RR FF UU LL BB RR DD RR";

// Length (with one extra character for the null terminator)

int str_len = kociemba_sol.length() + 1;

Serial.println("Arduino dice: Caracteres:");
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_inv();}

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

}

}

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

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

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

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

}

}

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

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

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

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

}

}

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

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

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

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

}

}

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

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

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

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

}

}

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

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

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

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

}

}

}

}
////////////////////////////////////////////////////////////////////////////
/////Rutinas del Cubo- se puede usar asi : YELLOW at FRONT -BLUE at UP//////
///////////////////////////////////////////////////////////////////////////

void right_inv()// movimiento RIGHT inverso del Cubo
{

Serial.println("R',");

digitalWrite(DIR_R, LOW);    //
for(int i = 0; i < pasosr; i++){     //Mueve 3x90 grados
digitalWrite(STEP_R, HIGH);       // nivel alto
delayMicroseconds(tiempo_step);
delayMicroseconds(tiempo_step);// por x ms segun
digitalWrite(STEP_R, LOW);        // nivel bajo variable tiempo_step
delayMicroseconds(tiempo_step);          // por x ms segun variable tiempo_step
delayMicroseconds(tiempo_step);
}
delay(espera);

}

void right()// mueve el cubo Right
{

Serial.println("R,");

digitalWrite(DIR_R, LOW);     //
for(int i = 0; i < pasos; i++){   //
digitalWrite(STEP_R, HIGH);
delayMicroseconds(tiempo_step);
delayMicroseconds(tiempo_step);
digitalWrite(STEP_R, LOW);
delayMicroseconds(tiempo_step);
delayMicroseconds(tiempo_step);
}
delay(espera);          // demora de x segundos

}

void up()// mueve el cubo UP
{

Serial.println("U,");

rinv_l();
delay(100);
front();
delay(100);
rinv_l();
rinv_l();
rinv_l();
delay(espera);
}

void up_inv()// mueve el cubo  UP INV
{

Serial.println("U',");

rinv_l();
delay(100);
front_inv();
delay(100);
rinv_l();
rinv_l();
rinv_l();
delay(espera);

}

void down()// mueve el cubo UP
{

Serial.println("D,");

rinv_l();
rinv_l();
rinv_l();
delay(100);
front();
delay(100);
rinv_l();
delay(espera);

}

void down_inv()// mueve el cubo Down_INV
{

Serial.println("D',");

rinv_l();
rinv_l();
rinv_l();
delay(100);
front_inv();
delay(100);
rinv_l();
delay(espera);

}

void left()// mueve el cubo LEFT

{

Serial.println("L,");

digitalWrite(DIR_L, LOW);    // giro en  sentido
for(int i = 0; i < pasosr; i++){     //
digitalWrite(STEP_L, HIGH);       // nivel alto
delayMicroseconds(tiempo_step);          // por x mseg
delayMicroseconds(tiempo_step);
digitalWrite(STEP_L, LOW);        // nivel bajo
delayMicroseconds(tiempo_step);          // por x mseg
delayMicroseconds(tiempo_step);
}
delay(espera);

}

void left_inv()// mueve el cubo LEFT INV
{

Serial.println("L',");

digitalWrite(DIR_L, LOW);     // giro en sentido NCW
for(int i = 0; i < pasos; i++){   //90 grados= xx pasos para motor de yy grados de angulo de paso
digitalWrite(STEP_L, HIGH);
delayMicroseconds(tiempo_step);
delayMicroseconds(tiempo_step);
digitalWrite(STEP_L, LOW);
delayMicroseconds(tiempo_step);
delayMicroseconds(tiempo_step);

}

delay(espera);          // demora de 2 segundos
}

void front_inv()// mueve el cubo front_inv
{
Serial.println("F',");

digitalWrite(DIR_F, HIGH);    // giro en  sentido CW
for(int i = 0; i < Fpasos3; i++){     //135 grados= xx pasos para motor de yy grados de angulo de paso
digitalWrite(STEP_F, HIGH);       // nivel alto
delayMicroseconds(tiempo_stepF);          // por 10 mseg
digitalWrite(STEP_F, LOW);        // nivel bajo
delayMicroseconds(tiempo_stepF);          // por 10 mseg
}

delay(100);

digitalWrite(DIR_F, LOW);
for(int i = 0; i < Fpasos4; i++){     //45 grados= 25x16 pasos para motor de 1.8 grados de angulo de paso
digitalWrite(STEP_F, HIGH);       // nivel alto
delayMicroseconds(tiempo_stepF);          // por 10 mseg
digitalWrite(STEP_F, LOW);        // nivel bajo
delayMicroseconds(tiempo_stepF);          // por 10 mseg
}
delay(espera);

}

void front()// mueve el cubo  front
{

Serial.println("F,");

digitalWrite(DIR_F, LOW);     //
for(int i = 0; i < Fpasos1; i++){   //135 grados= 70x16 pasos para motor de 1.8 grados de angulo de paso
digitalWrite(STEP_F, HIGH);
delayMicroseconds(tiempo_stepF);
digitalWrite(STEP_F, LOW);
delayMicroseconds(tiempo_stepF);
}

delay(100);
digitalWrite(DIR_F, HIGH);     //
for(int i = 0; i < Fpasos2; i++){   //45 grados= 25x16 pasos para motor de 1.8 grados de angulo de paso
digitalWrite(STEP_F, HIGH);
delayMicroseconds(tiempo_stepF);
digitalWrite(STEP_F, LOW);
delayMicroseconds(tiempo_stepF);
}

delay(espera);          // demora de 2 segundos

}

void back()// mueve el cubo back

{
Serial.println("B,");

rinv_l();
rinv_l();
delay(100);
front();
delay(100);
rinv_l();
rinv_l();
delay(espera);

}

void back_inv()// mueve el cubo back Inv
{

Serial.println("B',");

rinv_l();
rinv_l();
delay(100);
front_inv();
delay(100);
rinv_l();
rinv_l();
delay(espera);

}

////////PSEUDO L & R  PARA MOVIMIENTOS EN TANDEM ///

void rinv_l()// mueve el cubo RIGHT
{

Serial.println("R'+L,");

digitalWrite(DIR_R, HIGH);
digitalWrite(DIR_L,HIGH);
// giro en  sentido CW
for(int i = 0; i < pasos; i++){     //90 grados= 12 pasos para motor de 7.5 grados de angulo de paso
digitalWrite(STEP_R, HIGH);       // nivel alto
digitalWrite(STEP_L,HIGH);
delayMicroseconds(tiempo_step);
delayMicroseconds(tiempo_step);// por 1 mseg
digitalWrite(STEP_R, LOW);
digitalWrite(STEP_L,LOW);// nivel bajo
delayMicroseconds(tiempo_step);          // por 1 mseg
delayMicroseconds(tiempo_step);
}
delay(esperaT);

}

void r_linv()// mueve el cubo Right
{

Serial.println("R+L',");

digitalWrite(DIR_R, LOW);
digitalWrite(DIR_L,LOW);
// giro en sentido NCW
for(int i = 0; i < pasos; i++){   //90 grados= xx pasos para motor de 7yy grados de angulo de paso
digitalWrite(STEP_R, HIGH);
digitalWrite(STEP_L,HIGH);
delayMicroseconds(tiempo_step);
delayMicroseconds(tiempo_step);
digitalWrite(STEP_R, LOW);
digitalWrite(STEP_L,LOW);
delayMicroseconds(tiempo_step);
delayMicroseconds(tiempo_step);
}
delay(esperaT);          // demora de x segundos

}

////////////MOVIMIENTO FINAL DEL CUBO YA RESUELTO//////////

void show_off_cube()//muestra todo el cubo al terminar de resolverlo
{
```

## Schematics

Circuit Diagram #### Author

• Algorithm to solve the rubiks cube fromany scrambled position by Herbert Kociemba
• Arduino code-some pieces of his program by Matt2uy
• Spinner cube robot concept by LEGO

June 23, 2020

#### Members who respect this project

See similar projects
you might like

• 7,209 views
• 1 comment
• 9 respects

• 4,167 views
• 8 respects

#### 🎸 Hacking Auto-Tuning Guitar Pegs for Arduino/MIDI Control

Project tutorial by touchmysound

• 3,382 views
• 6 respects

#### DrumCube, an Arduino Robot Drummer

Project showcase by FrancoMolina

• 17,670 views
• 96 respects

#### Arduino Balancing Robot

Project showcase by TEAM DIY

• 14,825 views
• 1 comment
• 12 respects

#### 2WD Voice Controlled Robot with Arduino and BitVoicer Server

Project tutorial by Marcio Tamagushi

• 19,408 views