DEV Community

Cover image for Sliding Puzzle Next Move Suggesting Simple DL Model with ESP32 TensorFlow Lite
Trevor Lee
Trevor Lee

Posted on

Sliding Puzzle Next Move Suggesting Simple DL Model with ESP32 TensorFlow Lite

Sliding Puzzle 'Next Move' Suggesting Simple DL Model with ESP32 TensorFlow Lite

This project takes the game Sliding Puzzle
(with simple 'next move' suggesting 'search-directed heuristic' option),
adding to it the capability of suggesting 'next move' with a simple and naive DL model realized with ESP32 TensorFow Lite support.
The Sliding Puzzle game is implemented for Arduino framework compatible microcontroller boards with aids from DumbDisplay
to render the game remotely on your Android mobile phone.
Specifically, ESP32 / ESP32S3 is the targe microcontroller board for this experiment, since it not only supports Arduino framework, it also supports TensorFlow Lite.

The DL model of this experiment is implemented with TensorFlow that I worked out by referencing to two of my previous experiments:

In addition to an ESP32 / ESP32S3 microcontroller board, a few tools are assumed:

Building DL Model with VSCode

First, clone this project's source from the project's GitHub repository

git clone https://github.com/trevorwslee/ESP32SlidingPuzzle
Enter fullscreen mode Exit fullscreen mode

Open the cloned directory ESP32SlidingPuzzle with VSCode, then open train_model.ipynb

Run all cells of the Jupyter Notebook train_model.ipynb.
If environment is not setup already, it should first prompt you to create / select an Python environment.

Create a virtual Python environment for the project

As the last step, when asked to install dependencies, make sure to select requirement.txt

This should create the Python virtual environment .venv for the project with the needed dependencies installed.

If all the cells completed successfully, the model C header file src/esp32_sliding_puzzle/sp_model_4.h will be generated, overwriting the one already there.
Yes, there is one already included with this project, and hence it is not necessary for you to train the model again, unless you would like to tune the DL model.

The DL model is naively constructed with Keras like

tile_count = 4
batch_size = 128
epochs = 100
...
model = keras.models.Sequential()
model.add(keras.layers.Dense(256, activation='relu', input_shape=(tile_count * tile_count,)))
model.add(keras.layers.Dropout(0.3))
model.add(keras.layers.Dense(256, activation='relu'))
model.add(keras.layers.Dense(4, activation='softmax'))
...
model.compile(loss='categorical_crossentropy', optimizer=keras.optimizers.RMSprop(), metrics=['accuracy'])
history = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_validate, y_validate))
Enter fullscreen mode Exit fullscreen mode

With accuracy 0.868, the DL model appears not very good, but should be acceptable


Building and Uploading the Sketch

As mentioned previously, although not necessary, the steps to build and update the sketch is via PlatformIO (an extension of VSCode).

The configurations for developing and building of the sketch are basically written down in the platformio.ini file

[env]
monitor_speed = 115200

[env:ESP32]
platform = espressif32
board = esp32dev
framework = arduino
board_build.partitions = huge_app.csv
monitor_filters = esp32_exception_decoder
lib_deps =
    https://github.com/trevorwslee/Arduino-DumbDisplay
    tanakamasayuki/TensorFlowLite_ESP32@^1.0.0
build_flags =
    -D FOR_ESP32

[env:ESP32S3]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
lib_deps =
    https://github.com/trevorwslee/Arduino-DumbDisplay
    tanakamasayuki/TensorFlowLite_ESP32@^1.0.0
build_flags =
    -D FOR_ESP32S3
Enter fullscreen mode Exit fullscreen mode

Notice that you have choices of PlatformIO environments -- ESP32 and ESP32S3

Please choose the correct one according to the microcontroller board that you have.

In either case, the program entry point is src/main.cpp

#include <Arduino.h>

#if defined(CONFIG_IDF_TARGET_ESP32S3)
  #include "_secret.h"
#else
  #define BLUETOOTH "ESP32Sliding"
#endif

#include "esp32_sliding_puzzle/esp32_sliding_puzzle.ino"
Enter fullscreen mode Exit fullscreen mode

Notice that

  • For ESP32S3, WiFi connection to DumbDisplay Android app is used. In such a case, you will need to provide necessary WiFi login credentials in a header file src/_secret.h that you need to create with content like
  #define WIFI_SSID           "wifi-ssid"
  #define WIFI_PASSWORD       "wifi-password"
Enter fullscreen mode Exit fullscreen mode
  • Otherwise, for ESP32, Bluetooth connection to DumbDisplay Android app is used, with the Bluetooth device name ESP32Sliding

Build and upload the sketch with VSCode menu item View | Command Palette

For ESP32 which is using Bluetooth connectivity, you should see log entries with Serial Monitor (with baud rate 115200) like

For ESP32S3 which is using Wifi connectivity, the log entries will be like

Notice that the IP to connect to the ESP32 board shown by the log entries.

To connect your Android phone to your ESP32 / ESP32S3 microcontroller board via DumbDisplay Android app, open the DumbDisplay Android app and make connection like

with Bluetooth add WiFi with Wifi

Sliding Puzzle Game UI

After connection, you should see the picture of the board drawn.
To start a game, double click on the board, to divide the board into grid of tiles

Double clicking on the board will randomize the board by 5 steps (5 random moves).

During game play, you can click Suggest for a suggested 'next move'.
If you click Continuous, suggested 'next moves' are continuously made until either you disabled Continuous or the puzzle is solved.

There are three options for the 'next move' suggestion:
1) AI Only -- use the trained DL model for predicting 'next move' (the highest probability one)
2) AI+Search -- largely use the trained DL model for predicting 'next move'; however, if the top 'next move' probability is not high, fallback to use original "search* algo
3) Search Only -- use original "search" algo only

After every solving of the puzzle, 5 more randomize steps are added to randomization making the game a bit harder.

Any time if you want to reset / restart the game, double click on the Reset button.

Improving the 'Next Move' Suggestion Accuracy

The 'next move' suggestion is certainly not very accurate, specially when the board is randomized for many steps.

  • The naive DL model can certainly be improved. Notice that intrain_model.ipynb, the training data is randomized in reverse of how a board is randomize. Hence, it makes sense that the number of randomize steps affects the accuracy of the model specially in case the game is randomized for more steps than the model is trained. Here are the parameters for training the model:
    • round_count -- the number of rounds of random boards to generate; 10000 by default
    • random_step_count -- the number of random moves from "solved orientation" to "randomized orientation"; 20 by default
  • The "search" algo can be improved
  • The DL + "search" can be improved

Moreover, the board size can be bigger, like 5x5.
In order to change the board size to 5:

1) Need to change tile_count of train_model.ipynb generate a sp_model_5.h for the sketch

   # tile_count is the number of horizontal / vertical tiles ... a tile_count of 4 means a 4x4 board
   tile_count = 5
Enter fullscreen mode Exit fullscreen mode

2) Need to modify the sketch esp32_sliding_puzzle.ino

   #define TILE_COUNT 5
Enter fullscreen mode Exit fullscreen mode

which controls

    #if TILE_COUNT == 4
      #include "sp_model_4.h"
    #elif TILE_COUNT == 5
      #include "sp_model_5.h"
    #endif
    const tflite::Model* model = ::tflite::GetModel(sp_model);
Enter fullscreen mode Exit fullscreen mode

Interested friends are encouraged to try out and share how the 'next move' suggestion can be improved.

Enjoy!

Hope that you will have fun with it! Enjoy!

Peace be with you!
May God bless you!
Jesus loves you!
Amazing Grace!

Top comments (0)