更新日期:
机器学习打字手套的ML模型和Arduino编程
我是信息技术学位持有人。我最近获得了三个微型机器学习证书。
本教程将教你如何为机器学习打字手套编程
- 从Arduino获取模拟值并求平均值所需的代码。
- ML模型的代码可以让你的人工神经网络根据第一个教程中的数据进行训练。
- 这样,您的机器学习打字手套就可以在任何坚硬的表面上打字了。
滑入Arduino代码
- 手套本身应为每只手贴上标签,以便于使用。我给我的贴上了红色和绿色的标签。
- 请记住,以下代码将通过Arduino的Bluetooth Silver Mate将连接到手指的flex传感器的模拟值发送到计算机。
- 在第一个教程中构建的接收Python脚本将处理进入计算机的数据。
- 然后将其存储到逗号分隔的值列表中。我相信每个模拟值总共有6个字节。
- 表示模拟字符的(A)占用1个字节的内存感知字符为1个字节。然后传感器编号指示器占用4个字节,因为它是一个整数。
- 然后,我们使用lowByte从模拟值中获取最低有效字节。只要模拟值在1-255之间,这应该是正常的。
- 在手套上工作时,我还注意到模拟值是虚假的,所以我使用平均滤波器将其平滑到更可靠的值。
需要Math.h来平滑AverageFilter中的数据。
#包括
在Arduino程序的设置部分,我们将波特率设置为1200
无效的设置(){Serial.begin (1200);}
Average取16个模拟值,并将它们总共平均16次。然后,我们除以所取模拟值的数量。然后,函数返回一个分数。通过这样做,它可以更准确地表示最终的模拟值。
//平滑输入,消除机器学习模型中的随机值int平均滤波器(intaNum){浮动AverageAnalogValue =0;int测量平均值=16;为(int我=0;我< MeasurementsToAverage;+ + i){AverageAnalogValue + = analogRead (aNum);耽搁(1);}平均模拟值/=测量值与平均值之比;返回TakeFraction (.10,平均值);}intTakeFraction (浮动小山,int平均值(平均值){返回四舍五入(平均值*分数);}
第一个打印字符(A)在值和初始打印值后的第二个打印数字5-9之间有一定的间隔。它允许我们识别它是哪个传感器。
第三个打印值是flex传感器的实际模拟值。
无效的循环(){//每个传感器6字节电视连续剧打印(“A”);电视连续剧打印("5");电视连续剧打印(低字节(平均值)过滤器(0)));//读取本地模拟信号耽搁(5);电视连续剧打印(“A”);电视连续剧打印("6");电视连续剧打印(低字节(平均值)过滤器(1)));//读取本地模拟信号耽搁(5);电视连续剧打印(“A”);电视连续剧打印("7");电视连续剧打印(低字节(平均值)过滤器(2)));//读取本地模拟信号耽搁(5);电视连续剧打印(“A”);电视连续剧打印("8");电视连续剧打印(低字节(平均值)过滤器(3.)));//读取本地模拟信号耽搁(5);电视连续剧打印(“A”);电视连续剧打印("9");电视连续剧打印(低字节(平均值)过滤器(4)));电视连续剧打印(“\n”);}
A0{整数值} | A1{整数值} | A2{整数值} | A3{整数值} | A4{整数值} | A5{整数值} | A6{整数值} | A7{整数值} | A8{整数值} | A9{整数值} |
---|
一条小蟒蛇
- 首先,我们将一些必需的库导入到项目中。其中一些库在第一个教程中进行了解释,因此我们将不讨论它们。
- 我主要想关注TensorFlow、NumPy和Keras库。这些将用于机器学习模型。
- 由于我们想根据手套上的数据预测按下的键,脚本的某些部分将类似于我们在第一个教程中制作的pythonserialmlgloves1.1.py。我们有一个因变量和一个自变量。
- 程序的X和y分别扮演更改数据和更改结果的角色。
- 在本例中,录制的键盘键将是y或目标值。X将是我们在按下键时从脚本中录制的所有模拟值。
- 我们不能简单地接受价值观的本来面目。它们必须经过某种标准化。
- 如果不在特定范围内,它们可能会影响重要值和次要值的最终结果。由于计算机不能理解字母,我们必须使用OneHotEncoder来转换它们。
#本项目使用了Tensorflow v1.5进口大熊猫作为pd输入张量流作为tf进口numpy作为NP进口干酪导入序列号进口线程进口稀土从…起keras.models从_json导入模型_进口numpy从…起numpy进口数组从…起numpy进口重塑导入队列que=队列。队列()#如何将手套连接到手指#从小指1-5绿色开始#从拇指1-5红色开始字节\u到\u读取=23#HC-06(红色)ser0=串行。串行(“COM9”,1200,bytesize=serial.EIGHTBITS,timeout=None,parity=serial.parity\u None,rtscts=1)# RN(绿色)#将停止位更改为1ser1 =系列。系列(“COM10”,1200,bytesize=serial.EIGHTBITS,timeout=None,parity=serial.parity\u None,rtscts=1)数据集=pd.read\u csv(“目录”)X=dataset.iloc[:,1:11].价值观y = dataset.iloc [:,0].价值观#处理丢失的数据从…起sklearn.preprocessing导入插补器imputer = imputer (missing_values =“南”,策略=“的意思是”,轴=0)插补器=插补器拟合(X[:,1:11])X (:,1:11] = imputer.transform (X [:,1:11])#我想,由于openoffice格式中的列,数据集从1开始编码分类数据#编码因变量从…起sklearn.preprocessing导入标签编码器,OneHotEncoderlabelencoder_y=labelencoder()y=标签编码器y.拟合变换(y)#可能只需要在编码中走这么远onehotencoder = onehotencoder(稀疏的=假)y=y。重塑(透镜(y),1)y=onehotencoder.fit_变换(y)#将数据集拆分为训练集和测试集从…起sklearn.model\u选择导入列车\u测试\u拆分在下次训练时考虑使用另一个随机状态种子。#将random_state改为42X_train, X_test, y_test = train_test_split(X, y, test_size =0.2,随机状态=42)#特征缩放从…起sklearn。预处理进口StandardScalersc_X=StandardScaler()X_train = sc_X.fit_transform (X_train)X_test = sc_X.transform (X_test)#导入keras依赖项进口干酪从…起keras.models按顺序导入从…起keras。层进口密集从…起keras.models从_json导入模型_#初始化ANN分类器=顺序()
这些是神经网络的层。我们只有一个输入层和一个隐藏层。这种神经网络的神经元数量是任意的,可以改进。
然而,输出层确实需要28个神经元来编码字母表中的字母。
#添加第一个输入隐藏层classifier.add(密度(17kernel_initializer =“制服”激活=“雷卢”,输入尺寸=10))#添加第二个隐藏层classifier.add(密度(17kernel_initializer =“制服”激活=“雷卢”))#添加输出层classifier.add(密度(28kernel_initializer =“制服”激活=“softmax”))
使用分类熵是因为这是一个分类问题。
编译(丢失)=“分类熵”,优化器=“亚当”,指标=[“准确度”])#加载json并创建模型#json_file=open('model.json','r')#已加载的\u model\u json=json\u file.read()# json_file.close ()# loaded_model = model_from_json (loaded_model_json)#将权重加载到新模型中分类器.负载重量(“目录”)打印(“从磁盘加载模型”)#加载json并创建模型#json_file = open('directory', 'r')#已加载的\u model\u json=json\u file.read()# json_file.close ()#分类器= model_from_json (loaded_model_json)#打印(“从磁盘加载的模型”)#分级机.fit(X列,y列,批量=10,nb列=1000)graph=tf.get\u default\u graph()#将模型序列化为JSON#model_json=classifier.to_json()#with open("directory", "w") as json_file#json_file.write(model_json)#将权值序列化到HDF5#分类器。保存权重(“目录”)#打印(" save model to disk")
下面几乎所有的代码都与上一教程中的Python脚本相同。但是请注意下面的图表。这是用来保存神经网络的状态。
#类来做有关串行数据的重要程序类serprocedure():#以下变量是类级别的,并且是静态的,这意味着它们将在类实例之间持久化尝试:sensorlist除名称错误外:传感器列表=[]#一个存储丢失数据的列表尝试:缺失数据除名称错误外:丢失数据=[]#丢失数据的计数器尝试:麦考特除名称错误外:mcounter=0尝试:times_counter除名称错误外:times_counter = 0#使用_init__构造函数获取参数self和serdata#每个方法只做一件事定义初始化(self、serdata、标志):self.serdata=serdataself.flag=flagself.serdatalooper (self.flag)#如果它是第二个串行com的第二个线程,并且缺少的计数器小于1,并且传感器列表不大于10如果self.flag==1且serprocedure.mcounter<1且len(serprocedure.sensorlist)==10:#告诉用户程序正在执行进一步提取print(“执行进一步的数据提取和导出”)#进行进一步提取自进一步提取(serprocedure.sensorlist)serprocedure.times_计数器=serprocedure.times_计数器+1#如果它不是第一个带有0标志的串行COM,它只会这样做elif self.flag!=0:#复位计数器serprocedure.mcounter=0#清除列表,使其不会累积serprocedure.sensorlist.clear ()打印(“丢弃部分或多余结果”)que.put(假)方法提取串行数据的各个部分def extractanalog(自我、analognumber标志):#将十进制regexp更改为{1,2}量词found=re.search(r'(A'+str(类比数)+'\d{1,2}',str(self.serdata))如果发现不是None:如果找到。组():#创建数据列表# sensorlist必须被移到顶部作为一个类级别变量#传感器列表=[]serprocedure.sensorlist.append(str(found.group()))返回其他:serprocedure。mcounter + = 1#它被卡在这里了返回def提取(自我、新列表):#保存模拟标签的列表findanaloglabel=[]#用于保存模拟值的列表findanalogvalue=[]z=0#打印("This is the list in furtherextraction:")#打印(新列表)# Len计数列表中10个元素,但索引从0开始当z #这些将必须编入清单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 ()#将模拟值返回到主读模拟que.put (findanalogvalue)def serdatalooper(自我、旗):如果标志==0:我= 0结束=i+4其他:我= 5结束=i+4#循环遍历列表的整个长度并提取数据当我<=结束:“mainlist self.extractanalog(我)#增加计数器I = I + 1#排序列表serprocedure.sensorlist.sort()#if len(serprocess .missingdata) < 1:#q、 put(“没有丢失数据”)#返回真值#其他:#q、 put(“有”+str(len(serprocedure.missingdata))+“列表中缺少的数据”)#返回错误#从串行端口读取def从串行读取(串行、板、标志):#打印(“读取{}:端口{}”。格式(板,端口))有效载荷=b“bytes_count = 0#将serial.read(1)中的1改为bytes_at_a_time# bytes_at_a_time = serial.in_waiting#更改为<=以使其计数最后一个字节#当字节计数<=字节到读取时:#读取字节=串行。读取(1)# sum返回的字节数(不是2),你已经设置了串口的超时时间#见https://pythonhosted.org/pyserial/pyserial_api.html # serial.Serial.read#字节计数=字节计数+长度(读取字节)这似乎是一个进步。试着捕捉丢失的串行数据。读取字节=串行。读取字节直到('\n',40)Payload = Payload + read_bytes这里你有字节,做你的逻辑#从serprocedure类实例化对象serprocobj = serprocedure(载荷、旗)def main():而真正的:#将function、serial、board和key作为参数传入#我们将传入一个标志以标识正在使用哪个板t=线程。线程(目标=从串行读取,参数=(ser0,“HC-06(红色)”,0))t1=threading.Thread(目标=从串行读取,参数=(ser1,“RN(绿色)”,1))#启动线程t.start ()t1.start()#小心这是阻塞。获取丢失的数据量#打印(q.get ())#等待所有线程终止#连接可能会阻碍缓冲区刷新,如果将其移动到底部# t.join ()# t1.join ()#刷新串行输入和输出缓冲区ser0.reset_输入_缓冲区()ser0.reset_输出_缓冲区()ser1.reset_input_buffer()ser1.reset_output_buffer ()t.join ()t1.join()全局图与graph.as_default ():模拟预测=que.get()如果模拟预测!=假:#为了使其更好地工作,必须对输入进行缩放模拟到预测=sc到X.变换(numpy.数组([模拟到预测])new_pred = classifier.predict_classes (analog_to_predict)new_pred=labelencoder_y.逆变换(new_pred)打印(new_pred)其他:打印(“que.get()为False”)main ()
你想知道更多关于制作机器学习打字手套的知识吗?
如果您对这个过程感兴趣,请查阅我关于这个主题的第一个深入教程,其中包含更多信息:
此内容是准确和真实的作者的知识,并不是要取代正规和个性化的意见,从合格的专业人士。
©2021布罗克林奇