Source code for olo.navigation

"""Navigation wrapper over olo.navigation.v1.Navigation."""

from collections.abc import Callable, Iterator
from typing import Optional

import grpc
from olo_protos.navigation.v1 import navigation_pb2

from olo._convert import duration_to_seconds, seconds_to_duration
from olo.errors import OloFailedPrecondition, wrap_rpc_error
from olo.navigation.grid import OccupancyGrid, occupancy_grid_from_proto
from olo.navigation.types import (
    Activity,
    Availability,
    Nav2ErrorCode,
    NavigationFeedback,
    NavigationOutcome,
    NavigationResult,
    NavigationState,
    ReachabilityResult,
)
from olo.spatial import Pose, Transform
from olo.spatial._convert import pose_from_proto, pose_to_proto
from olo.utils.common import normalize_robot_namespace

_DEFAULT_TIMEOUT_SEC = 10.0
_DEFAULT_NAV_TIMEOUT_SEC = 120.0

_AVAILABILITY = {
    navigation_pb2.AVAILABILITY_UNSPECIFIED: Availability.UNSPECIFIED,
    navigation_pb2.AVAILABILITY_UNAVAILABLE: Availability.UNAVAILABLE,
    navigation_pb2.AVAILABILITY_READY: Availability.READY,
}
_ACTIVITY = {
    navigation_pb2.ACTIVITY_UNSPECIFIED: Activity.UNSPECIFIED,
    navigation_pb2.ACTIVITY_IDLE: Activity.IDLE,
    navigation_pb2.ACTIVITY_NAVIGATING: Activity.NAVIGATING,
}
_OUTCOME = {
    navigation_pb2.NAVIGATION_OUTCOME_UNSPECIFIED: NavigationOutcome.UNSPECIFIED,
    navigation_pb2.NAVIGATION_OUTCOME_SUCCEEDED: NavigationOutcome.SUCCEEDED,
    navigation_pb2.NAVIGATION_OUTCOME_CANCELLED: NavigationOutcome.CANCELLED,
    navigation_pb2.NAVIGATION_OUTCOME_ABORTED: NavigationOutcome.ABORTED,
    navigation_pb2.NAVIGATION_OUTCOME_TIMED_OUT: NavigationOutcome.TIMED_OUT,
}


def _state_from_proto(state: navigation_pb2.NavigationState) -> NavigationState:
        return NavigationState(
            availability=_AVAILABILITY.get(state.availability, Availability.UNSPECIFIED),
            activity=_ACTIVITY.get(state.activity, Activity.UNSPECIFIED),
            owned_goal_ids=tuple(state.owned_goal_ids),
            reason=state.reason,
        )


def _reachability_from_proto(
    result: navigation_pb2.ReachabilityResult,
) -> ReachabilityResult:
    return ReachabilityResult(
        reachable=bool(result.reachable),
        planner_error_code=int(result.planner_error_code),
        reason=result.reason,
        path_length=float(result.path_length),
    )


def _feedback_from_proto(feedback: navigation_pb2.NavigationFeedback) -> NavigationFeedback:
    return NavigationFeedback(
        distance_remaining=float(feedback.distance_remaining),
        navigation_time=duration_to_seconds(feedback.navigation_time),
        number_of_recoveries=int(feedback.number_of_recoveries),
        current_pose=pose_from_proto(feedback.current_pose),
    )


def _result_from_proto(result: navigation_pb2.NavigationResult) -> NavigationResult:
    return NavigationResult(
        outcome=_OUTCOME.get(result.outcome, NavigationOutcome.UNSPECIFIED),
        reason=result.reason,
        nav2_error_code=int(result.nav2_error_code),
    )














__all__ = [
    "Activity",
    "Availability",
    "Navigation",
    "Nav2ErrorCode",
    "NavigationGoal",
    "NavigationHandle",
    "NavigationOutcome",
    "NavigationResult",
    "NavigationState",
    "OccupancyGrid",
    "ReachabilityResult",
]