Inspect the map and navigate to a reachable goalΒΆ

Queries client.platform.navigation.deployment to confirm navigation is running.Then fetches the occupancy grid and asks the navigation engine whether the goal is planner-reachable before sending a NavigateToPose goal.

from olo import Client
from olo.platform import NavigationObservedState

TARGET_X = 1.0
TARGET_Y = 0.5

with Client() as client:
    # Require an already-running Nav2 deployment (start it via navigation-simple
    # or the UI). Namespace resolves like client.robot().
    info = client.platform.navigation.deployment()
    state = info.observed.state if info.observed else None
    if state != NavigationObservedState.READY:
        raise RuntimeError(
            f"Navigation engine is not ready (state={state}); "
            "start it first, then re-run this example"
        )
    print(f"Navigation engine: {state}")

    robot = client.robot()
    nav = robot.navigation

    # Fetch the current occupancy grid
    grid = nav.get_map()
    print(f"map={grid.width}x{grid.height} resolution={grid.resolution:.2f} m")

    # Reject cells outside the map, unexplored, or occupied
    cell = grid.world_to_cell(TARGET_X, TARGET_Y)
    if not grid.in_bounds(*cell):
        raise RuntimeError(f"Target ({TARGET_X}, {TARGET_Y}) is outside the map")
    if grid.is_unknown(*cell):
        raise RuntimeError(f"Target cell {cell} is unexplored")
    if grid.is_occupied(*cell):
        raise RuntimeError(f"Target cell {cell} is occupied")

    # Ask Nav2 whether the goal is planner-reachable
    goal = grid.pose_at(*cell, yaw=0.0)
    check = nav.check_reachability(goal)
    print(
        f"reachable={check.reachable} path_length={check.path_length:.2f} m "
        f"reason={check.reason or 'ok'}"
    )
    if not check.reachable:
        raise RuntimeError("Nav2 planner reports the goal is not reachable")

    # Send a NavigateToPose goal
    result = nav.navigate_to(goal)
    print(f"Outcome: {result.outcome.value} ({result.reason})")
import { connect } from "olo/web";

const TARGET_X = 1.0;
const TARGET_Y = 0.5;

const client = connect();

// Require an already-running Nav2 deployment (start it via navigation-simple
// or the UI). Namespace resolves like client.robot().
const info = await client.platform.navigation.deployment();
const state = info.observed?.state;
if (state !== "ready") {
  throw new Error(
    `Navigation engine is not ready (state=${state}); ` +
      "start it first, then re-run this example",
  );
}
console.log(`Navigation engine: ${state}`);

const robot = await client.robot();
const nav = robot.navigation;

// Fetch the current occupancy grid
const grid = await nav.getMap();
console.log(`map=${grid.width}x${grid.height} resolution=${grid.resolution.toFixed(2)} m`);

// Reject cells outside the map, unexplored, or occupied
const [cellX, cellY] = grid.worldToCell(TARGET_X, TARGET_Y);
if (!grid.inBounds(cellX, cellY)) {
  throw new Error(`Target (${TARGET_X}, ${TARGET_Y}) is outside the map`);
}
if (grid.isUnknown(cellX, cellY)) {
  throw new Error(`Target cell (${cellX}, ${cellY}) is unexplored`);
}
if (grid.isOccupied(cellX, cellY)) {
  throw new Error(`Target cell (${cellX}, ${cellY}) is occupied`);
}

// Ask Nav2 whether the goal is planner-reachable
const goal = grid.poseAt(cellX, cellY);
const check = await nav.checkReachability(goal);
console.log(
  `reachable=${check.reachable} path_length=${check.pathLength.toFixed(2)} m ` +
    `reason=${check.reason || "ok"}`,
);
if (!check.reachable) {
  throw new Error("Nav2 planner reports the goal is not reachable");
}

// Send a NavigateToPose goal
const result = await nav.navigateTo(goal);
console.log(`Outcome: ${result.outcome} (${result.reason})`);