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:
- Run a periodic solve loop at a configurable rate
- Accept target updates via
update_target/2 - Send actuator commands on each successful solve
- Report status including tracking error and solve statistics
Callbacks
start_tracking/5- Begin tracking a target linkupdate_target/2- Update the current target positionstatus/1- Get current tracking statusstop_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
Start tracking a target link.
Get current tracking status.
Stop tracking.
Update the current target position.
Types
@type positions() :: BB.IK.Solver.positions()
@type status() :: %{ tracking: boolean(), target: target() | nil, residual: float() | nil, iterations: non_neg_integer(), update_rate: pos_integer(), last_update: DateTime.t() | nil }
@type target() :: BB.IK.Solver.target()
@type tracker_state() :: term()
Callbacks
@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
@callback status(state :: tracker_state()) :: status()
Get current tracking status.
Returns
Status map containing:
tracking- Whether actively trackingtarget- Current target positionresidual- Distance from end-effector to targetiterations- Solver iterations on last updateupdate_rate- Current update frequencylast_update- Timestamp of last successful solve
@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
@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)