Locomotion

Obstacle-unaware local motion via odometry feedback and direct velocity leases.

Warning

Locomotion does not plan around obstacles. Use Navigation for map-level motion and ensure the swept path is clear before commanding it.

import math
import time

from olo import Client
from olo.locomotion import LocomotionFeedback, PlanarMotion

last_feedback_time = 0.0


def on_feedback(feedback: LocomotionFeedback, rate_limit: float = 3) -> None:
    global last_feedback_time
    now = time.monotonic()
    if now - last_feedback_time < 1 / rate_limit:
        return
    last_feedback_time = now
    print(f"Remaining: {feedback.remaining}")


with Client() as client:
    # Drive forward
    client.robot().locomotion.move(
        PlanarMotion(x=0.5),
        on_feedback=on_feedback,
    )
    time.sleep(1)

    # Turn_left
    client.robot().locomotion.move(
        PlanarMotion(yaw=math.pi / 2),
        on_feedback=on_feedback,
    )
    time.sleep(1)

    # Combined motion at a slower speed. Note that combined motions are much less
    # accurate, and separate motions are recommended.
    client.robot().locomotion.move(
        PlanarMotion(x=-1.0, yaw=-math.pi / 2),
        max_linear_speed=0.2,
        max_angular_speed=0.3,
        on_feedback=on_feedback,
    )
    time.sleep(1)
import { connect } from "olo/web";
import type { LocomotionFeedback } from "olo/locomotion";

const delay = (milliseconds: number) =>
  new Promise<void>((resolve) => setTimeout(resolve, milliseconds));

let lastFeedbackTime = 0;

function onFeedback(feedback: LocomotionFeedback, rateLimit = 3): void {
  const now = performance.now() / 1000;
  if (now - lastFeedbackTime < 1 / rateLimit) {
    return;
  }
  lastFeedbackTime = now;
  const remaining = feedback.remaining;
  console.log(
    `Remaining: PlanarMotion(x=${remaining.x.toFixed(3)}, y=${remaining.y.toFixed(3)}, yaw=${remaining.yaw.toFixed(3)})`,
  );
}

const robot = await connect().robot();

// Drive forward
await robot.locomotion.move({ x: 0.5, y: 0, yaw: 0 }, { onFeedback });
await delay(1_000);

// Turn_left
await robot.locomotion.move({ x: 0, y: 0, yaw: Math.PI / 2 }, { onFeedback });
await delay(1_000);

// Combined motion at a slower speed. Note that combined motions are much less
// accurate, and separate motions are recommended.
await robot.locomotion.move(
  { x: -1.0, y: 0, yaw: -Math.PI / 2 },
  {
    maxLinearSpeed: 0.2,
    maxAngularSpeed: 0.3,
    onFeedback,
  },
);
await delay(1_000);

Appliance-owned local locomotion.

Client interfaces

class olo.locomotion.Locomotion[source]

Bases: object

Sync wrapper for local locomotion.

__init__(session)[source]
Return type:

None

handle(namespace=None)[source]

Return a namespace-scoped locomotion-motion handle.

Return type:

LocomotionHandle

Parameters:

namespace (str | None)

move(motion, *, robot_namespace='', max_linear_speed=None, max_angular_speed=None, motion_timeout=30.0, cmd_vel_topic='', odom_topic='', on_feedback=None, timeout=10.0)[source]

Move to a planar pose relative to the starting base frame.

Return type:

LocomotionResult

Parameters:
send_velocity(x=0.0, yaw=0.0, *, y=0.0, lease=0.5, robot_namespace='', cmd_vel_topic='', timeout=10.0)[source]

Set planar velocity and refresh its appliance-owned lease.

Return type:

AppliedVelocity

Parameters:
stop(robot_namespace='', *, cmd_vel_topic='', timeout=10.0)[source]

Cancel owned locomotion and publish zero velocity.

Return type:

tuple[str, ...]

Parameters:
  • robot_namespace (str)

  • cmd_vel_topic (str)

  • timeout (float)

class olo.locomotion.LocomotionHandle[source]

Bases: object

Namespace-scoped local locomotion.

__init__(client, namespace)[source]
Parameters:
Return type:

None

move(motion, *, max_linear_speed=None, max_angular_speed=None, motion_timeout=30.0, cmd_vel_topic='', odom_topic='', on_feedback=None, timeout=10.0)[source]

Move to a planar pose relative to the starting base frame.

Return type:

LocomotionResult

Parameters:
send_velocity(x=0.0, yaw=0.0, *, y=0.0, lease=0.5, cmd_vel_topic='', timeout=10.0)[source]

Set planar velocity and refresh its appliance-owned lease.

Return type:

AppliedVelocity

Parameters:
stop(*, cmd_vel_topic='', timeout=10.0)[source]

Cancel owned locomotion and publish zero velocity.

Return type:

tuple[str, ...]

Parameters:

Types

class olo.locomotion.LocomotionFeedback[source]

Bases: object

Progress for an active local locomotion-motion command.

__init__(measured, remaining, elapsed)
Parameters:
Return type:

None

class olo.locomotion.LocomotionResult[source]

Bases: object

Terminal result for a local locomotion-motion command.

__init__(outcome, reason, requested, measured, residual, elapsed)
Parameters:
Return type:

None

class olo.locomotion.PlanarMotion[source]

Bases: object

Planar x/y/yaw values for displacement or velocity.

__init__(x=0.0, y=0.0, yaw=0.0)
Parameters:
Return type:

None

class olo.locomotion.AppliedVelocity[source]

Bases: object

Velocity accepted by the appliance and its resolved command topic.

__init__(applied, cmd_vel_topic)
Parameters:
Return type:

None

Enums

class olo.locomotion.LocomotionOutcome[source]

Bases: Enum

Terminal outcome for a local locomotion-motion command.

Import from olo/locomotion:

Client interfaces

  • Locomotionmove(), sendVelocity(), and stop().

  • LocomotionHandle — namespace-scoped handle from client.locomotion.handle().

Types

Enums