Posicionamento Indoor e Outdoor com BLE + LoRaWAN: Construção, Implantação e Resultados Medidos
Este não é um sistema com certificação de segurança: uplinks LoRaWAN podem ser perdidos, GNSS não funciona em ambientes internos e o posicionamento BLE se degrada perto de metal, então uma posição pode chegar atrasada, errada ou faltar. Não use isto como a única proteção para a segurança das pessoas.
O que esta solução faz
Um local geralmente tem tanto um prédio quanto uma área externa, e a pergunta é a mesma em ambos: onde está aquela empilhadeira, aquele instrumento, aquela pessoa, agora. Beacons alimentados por bateria marcam posições em ambientes internos; o próprio GNSS do rastreador assume em ambientes externos; ambos retornam via LoRaWAN, e um painel web os desenha em um único mapa. Uma planta baixa pode ser georreferenciada sobre o mapa externo, de modo que um trajeto que começa em um prédio e continua no pátio permaneça em uma única tela.
- Implementação open source: github.com/Seeed-Solution/Solution_IndoorPositioning_H5
- Escolhendo uma configuração e implantando: página de reference design
Sem cabeamento no lado de sensoriamento
Os beacons são alimentados por bateria e colados na parede; um rastreador reporta por meses com uma única carga. O que precisa de alimentação da rede elétrica e de um ponto de rede é o gateway e o host.
Ambientes interno e externo em um único mapa, alternado automaticamente
Quando um rastreador entra ou sai de um prédio, uma máquina de estados no lado do servidor alterna a camada; nada para alternar manualmente, e um rastreador parado perto de uma janela não fica mudando de um lado para o outro.
Open source, dados permanecem no seu host
O código-fonte da aplicação está no GitHub e roda como uma imagem Docker no seu próprio host. A única coisa que chega à internet é o mapa base, que pode ser substituído por um arquivo PMTiles offline.
Capacidade de servidor medida
200 tags simultâneas com P95 fim a fim de 828 ms com 0% de perda; 500 tags com P95 de 2,35 s. Testado com uplinks reproduzidos, sem rastreador ou gateway conectado.
Saída em tempo real
A camada indoor desenha os rastreadores na planta baixa registrada:

A camada outdoor é a mesma página no mesmo WebSocket, com tiles de mapa como base:

Um rastreador se movendo entre as duas:

O cliente no telefone mostra os mesmos dados:

O dashboard é uma única página em /web/map com uma troca de camada explícita entre Indoor e Outdoor; /web/map?layer=outdoor é um link direto adequado para um display de parede e assina o mesmo WebSocket. Um rastreador é desenhado em exatamente uma das duas visualizações por vez. Qual delas é decidido pela máquina de estados, e a decisão é carregada na mensagem como position.coordSystem — metric para um {x, y} de planta baixa, wgs84 para um {lat, lon}.
De que hardware você precisa
Três tipos de dispositivo no local; o número de beacons e rastreadores escala com a implantação.
① Beacons BLE — a referência de posição indoor. Alimentados por bateria, montados na parede, sem fiação. Áreas cobertas apenas por GNSS (pátios, estradas, estacionamento) não precisam de nenhum.
② O rastreador — carregado pela pessoa ou preso ao ativo. Ele faz varredura BLE em ambientes internos e usa seu próprio GNSS em ambientes externos, e tem um botão de SOS.
③ O gateway LoRaWAN — coleta os uplinks e os encaminha para um servidor de rede. Peça o gateway e o rastreador para a mesma banda regional.
| Dispositivo | Capacidade nominal | Quando escolhê-lo | |
|---|---|---|---|
| SenseCAP BC03 Indoor Bluetooth Beacon Referência de posição indoor, Bluetooth LE 5.0 | 2–3 m com 3+ por zona; nível de sala com 1 | Qualquer área indoor que precise ser resolvida melhor do que “dentro do prédio” | |
| SenseCAP LoRaWAN Card Tracker T1000-A Varredura BLE, GNSS, detecção de movimento, SOS | Um por pessoa ou ativo rastreado | O crachá ou tag de ativo; a mesma unidade cobre ambientes interno e externo | |
![]() | SenseCAP M2 LoRaWAN Indoor Gateway SX1302, variantes de frequência regionais | Até 2 km em linha de visada; 100–200 rastreadores | Um ou dois por local; ignore se você já opera LoRaWAN |
Todas as cifras de capacidade na tabela são nominais, a partir dos datasheets dos dispositivos e da prática de implantação com este hardware. A precisão do beacon depende da instalação descrita abaixo.
Além dos dispositivos, você precisa de um host para a aplicação (qualquer máquina que rode Docker; as medições no lado do servidor usaram uma unidade reComputer J30 series como um host arm64 simples), um servidor de rede — SenseCAP OpenStream ou seu próprio ChirpStack — e, a menos que você construa o mapa base offline, acesso à internet no host para tiles raster do OpenStreetMap.
Limites de Seleção Negativa
- Rastreamento Contínuo Submétrico: a precisão de beacon BLE é de 2–3 metros. Para navegação de AGV em alta velocidade ou máquinas automatizadas que exigem rastreamento contínuo submétrico, escolha UWB em vez de BLE.
- Intertravamentos de Segurança em Tempo Real: a comunicação LoRaWAN envolve latência e restrições de duty cycle com um limite de 15 minutos offline; não use para intertravamentos de segurança em escala de sub-segundo.
Implantando no local
1. Instale o hardware
Instale beacons a 2,5–3 m de altura com espaçamento de 5–10 m (o espaçamento recomendado do BC03), e adicione beacons onde houver prateleiras metálicas. Três ou mais beacons por zona é o que a cifra nominal de 2–3 m assume; um único beacon por zona resolve ao nível de sala. Registre o endereço MAC e a localização de cada beacon — posições indoor são calculadas a partir do mapeamento beacon-para-zona, então atualize o mapeamento sempre que um beacon for movido, ou toda posição derivada dele será deslocada.
Dimensione os gateways pela cobertura: o alcance nominal em linha de visada é de 2 km, então um ou dois cobrem um local típico; adicionar um segundo depende de paredes e distância, não da quantidade de tags. O gateway é fornecido em SKUs por banda (US915 / EU868 / AS923, etc.); confirme a banda de frequência do país antes de fazer o pedido e combine o rastreador com ela.
2. Instale o software: 7 etapas
As etapas por dispositivo e os pacotes de aplicação estão na página do reference design. Visão geral:
- Implante os beacons BLE — posicione, fixe e registre os endereços MAC.
- Configure o gateway LoRaWAN — coloque-o online contra o SenseCAP OpenStream ou seu ChirpStack.
- Implante a aplicação de posicionamento — um deployment em Docker, direcionado para a máquina em que você está ou para um host remoto via SSH.
- Configure e ative o rastreador — faça-o ingressar na rede e defina o intervalo de uplink.
- Georreferencie a planta baixa — envie a planta, depois defina origem, rotação e escala para que ela caia no lugar certo no mapa externo. Georreferenciamento e geofences ficam ambos na página de configuração:

- Configure um alarme de geofence — desenhe a cerca em WGS84 e associe uma regra de alarme.
- Abra o dashboard — verifique se um rastreador aparece, se move e dispara os alarmes que você configurou.
Dificuldade intermediária, cerca de 60 minutos. As etapas 5 e 6 são apenas de configuração de software e não exigem hardware extra.
A imagem está disponível para linux/arm64 e linux/amd64. O login padrão do dashboard é admin / 12345678; altere-o em Configuration → Authentication após o primeiro login.
Interfaces disponíveis
Tudo o que a aplicação expõe é servido na porta 5173 do host em que você a implantou. Três formas de acesso, dependendo de quem está integrando.
- Um display de parede ou uma segunda tela — abra
/web/map?layer=outdoor(ou?layer=indoor). É a mesma página e o mesmo WebSocket, então nada extra precisa ser configurado. - Um sistema existente de segurança, despacho ou presença — assine o WebSocket e aja sobre dois tipos de mensagem:
tracker_sospara o botão de emergência, etracker_checkin/tracker_position_detectionquando carregarem um blocogeofencecomtransition: enterouexit. Esses são os eventos; o restante é telemetria. - Seu próprio serviço — consuma o payload completo. Cada atualização carrega ou uma posição métrica em uma planta baixa ou uma posição WGS84, marcada por
coordSystem, e os endpoints REST permitem criar cercas e ler ou escrever os parâmetros de georreferenciamento programaticamente.
Interface completa e payload
| Interface | Endpoint | Payload |
|---|---|---|
| WebSocket | ws://<host>:5173/ws | tracker_update com position = {x, y, coordSystem: "metric"} ou {lat, lon, accuracy, coordSystem: "wgs84"}; tracker_checkin / tracker_position_detection carregam um bloco geofence extra em enter/exit; também tracker_sos e tracker_offline |
| REST | GET/PUT /api/configuration/dashboard/maps/{mapName}/registration | {origin_lat, origin_lon, rotation_deg, scale}. Rejeita |lat| > 85° e scale ≤ 0. Sessão de administrador necessária; uma sessão de convidado recebe 403 |
| REST | POST /api/geofences, POST /api/events | Geometria da cerca (polígono GeoJSON, ou um ponto mais radius_m) e a regra de alarme que a referencia |
| LoRaWAN uplink in | SenseCAP OpenStream, ou um tópico MQTT do ChirpStack | O mapeamento de campos está no guia de deployment |
Um alarme de geofence viaja na mesma mensagem que um check-in, em vez de em um canal próprio:
{"type": "tracker_checkin", "data": {"2CF7F1C0530004AD": {
"timestamp": 1788582647214, "map": "Plant A",
"geofence": {"id": 1, "name": "Plant A", "transition": "enter"},
"position": {"lat": 22.5362, "lon": 113.9432, "accuracy": null, "coordSystem": "wgs84"},
"last_detected_beacons": []}}}
Dois campos para tratar com cuidado: faça o branch em coordSystem, não na presença de lat, porque o mesmo tipo de mensagem pode carregar qualquer uma das formas de coordenada. accuracy é sempre null neste hardware (nem o uplink do SenseCAP nem o do ChirpStack carregam uma medição de acurácia GNSS); trate-o como desconhecido.
Desempenho e dados medidos
Tudo abaixo foi medido no lado do servidor: uplinks sintéticos foram publicados em um broker MQTT local e os resultados capturados a partir do WebSocket do dashboard, sem rastreador T1000 e sem gateway no circuito. A aplicação rodou em uma unidade reComputer J30 series (como um host arm64 simples, GPU não utilizada), 2–4 minutos por nível.
Capacidade e latência
| Métrica | Medido | Condições |
|---|---|---|
| Capacidade, estável | 200 tags simultâneas, P95 fim a fim 828 ms, 0% de perda de uplink | 1 uplink por tag a cada 30 s, 800 uplinks, 2 min |
| Capacidade, degradando | 500 tags, P95 2,35 s, 0% de perda | Mesmo, 2000 uplinks, 2 min; apenas o orçamento de latência de 2 s é excedido |
| Capacidade, em 1000 tags | P95 4,1 s, 0% de perda, processo ainda atendendo | Mesmo; ainda atendendo normalmente, a carga não foi forçada além disso |
| Taxa de atualização | 50 tags com intervalo de uplink de 2 s, P95 220 ms, 0% de perda em 4500 uplinks | 3 min; intervalos de 30 / 10 / 5 s também estáveis em P95 89 / 163 / 146 ms |
| Latência do alarme SOS | P50 24 ms, P95 29 ms, máx. 29 ms, n=20 | Tag única, sem carga concorrente; timestamp do uplink até o broadcast no WebSocket |
| Detecção de offline | 903 s e 950 s | 2 repetições; janela esperada [900 s, 960 s] a partir do limiar de 15 min e poll de 60 s |
Capacidade e taxa de atualização cobrem apenas o servidor; a rapidez com que um rastreador pode reportar depende do intervalo de uplink e do duty cycle do LoRaWAN.
Reproduza: runs/2026-09-05-orin-nano/boundary.capacity.yaml, boundary.update_frequency.yaml, boundary.sos_latency.yaml, boundary.offline_latency.yaml em indoor_positioning_ble_lorawan upstream (código da aplicação feature/outdoor @ 443bce6)
Geofence e georreferenciamento
| Métrica | Medido | Condições |
|---|---|---|
| Latência do alarme de geofence | P50 14 ms, máx. 14 ms, 2 alarmes | Ferramenta de replay e servidor no mesmo host via loopback, tag única, 17 uplinks |
| Histerese de geofence | 6 alternâncias de entra-e-sai na linha da cerca produziram 0 alarmes; enter e exit dispararam cada um no terceiro ponto consecutivo | Mesmo |
| Erro de georreferenciamento | ≤ 0,21 m em qualquer lugar dentro de 2 km da origem, |lat| ≤ 60° | Pior caso de uma varredura de azimute, a cada 15°, raios 500 / 1000 / 2000 m, lat0 ∈ 60; orçamento era 0,7 m; apenas matemática de projeção, sem levantamento de campo |
Reproduza: runs/2026-09-05-geofence-smoke/results.md, runs/2026-09-05-georef/results.md
Tempo de execução e parâmetros principais
O rastreador só reporta o que observou (os beacons configurados que viu, ou um fix GNSS); o servidor resolve isso em uma posição. Estes três parâmetros do lado do servidor definem o ritmo da alternância indoor/outdoor e dos alarmes:
- Alternância indoor ↔ outdoor: ir para outdoor exige 3 fixes GNSS em 20 s e nenhum beacon configurado visto por 15 s; voltar para indoor exige duas varreduras consecutivas, cada uma vendo 2 ou mais beacons configurados. Um rastreador ao lado de uma janela não fica alternando.
- Transição de geofence:
enter/exitdisparam apenas após 3 pontos consecutivos em 10 s. No modo geo o campotime_rangede uma regra de alarme não tem efeito; essa confirmação substitui um intervalo de tempo definido na UI. - Detecção de offline: nenhum uplink por 15 min, poll de 60 s, hard-coded.
- Basemap offline: um local sem internet constrói um arquivo PMTiles local com
go-pmtiles extract(ele baixa apenas os tiles dentro do bounding box); gere o arquivo e carregue-o uma vez antes da entrega.
Degradação conhecida
- A precisão indoor segue o layout dos beacons. A faixa de 2–3 m é nominal (wiki do BC03) e assume 3 ou mais beacons por zona a 2,5–3 m de altura e espaçamento de 5–10 m. Um beacon por zona dá nível de sala. Prateleiras metálicas degradam a trilateração; adicione beacons nesses locais.
- A latência cresce com a quantidade de tags: o P95 fim a fim é 2,35 s em 500 tags e 4,1 s em 1000.
- O erro de georreferenciamento cresce com o raio e a latitude: o alcance útil é de cerca de 2 km, e a API recusa
\|lat\|acima de 85°. accuracyealtnão carregam dados: lógica que faz branch em accuracy sempre segue o caminho nulo neste hardware, e o mecanismo de geofence trata umaaccuracyausente como aprovada.
Proveniência de dados e assets
- Dados medidos — todos os valores em Desempenho e dados medidos vêm de
description.mddeindoor_positioning_ble_lorawanno repositório upstreamsensecraft-solutions, que cita arquivos de relatório por execução pelo caminho. Os dados são traços de replay sintéticos gerados para as execuções; nenhum dado de site de cliente está envolvido. - Device EUIs mostrados nas capturas de tela e traços são os sintéticos usados pela ferramenta de replay.
- Tiles de basemap em qualquer captura de tela outdoor são © contribuidores do OpenStreetMap, licenciados sob a ODbL. Essa atribuição acompanha a página.
- Plantas baixas nas capturas de tela de georreferenciamento são imagens de teste sintéticas (uma planta de 1000×800 px em um mapa de demonstração de 50 m × 40 m), criadas para a execução de avaliação e excluídas depois.
- Código-fonte da aplicação está em Seeed-Solution/Solution_IndoorPositioning_H5; verifique os termos de licença no repositório antes de enviar um produto derivado.
- Capturas de dashboard e GIFs de demonstração — obtidos da própria UI da aplicação (
docs/ui/eassets/emsolution-indoor-positioning). O basemap da camada outdoor são tiles do OpenStreetMap, atribuídos sob ODbL; a proveniência está emgallery/ATTRIBUTION.mddo pacote upstream.
