├── .gitignore ├── Host ├── DataFile.py ├── PerformanceCounter.py ├── SensorChart.py ├── SensorProcess.py ├── model.h ├── model.tflite ├── start ├── tinyml.ipynb └── tinyml.py ├── Images ├── arduino1.png ├── arduino2.png ├── arduino_lib.png ├── beetle.jpg ├── inference.png ├── mu9250.jpg ├── network.png └── process.png ├── README.md ├── model.h ├── model.tflite └── predict_gesture ├── HRTimer.cpp ├── HRTimer.h ├── LED.cpp ├── LED.h ├── MPU9250.cpp ├── MPU9250.h ├── MPU9250_Reg.h ├── UDPChannel.cpp ├── UDPChannel.h ├── model.h └── predict_gesture.ino /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .ipynb_checkpoints 3 | .vscode 4 | *.csv 5 | *.bak -------------------------------------------------------------------------------- /Host/DataFile.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | class DataFile: 5 | def __init__(self): 6 | self.File = None 7 | self.BasePath = os.path.dirname(__file__) 8 | 9 | 10 | def __del__(self): 11 | self.Close() 12 | 13 | 14 | def Write(self, data): 15 | if self.File == None: 16 | self.Open() 17 | 18 | if len(data) >= 6: 19 | for i in range(6): 20 | if i > 0: self.File.write("\t") 21 | self.File.write(str(data[i])) 22 | 23 | self.File.write("\n") 24 | 25 | 26 | def Open(self): 27 | self.File = None 28 | self.File = open(self.BasePath + "/data/data.csv", "a+") 29 | 30 | 31 | def Close(self): 32 | if self.File != None: 33 | self.File.flush() 34 | self.File.close() 35 | 36 | self.File = None 37 | 38 | -------------------------------------------------------------------------------- /Host/PerformanceCounter.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | class PerformanceCounter: 4 | def __init__(self): 5 | self.Reset() 6 | 7 | 8 | def Reset(self): 9 | self.Count = 0 10 | self.LastTick = time.perf_counter() 11 | 12 | 13 | def Frame(self): 14 | self.Count = self.Count + 1 15 | 16 | tick = time.perf_counter() 17 | dt = tick - self.LastTick 18 | self.LastTick = tick 19 | 20 | return [self.Count, dt] -------------------------------------------------------------------------------- /Host/SensorChart.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from OpenGL import GLUT, GLU, GL 4 | 5 | AxisColor = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] 6 | BarScale = [0.00005, 0.00005, 0.00005, 0.00005, 0.00005, 0.00005, 0.0015, 0.0015, 0.0015] 7 | 8 | class SensorChart: 9 | def __init__(self): 10 | GLUT.glutInit() 11 | GLUT.glutInitDisplayMode(GLUT.GLUT_SINGLE | GLUT.GLUT_RGBA) 12 | GLUT.glutInitWindowSize(600, 600) 13 | GLUT.glutCreateWindow("3D") 14 | 15 | 16 | def Run(self, proc): 17 | GLUT.glutDisplayFunc(self.Draw) 18 | GLUT.glutIdleFunc(proc) 19 | 20 | GLUT.glutMainLoop() 21 | 22 | 23 | def Draw(self, data=None, data_his=None): 24 | GL.glClear(GL.GL_COLOR_BUFFER_BIT) 25 | GL.glBegin(GL.GL_LINES) 26 | 27 | YScale = lambda y: y / 5 * 0.00001 28 | 29 | # Draw Bars 30 | if data != None: 31 | for i in range(len(data)): 32 | x = i * 0.1 - 0.9 33 | y = 0.75 + YScale(data[i]) 34 | c = AxisColor[i % 3] 35 | 36 | GL.glColor3f(c[0], c[1], c[2]) 37 | GL.glVertex3f(x, 0.75, 0) 38 | GL.glVertex3f(x, y, 0) 39 | 40 | # Draw Curves 41 | if data_his != None and len(data_his) > 0: 42 | size = len(data_his) 43 | for i in range(6): 44 | c = AxisColor[i % 3] 45 | y0 = 0.1 if i > 2 else -0.6 46 | GL.glColor3f(c[0], c[1], c[2]) 47 | 48 | px = -1 49 | py = y0 + YScale(data_his[0][i]) 50 | for k in range(size - 1): 51 | x = -1 + (k + 1) * 2 / 120 52 | y = y0 + YScale(data_his[k + 1][i]) 53 | GL.glVertex3f(px, py, 0) 54 | GL.glVertex3f(x, y, 0) 55 | px = x 56 | py = y 57 | 58 | 59 | GL.glEnd() 60 | GL.glFlush() -------------------------------------------------------------------------------- /Host/SensorProcess.py: -------------------------------------------------------------------------------- 1 | from asyncio.windows_events import NULL 2 | import socket 3 | from unittest import skip 4 | from PerformanceCounter import PerformanceCounter 5 | from SensorChart import SensorChart 6 | from DataFile import DataFile 7 | 8 | class UdpServer: 9 | def __init__(self): 10 | self.Sample = [] 11 | self.Data = [] 12 | self.Idle = True 13 | self.SampleCount = 0 14 | 15 | self.Counter = PerformanceCounter() 16 | self.Chart = SensorChart() 17 | self.DataFile = DataFile() 18 | 19 | self.Server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 20 | self.Server.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) 21 | self.Server.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536 * 16) 22 | self.Server.settimeout(0.5) 23 | 24 | ip = self.GetLocalIP("192.168.10") 25 | print(ip) 26 | self.Server.bind((ip, 8000)) 27 | 28 | 29 | def Run(self): 30 | self.Chart.Run(self.Recv) 31 | self.DataFile = NULL 32 | 33 | 34 | def Recv(self): 35 | self.Data = [0] * 9 36 | 37 | try: 38 | data, address = self.Server.recvfrom(40) 39 | 40 | #print(len(data), data) 41 | reader = lambda p: int.from_bytes(data[p:p + 4], byteorder="little", signed=True) 42 | 43 | c = reader(0) 44 | for i in range(9): 45 | self.Data[i] = reader((i + 1) * 4) 46 | 47 | if self.Idle: 48 | self.Sample = [] 49 | self.Idle = False 50 | 51 | while self.AddData(c, self.Data[:]) < c: 52 | continue 53 | 54 | 55 | except socket.timeout: 56 | if not self.Idle: 57 | if len(self.Sample) == 120: 58 | self.SampleCount += 1 59 | for d in self.Sample: 60 | self.DataFile.Write(d) 61 | else: 62 | self.Sample = [] 63 | 64 | print("Sample: ", self.SampleCount) 65 | 66 | self.DataFile.Close() 67 | self.Counter.Reset() 68 | self.Idle = True 69 | 70 | except Exception as e: 71 | self.Data = [] 72 | print("error", e.args) 73 | 74 | 75 | def AddData(self, c, d): 76 | self.Sample.append(d) 77 | 78 | [count, t] = self.Counter.Frame() 79 | print(count, int(t * 1000), c, d) 80 | 81 | self.Chart.Draw(d, self.Sample) 82 | 83 | return count 84 | 85 | 86 | def GetLocalIP(self, mask): 87 | host_name = socket.gethostname() 88 | ips = socket.gethostbyname_ex(host_name)[2] 89 | 90 | for ip in ips: 91 | if ip.startswith(mask): 92 | ret = ip 93 | 94 | return ret 95 | 96 | 97 | 98 | if __name__ == '__main__': 99 | Server = UdpServer() 100 | Server.Run() 101 | -------------------------------------------------------------------------------- /Host/model.tflite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mushroomcloud-cc/tinyml-workshop/f8e89a41f96933f9f7bf7e0168035ddc6dd6e70f/Host/model.tflite -------------------------------------------------------------------------------- /Host/start: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | jupyter notebook --ip 0.0.0.0 --allow-root 4 | -------------------------------------------------------------------------------- /Host/tinyml.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "5b90960c", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "from tinyml import *\n" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 2, 16 | "id": "3aa59cd7", 17 | "metadata": { 18 | "scrolled": false 19 | }, 20 | "outputs": [ 21 | { 22 | "name": "stdout", 23 | "output_type": "stream", 24 | "text": [ 25 | "Model: \"sequential\"\n", 26 | "_________________________________________________________________\n", 27 | " Layer (type) Output Shape Param # \n", 28 | "=================================================================\n", 29 | " dense (Dense) (None, 32) 23072 \n", 30 | " \n", 31 | " dense_1 (Dense) (None, 16) 528 \n", 32 | " \n", 33 | " dense_2 (Dense) (None, 2) 34 \n", 34 | " \n", 35 | "=================================================================\n", 36 | "Total params: 23,634\n", 37 | "Trainable params: 23,634\n", 38 | "Non-trainable params: 0\n", 39 | "_________________________________________________________________\n" 40 | ] 41 | } 42 | ], 43 | "source": [ 44 | "Model = CreateModel()" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 3, 50 | "id": "43bcd7b1", 51 | "metadata": { 52 | "scrolled": true 53 | }, 54 | "outputs": [ 55 | { 56 | "name": "stdout", 57 | "output_type": "stream", 58 | "text": [ 59 | "Epoch 1/200\n", 60 | "6/6 [==============================] - 1s 61ms/step - loss: 0.0338 - categorical_accuracy: 1.0000 - val_loss: 3.3762e-04 - val_categorical_accuracy: 1.0000\n", 61 | "Epoch 2/200\n", 62 | "6/6 [==============================] - 0s 9ms/step - loss: 8.1729e-05 - categorical_accuracy: 1.0000 - val_loss: 6.4333e-05 - val_categorical_accuracy: 1.0000\n", 63 | "Epoch 3/200\n", 64 | "6/6 [==============================] - 0s 8ms/step - loss: 1.1689e-05 - categorical_accuracy: 1.0000 - val_loss: 2.4793e-05 - val_categorical_accuracy: 1.0000\n", 65 | "Epoch 4/200\n", 66 | "6/6 [==============================] - 0s 7ms/step - loss: 5.5902e-06 - categorical_accuracy: 1.0000 - val_loss: 1.4142e-05 - val_categorical_accuracy: 1.0000\n", 67 | "Epoch 5/200\n", 68 | "6/6 [==============================] - 0s 10ms/step - loss: 3.3807e-06 - categorical_accuracy: 1.0000 - val_loss: 1.0154e-05 - val_categorical_accuracy: 1.0000\n", 69 | "Epoch 6/200\n", 70 | "6/6 [==============================] - 0s 8ms/step - loss: 2.7307e-06 - categorical_accuracy: 1.0000 - val_loss: 8.3227e-06 - val_categorical_accuracy: 1.0000\n", 71 | "Epoch 7/200\n", 72 | "6/6 [==============================] - 0s 7ms/step - loss: 2.2622e-06 - categorical_accuracy: 1.0000 - val_loss: 7.3853e-06 - val_categorical_accuracy: 1.0000\n", 73 | "Epoch 8/200\n", 74 | "6/6 [==============================] - 0s 9ms/step - loss: 2.0293e-06 - categorical_accuracy: 1.0000 - val_loss: 6.8435e-06 - val_categorical_accuracy: 1.0000\n", 75 | "Epoch 9/200\n", 76 | "6/6 [==============================] - 0s 8ms/step - loss: 1.9018e-06 - categorical_accuracy: 1.0000 - val_loss: 6.5238e-06 - val_categorical_accuracy: 1.0000\n", 77 | "Epoch 10/200\n", 78 | "6/6 [==============================] - 0s 8ms/step - loss: 1.8158e-06 - categorical_accuracy: 1.0000 - val_loss: 6.3342e-06 - val_categorical_accuracy: 1.0000\n", 79 | "Epoch 11/200\n", 80 | "6/6 [==============================] - 0s 7ms/step - loss: 1.7659e-06 - categorical_accuracy: 1.0000 - val_loss: 6.1445e-06 - val_categorical_accuracy: 1.0000\n", 81 | "Epoch 12/200\n", 82 | "6/6 [==============================] - 0s 9ms/step - loss: 1.7174e-06 - categorical_accuracy: 1.0000 - val_loss: 6.0036e-06 - val_categorical_accuracy: 1.0000\n", 83 | "Epoch 13/200\n", 84 | "6/6 [==============================] - 0s 7ms/step - loss: 1.6772e-06 - categorical_accuracy: 1.0000 - val_loss: 5.8790e-06 - val_categorical_accuracy: 1.0000\n", 85 | "Epoch 14/200\n", 86 | "6/6 [==============================] - 0s 9ms/step - loss: 1.6370e-06 - categorical_accuracy: 1.0000 - val_loss: 5.7815e-06 - val_categorical_accuracy: 1.0000\n", 87 | "Epoch 15/200\n", 88 | "6/6 [==============================] - 0s 7ms/step - loss: 1.6176e-06 - categorical_accuracy: 1.0000 - val_loss: 5.6677e-06 - val_categorical_accuracy: 1.0000\n", 89 | "Epoch 16/200\n", 90 | "6/6 [==============================] - 0s 7ms/step - loss: 1.5719e-06 - categorical_accuracy: 1.0000 - val_loss: 5.5810e-06 - val_categorical_accuracy: 1.0000\n", 91 | "Epoch 17/200\n", 92 | "6/6 [==============================] - 0s 12ms/step - loss: 1.5442e-06 - categorical_accuracy: 1.0000 - val_loss: 5.4943e-06 - val_categorical_accuracy: 1.0000\n", 93 | "Epoch 18/200\n", 94 | "6/6 [==============================] - 0s 8ms/step - loss: 1.5137e-06 - categorical_accuracy: 1.0000 - val_loss: 5.3914e-06 - val_categorical_accuracy: 1.0000\n", 95 | "Epoch 19/200\n", 96 | "6/6 [==============================] - 0s 6ms/step - loss: 1.4929e-06 - categorical_accuracy: 1.0000 - val_loss: 5.2993e-06 - val_categorical_accuracy: 1.0000\n", 97 | "Epoch 20/200\n", 98 | "6/6 [==============================] - 0s 8ms/step - loss: 1.4638e-06 - categorical_accuracy: 1.0000 - val_loss: 5.2126e-06 - val_categorical_accuracy: 1.0000\n", 99 | "Epoch 21/200\n", 100 | "6/6 [==============================] - 0s 9ms/step - loss: 1.4430e-06 - categorical_accuracy: 1.0000 - val_loss: 5.1259e-06 - val_categorical_accuracy: 1.0000\n", 101 | "Epoch 22/200\n", 102 | "6/6 [==============================] - 0s 7ms/step - loss: 1.4180e-06 - categorical_accuracy: 1.0000 - val_loss: 5.0392e-06 - val_categorical_accuracy: 1.0000\n", 103 | "Epoch 23/200\n", 104 | "6/6 [==============================] - 0s 7ms/step - loss: 1.3958e-06 - categorical_accuracy: 1.0000 - val_loss: 4.9525e-06 - val_categorical_accuracy: 1.0000\n", 105 | "Epoch 24/200\n", 106 | "6/6 [==============================] - 0s 9ms/step - loss: 1.3681e-06 - categorical_accuracy: 1.0000 - val_loss: 4.8766e-06 - val_categorical_accuracy: 1.0000\n", 107 | "Epoch 25/200\n", 108 | "6/6 [==============================] - 0s 7ms/step - loss: 1.3432e-06 - categorical_accuracy: 1.0000 - val_loss: 4.8008e-06 - val_categorical_accuracy: 1.0000\n", 109 | "Epoch 26/200\n", 110 | "6/6 [==============================] - 0s 8ms/step - loss: 1.3224e-06 - categorical_accuracy: 1.0000 - val_loss: 4.7303e-06 - val_categorical_accuracy: 1.0000\n", 111 | "Epoch 27/200\n", 112 | "6/6 [==============================] - 0s 8ms/step - loss: 1.3044e-06 - categorical_accuracy: 1.0000 - val_loss: 4.6328e-06 - val_categorical_accuracy: 1.0000\n", 113 | "Epoch 28/200\n", 114 | "6/6 [==============================] - 0s 9ms/step - loss: 1.2711e-06 - categorical_accuracy: 1.0000 - val_loss: 4.5407e-06 - val_categorical_accuracy: 1.0000\n", 115 | "Epoch 29/200\n", 116 | "6/6 [==============================] - 0s 8ms/step - loss: 1.2461e-06 - categorical_accuracy: 1.0000 - val_loss: 4.4648e-06 - val_categorical_accuracy: 1.0000\n", 117 | "Epoch 30/200\n", 118 | "6/6 [==============================] - 0s 9ms/step - loss: 1.2295e-06 - categorical_accuracy: 1.0000 - val_loss: 4.3944e-06 - val_categorical_accuracy: 1.0000\n", 119 | "Epoch 31/200\n", 120 | "6/6 [==============================] - 0s 8ms/step - loss: 1.2087e-06 - categorical_accuracy: 1.0000 - val_loss: 4.3294e-06 - val_categorical_accuracy: 1.0000\n", 121 | "Epoch 32/200\n", 122 | "6/6 [==============================] - 0s 9ms/step - loss: 1.1907e-06 - categorical_accuracy: 1.0000 - val_loss: 4.2535e-06 - val_categorical_accuracy: 1.0000\n", 123 | "Epoch 33/200\n", 124 | "6/6 [==============================] - 0s 8ms/step - loss: 1.1741e-06 - categorical_accuracy: 1.0000 - val_loss: 4.1939e-06 - val_categorical_accuracy: 1.0000\n", 125 | "Epoch 34/200\n", 126 | "6/6 [==============================] - 0s 7ms/step - loss: 1.1547e-06 - categorical_accuracy: 1.0000 - val_loss: 4.1397e-06 - val_categorical_accuracy: 1.0000\n", 127 | "Epoch 35/200\n", 128 | "6/6 [==============================] - 0s 8ms/step - loss: 1.1353e-06 - categorical_accuracy: 1.0000 - val_loss: 4.0910e-06 - val_categorical_accuracy: 1.0000\n", 129 | "Epoch 36/200\n", 130 | "6/6 [==============================] - 0s 7ms/step - loss: 1.1200e-06 - categorical_accuracy: 1.0000 - val_loss: 4.0314e-06 - val_categorical_accuracy: 1.0000\n", 131 | "Epoch 37/200\n", 132 | "6/6 [==============================] - 0s 9ms/step - loss: 1.1061e-06 - categorical_accuracy: 1.0000 - val_loss: 3.9826e-06 - val_categorical_accuracy: 1.0000\n", 133 | "Epoch 38/200\n", 134 | "6/6 [==============================] - 0s 9ms/step - loss: 1.0854e-06 - categorical_accuracy: 1.0000 - val_loss: 3.9176e-06 - val_categorical_accuracy: 1.0000\n", 135 | "Epoch 39/200\n", 136 | "6/6 [==============================] - 0s 10ms/step - loss: 1.0756e-06 - categorical_accuracy: 1.0000 - val_loss: 3.8688e-06 - val_categorical_accuracy: 1.0000\n", 137 | "Epoch 40/200\n", 138 | "6/6 [==============================] - 0s 8ms/step - loss: 1.0604e-06 - categorical_accuracy: 1.0000 - val_loss: 3.8092e-06 - val_categorical_accuracy: 1.0000\n", 139 | "Epoch 41/200\n", 140 | "6/6 [==============================] - 0s 7ms/step - loss: 1.0452e-06 - categorical_accuracy: 1.0000 - val_loss: 3.7496e-06 - val_categorical_accuracy: 1.0000\n", 141 | "Epoch 42/200\n", 142 | "6/6 [==============================] - 0s 10ms/step - loss: 1.0299e-06 - categorical_accuracy: 1.0000 - val_loss: 3.6954e-06 - val_categorical_accuracy: 1.0000\n", 143 | "Epoch 43/200\n", 144 | "6/6 [==============================] - 0s 10ms/step - loss: 1.0202e-06 - categorical_accuracy: 1.0000 - val_loss: 3.6196e-06 - val_categorical_accuracy: 1.0000\n", 145 | "Epoch 44/200\n", 146 | "6/6 [==============================] - 0s 10ms/step - loss: 9.9941e-07 - categorical_accuracy: 1.0000 - val_loss: 3.5383e-06 - val_categorical_accuracy: 1.0000\n", 147 | "Epoch 45/200\n", 148 | "6/6 [==============================] - 0s 8ms/step - loss: 9.8139e-07 - categorical_accuracy: 1.0000 - val_loss: 3.4949e-06 - val_categorical_accuracy: 1.0000\n", 149 | "Epoch 46/200\n", 150 | "6/6 [==============================] - 0s 8ms/step - loss: 9.7169e-07 - categorical_accuracy: 1.0000 - val_loss: 3.4462e-06 - val_categorical_accuracy: 1.0000\n", 151 | "Epoch 47/200\n", 152 | "6/6 [==============================] - 0s 10ms/step - loss: 9.5783e-07 - categorical_accuracy: 1.0000 - val_loss: 3.3974e-06 - val_categorical_accuracy: 1.0000\n", 153 | "Epoch 48/200\n", 154 | "6/6 [==============================] - 0s 10ms/step - loss: 9.4674e-07 - categorical_accuracy: 1.0000 - val_loss: 3.3595e-06 - val_categorical_accuracy: 1.0000\n" 155 | ] 156 | }, 157 | { 158 | "name": "stdout", 159 | "output_type": "stream", 160 | "text": [ 161 | "Epoch 49/200\n", 162 | "6/6 [==============================] - 0s 8ms/step - loss: 9.3703e-07 - categorical_accuracy: 1.0000 - val_loss: 3.3107e-06 - val_categorical_accuracy: 1.0000\n", 163 | "Epoch 50/200\n", 164 | "6/6 [==============================] - 0s 7ms/step - loss: 9.2179e-07 - categorical_accuracy: 1.0000 - val_loss: 3.2782e-06 - val_categorical_accuracy: 1.0000\n", 165 | "Epoch 51/200\n", 166 | "6/6 [==============================] - 0s 10ms/step - loss: 9.1070e-07 - categorical_accuracy: 1.0000 - val_loss: 3.2511e-06 - val_categorical_accuracy: 1.0000\n", 167 | "Epoch 52/200\n", 168 | "6/6 [==============================] - 0s 9ms/step - loss: 9.0099e-07 - categorical_accuracy: 1.0000 - val_loss: 3.2023e-06 - val_categorical_accuracy: 1.0000\n", 169 | "Epoch 53/200\n", 170 | "6/6 [==============================] - 0s 9ms/step - loss: 8.9129e-07 - categorical_accuracy: 1.0000 - val_loss: 3.1644e-06 - val_categorical_accuracy: 1.0000\n", 171 | "Epoch 54/200\n", 172 | "6/6 [==============================] - 0s 10ms/step - loss: 8.7882e-07 - categorical_accuracy: 1.0000 - val_loss: 3.1048e-06 - val_categorical_accuracy: 1.0000\n", 173 | "Epoch 55/200\n", 174 | "6/6 [==============================] - 0s 8ms/step - loss: 8.6911e-07 - categorical_accuracy: 1.0000 - val_loss: 3.0669e-06 - val_categorical_accuracy: 1.0000\n", 175 | "Epoch 56/200\n", 176 | "6/6 [==============================] - 0s 9ms/step - loss: 8.6080e-07 - categorical_accuracy: 1.0000 - val_loss: 3.0290e-06 - val_categorical_accuracy: 1.0000\n", 177 | "Epoch 57/200\n", 178 | "6/6 [==============================] - 0s 9ms/step - loss: 8.5248e-07 - categorical_accuracy: 1.0000 - val_loss: 3.0019e-06 - val_categorical_accuracy: 1.0000\n", 179 | "Epoch 58/200\n", 180 | "6/6 [==============================] - 0s 15ms/step - loss: 8.4694e-07 - categorical_accuracy: 1.0000 - val_loss: 2.9531e-06 - val_categorical_accuracy: 1.0000\n", 181 | "Epoch 59/200\n", 182 | "6/6 [==============================] - 0s 9ms/step - loss: 8.3585e-07 - categorical_accuracy: 1.0000 - val_loss: 2.9206e-06 - val_categorical_accuracy: 1.0000\n", 183 | "Epoch 60/200\n", 184 | "6/6 [==============================] - 0s 9ms/step - loss: 8.1783e-07 - categorical_accuracy: 1.0000 - val_loss: 2.8935e-06 - val_categorical_accuracy: 1.0000\n", 185 | "Epoch 61/200\n", 186 | "6/6 [==============================] - 0s 7ms/step - loss: 8.0951e-07 - categorical_accuracy: 1.0000 - val_loss: 2.8718e-06 - val_categorical_accuracy: 1.0000\n", 187 | "Epoch 62/200\n", 188 | "6/6 [==============================] - 0s 10ms/step - loss: 8.0397e-07 - categorical_accuracy: 1.0000 - val_loss: 2.8339e-06 - val_categorical_accuracy: 1.0000\n", 189 | "Epoch 63/200\n", 190 | "6/6 [==============================] - 0s 10ms/step - loss: 7.9426e-07 - categorical_accuracy: 1.0000 - val_loss: 2.7851e-06 - val_categorical_accuracy: 1.0000\n", 191 | "Epoch 64/200\n", 192 | "6/6 [==============================] - 0s 9ms/step - loss: 7.8733e-07 - categorical_accuracy: 1.0000 - val_loss: 2.7526e-06 - val_categorical_accuracy: 1.0000\n", 193 | "Epoch 65/200\n", 194 | "6/6 [==============================] - 0s 7ms/step - loss: 7.7624e-07 - categorical_accuracy: 1.0000 - val_loss: 2.7147e-06 - val_categorical_accuracy: 1.0000\n", 195 | "Epoch 66/200\n", 196 | "6/6 [==============================] - 0s 8ms/step - loss: 7.6931e-07 - categorical_accuracy: 1.0000 - val_loss: 2.6876e-06 - val_categorical_accuracy: 1.0000\n", 197 | "Epoch 67/200\n", 198 | "6/6 [==============================] - 0s 9ms/step - loss: 7.5822e-07 - categorical_accuracy: 1.0000 - val_loss: 2.6551e-06 - val_categorical_accuracy: 1.0000\n", 199 | "Epoch 68/200\n", 200 | "6/6 [==============================] - 0s 8ms/step - loss: 7.5129e-07 - categorical_accuracy: 1.0000 - val_loss: 2.6226e-06 - val_categorical_accuracy: 1.0000\n", 201 | "Epoch 69/200\n", 202 | "6/6 [==============================] - 0s 8ms/step - loss: 7.4713e-07 - categorical_accuracy: 1.0000 - val_loss: 2.5955e-06 - val_categorical_accuracy: 1.0000\n", 203 | "Epoch 70/200\n", 204 | "6/6 [==============================] - 0s 8ms/step - loss: 7.3466e-07 - categorical_accuracy: 1.0000 - val_loss: 2.5684e-06 - val_categorical_accuracy: 1.0000\n", 205 | "Epoch 71/200\n", 206 | "6/6 [==============================] - 0s 8ms/step - loss: 7.2496e-07 - categorical_accuracy: 1.0000 - val_loss: 2.5467e-06 - val_categorical_accuracy: 1.0000\n", 207 | "Epoch 72/200\n", 208 | "6/6 [==============================] - 0s 8ms/step - loss: 7.1941e-07 - categorical_accuracy: 1.0000 - val_loss: 2.5196e-06 - val_categorical_accuracy: 1.0000\n", 209 | "Epoch 73/200\n", 210 | "6/6 [==============================] - 0s 9ms/step - loss: 7.1248e-07 - categorical_accuracy: 1.0000 - val_loss: 2.4817e-06 - val_categorical_accuracy: 1.0000\n", 211 | "Epoch 74/200\n", 212 | "6/6 [==============================] - 0s 8ms/step - loss: 7.0416e-07 - categorical_accuracy: 1.0000 - val_loss: 2.4546e-06 - val_categorical_accuracy: 1.0000\n", 213 | "Epoch 75/200\n", 214 | "6/6 [==============================] - 0s 7ms/step - loss: 6.9723e-07 - categorical_accuracy: 1.0000 - val_loss: 2.4221e-06 - val_categorical_accuracy: 1.0000\n", 215 | "Epoch 76/200\n", 216 | "6/6 [==============================] - 0s 9ms/step - loss: 6.9030e-07 - categorical_accuracy: 1.0000 - val_loss: 2.3950e-06 - val_categorical_accuracy: 1.0000\n", 217 | "Epoch 77/200\n", 218 | "6/6 [==============================] - 0s 7ms/step - loss: 6.8614e-07 - categorical_accuracy: 1.0000 - val_loss: 2.3625e-06 - val_categorical_accuracy: 1.0000\n", 219 | "Epoch 78/200\n", 220 | "6/6 [==============================] - 0s 8ms/step - loss: 6.7921e-07 - categorical_accuracy: 1.0000 - val_loss: 2.3300e-06 - val_categorical_accuracy: 1.0000\n", 221 | "Epoch 79/200\n", 222 | "6/6 [==============================] - 0s 8ms/step - loss: 6.7228e-07 - categorical_accuracy: 1.0000 - val_loss: 2.2975e-06 - val_categorical_accuracy: 1.0000\n", 223 | "Epoch 80/200\n", 224 | "6/6 [==============================] - 0s 9ms/step - loss: 6.6674e-07 - categorical_accuracy: 1.0000 - val_loss: 2.2704e-06 - val_categorical_accuracy: 1.0000\n", 225 | "Epoch 81/200\n", 226 | "6/6 [==============================] - 0s 7ms/step - loss: 6.6258e-07 - categorical_accuracy: 1.0000 - val_loss: 2.2487e-06 - val_categorical_accuracy: 1.0000\n", 227 | "Epoch 82/200\n", 228 | "6/6 [==============================] - 0s 9ms/step - loss: 6.5703e-07 - categorical_accuracy: 1.0000 - val_loss: 2.2270e-06 - val_categorical_accuracy: 1.0000\n", 229 | "Epoch 83/200\n", 230 | "6/6 [==============================] - 0s 7ms/step - loss: 6.5426e-07 - categorical_accuracy: 1.0000 - val_loss: 2.1891e-06 - val_categorical_accuracy: 1.0000\n", 231 | "Epoch 84/200\n", 232 | "6/6 [==============================] - 0s 8ms/step - loss: 6.5149e-07 - categorical_accuracy: 1.0000 - val_loss: 2.1620e-06 - val_categorical_accuracy: 1.0000\n", 233 | "Epoch 85/200\n", 234 | "6/6 [==============================] - 0s 8ms/step - loss: 6.4317e-07 - categorical_accuracy: 1.0000 - val_loss: 2.1403e-06 - val_categorical_accuracy: 1.0000\n", 235 | "Epoch 86/200\n", 236 | "6/6 [==============================] - 0s 8ms/step - loss: 6.3901e-07 - categorical_accuracy: 1.0000 - val_loss: 2.1187e-06 - val_categorical_accuracy: 1.0000\n", 237 | "Epoch 87/200\n", 238 | "6/6 [==============================] - 0s 8ms/step - loss: 6.3347e-07 - categorical_accuracy: 1.0000 - val_loss: 2.0916e-06 - val_categorical_accuracy: 1.0000\n", 239 | "Epoch 88/200\n", 240 | "6/6 [==============================] - 0s 9ms/step - loss: 6.2515e-07 - categorical_accuracy: 1.0000 - val_loss: 2.0590e-06 - val_categorical_accuracy: 1.0000\n", 241 | "Epoch 89/200\n", 242 | "6/6 [==============================] - 0s 9ms/step - loss: 6.1961e-07 - categorical_accuracy: 1.0000 - val_loss: 2.0374e-06 - val_categorical_accuracy: 1.0000\n", 243 | "Epoch 90/200\n", 244 | "6/6 [==============================] - 0s 9ms/step - loss: 6.1545e-07 - categorical_accuracy: 1.0000 - val_loss: 2.0157e-06 - val_categorical_accuracy: 1.0000\n", 245 | "Epoch 91/200\n", 246 | "6/6 [==============================] - 0s 7ms/step - loss: 6.0991e-07 - categorical_accuracy: 1.0000 - val_loss: 1.9940e-06 - val_categorical_accuracy: 1.0000\n", 247 | "Epoch 92/200\n", 248 | "6/6 [==============================] - 0s 8ms/step - loss: 6.0436e-07 - categorical_accuracy: 1.0000 - val_loss: 1.9724e-06 - val_categorical_accuracy: 1.0000\n", 249 | "Epoch 93/200\n", 250 | "6/6 [==============================] - 0s 8ms/step - loss: 6.0159e-07 - categorical_accuracy: 1.0000 - val_loss: 1.9507e-06 - val_categorical_accuracy: 1.0000\n", 251 | "Epoch 94/200\n", 252 | "6/6 [==============================] - 0s 7ms/step - loss: 5.9743e-07 - categorical_accuracy: 1.0000 - val_loss: 1.9290e-06 - val_categorical_accuracy: 1.0000\n", 253 | "Epoch 95/200\n", 254 | "6/6 [==============================] - 0s 8ms/step - loss: 5.9050e-07 - categorical_accuracy: 1.0000 - val_loss: 1.9073e-06 - val_categorical_accuracy: 1.0000\n", 255 | "Epoch 96/200\n" 256 | ] 257 | }, 258 | { 259 | "name": "stdout", 260 | "output_type": "stream", 261 | "text": [ 262 | "6/6 [==============================] - 0s 7ms/step - loss: 5.8911e-07 - categorical_accuracy: 1.0000 - val_loss: 1.8857e-06 - val_categorical_accuracy: 1.0000\n", 263 | "Epoch 97/200\n", 264 | "6/6 [==============================] - 0s 8ms/step - loss: 5.8357e-07 - categorical_accuracy: 1.0000 - val_loss: 1.8640e-06 - val_categorical_accuracy: 1.0000\n", 265 | "Epoch 98/200\n", 266 | "6/6 [==============================] - 0s 6ms/step - loss: 5.7664e-07 - categorical_accuracy: 1.0000 - val_loss: 1.8423e-06 - val_categorical_accuracy: 1.0000\n", 267 | "Epoch 99/200\n", 268 | "6/6 [==============================] - 0s 8ms/step - loss: 5.7248e-07 - categorical_accuracy: 1.0000 - val_loss: 1.8206e-06 - val_categorical_accuracy: 1.0000\n", 269 | "Epoch 100/200\n", 270 | "6/6 [==============================] - 0s 6ms/step - loss: 5.6694e-07 - categorical_accuracy: 1.0000 - val_loss: 1.8044e-06 - val_categorical_accuracy: 1.0000\n", 271 | "Epoch 101/200\n", 272 | "6/6 [==============================] - 0s 7ms/step - loss: 5.6416e-07 - categorical_accuracy: 1.0000 - val_loss: 1.7827e-06 - val_categorical_accuracy: 1.0000\n", 273 | "Epoch 102/200\n", 274 | "6/6 [==============================] - 0s 8ms/step - loss: 5.6139e-07 - categorical_accuracy: 1.0000 - val_loss: 1.7719e-06 - val_categorical_accuracy: 1.0000\n", 275 | "Epoch 103/200\n", 276 | "6/6 [==============================] - 0s 7ms/step - loss: 5.5446e-07 - categorical_accuracy: 1.0000 - val_loss: 1.7502e-06 - val_categorical_accuracy: 1.0000\n", 277 | "Epoch 104/200\n", 278 | "6/6 [==============================] - 0s 7ms/step - loss: 5.5307e-07 - categorical_accuracy: 1.0000 - val_loss: 1.7177e-06 - val_categorical_accuracy: 1.0000\n", 279 | "Epoch 105/200\n", 280 | "6/6 [==============================] - 0s 9ms/step - loss: 5.4892e-07 - categorical_accuracy: 1.0000 - val_loss: 1.7068e-06 - val_categorical_accuracy: 1.0000\n", 281 | "Epoch 106/200\n", 282 | "6/6 [==============================] - 0s 8ms/step - loss: 5.4614e-07 - categorical_accuracy: 1.0000 - val_loss: 1.6906e-06 - val_categorical_accuracy: 1.0000\n", 283 | "Epoch 107/200\n", 284 | "6/6 [==============================] - 0s 6ms/step - loss: 5.4337e-07 - categorical_accuracy: 1.0000 - val_loss: 1.6689e-06 - val_categorical_accuracy: 1.0000\n", 285 | "Epoch 108/200\n", 286 | "6/6 [==============================] - 0s 9ms/step - loss: 5.3505e-07 - categorical_accuracy: 1.0000 - val_loss: 1.6527e-06 - val_categorical_accuracy: 1.0000\n", 287 | "Epoch 109/200\n", 288 | "6/6 [==============================] - 0s 6ms/step - loss: 5.3505e-07 - categorical_accuracy: 1.0000 - val_loss: 1.6310e-06 - val_categorical_accuracy: 1.0000\n", 289 | "Epoch 110/200\n", 290 | "6/6 [==============================] - 0s 8ms/step - loss: 5.3090e-07 - categorical_accuracy: 1.0000 - val_loss: 1.6201e-06 - val_categorical_accuracy: 1.0000\n", 291 | "Epoch 111/200\n", 292 | "6/6 [==============================] - 0s 8ms/step - loss: 5.2396e-07 - categorical_accuracy: 1.0000 - val_loss: 1.6039e-06 - val_categorical_accuracy: 1.0000\n", 293 | "Epoch 112/200\n", 294 | "6/6 [==============================] - 0s 6ms/step - loss: 5.2119e-07 - categorical_accuracy: 1.0000 - val_loss: 1.5822e-06 - val_categorical_accuracy: 1.0000\n", 295 | "Epoch 113/200\n", 296 | "6/6 [==============================] - 0s 8ms/step - loss: 5.1703e-07 - categorical_accuracy: 1.0000 - val_loss: 1.5714e-06 - val_categorical_accuracy: 1.0000\n", 297 | "Epoch 114/200\n", 298 | "6/6 [==============================] - 0s 7ms/step - loss: 5.1288e-07 - categorical_accuracy: 1.0000 - val_loss: 1.5551e-06 - val_categorical_accuracy: 1.0000\n", 299 | "Epoch 115/200\n", 300 | "6/6 [==============================] - 0s 8ms/step - loss: 5.1010e-07 - categorical_accuracy: 1.0000 - val_loss: 1.5443e-06 - val_categorical_accuracy: 1.0000\n", 301 | "Epoch 116/200\n", 302 | "6/6 [==============================] - 0s 8ms/step - loss: 5.0594e-07 - categorical_accuracy: 1.0000 - val_loss: 1.5226e-06 - val_categorical_accuracy: 1.0000\n", 303 | "Epoch 117/200\n", 304 | "6/6 [==============================] - 0s 8ms/step - loss: 5.0594e-07 - categorical_accuracy: 1.0000 - val_loss: 1.5118e-06 - val_categorical_accuracy: 1.0000\n", 305 | "Epoch 118/200\n", 306 | "6/6 [==============================] - 0s 7ms/step - loss: 5.0040e-07 - categorical_accuracy: 1.0000 - val_loss: 1.5009e-06 - val_categorical_accuracy: 1.0000\n", 307 | "Epoch 119/200\n", 308 | "6/6 [==============================] - 0s 8ms/step - loss: 4.9901e-07 - categorical_accuracy: 1.0000 - val_loss: 1.4738e-06 - val_categorical_accuracy: 1.0000\n", 309 | "Epoch 120/200\n", 310 | "6/6 [==============================] - 0s 6ms/step - loss: 4.9486e-07 - categorical_accuracy: 1.0000 - val_loss: 1.4576e-06 - val_categorical_accuracy: 1.0000\n", 311 | "Epoch 121/200\n", 312 | "6/6 [==============================] - 0s 7ms/step - loss: 4.8931e-07 - categorical_accuracy: 1.0000 - val_loss: 1.4413e-06 - val_categorical_accuracy: 1.0000\n", 313 | "Epoch 122/200\n", 314 | "6/6 [==============================] - 0s 7ms/step - loss: 4.8654e-07 - categorical_accuracy: 1.0000 - val_loss: 1.4359e-06 - val_categorical_accuracy: 1.0000\n", 315 | "Epoch 123/200\n", 316 | "6/6 [==============================] - 0s 7ms/step - loss: 4.8515e-07 - categorical_accuracy: 1.0000 - val_loss: 1.4197e-06 - val_categorical_accuracy: 1.0000\n", 317 | "Epoch 124/200\n", 318 | "6/6 [==============================] - 0s 8ms/step - loss: 4.7961e-07 - categorical_accuracy: 1.0000 - val_loss: 1.4034e-06 - val_categorical_accuracy: 1.0000\n", 319 | "Epoch 125/200\n", 320 | "6/6 [==============================] - 0s 8ms/step - loss: 4.7545e-07 - categorical_accuracy: 1.0000 - val_loss: 1.3872e-06 - val_categorical_accuracy: 1.0000\n", 321 | "Epoch 126/200\n", 322 | "6/6 [==============================] - 0s 7ms/step - loss: 4.7406e-07 - categorical_accuracy: 1.0000 - val_loss: 1.3601e-06 - val_categorical_accuracy: 1.0000\n", 323 | "Epoch 127/200\n", 324 | "6/6 [==============================] - 0s 7ms/step - loss: 4.6852e-07 - categorical_accuracy: 1.0000 - val_loss: 1.3438e-06 - val_categorical_accuracy: 1.0000\n", 325 | "Epoch 128/200\n", 326 | "6/6 [==============================] - 0s 7ms/step - loss: 4.6575e-07 - categorical_accuracy: 1.0000 - val_loss: 1.3384e-06 - val_categorical_accuracy: 1.0000\n", 327 | "Epoch 129/200\n", 328 | "6/6 [==============================] - 0s 6ms/step - loss: 4.6297e-07 - categorical_accuracy: 1.0000 - val_loss: 1.3221e-06 - val_categorical_accuracy: 1.0000\n", 329 | "Epoch 130/200\n", 330 | "6/6 [==============================] - 0s 9ms/step - loss: 4.6020e-07 - categorical_accuracy: 1.0000 - val_loss: 1.3113e-06 - val_categorical_accuracy: 1.0000\n", 331 | "Epoch 131/200\n", 332 | "6/6 [==============================] - 0s 9ms/step - loss: 4.5743e-07 - categorical_accuracy: 1.0000 - val_loss: 1.2950e-06 - val_categorical_accuracy: 1.0000\n", 333 | "Epoch 132/200\n", 334 | "6/6 [==============================] - 0s 7ms/step - loss: 4.5327e-07 - categorical_accuracy: 1.0000 - val_loss: 1.2842e-06 - val_categorical_accuracy: 1.0000\n", 335 | "Epoch 133/200\n", 336 | "6/6 [==============================] - 0s 9ms/step - loss: 4.5050e-07 - categorical_accuracy: 1.0000 - val_loss: 1.2734e-06 - val_categorical_accuracy: 1.0000\n", 337 | "Epoch 134/200\n", 338 | "6/6 [==============================] - 0s 8ms/step - loss: 4.4773e-07 - categorical_accuracy: 1.0000 - val_loss: 1.2571e-06 - val_categorical_accuracy: 1.0000\n", 339 | "Epoch 135/200\n", 340 | "6/6 [==============================] - 0s 7ms/step - loss: 4.4357e-07 - categorical_accuracy: 1.0000 - val_loss: 1.2517e-06 - val_categorical_accuracy: 1.0000\n", 341 | "Epoch 136/200\n", 342 | "6/6 [==============================] - 0s 8ms/step - loss: 4.4080e-07 - categorical_accuracy: 1.0000 - val_loss: 1.2409e-06 - val_categorical_accuracy: 1.0000\n", 343 | "Epoch 137/200\n", 344 | "6/6 [==============================] - 0s 8ms/step - loss: 4.3941e-07 - categorical_accuracy: 1.0000 - val_loss: 1.2246e-06 - val_categorical_accuracy: 1.0000\n", 345 | "Epoch 138/200\n", 346 | "6/6 [==============================] - 0s 7ms/step - loss: 4.3664e-07 - categorical_accuracy: 1.0000 - val_loss: 1.2192e-06 - val_categorical_accuracy: 1.0000\n", 347 | "Epoch 139/200\n", 348 | "6/6 [==============================] - 0s 9ms/step - loss: 4.3525e-07 - categorical_accuracy: 1.0000 - val_loss: 1.2138e-06 - val_categorical_accuracy: 1.0000\n", 349 | "Epoch 140/200\n", 350 | "6/6 [==============================] - 0s 9ms/step - loss: 4.3387e-07 - categorical_accuracy: 1.0000 - val_loss: 1.1975e-06 - val_categorical_accuracy: 1.0000\n", 351 | "Epoch 141/200\n", 352 | "6/6 [==============================] - 0s 7ms/step - loss: 4.3109e-07 - categorical_accuracy: 1.0000 - val_loss: 1.1921e-06 - val_categorical_accuracy: 1.0000\n", 353 | "Epoch 142/200\n", 354 | "6/6 [==============================] - 0s 10ms/step - loss: 4.2693e-07 - categorical_accuracy: 1.0000 - val_loss: 1.1812e-06 - val_categorical_accuracy: 1.0000\n", 355 | "Epoch 143/200\n" 356 | ] 357 | }, 358 | { 359 | "name": "stdout", 360 | "output_type": "stream", 361 | "text": [ 362 | "6/6 [==============================] - 0s 8ms/step - loss: 4.2139e-07 - categorical_accuracy: 1.0000 - val_loss: 1.1542e-06 - val_categorical_accuracy: 1.0000\n", 363 | "Epoch 144/200\n", 364 | "6/6 [==============================] - 0s 7ms/step - loss: 4.1862e-07 - categorical_accuracy: 1.0000 - val_loss: 1.1487e-06 - val_categorical_accuracy: 1.0000\n", 365 | "Epoch 145/200\n", 366 | "6/6 [==============================] - 0s 8ms/step - loss: 4.1723e-07 - categorical_accuracy: 1.0000 - val_loss: 1.1433e-06 - val_categorical_accuracy: 1.0000\n", 367 | "Epoch 146/200\n", 368 | "6/6 [==============================] - 0s 8ms/step - loss: 4.1446e-07 - categorical_accuracy: 1.0000 - val_loss: 1.1271e-06 - val_categorical_accuracy: 1.0000\n", 369 | "Epoch 147/200\n", 370 | "6/6 [==============================] - 0s 9ms/step - loss: 4.1169e-07 - categorical_accuracy: 1.0000 - val_loss: 1.1216e-06 - val_categorical_accuracy: 1.0000\n", 371 | "Epoch 148/200\n", 372 | "6/6 [==============================] - 0s 7ms/step - loss: 4.0891e-07 - categorical_accuracy: 1.0000 - val_loss: 1.1108e-06 - val_categorical_accuracy: 1.0000\n", 373 | "Epoch 149/200\n", 374 | "6/6 [==============================] - 0s 7ms/step - loss: 4.0614e-07 - categorical_accuracy: 1.0000 - val_loss: 1.1000e-06 - val_categorical_accuracy: 1.0000\n", 375 | "Epoch 150/200\n", 376 | "6/6 [==============================] - 0s 8ms/step - loss: 4.0337e-07 - categorical_accuracy: 1.0000 - val_loss: 1.0946e-06 - val_categorical_accuracy: 1.0000\n", 377 | "Epoch 151/200\n", 378 | "6/6 [==============================] - 0s 8ms/step - loss: 4.0198e-07 - categorical_accuracy: 1.0000 - val_loss: 1.0837e-06 - val_categorical_accuracy: 1.0000\n", 379 | "Epoch 152/200\n", 380 | "6/6 [==============================] - 0s 7ms/step - loss: 3.9783e-07 - categorical_accuracy: 1.0000 - val_loss: 1.0783e-06 - val_categorical_accuracy: 1.0000\n", 381 | "Epoch 153/200\n", 382 | "6/6 [==============================] - 0s 11ms/step - loss: 3.9505e-07 - categorical_accuracy: 1.0000 - val_loss: 1.0675e-06 - val_categorical_accuracy: 1.0000\n", 383 | "Epoch 154/200\n", 384 | "6/6 [==============================] - 0s 7ms/step - loss: 3.9228e-07 - categorical_accuracy: 1.0000 - val_loss: 1.0566e-06 - val_categorical_accuracy: 1.0000\n", 385 | "Epoch 155/200\n", 386 | "6/6 [==============================] - 0s 8ms/step - loss: 3.9089e-07 - categorical_accuracy: 1.0000 - val_loss: 1.0458e-06 - val_categorical_accuracy: 1.0000\n", 387 | "Epoch 156/200\n", 388 | "6/6 [==============================] - 0s 9ms/step - loss: 3.8812e-07 - categorical_accuracy: 1.0000 - val_loss: 1.0404e-06 - val_categorical_accuracy: 1.0000\n", 389 | "Epoch 157/200\n", 390 | "6/6 [==============================] - 0s 8ms/step - loss: 3.8535e-07 - categorical_accuracy: 1.0000 - val_loss: 1.0404e-06 - val_categorical_accuracy: 1.0000\n", 391 | "Epoch 158/200\n", 392 | "6/6 [==============================] - 0s 8ms/step - loss: 3.8258e-07 - categorical_accuracy: 1.0000 - val_loss: 1.0349e-06 - val_categorical_accuracy: 1.0000\n", 393 | "Epoch 159/200\n", 394 | "6/6 [==============================] - 0s 9ms/step - loss: 3.8258e-07 - categorical_accuracy: 1.0000 - val_loss: 1.0241e-06 - val_categorical_accuracy: 1.0000\n", 395 | "Epoch 160/200\n", 396 | "6/6 [==============================] - 0s 8ms/step - loss: 3.8119e-07 - categorical_accuracy: 1.0000 - val_loss: 1.0187e-06 - val_categorical_accuracy: 1.0000\n", 397 | "Epoch 161/200\n", 398 | "6/6 [==============================] - 0s 7ms/step - loss: 3.7703e-07 - categorical_accuracy: 1.0000 - val_loss: 1.0133e-06 - val_categorical_accuracy: 1.0000\n", 399 | "Epoch 162/200\n", 400 | "6/6 [==============================] - 0s 8ms/step - loss: 3.7703e-07 - categorical_accuracy: 1.0000 - val_loss: 1.0079e-06 - val_categorical_accuracy: 1.0000\n", 401 | "Epoch 163/200\n", 402 | "6/6 [==============================] - 0s 6ms/step - loss: 3.7426e-07 - categorical_accuracy: 1.0000 - val_loss: 9.9702e-07 - val_categorical_accuracy: 1.0000\n", 403 | "Epoch 164/200\n", 404 | "6/6 [==============================] - 0s 7ms/step - loss: 3.7287e-07 - categorical_accuracy: 1.0000 - val_loss: 9.9702e-07 - val_categorical_accuracy: 1.0000\n", 405 | "Epoch 165/200\n", 406 | "6/6 [==============================] - 0s 8ms/step - loss: 3.7149e-07 - categorical_accuracy: 1.0000 - val_loss: 9.9160e-07 - val_categorical_accuracy: 1.0000\n", 407 | "Epoch 166/200\n", 408 | "6/6 [==============================] - 0s 7ms/step - loss: 3.6456e-07 - categorical_accuracy: 1.0000 - val_loss: 9.8618e-07 - val_categorical_accuracy: 1.0000\n", 409 | "Epoch 167/200\n", 410 | "6/6 [==============================] - 0s 8ms/step - loss: 3.6317e-07 - categorical_accuracy: 1.0000 - val_loss: 9.8076e-07 - val_categorical_accuracy: 1.0000\n", 411 | "Epoch 168/200\n", 412 | "6/6 [==============================] - 0s 7ms/step - loss: 3.6179e-07 - categorical_accuracy: 1.0000 - val_loss: 9.6993e-07 - val_categorical_accuracy: 1.0000\n", 413 | "Epoch 169/200\n", 414 | "6/6 [==============================] - 0s 9ms/step - loss: 3.5901e-07 - categorical_accuracy: 1.0000 - val_loss: 9.6993e-07 - val_categorical_accuracy: 1.0000\n", 415 | "Epoch 170/200\n", 416 | "6/6 [==============================] - 0s 8ms/step - loss: 3.5763e-07 - categorical_accuracy: 1.0000 - val_loss: 9.6451e-07 - val_categorical_accuracy: 1.0000\n", 417 | "Epoch 171/200\n", 418 | "6/6 [==============================] - 0s 8ms/step - loss: 3.5485e-07 - categorical_accuracy: 1.0000 - val_loss: 9.5909e-07 - val_categorical_accuracy: 1.0000\n", 419 | "Epoch 172/200\n", 420 | "6/6 [==============================] - 0s 7ms/step - loss: 3.5347e-07 - categorical_accuracy: 1.0000 - val_loss: 9.5909e-07 - val_categorical_accuracy: 1.0000\n", 421 | "Epoch 173/200\n", 422 | "6/6 [==============================] - 0s 7ms/step - loss: 3.5347e-07 - categorical_accuracy: 1.0000 - val_loss: 9.4825e-07 - val_categorical_accuracy: 1.0000\n", 423 | "Epoch 174/200\n", 424 | "6/6 [==============================] - 0s 7ms/step - loss: 3.5070e-07 - categorical_accuracy: 1.0000 - val_loss: 9.4283e-07 - val_categorical_accuracy: 1.0000\n", 425 | "Epoch 175/200\n", 426 | "6/6 [==============================] - 0s 9ms/step - loss: 3.5070e-07 - categorical_accuracy: 1.0000 - val_loss: 9.3741e-07 - val_categorical_accuracy: 1.0000\n", 427 | "Epoch 176/200\n", 428 | "6/6 [==============================] - 0s 7ms/step - loss: 3.4931e-07 - categorical_accuracy: 1.0000 - val_loss: 9.3741e-07 - val_categorical_accuracy: 1.0000\n", 429 | "Epoch 177/200\n", 430 | "6/6 [==============================] - 0s 11ms/step - loss: 3.4792e-07 - categorical_accuracy: 1.0000 - val_loss: 9.3200e-07 - val_categorical_accuracy: 1.0000\n", 431 | "Epoch 178/200\n", 432 | "6/6 [==============================] - 0s 8ms/step - loss: 3.4792e-07 - categorical_accuracy: 1.0000 - val_loss: 9.2116e-07 - val_categorical_accuracy: 1.0000\n", 433 | "Epoch 179/200\n", 434 | "6/6 [==============================] - 0s 7ms/step - loss: 3.4654e-07 - categorical_accuracy: 1.0000 - val_loss: 9.1574e-07 - val_categorical_accuracy: 1.0000\n", 435 | "Epoch 180/200\n", 436 | "6/6 [==============================] - 0s 7ms/step - loss: 3.4515e-07 - categorical_accuracy: 1.0000 - val_loss: 9.1574e-07 - val_categorical_accuracy: 1.0000\n", 437 | "Epoch 181/200\n", 438 | "6/6 [==============================] - 0s 8ms/step - loss: 3.4377e-07 - categorical_accuracy: 1.0000 - val_loss: 9.1032e-07 - val_categorical_accuracy: 1.0000\n", 439 | "Epoch 182/200\n", 440 | "6/6 [==============================] - 0s 8ms/step - loss: 3.4377e-07 - categorical_accuracy: 1.0000 - val_loss: 9.0490e-07 - val_categorical_accuracy: 1.0000\n", 441 | "Epoch 183/200\n", 442 | "6/6 [==============================] - 0s 7ms/step - loss: 3.3961e-07 - categorical_accuracy: 1.0000 - val_loss: 9.0490e-07 - val_categorical_accuracy: 1.0000\n", 443 | "Epoch 184/200\n", 444 | "6/6 [==============================] - 0s 8ms/step - loss: 3.3683e-07 - categorical_accuracy: 1.0000 - val_loss: 8.9407e-07 - val_categorical_accuracy: 1.0000\n", 445 | "Epoch 185/200\n", 446 | "6/6 [==============================] - 0s 7ms/step - loss: 3.3545e-07 - categorical_accuracy: 1.0000 - val_loss: 8.8323e-07 - val_categorical_accuracy: 1.0000\n", 447 | "Epoch 186/200\n", 448 | "6/6 [==============================] - 0s 7ms/step - loss: 3.3545e-07 - categorical_accuracy: 1.0000 - val_loss: 8.8323e-07 - val_categorical_accuracy: 1.0000\n", 449 | "Epoch 187/200\n", 450 | "6/6 [==============================] - 0s 8ms/step - loss: 3.3268e-07 - categorical_accuracy: 1.0000 - val_loss: 8.7781e-07 - val_categorical_accuracy: 1.0000\n", 451 | "Epoch 188/200\n", 452 | "6/6 [==============================] - 0s 7ms/step - loss: 3.2990e-07 - categorical_accuracy: 1.0000 - val_loss: 8.7239e-07 - val_categorical_accuracy: 1.0000\n", 453 | "Epoch 189/200\n", 454 | "6/6 [==============================] - 0s 7ms/step - loss: 3.2852e-07 - categorical_accuracy: 1.0000 - val_loss: 8.6155e-07 - val_categorical_accuracy: 1.0000\n", 455 | "Epoch 190/200\n" 456 | ] 457 | }, 458 | { 459 | "name": "stdout", 460 | "output_type": "stream", 461 | "text": [ 462 | "6/6 [==============================] - 0s 8ms/step - loss: 3.2713e-07 - categorical_accuracy: 1.0000 - val_loss: 8.5072e-07 - val_categorical_accuracy: 1.0000\n", 463 | "Epoch 191/200\n", 464 | "6/6 [==============================] - 0s 7ms/step - loss: 3.2713e-07 - categorical_accuracy: 1.0000 - val_loss: 8.4530e-07 - val_categorical_accuracy: 1.0000\n", 465 | "Epoch 192/200\n", 466 | "6/6 [==============================] - 0s 7ms/step - loss: 3.2713e-07 - categorical_accuracy: 1.0000 - val_loss: 8.3988e-07 - val_categorical_accuracy: 1.0000\n", 467 | "Epoch 193/200\n", 468 | "6/6 [==============================] - 0s 8ms/step - loss: 3.2575e-07 - categorical_accuracy: 1.0000 - val_loss: 8.3988e-07 - val_categorical_accuracy: 1.0000\n", 469 | "Epoch 194/200\n", 470 | "6/6 [==============================] - 0s 7ms/step - loss: 3.2159e-07 - categorical_accuracy: 1.0000 - val_loss: 8.3446e-07 - val_categorical_accuracy: 1.0000\n", 471 | "Epoch 195/200\n", 472 | "6/6 [==============================] - 0s 7ms/step - loss: 3.2159e-07 - categorical_accuracy: 1.0000 - val_loss: 8.2904e-07 - val_categorical_accuracy: 1.0000\n", 473 | "Epoch 196/200\n", 474 | "6/6 [==============================] - 0s 8ms/step - loss: 3.2020e-07 - categorical_accuracy: 1.0000 - val_loss: 8.2362e-07 - val_categorical_accuracy: 1.0000\n", 475 | "Epoch 197/200\n", 476 | "6/6 [==============================] - 0s 7ms/step - loss: 3.2020e-07 - categorical_accuracy: 1.0000 - val_loss: 8.1279e-07 - val_categorical_accuracy: 1.0000\n", 477 | "Epoch 198/200\n", 478 | "6/6 [==============================] - 0s 8ms/step - loss: 3.2020e-07 - categorical_accuracy: 1.0000 - val_loss: 8.1279e-07 - val_categorical_accuracy: 1.0000\n", 479 | "Epoch 199/200\n", 480 | "6/6 [==============================] - 0s 8ms/step - loss: 3.1604e-07 - categorical_accuracy: 1.0000 - val_loss: 8.0737e-07 - val_categorical_accuracy: 1.0000\n", 481 | "Epoch 200/200\n", 482 | "6/6 [==============================] - 0s 10ms/step - loss: 3.1327e-07 - categorical_accuracy: 1.0000 - val_loss: 8.0737e-07 - val_categorical_accuracy: 1.0000\n" 483 | ] 484 | } 485 | ], 486 | "source": [ 487 | "x, y = ReadTrainingData()\n", 488 | "TrainModel(Model, x, y)" 489 | ] 490 | }, 491 | { 492 | "cell_type": "code", 493 | "execution_count": null, 494 | "id": "068ca7bd", 495 | "metadata": { 496 | "scrolled": true 497 | }, 498 | "outputs": [], 499 | "source": [ 500 | "ConvertModel(Model)" 501 | ] 502 | }, 503 | { 504 | "cell_type": "code", 505 | "execution_count": null, 506 | "id": "dffe07f9", 507 | "metadata": {}, 508 | "outputs": [], 509 | "source": [ 510 | "Hex2H(Model, \"model\")" 511 | ] 512 | } 513 | ], 514 | "metadata": { 515 | "interpreter": { 516 | "hash": "065a7fd65857af9b0d7d7760ab62099efda22ea2fccd7cdd83105fb1a789eaf5" 517 | }, 518 | "kernelspec": { 519 | "display_name": "Python 3", 520 | "language": "python", 521 | "name": "python3" 522 | }, 523 | "language_info": { 524 | "codemirror_mode": { 525 | "name": "ipython", 526 | "version": 3 527 | }, 528 | "file_extension": ".py", 529 | "mimetype": "text/x-python", 530 | "name": "python", 531 | "nbconvert_exporter": "python", 532 | "pygments_lexer": "ipython3", 533 | "version": "3.8.10" 534 | } 535 | }, 536 | "nbformat": 4, 537 | "nbformat_minor": 5 538 | } 539 | -------------------------------------------------------------------------------- /Host/tinyml.py: -------------------------------------------------------------------------------- 1 | import numbers 2 | import os 3 | os.environ["CUDA_VISIBLE_DEVICES"] = "-1" 4 | 5 | import math 6 | import numpy as np 7 | import tensorflow as tf 8 | 9 | from tensorflow import keras 10 | layers = keras.layers 11 | 12 | SAMPLES_PER_GESTURE = 120 13 | 14 | Model = None 15 | 16 | def CreateModel(): 17 | # create a NN with 2 layers of 16 neurons 18 | model = tf.keras.Sequential() 19 | model.add(layers.Dense(32, activation='relu', input_shape=(6 * SAMPLES_PER_GESTURE,))) 20 | model.add(layers.Dense(16, activation='relu')) 21 | model.add(layers.Dense(2, activation='softmax')) 22 | 23 | opt_adam = keras.optimizers.Adam() 24 | model.compile(optimizer=opt_adam, loss='categorical_crossentropy', metrics=['categorical_accuracy']) 25 | model.summary() 26 | 27 | return model 28 | 29 | 30 | def PrepareModel(model): 31 | SAMPLES = 100 32 | np.random.seed(1337) 33 | 34 | x_values = np.random.uniform(low=0, high=2 * math.pi, size=(SAMPLES, 6 * SAMPLES_PER_GESTURE)) 35 | # shuffle and add noise 36 | np.random.shuffle(x_values) 37 | y_values = np.random.uniform(low=0, high=1, size=(SAMPLES, 2)) 38 | #y_values = np.random.randn(*y_values.shape) 39 | 40 | return x_values, y_values 41 | 42 | 43 | def TrainModel(model, x, y): 44 | SampleCount = len(x) 45 | 46 | # split into train, validation, test 47 | TRAIN_SPLIT = int(0.8 * SampleCount) 48 | x_train, x_validate = np.split(x, [TRAIN_SPLIT, ]) 49 | y_train, y_validate = np.split(y, [TRAIN_SPLIT, ]) 50 | 51 | model.fit(x_train, y_train, epochs=200, batch_size=16, validation_data=(x_validate, y_validate)) 52 | 53 | 54 | def ConvertModel(model): 55 | converter = tf.lite.TFLiteConverter.from_keras_model(model) 56 | tflite_model = converter.convert() 57 | 58 | return tflite_model 59 | 60 | def SaveModel(model): 61 | with open("model.tflite", "wb") as f: 62 | f.write(model) 63 | 64 | 65 | # Function: Convert some hex value into an array for C programming 66 | def Hex2H(model, h_model_name): 67 | c_str = '' 68 | model_len = len(model) 69 | 70 | # Create header guard 71 | c_str += '#ifndef ' + h_model_name.upper() + '_H\n' 72 | c_str += '#define ' + h_model_name.upper() + '_H\n' 73 | 74 | # Add array length at top of file 75 | c_str += '\nconst unsigned int ' + h_model_name + '_len = ' + str(model_len) + ';\n' 76 | 77 | # Declare C variable 78 | c_str += 'const unsigned char ' + h_model_name + '[] = {' 79 | hex_array = [] 80 | for i, val in enumerate(model) : 81 | # Construct string from hex 82 | hex_str = format(val, '#04x') 83 | 84 | # Add formatting so each line stays within 80 characters 85 | if (i + 1) < model_len: 86 | hex_str += ',' 87 | if (i + 1) % 12 == 0: 88 | hex_str += '\n ' 89 | hex_array.append(hex_str) 90 | 91 | # Add closing brace 92 | c_str += '\n ' + format(' '.join(hex_array)) + '\n};\n\n' 93 | 94 | # Close out header guard 95 | c_str += '#endif //' + h_model_name.upper() + '_H\n' 96 | 97 | # Write TFLite model to a C source (or header) file 98 | base_path = os.path.dirname(__file__) 99 | with open(base_path + "/" + h_model_name + '.h', 'w') as file: 100 | file.write(c_str) 101 | file.flush() 102 | 103 | 104 | def ReadDataFile(file, v): 105 | size = SAMPLES_PER_GESTURE * 6 106 | 107 | dataX = np.empty([0, size]) 108 | # dataY = np.empty([0,]) 109 | dataY = np.empty([0, 2]) 110 | 111 | base_path = os.path.dirname(__file__) 112 | file = open(base_path + "/data/" + file, "r") 113 | 114 | data = [] 115 | for line in file.readlines(): 116 | items = line.split() 117 | values = [int(v) / 32768 for v in items ] 118 | data += values 119 | 120 | count = len(data) 121 | 122 | for i in range(0, count, size): 123 | tmp = np.array(data[i: i + size]) 124 | if len(tmp) == size: 125 | tmp = np.expand_dims(tmp, axis=0) 126 | 127 | dataX = np.concatenate((dataX, tmp), axis=0) 128 | # dataY = np.append(dataY, v) 129 | dataY = np.concatenate((dataY, [[1, 0]] if v == 0 else [[0, 1]])) 130 | 131 | return dataX, dataY 132 | 133 | 134 | def ReadTrainingData(): 135 | circle_x, circle_y = ReadDataFile("circle.csv", 1) 136 | cross_x, cross_y = ReadDataFile("cross.csv", 0) 137 | 138 | dataX = np.concatenate((circle_x, cross_x), axis=0) 139 | dataY = np.concatenate((circle_y, cross_y), axis=0) 140 | 141 | return dataX, dataY 142 | 143 | if __name__ == '__main__': 144 | Model = CreateModel() 145 | #PrepareModel(Model) 146 | 147 | x, y = ReadTrainingData() 148 | TrainModel(Model, x, y) 149 | 150 | print("==== Convert Model") 151 | tfModel = ConvertModel(Model) 152 | 153 | print("==== Make Header File") 154 | Hex2H(tfModel, "model") 155 | 156 | print("==== Model Build Finished") -------------------------------------------------------------------------------- /Images/arduino1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mushroomcloud-cc/tinyml-workshop/f8e89a41f96933f9f7bf7e0168035ddc6dd6e70f/Images/arduino1.png -------------------------------------------------------------------------------- /Images/arduino2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mushroomcloud-cc/tinyml-workshop/f8e89a41f96933f9f7bf7e0168035ddc6dd6e70f/Images/arduino2.png -------------------------------------------------------------------------------- /Images/arduino_lib.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mushroomcloud-cc/tinyml-workshop/f8e89a41f96933f9f7bf7e0168035ddc6dd6e70f/Images/arduino_lib.png -------------------------------------------------------------------------------- /Images/beetle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mushroomcloud-cc/tinyml-workshop/f8e89a41f96933f9f7bf7e0168035ddc6dd6e70f/Images/beetle.jpg -------------------------------------------------------------------------------- /Images/inference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mushroomcloud-cc/tinyml-workshop/f8e89a41f96933f9f7bf7e0168035ddc6dd6e70f/Images/inference.png -------------------------------------------------------------------------------- /Images/mu9250.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mushroomcloud-cc/tinyml-workshop/f8e89a41f96933f9f7bf7e0168035ddc6dd6e70f/Images/mu9250.jpg -------------------------------------------------------------------------------- /Images/network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mushroomcloud-cc/tinyml-workshop/f8e89a41f96933f9f7bf7e0168035ddc6dd6e70f/Images/network.png -------------------------------------------------------------------------------- /Images/process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mushroomcloud-cc/tinyml-workshop/f8e89a41f96933f9f7bf7e0168035ddc6dd6e70f/Images/process.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TinyML for Predict Gesture on ESP32-C3 2 | 3 | ## 概述 4 | 5 | 基于6轴传感器数据采样(加速度计和陀螺仪),识别两种手势动作 6 | 7 | ## 硬件 8 | 9 | ![image](Images/beetle.jpg) 10 | ![image](Images/mu9250.jpg) 11 | 12 | ## 框架 13 | 14 | - Tensorflow 15 | - Keras 16 | - Tensorflow Lite Micro 17 | 18 | ## 环境 19 | 20 | ### Python 21 | 22 | - Python 3.8 23 | - Tensorflow 2.9.2 24 | - numpy 1.22.4 25 | - PyOpenGL 3.1.6 26 | 27 | [whl下载链接](https://www.lfd.uci.edu/~gohlke/pythonlibs/) 28 | 29 | ### Arduino 30 | 31 | - ESP32 Arduino 2.0.3 32 | ![image](Images/arduino1.png) 33 | ![image](Images/arduino2.png) 34 | 35 | - TensorFlowLite_ESP32 0.9.0 36 | ![image](Images/arduino_lib.png) 37 | 38 | ## 设计 39 | 40 | ### 数据 41 | 42 | - 1.2s 数据长度, 43 | - 100采样/s 44 | 45 | ### 模型 46 | 47 | ![image](Images/network.png) 48 | 49 | - 线性全连接网络 50 | - 720-向量输入 51 | - 2-向量输出 52 | 53 | ## 流程 54 | 55 | ![image](Images/process.png) 56 | 57 | 数据采集 58 | 59 | - UDP数据传输 60 | 61 | 预处理 62 | 63 | - 滑动平均 64 | 65 | 训练 66 | 67 | 优化、转换 68 | 69 | 推理应用 70 | ![image](Images/inference.png) 71 | 72 | ## 代码 73 | 74 | - Host 75 | 76 | 1. 数据采集 SensorProcess.py 77 | 1. 模型创建与训练 tinyml.py 78 | 79 | - prediect_gesture 80 | 81 | ## 网站 82 | 83 | - [TensorFlow Lite for Microcontrollers](https://tensorflow.google.cn/lite/microcontrollers/overview) 84 | - [Keras Docs](https://keras.io/api/) 85 | - [Edge Impulse](https://www.edgeimpulse.com/) 86 | -------------------------------------------------------------------------------- /model.tflite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mushroomcloud-cc/tinyml-workshop/f8e89a41f96933f9f7bf7e0168035ddc6dd6e70f/model.tflite -------------------------------------------------------------------------------- /predict_gesture/HRTimer.cpp: -------------------------------------------------------------------------------- 1 | #include "HRTimer.h" 2 | 3 | #include 4 | 5 | HRTimer::HRTimer() 6 | { 7 | this->LastTime = 0; 8 | } 9 | 10 | void HRTimer::Start() 11 | { 12 | this->LastTime = micros(); 13 | } 14 | 15 | 16 | unsigned long HRTimer::End() 17 | { 18 | unsigned long ret; 19 | unsigned long t = micros(); 20 | 21 | ret = t - this->LastTime; 22 | if(t < this->LastTime) 23 | { 24 | ret = (unsigned long)-1 - ret + 1; 25 | } 26 | 27 | return ret; 28 | } 29 | -------------------------------------------------------------------------------- /predict_gesture/HRTimer.h: -------------------------------------------------------------------------------- 1 | #ifndef _HRTIMER_H_ 2 | #define _HRTIMER_H_ 3 | 4 | #include "MPU9250_Reg.h" 5 | 6 | class HRTimer { 7 | public: 8 | HRTimer(); 9 | void Start(); 10 | unsigned long End(); 11 | 12 | private: 13 | unsigned long LastTime; 14 | }; 15 | 16 | #endif // _HRTIMER_H_ 17 | -------------------------------------------------------------------------------- /predict_gesture/LED.cpp: -------------------------------------------------------------------------------- 1 | #include "LED.h" 2 | 3 | #include 4 | 5 | LED::LED() 6 | { 7 | pinMode(LED_PIN, OUTPUT); 8 | pinMode(BLUE_PIN, OUTPUT); 9 | pinMode(RED_PIN, OUTPUT); 10 | 11 | this->Off(); 12 | this->Blank(); 13 | } 14 | 15 | void LED::On() 16 | { 17 | digitalWrite(LED_PIN, HIGH); 18 | this->State = true; 19 | } 20 | 21 | void LED::Off() 22 | { 23 | digitalWrite(LED_PIN, LOW); 24 | this->State = true; 25 | } 26 | 27 | void LED::Toggle() 28 | { 29 | this->State ? this->Off() : this->On(); 30 | } 31 | 32 | void LED::Blue() 33 | { 34 | digitalWrite(RED_PIN, HIGH); 35 | digitalWrite(BLUE_PIN, LOW); 36 | } 37 | 38 | void LED::Red() 39 | { 40 | digitalWrite(BLUE_PIN, HIGH); 41 | digitalWrite(RED_PIN, LOW); 42 | } 43 | 44 | void LED::Blank() 45 | { 46 | digitalWrite(BLUE_PIN, HIGH); 47 | digitalWrite(RED_PIN, HIGH); 48 | } 49 | 50 | LED Led; 51 | -------------------------------------------------------------------------------- /predict_gesture/LED.h: -------------------------------------------------------------------------------- 1 | #ifndef _LED_H_ 2 | #define _LED_H_ 3 | 4 | const int LED_PIN = 10; 5 | const int BLUE_PIN = 6; 6 | const int RED_PIN = 7; 7 | 8 | class LED { 9 | public: 10 | LED(); 11 | 12 | void On(); 13 | void Off(); 14 | void Toggle(); 15 | 16 | void Blue(); 17 | void Red(); 18 | void Blank(); 19 | private: 20 | bool State; 21 | }; 22 | 23 | extern LED Led; 24 | 25 | #endif // _LED_H_ 26 | -------------------------------------------------------------------------------- /predict_gesture/MPU9250.cpp: -------------------------------------------------------------------------------- 1 | #include "MPU9250.h" 2 | 3 | #include 4 | #include 5 | 6 | #define GET_RINT(p, i) (short)(((unsigned short)p[i]) << 8 | p[i + 1]); 7 | #define GET_INT(p, i) (short)(((unsigned short)p[i + 1]) << 8 | p[i]); 8 | 9 | MPU9250::MPU9250(int scl, int sda) 10 | { 11 | if(scl >= 0 && sda >= 0) 12 | { 13 | if(!Wire.setPins(sda, scl)) Serial.println("Wire Set Pin Faild!"); 14 | } 15 | 16 | if(!Wire.begin()) Serial.println("Wire Begin Faild!"); 17 | } 18 | 19 | void MPU9250::Read(short* data) 20 | { 21 | unsigned char buff[25]; 22 | 23 | // Read accelerometer and gyroscope 24 | I2Cread(MPU9250_ADDRESS, ACCEL_XOUT_H, 14, buff); 25 | 26 | unsigned char ST1; 27 | // Read register Status 1 and wait for the DRDY: Data Ready 28 | // I2Cread(AK8963_ADDRESS, AK8963_ST1, 1, &ST1); 29 | // if (ST1 & 0x01) 30 | { 31 | // Read magnetometer data 32 | // I2Cread(AK8963_ADDRESS, AK8963_XOUT_L, 6, buff + 14); 33 | } 34 | 35 | // ax, ay, az 36 | data[0] = GET_RINT(buff, 0); 37 | data[1] = GET_RINT(buff, 2); 38 | data[2] = GET_RINT(buff, 4); 39 | 40 | // Gyroscope 41 | data[3] = GET_RINT(buff, 8); 42 | data[4] = GET_RINT(buff, 10); 43 | data[5] = GET_RINT(buff, 12); 44 | 45 | // mx, my, mz 46 | data[6] = GET_INT(buff, 14); 47 | data[7] = GET_INT(buff, 16);; 48 | data[8] = GET_INT(buff, 18); 49 | } 50 | 51 | void MPU9250::Init() 52 | { 53 | I2CwriteByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x80); // Reset mpu9250 54 | I2CwriteByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x01); // Set clock of mpu9250 55 | 56 | I2CwriteByte(MPU9250_ADDRESS, CONFIG, LPF_BANDWIDTH_FULL); // Set accelerometers low pass filter at 5Hz 57 | I2CwriteByte(MPU9250_ADDRESS, ACCEL_CONFIG2, LPF_BANDWIDTH_FULL); // Set gyroscope low pass filter at 5Hz 58 | I2CwriteByte(MPU9250_ADDRESS, GYRO_CONFIG, GYRO_FULL_SCALE_250_DPS); // Configure gyroscope range 59 | I2CwriteByte(MPU9250_ADDRESS, ACCEL_CONFIG, ACC_FULL_SCALE_2_G); // Configure accelerometers range 60 | I2CwriteByte(MPU9250_ADDRESS, INT_PIN_CFG, 0x02); // Set by pass mode for the magnetometers 61 | 62 | I2CwriteByte(AK8963_ADDRESS, AK8963_ASTC, 0x01); // Reset magnetometer 63 | I2CwriteByte(AK8963_ADDRESS, AK8963_CNTL, 0x00); // Set magnetometer power down 64 | delay(1); 65 | I2CwriteByte(AK8963_ADDRESS, AK8963_CNTL, 0x16); // Request continuous magnetometer measurements in 16 bits 66 | 67 | unsigned char ID_MPU9250; 68 | unsigned char ID_AK8963; 69 | char buf[50]; 70 | I2Cread(MPU9250_ADDRESS, WHO_AM_I_MPU9250, 1, &ID_MPU9250); 71 | I2Cread(MPU9250_ADDRESS, WHO_AM_I_AK8963, 1, &ID_AK8963); 72 | sprintf(buf, "IMU ID: %02x, Mag ID: %02x", ID_MPU9250, ID_AK8963); 73 | Serial.println(buf); 74 | } 75 | 76 | // This function read Nbytes bytes from I2C device at address Address. 77 | // Put read bytes starting at register Register in the Data array. 78 | void MPU9250::I2Cread(int Address, int Register, int Nbytes, unsigned char* Data) 79 | { 80 | // Set register address 81 | Wire.beginTransmission(Address); 82 | Wire.write(Register); 83 | Wire.endTransmission(); 84 | 85 | // Read Nbytes 86 | Wire.requestFrom(Address, Nbytes); 87 | uint8_t index = 0; 88 | while (Wire.available()) 89 | { 90 | Data[index++] = Wire.read(); 91 | } 92 | } 93 | 94 | // Write a byte (Data) in device (Address) at register (Register) 95 | void MPU9250::I2CwriteByte(int Address, int Register, unsigned char Data) 96 | { 97 | // Set register address 98 | Wire.beginTransmission(Address); 99 | Wire.write(Register); 100 | Wire.write(Data); 101 | Wire.endTransmission(); 102 | } 103 | -------------------------------------------------------------------------------- /predict_gesture/MPU9250.h: -------------------------------------------------------------------------------- 1 | /* 2 | Note: The MPU9250 is an I2C sensor and uses the Arduino Wire library. 3 | Because the sensor is not 5V tolerant, we are using a 3.3 V 8 MHz Pro Mini or 4 | a 3.3 V Teensy 3.1. We have disabled the internal pull-ups used by the Wire 5 | library in the Wire.h/twi.c utility file. We are also using the 400 kHz fast 6 | I2C mode by setting the TWI_FREQ to 400000L /twi.h utility file. 7 | */ 8 | #ifndef _MPU9250_H_ 9 | #define _MPU9250_H_ 10 | 11 | #include "MPU9250_Reg.h" 12 | 13 | class MPU9250 { 14 | public: 15 | MPU9250(int scl, int sda); 16 | void Init(); 17 | void Read(short* buff); 18 | 19 | private: 20 | // This function read Nbytes bytes from I2C device at address Address. 21 | // Put read bytes starting at register Register in the Data array. 22 | void I2Cread(int Address, int Register, int Nbytes, unsigned char* Data); 23 | // Write a byte (Data) in device (Address) at register (Register) 24 | void I2CwriteByte(int Address, int Register, unsigned char Data); 25 | }; 26 | 27 | #endif // _MPU9250_H_ 28 | -------------------------------------------------------------------------------- /predict_gesture/MPU9250_Reg.h: -------------------------------------------------------------------------------- 1 | #ifndef _MPU9250_REG_H_ 2 | #define _MPU9250_REG_H_ 3 | 4 | // See also MPU-9250 Register Map and Descriptions, Revision 4.0, 5 | // RM-MPU-9250A-00, Rev. 1.4, 9/9/2013 for registers not listed in above 6 | // document; the MPU9250 and MPU9150 are virtually identical but the latter has 7 | // a different register map 8 | 9 | #define SELF_TEST_X_GYRO 0x00 10 | #define SELF_TEST_Y_GYRO 0x01 11 | #define SELF_TEST_Z_GYRO 0x02 12 | 13 | /* 14 | #define X_FINE_GAIN 0x03 // [7:0] fine gain 15 | #define Y_FINE_GAIN 0x04 16 | #define Z_FINE_GAIN 0x05 17 | #define XA_OFFSET_H 0x06 // User-defined trim values for accelerometer 18 | #define XA_OFFSET_L_TC 0x07 19 | #define YA_OFFSET_H 0x08 20 | #define YA_OFFSET_L_TC 0x09 21 | #define ZA_OFFSET_H 0x0A 22 | #define ZA_OFFSET_L_TC 0x0B 23 | */ 24 | 25 | #define SELF_TEST_X_ACCEL 0x0D 26 | #define SELF_TEST_Y_ACCEL 0x0E 27 | #define SELF_TEST_Z_ACCEL 0x0F 28 | 29 | #define SELF_TEST_A 0x10 30 | 31 | #define XG_OFFSET_H 0x13 // User-defined trim values for gyroscope 32 | #define XG_OFFSET_L 0x14 33 | #define YG_OFFSET_H 0x15 34 | #define YG_OFFSET_L 0x16 35 | #define ZG_OFFSET_H 0x17 36 | #define ZG_OFFSET_L 0x18 37 | #define SMPLRT_DIV 0x19 38 | #define CONFIG 0x1A 39 | #define GYRO_CONFIG 0x1B 40 | #define ACCEL_CONFIG 0x1C 41 | #define ACCEL_CONFIG2 0x1D 42 | #define LP_ACCEL_ODR 0x1E 43 | #define WOM_THR 0x1F 44 | 45 | // Duration counter threshold for motion interrupt generation, 1 kHz rate, 46 | // LSB = 1 ms 47 | #define MOT_DUR 0x20 48 | // Zero-motion detection threshold bits [7:0] 49 | #define ZMOT_THR 0x21 50 | // Duration counter threshold for zero motion interrupt generation, 16 Hz rate, 51 | // LSB = 64 ms 52 | #define ZRMOT_DUR 0x22 53 | 54 | #define FIFO_EN 0x23 55 | #define I2C_MST_CTRL 0x24 56 | #define I2C_SLV0_ADDR 0x25 57 | #define I2C_SLV0_REG 0x26 58 | #define I2C_SLV0_CTRL 0x27 59 | #define I2C_SLV1_ADDR 0x28 60 | #define I2C_SLV1_REG 0x29 61 | #define I2C_SLV1_CTRL 0x2A 62 | #define I2C_SLV2_ADDR 0x2B 63 | #define I2C_SLV2_REG 0x2C 64 | #define I2C_SLV2_CTRL 0x2D 65 | #define I2C_SLV3_ADDR 0x2E 66 | #define I2C_SLV3_REG 0x2F 67 | #define I2C_SLV3_CTRL 0x30 68 | #define I2C_SLV4_ADDR 0x31 69 | #define I2C_SLV4_REG 0x32 70 | #define I2C_SLV4_DO 0x33 71 | #define I2C_SLV4_CTRL 0x34 72 | #define I2C_SLV4_DI 0x35 73 | #define I2C_MST_STATUS 0x36 74 | #define INT_PIN_CFG 0x37 75 | #define INT_ENABLE 0x38 76 | #define DMP_INT_STATUS 0x39 // Check DMP interrupt 77 | #define INT_STATUS 0x3A 78 | #define ACCEL_XOUT_H 0x3B 79 | #define ACCEL_XOUT_L 0x3C 80 | #define ACCEL_YOUT_H 0x3D 81 | #define ACCEL_YOUT_L 0x3E 82 | #define ACCEL_ZOUT_H 0x3F 83 | #define ACCEL_ZOUT_L 0x40 84 | #define TEMP_OUT_H 0x41 85 | #define TEMP_OUT_L 0x42 86 | #define GYRO_XOUT_H 0x43 87 | #define GYRO_XOUT_L 0x44 88 | #define GYRO_YOUT_H 0x45 89 | #define GYRO_YOUT_L 0x46 90 | #define GYRO_ZOUT_H 0x47 91 | #define GYRO_ZOUT_L 0x48 92 | #define EXT_SENS_DATA_00 0x49 93 | #define EXT_SENS_DATA_01 0x4A 94 | #define EXT_SENS_DATA_02 0x4B 95 | #define EXT_SENS_DATA_03 0x4C 96 | #define EXT_SENS_DATA_04 0x4D 97 | #define EXT_SENS_DATA_05 0x4E 98 | #define EXT_SENS_DATA_06 0x4F 99 | #define EXT_SENS_DATA_07 0x50 100 | #define EXT_SENS_DATA_08 0x51 101 | #define EXT_SENS_DATA_09 0x52 102 | #define EXT_SENS_DATA_10 0x53 103 | #define EXT_SENS_DATA_11 0x54 104 | #define EXT_SENS_DATA_12 0x55 105 | #define EXT_SENS_DATA_13 0x56 106 | #define EXT_SENS_DATA_14 0x57 107 | #define EXT_SENS_DATA_15 0x58 108 | #define EXT_SENS_DATA_16 0x59 109 | #define EXT_SENS_DATA_17 0x5A 110 | #define EXT_SENS_DATA_18 0x5B 111 | #define EXT_SENS_DATA_19 0x5C 112 | #define EXT_SENS_DATA_20 0x5D 113 | #define EXT_SENS_DATA_21 0x5E 114 | #define EXT_SENS_DATA_22 0x5F 115 | #define EXT_SENS_DATA_23 0x60 116 | #define MOT_DETECT_STATUS 0x61 117 | #define I2C_SLV0_DO 0x63 118 | #define I2C_SLV1_DO 0x64 119 | #define I2C_SLV2_DO 0x65 120 | #define I2C_SLV3_DO 0x66 121 | #define I2C_MST_DELAY_CTRL 0x67 122 | #define SIGNAL_PATH_RESET 0x68 123 | #define MOT_DETECT_CTRL 0x69 124 | #define USER_CTRL 0x6A // Bit 7 enable DMP, bit 3 reset DMP 125 | #define PWR_MGMT_1 0x6B // Device defaults to the SLEEP mode 126 | #define PWR_MGMT_2 0x6C 127 | #define DMP_BANK 0x6D // Activates a specific bank in the DMP 128 | #define DMP_RW_PNT 0x6E // Set read/write pointer to a specific start address in specified DMP bank 129 | #define DMP_REG 0x6F // Register in DMP from which to read or to which to write 130 | #define DMP_REG_1 0x70 131 | #define DMP_REG_2 0x71 132 | #define FIFO_COUNTH 0x72 133 | #define FIFO_COUNTL 0x73 134 | #define FIFO_R_W 0x74 135 | #define WHO_AM_I_MPU9250 0x75 // Should return 0x71 136 | #define XA_OFFSET_H 0x77 137 | #define XA_OFFSET_L 0x78 138 | #define YA_OFFSET_H 0x7A 139 | #define YA_OFFSET_L 0x7B 140 | #define ZA_OFFSET_H 0x7D 141 | #define ZA_OFFSET_L 0x7E 142 | 143 | 144 | //Magnetometer Registers 145 | 146 | #define WHO_AM_I_AK8963 0x00 // should return 0x48 147 | #define INFO 0x01 148 | #define AK8963_ST1 0x02 // data ready status bit 0 149 | #define AK8963_XOUT_L 0x03 // data 150 | #define AK8963_XOUT_H 0x04 151 | #define AK8963_YOUT_L 0x05 152 | #define AK8963_YOUT_H 0x06 153 | #define AK8963_ZOUT_L 0x07 154 | #define AK8963_ZOUT_H 0x08 155 | #define AK8963_ST2 0x09 // Data overflow bit 3 and data read error status bit 2 156 | #define AK8963_CNTL 0x0A // Power down (0000), single-measurement (0001), self-test (1000) and Fuse ROM (1111) modes on bits 3:0 157 | #define AK8963_ASTC 0x0C // Self test control 158 | #define AK8963_I2CDIS 0x0F // I2C disable 159 | #define AK8963_ASAX 0x10 // Fuse ROM x-axis sensitivity adjustment value 160 | #define AK8963_ASAY 0x11 // Fuse ROM y-axis sensitivity adjustment value 161 | #define AK8963_ASAZ 0x12 // Fuse ROM z-axis sensitivity adjustment value 162 | 163 | 164 | // eggfly added 165 | #define PWR1_SLEEP_BIT 6 166 | 167 | // Using the MPU-9250 breakout board, ADO is set to 0 168 | // Seven-bit device address is 110100 for ADO = 0 and 110101 for ADO = 1 169 | 170 | #define AK8963_ADDRESS 0x0C 171 | 172 | #if ADO 173 | #define MPU9250_ADDRESS 0x69 // Device address when ADO = 1 174 | #else 175 | #define MPU9250_ADDRESS 0x68 // Device address when ADO = 0 176 | #endif // AD0 177 | 178 | 179 | #define GYRO_FULL_SCALE_250_DPS 0x00 180 | #define GYRO_FULL_SCALE_500_DPS 0x08 181 | #define GYRO_FULL_SCALE_1000_DPS 0x10 182 | #define GYRO_FULL_SCALE_2000_DPS 0x18 183 | 184 | #define ACC_FULL_SCALE_2_G 0x00 185 | #define ACC_FULL_SCALE_4_G 0x08 186 | #define ACC_FULL_SCALE_8_G 0x10 187 | #define ACC_FULL_SCALE_16_G 0x18 188 | 189 | #define LPF_BANDWIDTH_FULL 0x00 190 | #define LPF_BANDWIDTH_460 0x08 191 | #define LPF_BANDWIDTH_184 0x09 192 | #define LPF_BANDWIDTH_92 0x0A 193 | #define LPF_BANDWIDTH_41 0x0B 194 | #define LPF_BANDWIDTH_20 0x0C 195 | #define LPF_BANDWIDTH_10 0x0D 196 | #define LPF_BANDWIDTH_5 0x0E 197 | 198 | #endif 199 | -------------------------------------------------------------------------------- /predict_gesture/UDPChannel.cpp: -------------------------------------------------------------------------------- 1 | #include "UDPChannel.h" 2 | 3 | #include "LED.h" 4 | #include 5 | 6 | 7 | UDPChannel::UDPChannel() 8 | { 9 | 10 | } 11 | 12 | void UDPChannel::ConnectAP(const char* ssid, const char* pwd) 13 | { 14 | // WiFi.softAP(AP_SSID, AP_PWD); 15 | WiFi.begin(ssid, pwd); 16 | 17 | Serial.write("Waiting for connect to AP"); 18 | while (!WiFi.isConnected()) 19 | { 20 | Led.Toggle(); 21 | Serial.write('.'); 22 | } 23 | 24 | Led.Off(); 25 | Serial.println(""); 26 | } 27 | 28 | void UDPChannel::Send(int count, unsigned char* buf, int len) 29 | { 30 | UDP.beginPacket("255.255.255.255", 8000); 31 | UDP.write((unsigned char*)&count, 4); 32 | UDP.write(buf, len); 33 | UDP.endPacket(); 34 | } 35 | -------------------------------------------------------------------------------- /predict_gesture/UDPChannel.h: -------------------------------------------------------------------------------- 1 | #ifndef _UDP_CHANNEL_H 2 | #define _UDP_CHANNEL_H 3 | 4 | #include 5 | 6 | class UDPChannel 7 | { 8 | public: 9 | UDPChannel(); 10 | 11 | void ConnectAP(const char* ssid, const char* pwd); 12 | void Send(int count, unsigned char* buf, int len); 13 | 14 | private: 15 | WiFiUDP UDP; 16 | }; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /predict_gesture/predict_gesture.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "MPU9250.h" 15 | #include "UDPChannel.h" 16 | #include "HRTimer.h" 17 | #include "LED.h" 18 | 19 | #include "model.h" 20 | 21 | const int BUTTOM_PIN = 4; 22 | 23 | const char* AP_SSID = "iCheng"; 24 | const char* AP_PWD = "nopassword"; 25 | 26 | const char* GESTURES[] = { 27 | "cross", 28 | "circle" 29 | }; 30 | const int NUM_GESTURES = sizeof(GESTURES) / sizeof(GESTURES[0]); 31 | const int SAMPLE_COUNT = 120; 32 | 33 | MPU9250 IMU(9, 8); 34 | UDPChannel Channel; 35 | HRTimer LoopTimer; 36 | HRTimer ExeTimer; 37 | 38 | char SerialBuffer[50]; 39 | 40 | int conut = 0; 41 | unsigned char sign = 0; 42 | unsigned char counter = 0; 43 | 44 | short SampleData[9]; 45 | int IMUData[9]; 46 | int LastData[9]; 47 | 48 | const float ACCELERATION_THRESHOLD = 2E6; 49 | const int SMOTH_COUNT = 5; 50 | int RecordCount = -1; // -1 表示数据采集未启动 51 | 52 | float Samples[6][SAMPLE_COUNT]; 53 | 54 | tflite::MicroErrorReporter tflErrorReporter; 55 | tflite::ops::micro::AllOpsResolver tflOpsResolver; 56 | 57 | const tflite::Model* tflModel = nullptr; 58 | tflite::MicroInterpreter* tflInterpreter = nullptr; 59 | TfLiteTensor* tflInputTensor = nullptr; 60 | TfLiteTensor* tflOutputTensor = nullptr; 61 | 62 | constexpr int tensorArenaSize = 8 * 1024; 63 | byte tensorArena[tensorArenaSize]; 64 | 65 | void setup() { 66 | pinMode(BUTTOM_PIN, INPUT_PULLUP); 67 | 68 | Serial.begin(115200); 69 | Channel.ConnectAP(AP_SSID, AP_PWD); 70 | 71 | Serial.println("Starting IMU..."); 72 | IMU.Init(); 73 | 74 | LoadModel(); 75 | } 76 | 77 | void loop() { 78 | LoopTimer.Start(); 79 | 80 | // TrainingMode(); 81 | PredictMode(); 82 | 83 | auto t = LoopTimer.End() / 1000.0; 84 | // Serial.println(t); 85 | if (t < 10) { 86 | delay(10 - t); 87 | } 88 | } 89 | 90 | // 91 | // Functions 92 | // 93 | 94 | void LoadModel() { 95 | Serial.println("Loading Model"); 96 | tflModel = tflite::GetModel(model); 97 | 98 | int ModelVersion = tflModel->version(); 99 | 100 | sprintf(SerialBuffer, "Model Version: %d, TFLite Version: %d", ModelVersion, TFLITE_SCHEMA_VERSION); 101 | Serial.println(SerialBuffer); 102 | 103 | if (ModelVersion != TFLITE_SCHEMA_VERSION) { 104 | Serial.println("Model schema mismatch!"); 105 | } else { 106 | Serial.println("Model Loaded!"); 107 | } 108 | 109 | tflInterpreter = new tflite::MicroInterpreter(tflModel, tflOpsResolver, tensorArena, tensorArenaSize, &tflErrorReporter); 110 | tflInterpreter->AllocateTensors(); 111 | tflInputTensor = tflInterpreter->input(0); 112 | tflOutputTensor = tflInterpreter->output(0); 113 | 114 | sprintf(SerialBuffer, "Input Size: %d[%d, %d], Outpu Size: %d[%d, %d]", tflInputTensor->dims->size, tflInputTensor->dims->data[0], tflInputTensor->dims->data[1], tflOutputTensor->dims->size, tflOutputTensor->dims->data[0], tflOutputTensor->dims->data[1]); 115 | Serial.println(SerialBuffer); 116 | } 117 | 118 | void TrainingMode() { 119 | Acquisition(); 120 | 121 | if (digitalRead(BUTTOM_PIN) == LOW && RecordCount == -1) { 122 | RecordCount = 0; 123 | Led.On(); 124 | } 125 | 126 | if (RecordCount > -1) { 127 | RecordCount++; 128 | Send(); 129 | } 130 | 131 | if (RecordCount >= SAMPLE_COUNT) { 132 | RecordCount = -1; 133 | Led.Off(); 134 | } 135 | } 136 | 137 | void PredictMode() 138 | { 139 | Acquisition(); 140 | 141 | if ((/*(DetectMotion() ||*/ digitalRead(BUTTOM_PIN) == LOW) && RecordCount == -1) { 142 | RecordCount = 0; 143 | Led.On(); 144 | } 145 | 146 | if (RecordCount >= SAMPLE_COUNT) { 147 | RecordCount = -1; 148 | Led.Off(); 149 | 150 | if (Inference()) Result(); 151 | } 152 | else if (RecordCount > -1) { 153 | for (int i = 0; i < 9; i++) { 154 | Samples[i][RecordCount] = IMUData[i] / 32768.0; 155 | } 156 | 157 | RecordCount++; 158 | } 159 | } 160 | 161 | 162 | bool DetectMotion() { 163 | float sum = 0; 164 | 165 | for (int i = 3; i < 6; i++) { 166 | float a = (float)IMUData[i] - (float)LastData[i]; 167 | sum += a * a; 168 | } 169 | 170 | for (int i = 0; i < 9; i++) { 171 | LastData[i] = IMUData[i]; 172 | } 173 | 174 | bool ret = sum > ACCELERATION_THRESHOLD; 175 | // if(ret) Serial.println(sum); 176 | 177 | return ret; 178 | } 179 | 180 | void Acquisition() { 181 | for (int i = 0; i < 9; i++) { 182 | IMUData[i] = 0; 183 | } 184 | 185 | for (int c = 0; c < SMOTH_COUNT; c++) { 186 | IMU.Read(SampleData); 187 | 188 | for (int i = 0; i < 9; i++) { 189 | IMUData[i] += SampleData[i]; 190 | } 191 | } 192 | 193 | // sprintf(SerialBuffer, "%+5d\t%+5d\t%+5d | %+5d\t%+5d\t%+5d | %+5d\t%+5d\t%+5d\r\n", IMUData[0], IMUData[1], IMUData[2], IMUData[3], IMUData[4], IMUData[5], IMUData[6], IMUData[7], IMUData[8]); 194 | // Serial.print(SerialBuffer); 195 | } 196 | 197 | void Send() 198 | { 199 | Channel.Send(RecordCount, (unsigned char*)IMUData, 36); 200 | } 201 | 202 | bool Inference() 203 | { 204 | bool ret = false; 205 | 206 | // Copy Data to Model Input 207 | for (int k = 0; k < SAMPLE_COUNT; k++) { 208 | for (int i = 0; i < 6; i++) { 209 | tflInputTensor->data.f[k * 6 + i] = Samples[i][k]; 210 | } 211 | } 212 | 213 | // Start Inference 214 | ExeTimer.Start(); 215 | TfLiteStatus invokeStatus = tflInterpreter->Invoke(); 216 | unsigned long t = ExeTimer.End(); 217 | 218 | // Check Result 219 | if (invokeStatus == kTfLiteOk) { 220 | sprintf(SerialBuffer, "Invoke In %8.6f(ms)", t / 1000.0); 221 | Serial.println(SerialBuffer); 222 | 223 | ret = true; 224 | } 225 | else { 226 | Serial.println("Invoke failed!"); 227 | } 228 | 229 | return ret; 230 | } 231 | 232 | void Result() 233 | { 234 | float p_threshold = 0.99; 235 | 236 | auto p_cross = tflOutputTensor->data.f[0]; 237 | auto p_circle = tflOutputTensor->data.f[1]; 238 | 239 | sprintf(SerialBuffer, "Cross: %8.6f, Circle: %8.6f", p_cross, p_circle); 240 | Serial.println(SerialBuffer); 241 | 242 | if (p_cross > p_threshold) 243 | { 244 | Led.Red(); 245 | } 246 | else if (p_circle > p_threshold) 247 | { 248 | Led.Blue(); 249 | } 250 | else 251 | { 252 | Led.Blank(); 253 | } 254 | } 255 | 256 | void ShowOutput() 257 | { 258 | for (int i = 0; i < NUM_GESTURES; i++) 259 | { 260 | sprintf(SerialBuffer, "%s: %8.6f", GESTURES[i], tflOutputTensor->data.f[i]); 261 | Serial.println(SerialBuffer); 262 | } 263 | } 264 | --------------------------------------------------------------------------------