Funpack第九期-基于SensorTile.box的环境监测工具
使用SensorTile.box 立方体较大的四个面,实现四个不同的功能,如: · 面1,测量桌面倾斜程度; · 面2,测量温度; · 面3,测量湿度; · 面4,测量气压; 注:需使用串口工具对数据进行可视化显示
标签
嵌入式系统
网络与通信
yearnext
更新2021-06-24
643

内容介绍

funpack9 项目说明文档

我是小易,在智能家居领域从事电子产品的开发工作,目前正在进行环境信息采集方向的相关工作

 

一、功能介绍

如右图所示,使用SensorTile.box 立方体较大的四个面,实现四个不同的功能,如:

FundthnViy-BjfduztpkbLegLR64

  • 面1,测量桌面倾斜程度;
  • 面2,测量温度;
  • 面3,测量湿度;
  • 面4,测量气压;

注:需使用串口工具对数据进行可视化显示

二、开发环境介绍

本项目使用SensorTile.box套件进行开发,SensorTile.box具有丰富的传感器以满足我们对环境检测的要求,板载传感器如下:

  • 数字温度传感器(STTS751)
  • 六轴惯性测量单元(LSM6DSOX)
  • 三轴加速度计(LIS2DW12和LIS3DHH)
  • 三轴磁力计(LIS2MDL)
  • 高度计/压力传感器(LPS22HH)
  • 麦克风/音频传感器(MP23ABS1)
  • 湿度传感器(HTS221)
  实现思路

本项目通过SensorTile.box采集环境数据,并将采集到的数据由VCom通道发送给PC端,PC端通过上位机软件显示实时的环境信息以及数据变化曲线

设计步骤
  1. 通过Algobuilder软件进行传感器配置以及算法,并生成IAR工程
  2. 通过IAR(IAR8.50.9)软件打开工程,增加与上位机通讯的协议代码,并修改部分与之冲突的通讯方式
  3. 通过Algobuilder软件进行烧录程序
  4. 通过Python(3.8.10)开发PC端上位机软件,实现通讯协议以及环境数据可视化
  5. 连接电脑进行环境数据可视化演示
三、代码介绍Algobuilder关键程序介绍

项目要求通过不同的面来采集不同的环境数据,因此我们需要通过算法获取当前SensorTile.box处于哪一个面,经过不断调试验证,最终我们通过解析加速度传感器采集到的运动数据来判定SensorTile.box当前处于哪一个面,在此过程中我们参考了官方例程Example03_Tilt_Measurement.xml、Example08_6D_Detection.xml,并做了些许精简优化,相关代码如下所示:

FrKP-5hjR72xJUfC0c7rPit-y9gO

当前角度计算方式同上,相关代码如下所示:

Fqe63ClyMljYWrQrl5RY1wwmVoR6

当前温度、湿度、其他则需要将浮点数转换为整数以方便数据可视化,相关代码如下所示:

FvyG96bBWSLhHqFK3A22f26lq8Nh

SensorTile.box关键代码介绍

由于SensorTile.box支持虚拟串口,因此我们可以将当前采集到的数据通过虚拟串口发送给PC端用于图形显示。

在algo_builder.c文件下增加以下代码,用于输出当前数据信息

#include "stddef.h"
#include "stdarg.h"
#include "string.h"
#include "stdio.h"
#include "vcom.h"
void abLog(char *str, ...)
{
    va_list list;
    static char abLogTemp[128];
    memset(abLogTemp, 0, sizeof(abLogTemp));
    va_start(list, str);
    uint32_t len = vsprintf((char *)abLogTemp, str, list);
    va_end(list);

    VCOM_write(abLogTemp, len);
}

在AB_Handler函数中调整以下代码,输出当前数据信息

void AB_Handler(void)
{
	Dec_To_Rad_1_out[0] = (3.14159265f * Input_Value_Float_2_out[0]) / 180.0f;
	Sin_1_out[0] = sinf(Dec_To_Rad_1_out[0]);
	Sensor_Hub_Handler(&Sensor_Hub_1_out);
	Accelero_Sensor_GetData(Sensor_Hub_1_out, Acceleration_g_1_data);
	Demux_3_float(Acceleration_g_1_data, DummyNodeFloat, Demux_Float_1_out2, Demux_Float_1_out3);
	if (Demux_Float_1_out2[0] > Sin_1_out[0]) Greater_than_2_out[0] = 1; else Greater_than_2_out[0] = 0;
	if (Demux_Float_1_out3[0] > Sin_1_out[0]) Greater_than_3_out[0] = 1; else Greater_than_3_out[0] = 0;
	Multiply_1_out[0] = Sin_1_out[0] * Constant_Float_1_out[0];
	if (Demux_Float_1_out2[0] < Multiply_1_out[0]) Less_than_2_out[0] = 1; else Less_than_2_out[0] = 0;
	if (Demux_Float_1_out3[0] < Multiply_1_out[0]) Less_than_1_out[0] = 1; else Less_than_1_out[0] = 0;
	Mux_4_int(Greater_than_3_out, Less_than_2_out, Less_than_1_out, Greater_than_2_out, Mux_Int_2_out);
	Humidity_Sensor_GetData(Sensor_Hub_1_out, Humidity_percent_1_data);
	Float_To_Int_2_out[0] = (int32_t) Humidity_percent_1_data[0];
	Temperature_Sensor_GetData(Sensor_Hub_1_out, Temperature_C_1_data);
	Float_To_Int_1_out[0] = (int32_t) Temperature_C_1_data[0];
	Demux_3_float(Acceleration_g_1_data, Demux_Float_2_out1, Demux_Float_2_out2, Demux_Float_2_out3);
	MovingAverage(Demux_Float_2_out3, Moving_Average_2_out, 50, Mem1, Mem2);
	Square_2_out[0] = pow(Moving_Average_2_out[0], 2);
	MovingAverage(Demux_Float_2_out2, Moving_Average_3_out, 50, Mem3, Mem4);
	Square_1_out[0] = pow(Moving_Average_3_out[0], 2);
	Add_2_out[0] = Square_1_out[0] + Square_2_out[0];
	Square_Root_1_out[0] = sqrt(Add_2_out[0]);
	MovingAverage(Demux_Float_2_out1, Moving_Average_1_out, 50, Mem5, Mem6);
	Arctan2_3_out[0] = atan2f(Moving_Average_1_out[0], Square_Root_1_out[0]);
	Rad2Dec_3_out[0] = (180.0f * Arctan2_3_out[0]) / 3.14159265f;
	Float_To_Int_4_out[0] = (int32_t) Rad2Dec_3_out[0];
	Pressure_Sensor_GetData(Sensor_Hub_1_out, Pressure_hPa_1_data);
	Float_To_Int_3_out[0] = (int32_t) Pressure_hPa_1_data[0];
	Mux_4_int(Float_To_Int_4_out, Float_To_Int_1_out, Float_To_Int_2_out, Float_To_Int_3_out, Mux_Int_3_out);
	uint32_t index = 1;
    if (Mux_Int_2_out[0] == 1)
	{
	    to4dBoxGraph_1_out[0] = Mux_Int_3_out[0];
        index = 1;
	}
	else if (Mux_Int_2_out[1] == 1)
	{
	    to4dBoxGraph_1_out[0] = Mux_Int_3_out[1];
        index = 2;
	}
	else if (Mux_Int_2_out[2] == 1)
	{
	    to4dBoxGraph_1_out[0] = Mux_Int_3_out[2];
        index = 3;
	}
	else if (Mux_Int_2_out[3] == 1)
	{
	    to4dBoxGraph_1_out[0] = Mux_Int_3_out[3];
        index = 4;
	}
	else
	{
	    to4dBoxGraph_1_out[0] = Mux_Int_3_out[1];
        index = 2;
	}
	Square_3_out[0] = pow(Moving_Average_1_out[0], 2);
	Add_3_out[0] = Square_3_out[0] + Square_1_out[0];
	Square_Root_3_out[0] = sqrt(Add_3_out[0]);
	Arctan2_1_out[0] = atan2f(Moving_Average_2_out[0], Square_Root_3_out[0]);
	Rad2Dec_1_out[0] = (180.0f * Arctan2_1_out[0]) / 3.14159265f;
	Add_1_out[0] = Square_3_out[0] + Square_2_out[0];
	Square_Root_2_out[0] = sqrt(Add_1_out[0]);
	Arctan2_2_out[0] = atan2f(Moving_Average_3_out[0], Square_Root_2_out[0]);
	Rad2Dec_2_out[0] = (180.0f * Arctan2_2_out[0]) / 3.14159265f;
	Mux_3_float(Rad2Dec_3_out, Rad2Dec_2_out, Rad2Dec_1_out, Mux_Float_2_out);
//	Display_Update(Acceleration_g_1_data, &display_info_list[1]);
//	Display_Update(Mux_Float_2_out, &display_info_list[2]);
//	Display_Update(to4dBoxGraph_1_out, &display_info_list[3]);
//	Display_Update(Mux_Int_3_out, &display_info_list[4]);
//	Display_Update(Mux_Int_2_out, &display_info_list[5]);
    
    abLog("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", index, 
                                                   Mux_Int_2_out[0], Mux_Int_2_out[1], Mux_Int_2_out[2], Mux_Int_2_out[3],
                                                   (int32_t)Mux_Float_2_out[0], (int32_t)Mux_Float_2_out[1], (int32_t)Mux_Float_2_out[2], 
                                                   Mux_Int_3_out[0], Mux_Int_3_out[1], Mux_Int_3_out[2], Mux_Int_3_out[3]);
}

 

PC端关键代码介绍

PC端软件基于PyQt5开发,通过Qt Creator软件设计UI样式并通过pyuic5工具将Qt的.ui文件转换为python的.py文件

工作流程如下所示:

  1. 初始化
    class boxScanGui(QtWidgets.QWidget, Ui_scan):
        def __init__(self):
            super().__init__()
    
            # UI 初始化
            self.setupUi(self)
            self.showMaximized()
    
            # 信号槽初始化
            self.signalSoltInit()
    
            # 绘图初始化
            self.graphInit()
    
            # 串口初始化
            self.comInit()

 

  1. 串口接收,解析数据
    # 串口接收处理
    def port_recv(self):
        recvLine = []
        while True:
            if self.com.canReadLine():
                received_data = self.com.readLine()
                recvLine.append(received_data)
            else:
                # print(self.recvLine)
                # self.recvLine.clear()
                break
  1. 更新数据
        # 更新图表显示
        for line in recvLine:
            # # 计算时间
            # timeLineLen = self.timeLine.getLen()
            # 字符串转数字
            lineStr = str(line, encoding='utf-8')
            self.setComRecvInfo(lineStr, line.count())

            dataList = d4box.boxInfoType.line2info(lineStr, self.recvLine)
            if dataList is None:
                return 
            
            self.recvLine.append(dataList.toArray())

            # 显示刷新
            self.showDeviceInfo(dataList)
            self.showGraph(dataList)
  1. 图表刷新
        # 图表显示
        def showGraph(self, info):
            self.graphList[0].setLine1(self.boxData.getData().getGraphData())
            self.graphList[0].setLine2(self.boxData.getAvgData().getGraphData())
四、功能演示 面一

Fj-GH9m09LAsbdAEAXTrXZIX1VDE

面二

FtNxeg46RnWXlRV1J64L26F9YTUn

面三

Fk4vYo04qBHX1th9I9HSavp0HFkG

面四

FiN8MleA1FqkiWUq9uSUzPqJxI0e

 

五.心得体会

本次活动最大的亮点是通过AlgoBuilder使用图形化的编程方式来设计功能算法与逻辑,大大节省了开发时间以及开发效率,不过在我们目前的使用上来看还有一些不足之处,在我们在设计一些较为复杂逻辑的时候就会显得比较混乱,需要拖拽许多逻辑模块以及连线,在设计子模块的时候希望增加更完善的帮助提示,以及代码编辑功能,同时也希望在生成的c文件中增加用户代码区的概念,类似于cube中修改了某些配置后,生成完工程,只修改驱动程序而不修改驱动程序里面的用户程序。当然吐槽了那么多,这个软件还是为我们设计软件提供了一种新的思路,总之这次活动也让我开拓了不少视野也对不同的环境传感器有了新的认识。

附件下载

主机程序.zip
PC端上位机程序源码
板卡程序.7z
板卡程序源码

团队介绍

评论

0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号