跳到主要内容
更新日期:

机器学习打字手套的ML模型和Arduino编程

我是一个信息技术专业的毕业生。我最近获得了三个微型机器学习证书。

本教程将教你机器学习编程打字手套

  • 从Arduino中获取模拟值并求平均值所需的代码。
  • ML模型的代码,使您的人工神经网络训练从第一个教程的数据。
  • 这样你的机器学习打字手套就可以在任何坚硬的表面上打字了。

滑动到Arduino代码

  1. 手套本身应该为每只手贴上标签,使它们使用起来更直观。我把我的标为红色和绿色。
  2. 请记住,下面的代码将通过Arduino的蓝牙Silver Mate将手指上的弯曲传感器的模拟值发送到计算机。
  3. 在第一个教程中构建的接收Python脚本将处理进入计算机的数据。
  4. 然后将其存储到一个逗号分隔值列表中。我相信每个模拟值总共有6个字节。
  5. 表示一个模拟字符的(A)占存储器的一个字节,感应字符是一个字节。然后传感器数字指示器占用四个字节,因为它是一个整数。
  6. 然后,我们使用lowByte从模拟值中获取最低有效字节。只要模拟值在1-255之间,就可以了。
  7. 在手套上工作时,我还注意到模拟值是假的,所以我使用平均滤波器将它们平滑成更可靠的值。

Math.h需要在AverageFilter中平滑数据。

# include < math.h >

在Arduino程序的setup部分,我们将波特率设置为1200

无效设置(){Serial.begin (1200);

Average取16个模拟值,并将它们合计取16次平均值。在这之后,我们除以所获得的模拟值的数量。然后,函数返回一个分数。通过这样做,它可以更准确地表示最终模拟值。

//平滑输入,消除机器学习模型中的随机值intAverageFilter (intaNum)浮动AverageAnalogValue =0intMeasurementsToAverage =16int我=0;我< MeasurementsToAverage;+ + i)AverageAnalogValue + = analogRead (aNum);延迟(1);AverageAnalogValue / = MeasurementsToAverage;返回TakeFraction (.10, AverageAnalogValue);intTakeFraction (浮动FractionAmount,intAveragedAnalogValue)返回轮(AveragedAnalogValue * FractionAmount);

第一个打印字符(A)在两个值之间提供了一些间隔,第二个打印数字在初始打印值之后为5-9。它能让我们识别它是哪个传感器。

第三个打印值是柔性传感器的实际模拟值。

无效循环(){//每个传感器6字节系列。打印“一个”);系列。打印“5”);系列。打印(lowByte (AverageFilter (0)));//读取本地模拟信号延迟(5);系列。打印“一个”);系列。打印“6”);系列。打印(lowByte (AverageFilter (1)));//读取本地模拟信号延迟(5);系列。打印“一个”);系列。打印“7”);系列。打印(lowByte (AverageFilter (2)));//读取本地模拟信号延迟(5);系列。打印“一个”);系列。打印“8”);系列。打印(lowByte (AverageFilter (3.)));//读取本地模拟信号延迟(5);系列。打印“一个”);系列。打印“9”);系列。打印(lowByte (AverageFilter (4)));系列。打印“\ n”);
A0{整数值} A1{整数值} A2{整数值} A3{整数值} A4{整数值} A5{整数值} A6{整数值} A7{整数值} A8{整数值} A9{整数值}

一个Python

  1. 首先,我们将一些必需的库导入到项目中。其中一些在第一个教程中已经解释过了,所以我们就不讨论它们了。
  2. 我主要想关注的是类库TensorFlow, NumPy和Keras。这些将用于机器学习模型。
  3. 由于我们希望根据手套的数据预测按下了什么键,因此脚本的某些部分将类似于我们在第一个教程中制作的pythonserialmlgloves1.1.py。我们有一个因变量和一个自变量。
  4. 程序的X和y分别扮演变化数据和变化结果的角色。
  5. 在本例中,所记录的键盘键将是y或目标值。X将是我们在按下该键时从脚本中记录的所有模拟值。
  6. 我们不能简单地接受这些价值观。它们必须经过某种正常化。
  7. 如果没有在特定的范围内,它们可能会扭曲重要值和次要值的最终结果。由于计算机无法理解字母,我们必须使用OneHotEncoder对它们进行转换。
# Tensorflow v1.5在这个项目中使用进口熊猫作为pd进口tensorflow作为特遣部队进口numpy作为np进口keras进口系列进口线程进口再保险keras。模型导入model_from_json进口numpynumpy进口数组numpy进口重塑进口队列是= queue.Queue ()#如何把手套和手指连接起来#从粉色1-5绿色开始#从大拇指1-5红色开始BYTES_TO_READ =23# HC-06(红色)ser0 =系列。系列(“COM9”1200, bytesize =系列。EIGHTBITS超时= None,平价=系列。PARITY_NONE rtscts =1# RN(绿色)#停车次数改为1次ser1 =系列。系列(“COM10”1200, bytesize =系列。EIGHTBITS超时= None,平价=系列。PARITY_NONE rtscts =1数据集= pd.read_csv (“目录”X = dataset.iloc [:,111) . valuesy = dataset.iloc [:,0) . values#处理丢失的数据sklearn。预处理进口输入imputer = imputer (missing_values =“南”、战略=“的意思是”轴=0输入= imputer.fit (X [:,111])X (:,111] = imputer.transform (X [:,111])# dataset从1开始,因为列从openoffice格式,我想#编码分类数据#编码因变量sklearn。预处理导入LabelEncoder, OneHotEncoderlabelencoder_y = LabelEncoder ()y = labelencoder_y.fit_transform (y)#可能只需要在编码中走这么远onehotencoder = onehotencoder(稀疏的=y = y.reshape (len (y),1y = onehotencoder.fit_transform (y)#将数据集拆分为Training set和Test setsklearn。model_selection进口train_test_split#下次训练时考虑使用另一个random_state种子#将random_state更改为42X_train, X_test, y_train, y_test = train_test_split(X, y, test_size =。0.2random_state =42#功能扩展sklearn。预处理进口StandardScalersc_X = StandardScaler ()X_train = sc_X.fit_transform (X_train)X_test = sc_X.transform (X_test)#导入keras依赖进口keraskeras。模型导入顺序keras。层进口密集keras。模型导入model_from_json#初始化ANN分类器=顺序()

这些是神经网络的层次。我们只有一个输入层和一个隐藏层。该神经网络的神经元数量是任意的,可以改进。

然而,输出层确实需要28个神经元来编码字母。

#添加第一个输入隐藏层classifier.add(密度(17kernel_initializer =“统一”激活=“relu”input_dim =10))#添加第二个隐藏层classifier.add(密度(17kernel_initializer =“统一”激活=“relu”))#添加输出层classifier.add(密度(28kernel_initializer =“统一”激活=“softmax”))

之所以使用category_crosssentropy,是因为这是一个分类问题。

classifier.compile(损失=“categorical_crossentropy”优化器=“亚当”指标= (“准确性”])#加载json并创建模型# json_file =开放(”模型。json”、“r”)# loaded_model_json = json_file.read ()# json_file.close ()# loaded_model = model_from_json (loaded_model_json)#加载权重到新模型classifier.load_weights (“目录”打印“从磁盘加载模型”#加载json并创建模型#json_file = open('directory', 'r')# loaded_model_json = json_file.read ()# json_file.close ()#分类器= model_from_json (loaded_model_json)#print("从磁盘加载模型")# classifier.fit (X_train y_train batch_size = 10, nb_epoch = 1000)图= tf.get_default_graph ()将模型序列化为JSON# model_json = classifier.to_json ()#使用open("directory", "w")作为json_file:# json_file.write (model_json)#序列化权重到HDF5# classifier.save_weights(“目录”)#print("已保存的模型到磁盘")

下面的代码几乎都与前面教程中的Python脚本相同。但请注意底部使用了一个图表。这是用来保存神经网络的状态。

#类做重要程序上的串行数据类serprocedure ():#下面的变量是类级的,是静态的,这意味着它们将在类实例中持久存在试一试:sensorlist除了NameError:sensorlist = []#一个存储丢失数据的列表试一试:missingdata除了NameError:missingdata = []#丢失数据的计数器试一试:mcounter除了NameError:mcounter = 0试一试:times_counter除了NameError:times_counter = 0#使用__init__构造函数接受参数self和serdata#每个方法只做一件事def __init__(自我、serdata标志):自我。serdata = serdata自我。国旗=国旗self.serdatalooper (self.flag)#如果是带有第二个串行com的第二个线程,缺失的计数器小于1,传感器不大于10如果自我。Flag == 1和serprocedure。mcounter< 1 and len(serprocedure.sensorlist) == 10:#告诉用户程序正在执行进一步的提取打印(“执行进一步的数据提取和导出”)#执行进一步的提取self.furtherextraction (serprocedure.sensorlist)serprocedure。times_counter= serprocedure.times_counter + 1#它只会这样做,如果它不是第一个带有标志0的串行COMelif自我。国旗! = 0:#复位计数器serprocedure。mcounter = 0#清除列表,以免其累积serprocedure.sensorlist.clear ()print(扔掉部分或多余的结果。)que.put(假)方法提取串行数据的各个部分def extractanalog(自我、analognumber标志):将十进制regexp更改为{1,2}限定符find = re.search(r'(A' + str(类推数)+ '\d{1,2})',str(self.serdata)))如果发现不为None:如果found.group ():#创建一个数据列表# sensorlist必须移到最上面,成为一个类级变量# sensorlist = []serprocedure.sensorlist.append (str (found.group ()))返回其他:serprocedure。mcounter + = 1它卡在这里了返回def furtherextraction(自我,newlist):#保存模拟标签的列表findanaloglabel = []#用于保存模拟值的列表findanalogvalue = []z = 0#print(“这是进一步提取的列表:”)#打印(newlist)# Len计数列表中10个元素,但索引从0开始当z < len(newlist):这些将被制作成列表findanaloglabel.append (re.search (r (A \ d), newlist [z]) .group ())# ?<=向后查找,只匹配前面的内容将十进制regexp更改为{1,2}限定符findanalogvalue.append (int (re.search (r ' ((? < = A \ d {1}) \ d{1,2})”,newlist [z]) .group ()))#增量zZ = Z + 1#打印列表findanalogvalue打印(findanalogvalue)#调用导出方法serprocedure.sensorlist.clear ()返回模拟值到主read_analogque.put (findanalogvalue)def serdatalooper(自我、旗):If flag == 0:我= 0End = I + 4其他:我= 5End = I + 4#循环遍历整个列表长度并提取数据当我<=结束:“mainlist self.extractanalog(我)#增加计数器I = I + 1#排序列表serprocedure.sensorlist.sort ()#if len(serprocedure.missingdata) < 1:#问。放置(“没有丢失数据”)#还真其他:#问。put("There are " + str(len(serprocedure.missingdata)) + " of data missing from list")#返回假#从串口读取def read_from_serial(串行、董事会、旗):#print("reading from {}: port{}")。格式(董事会、港口)有效载荷= b”bytes_count = 0#将serial.read(1)中的1更改为bytes_at_a_time# bytes_at_a_time = serial.in_waiting#更改为<=以计算最后一个字节#while bytes_count <= BYTES_TO_READ:# read_bytes = serial.read (1)# sum返回的字节数(不是2),你已经设置了串口的超时时间#见https://pythonhosted.org/pyserial/pyserial_api.html # serial.Serial.read# bytes_count = bytes_count + len(read_bytes)这似乎是一种进步。尝试捕获丢失的串行数据。read_bytes = serial.read_until(“\ n”,40)Payload = Payload + read_bytes#这里有字节,做你的逻辑从serprocedure类实例化对象serprocobj = serprocedure(载荷、旗)def main ():而真正的:#将function、serial、board和key作为参数传入#我们将传递一个标志来标识哪个板正在被使用t =线程。线程(目标= read_from_serial args = (ser0,“HC-06(红色)”,0))t1 =线程。线程(目标= read_from_serial args = (ser1, RN(绿色),1))#启动线程t.start ()t1.start ()#小心这是阻塞。获取丢失的数据量#打印(q.get ())#等待所有线程终止#连接可能会阻碍缓冲区刷新,如果他们是移动到底部# t.join ()# t1.join ()#刷新串行输入和输出缓冲区ser0.reset_input_buffer ()ser0.reset_output_buffer ()ser1.reset_input_buffer ()ser1.reset_output_buffer ()t.join ()t1.join ()全球图与graph.as_default ():analog_to_predict = que.get ()if analog_to_predict != False:#输入必须进行缩放,以便更好地工作analog_to_predict = sc_X.transform (numpy.array ([analog_to_predict]))new_pred = classifier.predict_classes (analog_to_predict)new_pred = labelencoder_y.inverse_transform (new_pred)打印(new_pred)其他:打印(“que.get()是假的”)main ()

你想知道更多关于制作机器学习打字手套吗?

如果你对这个过程感兴趣,最好看看我关于这个主题的第一个深入教程,其中包含了更多的信息:

如何制作更好的机器学习打字手套

此内容是准确和真实的作者的知识,并不是要取代正规和个性化的意见,从合格的专业人士。

©2021布洛克·林奇

相关文章

Baidu