11月22日, 2014 3,873 次查看次
这个说来也是快两年前的事情了,当时和海涛和山哥一起作妖真的是很值得怀念的事情啊。
当时参加比赛得了辽宁省金奖,感觉很不甘心没有进国赛,不过现在看来,当年做的东西的确是渣渣,渣到爆,真的有点不好意思贴出来,没什么发的,当是刷刷文章算了。
当时的照片视频什么的有空再发吧,这篇就只发论文好了。
未做任何删改,保持原来的样子就好。
——————————————————分割——————————————————
3D化zigbee室内定位系统
何山,林海涛,段育凯
(东北育才学校)
一. 引言
随着科技的迅速发展,GPS的观念和理念深入人心,当你到一个陌生的环境中,你自然而然地就会想到拿出手机,打开地图软件,用GPS确定你现在的位置以及周围的环境。但是,如果你并不是在户外呢?假设你在一座你完全不知道的大楼里面,你又迷了路,当你打开GPS时你又失望地发现GPS在室内信号相当差,极其不准。又或者你在一个大商场中,你想要去某个地方,可是又没有人,你也不知道你在哪里。这些情况很有可能在现实生活中发生。这时室内定位技术就显得极为重要了。目前室内定位有以下几种:
(1)A-GPS技术
辅助GPS的系统,GPS受建筑物的影响还是最大的问题。
(2)红外线室内定位技术
红外线与光学传感器的配合,定位精度足够,但易受墙壁等物体和灯光的干扰。
(3)蓝牙技术
设备体积小,蓝牙器件和设备的价格比较昂贵,受噪声信号干扰大。
(4)Wi-Fi技术
小范围的室内定位,成本较低。很容易受到其他信号的干扰。
(5)zigbee技术
新兴的短距离、低速率无线网络技术,低功耗和低成本,通信效率非常高。
根据这几种技术的比较来看,我们更倾向于zigbee技术。而在网上,尽管有很多关于zigbee的研究,但仍没有一个合理的完整体系,并且更没有与3D模型相结合,制造出真正的室内定位。所以本文主要研究基于zigbee的室内定位的3D室内地图。
二. 总体思路
为了实现zigbee定位,我们首先让zigbee模块自动建网,建网后让每一个zigbee模块向外发送带有此模块特征的数据,当与电脑(客户端)相连的那个zigbee模块收到其他模块发送过来的信息时,便可通过其信号强度间接测出此模块与各个模块之间的距离,之后,为了达到更好的定位效果,我们又将虚拟3D技术与定位技术结合,用3D建模软件建成一个3D地图模型,通过zigbee传回的数据在虚拟的3D环境中定位。
具体的思路如下:
(1) 利用网峰的Webee(zigbee的一种),coordinator与router互相配合,传送RSSI值。
(2) 把RSSI值导入processing(一种编程环境)中。
(3) 根据RSSI值计算实际距离。
(4) 根据实际距离进行定位。
(5) 用sweet home 3D(一种3D建模软件)绘制3D模型。
(6) 把模型和定位的坐标导入processing中结合。
(7) 配合arduino(针对arduino单片机的编程环境),使用指南针进行方向模拟。
(8) 最终在3D地图中定位zigbee所在位置。
三. 定位数据的采集与传输
3.1.软硬件设备介绍
本文使用美国德州仪器(Texas Instruments)公司开发的z-stack zigbee 协议栈和软件IAR Embedded Workbench进行定位系统软硬件的开发。
3.1.1.z-stack
TI公司的Z-Stack协议栈,其主要特点就是其兼容性,该协议栈可以实现复杂的网络链接,在协调器节点中实现对路由表和绑定表的非易失性存储,因此网络具有一定的记忆功能。
3.1.2.IAR Embedded Workbench
嵌入式IAR Embedded Workbench适用于大量8位、16位以及32位的微处理器和微控制器,使用户在开发新的项目时也能在所熟悉的开发环境中进行。它为用户提供一个易学和具有最大量代码继承能力的开发环境,以及对大多数和特殊目标的支持。
图1.IAR Embedded Workbench截图
3.1.3.单片机:
本文采用网蜂生产的CC2530F256 zigbee 模块进行开发
图2.CC2530F256模块
3.2..单片机软件程序
3.2.1.信息发送
首先,运用send_preiodic_message函数每0.1秒向网络中每一个原件发送数据。为之后单片机分析信号强度判断距离提供前提。
z-stack协议栈中有专门为zigbee设计的对于处理函数收发的函数,本文主要修改其中的SampleApp.C程序达到传输距离数据的作用。
其函数程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | /**********************周期性发送数据函数*************************/ void SampleApp_SendPeriodicMessage( void ) { if(AF_DataRequest(&SampleApp_Periodic_DstAddr, &SampleApp_epDesc, SAMPLEAPP_PERIODIC_CLUSTERID, 1, (uint8*)&SampleAppPeriodicCounter, &SampleApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) { } else { } } |
在此函数中,包含了一个zigbee通过其芯片将数据打成数据包,并传出使其符合zigbee数据格式的函数AF_DataRequest,其具体含义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | AF_DataRequest(&SampleApp_Periodic_DstAddr,//zigbee模块短地址 &SampleApp_epDesc, SAMPLEAPP_PERIODIC_CLUSTERID, 1,//数据长度 Data,//发送的数据 &SampleApp_TransID, AF_DISCV_ROUTE,AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) |
运用如上程序,即可使zigbee模块每0.1s向外发送数据,但发送数据程序完成后,还需要与电脑相连接zigbee模块识别出每一个节点,防止混乱。为此,我们想出了几种方案。
(1) 运用zigbee模块组网时Cordinator(适配器)模块分配给每一个Router(路由器)模块的短地址区分。
(2) 设置每个zigbee模块所发送的数据长度,使每个模块发送的数据长度,并根据数据长度大小区分。
由于zigbee模块组网时分配短地址的方式为随机分配,使每一个zigbee模块在每次开机组网后短地址都会变化,且在传输时数据易受干扰,往往无法正确区分节点。但是,设置数据长度虽然许在烧写程序之前人工设置,但不易受到干扰,且方法简便,只需改变AF DataRequest 函数中数据长度即可。通过以上综合分析,本作品最终采用(2)方案。
这部分代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | void SampleApp_SendPeriodicMessage( void ) { uint8 data[3]={1,1,1};//设置发送的数据与长度,此设为三号机。 //若为2号机,则为data[2]={1,1} //若为1号机,则为data[1]={1} if ( AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc, SAMPLEAPP_PERIODIC_CLUSTERID, 3, data, &SampleApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) { } else { } } |
3.2.2.信号接收与传回电脑
信息发送后,与电脑相连的zigbee模块将收到数据包中包含的信号强度信息传输回电脑供电脑处理。
Zigbee模块接收数据将其收到的全部信息以一个数据包afIncomingMSGPacket_t *pkt的形式处理
afIncomingMSGPacket_t *pkt所包含的内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | typedef struct { osal_event_hdr_t hdr; uint16 groupId; uint16 clusterId; afAddrType_t srcAddr; it's an InterPAN message */ uint16 macDestAddr; /* 短地址 */ uint8 endPoint; uint8 wasBroadcast; uint8 LinkQuality; uint8 correlation; int8 rssi; /* 信号强度 */ uint8 SecurityUse; uint32 timestamp; / afMSGCommandFormat_t cmd; /* 收到的数据*/ } afIncomingMSGPacket_t; typedef struct { byte TransSeqNumber; uint16 DataLength; // 数据长度 byte *Data; } afMSGCommandFormat_t; |
在该数据包中,int8 rssi就是我们需要的信号强度值。提取了rssi值,再通过子包cmd中的uint16 DataLengt数据长度量判断完信息来源后,我们还需调用串口发送函数HalUARTWrite将rssi值通过串口传回电脑。为了也使电脑分清楚rssi值的来源,我们又将模块代号插入在rssi值前端,并用“,”将二者隔离。这部分代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ) { //判断是否为周期性发送函数发送的信息 switch ( pkt->clusterId ) { case SAMPLEAPP_PERIODIC_CLUSTERID://为周期性数据 if(pkt->cmd.DataLength==3){//如果数据长度为3,则判断为3号机 sprintf(s,"%d",-pkt->rssi);//获取RSSI HalUARTWrite(0,"33",2);//传回电脑,“33”代表3号机 HalUARTWrite(0,",",1);//分格用的逗号 HalUARTWrite(0,s,10);//传输RSSI HalUARTWrite(0,"\n",1); } if(pkt->cmd.DataLength==2){// 如果数据长度为2,则判断为2号机 sprintf(s,"%d",-pkt->rssi); HalUARTWrite(0,"22",2); // 传回电脑,“22”代表1号机 HalUARTWrite(0,",",1); HalUARTWrite(0,s,10); HalUARTWrite(0,"\n",1); } if(pkt->cmd.DataLength==1){// 如果数据长度为1,则判断为1号机 sprintf(s,"%d",-pkt->rssi); HalUARTWrite(0,"11",2);// 传回电脑,“11”代表1号机 HalUARTWrite(0,",",1); HalUARTWrite(0,s,10); HalUARTWrite(0,"\n",1); } break; case SAMPLEAPP_FLASH_CLUSTERID: break; } } |
3.3电脑客户端的数据获取
单片机发送了串口数据后,接下来需要电脑客户端通过串口接收并处理单片机传回的数据,以便于下一部分应用算法获得距离。现在,从单片机中传回的数据形式为11,75/22,67//33,45,其中,前两位(“11”,“22”,“33”)分别代表1,2,3号模块,后两位为从模块发回数据的rssi值。本作品应用编译环境processing(一个十分强大的编程软件)中的Serial库进行数据采集。
首先,定义串口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import processing.serial.*; Serial myPort; String portName = Serial.list()[2];//选择串口号,为所有串口号列表中的第2号, //用户可自己设定 myPort = new Serial(this, portName, 38400);//38400为波特率,myPort为定义串口 //类型变量 byte[] inBuffer = new byte[100]; float c; float val; |
之后,如果串口收到数据,则运用函数readBytesUntil()将串口缓冲区内的数据按“,”划分:
1 2 3 4 5 6 7 8 9 10 11 | if ( myPort.available() > 0) { //如果串口收到数据 if (myPort.readBytesUntil(lf, inBuffer) > 0) { String inputString = new String(inBuffer);//定义一个暂时储存数据的字符串 String [] inputStringArr = split(inputString, ',');//将数据进行分割 } } |
此时inputStringArr[0]储存着“11,22,33”判断模块来源的信息,inputStringArr[1]储存着rssi值,之后进一步将数据转化为整型并加以判断:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | c= float(inputStringArr[0]); val=float(inputStringArr[1]); if (c==11){ rssi[0]=val; } if (c== 22){ rssi[1]=val; } if (c==33){ rssi[2]=val; } |
到此为止,zigbee传回的rssi值便以整型的形式储存到了rssi[0](代表1号机),rssi[1](代表2号机),rssi[2](代表3号机)中了,可以进一步计算距离了。
四.算法介绍
4.1. zigbee 中RSSI 测距原理
无线信号传输中普遍采用的理论模型— Shadowing模型由式(1)给出:
式中,为接收端与发射端之间的距离(m);
为参考距离(m),一般取1m;
是接收端的接收信号功率(dBm);
是参考距离
点对应的接收信号功率(dBm);
是一个平均值为0的高斯随机变量(dBm),反映了当距离一定时,接收信号功率的变化;n是行为路径损耗指数,是一个与环境相关的值。在实际应用中,我们采用简化的Shadowing模型,由式(2)给出:
并且通常取=1 m,从而得到实际应用中的RSSI测距公式,由式(3)给出:
上式中,A为信号传输1 m远处接收信号的功率(dBm)。研究表明,RSSI和无线信号传输距离之间有确定关系,RSSI的测量具有重复性和互换性,在应用环境下RSSI适度的变化有规律可循。
但在实际应用环境中,多径、绕射、障碍物等不稳定因素都会对无线信号的传输产生影响,所以在解决好环境因素的影响后,RSSI可以进行室内和室外的测距及定位。
下面是有关测距原理的代码:
1 2 3 4 5 | rssi[0]=pow(10,(-A+val)/(10*n)); //val 即为传来的RSSI值 rssi[1]=pow(10,(-A+val)/(10*n)); rssi[2]=pow(10,(-A+val)/(10*n)); |
4.2 RSSI 的校正模型
基于RSSI 值的不稳定性以及精确性上的缺陷,我们分别在这两个问题上做了相应的处理。
(1) 高斯模型
RSSI值有时会有一些与真实值差距较大的数据,但这也仅仅是小概率事件,所以为了清除这些数据所造成的定位误差,我们采用了高斯模型。这种做法减少了一些小概率、大干扰事件对整体测量的影响,增强了定位信息的准确性。
将未知节点在同一位置时接收到的RSSI测量值记录10次到对应的RSSI值数组中,运用高斯分布函数处理这些RSSI值:
根据实际经验,本文选择0.6为临界点。即当高斯分布函数(由式(4)得出)大于0.6时,认为对应的RSSI值为高概率发生值;当高斯分布函数值小于或等于0.6时,认为对应的RSSI值是小概率随机事件。通过式(5)与式(6)再分别求出均值m与方差
。
把是高概率发生值存进另一个数组中,最终得出的10次RSSI值的优化值由式(7)求得。
n为经过高斯模型处理后10个数据中所剩数据的个数。
高斯模型解决了RSSI在实际测试中易受干扰、稳定性差等问题,提高了定位精度。但是高斯模型只能消除小概率短暂的扰动,对于如室内定位墙壁对RSSI的能量反射等长时间干扰问题其效果将有所下降。
下文是关于一个zigbee传来的数据的分析和处理的一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | rssixiu[0]=(xiu0[0]+xiu0[1]+xiu0[2]+xiu0[3]+xiu0[4]+xiu0[5]+xiu0[6]+xiu0[7]+xiu0[8]+xiu0[9])/10; //10个RSSI的平均值 for(int j=0;j<=9;j++){ fangcha[0]=fangcha[0]+(xiu0[j]-rssixiu[0])*(xiu0[j]-rssixiu[0]); } //计算方差 for(int i=0;i<=9;i++){ gao[i]=pow(e,(-(xiu0[i]-rssixiu[0])*(xiu0[i]-rssixiu[0]))/(2*fangcha[0]/9))/sqrt(2*PI*fangcha[0]/9); //计算高斯分布 if(gao[i]>0.6/sqrt(2*PI*fangcha[0]/9)){ P[0]=P[0]+1; //判断高概率分布值 rssigauss0[i]=xiu0[i]; } } |
(2) 最小二乘法拟合
尽管除掉了小概率误差的影响,但基于RSSI本身精确度的缺陷,还是需要在RSSI算出距离后进行修正。此处我们采用最小二乘法拟合。
(1)根据实际情况布置好节点,参考节点()与coordinator(
)的位置坐标均已知。可以根据式(8)得到实际节点之间的距离。
(2)根据式(1)估算出coordinator与各个参考节点之间的
距离。
(3) 采用最小二乘法拟合实际距离.与估计距离的
a , b分别由最小二乘法原理中式(9)和式(10)得出。
其中
。根据得到的a, b的值可以拟合出修正距离与估计距离的关系式(11)
下文是最小二乘法拟合的一段代码:
1 2 3 4 5 6 7 8 9 10 11 | rA=(rr[0]+rr[1]+rr[2])/3; //求平均值 DA=(D[0]+D[1]+D[2])/3; ra=((rr[0]-rA)*(D[0]-DA)+(rr[1]-rA)*(D[1]-DA)+(rr[2]-rA)*(D[2]-DA))/((rr[0]-rA)*(rr[0]-rA)+(rr[1]-rA)*(rr[1]-rA)+(rr[2]-rA)*(rr[2]-rA)); rb=DA-ra*rA; //最小二乘法原理 R[q[0]]=ra*rr[q[0]]+rb; R[q[1]]=ra*rr[q[1]]+rb; R[q[2]]=ra*rr[q[2]]+rb; //拟合之后的距离 |
4.3 室内定位模型
(1) 相交区域质心
由于各种障碍物的影响,绝大多数实际情况中,预测出的RSSI比实际信号RSSI偏大,当距离d 增大时,RSSI的偏差也会增大。所以,我们采用确定相交区域质心的数学模型。
图3 相交区域质心数学模型
理想状况为(a),但在实际情况中,由于RSSI 测距存在误差,并且由于实际的路径损耗比理论模型的数值偏大,也就是说测量出来的未知点到锚节点的距离d 总是大于实际距离r。以A、B和C 三点为圆心,以、
和
为半径作圆,三圆将不再相交于点O,而是存在一个相交区域,如图(b)所示
三圆相交区域的边界有三个交点,三点质心为点D。其中点D 的坐标可以通过式(12)求解。
但是二次方程,求解过程计算量较大,影响速率,因而本文中采用如图(b)所示的点D1 的坐标近似质心D 的坐标。三圆两两相交,则三条交线将相交于点D1。将式(12)中的方程式两两相减,则分别得到每条交线的直线方程,D1 的坐标则可以通过这些直线方程求解,如式(13)。
下文是相交区域质心的数学模型的一段代码:
当有多个router时,为更方便定位,我们可以选择出离coordinator最近的三个router,以这三个为A,B,C,进行定位。目前我们只是一共使用三个router,但此方法可以适用于多个router的情况。
以下是关于选出三个最近的router的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | for(int i=0;i<=2;i++ ){ for(int j=i+1;j<=3;j++){ if(rssiac[i]<=rssiac[j]){ p[i]=p[i]+1; p[j]=p[j]-1; } else if (rssiac[i]>rssiac[j]){ p[j]=p[j]+1; p[i]=p[i]-1; } } } //比较哪个RSSI值较小 for(int i=0;i<=3;i++){ if(p[i]==3){ q[0]=i; } else if(p[i]==1){ q[1]=i; } else if(p[i]==-1){ q[2]=i; } } //这只是四个router的程序,多个router也类似 |
(2) 距离修正
某些文章中,以D1 的坐标作为点O 的近似值,其准确度虽然比三边定位等方法要高,但是还是可能存在较大的误差,尤其是当、
和
与
、
和
的相对误差
不相同时尤其明显,因而需要对RSSI 方法测出的距离、
和
进行修正,然后再重复地求出新的三线交点D2 的坐标,则可以用点D2 的坐标作为点O 的近似坐标。
设点A、B 和C 到D1 的距离、
和
,则总体修正系数如式(14)所示。
根据假设中距离越远测距相对误差越大,则其修正程度越大,则的修正系数如式(15)所示,
和
的修正系数类似。
下文是定位距离修正的一段代码:
1 2 3 4 5 | l[q[0]]=sqrt((a[q[0]]-x0)*(a[q[0]]-x0)+(b[q[0]]-y0)*(b[q[0]]-y0)) //zigbee估计距离 m=1-pow((pow(l[q[0]],n)+pow(l[q[1]],n)+pow(l[q[2]],n))/(pow(r[q[0]],n)+pow(r[q[1]],n)+pow(r[q[2]],n)),1/n); //修正总系数 k[q[0]]=m*2*r[q[0]]/(r[q[0]]+r[q[1]]+r[q[2]]); //各自修正系数 rr[q[0]]=r[q[0]]*(1-k[q[0]]); //修正后距离 |
(3) 三维距离修正
上文使用的定位系统只是局限于二维中,而实际情况却是三维的,这会造成一定的误差,而这个误差又与用户的身高有关。所以,在用户初次使用这一软件时,我们可以获取用户的身高信息,配合实际测定的距离,尽可能的减小误差。
五、3D化图形界面
为了更好的向监控人员展示目标人物所在位置,我们并非只是用显示坐标这样抽象的方法,而是结合室内建筑的3D仿真的模型,向监控人员提供鸟瞰模式与第一人称模拟的显示模式,
第一人称模式(普通版地图(还有炫彩版、极简版))
图4. 鸟瞰模式与第一人称模拟的显示模式 图5. 鸟瞰模式
来辅助监控人员更方便的了解其所在位置具体情况。而对于手持终端用户也可以通过ZIGBEE定位获得自己的位置,再使用如android客户端来接受这些位置信息,同样可以以鸟瞰模式或第一人称模拟的显示模式来清楚的了解到自己所在位置以及周围房间(如学校中)或者商家(商场中)自己的方位,同时可以使用模拟参观模式,可以在不走动的情况下,虚拟地以自己位置为起点,向四处走动以了解周围具体情况,比较方便如老年人等不易多行走的人。在虚拟行走界面,使用者可以方便的改变自己的视线高度、环绕角度,方便地前进后退,观察周围房间。同时我们也有房间平面图让使用者或监控人员有以更多的选择。如图所示:
图6. 地图示例
地图的地板上都标有临近房间名,便于直接了解周围情况。
对于控制部分,为了能是使用者在整个球面都可以获得视角,我们便定义了当前的视角环绕角度,用来模拟左右转身,定义了仰俯角度,来模拟抬头低头,定义了视角高度来模拟上楼下楼或起身俯身。
关键控制代码如下:
视角位置:
1 2 3 4 5 | camera( myx, -myy, myz,myx +10*sin(myanglezhuan)*cos(myangleyang) , -myy-10*sin(myangleyang) ,myz+10*cos(myanglezhuan)*cos(myangleyang) , 0, 1, 0 ) //由camera控制人眼位置、观察方向,配合三角函数,精确计算 |
控制部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | void keyPressed() { //keypress控制环视、仰角、高度、行进等 if (key == 'a') { //a键与d键控制环视角度(向左、向右转) myanglezhuan = myanglezhuan + PI / 18; if (myanglezhuan > TWO_PI){ myanglezhuan = myanglezhuan - TWO_PI; } } else if(key == 'w'){ //w键、s键控制前进后退 myz = myz + 100*cos(myanglezhuan); myx = myx + 100*sin(myanglezhuan); } else if(key == 'd'){ myanglezhuan = myanglezhuan - PI/18; if (myanglezhuan < 0){ myanglezhuan = myanglezhuan + TWO_PI; } } else if(key == 's'){ myz = myz - 100*cos(myanglezhuan); myx = myx - 100*sin(myanglezhuan); } else if(key == 'z'){ //z键、x键控制仰俯角(抬头低头) myangleyang = myangleyang + PI/18; if (myangleyang > TWO_PI ){ myangleyang = myangleyang - TWO_PI; } } else if(key == 'x'){ myangleyang = myangleyang - PI/18; if (myangleyang < 0 ){ myangleyang = myangleyang + TWO_PI; } }else if(key == 'o'){ //o键、p键控制人眼上升下降 myy = myy+100; }else if(key == 'p'){ myy = myy-100; } } |
如果使用者的手机比较先进,可以通过结合手机的指南针功能来优化精确使用者所面对的方向,使使用者在一定意义上无需太多的操作也能获得与实际非常符合的场景,方便使用。对于指南针来说,使用者手持终端或者android手机(含指南针功能)自身旋转便可使程序得知使用者朝向,与地图的坐标相结合,在第一人称视角中,可以同步显示使用者的面朝方向,在鸟瞰模式下,会将使用者实际所在处的标识模型的面朝方向显示出来。
对于3D模型来说,我们使用3D建模软件制作一个与原建筑特征相符的模型,尽量还原现场,仅在原建筑基础上,改变一些如墙体颜色、纹路等属性,使使用者不会因墙体白色而视觉疲劳或难以分辨。为了适应各种设备的性能,我们将建筑模型分成了几种细致等级,以便使配置较低的设备也能使用其中的基本功能。如图所示,最简单的地图只有3D墙体、门窗与基本标示,满足了简单的使用要求,最复杂的地图甚至精细到小部件,让用户有更好的使用体验,有身临其境之感。
关于3D模型的创建,我们使用了SweetHome,一款开源软件,并没有使用如3D MAX等大型3D 环境是为了方便对于拓展大量地图的需求,使用熟练的操作人员可以尽量快速的创建3D模型。
对于模型的使用来说,我们是将模型导出为OBJ模型(一种常见的3D模型),
OBJ模型是一种定义简洁,容易理解的3d模型。Maya模型导出的便是OBJ格式,而且它有较广的通用性,因为其以文本文件形式存储,用记事本打开就可以看到点线的坐标值等,便于适应多OS的移植。
我们的一个建筑模型的部分内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | “mtllib buiding_no1.mtl g ground_1 usemtl ground_1 v -6.250019 0.0 14.907569 v -6.250019 0.0 451.30927 v 1205.25 0.0 451.30927 v 1205.25 0.0 14.907569 v 141.75 0.0 23.30922 v 141.75 0.0 157.80922 ……” |
导入到processing开发环境,使用OPENGL来加载与渲染。使用关于processing开发环境:“processing是一种革命性的新兴计算机语言,是在电子艺术的环境下介绍程序语言”它是Java语言的延伸。我们使用processing来制作监控端图形界面,同时适应了从windows到mac os、linux的多系统环境使用,充分利用processing的电子艺术编程优势,使3D模型的渲染尽量完美。
功能介绍:
查找路径功能:
作为一个室内定位的主要应用,当然是要如同室外GPS定位一样,要有导航功能,我们项目的核心功能当然就是查找路径功能,原理是我们使用A*算法,计算出从出发点到目的位置的最短距离,并显示在地图中,方便使用。如图为平面图中对路径的检索。并显示到地图中,用户可以根据地图上的指示方便的找到所要去的房间(或如商铺等)
图7查找功能示例
六:电子指南针
6.1.引言
在当今众多的定位软件中,我们发现当今很多软件只注重定位,而忽视了用户的朝向,使得系统当用户转身,调转方向时无法做出反应,给用户造成了很多不便。为了弥补这一缺陷,我们又将电子指南针附加在定位系统中,使得当用户转身时,系统可以根据电子指南针指向的不同做出反应。
6.2.应用软硬件:
(1)Arduino,是一个基于开放原始码的软硬体平台,构建于开放原始码simple I/O介面版,并且具有使用类似Java,C语言的Processing/Wiring开发环境。它能通过各种各样的传感器来感知环境,通过控制灯光、马达和其他的装置来反馈、影响环境。
(2)Arduino UNO 单片机:
一款与arduino开发环境配套的单片机,功能强大。
图8 Arduino Uno 单片机
(3)HMC5883L:
一款经常与九轴陀螺仪结合的电磁指南针芯片,可以敏锐的感受到地磁场变化。
6.3.单片机程序:
HMC5883L接上电后可以通过I2C协议与Arduino单片机芯片展开通讯,为此我们调用了HMC5883L.h库与之通讯。
首先,调用I2C库与HMC5883L.h库,并定义HMC5883L芯片变量与串口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | #include <Wire.h> #include <HMC5883L.h> HMC5883L compass;//定义库中HMC5883L芯片的变量为compass Serial.begin(38400); int error = 0; Wire.begin();//I2C初始化 compass = HMC5883L(); // 构筑新HMC5883L指南针 error = compass.SetScale(1.3); // 设置指南针大小 error = compass.SetMeasurementMode(Measurement_Continuous); // 将发送模式//设为不间断发送 之后,在系统不断处理的函数Void loop()中收集数据: MagnetometerRaw raw = compass.ReadRawAxis();//读取数据 MagnetometerScaled scaled = compass.ReadScaledAxis();//读取数据 int MilliGauss_OnThe_XAxis = scaled.XAxis; float heading = atan2(scaled.YAxis, scaled.XAxis);//计算朝向 float declinationAngle = 0.0457; heading += declinationAngle; if(heading < 0) heading += 2*PI; if(heading > 2*PI) heading -= 2*PI;//处理芯片朝向 float headingDegrees = heading * 180/M_PI; Serial.println(","); Serial.println(headingDegrees);//输出数据,heading为北朝向 |
如此一来,compass 传回的数据便是与正北方向的夹角,并从串口传回。
6.4.电脑3D模拟
接收到数据后,电脑将收到的数据通过与zigbee模块数据相同的处理技术,将传回的数据存入一整型变量中,之后,在运用processing 强大的3D生成功能进行3D控制。这样,系统的客户端便可以根据传回的数据及时改变用户的朝向,并与之前的zigbee室内定位系统结合。
七:安卓客户端
我们已经实现了定位系统在安卓机上的应用,通过安卓机与bluetooth-zigbee-arduino三合一模块信息交换体现在安卓机上并实现了定位与路径搜索的功能。具体展示请登录育才网论坛:
http://www.iyucai.com 创新大赛专版查看。
关于我们的具体信息请登录育才网论坛:
http://www.iyucai.com 创新大赛专版 查看。
我们会将照片演示视频其后放置在其上,因学业紧张,可能会有延迟更新,请联系我们获得资料(在该论坛上发帖并email:a@yucai.me ),我们会尽快与您联系。
test