Skip to content

Latest commit

Β 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

RS1 Rubik's Cube Algorithm

YouTube Demo

▢️ Watch the Demo Video


Overview

This is an open-source project developed by Samuele Riccardi, a university student passionate about robotics and algorithm development.

LinkedIn

RS1 is a Rubik's Cube solving algorithm that implements a hybrid solving method: the classic Layer by Layer approach for the first two layers, combined with OLL/PLL algorithms for the last layer. The algorithm receives a scrambled cube configuration and returns the sequence of moves required to solve it.

This repository contains the algorithm module of a larger robotics project. In the future, additional modules will be published to assemble a complete cube-solving robot, including:

  • Vision module (cube scanning and color recognition)
  • Hardware control module (robotic arm movements)
  • Integration module (orchestrating all components)

Processing Pipeline

Input Format

The service accepts a Rubik's Cube represented as 6 faces in a specific order. This order was designed to match the scanning sequence of a robotic arm that cannot scan faces consecutively:

Input Index Face Color Emoji
0 Front Blue 🟦
1 Top Yellow 🟨
2 Back Green 🟩
3 Bottom White ⬜
4 Right Red πŸŸ₯
5 Left Orange 🟧

Each face is a 3x3 matrix of color indices (0-5), read row by row from top-left to bottom-right.

⚠️ Important: Face Rotation Normalization

When building a physical cube scanner, the camera may capture faces with incorrect rotations relative to the cube's standard orientation. Before sending the cube to the solver, you must normalize each face's rotation.

The algorithm expects each face to be oriented so that its bottom neighbor matches the expected color relationship. If your scanner captures faces in an arbitrary rotation, implement a normalization function like this:

void align_face_to_bottom_neighbor(json& cube_json, int face_index, int bottom_face_index) {
    int current_face_color = cube_json["cube"][face_index][cube::CENTER_ROW][cube::CENTER_COL];
    int current_bottom_face = cube_json["cube"][bottom_face_index][cube::CENTER_ROW][cube::CENTER_COL];
    int expected_bottom = FACE_NEIGHBORS[current_face_color][static_cast<int>(Direction::BOTTOM)];

    if (expected_bottom != current_bottom_face) {
        int rotation_count = 0;
        for (; rotation_count < 4; rotation_count++) {
            if (current_bottom_face == FACE_NEIGHBORS[current_face_color][rotation_count]) {
                break;
            }
        }

        for (int i = 0; i < rotation_count; i++) {
            rotate_json_face_clockwise(&cube_json["cube"][face_index]);
        }
    }
}

void fix_scan_rotation(json& cube_json) {
    align_face_to_bottom_neighbor(cube_json, cube::BOTTOM_FACE, cube::FRONT_FACE);
    align_face_to_bottom_neighbor(cube_json, cube::FRONT_FACE, cube::RIGHT_FACE);
    align_face_to_bottom_neighbor(cube_json, cube::RIGHT_FACE, cube::BACK_FACE);
    align_face_to_bottom_neighbor(cube_json, cube::BACK_FACE, cube::BOTTOM_FACE);
    align_face_to_bottom_neighbor(cube_json, cube::LEFT_FACE, cube::FRONT_FACE);
    align_face_to_bottom_neighbor(cube_json, cube::TOP_FACE, cube::BACK_FACE);
}

How it works:

  1. Each face has a known neighbor relationship (stored in FACE_NEIGHBORS)
  2. The function checks if the current bottom neighbor matches the expected one
  3. If not, it calculates how many 90Β° clockwise rotations are needed
  4. The face is rotated until it aligns with the standard orientation

Solving Steps

Once the cube is received, the algorithm:

  1. Reorders faces - Maps input order to internal representation
  2. Builds the cube structure - Creates faces with all cell references
  3. Links adjacent faces - Establishes neighbor relationships (top, bottom, left, right, opposite)
  4. Links border cells - Connects edge and corner cells to their neighbors on adjacent faces
  5. Solves using Layer by Layer + OLL/PLL:
    • Cross - Solves the white cross on the bottom face
    • First Layer Corners - Places all 4 corners of the bottom layer
    • Second Layer Edges - Places all 4 edges of the middle layer
    • OLL (Orientation of Last Layer) - Orients all yellow pieces on top
    • PLL (Permutation of Last Layer) - Permutes the last layer pieces to complete the solve

Installation

Prerequisites: ROS2 Humble

This project requires ROS2 Humble. Follow the official installation guide:

# Set locale
sudo apt update && sudo apt install locales
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8

# Setup sources
sudo apt install software-properties-common
sudo add-apt-repository universe
sudo apt update && sudo apt install curl -y
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

# Install ROS2 Humble Desktop
sudo apt update
sudo apt install ros-humble-desktop

Clone the Repository

mkdir -p ~/rs1_ws/src
cd ~/rs1_ws/src
git clone https://github.com/ZiRoX7/RS1-Algorithm.git .

Install Dependencies

cd ~/rs1_ws
source /opt/ros/humble/setup.bash

# Install ROS dependencies
rosdep install --from-paths src --ignore-src -r -y

# Install nlohmann-json (JSON library)
sudo apt install nlohmann-json3-dev

Quick Start

Build the Project

cd ~/rs1_ws
source /opt/ros/humble/setup.bash
colcon build
source install/setup.bash

Start the Solver Service

In one terminal:

source /opt/ros/humble/setup.bash
source ~/rs1_ws/install/setup.bash
ros2 run cube_algorithm cube_algorithm_node

Test with a Scrambled Cube

In another terminal, call the service with a scrambled cube:

source /opt/ros/humble/setup.bash
source ~/rs1_ws/install/setup.bash

ros2 service call /solve_cube cube_algorithm/srv/SolveCube "{cube_faces: [{cells: [3,1,2,5,1,0,4,3,3]}, {cells: [3,1,5,3,5,4,4,2,3]}, {cells: [2,4,5,0,3,5,1,4,0]}, {cells: [5,0,0,3,0,2,2,0,0]}, {cells: [0,3,1,2,2,1,4,5,4]}, {cells: [2,2,5,1,4,4,1,5,1]}]}"

The service will return:

  • success: Whether the cube was solved successfully
  • moves_json: JSON array of moves to solve the cube
  • error_message: Error description if solving failed

Testing with Random Cubes

The cube_tester package allows you to validate the solver by testing it against randomly scrambled cubes.

Configuration

Edit the constants in cube_tester/include/cube_tester/cube_tester.hpp:

// Number of cubes to test
constexpr int NUMBER_OF_CUBES = 100;

// Number of random moves to scramble each cube
constexpr int NUMBER_OF_RANDOM_MOVES = 25;
  • NUMBER_OF_CUBES: How many random cubes to generate and solve
  • NUMBER_OF_RANDOM_MOVES: Scramble complexity (higher = more scrambled)

Running the Tester

First, start the solver service (if not already running):

ros2 run cube_algorithm cube_algorithm_node

Then, in another terminal, run the tester:

ros2 run cube_tester cube_tester_node

What the Tester Does

  1. Creates a solved cube
  2. Applies N random moves to scramble it
  3. Sends the scrambled cube to the solver service
  4. Verifies the response
  5. If successful: Deletes the test file
  6. If failed: Keeps the cube JSON in src/cube_tester/failed_cubes/ for debugging

At the end, it prints a summary:

Passed: 100/100
Failed: 0/100

Project Structure

RS1/src/
β”œβ”€β”€ cube_structure/          # Core data structures
β”‚   β”œβ”€β”€ include/             # Headers (structs, constants, cube operations)
β”‚   └── src/                 # Implementation (cube building, movements)
β”‚
β”œβ”€β”€ cube_algorithm/          # Solver implementation (Layer by Layer + OLL/PLL)
β”‚   β”œβ”€β”€ include/             # Solver headers (cross, layers, OLL, PLL)
β”‚   β”œβ”€β”€ src/                 # Solver implementations
β”‚   └── srv/                 # ROS2 service definition
β”‚
└── cube_tester/             # Testing utilities
    β”œβ”€β”€ include/             # Tester headers
    └── src/                 # Random cube generation and validation

Author

Samuele Riccardi

LinkedIn YouTube


License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Rubik's Cube solving algorithm module for the RS1 robot. Solves any valid 3x3 cube and outputs notation moves. Built with ROS2 Humble and C++17.

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages