GLiNav

GLiNav local robot navigation

Seven Habitat runs where GLiNav reached the goal. The camera views are rebuilt from the recorded simulator poses, not real camera or robot footage.

Navigation decisions, fully local

GLiNav is a tiny local navigation model. You give it the world state and it answers six questions: drive, strafe, turn, stop, task state and target. A small controller on top blocks early finishes and gets it moving again when it stalls. No hosted model in the loop.

It is a 113 MiB finetune on top of GLiFormer Base v1, which is 1,008 MiB, so you need both.

It is not tied to one robot. For a Unitree Go2 or any other robot, you bring the world state and keep your own perception, motion and safety layers. I tested it on Linux with an NVIDIA CUDA GPU.

GLiNav and Jev

I ran GLiNav and the hosted Jev model from TypeSafe on the same 73 Habitat tasks, keeping only tasks where both runs were clean.

Measure GLiNav Jev
Goals reached 38/73 (52.1%) 29/73 (39.7%)
Premature finishes 0 5
Decision path Local Hosted
Observed response ~232 ms ~328 ms

The runs were separate, not a live race. Response times come from different paths, one local and one hosted, so they are rough operating numbers, not a speed test.

Without the controller

The same GLiNav weights with no finish guard and no recovery:

Setup Goals reached Premature finishes
Model only 24/73 (32.9%) 4
Full GLiNav 38/73 (52.1%) 0

Separate runs on the same 73 tasks. This is why the controller ships with the model, but it is not a causal study.

Over all 79 audited first attempts, the full setup reached 41 goals with no premature finishes. One more task failed its infrastructure audit and was left out, not retried.

Run it

You need Python 3.14, Git and an NVIDIA GPU with CUDA. The tested setup used a 4 GiB RTX 3050. CPU inference is not supported. Plan for about 7 GiB of free disk space for the base model, CUDA/PyTorch environment, GLiNav delta and upstream sources.

mkdir -p glinav
python3.14 -m venv glinav/.venv
glinav/.venv/bin/python -m pip install --only-binary=:all: huggingface_hub==1.32.0

glinav/.venv/bin/hf download espejelomar/glinav-v1 \
  --revision e79549f2086a6af7f218a63cdebf36ebf5e7f979 \
  --local-dir glinav
glinav/.venv/bin/hf download knowledgator/gliformer-base-v1 \
  --revision 590f9d3f577ea2f6d685aaec84b2d66b6db86b15 \
  --local-dir glinav/base
mkdir -p glinav/upstream
git clone https://github.com/Knowledgator/GLiFormer.git glinav/upstream/GLiFormer
git -C glinav/upstream/GLiFormer checkout b5c0a0fd2aacff64736fbfa0bac0bdcc032d5eff
git clone https://github.com/urchade/GLiNER.git glinav/upstream/GLiNER
git -C glinav/upstream/GLiNER checkout cf9e5f7d9fb99158b592132a9ec7cbfabb43a9a0
cd glinav
.venv/bin/python -m pip install --only-binary=:all: -r requirements.lock.txt
.venv/bin/python glinav_controller.py --base-dir base \
  --upstream-src upstream/GLiFormer --gliner-src upstream/GLiNER \
  --request example-request.json

This runs one tick from example-request.json through the model, the one-metre finish guard and the recovery controller. It prints JSON with the raw model answers, the answers after the controller, the actions, the finish check and any controller events.

For the included request, a successful run prints one glinav-v1 tick. Its effective action turns right, continues toward table and does not stop. The finish guard rejects completion because the target is still 2.59 m away. The first load may also print non-fatal Torch and FlashDeberta warnings to stderr; the final stdout line is the JSON result.

The controller has to see ticks in a row to notice a stall. Send them together as a {"ticks": [...]} request, or keep one GLiNavController object alive in your own loop.

Use it in your own loop

example-request.json is the input contract. Keep its six question groups (drive.x, drive.y, drive.yaw, stop, task and target) and replace the world state on each tick. Create the model and controller once so the model stays loaded and the controller keeps its stall history.

import json
from pathlib import Path

import torch

from glinav_controller import GLiNavController
from glinav_model import GLiNavModel

torch.set_num_threads(2)
torch.set_num_interop_threads(2)

model = GLiNavModel(
    base_dir=Path("base"),
    checkpoint=Path("glinav-delta.safetensors"),
    upstream_src=Path("upstream/GLiFormer"),
    gliner_src=Path("upstream/GLiNER"),
)
controller = GLiNavController()


def decide(request):
    state = request["state"]
    model_answers = model.predict(state, request["questions"])
    return controller.apply(state, model_answers)


request = json.loads(Path("example-request.json").read_text())
print(json.dumps(decide(request), allow_nan=False))

What the numbers mean

The tasks ran in Habitat on HSSD scenes. The simulator gave GLiNav the object positions, and I had looked at these scenes before. So these are navigation-decision results, not camera navigation, not a physical robot, not a standard Habitat leaderboard score and not the 327-task Can Jev Nav? benchmark.

Training used 6,000 synthetic room states built with DimOS world-state and geometry tools. No Habitat scenes, images or robot recordings.

GLiNav does not see, detect objects, build maps or keep anything safe. Do not connect it directly to a robot.

The GLiNav weights, loader and controller are Apache-2.0. Knowledgator provides the base and GLiFormer; the loader uses GLiNER. No endorsement is implied.

SHA-256 of glinav-delta.safetensors: 8ba9d2b7738be545185d01316792be9603941fe239dfae64ac48ea47928971ba.

Downloads last month
-
Video Preview
loading

Model tree for espejelomar/glinav-v1

Finetuned
(1)
this model