学习
实践
活动
工具
TVP
写文章
专栏首页腾讯云IoT【IoT应用创新大赛】LoRaWAN在工业互联网中的应用
原创

【IoT应用创新大赛】LoRaWAN在工业互联网中的应用

视频内容
LoRaWAN在工业互联网中的应用.ppt

1、选题背景

工业互联网,是智能制造发展的基础,可以提供共性的基础设施和能力;我国已经将工业互联网作为重要基础设施,为工业智能化提供支撑。

国内智能制造选择是一条“中间路线”,将工业互联网作为重要基础设施,为工业智能化提供支撑。在国内这种道路选择中,工业互联网可能发挥更大的作用。

一方面,国内有着较强的工业制造能力,产业门类齐全,产业链完整,大量的工厂、车间和生产线具备网联化的潜力,但是自动化水平同德国相差较大。

另一方面,国内物联网、人

工智能、云计算、移动互联、大数据等技术在迅速发展,工业互联网同国际水平的差距,明显小于传统的自动化、数控领域。

因此,在智能制造体系中,智慧工厂、智慧车间、智慧产线国内也会重点做,但是其中会加大工业互联网技术的应用,充分利用国内信息化的优势,弥补在自动化等传统领域的短板。

工业互联网对智能制造的支撑作用

利用工业互联网平台,企业能迅速调整供应链,及早转产、复产;即便很多员工无法返岗,智能互联工厂也能正常运转,100%按时完成订单任务;设备维护不会受到交通管制影响,远程诊断基本解决问题……

现实是最好的教科书。越来越多的制造业企业意识到工业互联网已不再是可有可无的“噱头”,而是发展进程中不可或缺的必由之路。

2、方案设计

本方案使用LoRaWAN网络将工业现场中的控制器、电表、以及环境传感器数据上云;实现远程监控、控制功能;在工业现场中,因为大部分设备都是使用的Modbus、CAN总线协议,所以本方案中使用Modbus协议的采集链路;通过Modbus读取工业设备中的数据,然后将数据通过LoRaWAN发送到云端,然后通过小程序进行展示、并且可以通过小程序实现对机电设备的启停、开关机等功能,系统框架如下:

系统框架

3、 硬件设计

下图是我们本次使用的硬件环境,我们使用三种类型的板子进行开发,绿色的板子是我们自己设计的一个Lora的节点,使用SPI驱动的;本次实训我们直接使用板载的温湿度传感器进行环境数据采集,然后通过串口外接串口转485对Modbus设备进行数据采集:

硬件

由于我们没办法去工业现场连接真正的Modbus-RTU设备,我们这里使用Modbus Slave软件进行模拟;模拟部分如下:

Modbus模拟软件配置

我们能够看见,我这里一共模拟了四个设备,期间从站地址1的设备包含了03功能码的保持寄存器、以及01功能码的线圈状态;地址2是我们的电表;地址3压力传感器;地址4是流量计;我们通过节点驱动Modbus来对各个数据进行采集。

我这里使用的SPI驱动的Lora板子原理图如下,需要注意的是,我没用直接使用semtech公司的SX127X\SX126X芯片,而是使用的安信可的Ra-01,这里也是直接使用的SPI驱动,原理图如下图所示:

硬件原理图

PCBA的3D视图如下图所示:

PCBA 3D视图

安信可 LoRa 系列模块是安信可科技基于 SX1278 设计开发的,主要采用LoRa™远程调制解调器,用于超长距离扩频通信,抗干扰性强,能够最大限度降低电流消耗。借助 SEMTECH 的 LoRa™ 专利调制技术,SX1278 具有超过 -148dBm 的高灵敏度,+18dBm 的功率输出,传输距离远,可靠性高。同时,相对传统调制技术,LoRa™ 调制技术在抗阻塞和选择方面也具有明显优势,解决了传统设计方案无法同时兼顾距离、抗干扰和功耗的问题。Ra-01如下图所示:

Ra-01

4、 软件设计

4.1 LoraWAN驱动程序设计

关于LoraWAN的驱动程序部分,我们这里一共分为两种类别,一种是使用AT指令进行驱动的LoraWAN模组,另一种是直接驱动SPI的Lora芯片进行通讯的;关于驱动部分我们只做简单讲述,后期有时间了之后我会考虑详细讲述下关于使用SPI驱动Lora芯片的移植方法;我们直接在假设我们已经移植好了LoraWAN协议的情况下,根据我们网关的实际情况来进行修改;

网关配置如:

LoraWAN网关配置

我们能够看见我们网关的八个信道,对应的,我们也需要将我们的Lora节点设置到对应的信道,我们首先找到RegionCN470.c,然后找到RegionCN470InitDefaults函数,我们添加一个数组用来存放频段,然后根据信道计算出我们设置的每个频段的信号号,将我们对应的频段设置号,在设置信道前,我们首先需要将所有信道屏蔽掉,设置完成后函数如下:

1.uint32_t UserFreq[8]={486300000,486500000,486700000,486900000,487100000,487300000,487300000,487700000};  
2. 
3.void RegionCN470InitDefaults( InitDefaultsParams_t* params )  
4.{  
5.    Band_t bands[CN470_MAX_NB_BANDS] =  
6.    {  
7.        CN470_BAND0  
8.    };  
9. 
10. switch( params->Type )  
11.    {  
12. case INIT_TYPE_INIT:  
13.        {  
14. // Initialize bands 
15.            memcpy1( ( uint8_t* )NvmCtx.Bands, ( uint8_t* )bands, sizeof( Band_t ) * CN470_MAX_NB_BANDS );  
16. 
17. // Channels 
18. // 125 kHz channels 
19.//            for( uint8_t i = 0; i < CN470_MAX_NB_CHANNELS; i++ ) 
20.//            { 
21.//                NvmCtx.Channels[i].Frequency = 470300000 + i * 200000; 
22.//                NvmCtx.Channels[i].DrRange.Value = ( DR_5 << 4 ) | DR_0; 
23.//                NvmCtx.Channels[i].Band = 0; 
24.//            } 
25. 
26.//            // Initialize the channels default mask 
27.//            NvmCtx.ChannelsDefaultMask[0] = 0xFFFF; 
28.//            NvmCtx.ChannelsDefaultMask[1] = 0xFFFF; 
29.//            NvmCtx.ChannelsDefaultMask[2] = 0xFFFF; 
30.//            NvmCtx.ChannelsDefaultMask[3] = 0xFFFF; 
31.//            NvmCtx.ChannelsDefaultMask[4] = 0xFFFF; 
32.//            NvmCtx.ChannelsDefaultMask[5] = 0xFFFF; 
33.            NvmCtx.ChannelsDefaultMask[0] = 0x0000;  
34.            NvmCtx.ChannelsDefaultMask[1] = 0x0000;  
35.            NvmCtx.ChannelsDefaultMask[2] = 0x0000;  
36.            NvmCtx.ChannelsDefaultMask[3] = 0x0000;  
37.            NvmCtx.ChannelsDefaultMask[4] = 0x0000;  
38.            NvmCtx.ChannelsDefaultMask[5] = 0x0000;  
39. 
40. for( uint8_t i = 0,j=0; i < 8; i++ )  
41.            {  
42.                j=(UserFreq[i]-470300000 )/200000;//计算信道号 
43. 
44.                NvmCtx.Channels[j].Frequency= UserFreq[i] ;  
45.                NvmCtx.Channels[j].DrRange.Value=( DR_5 << 4 ) | DR_0;   
46.                NvmCtx.Channels[j].Band = 0;  
47. 
48.                NvmCtx.ChannelsDefaultMask[j/16]|=1<<(j%16);//相应的信道掩码位设置为1 
49.            }  
50. 
51. // Update the channels mask 
52.            RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 6 );  
53. break;  
54.        }  
55. case INIT_TYPE_RESTORE_CTX:  
56.        {  
57. if( params->NvmCtx != 0 )  
58.            {  
59.                memcpy1( (uint8_t*) &NvmCtx, (uint8_t*) params->NvmCtx, sizeof( NvmCtx ) );  
60.            }  
61. break;  
62.        }  
63. case INIT_TYPE_RESTORE_DEFAULT_CHANNELS:  
64.        {  
65. // Restore channels default mask 
66.            RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 6 );  
67. break;  
68.        }  
69. default:  
70.        {  
71. break;  
72.        }  
73.    }  
74.}  

我们在入网前还需要确定好使用的入网方式以及设备ID、密钥等相关参数,进入到Commissioning.h中进行设置,我这里使用的是APB的入网方式,所以我们直接把空中激活的宏OVER_THE_AIR_ACTIVATION设置为0,以及设置为将DEV_EUI设置为静态,完成之后我们需要填写LORAWAN_DEVICE_EUI、LORAWAN_APP_KEY、LORAWAN_NWK_KEY、LORAWAN_DEVICE_ADDRESS这几个参数。

我们使用AT的模组时也要使用APB方式入网,同样的需要将上面的第四个参数填写完成。

4.2 LoraWAN应用程序编写

关于应用层,我们使用的SPI或者AT命令驱动都是一样的,我这里直接创建一个了个Modbus采集的任务,函数如下:

1.void modbus_app(void *arg)  
2.{  
3.    ModbusMaster_begin();  
4.    MX_USART3_UART_Init();  
5.    comm.SlaveID = 0x01;            //Modbus从设备地址 
6.    comm.u16ReadAddress = 0x00;     //读取地址 
7.    comm.u16ReadQty = 8;             //读线圈数量 
8.    comm.u8MBFunction = 0x03;       //功能字 
9. while(1){  
10. //读PLC 保持寄存器数据 地址2:运行状态 
11.        comm.SlaveID = 0x01;            //Modbus从设备地址 
12.        comm.u16ReadAddress = 0x02;     //读取地址 
13.        comm.u16ReadQty = 1;             //读线圈数量 
14.        comm.u8MBFunction = 0x03;       //功能字 
15. if(ModBusMasterCommunication(comm) == 0x00) {  
16.            dev_data_wrapper.u.dev_data.runState = ModbusMaster_getResponseBuffer(0);  
17.            printf("Read 01 03:%d\r\n", dev_data_wrapper.u.dev_data.runState );  
18.        }  
19. //读电表数据 地址1-6 
20.        comm.SlaveID = 0x02;  
21.        comm.u8MBFunction = 0x03;  
22.        comm.u16ReadQty = 6;  
23.        comm.u16ReadAddress = 0x01;  
24. if(ModBusMasterCommunication(comm) == 0x00) {  
25.            dev_data_wrapper.u.dev_data.A_Voltage = ModbusMaster_getResponseBuffer(0);  
26.            dev_data_wrapper.u.dev_data.B_Voltage = ModbusMaster_getResponseBuffer(1);  
27.            dev_data_wrapper.u.dev_data.C_Voltage = ModbusMaster_getResponseBuffer(2);  
28.            dev_data_wrapper.u.dev_data.A_Current = ModbusMaster_getResponseBuffer(3);  
29.            dev_data_wrapper.u.dev_data.B_Current = ModbusMaster_getResponseBuffer(4);  
30.            dev_data_wrapper.u.dev_data.C_Current = ModbusMaster_getResponseBuffer(5);  
31.            printf("电表读取成功\n");  
32.        }  
33. //读压力传感器数据 地址1 
34.        comm.SlaveID = 0x03;  
35.        comm.u8MBFunction = 0x03;  
36.        comm.u16ReadQty = 1;  
37.        comm.u16ReadAddress = 0x01;  
38. if(ModBusMasterCommunication(comm) == 0x00) {  
39.            dev_data_wrapper.u.dev_data.Pressure = ModbusMaster_getResponseBuffer(0);  
40.            printf("压力传感器读取成功\n");  
41.        }  
42. //读流量计数据 地址1 
43.        comm.SlaveID = 0x04;  
44.        comm.u8MBFunction = 0x04;  
45.        comm.u16ReadQty = 1;  
46.        comm.u16ReadAddress = 0x01;  
47. if(ModBusMasterCommunication(comm) == 0x00) {  
48.            dev_data_wrapper.u.dev_data.Flowmeter = ModbusMaster_getResponseBuffer(0);  
49.            printf("流量计读取成功\n");  
50.        }  
51.        tos_task_delay(1000);  
52.    }  
53.}  

我这里封装了一下采集程序的结构体,我们直接设置结构体中的对应的值进能够实现对Modbus的读写命令了。结构体结构如下图所示:

Modbus读写结构体

由于篇幅有限,我们就不对Modbu做过多讲解,我们设置好结构体之后我们使用ModBusMasterCommunication函数进行读写即可,当返回值为0x00即表示读写成功,然后通过ModbusMaster_getResponseBuffer读取对应数值的数据即可;

Lora上报数据的结构体如下图所示:

Lora数据结构体

我们使用另一个任务定时发送Lora数据,如下图所示:

1.void application_entry(void *arg)  
2.{  
3.    rhf76_lora_init(HAL_UART_PORT_0);  
4.    tos_lora_module_recvcb_register(recv_callback);  
5.    rhf76_join_abp("XXX", "XXX","XXX","XXX");  
6. 
7.    (void)tos_task_create(&task_modbus, "task_prio5", modbus_app,  
8.                  NULL, 0,  
9.                  stack_task_modbus, STK_SIZE_TASK_MODBUS, 0);  
10. while (1) {  
11.        E53_IA1_Read_Data();  
12.        printf("Lux:%f,Humi:%f,Temp:%f,Motor:%d,Light:%d", E53_IA1_Data.Lux,E53_IA1_Data.Humidity,E53_IA1_Data.Temperature,E53_IA1_Data.MotorMode,E53_IA1_Data.LightMode);  
13. 
14.        dev_data_wrapper.u.dev_data.temperature = E53_IA1_Data.Temperature;  
15.        dev_data_wrapper.u.dev_data.humidity    = E53_IA1_Data.Humidity;  
16.        dev_data_wrapper.u.dev_data.period      = report_period;  
17. 
18.        tos_lora_module_send(dev_data_wrapper.u.serialize, sizeof(dev_data_t));  
19.        tos_task_delay(report_period * 1000);  
20.    }  
21.}  
rhf76_join_abp中传入的数据是我们前面说的那四个参数;
Lora的接收回调函数如下所示:
1.void recv_callback(uint8_t *data, uint8_t len)  
2.{  
3. int i = 0;  
4. 
5.    printf("len: %d\n", len);  
6. 
7. for (i = 0; i < len; ++i) {  
8.        printf("data[%d]: %d\n", i, data[i]);  
9.    }  
10. 
11. if(data[0] != 0 | data[1] != 0 )  
12.        report_period = data[0] | (data[1] << 8);  
13. if(data[2] != 0 | data[3] != 0 )  
14.        runState = data[2] | (data[3] << 8);  
15. if(data[4] != 0)  
16.        runFlag = data[4];  
17.    printf("report_period: %d runState: %d,runFlag: %d\n", report_period,runState,runFlag);  
18.    comm.u16WriteAddress = 0x07;  
19.    comm.u8MBFunction = 0x06;  
20.    comm.u16WriteValue = runState;  
21. if(ModBusMasterCommunication(comm) == 0x00) {  
22.        printf("write data sucess");  
23.    }  
24. if(runFlag == 1)  
25.        light_control(1);  
26. else if(runFlag == 2)  
27.        light_control(0);  
28.}  

我们这里直接将运行状态同通过06功能码写入到对应位置。

4.3 腾讯物联网平台配置

上面我们说了关于Lora数据的结构体以及下发的解析程序,我们来到腾讯物联网平台创建好对应的产品,然后将我们定义的传感器数据在云端定义好,最后就是解析部分,上行解析代码如下:

1.function RawToProtocol(fPort, bytes) {  
2.    var data = {  
3. "method": "report",  
4. "clientToken" : new Date(),  
5. "params" : {}  
6.    };  
7.    data.params.temperature = bytes[0];  
8.    data.params.humidity = bytes[1];  
9.    data.params.period = bytes[2] | (bytes[3] << 8);  
10.    data.params.runState = bytes[4];  
11.    data.params.Pressure = bytes[5] | (bytes[6] << 8);  
12.    data.params.A_Voltage = bytes[7] | (bytes[8] << 8);  
13.    data.params.B_Voltage = bytes[9] | (bytes[10] << 8);  
14.    data.params.C_Voltage = bytes[11] | (bytes[12] << 8);  
15.    data.params.A_Current = bytes[13];  
16.    data.params.B_Current = bytes[14];  
17.    data.params.C_Current = bytes[15];  
18.    data.params.Flowmeter = bytes[16] | (bytes[17] << 8);  
19. return data;  
20.}  

下行解析代码如下:

1.function ProtocolToRaw(obj) {  
2.    var data = new Array();  
3.    data[0] = 5;// fport=5 
4.    data[1] = 0;// unconfirmed mode 
5.    data[2] = obj.params.period & 0x00FF;  
6.    data[3] = (obj.params.period >> 8) & 0x00FF;  
7.    data[4] = obj.params.runState & 0x00FF;  
8.    data[5] = (obj.params.runState >> 8) & 0x00FF;  
9.    data[6] = obj.params.runFlag?1:2;  
10. return data;  
11.}  

最后我们布局好小程序,然后给设备上电,我们就能够在云端看见我们的设备采集上来的数据,可以在云端对设别进行控制了。

5、 实验现象

我们将程序烧写到我们的硬件之后,因为我们的硬件是没有485电平转换芯片的,如果我们需要接真正的机器设备的话,我们还需要对硬件进行修改,增加一个ttl串口转485的电路,下面推荐一个485电路,这个电路我们可以不用去考虑485的收发状态,还增加了光耦隔离,跟用普通的串口一样:

485原理图

我们这里不直接接机电设别,我们直接使用PC端对设备进行模拟,如下图所示:

实验现象
小程序页面显示

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

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

登录 后参与评论
0 条评论

相关文章

  • 【IoT应用创新大赛】基于LoRaWAN在园区路灯控制系统

    在机缘巧合下获得了由腾讯云主办的《IOT应用创新大赛》的LORAWAN开发板,但由于种种原因个人资源和精力有限,没办法做得华丽就做了一个简单的小项目:基于LoR...

    云鱼OS
  • 【IoT应用创新大赛】基于TencentOS tiny与LoRa SX1301的LoRaWAN协议分析工具

    从2013年Semtech公司发布第一代商用LoRa芯片以来,LoRa技术经受住了物联网行业的考验,凭借其低功耗远距离等技术优势,近几年在全球物联网无线通信的细...

    forest-rain
  • 【IoT应用创新大赛】基于LoRa的智慧办公场景方案

    随着物联网技术的发展,越来越多的应用需求被提及,整个物联网产业链的基础设施也得到快速发展。以腾讯、阿里为首的头部云计算企业,纷纷推出了物联网设备接入的基础设施(...

    古月瘦水
  • 【IoT应用创新大赛】智能快递箱的设计与实现

    物联网时代的来临给生活带了科技感,让生活充满了便捷,在物流领域产生了重要的推动作用。可以说,物联网是开启物流信息化整合的时代引擎,谁抓住了物联网,谁就抓住了物流...

    吕昉
  • 【IoT应用创新大赛】基于腾讯云的智能停车平台

    都说科技改变生活,今天来聊的这个作品可以真实的改变生活相信有车的朋友最头疼的莫过于停车问题,其他小城市还好,像深圳这样的大城市,停车问题一直困扰着有车一族:- ...

    物联风景
  • 【IoT应用创新大赛】基于LoRa的机房环境监控案例

    LoRa是semtech公司创建的低功耗局域网无线标准,低功耗一般很难覆盖远距离,远距离一般功耗高,LoRa的名字就是远距离无线电(Long Ra...

    极速紫韵
  • 入围名单公布!腾讯云IoT应用创新大赛火爆进行中!

    腾讯云IoT应用创新大赛是腾讯云面向物联网领域举办的大型竞赛,通过腾讯云IoT全链路产品能力,开放平台和服务,与广大开发者共同创新,孵化优秀的IoT产品和解决方...

    腾小云
  • 【IoT应用创新大赛】基于TencentOS tiny的 智能 家居总控系统

    ​首先,我要先讲一下概念,在传统的生活方式中呢,我们都是手动打开电器,亲自去检查门有没有关好,亲手去拉窗帘。 而到了现在,我们有了各种各样的智能电器,例如智能电...

    黑白方圆丶
  • 【IoT应用创新大赛】基于TencentOS的智能环境监测系统

    物联网( IoT ,Internet of things )即“万物相连的互联网”,是互联网基础上的延伸和扩展的网络,将各种信息传感设备与互联网结合起来而形成的...

    yyyyyyw
  • 【IoT应用创新大赛】基于LoRa与机械臂的家居系统

    物联网是一种连接各种各样的传感器的网络,与之对应的是20世纪60年代开始研究的计算机网络,后者将分散于不同地理位置的计算机连接起来。物联网传感器可以采集的信息包...

    羽翰尘
  • AIoT应用创新大赛-TencentOS Tiny AIoT开发板在智能轮椅中的应用

    腾讯物联网操作系统(TencentOS tiny)是腾讯面向物联网领域开发的实时操作系统,具有低功耗,低资源占用,模块化,可裁剪等特性。TencentOS ti...

    LinwCui
  • 【IOT应用创新大赛】基于 EVB_MX_Plus 的盆栽土壤监测

    注:因社区编辑器限制,完整文章详见:【IOT应用创新大赛】基于 EVB_MX_Plus 的盆栽土壤监测

    远哥制造
  • 工业相机在全息成像中的应用

    对透明物体成像作为一种独特的技术,广泛应用于生物学、医学、工业机器视觉等领域,其中特殊涂层、样本染色、相位成像、结构光和多光谱成像等,都是透明物体成像技术的一种...

    小白学视觉
  • 标识解析技术在工业互联网中的应用,你了解多少?

    物联网的通信技术与物联网物体的价值是目前物联网在发展的过程中遇到的两个基础问题。而物联网物体的价值问题是推动物联网发展的中心问题,主要是对为什么万物互联或是万物...

    yansunxer
  • 5G和MEC在工业互联网中的应用探讨

    工业互联网已成为中国经济发展的重要战略之一,在工业化和互联网化两化融合的过程中存在诸多难题,需要 5G 和 MEC 等 CT 新技术贯通工业 OT 域和 IT域...

    边缘计算
  • 开发板免费领!腾讯云IoT应用创新大赛正式启动!

    腾讯云IoT应用创新大赛是腾讯云面向物联网领域举办的大型竞赛,通过腾讯云IoT全链路产品能力,开放平台和服务,与广大开发者共同创新,孵化优秀的IoT产品和解决方...

    腾讯云物联网团队
  • 标识在5G+工业互联网中的典型应用场景

    工业互联网的基础是网络体系,网络互联实现信息互通,但由于种种原因,“信息孤岛”现象在企业内部、企业之间大量存在。标识解析是网络体系中承上启下的部分,是工业互联网...

    yansunxer
  • 【IoT应用创新大赛】基于LoRa和Tiny OS的液化气智能充装系统

    目前,常见的液化气充装系统是充装人员根据开票人员提供的充值小票来给液化气罐定量的充值,这种充装方式受充装人员的操作影响较大,容易受到充装人员误操作导致的多充或少...

    用户5927942

扫码关注腾讯云开发者

领取腾讯云代金券