Beam Bots Logo

BB.IK.FABRIK

CILicense: Apache 2.0Hex version badgeREUSE status

A FABRIK-based inverse kinematics solver for the Beam Bots robotics framework.

FABRIK (Forward And Backward Reaching Inverse Kinematics) is an iterative algorithm that computes joint angles needed to position an end-effector at a target location. It works by alternately reaching from the end-effector toward the target, then from the base back to maintain segment lengths.

Features

Installation

Add bb_ik_fabrik to your list of dependencies in mix.exs:

def deps do
  [
    {:bb_ik_fabrik, "~> 0.3.1"}
  ]
end

Usage

# Define your robot using the BB DSL
robot = MyRobot.robot()

# Create initial state
{:ok, state} = BB.Robot.State.new(robot)

# Define a target position for the end-effector
target = {0.3, 0.2, 0.1}

# Solve inverse kinematics
case BB.IK.FABRIK.solve(robot, state, :end_effector, target) do
  {:ok, positions, meta} ->
    # Apply the solved positions to the robot state
    BB.Robot.State.set_positions(state, positions)
    IO.puts("Solved in #{meta.iterations} iterations")
    IO.puts("Final distance to target: #{meta.residual}m")

  {:error, %BB.Error.Kinematics.Unreachable{residual: residual, positions: positions}} ->
    # Target is beyond the robot's reach
    IO.puts("Target unreachable, best distance: #{residual}m")
    # positions contains best-effort joint values

  {:error, %BB.Error.Kinematics.NoSolution{}} ->
    IO.puts("Failed to converge within max iterations")
end

Solving with Options

BB.IK.FABRIK.solve(robot, state, :end_effector, target,
  max_iterations: 100,         # Maximum FABRIK iterations (default: 50)
  tolerance: 0.001,            # Position tolerance in metres (default: 1.0e-4)
  orientation_tolerance: 0.1,  # Orientation tolerance in radians (default: 0.01)
  respect_limits: true         # Clamp to joint limits (default: true)
)

Using solve_and_update/5

For convenience, solve_and_update/5 solves IK and updates the state in one call:

case BB.IK.FABRIK.solve_and_update(robot, state, :end_effector, target) do
  {:ok, positions, meta} ->
    # State has already been updated
    :ok

  {:error, %BB.Error.Kinematics.Unreachable{} = error} ->
    # State is unchanged on error
    {:error, error}
end

Target Formats

Targets can be specified as:

# Position only (Vec3)
target = BB.Math.Vec3.new(0.3, 0.2, 0.1)

# Position with axis constraint ("point tool in this direction")
target = {BB.Math.Vec3.new(0.3, 0.2, 0.1), {:axis, BB.Math.Vec3.new(0.0, 0.0, -1.0)}}

# Position with full orientation (quaternion)
quat = BB.Math.Quaternion.from_axis_angle(BB.Math.Vec3.unit_z(), :math.pi() / 4)
target = {BB.Math.Vec3.new(0.3, 0.2, 0.1), {:quaternion, quat}}

# 4x4 homogeneous transform (extracts both position and orientation)
target = BB.Math.Transform.from_position_quaternion(
  BB.Math.Vec3.new(0.3, 0.2, 0.1),
  BB.Math.Quaternion.identity()
)

When using orientation constraints, the result metadata includes orientation_residual (in radians) alongside the position residual.

Supported Arm Configurations

FABRIK works best with simple planar or spatial arms where:

Works Well

Limited Support

Limitations

When to Use a Different Solver

Consider analytical IK or Jacobian-based methods when:

Documentation

Full documentation is available at HexDocs.