{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Predict hand gesture using a trained model\n", "## Import modules\n", "* __serial:__ To receive acceleration data from BBC Microbit connected through USB with the laptop\n", "* __numpy:__ To handle numpy arrays\n", "* __matplotlib:__ To plot the graph of the received data\n", "* __keras:__ To load the trained model" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import serial\n", "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "from keras.models import load_model" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import sys\n", "sys.path.insert(0, \"src\")\n", "from Utils import pad_constant, uniform_split, load_raw_data, LABELS" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__Utils__ module contains some custom functions and is located in the __src__ directory of our project. By adding __src__ in the system path, we can import the modules from it directly.\n", "Description of the functions loaded from __Utils__ modules are as follows:\n", "* __pad_constant:__ Pads a given array at the start with initial value or at the end at final value to achieve given item length\n", "* __load_raw_data:__ Processes an array with raw acceleration data by smoothing and normalising it\n", "\n", "__LABELS__ is a tuple with labels of the gestures." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Load Model\n", "Load a trained model from the **Models** directory." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "model = load_model(r\"Models/Model 96.11 12.06.2019 00.12.HDF5\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Receive data through serial communication from the BBC Micro:bit\n", "The dictionary CONFIG holds the configuration for the serial communication via USB between the program and the BBC Microbit.\n", "\n", "> Check the **port** id of the receiver BBC Micro:bit." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "CONFIG = {\"port\":\"COM5\", \"baudrate\":115200, \"bytesize\":8, \"parity\":\"N\", \"stopbits\":1}\n", "with serial.Serial(**CONFIG) as ser:\n", " raw_data = []\n", " i = 0\n", " print(\"# Waiting for data\")\n", " while True:\n", " sample_data = ser.readline()\n", " if sample_data.startswith(b\"done\"):\n", " print(\"\\n Done\")\n", " break\n", " elif b\",\" in sample_data:\n", " print(\" Receiving data {:<15}\".format(\".\"*i), end=\"\\r\")\n", " raw_data.append(sample_data)\n", " i = i+1 if (i < 15) else 0 # For progress animation\n", " ser.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Load and Process data\n", "Using the file name, we determine the label of the gesture and append it to the **labels** list.\n", "\n", "Then we load all the files we want to test using **load_raw_data** function. Through the parameters of this function, we can control the columns to be loaded **(cols)**, width of the moving average window **(movingAvgWindow)** and whether to normalize the loaded data or not **(normalize)**. Afterwards, each axis reading of the loaded data is padded at the start with its initial value to achieve the data length mentioned in **review_length** variable. Then each axis reading is reshaped and appended to the particular index of the **final_data** array depending on the axis type.\n", "\n", "Finally, the class vector (integers) of the loaded **labels** are converted to binary class matrix using the **to_categorical** function from **keras** module." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "final_data = [[], [], []] # Stores all processed data; [[x-axis], [y-axis], [z-axis]]\n", "review_length = 150 # Review length: length of each data after padding\n", "# Strip \"()\\n\" from the raw data, split at \",\", convert values from byte string to integer and store in a list\n", "fmt_data = [list(map(int, row.strip(b\"()\\n\").split(b\",\"))) for row in raw_data]\n", "columns = (\"x\", \"y\", \"z\")\n", "df = pd.DataFrame(fmt_data, columns=columns)\n", "df.columns = pd.Index([i.strip() for i in df.columns])\n", "data = load_raw_data(df, cols=columns, movingAvgWindow=13, normalizeData=True)\n", "data = uniform_split(data, parts=len(columns))\n", "for i, array in enumerate(data):\n", " array = pad_constant(array, max_length=review_length, pad_pos=\"start\")\n", " array = np.reshape(array, (1, array.shape[0]))\n", " final_data[i].append(array)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plotting graph\n", "Here we plot the acceleration data of all the planes on the y-axis and time sampled at interval of 100 ms on the x-axis." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sample_period = 0.1\n", "t = np.arange(review_length)*sample_period # Time range for each plot\n", "x, y, z = final_data\n", "plt.title(\"Unknown gesture\")\n", "plt.xlabel(\"time (s)\")\n", "plt.ylabel(\"Normalized acceleration\")\n", "plt.plot(t, np.array(x).reshape(review_length,), \"r\", label=\"x acceleration\")\n", "plt.plot(t, np.array(y).reshape(review_length,), \"g\", label=\"y acceleration\")\n", "plt.plot(t, np.array(z).reshape(review_length,), \"b\", label=\"z acceleration\")\n", "plt.legend()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Determine accuracy\n", "From the sampled data, we try to predict its label using our trained model." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "predicted_label = LABELS[np.argmax(model.predict(final_data), axis=1)[0]]\n", "print(\"Predicted motion:\", predicted_label.upper())" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.7" } }, "nbformat": 4, "nbformat_minor": 2 }