打印

基于ESP32的位置实时显示

[复制链接]
3814|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 gaochy1126 于 2020-12-15 12:36 编辑

#申请原创#   @21小跑堂
之前玩航模的时候,飞机飞丢了。设备信号传输不好,飞丢位置找不到了,造成了一定的经济损失,所以想做一个位置跟踪和展示的设备。
这是做的一个简单的框架图。因为设备需要锂电池供电,所以功耗需要降低。
同时数据还需要同步到Web网页数据上,所以WebSocket 是最好的选择。
实现的模式是终端设备通过网络将位置数据传输到服务上,然后保存相关数据,并将数据推送到Web网页上显示。



先来个视频看看效果怎么样。这个是开着车跑了一圈,检测效果怎么样。基本上能够实时传输地址,说明通信的速度和显示的效果都可以的。
https://player.youku.com/embed/XNTAwODMxNTI1Mg==


看到很多的人都在玩ESP32。而且是arduino的开发环境,开发比较简单,而且性能和价格都比较便宜一些。第三方的库文件比较多,不需要自己另外的编写库函数。所以选择了ESP32作为处理器了。ESP32超低功耗, 专为移动设备、可穿戴电子产品和物联网应用而设计,具有业内高水平的低功耗性能,包括精细分辨时钟门控、省电模式和动态电压调整等。ESP32 只需极少的外围器件,即可实现强大的处理性能、可靠的安全性能,和 Wi-Fi & 蓝牙功能。


看到网上有SIM868,sim868是一款体积很小的2G模块,包含GPS GSM GPRS功能。定位精度2.5米左右。这样就节省了使用GPS模块的花费,而且SIM868还可以有网络定位的功能,如果前期GPS信号不好的时候,可以使用网络定位作为信号的补充。

服务器的购买环节就不在这里赘述了。现在新用户的优惠比较多一些。几百块钱可以用一年多,算是自己研究着玩吧。
通信协议选择了MQTT。 (MQTT) 是轻量级基于代理的发布/订阅的消息传输协议,设计思想是开放、简单、轻量、易于实现。小型传输,开销很小(固定长度的头部是 2 字节),协议交换最小化,以降低网络流量。而且在paho-mqtt库中,有一种重要的函数–回调函数。这个在网页开发比较简单了。

在服务器上搭建一个MQTT的服务器,有两种选择一个EMQ X和 mosquitto。MQ X Broker 是基于高并发的 Erlang/OTP 语言平台开发,支持百万级连接和分布式集群架构,发布订阅模式的开源 MQTT 消息服务器。Eclipse Mosquitto是一个开源消息代理,实现了MQTT协议版本3.1和3.1.1。Mosquitto轻量,适用于低功耗单板计算机到完整服务器的所有设备。
经过综合评估,于是在服务器上搭建了一个EMQ 的服务器,因为保存数据到SQL数据库,需要企业级别的才行(价格比较高)。所以选择了另外的方式进行保存:在MQTT服务器上搭建了Web_Hook的方式进行保存,节省了一笔开销。EMQ的安装建议大家百度一下,网上有很多的教程,建议开启账号和密码的验证功能,这样防止数据的泄漏。

页面展示使用百度地图。百度地图的开发比较成熟了,而且API函数非常的多,可以直接调用,性能也不错。
先从显示网页的开发介绍起来。

百度地图的显示建议搜索百度API代码非常的多。推荐地址http://lbsyun.baidu.com/index.php?title=jspopularGL 。查看demo的地址http://lbsyun.baidu.com/jsdemo.htm#a1_2
需要注意的是:GPS的经纬度转换到百度地图,需要多次转换才行。
目前国内主要有以下三种坐标系:

WGS84:为一种大地坐标系,也是目前广泛使用的GPS全球卫星定位系统使用的坐标系。

GCJ02:又称火星坐标系,是由中国国家测绘局制订的地理信息系统的坐标系统。由WGS84坐标系经加密后的坐标系。

BD09:为百度坐标系,在GCJ02坐标系基础上再次加密。其中bd09ll表示百度经纬度坐标,bd09mc表示百度墨卡托米制坐标。

附上一个JavaScript坐标系转换的代码。
        var GPS = {
            PI: 3.14159265358979324,
            x_pi: 3.14159265358979324 * 3000.0 / 180.0,
            delta: function (lat, lon)
            {
                var a = 6378245.0; //  a: 卫星椭球坐标投影到平面地图坐标系的投影因子。
                var ee = 0.00669342162296594323; //  ee: 椭球的偏心率。
                var dLat = this.transformLat(lon - 105.0, lat - 35.0);
                var dLon = this.transformLon(lon - 105.0, lat - 35.0);
                var radLat = lat / 180.0 * this.PI;
                var magic = Math.sin(radLat);
                magic = 1 - ee * magic * magic;
                var sqrtMagic = Math.sqrt(magic);
                dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * this.PI);
                dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * this.PI);
                return { 'lat': dLat, 'lon': dLon };
            },

            //WGS-84 to GCJ-02
            gcj_encrypt: function (wgsLat, wgsLon)
            {
                if (this.outOfChina(wgsLat, wgsLon))
                    return { 'lat': wgsLat, 'lon': wgsLon };

                var d = this.delta(wgsLat, wgsLon);
                return { 'lat': wgsLat + d.lat, 'lon': wgsLon + d.lon };
            },
            //GCJ-02 to WGS-84
            gcj_decrypt: function (gcjLat, gcjLon)
            {
                if (this.outOfChina(gcjLat, gcjLon))
                    return { 'lat': gcjLat, 'lon': gcjLon };

                var d = this.delta(gcjLat, gcjLon);
                return { 'lat': gcjLat - d.lat, 'lon': gcjLon - d.lon };
            },
            //GCJ-02 to WGS-84 exactly
            gcj_decrypt_exact: function (gcjLat, gcjLon)
            {
                var initDelta = 0.01;
                var threshold = 0.000000001;
                var dLat = initDelta, dLon = initDelta;
                var mLat = gcjLat - dLat, mLon = gcjLon - dLon;
                var pLat = gcjLat + dLat, pLon = gcjLon + dLon;
                var wgsLat, wgsLon, i = 0;
                while (1)
                {
                    wgsLat = (mLat + pLat) / 2;
                    wgsLon = (mLon + pLon) / 2;
                    var tmp = this.gcj_encrypt(wgsLat, wgsLon)
                    dLat = tmp.lat - gcjLat;
                    dLon = tmp.lon - gcjLon;
                    if ((Math.abs(dLat) < threshold) && (Math.abs(dLon) < threshold))
                        break;

                    if (dLat > 0) pLat = wgsLat; else mLat = wgsLat;
                    if (dLon > 0) pLon = wgsLon; else mLon = wgsLon;

                    if (++i > 10000) break;
                }
                //console.log(i);
                return { 'lat': wgsLat, 'lon': wgsLon };
            },
            //GCJ-02 to BD-09
            bd_encrypt: function (gcjLat, gcjLon)
            {
                var x = gcjLon, y = gcjLat;
                var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * this.x_pi);
                var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * this.x_pi);
                bdLon = z * Math.cos(theta) + 0.0065;
                bdLat = z * Math.sin(theta) + 0.006;
                return { 'lat': bdLat, 'lon': bdLon };
            },
            //BD-09 to GCJ-02
            bd_decrypt: function (bdLat, bdLon)
            {
                var x = bdLon - 0.0065, y = bdLat - 0.006;
                var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * this.x_pi);
                var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * this.x_pi);
                var gcjLon = z * Math.cos(theta);
                var gcjLat = z * Math.sin(theta);
                return { 'lat': gcjLat, 'lon': gcjLon };
            },
            //WGS-84 to Web mercator
            //mercatorLat -> y mercatorLon -> x
            mercator_encrypt: function (wgsLat, wgsLon)
            {
                var x = wgsLon * 20037508.34 / 180.;
                var y = Math.log(Math.tan((90. + wgsLat) * this.PI / 360.)) / (this.PI / 180.);
                y = y * 20037508.34 / 180.;
                return { 'lat': y, 'lon': x };
            },
            // Web mercator to WGS-84
            // mercatorLat -> y mercatorLon -> x
            mercator_decrypt: function (mercatorLat, mercatorLon)
            {
                var x = mercatorLon / 20037508.34 * 180.;
                var y = mercatorLat / 20037508.34 * 180.;
                y = 180 / this.PI * (2 * Math.atan(Math.exp(y * this.PI / 180.)) - this.PI / 2);
                return { 'lat': y, 'lon': x };
            },
            // two point's distance
            distance: function (latA, lonA, latB, lonB)
            {
                var earthR = 6371000.;
                var x = Math.cos(latA * this.PI / 180.) * Math.cos(latB * this.PI / 180.) * Math.cos((lonA - lonB) * this.PI / 180);
                var y = Math.sin(latA * this.PI / 180.) * Math.sin(latB * this.PI / 180.);
                var s = x + y;
                if (s > 1) s = 1;
                if (s < -1) s = -1;
                var alpha = Math.acos(s);
                var distance = alpha * earthR;
                return distance;
            },
            outOfChina: function (lat, lon)
            {
                if (lon < 72.004 || lon > 137.8347)
                    return true;
                if (lat < 0.8293 || lat > 55.8271)
                    return true;
                return false;
            },
            transformLat: function (x, y)
            {
                var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
                ret += (20.0 * Math.sin(6.0 * x * this.PI) + 20.0 * Math.sin(2.0 * x * this.PI)) * 2.0 / 3.0;
                ret += (20.0 * Math.sin(y * this.PI) + 40.0 * Math.sin(y / 3.0 * this.PI)) * 2.0 / 3.0;
                ret += (160.0 * Math.sin(y / 12.0 * this.PI) + 320 * Math.sin(y * this.PI / 30.0)) * 2.0 / 3.0;
                return ret;
            },
            transformLon: function (x, y)
            {
                var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
                ret += (20.0 * Math.sin(6.0 * x * this.PI) + 20.0 * Math.sin(2.0 * x * this.PI)) * 2.0 / 3.0;
                ret += (20.0 * Math.sin(x * this.PI) + 40.0 * Math.sin(x / 3.0 * this.PI)) * 2.0 / 3.0;
                ret += (150.0 * Math.sin(x / 12.0 * this.PI) + 300.0 * Math.sin(x / 30.0 * this.PI)) * 2.0 / 3.0;
                return ret;
            }
        };

加载百度地图的关键代码 <script type="text/javascript" src="//api.map.baidu.com/api?v=2.0&ak=您的密钥"></script>其他的代码都是配置代码了。
然后再JavaScript编写MQTT的协议就行了。
下面开始做MQTT初始化;XXXX为服务器地址,需要配置服务器为Wss,即需要证书。
client = new Paho.MQTT.Client("XXXXX", Number(8084), GenNonDuplicateID());
连接MQTT,并订阅 Pos的位置。
//初始化客户端选项 conn_opts
client.connect({
              onSuccess: onConnect
}
);
//连接服务器并注册连接成功处理事件
function onConnect() {
    console.log("onConnected");
    client.subscribe("pos", {
        qos: 0
    }
    );
}
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;

这里是添加标志的代码
var myIcon = new BMap.Icon("__INDEX__/img/car.gif", new BMap.Size(20, 40));
        var point = new BMap.Point(lon, lat);
        var marker = new BMap.Marker(point, {
                    icon: myIcon
                });



未完待续。。。。。



使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:这个社会混好的两种人:一是有权有势,二是没脸没皮的。

1025

主题

11271

帖子

25

粉丝