前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【腾讯连连IoT开发大赛】滑坡灾害监测设备

【腾讯连连IoT开发大赛】滑坡灾害监测设备

原创
作者头像
soffio小宇
修改2021-01-11 09:13:50
1.1K2
修改2021-01-11 09:13:50
举报
文章被收录于专栏:腾讯云IoT

0 Introduction

不得不再次感叹一下,ddl是第一生产力!!

历经了7天的磨练,这个小东西终于被搞定了。

其实是每天下班后,还不想加班的我,回来完成一个小任务后开始躺尸。

看着群里面的大佬们每天在讨论H5啥啥啥的高端的玩意儿,总觉得自己菜的不行……

言归正传,鹅厂这次搞得【腾讯连连IoT开发大赛】不得不说是个特别好玩的东西

其实作为一个滑坡灾害监测设备的话,一般应该是安装在户外,也就是用4G或者NB-IoT的通讯方式更好。

でもね、手头目前缺少设备- -,就用了上次从鹅厂嫖到的TOS_EVB_G0开发板作为核心。

主要设备:

  • TOS_EVB_G0开发板(STM32G0核心+ESP8266通讯模块)
  • MIRAN拉绳式位移传感器
  • SCA100T倾斜度传感器

接下来是个全家福

小东西的全家福
小东西的全家福

先上一个视频

视频内容

1 硬件工作准备

首先做好硬件开发准备工作,把传感器连接到核心板上,写好驱动代码,读取传感器数值。

1.1 位移传感器工作准备

位移传感器是一个三线制传感器,行程1000mm,供电5-10V(实测3V3工作正常,反正是个滑动变阻器……)

传感器基本上是线性的,所以用ADC读取后,可以直接用公式进行转换

位移传感器的接线
位移传感器的接线

输出端口接到ADC1上,然后在软件中对ADC1进行配置

代码语言:c
复制
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.LowPowerAutoPowerOff = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_1CYCLE_5;
  hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_1CYCLE_5;
  hadc1.Init.OversamplingMode = DISABLE;
  hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  

然后驱动ADC1,读取数值,将其转换成实际位移

代码语言:c
复制
//读取ADC的值,数据存放在param_dis_adc
HAL_ADC_Start(&hadc1);
HAL_Delay(1000);
printf("Distance:\r\n");
//获取adc的值
param_dis_adc=HAL_ADC_GetValue(&hadc1);
printf("adc value %d \r\n", param_dis_adc);
		
//将ADC的值转换为位移量
adcConvertedDist =(double)param_dis_adc*1000/4096;
printf("dist value %.2f mm \r\n", adcConvertedDist);

1.2 倾斜度传感器工作准备

倾斜度传感器选用的是SCA100T,这是一个SPI总线的倾斜度传感器

数字式传感器可以有效解决因为噪声导致的干扰

倾斜度传感器SCA100T
倾斜度传感器SCA100T

在驱动了板载硬件SPI后,调试未果,便采用了模拟SPI时序的方法进行驱动

SCA100T—SPI时序图
SCA100T—SPI时序图

以X轴加速度读取为例:

代码语言:c
复制
CS_ONE();
tos_task_delay(4);
CS_ZERO();      //这一阶段开始读数据
tos_task_delay(4);

for(i=0; i<8; i++){								
	Temp = RDA & 0X80;				
	RDA <<= 1;
	//开始加载数据
	if(Temp == 0x80){SDI_ONE();}
	else{SDI_ZERO();}				
	SCLK_ZERO();
	tos_task_delay(4);
	SCLK_ONE();				//时钟给定上升沿
	tos_task_delay(4);
}	
tos_task_delay(4);		
for(i=0; i<11; i++){
	SCLK_ONE();			//数据在下降沿改变
	tos_task_delay(4);	
	SCLK_ZERO();																						
	tos_task_delay(4);
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)){
		ACC_X <<= 1; ACC_X += 1;
	}else{
		ACC_X <<= 1;
	}					
}	
CS_ONE();
tos_task_delay(4);

最后获得到当前的XY轴加速度,然后根据下面的公式进行换算

这里要吐槽一下编辑器不支持mathtype
这里要吐槽一下编辑器不支持mathtype

其中

然后进行一个计算校准

代码语言:c
复制
int miay;
miay = (ACC_Y-1024);
Angle_Y = ((float)miay/1638)*180.0/PI;
printf("Angle_Y = %.2f\r\n", Angle_Y);

这里很奇怪的是,直接做减法后强制类型转换得到的结果值有错误……

所以用了个中间变量做转换……疑惑脸🧐

最后利用串口输出X和Y轴的角度值

代码语言:c
复制
	//读取SCA100T的值,数据存放在Angle_X,Angle_Y
	SCA_GPIO_INIT();
	SCA100T_Angle_X();
	printf("Angle_X = %f\r\n", Angle_X);
	HAL_Delay(1000);
	SCA100T_Angle_Y();
	printf("Angle_Y = %f\r\n", Angle_Y);
	HAL_Delay(1000);

1.3 差值计算

因为灾害预警一般是看其变化的情况,所以在程序里面还有对差值进行计算判断

首先把当前的位移和倾斜度的值存储在一个变量中

然后把每次读到的值和上一次的值求差值计算

代码语言:c
复制
//求取与上次位移量的差值
minus = abs( adcConvertedDist - lastdist);
printf("dist minus value %.2f mm \r\n", minus);
//求取与上次角度的差值
minusangx = fabs(Angle_X - lastangx);
minusangy = fabs(Angle_Y - lastangy);
printf("anglex minus value %.2f rad \r\n", minusangx);
printf("angley minus value %.2f rad \r\n", minusangy);
//刷新上一次的寄存器
lastdist = adcConvertedDist;
lastangx = Angle_X;
lastangy = Angle_Y;

1.4 预警判断

接下来进行差值判断,首先定义报警阈值

代码语言:javascript
复制
//定义报警阈值
#define blue_dist  20
#define yellow_dist  40
#define orange_dist  60
#define red_dist  80
#define blue_ang  3.0
#define yellow_ang  4.0
#define orange_ang  5.0
#define red_ang  6.0
//定义报警变量
char*red_warn_data="red";
char*orange_warn_data="orange";
char*yellow_warn_data="yellow";
char*blue_warn_data="blue";
char*safe_warn_data="safe";
char warn_data[10]={0};
int warn_num;

报警一共分为四个等级(对应报警值为模拟,实际使用时会根据现场情况进行调整)

等级

对应数值

蓝色警报

位移差值>20mm 或 角度变化>3°

黄色警报

位移差值>40mm 或 角度变化>4°

橙色警报

位移差值>60mm 或 角度变化>5°

红色警报

位移差值>80mm 或 角度变化>6°

然后开始进行条件判断

代码语言:c
复制
if(minus>blue_dist||minusangx>blue_ang||minusangy>blue_ang) {
	if(minus>yellow_dist||minusangx>yellow_ang||minusangy>yellow_ang){
		if(minus>orange_dist||minusangx>orange_ang||minusangy>orange_ang){
			if(minus>red_dist||minusangx>red_ang|minusangy>red_ang)	{
				warn_num = 4;
				sprintf(warn_data,"%s",red_warn_data);
			}else{
				warn_num = 3;
				sprintf(warn_data,"%s",orange_warn_data);
			}					
		}else{
			warn_num = 2;
			sprintf(warn_data,"%s",yellow_warn_data);
		}
	}else{
		warn_num = 1;
		sprintf(warn_data,"%s",blue_warn_data);
	}
	printf("%s,warning!\r\n",warn_data);
}else{
	warn_num = 0;
	sprintf(warn_data,"%s",safe_warn_data);
}

1.5 调试结果

拉动位移传感器,改变传感器的值,主控自动进行报警操作

2 云平台准备

准备好硬件以后,就开始在云平台构建物模型了

首先在腾讯云物联网开发平台中依次点击“产品开发”—“新建产品”

然后依次填写信息,因为这里我才用的鹅厂开发板板载的ESP8266,所以通信方式选择WiFi

然后点击卡片进入

2.1 定义数据模板

接下来定义数据模板,可以选择导入json的方式,也可以一步一步自己添加

下面是我的产品所需要的属性,和其对应的json信息

代码语言:json
复制
{
  "version": "1.0",
  "profile": {
    "ProductId": "E0UJSCFA1X",
    "CategoryId": "1"
  },
  "properties": [
    {
      "id": "dist",
      "name": "位移值",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "float",
        "min": "0",
        "max": "1000",
        "start": "0",
        "step": "0.01",
        "unit": "mm"
      },
      "required": false
    },
    {
      "id": "warning",
      "name": "报警事件",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "string",
        "min": "0",
        "max": "2048"
      },
      "required": false
    },
    {
      "id": "warn_num",
      "name": "等级数据",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "enum",
        "mapping": {
          "0": "safe",
          "1": "blue",
          "2": "yellow",
          "3": "orange",
          "4": "red"
        }
      },
      "required": false
    },
    {
      "id": "angx",
      "name": "X角度",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "float",
        "min": "-90",
        "max": "90",
        "start": "0",
        "step": "0.001",
        "unit": "°"
      },
      "required": false
    },
    {
      "id": "angy",
      "name": "Y角度",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "float",
        "min": "-90",
        "max": "90",
        "start": "0",
        "step": "0.001",
        "unit": "°"
      },
      "required": false
    },
    {
      "id": "int_time",
      "name": "采集间隔时间",
      "desc": "",
      "mode": "rw",
      "define": {
        "type": "enum",
        "mapping": {
          "1": "间隔10s采集",
          "2": "间隔20s采集",
          "3": "间隔30s采集",
          "4": "间隔40s采集"
        }
      },
      "required": false
    }
  ],
  "events": [],
  "actions": []
}

那么简单来说一下吧

2.1.1 浮点型数据

在我的模块中,位移和倾斜度的值,都属于浮点型数据,所以我可以新建浮点型数据属性,来读取设备上传的值

例如你的变量范围是-30°~30°的一个数据范围,就可以如上新建数据属性

这里值得注意的是,标识符一定要和数据上报的字符串中的数据一致

例如我的倾斜度X上报的数据如下:

代码语言:javascript
复制
#define REPORT_ANGX_DATA_TEMPLATE  "{\\\"method\\\":\\\"report\\\"\\,\\\"clientToken\\\":\\\"00000001\\\"\\,\\\"params\\\":{\\\"angx\\\":%.3f}}"

那么我的标识符就要保持一致

2.1.2 字符串型数据

因为一开始我想直接通过MCU判断当前是属于什么警报类型,直接上传到云平台,所以建立了一个如下的数据模板

代码语言:javascript
复制
#define REPORT_WARNING_DATA_TEMPLATE "{\\\"method\\\":\\\"report\\\"\\,\\\"clientToken\\\":\\\"00000001\\\"\\,\\\"params\\\":{\\\"warning\\\":\\\"%s\\\"}}"

上报的数据如下

代码语言:c
复制
char*red_warn_data="red";
char*orange_warn_data="orange";
char*yellow_warn_data="yellow";
char*blue_warn_data="blue";
char*safe_warn_data="safe";
char warn_data[10]={0};

通过测试,的确服务器可以收到相应的报警数据

但是腾讯连连竟然不支持字符串的显示!!!!!!!

2.1.3 枚举类型数据

在极度的气愤和无奈下ヾ(≧へ≦)〃

咨询了鹅厂的工程师,他们给出的建议是采用枚举类型

果然柳暗花明又一村!!

新建枚举类型数据,然后把每个报警值对应到一个数字(见1.4部分)

新建一个数据模板

代码语言:javascript
复制
#define REPORT_WARNING_NUM_TEMPLATE "{\\\"method\\\":\\\"report\\\"\\,\\\"clientToken\\\":\\\"00000001\\\"\\,\\\"params\\\":{\\\"warn_num\\\":\\\"%d\\\"}}"

这样就会获得一个值,然后云平台会根据这个值来对应报警类型。

2.2 交互开发

点击交互开发按钮

在下面的属性中找到面板配置

这里就是每天看各位大佬讨论的H5开发了,对于我一个硬件开发者来说,属实有点点难度,暂且先略过

目前采用的是标准面板

这里可以把每一个值选择其显示的方式

比如浮点数的变量会自动匹配一个棒图

那么这个里面为了让当前状态更明显,所以我把报警等级放做大图标,其他的数据都作为小图标看数值即可。

2.3 设备上行数据调试

其实接下来就基本大功告成了,剩下的就是配置软硬件接口部分了

首先点击设备调试,找到对应的设备,点击调试

当然,一开始你可能没有设备,那么就点击新建设备

输入设备名称,点击保存

点击设备信息,然后就可以看到你的一些关键信息

然后在硬件程序中配置你的这几个信息

代码语言:javascript
复制
// 物联网开发平台设备信息
#define PRODUCT_ID              "E0U***A1X"
#define DEVICE_NAME             "geo_iot"
#define DEVICE_KEY              "wj38L3****uWFm3A=="

在程序中订阅topic

代码语言:javascript
复制

// 3. 设置设备信息:产品ID,设备名,设备密钥
strncpy(dev_info.product_id, product_id, PRODUCT_ID_MAX_SIZE);
strncpy(dev_info.device_name, device_name, DEVICE_NAME_MAX_SIZE);
strncpy(dev_info.device_serc, key, DEVICE_SERC_MAX_SIZE);
tos_tf_module_info_set(&dev_info, TLS_MODE_PSK);
// 4. 连接IoT Explorer
 mqtt_param_t init_params = DEFAULT_MQTT_PARAMS;
 if (tos_tf_module_mqtt_conn(init_params) != 0) {
     printf("module mqtt conn fail\n");
 } else {
     printf("module mqtt conn success\n");
 }
 if (tos_tf_module_mqtt_state_get(&state) != -1) {
     printf("MQTT: %s\n", state == MQTT_STATE_CONNECTED ? "CONNECTED" : "DISCONNECTED");
 }
// 5. 订阅数据模板 topic
 size = snprintf(report_reply_topic_name, TOPIC_NAME_MAX_SIZE, "$thing/down/property/%s/%s", product_id, device_name);
 if (size < 0 || size > sizeof(report_reply_topic_name) - 1) {
     printf("sub topic content length not enough! content size:%d  buf size:%d", size, (int)sizeof(report_reply_topic_name));
 }
 if (tos_tf_module_mqtt_sub(report_reply_topic_name, QOS0, default_message_handler) != 0) {
     printf("module mqtt sub fail\n");
 } else {
     printf("module mqtt sub success\n");
 }
 memset(report_topic_name, sizeof(report_topic_name), 0);
 size = snprintf(report_topic_name, TOPIC_NAME_MAX_SIZE, "$thing/up/property/%s/%s", product_id, device_name);
 if (size < 0 || size > sizeof(report_topic_name) - 1) {
     printf("pub topic content length not enough! content size:%d  buf size:%d", size, (int)sizeof(report_topic_name));
 }

然后定义上报数据类型

代码语言:javascript
复制
#define REPORT_ALL_TEMPLATE	"{\\\"method\\\":\\\"report\\\"\\,\\\"clientToken\\\":\\\"00000001\\\"\\,\\\"params\\\":{\\\"dist\\\":%.3f\\,\\\"angx\\\":%.3f\\,\\\"angy\\\":%.3f\\,\\\"warning\\\":\\\"%s\\\"\\,\\\"warn_num\\\":%d}}"

// 1. 构造上报的JSON
snprintf(payload, sizeof(payload), REPORT_ALL_TEMPLATE, adcConvertedDist,Angle_X,Angle_Y,warn_data,warn_num);
// 2. 向数据模板topic发布信息
if (tos_tf_module_mqtt_pub(report_topic_name, QOS0, payload) != 0) {
    printf("module mqtt pub fail\n");
    break;
} else {
    printf("module mqtt pub success\n");
}		

点击在线调试

就可以实时看到你的设备上报的数据了

2.4 设备下行数据调试

定义一个读写数据

然后在腾讯连连小程序中,就会出现一个可以修改的数据变量

在MCU程序中编写对数据的读取解析

首先看一下平台会返回到的数据payload

代码语言:javascript
复制
topic:$thing/down/property/E0UJSCFA1X/geo_iot
payload:"{"method":"control","clientToken":"clientToken-X6rxefd-H","params":{"int_time":1}}"

然后对其进行解析

代码语言:c
复制
static void default_message_handler(mqtt_message_t* msg)
{
	cJSON *root;
	cJSON *params;
	cJSON *token;
	cJSON *method;
	cJSON *int_time;

	int int_time1;

    printf("callback:\r\n");
    printf("---------------------------------------------------------\r\n");
    printf("\ttopic:%s\r\n", msg->topic);
    printf("\tpayload:%s\r\n", msg->payload);
    printf("---------------------------------------------------------\r\n");

	// 1. 解析从云端收到的控制信息,示例控制信息为
	//"{"method":"control","clientToken":"clientToken-Xx-N_enad","params":{"int_time":0}}"
	root = cJSON_Parse(msg->payload +1);
	if (!root){
		printf("Invalid json root\r\n");
		return;
	}

	// 2. 解析出method
	method = cJSON_GetObjectItem(root, "method");
	if (!method){
		printf("Invalid json method\r\n");
		cJSON_Delete(root);
		return;
	}

	// 3. 仅处理云端下发的 control 数据,report_reply暂不处理
	if (0 != strncmp(method->valuestring, "control", sizeof("control") - 1)){
		cJSON_Delete(root);
		return;
	}

	// 4. 解析出params
	params = cJSON_GetObjectItem(root, "params");
	if (!params){
		printf("Invalid json params\r\n");
		cJSON_Delete(root);
		return;
	}

	// 1. 解析出int_time
	int_time = cJSON_GetObjectItem(params, "int_time");
	int_time1 = int_time -> valueint;

	// 2. 根据int_time控制时间间隔
	if (1 == int_time1){
		int_time_val = 10000;
		printf("get server data success\r\n");
		printf("int_time_val = 10000\r\n");
	}
	if (2 == int_time1){
		int_time_val = 20000;
		printf("get server data success\r\n");
		printf("int_time_val = 20000\r\n");
	}
	if (3 == int_time1){
		int_time_val = 30000;
		printf("get server data success\r\n");
		printf("int_time_val = 30000\r\n");
	}
	if (4 == int_time1){
		int_time_val = 40000;
		printf("get server data success\r\n");
		printf("int_time_val = 40000\r\n");
	}

	// 4. 设置clientToken回复
	token = cJSON_GetObjectItem(root, "clientToken");
	if (token) {
		strcpy(client_token_cache, token->valuestring);
		is_client_token_received = true;
	}

	cJSON_Delete(root);
}

int_time_val里面存放的是数据采集间隔时间,然后在主循环中编写相应程序

代码语言:javascript
复制
tos_sleep_ms(int_time_val); //根据服务器时间调整间隔

3 数据链路开发

鹅厂的IoT系统中有一个数据流,挺有意思的

左侧选择 数据开发 — 新建数据流

例如我这里 新建一个 警报推送

交互数据里面有输入、处理、输出 三大部分内容

首先添加一个设备数据输入,选择相应产品,然后选择属性

这里的属性就是我们之前定义的数据属性,这里我们选择报警事件

(其实也可以用warn_num,但是这个string类型的数据不能浪费他呀)

添加一个数据过滤,然后加一个条件。

我们一共有四个条件(red、orange、yellow、blue),分别添加四个数据过滤

最下面添加一个输出—公众号推送

然后分别把他们连接起来

然后启用这个数据流

这样的话,我们就可以在腾讯连连 微信公众号中看到报警信息

4 开发感悟

最后再来一句感慨

鹅厂的IoT平台真的是好用,但是为什么string类型数据不能显示(╯▔皿▔)╯

上面的部分代码是腾讯云物联实验室给的示例代码,本来不想贴出来,但是感觉很多人还是在走弯路,所以还是贴出来大家一起参考一下

然后就是关于面板,因为做硬件开发,很少开发前端,发现H5的开发不只是js部分,还需要SDK配置,这个只能说学无止境,展望一下后续吧

腾讯云IoT Explorer平台和TencentOS-tiny简直是提供了太大的开发便利,一个产品利用腾讯IoT平台进行开发,可以大大缩短周期,能够尽快上线!

不过也有不足,这次开发是基于ESP8266进行开发的,我的设备应用场景多在户外,因此可能更需要用4G和NB-IoT来进行s据传输。这次时间仓促,手边没有相应模块,只能先用WiFi调试了,看来接下来还有的事情做~

短时间内堆起了这么一个小家伙,还是没有把预想的功能全部做完,不足之处还请各位看官多多见谅,大家相互交流。

最后,感谢鹅厂的这次活动~

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0 Introduction
  • 1 硬件工作准备
    • 1.1 位移传感器工作准备
      • 1.2 倾斜度传感器工作准备
        • 1.3 差值计算
          • 1.4 预警判断
            • 1.5 调试结果
            • 2 云平台准备
              • 2.1 定义数据模板
                • 2.1.1 浮点型数据
                • 2.1.2 字符串型数据
                • 2.1.3 枚举类型数据
              • 2.2 交互开发
                • 2.3 设备上行数据调试
                  • 2.4 设备下行数据调试
                  • 3 数据链路开发
                  • 4 开发感悟
                  相关产品与服务
                  物联网开发平台
                  腾讯云物联网开发平台(IoT Explorer)是面向智慧生活与产业物联应用的一站式物联网PaaS平台,为各行业用户提供一站式设备智能化服务。平台提供海量设备连接与消息通信能力,基于腾讯连连小程序应用开发能力、音视频能力及AI增值服务,聚合腾讯生态内容能力。提升传统行业设备智能化的效率,降低用户的开发运维成本。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档