├── .gitignore ├── __pycache__ └── awt.cpython-36.pyc ├── README.md └── nn.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints 2 | -------------------------------------------------------------------------------- /__pycache__/awt.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonComo/Arduino_weight_trainer/HEAD/__pycache__/awt.cpython-36.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arduino Weight Trainer (AWT) 2 | 3 | Made for this project https://github.com/IdleHandsProject/makennbot 4 | Or any arduino project that uses the neural network written here http://robotics.hobbizine.com/arduinoann.html 5 | 6 | You'll need the following packages (you can pip install each of them) 7 | 8 | tensorflow 9 | 10 | keras 11 | 12 | numpy 13 | 14 | jupyter notebook 15 | 16 | matplotlib 17 | 18 | To use: 19 | 20 | Setup x_train and y_train in the notebook to be the examples you want the network to train on. 21 | 22 | Run the cells sequentially and you'll see your network fit the training data. 23 | 24 | The final cell prints out a nicely formatted text version of the trained weights that you can copy directly into your arduino sketch! 25 | 26 | You have to disable weight randomization if you want to use your trained weights, comment out these lines in the sketch to do so: 27 | 28 | HiddenWeights[j][i] = 2.0 * ( Rando - 0.5 ) * InitialWeightMax ; 29 | OutputWeights[j][i] = 2.0 * ( Rando - 0.5 ) * InitialWeightMax ; 30 | 31 | That's about it, let me know how it works! 32 | -------------------------------------------------------------------------------- /nn.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stderr", 10 | "output_type": "stream", 11 | "text": [ 12 | "Using TensorFlow backend.\n" 13 | ] 14 | } 15 | ], 16 | "source": [ 17 | "import keras\n", 18 | "from keras.layers import Dense\n", 19 | "from keras.models import Sequential\n", 20 | "from keras import optimizers\n", 21 | "from keras import backend as K\n", 22 | "import numpy as np\n", 23 | "\n", 24 | "from matplotlib import pyplot as plt\n", 25 | "from IPython.display import clear_output" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": { 32 | "collapsed": true 33 | }, 34 | "outputs": [], 35 | "source": [ 36 | "#training data from https://github.com/IdleHandsProject/makennbot\n", 37 | "x_train = [\n", 38 | " [ 0, 1, 1, 0 ], # LIGHT ON LEFT AND RIGHT\n", 39 | " [ 0, 1, 0, 0 ], # LIGHT ON LEFT\n", 40 | " [ 1, 1, 1, 0 ], # LIGHT ON TOP, LEFT, and RIGHT\n", 41 | " [ 1, 1, 0, 0 ], # LIGHT ON TOP and LEFT\n", 42 | " [ 0, 0, 1, 0 ], # LIGHT ON RIGHT\n", 43 | " [ 1, 0, 0, 0 ], # LIGHT ON TOP\n", 44 | " [ 0, 0, 0, 0 ], # NO LIGHT\n", 45 | " [ 0, 0, 0, 1 ], # LIGHT ON BOTTOM\n", 46 | " [ 0, 1, 0, 1 ], # LIGHT ON BOTTOM AND LEFT\n", 47 | " [ 0, 0, 1, 1 ], # LIGHT ON BOTTOM AND RIGHT\n", 48 | " [ 0, 1, 1, 1 ], # LIGHT ON BOTTOM, LEFT, and RIGHT\n", 49 | " [ 1, 0, 0, 1 ], # LIGHT ON TOP AND BOTTOM\n", 50 | " [ 1, 1, 0, 1 ], # LIGHT ON TOP, BOTTOM, and LEFT\n", 51 | " [ 1, 0, 1, 1 ], # LIGHT ON TOP, BOTTOM, and RIGHT\n", 52 | " [ 1, 0, 1, 0 ], # LIGHT ON TOP AND RIGHT\n", 53 | " [ 1, 1, 1, 1 ], # LIGHT ON ALL\n", 54 | "]\n", 55 | "\n", 56 | "y_train = [\n", 57 | " [ 0.65, 0.55 ], #LEFT MOTOR SLOW\n", 58 | " [ 0.75, 0.5 ], #LEFT MOTOR FASTER\n", 59 | " [ 0.2, 0.2 ], #BOTH MOTORS FULL BACKWARDS\n", 60 | " [ 1, 0.2 ], #MOTOR LEFT FULL FORWARD, RIGHT BACKWARDS\n", 61 | " [ 0.5, 0.75 ], #MOTOR LEFT STOPPED, RIGHT FORWARDS\n", 62 | " [ 0.3, 0.3 ], #BOTH BACKWARDS \n", 63 | " [ 0.5, 0.5 ], #BOTH MOTORS STOPPED\n", 64 | " [ 0.75, 0.75 ],\n", 65 | " [ 1, 0.75 ],\n", 66 | " [ 0.75, 1 ],\n", 67 | " [ 1, 1 ],\n", 68 | " [ 1, 0 ],\n", 69 | " [ 1, 0.75 ],\n", 70 | " [ 0.75, 1 ],\n", 71 | " [ 0.2, 1 ],\n", 72 | " [ 0.65, 0.65],\n", 73 | "]\n", 74 | "\n", 75 | "x_train = np.array(x_train, dtype=np.float32)\n", 76 | "y_train = np.array(y_train)" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": null, 82 | "metadata": { 83 | "collapsed": true 84 | }, 85 | "outputs": [], 86 | "source": [ 87 | "# training data from http://robotics.hobbizine.com/arduinoann.html\n", 88 | "x_train = [\n", 89 | " [ 1, 1, 1, 1, 1, 1, 0 ], # 0\n", 90 | " [ 0, 1, 1, 0, 0, 0, 0 ], # 1\n", 91 | " [ 1, 1, 0, 1, 1, 0, 1 ], # 2\n", 92 | " [ 1, 1, 1, 1, 0, 0, 1 ], # 3\n", 93 | " [ 0, 1, 1, 0, 0, 1, 1 ], # 4\n", 94 | " [ 1, 0, 1, 1, 0, 1, 1 ], # 5\n", 95 | " [ 0, 0, 1, 1, 1, 1, 1 ], # 6\n", 96 | " [ 1, 1, 1, 0, 0, 0, 0 ], # 7 \n", 97 | " [ 1, 1, 1, 1, 1, 1, 1 ], # 8\n", 98 | " [ 1, 1, 1, 0, 0, 1, 1 ] # 9\n", 99 | "]\n", 100 | "\n", 101 | "y_train = [\n", 102 | " [ 0, 0, 0, 0 ], \n", 103 | " [ 0, 0, 0, 1 ], \n", 104 | " [ 0, 0, 1, 0 ], \n", 105 | " [ 0, 0, 1, 1 ], \n", 106 | " [ 0, 1, 0, 0 ], \n", 107 | " [ 0, 1, 0, 1 ], \n", 108 | " [ 0, 1, 1, 0 ], \n", 109 | " [ 0, 1, 1, 1 ], \n", 110 | " [ 1, 0, 0, 0 ], \n", 111 | " [ 1, 0, 0, 1 ] \n", 112 | "]\n", 113 | "\n", 114 | "x_train = np.array(x_train, dtype=np.float32)\n", 115 | "y_train = np.array(y_train)" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "metadata": { 122 | "collapsed": true 123 | }, 124 | "outputs": [], 125 | "source": [ 126 | "model = Sequential()\n", 127 | "\n", 128 | "IN = x_train.shape[1]\n", 129 | "HIDDEN = IN + 1\n", 130 | "OUT = y_train.shape[1]\n", 131 | "\n", 132 | "model.add(Dense(units=HIDDEN, activation='sigmoid', input_dim=IN))\n", 133 | "model.add(Dense(units=OUT, activation='sigmoid'))\n", 134 | "\n", 135 | "model.compile(loss='mean_squared_error',\n", 136 | " optimizer=optimizers.SGD(lr=0.4))" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": null, 142 | "metadata": { 143 | "collapsed": true 144 | }, 145 | "outputs": [], 146 | "source": [ 147 | "class PlotLosses(keras.callbacks.Callback):\n", 148 | " def on_train_begin(self, logs={}):\n", 149 | " self.i = 0\n", 150 | " self.x = []\n", 151 | " self.losses = []\n", 152 | " self.val_losses = []\n", 153 | " \n", 154 | " self.fig = plt.figure()\n", 155 | " \n", 156 | " self.logs = []\n", 157 | "\n", 158 | " def on_epoch_end(self, epoch, logs={}):\n", 159 | " \n", 160 | " self.logs.append(logs)\n", 161 | " self.x.append(self.i)\n", 162 | " self.losses.append(logs.get('loss'))\n", 163 | " self.val_losses.append(logs.get('val_loss'))\n", 164 | " self.i += 1\n", 165 | " \n", 166 | " clear_output(wait=True)\n", 167 | " plt.plot(self.x, self.losses, label=\"loss\")\n", 168 | " plt.plot(self.x, self.val_losses, label=\"val_loss\")\n", 169 | " plt.legend()\n", 170 | " plt.show();\n", 171 | " \n", 172 | "plot_losses = PlotLosses()" 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": null, 178 | "metadata": {}, 179 | "outputs": [], 180 | "source": [ 181 | "model.fit(x_train, y_train, epochs=50, batch_size=1, verbose=False, callbacks=[plot_losses])" 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": null, 187 | "metadata": {}, 188 | "outputs": [], 189 | "source": [ 190 | "preds = model.predict(x_train).tolist()\n", 191 | "for i, pred in enumerate(preds):\n", 192 | " print('model:\\t', np.round(pred,2))\n", 193 | " print('label:\\t', y_train[i])\n", 194 | " print(' ')" 195 | ] 196 | }, 197 | { 198 | "cell_type": "code", 199 | "execution_count": null, 200 | "metadata": { 201 | "collapsed": true 202 | }, 203 | "outputs": [], 204 | "source": [ 205 | "def to_str(name, W):\n", 206 | " s = str(W.tolist()).replace('[', '{').replace(']', '}')\n", 207 | " return 'float '+name+'['+str(W.shape[0])+']['+str(W.shape[1])+'] = ' + s + ';'" 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": null, 213 | "metadata": {}, 214 | "outputs": [], 215 | "source": [ 216 | "# output weights as strings you can copy into arduino sketch\n", 217 | "W1 = np.vstack((K.eval(model.weights[0]), K.eval(model.weights[1])))\n", 218 | "W2 = np.vstack((K.eval(model.weights[2]), K.eval(model.weights[3])))\n", 219 | "\n", 220 | "print('// replace these two lines in arduino code:')\n", 221 | "print('// float HiddenWeights[InputNodes+1][HiddenNodes]')\n", 222 | "print('// float OutputWeights[HiddenNodes+1][OutputNodes]')\n", 223 | "print('// With trained weights below.')\n", 224 | "print('\\n')\n", 225 | "print('// You also have to disable the initial weight randomization')\n", 226 | "print('// you can find it under this section in the arduino code:')\n", 227 | "print('//* Initialize HiddenWeights and ChangeHiddenWeights ')\n", 228 | "print('\\n')\n", 229 | "print(to_str('HiddenWeights', W1))\n", 230 | "print(to_str('OutputWeights', W2))" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": null, 236 | "metadata": { 237 | "collapsed": true 238 | }, 239 | "outputs": [], 240 | "source": [] 241 | } 242 | ], 243 | "metadata": { 244 | "kernelspec": { 245 | "display_name": "Python 3", 246 | "language": "python", 247 | "name": "python3" 248 | }, 249 | "language_info": { 250 | "codemirror_mode": { 251 | "name": "ipython", 252 | "version": 3 253 | }, 254 | "file_extension": ".py", 255 | "mimetype": "text/x-python", 256 | "name": "python", 257 | "nbconvert_exporter": "python", 258 | "pygments_lexer": "ipython3", 259 | "version": "3.6.1" 260 | } 261 | }, 262 | "nbformat": 4, 263 | "nbformat_minor": 2 264 | } 265 | --------------------------------------------------------------------------------