前言
柴火认证会员是指通过柴火新一代信息技术培训课程并通过项目认证,或符合条件直接通过认证的会员群体。更多关于认证会员信息,戳此了解。
今天柴火菌给大家隆重推出【柴火认证会员项目show】栏目,跟大家分享柴火认证会员群体在造物上的项目经验。栏目首篇推文,给大家推荐一篇超级无敌详细的教程,带你入门sklearn机器学习,运用Arduino和Python来根据温度和湿度判断天气情况。教程来自柴火认证会员郑博培Mr.郑先生,感谢开源分享。Open source is love.
郑博培
会员编号:CHSZ20200002002
专业背景:自动化
服务行业:/
就读学校:北京联合大学
越是不可能,越要创造无限可能!目前在人工智能的领域里探索
认证信息
认证项目:基于Arduino的天气判断模型
项目简介:该项目基于DHT11湿度模块以及DS18B20测温模块,经过模型训练后,可以输出实时的天气情况,并将数据保存在数据库中。该项目可以应用在智能家居,如智能晾衣架,智能窗户等;
最近上手了DHT11湿度模块以及DS18B20测温模块,于是想着能不能用温度和湿度这两个数据做些什么。我们知道:
温度与湿度在一定程度上和天气有关,下雨时,湿度会高一些;晴天时,湿度会略低一些
因此我们可以根据这一点来判断天气,下面是这次实践的4大步骤:
01 使用Arduino获取温度与湿度数据
获取数据首先需要一些硬件:
Arduino UNO开发板(其他型号的也ok)
DS18B20测温模块
DHT11湿度模块(自带测温模块,但是精度没有DS18B20高)
如果没有的话,我们也可以通过网络爬虫抓取中国天气网当前时段所有城市的天气数据(python+xpath)。
有了硬件以后我们便可以开始了,首先是连线:
![ed74c5b67d7a0e12491a78b5c13e7dcd.png](https://i-blog.csdnimg.cn/blog_migrate/55ce53b0db094fba36028ddf7783dd09.jpeg)
连线方式很简单,首先GND表示接地,接到开发板上任意的GND即可
VCC可以理解为电源,开发板上有3.3V和5V两种,接到哪一个都行
剩下的就是一些数据传输的接口了:
这里有一排接口,随便接哪个都OK的(请自行忽略那个帽子掉了的杜邦线)
接下来我们打开Arduino的IDE,导入库及定义引脚
#include #define ONE_WIRE_BUS 4 //1-wire数据总线连接在IO4OneWire oneWire(ONE_WIRE_BUS); //声明DallasTemperature sensors(&oneWire); //声明#include //引用dht11库文件,使得下面可以调用相关参数#define DHT11PIN 2 //定义温湿度针脚号为2号引脚dht11 DHT11; //实例化一个对象
初始化设置
void setup(void){ Serial.begin(9600); Serial.println(""); sensors.begin(); //初始化总线 sensors.setWaitForConversion(false); //设置为非阻塞模式 pinMode(DHT11PIN,OUTPUT); //定义湿度模块输出口}
循环体
unsigned long previousMillis = 0; //毫秒时间记录const long interval = 5000; //时间间隔void loop(void){ //以下段落相当于每秒读取前次温度,并发起新一次温度转换 unsigned long currentMillis = millis(); //读取当前时间 int chk = DHT11.read(DHT11PIN); //将读取到的值赋给chk int tem=(float)DHT11.temperature; //将温度值赋值给tem int hum=(float)DHT11.humidity; //将湿度值赋给hum if (currentMillis - previousMillis >= interval) //如果和前次时间大于等于时间间隔 { previousMillis = currentMillis; //更新时间记录 float tempC = sensors.getTempCByIndex(0); //获取索引号0的传感器摄氏温度数据 if (tempC != DEVICE_DISCONNECTED_C) //如果获取到的温度正常 { Serial.print("temputer:"); Serial.print(tempC); Serial.print("℃"); Serial.print(","); } sensors.requestTemperatures(); //发起新的温度转换// Serial.print("Tempeature:"); //打印出Tempeature:// Serial.println(tem); //打印温度结果 Serial.print("humidity:"); //打印出Humidity: Serial.print(hum); //打印出湿度结果 Serial.print("%"); //打印出% } delay(5000);}
下面是输出结果:
很好,现在已经可以获取温度和湿度数据了!
02 使用正则表达式清洗数据并保存到MySQL
这时我们需要用到python,先来读取以下串口的数据:
import serialserialPort = "COM6" #串口baudRate = 9600 #波特率ser = serial.Serial(serialPort, baudRate, timeout=0.5)print("参数设置:串口=%s ,波特率=%d" % (serialPort, baudRate))while True: str = ser.readline().decode('utf-8') if str.strip()!='': print(str)
这里设置了一个条件判断,不为空行时才输出,不然输出时会有很多空行
输出时,带有一些文字,这时我们用正则表达式处理,把文字去掉,只留数值加上符号:
先把逗号前面的内容捕获,然后把temputer以及冒号出去,最后把最后面的逗号也除去即可:
temputer = re.findall("[\S]+,",str)temputer = re.sub(r'temputer:', "",temputer[0])temputer = re.sub(r',', "",temputer)
湿度的处理方法同上:
humidity = re.findall("humidity:[\S]+",str)humidity = re.sub(r'humidity:', "", humidity[0])
下面我们只需要把这些数据存到数据库即可,先进入MySQL建个表:
CREATE TABLE `rain` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `temputer` CHAR(10) DEFAULT NULL, `humidity` CHAR(10) DEFAULT NULL, `updata_time` CHAR(20) DEFAULT NULL, PRIMARY KEY (`id`))
设置4个属性,分别是id,温度,湿度以及更新时间,下面我们用python把数据存进去:
连接数据库
connection = pymysql.connect(host='localhost', port=3306, user='root', password='root', db='arduino_1', charset='utf8')cursor = connection.cursor()print("已成功连接至数据库!")
存入数据
sql = 'insert into table1(temputer,humidity,updata_time)VALUES(%s,%s,%s)'cursor.execute(sql,[temputer,humidity,updata_time])connection.commit()#connection.close()
connection.close()请自行放在循环体外,数据全部存入后再执行该条语句
来看下数据表:
因为是每5秒获取一次数据,所以变化不大,但是如果放一天,还是能看出变化的:
SELECT * FROM table1 GROUP BY table1.`humidity`
可以看出,从早上到中午,温度越来越高,而湿度是越来越低
03 构建SVM分类器并训练模型
这里我们需要用到一个机器学习库sklearn:
import numpy as npfrom sklearn import svmfrom sklearn import model_selection
创建它很简单:
def classifier(): # SVM分类器构建 clf = svm.SVC(C=0.5, #误差项惩罚系数,默认值是1 kernel='linear', #线性核 kenrel="rbf":高斯核 decision_function_shape='ovr') #决策函数 return clf
难就难在我们怎么导入数据?
这里我手动对数据做了处理,添加上了标签:
数据量太大,就不全部展示了哈哈哈,简单介绍一下,这里有四个标签:
Sunny
Cloudy
Rainy
Snowy
为了便于数据加载,这里我们把标签转换成数值:
def weather_type(s): # 将字符串转为整型,便于数据加载 weather = {b'Sunny':0, b'Cloudy':1, b'Rainy':2, b'Snowy':3} return weather[s]
下面我们处理好的数据读取进来:
def load_data(): #加载数据 data_path = r'F:\csdn\arduino判断天气\weather_data.csv'#数据文件的路径 data = np.loadtxt(open(data_path,'r',encoding='utf-8'), delimiter=',', #数据分隔符 converters={3:weather_type}) #将第4列使用函数weather_type进行转换 # print(data) # print(data.shape) #数据分割 x, y = np.split(data, #要切分的数组 (3,), #沿轴切分的位置,第3列开始往后为y axis=1) #代表纵向分割,按列分割 x = x[:, 1:3] #在X中我们取前两列作为特征,为了后面的可视化。x[:,0:4]代表第一维(行)全取,第二维(列)取0~2 # print(x) x_train,x_test,y_train,y_test=model_selection.train_test_split(x, #所要划分的样本特征集 y, #所要划分的样本结果 random_state=1, #随机数种子 test_size=0.3) #测试样本占比 # print(y_train) return x_train,x_test,y_train,y_test
有了数据以后,就可以开始训练了:
def train(clf,x_train,y_train): clf.fit(x_train, #训练集特征向量 y_train.ravel()) #训练集目标值
计算一下各项指标:
def show_accuracy(test, result, tip): acc = test.ravel() == result.ravel() print('%s Accuracy:%.3f' %(tip, np.mean(acc)))def print_accuracy(clf,x_train,y_train,x_test,y_test): #分别打印训练集和测试集的准确率 score(x_train,y_train):表示输出x_train,y_train在模型上的准确率 print('trianing prediction:%.3f' %(clf.score(x_train, y_train))) print('test data prediction:%.3f' %(clf.score(x_test, y_test))) #原始结果与预测结果进行对比 predict()表示对x_train样本进行预测,返回样本类别 show_accuracy(clf.predict(x_train), y_train, 'traing data') show_accuracy(clf.predict(x_test), y_test, 'testing data')
最后在主函数里整体调用:
def main(): clf = classifier() x_train,x_test,y_train,y_test = load_data()[0],load_data()[1],load_data()[2],load_data()[3] train(clf,x_train,y_train) print_accuracy(clf,x_train,y_train,x_test,y_test)if __name__ == '__main__': main()
来看一下准确率:
接近100%了,看来模型效果不错,下面我们来实际测试一下
04 把模型应用到Arduino实时检测天气上
def main(): clf = classifier() x_train,x_test,y_train,y_test = load_data()[0],load_data()[1],load_data()[2],load_data()[3] train(clf,x_train,y_train) print_accuracy(clf,x_train,y_train,x_test,y_test) data_test = (-5.23,70) #input temputer and humidity data_test = np.array(data_test).reshape(1, -1) result = ['Sunny', 'Cloudy', 'Rainy', 'Snowy'] test = clf.predict(data_test) print(50*"-") print("The current weather is {}".format(result[int(test[0])]))if __name__ == '__main__': main()
这是最基础版的,下面我们把Arduino返回的数据导入:
def main(): serialPort = "COM6" # 串口 baudRate = 9600 # 波特率 ser = serial.Serial(serialPort, baudRate, timeout=0.5) # print("参数设置:串口=%s ,波特率=%d" % (serialPort, baudRate)) clf = classifier() x_train,x_test,y_train,y_test = load_data()[0],load_data()[1],load_data()[2],load_data()[3] train(clf,x_train,y_train) print_accuracy(clf,x_train,y_train,x_test,y_test) while True: str = ser.readline().decode('utf-8') if str.strip()!='': print(50*"-") print(str) temputer = re.findall("[\S]+,",str) temputer = re.sub(r'temputer:', "",temputer[0]) temputer = re.sub(r'℃,', "",temputer) humidity = re.findall("humidity:[\S]+",str) humidity = re.sub(r'humidity:', "", humidity[0]) humidity = re.sub(r'%', "", humidity) data_test = (temputer,humidity) #input temputer and humidity data_test = np.array(data_test).reshape(1, -1) result = ['Sunny', 'Cloudy', 'Rainy', 'Snowy'] test = clf.predict(data_test) print("The current weather is {}".format(result[int(test[0])])) ser.close()if __name__ == '__main__': main()
结合了前面几部分的内容:
这样便可以实时地输出天气结果了!
?️?️?️
读完上文,你可能会有疑问,如何成为柴火认证会员?
申请柴火认证会员,目前有两条渠道:
如果你有技术背景,可通过提交项目直接申请认证;
如果你是技术小白,欢迎报名参加『柴火新一代信息技术』培训,通过结业项目进行认证;
写在最后-文末小广告
特大好消息!『柴火新一代信息技术』硬件开发入门首期培训班(开班时间:5月16-17日,周末),已经开始招生啦(点击了解详情)!通过这个培训,你可以:
通过课程设计的70%实操,动手造物,搭建项目原型,入门硬件开发
三证加持,拿到柴火创客空间颁发的培训证书&国家工信部教育与考试中心颁发的专项技术中级证书,以及柴火认证会员证书
背靠柴火近10年国际创客社区资源积累,融入国际创客社区圈子
点击上图,前往了解更多培训招生详情
----END----
Chaihuo x.factory|深圳,河北