The Rubik's cube Robot solver, together with my assistant
The hardware side is finished, let's produce some code to make it alive
The Rubik's cube Robot solver, together with my assistant
The hardware side is finished, let's produce some code to make it alive
together with my assistant
Your assistant does not look impressed. You need another groupie.
Nicely laid out and good fit.
Your assistant does not look impressed
She is just a bit jealous of this time consuming project
Nicely laid out and good fit
Thanks zoomkat
First cube moves according to Singmaster notation (see post #8)
< D, B, B', D' >
This sequence will finally bring back the cube to its initial position
Those 4 moves are hard coded in the Arduino sketch
I will now prepare a sketch with all possible moves:
F (Front), B (Back), U (Up), D (Down), L (Left), R (Right), plus the " ' " and " 2 " variants
For debugging purpose, moves will be entered through Arduino's serial monitor
EDIT: see post #242 (code)
Hi Looking for something to build. I am a relative newbie to Arduino and have made a finished a robot car using a uno board and Robot Shield. I found this quite easy and want to make the rubixcube solver. How hard was this build on a scale of 1-10? Looks good. Need one as I can complete a rubixcude in a couple of days.
Hi bjim525
You just passed from "Lurker" status to "Active Contributor"
Congratulation !!
How hard was this build on a scale of 1-10?
I would say... 6
The project is challenging both on the Hardware and Software sides
To create the grips, you need a CNC, a Laser cutter or a 3D printer
Do you have access to this type of equipment ??
Assembly is an easy task:
Should you need additional info, let me know
I am in the progress of saving up the money for a 3d printer. Any ideas which one. The Arduino one looks good. Costs a lot though!!!
Not too familiar with 3D printers
Rubik's robot parts are CNC'd using a cheap chinese 30X40 router
I will now prepare a sketch with all possible moves:
F (Front), B (Back), U (Up), D (Down), L (Left), R (Right), plus the " ' " and " 2 " variantsFor debugging purpose, moves will be entered through Arduino's serial monitor
Here it is:
#define VERSION "Cube Mover V1.2 @kas2014\n"
// V1.2: refactored using Cube class
// V1.1: replaced Servo with VarSpeedServo library
// V1.0: initial release
#include <VarSpeedServo.h>
#include "cube.h"
// ---------- user adjustments -------------------
#define DOWN_CLOSE 91 //92
#define DOWN_OPEN 132
#define DOWN_CW 6
#define DOWN_MID 89
#define DOWN_CCW 172
#define BACK_CLOSE 84 //85
#define BACK_OPEN 129
#define BACK_CW 2
#define BACK_MID 87
#define BACK_CCW 171
#define LOW_SPEED 50 //50
#define HI_SPEED 100 //80
// -----------------------------------------------
#define downPinchPin 9
#define downRotPin 10
#define backPinchPin 5
#define backRotPin 6
#define bipPin 11 // buzzer
#define myRX 2
#define myTX 3
#define STX 0x02 // serial data frame delimiters
#define ETX 0x03
Cube myCube(downPinchPin, downRotPin, backPinchPin, backRotPin);
char cmd[128]; // bytes received buffer
void setup() {
Serial.begin(57600);
Serial.println(VERSION);
pinMode(bipPin, OUTPUT);
myCube.begin(HI_SPEED); // set HIGH servo's speed
myCube.downSetLimits(DOWN_CLOSE, DOWN_OPEN, DOWN_CW,DOWN_MID, DOWN_CCW); // set limits for pinch and rotation servo's
myCube.backSetLimits(BACK_CLOSE, BACK_OPEN, BACK_CW, BACK_MID, BACK_CCW);
myCube.seize();
bip(20, 2); // bip
}
void loop() {
if(getSerialData()) parseData();
}
// ---------------------------
boolean getSerialData() {
if(Serial.available()) { // data received from smartphone
delay(2);
cmd[0] = Serial.read();
if(cmd[0] == STX) {
int i=1;
while(Serial.available()) {
delay(1);
cmd[i] = Serial.read();
// Serial.print(cmd[i]);
if(cmd[i]>'u' || i>124) { bip(20, 5); return false; } // Communication error XXX reinitialiser à zero <<<
if((cmd[i]==ETX)) return true; //
i++;
}
}
}
return false;
}
boolean getSerialMonitor() { // Serial Monitor fsetting: Newline
if(Serial.available()) {
for(int i=0; i<124; i++) cmd[i] = 0;
int n = Serial.readBytesUntil('\n', cmd, 124);
// Serial.print(cmd[0]); Serial.print(" ");
cmd[n+1] = ETX;
return true;
}
return false;
}
void parseData() { // parseData(cmd)
int i = 0;
String progress = "";
while (cmd[i] != ETX) {
// Serial.print(cmd[i]); mySerial.print(" ");
switch(cmd[i]) {
// Move commands ------------------------------------------------------------
case 'R': // 'R' moves
switch(cmd[i+1]) {
case '2':
Serial.print("R2 ");
myCube.R2();
break;
case 39:
Serial.print("R' ");
myCube.Rp();
break;
default:
Serial.print("R ");
myCube.R();
break;
}
break;
case 'L': // 'L' moves
switch(cmd[i+1]) {
case '2':
Serial.print("L2 ");
myCube.L2();
break;
case 39:
Serial.print("L' ");
myCube.Lp();
break;
default:
Serial.print("L ");
myCube.L();
break;
}
break;
case 'U': // 'U' moves
switch(cmd[i+1]) {
case '2':
Serial.print("U2 ");
myCube.U2();
break;
case 39:
Serial.print("U' ");
myCube.Up();
break;
default:
Serial.print("U ");
myCube.U();
break;
}
break;
case 'D': ** snip (9000 caracters limitation) **
case 'F':
case 'B':
}
break;
// Scan commands -----------------------------------------------------------
case 'f': // Scan Front side
myCube.scanFront();
Serial.println("OKf");
break;
case 'r': // Scan Right side
myCube.scanRight();
Serial.println("OKr");
break;
case 'b': // Scan Back side
myCube.scanBack();
Serial.println("OKb");
break;
case 'l': // Scan Right side
myCube.scanLeft();
Serial.println("OKl");
break;
case 'u': // Scan Up side
myCube.scanUp();
Serial.println("OKu");
break;
case 'd': // Scan Down side
myCube.scanDown();
Serial.println("OKd");
break;
case 'g': // back to Front side
myCube.scanFront2();
Serial.println("OKg");
break;
// Other commands --------------------------------------------------------------
case 'T': // release gripper pressure
myCube.seize();
bip(40, 2);
Serial.print("seize");
break;
case 'S': // change move speed
switch(cmd[i+1]) {
case '2':
myCube.setSpeed(HI_SPEED);
Serial.print("High Speed");
break;
case '1':
myCube.setSpeed(LOW_SPEED);
Serial.print("Low Speed");
break;
}
break;
case 'V': // bips
switch(cmd[i+1]) {
case '4':
bip(80, 4);
Serial.print("bip (4)");
break;
case '2':
bip(80, 2);
Serial.print("bip (2)");
break;
default:
bip(80, 1);
Serial.print("bip ");
break;
}
break;
default:
break;
}
i++;
}
Serial.println();
bip(20, 2);
}
void bip(int duration, int n) { // Bip piezo: duration in ms, n repeats
for(int i=0; i<n; i++) {
digitalWrite(bipPin, HIGH);
delay(duration);
digitalWrite(bipPin, LOW);
delay(75);
}
}
I also created a library to separate the "logic" of the program from the low-level details
EDIT: see post #43 for complete code including cube.h
According to Singmaster notation,
myCube.L generates a move
myCube.L2 for move
myCube.Lp (L prime) for a <L'> move
For demonstration purpose, the cube was first mixed according to < D B2 R2 U' F' L F2 R D2 R B2 R' >
In this video, I entered < R B2 R' D2 R' F2 L' F U R2 B2 D' > (inverse moves) in the IDE Serial Monitor.
The cube is restored, as expected
I will now create a simple Python script (2 buttons) that will:
Nice!
I have started to build a cube solver a couple of times but never finished any one. I will follow your project and maybe i will be inspired to build one too. After all you got me to build an balancing bot
I feel now pretty confident to finish this project
Should I succeed, my long range plan is to remove the webcam and PC and use a single Android phone as both a camera and a computing device
This will then become a 100% autonomous machine
**It's python's time folks **
Python is a nice language when it's comes to produce small utilities and middlewares
For the moment, I just implemented the "Arduino side"
this program accepts a string and transmit it to Arduino, through the serial port
in same way as Arduino Serial Monitor in Post #18
This is Rubik kasBot V1.13 (May 2017: change software versioning )
## Rubik kasBot @ kas 2014
## V1.13 changed windows position
## V1.12 removed delayB4scan
## V1.11 slow/fast cube moves
## V1.1 communication error management
## V1.0 initial release, serial communication with Arduino only
from tkinter import *
import serial, time
from serial import SerialException
import atexit
import subprocess
defaultPortNumber = '3' ## default Serial port
root =Tk()
root.title('Rubik kasBot')
root.geometry('325x335+1000+100') # window size + position
vSolve = StringVar()
comVar = IntVar()
speedVar = IntVar()
comSent = StringVar()
comIn = StringVar()
vErrror = StringVar()
vComPort = StringVar()
vComPort.set(defaultPortNumber)
comSent.set("")
comIn.set("")
def bSolve_CallB():
arduino.write(b"x02" + str.encode(vSolve.get() + 'T') + b"x03")
def speed_CallB():
if speedVar.get():
arduino.write(b"x02 S2 x03") ## slow moves
else:
arduino.write(b"x02 S1 x03") ## fast moves
def com_CallB():
if comVar.get():
root.update()
global arduino
try:
arduino = serial.Serial('COM' + vComPort.get(), 57600, timeout=15)
time.sleep(1.25) ## give time to settle
sComPort.config(state = DISABLED)
print("COM <ON>")
comSent.set("COM <ON>")
EnableButtons(True)
speedVar.set(True)
except SerialException:
EnableButtons(False)
comVar.set(False)
displayComError('COM' + vComPort.get() +" not available")
else:
speedVar.set(False)
EnableButtons(False)
arduino.close()
sComPort.config(state = NORMAL)
print("COM <OFF>")
comSent.set("COM <OFF>")
comIn.set("")
## utilities ------------------------------------
def displayComError(message):
vErrror.set(message)
root.update()
print(message)
time.sleep(2)
vErrror.set("")
def EnableButtons(flag):
if flag == True:
aspect = NORMAL
else:
aspect = DISABLED
bSolve.config(state=aspect)
eSolve.config(state=aspect)
checkSpeed.config(state=aspect)
def cleanup(): ## Exit Cube Explorer and close COM port
if comVar.get():
arduino.close()
atexit.register(cleanup)
## UI elements --------------------------
eSolve = Entry(textvariable = vSolve, width = 60, fg="Blue", bd = 2, font=('arial', 6))
eSolve.place(x=20, y=135, height=20, width=285)
bSolve = Button(padx=59, pady=0, bd=3, text="Solve cube ", fg="black", font=('arial', 16), command = bSolve_CallB)
bSolve.place(x=20, y=160, height=55, width=285)
checkSpeed = Checkbutton(text = "High speed", variable = speedVar, command = speed_CallB)
checkSpeed.place(x=20, y=255)
tError = Label(textvariable = vErrror, fg = "red", bd = 3, font=('arial', 8))
tError.place(x=160, y=260)
checkCom = Checkbutton(text = "COM", variable = comVar, command = com_CallB)
checkCom.place(x=20, y=287)
tComOut = Label(textvariable = comSent, bd = 3, font=('arial', 8))
tComOut.place(x=140, y=278)
tComIn = Label(textvariable = comIn, bd = 3, font=('arial', 8))
tComIn.place(x=140, y=297)
sComPort = Spinbox(from_=1, to=9, width = 1, textvariable=vComPort)
sComPort.place(x=80, y=289)
checkCom.invoke()
root.mainloop()
To run or modify this code, please download Python 3.4.2
(available for Windows, Mac OS, Linux and others)
As for previous test, I shuffled the cube using < D B2 R2 U' F' L F2 R D2 R B2 R' > moves
and entered < R B2 R' D2 R' F2 L' F U R2 B2 D'> to solve it
Same result as above video, trust me on this one
Next steps:
EDIT: getting started (April 2017) ---------------------------------------------------
install Python 3.xx
install tkinter (graphical UI)
install pyserial (Serial comm)
now... do your home work (this thread is not a Python tutorial)
... and run this basic "hello World" test program:
## Rubik (Hello, World) @ kas 2017
from tkinter import *
import serial, time
from serial import SerialException
import atexit
import subprocess
root =Tk()
root.title('Hello, World')
root.geometry('300x300+200+200') ## window size + position
root.mainloop()
See the window ?? you are all set
The final bot, with led's and webcam:
Now let's do the final Python coding to transmit color information to Cube Explorer, and obtain the magic formula to solve the cube
Hey! I am building the same project and wanted to know how u automated the scanning of the each 9 tiles of a face and the entire cube using this setup.
Hey! I am building the same project and wanted to know how u automated the scanning of the each 9 tiles of a face and the entire cube using this setup.
Hi dd5665,
As mentioned, I use Cube Explorer (CE)
Cube explorer has a built in webserver
The robot has to move the cube and expose each face to the webcam, while sending IP queries to CE
Cube Explorer will insure facelets color recognition and will finally compute the solution
This is an excerpt from CE manual:
You can control the process of scanning the cube with the webcam interface by sending some
strings to the webserver.
Position the Back face of the cube in front of the webcam with your robot (as you would do it manually)
and send the string " http://127.0.0.1:8081/?scanB" to the webserver to scan the back face of the cube.
Then you position the Left face and send the string "http://127.0.0.1:8081/?scanL".
Proceed in this way, using the strings "?scanF", "?scanR", "?scanU" and "?scanD".
The webserver will respond with a "Done!" in all cases.When the 6 faces have been scanned, you send the string "http://127.0.0.1:8081/?transfer".
If all facelets are ok, the scanned cube is transferred to the Main Window and the solving maneuver is computed.
The webserver will respond with a "Done!".Finally, with the string " http://127.0.0.1:8081/?getLast" the webserver will respond with the last
computed solving maneuver in the Main Window of Cube Explorer.
Process this string with your robot to solve the cube.
I am busy coding this feature, using Python :-\
Thanks! I have read the Cube explorer manual!
Your documentation is very informative. Can u give more insights onto how I can build the gripper using ply board. Do you have any drawings of all the parts needed to build the gripper. I do not know how to use Solid works or any such CAD softwares. ( Electronics student ).
Thanx in advance!
Hey Kas, amazing design man! I would love to get started also and maybe you can upload the paperscan of the wood grippers so i can print it and also make the grippers.
Looking forward to your reply!
Hi guys,
Too many relatives at home for the moment
Will be back in a few days
I do not know how to use Solid works or any such CAD softwares. ( Electronics student )
This is a nice opportunity to get your hands dirty
You will definitely have to use these softs in your future jobs
Vectric Vcarve Pro cutting simulation:
The assembly Video (reply #15) has been created using Autodesk Inventor
For dd5665, arduino5 and others, I attach to this post the gripper parts in pdf format
Not sure, you may have to login/register to see the file
Let me know if you need more info
Servo_gripper7(2).pdf (10.7 KB)