作者 | Haor.L
责编 | 王晓曼
出品 | CSDN博客
笔者最近参加了校内的一场物联网开发竞赛,从零开始,踩坑无数,感觉很多时候事情都不像预料的一样发展,离开了美好的IDE,太多事情要在板子上一步步摸索。运行失败还好,运行成功但BUG了,简直不知道从何查起。
但认识了M5Stack简单的线上系统,学习了MQTT,HTTP等数据传输方式,入门Arduino和MIrcopython等开发语言,接触ESP32的板子,感受最深的一点就是,物联网的准入门槛并没有那么高,成本也没有那么高,但这还是一片混沌未开的区域,进场者真的可以大有所为,起码方便自己的日常生活是绰绰有余的。
总的来说,这次物联网入坑,值得!
阅读本文后你将收获:
开发准备
本博客作为学习物联网开发的笔记,也简单的将自己的片上系统作为例程写出来。
M5STACK简介
M5STACK是一款对初学者非常友好的ESP32开发板,可以用Micropython和C编程,也可以用很简单的拖拽式编程,拥有庞大的官方文档,只是国内只在最近开始流行,油管和B站上都有官方的教学视频,也在常常更新,很有创造力的一个产品。
结构上主要分为Core和Unit,Core作为核心控件,Unit作为传感器采集数据。
下图图就是笔者自己做的产品雏形,中间的小屏幕是Core,作为主控,周围有GPS和RFID,摄像头等单元用来采集数据。
设计雏形:
由于所有的M5产品都预设了乐高块,所有你可以把他们拼在乐高模组上,油管上还有不少人用它做乐高机器人,确实是很有创意的一款产品,颜值也不错,所以笔者选择它用来开发。
环境配置
UIFlow环境
在线编程地址:UIFlow
前几天GIthub发布了远程编译器Codespace,可以看出远程编译确实是大势所趋。
这里不得不说UIFlow把物联网的门槛大大降低了,笔者配置ESP-IDF用了将近一天,而使用UIFlow可以免去一切环境配置的痛苦。
支持拖拽编程,可视化UI设计,自带例程,确实是良心产品。
ESP-IDF环境
方法一
笔者配置ESP-IDF工具链时,一开始是使用Windows系统的工具安装器。
ESP-IDF 工具安装器可在“开始”菜单中,创建一个打开ESP-IDF 命令提示符窗口的快捷方式。本快捷方式可以打开 Windows 命令提示符(即 cmd.exe),并运行 export.bat 脚本以设置各环境变量(比如 PATH,IDF_PATH 等)。
(不得不说,这个安装器的健壮性非常差!!)
安装心得:上网技巧+把系统的PATH重新检查一遍,有些卸载残余的PATH会导致玄学问题!
方法二(更推荐)
宇宙第一VS code中有插件 ESPRESSIF
可以更清楚每时每刻在干什么,也更清楚出了BUG去哪里修补。
感知模块
M5开发了很多环境传感器,包括温湿度,人体感应,RFID,摄像头等等,在官方开发文档上也都给出了相关例程和GIthub的源码链接。
笔者自己的项目使用的是RFID、GPS和Camera模块,其中除了Camera只能用ESP-IDF编程,其他单元都支持在UIFlow上在线编程,再加上,Micropython确实比C++舒服太多。
网络连接
Wi-Fi链接
M5Stack已经自己预置了Wi-Fi链接,开机就是,不过在Mircopython里写起来也很简单,下面是一个范例:
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
{
"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
}
]
}
]
}
def http_put_data(data):
#post data into onenet
url=
'http://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
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:/
/api.bilibili.com/x/relation/stat?vmid=
99566555
rfid0 =
unit.get(
unit.RFID,
unit.PORTA)
rfid0 =
unit.get(
unit.RFID,
unit.PORTA)
env0 =
unit.get(
unit.ENV,
unit.PORTA)
#循环判断是否有卡片接近
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)
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=
'http://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
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 object\r\n");
vTaskDelete(
NULL) ;
}
//printf("begin to quirc_resize\r\n");
if (quirc_resize(q, camera_config->width, camera_config->height)<
0)
{
printf(
"quirc_resize err\r\n");
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);
}
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)
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)
更多精彩推荐
![]()
你点的每个“在看”,我都认真当成了喜欢