笔者最近参加了校内的一场物联网开发竞赛,从零开始,踩坑无数,感觉很多时候事情都不像预料的一样发展,离开了美好的IDE,太多事情要在板子上一步步摸索。运行失败还好,运行成功但BUG了,简直不知道从何查起😓 总的来说,这次物联网入坑,值得! 阅读本文后你将收获: 本博客作为学习物联网开发的笔记,也简单的将自己的片上系统作为例程写出来。 M5STACK是一款对初学者非常友好的ESP32开发板,可以用micropython和C编程,也可以用很简单的拖拽式编程,拥有庞大的官方文档,只是国内只在最近开始流行,油管和b站上都有官方的教学视频,也在常常更新,很有创造力的一个产品。 结构上主要分为Core和Unit,Core作为核心控件,Unit作为传感器采集数据。 下图图就是笔者自己做的产品雏形,中间的小屏幕是Core,作为主控,周围有GPS和RFID,摄像头等单元用来采集数据。 【设计雏形:】 由于所有的M5产品都预设了乐高块,所有你可以把他们拼在乐高模组上,油管上还有不少人用它做乐高机器人~确实是很有创意的一款产品,颜值也不错,所以笔者选择它用来开发。 在线编程地址:UIflow 这里不得不说Uiflow把物联网的门槛大大降低了,笔者配置ESP-IDF用了将近一天,而使用Uiflow可以免去一切环境配置的痛苦。 支持拖拽编程,可视化UI设计,自带例程,确实是良心产品。 笔者配置ESP-IDF工具链时,一开始是使用windows系统的工具安装器 (不得不说,这个安装器的健壮性非常差!!) 宇宙第一VS code中有插件 ESPRESSIF M5开发了很多环境传感器,包括温湿度,人体感应,RFID,摄像头等等,在官方开发文档上也都给出了相关例程和GIthub的源码链接 M5Stack已经自己预置了wifi链接,开机就是,不过在mircopython里写起来也很简单,下面是一个范例 使用mircoython的wifi模块,connect(ssid,password),就可以进入可爱的wifi连接界面了,m5go的封装还是不错的。 IOT模组需要额外配一张NB卡,某宝20就可以拿下一年500m流量,不过笔者没有继续尝试,已经有可爱的M5GO和稳定的wifi,就没探索用3G进行通讯。 接下来介绍物联网的精髓,“联网”,采集到了数据,那数据上报和传输是重中之重。 首先需要创建一个数据流模板,用于接收传过来的数据: 请求方式:POST URL:https://api.heclouds.com/devices/device_id/datapoints 注意:ONENET默认post的数据叫datastreams,参数配置见表: 使用ONENET的模拟API调用可以快速熟悉数据的模式: uiflow里自带了HTTP模块,但是很玄学,很难用 亲测还是很好用的,可能是uiflow自己的json封装比较奇怪? 既然M5STACK可以同时使用多个模组,那么自然也就可以使用模组来控制数据传输: 第一行的rfid0 = unit.get(unit.RFID, unit.PORTA)是指定从PORTA读取RFID的射频信息 有POST就要有GET,这里介绍一个B站大佬“正负加减”的例程,获取自己的粉丝数,里面讲解也很细致,大佬也是老geek了,关注不亏 核心思想是知道哪个key是follow,可以在F5审查源代码找到: UP和DOWN是控制RGB等的函数。 在疫情管控最严格的的时候,经常能看到触目惊心的“寻找x月x日乘坐xxxx的乘客”,如果能追寻乘坐公共交通者的足迹,会给疫情管控带来很大便利。 笔者希望结合GPS,RFID和摄像头功能,做个车载的识别信息-上报信息的小系统。 然而,这个设计一开始就遇到了难题。。.网上购买的测温枪,他的蓝牙数据我无法解包,好像是和腾讯连连有自己的相关配置 既然没办法解析内容,那下面笔者将用ENV单元采集的环境温度代替乘客温度进行收发。 首先声明RFID模块的串口 该段指从A口串入RFID模组 由于笔者同时还需要使用红色串口的ENV单元,因此额外购买了GROVE HUB: 笔者使用循环判断是否有卡片接近,无则显示待机Emoji,有则显示✅ 这里的Emoji模块是先在UIFlow里敲好,再进micropython里查看的😜 HTTP传输在上文已经讲了不少,这里优先介绍GPS的传输 这里请把YOUR-DEVICE-ID替换为自己的数据流中设备编号,参考ONENET手册 UIflow里封装了很好的wifi-connect: 如果你的micropython里没有一键wifi连接,笔者自己也实现了一个: 参考官方例程 这里依赖了太多官方库…建议去代码仓库翻一翻。 上文是ESP32类型的开发板识别代码,可以看到非常繁琐,改起来简直要了老命… 使用Micropython的话,代码就变的可爱多了~ 【此部分使用Maxipy编程】 这里Maxipy的官方文档还给出了修正图像的方法: 如果使用了镜头,画面会有扭曲,需要矫正画面 使用 lens_corr 函数来矫正, 比如 2.8mm, img.lens_corr(1.8) (没事翻一翻这个Maxipy的文档还是很有启发的,大概两小时就能通读一遍) 室内经常没有信号(实测室外也很少有…)因此在传递GPS的时候笔者额外设计了防止无信号的代码. 参赛时间仓促,没能完全搞明白每个引脚的用途,没有好好触摸一遍C和开发板,没有用NB-IOT通讯。没有做蓝牙通讯解包…还是有很多遗憾的,还好设备还在,可以继续探索物联网的神奇。 成品效果:我的M5Stack物联网开发入门和踩坑历程:基于M5STACK和ONENET
但认识了M5Stack简单的线上系统,学习了MQTT,HTTP等数据传输方式,入门Arduino和MIrcopython等开发语言,接触ESP32的板子,感受最深的一点就是,物联网的准入门槛并没有那么高,成本也没有那么高,但这还是一片混沌未开的区域,进场者真的可以大有所为,起码方便自己的日常生活是绰绰有余的
开发准备
M5STACK简介
环境配置
UIflow环境
前几天GIthub发布了远程编译器Codespace,可以看出远程编译确实是大势所趋,
ESP-IDF环境
方法一
ESP-IDF 工具安装器可在“开始”菜单中,创建一个打开 ESP-IDF 命令提示符窗口的快捷方式。本快捷方式可以打开 Windows 命令提示符(即 cmd.exe),并运行 export.bat 脚本以设置各环境变量(比如 PATH,IDF_PATH 等)
安装心得:上网技巧+把系统的PATH重新检查一遍,有些卸载残余的PATH会导致玄学问题方法二(更推荐)
可以更清楚每时每刻在干什么,也更清楚出了BUG去哪里修补
感知模块
笔者自己的项目使用的是RFID、GPS和Camera模块,其中除了Camera只能用ESP-IDF编程,其他单元都支持在uiflow上在线编程,再加上,micropython确实比C++舒服太多~网络连接
Wifi链接
import network SSID="YOUR-WIFI-NAME" PASSWORD="YOUR-WIFI-PASSWORD" wlan=None s=None def connectWifi(ssid,passwd): ''' 连接指定wifi ''' global wlan wlan=network.WLAN(network.STA_IF) wlan.active(True) wlan.disconnect() wlan.connect(ssid,passwd) while(wlan.ifconfig()[0]=='0.0.0.0'): time.sleep(1) return True
NB-IOT
HTTP通讯
笔者觉得HTTP是最好理解,好入门的通讯协议,这里也先介绍这种方法。
建议参考视频:b站:接入中国移动ONENET平台
笔者尝试过诸如阿里云和一些外国的平台,最后发现都不如中国移动专门为物联网开发的ONENET,一来稳定,不用担心服务商跑路,而来阿里云显得太过臃肿,对入门者很不友好,最终选择了ONENET,他的HTTP封装好了很好看的数据流模板,
如:
POST上传数据
创建流模板
发送请求
其中,device_id:需要替换为设备ID
请求实例{ "datastreams": [{ "id": "temperature", "datapoints": [{ "at": "2013-04-22T00:35:43", "value": "bacd" }, { "at": "2013-04-22T00:55:43", "value": 84 } ] }, { "id": "key", "datapoints": [{ "at": "2013-04-22T00:35:43", "value": { "x": 123, "y": 123.994 } }, { "at": "2013-04-22T00:35:43", "value": 23.001 } ] } ] }
其中,URL的device_id,和下面的API_key换成自己设备的,可以在设备列表找到,就可以往自己设备的数据流模板传一个值为3的value。
Micropython用HTTP
这里笔者用micropython自己写了一份HTTP的传输def http_put_data(data): #post data into onenet url='https://api.heclouds.com/devices/'+DEVICE_ID+'/datapoints' values={'datastreams':[{"id":"temperature","datapoints":[{"value":data}]}]} jdata = json.dumps(values) r=urequests.post(url,data=jdata,headers={"api-key":API_KEY}) return r
使用模组交互的数据传输
如:使用RFID卡,控制POST:rfid0 = unit.get(unit.RFID, unit.PORTA) while(True): if rfid0.isCardOn(): rsp = http_put_data(12) emoji0.show_map([[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,1,1,1,1,1,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]], 0xff0000) else: #wlan.disconnect() #wlan.active(False) emoji0.show_map([[0,0,0,1,0,0,0],[0,0,0,1,0,0,0],[0,0,0,1,0,0,0],[0,0,0,1,0,0,0],[0,0,0,1,0,0,0],[0,0,0,1,0,0,0],[0,0,0,1,0,0,0]], 0xff0000) wait(1)
使用HTTP的GET获取b站信息
UIFlow的GET结构:
此处的url是http://api.bilibili.com/x/relation/stat?vmid=99566555
我的片上系统设计全过程
设计初衷
设计方法
具体涉及到二维码识别,RFID识别,GPS获取和HTTP上报。
腾讯连连界面:
既然腾讯连连已经写到那么好了,那就不抢他的饭碗了分模块实现
RFID控制块
rfid0 = unit.get(unit.RFID, unit.PORTA)
【注:M5STACK使用颜色标明了A,B,C三个Grove口,见下图】
上图中RFID的串口是红色,就对应到M5GO左侧的红色接口:
GRIVE HUB
这样就有两个A口了。
访问设置时不需要加以区分,都从PORTA引入:rfid0 = unit.get(unit.RFID, unit.PORTA) env0 = unit.get(unit.ENV, unit.PORTA)
使用Emoji模块做可视化
#循环判断是否有卡片接近 while(True): #熄灭RGB灯 rgb.setBrightness(0) #清空Emoji显示 emoji0.show_map([[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]], 0x000000) #判断是否有卡片接近 if rfid0.isCardOn(): #有卡片接近显示对号 emoji0.show_map([[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,1],[0,0,0,0,0,1,1],[1,0,0,0,1,1,0],[0,1,1,1,1,0,0],[0,0,1,1,0,0,0]], 0x33ff33) #发送RFID读取到的卡片ID rsp_RFID = http_put_RFID((str(rfid0.readUid()))) #完成后指示灯变绿 rgb.setColorAll(0x33ff33) rgb.setBrightness(10) else: #可选是否断开wifi #wlan.disconnect() #wlan.active(False) #等待卡片接近时,Emoji展示"。。。" emoji0.show_map([[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,1,0,1,0,1,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]], 0x000000) wait(1)
HTTP传输块
GPS的命令也是要加“value:”的,形如value:{“lon”:lon,“lat”:lat},这个地方一开始把笔者坑的不轻def http_put_location(lon,lat): ''' 传输地理位置数据点至ONENET平台的location数据流 lon:longitude,经度 lat: latitude,纬度 url:http的post地址 values:请参考https://open.iot.10086.cn/doc/multiprotocol/ 文档中的"HTTP协议上传数据点模块,配置json格式信息" API_KEY:设备发送HTTP请求的证书,请参考https://open.iot.10086.cn/doc/multiprotocol/book/develop/http/api/api-usage.html 文档中的"鉴权说明" ''' url='https://api.heclouds.com/devices/YOUR-DEVICE-ID/datapoints' values={'datastreams':[{"id":"location","datapoints":[{"value":{"lon":lon,"lat":lat}}]}]} jdata = json.dumps(values) r=urequests.post(url,data=jdata,headers={"api-key":API_KEY}) return r
Wi-Fi连接块
wifiCfg.doConnect(SSID, PASSWORD)
def connectWifi(ssid,passwd): ''' 如果您的Micropython不携带WifiCfg.doconnect,请参考本函数 函数作用:连接至名称为SSID,密码为passwd的wifi ''' global wlan wlan=network.WLAN(network.STA_IF) wlan.active(True) wlan.disconnect() wlan.connect(ssid,passwd) while(wlan.ifconfig()[0]=='0.0.0.0'): time.sleep(1) return True
二维码识别块
//拍摄 camera_fb_t* esp_camera_fb_get() { if (s_state == NULL) { return NULL; } if(!I2S0.conf.rx_start) { if(s_state->config.fb_count > 1) { ESP_LOGD(TAG, "i2s_run"); } if (i2s_run() != 0) { return NULL; } } if(s_state->config.fb_count == 1) { xSemaphoreTake(s_state->frame_ready, portMAX_DELAY); } if(s_state->config.fb_count == 1) { return (camera_fb_t*)s_state->fb; } camera_fb_int_t * fb = NULL; if(s_state->fb_out) { xQueueReceive(s_state->fb_out, &fb, portMAX_DELAY); } return (camera_fb_t*)fb; } //二维码识别 void qr_recoginze(void *pdata) { camera_fb_t *camera_config = pdata; if(pdata==NULL) { ESP_LOGI(TAG,"Camera Size err"); return; } struct quirc *q; struct quirc_data qd; uint8_t *image; q = quirc_new(); if (!q) { printf("can't create quirc objectrn"); vTaskDelete(NULL) ; } //printf("begin to quirc_resizern"); if (quirc_resize(q, camera_config->width, camera_config->height)< 0) { printf("quirc_resize errrn"); quirc_destroy(q); vTaskDelete(NULL) ; } image = quirc_begin(q, NULL, NULL); memcpy(image, camera_config->buf, camera_config->len); quirc_end(q); int id_count = quirc_count(q); if (id_count == 0) { quirc_destroy(q); return; } struct quirc_code code; quirc_extract(q, 0, &code); quirc_decode(&code, &qd); dump_info(q); quirc_destroy(q); }
K210的二维码识别
import sensor import image import lcd import time clock = time.clock() lcd.init() sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.set_vflip(1) sensor.run(1) sensor.skip_frames(30) while True: clock.tick() img = sensor.snapshot() res = img.find_qrcodes() fps =clock.fps() if len(res) > 0: img.draw_string(2,2, res[0].payload(), color=(0,128,0), scale=2) print(res[0].payload()) lcd.display(img)
GPS传输块
GPS的http传输函数已经在上文讲了,此处和RFID卡片控制进行结合: if rfid0.isCardOn(): #有卡片接近显示对号 emoji0.show_map([[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,1],[0,0,0,0,0,1,1],[1,0,0,0,1,1,0],[0,1,1,1,1,0,0],[0,0,1,1,0,0,0]], 0x33ff33) #发送RFID读取到的卡片ID rsp_RFID = http_put_RFID((str(rfid0.readUid()))) #防止测试时无信号 if str(gps0.pos_quality) != "1" and str(gps0.pos_quality) != "6": lon=116.39137751349433 lat=39.8969585128568 else: #默认北京 lon=gps0.longitude lat=gps0.latitude try: rsp_LOCATION=http_put_location(float(lon),float(lat)) except: emoji0.show_map([[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,1],[0,0,0,0,0,1,1],[1,0,0,0,1,1,0],[0,1,1,1,1,0,0],[0,0,1,1,0,0,0]], 0xff0000) #传输温度 rsp = http_put_data(env0.temperature) #完成后指示灯变绿 rgb.setColorAll(0x33ff33) rgb.setBrightness(10) else: #可选是否断开wifi #wlan.disconnect() #wlan.active(False) #等待卡片接近时,Emoji展示"。。。" emoji0.show_map([[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,1,0,1,0,1,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]], 0x000000) wait(1)
后记
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算