BB.Motion.Tracker behaviour (bb v0.15.4)

Copy Markdown View Source

Behaviour for continuous position tracking with IK.

Trackers maintain an ongoing IK solution loop, continuously solving for updated targets and sending actuator commands. This is useful for:

  • Following a moving target (visual tracking)
  • Smooth trajectory interpolation
  • Real-time position control from external sources

Implementing a Tracker

Trackers are typically GenServers that:

  1. Run a periodic solve loop at a configurable rate
  2. Accept target updates via update_target/2
  3. Send actuator commands on each successful solve
  4. Report status including tracking error and solve statistics

Callbacks

  • start_tracking/5 - Begin tracking a target link
  • update_target/2 - Update the current target position
  • status/1 - Get current tracking status
  • stop_tracking/2 - Stop tracking and optionally return final positions

Example Implementation

See BB.IK.FABRIK.Tracker for a reference implementation.

Usage Pattern

# Start tracking
{:ok, tracker} = BB.IK.FABRIK.Tracker.start_link(
  robot: MyRobot,
  target_link: :gripper,
  initial_target: {0.3, 0.2, 0.1},
  update_rate: 30
)

# Update target from vision callback
BB.IK.FABRIK.Tracker.update_target(tracker, new_target)

# Check status
%{residual: 0.001, tracking: true} = BB.IK.FABRIK.Tracker.status(tracker)

# Stop and get final positions
{:ok, positions} = BB.IK.FABRIK.Tracker.stop(tracker)

Summary

Callbacks

Get current tracking status.

Update the current target position.

Types

positions()

@type positions() :: BB.IK.Solver.positions()

status()

@type status() :: %{
  tracking: boolean(),
  target: target() | nil,
  residual: float() | nil,
  iterations: non_neg_integer(),
  update_rate: pos_integer(),
  last_update: DateTime.t() | nil
}

target()

@type target() :: BB.IK.Solver.target()

tracker_state()

@type tracker_state() :: term()

Callbacks

start_tracking(robot, robot_state, target_link, initial_target, opts)

@callback start_tracking(
  robot :: module() | BB.Robot.t(),
  robot_state :: BB.Robot.State.t(),
  target_link :: atom(),
  initial_target :: target(),
  opts :: keyword()
) :: {:ok, tracker_state()} | {:error, term()}

Start tracking a target link.

Options

Required:

  • :robot - Robot module or struct
  • :target_link - Name of the link to track
  • :initial_target - Starting target position

Optional:

  • :update_rate - Solve frequency in Hz (default: 20)
  • :delivery - Actuator command delivery mode (default: :direct)
  • :max_iterations - Maximum solver iterations per update
  • :tolerance - Convergence tolerance

Returns

  • {:ok, state} - Tracking started
  • {:error, reason} - Failed to start

status(state)

@callback status(state :: tracker_state()) :: status()

Get current tracking status.

Returns

Status map containing:

  • tracking - Whether actively tracking
  • target - Current target position
  • residual - Distance from end-effector to target
  • iterations - Solver iterations on last update
  • update_rate - Current update frequency
  • last_update - Timestamp of last successful solve

stop_tracking(state, opts)

@callback stop_tracking(state :: tracker_state(), opts :: keyword()) ::
  {:ok, positions()} | {:error, term()}

Stop tracking.

Options

  • :hold - Whether to send hold commands to actuators (default: false)

Returns

  • {:ok, positions} - Final joint positions
  • {:error, reason} - Stop failed

update_target(state, target)

@callback update_target(state :: tracker_state(), target :: target()) ::
  {:ok, tracker_state()} | {:error, term()}

Update the current target position.

The tracker will solve for the new target on its next update cycle.

Returns

  • {:ok, state} - Target updated
  • {:error, reason} - Update failed (e.g., tracker stopped)