跳转至

基站/WIFI/GPS定位

一、基站/wifi/GPS 定位概述

1.1 基站定位原理

基站定位也就是"LBS 定位",全称是 Location Based Service,它包括两层含义:首先是确定移动设备或用户所在的地理位置;其次是提供与位置相关的各类信息服务。意指与定位相关的各类服务系统,简称"定位服务"。

多基站定位中,模块正常联网后,搜索并上报周围的基站信息, 上报到服务器后, 服务器根据三角定位法, 估算出一个大概的坐标,最后返回计算出来的经纬度给模块。

单基站定位中,模块正常联网后,搜索并上报周围的基站信息,服务器会存储多数已知基站的经纬度,根据模块上报的基站信息,直接下发对应位置的经纬度数据。

多基站一般精度在 10-300 米内,单基站误差有可能会在 1.5KM 内

1.2 wifi 定位原理

WIFI 定位的原理和基站定位原理类似,搜索并上报附近的 wifi 信息, 上报到服务器后, 服务器根据三角定位法, 估算出一个大概的坐标,精度在 50~500 米不等。

1.3 GPS 定位原理

GPS 不限制终端数,在 GPS 卫星信号不被阻挡的情况下,在地球上任何地点、任何时间,任何 GPS 终端都可以得到正确的位置和时间。定位只需要一个条件,那就是能够接收到足够多的卫星信号。因此在室内通常无法定位。

1.4 免费和收费服务区别

在过去的时间里,合宙为您提供了免费的单基站(LBS)定位服务,为您创造了重要价值。

但是由于单基站定位技术本身的原因,无法提供相对精准的定位服务。

在产品不支持 GPS 功能的情况下,为了满足部分用户更精准的定位需求,合宙现在已推出了多 LBS/WIFI 定位收费服务,相对于免费的单 LBS 定位服务来说,定位精度更高。

1.4.1 免费服务

1. 免费服务仅支持单基站定位,无 wifi 定位, 使用旧的后台接口,只使用合宙数据库,当前请求频率限制:2 分钟最多 1 次。

2. 超过频次的定位请求均会返回定位失败。返回错误码,不包含位置信息。

1.4.2 收费服务

收费服务支持多基站定位和 wifi 定位,相对于免费的单 LBS 定位服务来说,定位精度更高。

收费服务有两种,一种是直接使用合宙的基站 WIFI 位置数据库,一种是直接使用高德的基站 WIFI 位置数据库;

这两种服务的主要区别是:

合宙数据库可能没有高德数据库的位置信息全,虽然可能不是很全,但是合宙数据库每天都会自动收集更新新的位置信息到数据库中,如果在位置的精准度和收费成本上,做个权衡,可以选择合宙数据库的收费服务;如果对成本不敏感,对位置的精准度要求很高,可以选择高德数据库的收费服务。

1. 合宙数据库

注意:只有用2014年11月25号后的lib库才能支持。

相比与免费版的优势:支持多基站和 WIFI 定位,定位精度高

使用合宙数据库,根据请求频率限制,收费价格表如下:

每小时请求次数限制
每次请求间隔限制
单台设备年费(元)
12
至少 5 分钟
1 元
24
至少 2.5 分钟
2 元
60
至少 1 分钟
5 元
240
至少 15 秒
10 元

2. 高德数据库

注意:只有用2014年11月25号后的lib库才能支持。

相比与免费版的优势:支持多基站和 WIFI 定位,不请求合宙数据库,直接请求高德数据库,定位精度更高

使用高德数据库,根据请求频率限制,收费价格表如下:

每小时请求次数限制
每次请求间隔限制
单台设备年费(元)
12
至少 5 分钟
10 元
24
至少 2.5 分钟
20 元
60
至少 1 分钟
50 元

3. 收费服务开通

在 IOT 平台开启付费服务 iot.openluat.com

注:当前后台还未支持新的开启收费服务的前端自主缴费功能,待后续补充,目前如需开通收费服务,需告知合宙销售要开通的 iot 账号和设备 IMEI 列表,与合宙销售同事对接商务流程。

4. 查看已经开通的收费业务

首先登录平台 iot.openluat.com,点击 LBS 服务

进入后我们可以在我的订单中查看已开通的收费服务

二、演示功能概述

Air201 支持三种定位,分别是 LBS 定位,WIFI 定位,GPS 定位

本文主要介绍基于合宙 Air201 来实现定位服务,大致流程如下:

1. 免费版本基站定位

烧录示例 demo,通过 lbsLoc2.request 接口发起请求,进行单基站定位

2. 收费版本 wifi+ 基站混合定位

联系销售开通付费服务,然后去 iot 平台 LBS 服务中查看自己的 id 和 key,烧录示例 demo,通过 airlbs.request 接口发起请求,上报基站和 wifi,进行混合定位

3. gps 定位

烧录示例 demo,实现 gps 定位

三、准备硬件环境

3.1 Air201 模组

使用 Air201 开发套件,如下图所示:

淘宝购买链接:Air201 开发套件淘宝购买链接

此开发套件的详细使用说明参考:Air201 产品手册 中的 Air201 硬件手册Air201 的 LuatOS 快速入门

3.2 SIM 卡

请准备一张可正常上网的 SIM 卡,该卡可以是物联网卡或您的个人手机卡。

特别提醒: 请确保 SIM 卡未欠费且网络功能正常,以便顺利进行后续操作。

3.3 PC 电脑

WIN10 以及以上版本的 WINDOWS 系统。

3.4 数据通信线

USB 数据线(其一端为 Type-C 接口,用于连接 Air201)。

四、准备软件环境

“凡事预则立,不预则废。”在详细阐述本功能示例之前,我们需先精心筹备好以下软件环境。

1. Luatools 工具

2. 内核固件文件(底层 core 固件文件):core/LuatOS-SoC_V2002_Air201.soc · 合宙 Luat/LuatOS-Air201 - Gitee.com;

3. luatos 需要的脚本和资源文件

GPS 定位脚本所在位置:https://gitee.com/openLuat/LuatOS-Air201/blob/master/demo/gps_lbs_wifi/gnss.lua

免费版本基站定位所在位置:https://gitee.com/openLuat/LuatOS-Air201/blob/master/demo/lbsLoc2/main.lua

付费版本基站定位所在位置:https://gitee.com/openLuat/LuatOS-Air201/blob/master/demo/airlbs/main.lua

五、软硬件资料

5.1 API 接口介绍

本教程使用 api 接口为:

1. airlbs - airlbs 定位服务(收费服务,需自行联系销售申请) - LuatOS 文档 付费版本基站定位 api 接口

2. lbsLoc2 - 基站定位 v2 - LuatOS 文档 免费版本单基站定位 api 接口

3. libgnss - NMEA 数据处理 - LuatOS 文档

5.2 Air201 烧录说明

将 Air201 通过 usb-boot 小板连接电脑,如下图所示:

注意:boot 小板和 Air201 连接时,要确保 RESET 按键,BOOT 按键,电源开关机键 三个按键在同一侧,否则无法进入 boot 下载模式。

如何判断有没有进入下载模式:可以通过 PC 端的设备管理器中虚拟出来的 USB 断开数量来判断,

正常开机模式:

下载模式:

六、代码示例介绍

三种定位示例:GPS 定位,基站定位免费版本和基站定位付费版本,基站定位免费版本只有单基站定位,基站定位付费版本有多基站定位和 wifi+ 基站混合定位

6.1 GPS 定位

6.1.1 代码介绍

1. 打开 gps 的供电和复位引脚

local function gnssPower(onoff)
    gpio.setup(26, onoff and 1 or 0)
    gpio.setup(25, onoff and 1 or 0)
end

2. 开机后初始化一些 gps 和打印数据的端口,清空一下历史定位数据,设置端口参数,更新星历,绑定端口

sys.taskInit(function()
    log.info("GPS", "start")
    -- 开启gps的供电引脚
    gnssPower(isOn);

    local uartId = 2
    libgnss.clear() -- 清空数据,兼初始化
    -- 设置端口2波特率为115200
    uart.setup(uartId, 115200)

    sys.wait(200) -- GPNSS芯片启动需要时间
    -- 更新星历,使用agps辅助定位功能
    gnss.agps()
    -- 调试日志,可选
    libgnss.debug(true)
    -- 绑定读取gnss数据的端口
    libgnss.bind(2)
end)

3. 订阅 gnss 状态,gnss 有两种状态,FIXED-定位成功和 LOSE-定位丢失。

-- 订阅GNSS状态编码
sys.subscribe("GNSS_STATE", function(event, ticks)
    -- event取值有
    -- FIXED 定位成功
    -- LOSE  定位丢失
    -- ticks是事件发生的时间,一般可以忽略
    log.info("gnss", "state", event, ticks)
    if event == "FIXED" then
        -- 当定位成功时,打印位置字符串
        local locStr = libgnss.locStr()
        log.info("gnss", "locStr", locStr)
        isFix = true
    elseif event == "LOSE" then
        -- 当定位失败时,打印个日志提示一下
        log.info("gnss", "no fix")
    end
end)

4. 写入星历,即 apgs 辅助定位。

local function doAgps()
    -- 首先, 发起位置查询
    local lat, lng
    if mobile then
        -- 查询基站信息
        mobile.reqCellInfo(6)
        -- 等待基站数据已更新的消息,超时时间6秒
        sys.waitUntil("CELL_INFO_UPDATE", 6000)
        -- 包含一下lbsLoc2库
        local lbsLoc2 = require("lbsLoc2")
        -- 执行定位请求,返回坐标的纬度和精度
        lat, lng = lbsLoc2.request(5000)
        log.info("lbsLoc2", lat, lng)
        if lat and lng then
            -- 确保lat和lng是数字
            lat = tonumber(lat)
            lng = tonumber(lng)
            log.info("lbsLoc2", lat, lng)
        end
    end
    if not lat then
        log.info("not lat")
        -- 获取最后的本地位置
        local locStr = io.readFile("/hxxtloc")
        if locStr then
            local jdata = json.decode(locStr)
            if jdata and jdata.lat then
                lat = jdata.lat
                lng = jdata.lng
            end
        end
    end
    -- 然后, 判断星历时间和下载星历
    local now = os.time()
    local agps_time = tonumber(io.readFile("/hxxt_tm") or "0") or 0
    log.info("now-->",now,"---agps_time-->",agps_time)
    if now - agps_time > 3600 then
        -- local url = "http://download.openluat.com/9501-xingli/HXXT_GPS_BDS_AGNSS_DATA.dat" -- GPS和北斗
        local url = "http://download.openluat.com/9501-xingli/HXXT_ALL_AGNSS_DATA.dat"        -- 全星历

        local code = http.request("GET", url, nil, nil, {
            dst = "/hxxt.dat"
        }).wait()
        if code and code == 200 then
            log.info("下载星历成功", url)
            io.writeFile("/hxxt_tm", tostring(now))
        else
            log.info("下载星历失败", code)
        end
    else
        log.info("星历不需要更新", now - agps_time)
    end
    -- 写入星历
    local agps_data = io.readFile("/hxxt.dat")
    if agps_data and #agps_data > 1024 then
        log.info("写入星历数据", "长度", #agps_data)
        for offset = 1, #agps_data, 512 do
            log.info("gnss", "AGNSS", "write >>>", #agps_data:sub(offset, offset + 511))
            sys.wait(100) -- 等100ms反而更成功
        end
    else
        log.info("没有星历数据")
        isFix = false
        return
    end

    -- 写入参考位置
    -- "lat":23.4068813,"min":27,"valid":true,"day":27,"lng":113.2317505
    if not lat or not lng then
        -- lat, lng = 23.4068813, 113.2317505
        log.info("没有GPS坐标", lat, lng)
        isFix = false
        return -- TODO 暂时不写入参考位置
    end
    if socket.sntp then
        --时间同步
        socket.sntp()
        --等待时间同步成功消息
        sys.waitUntil("NTP_UPDATE", 1000)
    end
    --获取日期函数,参数1是格式化字符串
    local date = os.date("!*t")
    if date.year >= 2024 then
        local str = string.format("$AIDTIME,%d,%d,%d,%d,%d,%d,000", date["year"], date["month"], date["day"], date["hour"], date["min"], date["sec"])
        log.info("参考时间", str)
        sys.wait(20)
    end

    local str = string.format("$AIDPOS,%.7f,%s,%.7f,%s,1.0\r\n", lat > 0 and lat or (0 - lat), lat > 0 and 'N' or 'S', lng > 0 and lng or (0 - lng), lng > 0 and 'E' or 'W')
    log.info("写入AGPS参考位置", str)
    sys.wait(200)
    local times = 0
    while times < 120 do
        if isFix then
            break
        end
        times = times + 1
        sys.wait(1000)
    end
    sys.wait(6000)
    isFix = false
    -- 两小时更新一次星历吧
    sys.timerStart(gnss.agps, 2 * 60 * 60 * 1000)
end

local agpsTaskHandle

-- 下载并写入星历
function gnss.agps()
    if not agpsTaskHandle or coroutine.status(agpsTaskHandle) == "dead" then
        agpsTaskHandle = sys.taskInit(doAgps)
    end
end

6.1.2 运行结果展示

定位成功后,获取位置字符串。

6.2 免费版本基站定位

免费版本仅支持单基站定位,若需要更精准的定位服务,请查看付费版本多基站定位或 GPS 定位。

6.2.1 代码介绍

local lbsLoc2 = require("lbsLoc2")
sys.taskInit(function()
    sys.waitUntil("IP_READY", 30000)
    while mobile do -- 没有mobile库就没有基站定位
        local lat, lng, t = lbsLoc2.request(5000)--仅需要基站定位给出的经纬度
        --local lat, lng, t = lbsLoc2.request(5000,nil,nil,true)--需要经纬度和当前时间
        --(时间格式{"year":2024,"min":56,"month":11,"day":12,"sec":44,"hour":14})
        log.info("lbsLoc2", lat, lng, (json.encode(t or {})))
        sys.wait(60000)
    end
end)

6.2.2 运行结果展示

6.3 付费版本多基站定位

付费版本 可以使用多基站/基站 +wifi 定位多种方式,当然,受限于模块设计,在使用 wifi 扫描时候,4G 数据传输较慢丢包概率较大,所以尽量在 wifi 扫描完毕后,再进行数传工作

6.3.1 代码介绍

local airlbs = require "airlbs"

local timeout = 15--扫描基站做基站定位的超时时间,最小5S,最大60S
-- 此为收费服务,需自行联系销售申请
local airlbs_project_id = ""
local airlbs_project_key = ""

sys.taskInit(function()
    sys.waitUntil("IP_READY")

    socket.sntp()
    sys.waitUntil("NTP_UPDATE", 1000)

    while 1 do
        local result , data = airlbs.request({project_id = airlbs_project_id,project_key = airlbs_project_key,timeout =timeout*1000})
        if result then
            print("airlbs多基站定位返回的经纬度数据为", json.encode(data))
        end
        sys.wait(20000)
    end

end)

6.3.2 运行结果显示

6.4 付费版本 wifi+ 基站混合定位

付费版本 可以使用多基站/基站 +wifi 定位多种方式,当然,受限于模块设计,在使用 wifi 扫描时候,4G 数据传输较慢丢包概率较大,所以尽量在 wifi 扫描完毕后,再进行数传工作。

6.4.1 代码介绍

1. 初始化:等待联网,初始化 wlan,扫码 wifi 频段。

sys.taskInit(function()
    sys.waitUntil("IP_READY")
    -- 如需wifi定位,需要硬件以及固件支持wifi扫描功能
    local wifi_info = nil
    if wlan then
        sys.wait(3000) -- 网络可用后等待一段时间才再调用wifi扫描功能,否则可能无法获取wifi信息
        wlan.init()
        wlan.scan()
        sys.waitUntil("WLAN_SCAN_DONE", timeout * 1000)
        wifi_info = wlan.scanResult()
        log.info("scan", "wifi_info", #wifi_info)
    end
end)

2. wifi+ 基站混合定位

wifi 扫描成功后,通过 airlbs.request 发送定位请求,进行混合定位。

while 1 do
    local result, data = airlbs.request({
        project_id = airlbs_project_id,
        project_key = airlbs_project_key,
        wifi_info = wifi_info,
        timeout = timeout * 1000
    })
    if result then
        print("airlbs wifi+多基站混合定位的结果", json.encode(data))
    end
    sys.wait(20000) -- 循环20S一次wifi定位
end

6.4.2 运行结果展示

本示例采用 wifi+ 多 LBS 混合定位,使用 airlbs.request 接口,上报基站和 wifi,进行混合定位。

开通了付费服务后,会显示附近多个基站定位信息,基站定位成功后会返回获取到的经纬度信息,如下图所示:

相对于免费的单 LBS 定位服务来说,定位精度更高。

七、总结

本章简单介绍了如何使用合宙免费基站定位,付费基站定位,GPS 定位,相对于免费的单 LBS 定位服务来说,收费版定位精度更高。

八、常见问题

1. 基站定位精度如何?

搜索到的小区越多,定位的精度越高;一般来说,城市中心定位精度比郊区和农村定位精度高,城市中心的定位精度在几十米到几百米不等,郊区和农村的定位精度更低,可能会有几千米甚至更多的误差。

通过多小区定位,将实时搜索到的所有小区同时上报给后台参与定位,基站定位的误差都比较大,如果需要准确定位,请使用支持 GPS 的模块。

2. 为什么基站定位失败?

(1)后台基站数据库查询不到所有小区的位置信息;在 LuaTools 脚本日志中向上搜索 mcc,mnc,lac,ci,然后在电脑浏览器中打开定位查询,手动查找 mcc,mnc,lac,ci 后的所有小区位置;

如果手动可以查到位置,则服务器存在 BUG,直接向技术支持人员反映问题;如果手动无法查到位置,则基站数据库还没有收录当前设备的小区位置信息,向技术支持人员反馈,我们会尽快收录。

(2)达到了总的 qps 限制数量。

3. 合宙官方的基站定位能在国外使用吗?

不能,没有国外的基站数据库。

4. 基站/WIFI 定位定位获取的经纬度是什么格式的?

基站定位获取的经纬度为 WGS-84 格式,各种坐标系说明以及转换方法请网上搜索坐标系在线转换工具即可查询。

5. GPS 定位经纬度不准确

(1)坐标没有纠偏,GPS 定位输出的坐标为 WGS84 坐标系,请网上搜索坐标系在线转换工具进行纠偏

(2)周围有比较高的障碍物,会导致定位误差

(3)在开阔地带,正常情况下定位精度只能做到 5 米

(4)不能在室内测试,必须到室外测试;如果只能在室内测试,可以淘宝搜索“gps 信号转发器”