OK, new Forum bugs are slowly desappearing, time to post again
This is the (probably) final design
>> Video <<
Time to start testing with a Rubik's cube
OK, new Forum bugs are slowly desappearing, time to post again
This is the (probably) final design
Time to start testing with a Rubik's cube
First test with a real Rubik's cube
Here is the demo code
#define VERSION "\n\nGripper demo V1.2- @kas2014\n"
// V1.2 use VarSpeedServo library
// V1.1 2 servo's
// V1.0 1 servo
#include <VarSpeedServo.h>
#define rot_pin 10 // Green
#define pinch_pin 9 // Yellow
#define CLOSE 85 // servo's limits
#define OPEN 132
#define CW 0
#define MID 87
#define CCW 171
#define SLOW 30
#define FAST 80
VarSpeedServo pinch_servo; // create servo objects
VarSpeedServo rot_servo;
void setup() {
pinch_servo.attach(pinch_pin);
rot_servo.attach(rot_pin, 580, 2570);
gripOpen(FAST);
armCenter(FAST);
delay(500);
}
void loop() {
for(int i=0; i<3; i++) {
gripClose(SLOW);
armRight(SLOW);
gripOpen(SLOW);
armCenter(SLOW);
}
delay(500);
for(int i=0; i<3; i++) {
gripClose(FAST);
armRight(FAST);
gripOpen(FAST);
armCenter(FAST);
}
delay(500);
for(int i=0; i<2; i++) {
gripClose(SLOW);
armLeft(SLOW);
gripOpen(SLOW);
armCenter(SLOW);
}
while(true);
}
void armRight(int speed) { rot_servo.write(CW, speed, true); }
void armLeft(int speed) { rot_servo.write(CCW, speed, true); }
void armCenter(int speed) { rot_servo.write(MID, speed, true); }
void gripOpen(int speed) { pinch_servo.write(OPEN, speed, true); }
void gripClose(int speed) { pinch_servo.write(CLOSE, speed, true); }
For this project I chose the "VarSpeedServo" library which has some definite advantages
compared to the standard Servo library:
Next stop: build a second gripper and assemble the final robot
** EDIT: see post #111 **
Nice looking setup. I'm assuming that the code actually makes the arm do what you claim. But, how is that going to be sufficient to solve a rubik's cube? How is the robot/Arduino going to know what moves to make to solve the cube? How is it going to know where to start? How is it going to know when to stop?
Hi Paul,
Nice looking setup
Thanks
how is that going to be sufficient to solve a rubik's cube?
How is the robot/Arduino going to know what moves to make to solve the cube?
Please refer to post#1, the solving itself will be performed using Cube Explorer
Solution will be passed to Arduino using Singmaster notation
(look here for a visual approach)
Arduino will convert notation into real world moves
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 :-\