### Continuous Tracking with IK Solver Source: https://github.com/beam-bots/bb_ik_dls/blob/main/README.md Implement real-time target following using the BB.IK.DLS.Tracker GenServer. Start tracking, update the target dynamically, and stop the tracker to get final joint positions. ```elixir # Start tracking a moving target {:ok, tracker} = BB.IK.DLS.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.DLS.Tracker.update_target(tracker, {0.35, 0.25, 0.15}) # Stop tracking {:ok, final_positions} = BB.IK.DLS.Tracker.stop(tracker) ``` -------------------------------- ### Start Tracker with Named Registration Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Starts the Tracker GenServer with a specific name registered in a Registry. This is useful for integrating the tracker into a supervision tree. ```elixir Tracker.start_link( robot: MyRobot, target_link: :gripper, initial_target: {0.0, 0.0, 0.3}, name: {:via, Registry, {MyApp.Registry, :gripper_tracker}} ) ``` -------------------------------- ### Build and Test Commands Source: https://github.com/beam-bots/bb_ik_dls/blob/main/AGENTS.md Common mix commands for checking, testing, formatting, and linting the project. Always prefer `mix check --no-retry` for comprehensive checks. ```bash mix check --no-retry # Run all checks (compile, test, format, credo, dialyzer, reuse) ``` ```bash mix test # Run tests ``` ```bash mix test path/to/test.exs:42 # Run single test at line ``` ```bash mix format # Format code ``` ```bash mix credo --strict # Linting ``` -------------------------------- ### Solve and Send Actuator Commands with BB.IK.DLS.Motion.move_to/4 Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Wraps BB.Motion.move_to/4 to solve IK and dispatch actuator commands. Accepts a robot module or BB.Command.Context. Returns {:ok, meta} on success or {:error, reason, meta} on failure. ```elixir alias BB.IK.DLS.Motion # Basic move case Motion.move_to(MyRobot, :gripper, {0.3, 0.2, 0.1}) do {:ok, %{iterations: n, residual: r, reached: true}} -> IO.puts("Moved in #{n} iterations") {:error, :no_solution, meta} -> IO.puts("Unreachable, best residual: #{meta.residual} m") end ``` ```elixir # With full target format and options target = {Vec3.new(0.3, 0.2, 0.1), {:quaternion, Quaternion.identity()}} Motion.move_to(MyRobot, :gripper, target, delivery: :sync, # :pubsub (default) | :direct | :sync max_iterations: 200, tolerance: 0.001, lambda: 0.3, exclude_joints: [:left_finger, :right_finger] ) ``` ```elixir # Inside a BB.Command defmodule GraspCommand do use BB.Command @impl BB.Command def handle_command(%{target: target}, context, state) do case Motion.move_to(context, :gripper, target) do {:ok, meta} -> {:stop, :normal, %{state | result: meta}} {:error, reason, _meta} -> {:stop, :normal, %{state | result: {:error, reason}}} end end @impl BB.Command def result(%{result: {:error, _} = e}), do: e def result(%{result: meta}), do: {:ok, meta} end ``` -------------------------------- ### One-shot IK solve with custom solver options Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Configures the DLS solver with various parameters like maximum iterations, tolerances, damping factor, and adaptive damping. ```elixir # ── Custom solver options ───────────────────────────────────────────────────── {:ok, positions, meta} = DLS.solve(robot, state, :gripper, target, max_iterations: 200, tolerance: 1.0e-5, orientation_tolerance: 0.005, lambda: 0.3, adaptive_damping: true, step_size: 0.05, respect_limits: true, exclude_joints: [:gripper_finger_left, :gripper_finger_right] ) ``` -------------------------------- ### Run All Tests Source: https://github.com/beam-bots/bb_ik_dls/blob/main/CLAUDE.md Execute all tests within the project. For running a specific test, append the file path and line number. ```bash mix test ``` ```bash mix test path/to/test.exs:42 ``` -------------------------------- ### Continuous Real-Time Target Tracking with BB.IK.DLS.Tracker Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt A GenServer for continuous IK-actuator loops at a configurable rate. The tracker solves for the current target and sends commands, continuing best-effort tracking even if individual solves fail. ```elixir alias BB.IK.DLS.Tracker # Start tracking a moving target at 30 Hz {:ok, tracker} = Tracker.start_link( robot: MyRobot, target_link: :gripper, initial_target: {0.3, 0.2, 0.1}, update_rate: 30, # Hz; default 20 delivery: :direct, # low-latency; default for tracker lambda: 0.3, step_size: 0.05, respect_limits: true ) ``` ```elixir # Update target from a vision callback defp on_vision_update(tracker, detected_xyz) do Tracker.update_target(tracker, detected_xyz) end ``` ```elixir # Check current tracking status %{ tracking: true, target: _current_target, residual: 0.0023, iterations: 14, update_rate: 30, last_update: _datetime } = Tracker.status(tracker) ``` ```elixir # Stop tracking and retrieve final positions {:ok, final_positions} = Tracker.stop(tracker) IO.inspect(final_positions) ``` ```elixir # Stop and hold actuators at current positions {:ok, _positions} = Tracker.stop(tracker, hold: true) ``` -------------------------------- ### BB.IK.DLS.Tracker Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt A GenServer that provides continuous, real-time target tracking by executing a periodic IK-to-actuator command loop at a configurable rate. The tracker continuously solves for the current target and dispatches actuator commands, allowing the target to be updated dynamically from external sources. It maintains best-effort tracking even if individual solves fail. ```APIDOC ## `BB.IK.DLS.Tracker` — Continuous real-time target tracking A `GenServer` that runs a periodic IK→actuator loop at a configurable rate (Hz). The tracker continuously solves for the current target and sends actuator commands. The target can be updated at any time from external sources such as a vision pipeline or joystick input. Continues best-effort tracking even when individual solves fail. ### Example Usage: ```elixir alias BB.IK.DLS.Tracker # Start tracking a moving target at 30 Hz {:ok, tracker} = Tracker.start_link( robot: MyRobot, target_link: :gripper, initial_target: {0.3, 0.2, 0.1}, update_rate: 30, # Hz; default 20 delivery: :direct, # low-latency; default for tracker lambda: 0.3, step_size: 0.05, respect_limits: true ) # Update target from a vision callback defp on_vision_update(tracker, detected_xyz) do Tracker.update_target(tracker, detected_xyz) end # Check current tracking status %{ tracking: true, target: _current_target, residual: 0.0023, iterations: 14, update_rate: 30, last_update: _datetime } = Tracker.status(tracker) # Stop tracking and retrieve final positions {:ok, final_positions} = Tracker.stop(tracker) IO.inspect(final_positions) # Stop and hold actuators at current positions {:ok, _positions} = Tracker.stop(tracker, hold: true) ``` ``` -------------------------------- ### Motion Convenience API for IK Solving Source: https://github.com/beam-bots/bb_ik_dls/blob/main/README.md Utilize the BB.Motion integration for simplified robot movement commands. Supports single end-effector movements and coordinated multi-limb motions. ```elixir # Move end-effector using BB.Motion integration case BB.IK.DLS.Motion.move_to(MyRobot, :gripper, {0.3, 0.2, 0.1}) do {:ok, meta} -> IO.puts("Reached in #{meta.iterations} iterations") {:error, reason, _meta} -> IO.puts("Failed: #{reason}") end # Coordinated multi-limb motion targets = %{left_foot: {0.1, 0.0, 0.0}, right_foot: {-0.1, 0.0, 0.0}} BB.IK.DLS.Motion.move_to_multi(MyRobot, targets) ``` -------------------------------- ### Run All Checks with mix check Source: https://github.com/beam-bots/bb_ik_dls/blob/main/CLAUDE.md Use this command to run all project checks, including compilation, testing, formatting, linting, and Dialyzer. It is preferred over running individual tools. ```bash mix check --no-retry ``` -------------------------------- ### Add bb_ik_dls to Mix Dependencies Source: https://github.com/beam-bots/bb_ik_dls/blob/main/README.md Add this dependency to your project's mix.exs file to include the BB.IK.DLS library. ```elixir def deps do [ {:bb_ik_dls, "~> 0.3.1"} ] end ``` -------------------------------- ### BB.IK.DLS.Motion.move_to/4 Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Solves Inverse Kinematics (IK) and sends actuator commands to move a specified end-effector to a target pose. It wraps the BB.Motion.move_to/4 function, pre-configuring the DLS solver. The function returns `{:ok, meta}` upon successful dispatch or `{:error, reason, meta}` if a solution cannot be found or an error occurs during dispatch. ```APIDOC ## `BB.IK.DLS.Motion.move_to/4` — Solve and send actuator commands Wraps `BB.Motion.move_to/4` with the DLS solver pre-configured. Solves the IK and dispatches actuator commands in one call. Accepts a robot module or a `BB.Command.Context`. Returns `{:ok, meta}` (no positions — motion was dispatched) or `{:error, reason, meta}`. ### Example Usage: ```elixir alias BB.IK.DLS.Motion # Basic move case Motion.move_to(MyRobot, :gripper, {0.3, 0.2, 0.1}) do {:ok, %{iterations: n, residual: r, reached: true}} -> IO.puts("Moved in #{n} iterations") {:error, :no_solution, meta} -> IO.puts("Unreachable, best residual: #{meta.residual} m") end # With full target format and options target = {Vec3.new(0.3, 0.2, 0.1), {:quaternion, Quaternion.identity()}} Motion.move_to(MyRobot, :gripper, target, delivery: :sync, # :pubsub (default) | :direct | :sync max_iterations: 200, tolerance: 0.001, lambda: 0.3, exclude_joints: [:left_finger, :right_finger] ) # Inside a BB.Command defmodule GraspCommand do use BB.Command @impl BB.Command def handle_command(%{target: target}, context, state) do case Motion.move_to(context, :gripper, target) do {:ok, meta} -> {:stop, :normal, %{state | result: meta}} {:error, reason, _meta} -> {:stop, :normal, %{state | result: {:error, reason}}} end end @impl BB.Command def result(%{result: {:error, _} = e}), do: e def result(%{result: meta}), do: {:ok, meta} end ``` ``` -------------------------------- ### BB.IK.DLS.solve_and_update/5 — Solve and apply to state in-place Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Solves for inverse kinematics and automatically updates the provided `BB.Robot.State` ETS table with the resulting joint positions upon success. Returns `{:ok, positions, meta}` on success or an error tuple on failure. ```APIDOC ## BB.IK.DLS.solve_and_update/5 ### Description Identical to `solve/5` but automatically writes the resulting positions back to the `BB.Robot.State` ETS table on success. Useful when you want to commit the solution immediately without an explicit `State.set_positions/2` call. ### Method `BB.IK.DLS.solve_and_update/5` ### Parameters - `robot`: The robot definition. - `state`: The `BB.Robot.State` to update. - `target_link`: The name of the end-effector link. - `target`: The target pose (Vec3, Transform, quaternion tuple, or axis-direction constraint). - `options`: Optional keyword list for solver parameters. ### Request Example ```elixir robot = MyRobot.robot() {:ok, state} = BB.Robot.State.new(robot) target = Vec3.new(0.35, 0.1, 0.2) case BB.IK.DLS.solve_and_update(robot, state, :end_effector, target) do {:ok, _positions, %{iterations: n, residual: r}} -> # state's ETS table already reflects the new positions IO.puts("State updated after #{n} iterations, residual #{r} m") {:error, %BB.Error.Kinematics.NoSolution{}} -> IO.puts("Could not reach target; state unchanged") end ``` ### Response #### Success Response - `{:ok, positions, meta}`: Similar to `solve/5`, where `state` is updated in-place. #### Error Response - `{:error, %BB.Error.Kinematics{...}}`: Indicates failure to solve; the `state` remains unchanged. ``` -------------------------------- ### Format Code with mix format Source: https://github.com/beam-bots/bb_ik_dls/blob/main/CLAUDE.md Applies code formatting rules to the project. Ensure code is formatted before committing changes. ```bash mix format ``` -------------------------------- ### Validate Reachability Without Moving with BB.IK.DLS.Motion.solve/4 Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Runs the DLS solver to return joint positions without dispatching actuator commands. Use this to check reachability before committing to motion. Returns {:ok, positions, meta} or {:error, :no_solution, meta}. ```elixir alias BB.IK.DLS.Motion case Motion.solve(MyRobot, :gripper, {0.3, 0.2, 0.1}) do {:ok, positions, %{reached: true, residual: r}} -> IO.puts("Reachable, residual #{r} m") IO.inspect(positions) {:ok, _positions, %{reached: false, residual: r}} -> IO.puts("Best-effort only, residual #{r} m") {:error, :no_solution, _meta} -> IO.puts("Failed to converge") end ``` -------------------------------- ### One-shot IK solve with explicit quaternion tuple target Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Solves for a target pose specified as a tuple containing a position and an explicit quaternion. ```elixir # ── Explicit quaternion tuple ───────────────────────────────────────────────── target_q = {Vec3.new(0.2, 0.1, 0.4), {:quaternion, Quaternion.identity()}} {:ok, _positions, _meta} = DLS.solve(robot, state, :gripper, target_q) ``` -------------------------------- ### BB.IK.DLS.solve/5 — One-shot IK solve Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Computes joint positions for a target pose. Returns {:ok, positions, meta} on success or a BB.Error.Kinematics error on failure. Supports position-only, 6-DOF, and axis-direction targets, with options for custom solver parameters. ```APIDOC ## BB.IK.DLS.solve/5 ### Description Computes joint positions that place the named end-effector link at the given target pose. Accepts a `BB.Robot.State` or a plain positions map. On success returns `{:ok, positions, meta}` where `meta` contains `:iterations`, `:residual` (metres), `:orientation_residual` (radians or `nil`), and `:reached` (boolean). On failure returns a structured `BB.Error.Kinematics` error that still carries the best-effort positions reached before giving up. ### Method `BB.IK.DLS.solve/5` ### Parameters - `robot`: The robot definition. - `state`: The current robot state or a positions map. - `target_link`: The name of the end-effector link. - `target`: The target pose (Vec3, Transform, quaternion tuple, or axis-direction constraint). - `options`: Optional keyword list for solver parameters (e.g., `max_iterations`, `tolerance`, `lambda`). ### Request Example ```elixir alias BB.IK.DLS alias BB.Math.{Vec3, Quaternion, Transform} alias BB.Error.Kinematics.{NoSolution, UnknownLink, NoDofs} robot = MyRobot.robot() {:ok, state} = BB.Robot.State.new(robot) # Position-only target target = Vec3.new(0.4, 0.2, 0.1) case DLS.solve(robot, state, :end_effector, target) do {:ok, positions, %{iterations: n, residual: r, reached: true}} -> IO.puts("Converged in #{n} iterations, residual #{Float.round(r, 6)} m") BB.Robot.State.set_positions(state, positions) {:error, %NoSolution{residual: r, positions: best_positions}} -> IO.puts("Did not converge; best residual #{Float.round(r, 4)} m") {:error, %UnknownLink{target_link: link}} -> IO.puts("Link #{link} not found in topology") {:error, %NoDofs{target_link: link}} -> IO.puts("No movable joints in chain to #{link}") end # Full 6-DOF target via Transform transform_target = Transform.from_position_quaternion( Vec3.new(0.3, 0.2, 0.1), Quaternion.from_axis_angle(Vec3.unit_z(), :math.pi() / 4) ) {:ok, positions, meta} = DLS.solve(robot, state, :gripper, transform_target) IO.puts("Orientation residual: #{meta.orientation_residual} rad") # Explicit quaternion tuple target_q = {Vec3.new(0.2, 0.1, 0.4), {:quaternion, Quaternion.identity()}} {:ok, _positions, _meta} = DLS.solve(robot, state, :gripper, target_q) # Axis-direction constraint (point tool along Z) target_axis = {Vec3.new(0.2, 0.1, 0.4), {:axis, Vec3.unit_z()}} {:ok, _positions, _meta} = DLS.solve(robot, state, :gripper, target_axis) # Custom solver options {:ok, positions, meta} = DLS.solve(robot, state, :gripper, target, max_iterations: 200, tolerance: 1.0e-5, orientation_tolerance: 0.005, lambda: 0.3, adaptive_damping: true, step_size: 0.05, respect_limits: true, exclude_joints: [:gripper_finger_left, :gripper_finger_right] ) ``` ### Response #### Success Response - `{:ok, positions, meta}` where `meta` is a map containing: - `:iterations` (integer): Number of iterations performed. - `:residual` (float): Euclidean distance error in metres. - `:orientation_residual` (float | nil): Orientation error in radians, or nil if not computed. - `:reached` (boolean): True if the target was reached within tolerance. #### Error Response - `{:error, %BB.Error.Kinematics{...}}`: A structured error containing details about the failure (e.g., `NoSolution`, `UnknownLink`, `NoDofs`). The error struct may contain `positions` with the best-effort solution found. ``` -------------------------------- ### Coordinated Multi-Limb Motion with BB.IK.DLS.Motion.move_to_multi/3 Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Solves IK for multiple end-effectors simultaneously and dispatches all actuator commands together. Designed for coordinated motion. All targets are solved independently with DLS. ```elixir alias BB.IK.DLS.Motion targets = %{ left_foot: {0.10, 0.15, 0.00}, right_foot: {-0.10, 0.15, 0.00} } case Motion.move_to_multi(MyRobot, targets) do {:ok, results} -> Enum.each(results, fn {link, {:ok, _pos, meta}} -> IO.puts("#{link} reached in #{meta.iterations} iterations") end) {:error, failed_link, reason, results} -> IO.puts("#{failed_link} failed: #{reason}") # `results` contains outcomes for the other links end ``` -------------------------------- ### One-shot IK solve with 6-DOF target via Transform Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Solves for a target pose defined by a Transform, including position and orientation. Reports orientation residual on success. ```elixir # ── Full 6-DOF target via Transform ────────────────────────────────────────── transform_target = Transform.from_position_quaternion( Vec3.new(0.3, 0.2, 0.1), Quaternion.from_axis_angle(Vec3.unit_z(), :math.pi() / 4) ) {:ok, positions, meta} = DLS.solve(robot, state, :gripper, transform_target) IO.puts("Orientation residual: #{meta.orientation_residual} rad") ``` -------------------------------- ### Nx Defn for DLS Computation Source: https://github.com/beam-bots/bb_ik_dls/blob/main/CLAUDE.md This snippet shows the core computation within the DLS algorithm using Nx.Defn for performance. It calculates the damped pseudoinverse. ```elixir defn compute_update(jacobian, error, lambda) do jjt = Nx.dot(jacobian, Nx.transpose(jacobian)) # ... end ``` -------------------------------- ### Solve IK and apply to robot state in-place Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Solves the inverse kinematics problem and directly updates the robot's state in the ETS table upon successful convergence. Returns an error if the target cannot be reached, leaving the state unchanged. ```elixir robot = MyRobot.robot() {:ok, state} = BB.Robot.State.new(robot) target = Vec3.new(0.35, 0.1, 0.2) case BB.IK.DLS.solve_and_update(robot, state, :end_effector, target) do {:ok, _positions, %{iterations: n, residual: r}} -> # state's ETS table already reflects the new positions IO.puts("State updated after #{n} iterations, residual #{r} m") {:error, %BB.Error.Kinematics.NoSolution{}} -> IO.puts("Could not reach target; state unchanged") end ``` -------------------------------- ### One-shot IK solve with position-only target Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Computes joint positions for a target position. Handles success, no solution, unknown link, and no degrees of freedom errors. Updates robot state on success. ```elixir alias BB.IK.DLS alias BB.Math.{Vec3, Quaternion, Transform} alias BB.Error.Kinematics.{NoSolution, UnknownLink, NoDofs} robot = MyRobot.robot() {:ok, state} = BB.Robot.State.new(robot) # ── Position-only target ────────────────────────────────────────────────────── target = Vec3.new(0.4, 0.2, 0.1) case DLS.solve(robot, state, :end_effector, target) do {:ok, positions, %{iterations: n, residual: r, reached: true}} -> IO.puts("Converged in #{n} iterations, residual #{Float.round(r, 6)} m") BB.Robot.State.set_positions(state, positions) {:error, %NoSolution{residual: r, positions: best_positions}} -> IO.puts("Did not converge; best residual #{Float.round(r, 4)} m") # best_positions still usable for approximate motion {:error, %UnknownLink{target_link: link}} -> IO.puts("Link #{link} not found in topology") {:error, %NoDofs{target_link: link}} -> IO.puts("No movable joints in chain to #{link}") end ``` -------------------------------- ### Basic Inverse Kinematics Solving Source: https://github.com/beam-bots/bb_ik_dls/blob/main/README.md Solve for the joint angles required to reach a target position using the DLS solver. Handles successful convergence and provides feedback on iterations, or reports failure with residual error. ```elixir robot = MyRobot.robot() {:ok, state} = BB.Robot.State.new(robot) # Solve for end-effector to reach target position target = Vec3.new(0.4, 0.2, 0.1) case BB.IK.DLS.solve(robot, state, :end_effector, target) do {:ok, positions, meta} -> BB.Robot.State.set_positions(state, positions) IO.puts("Solved in #{meta.iterations} iterations") {:error, %BB.Error.Kinematics.NoSolution{residual: residual}} -> IO.puts("Failed to converge, residual: #{residual}m") end ``` -------------------------------- ### Validate Multiple Targets Without Moving with BB.IK.DLS.Motion.solve_multi/3 Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Validates reachability for a set of end-effector targets without moving the robot. Returns all solved positions for inspection. Handles {:ok, results} or {:error, failed_link, reason, results}. ```elixir alias BB.IK.DLS.Motion targets = %{left_foot: {0.1, 0.0, 0.0}, right_foot: {-0.1, 0.0, 0.0}} case Motion.solve_multi(MyRobot, targets) do {:ok, results} -> Enum.each(results, fn {link, {:ok, _pos, meta}} -> IO.puts("#{link}: residual #{meta.residual} m (reached: #{meta.reached})") end) {:error, failed_link, reason, _results} -> IO.puts("#{failed_link} unreachable: #{reason}") end ``` -------------------------------- ### Lint Code with mix credo Source: https://github.com/beam-bots/bb_ik_dls/blob/main/CLAUDE.md Perform strict linting on the codebase to enforce coding standards. Address any issues reported by Credo. ```bash mix credo --strict ``` -------------------------------- ### Inverse Kinematics Solving with Orientation Source: https://github.com/beam-bots/bb_ik_dls/blob/main/README.md Solve for end-effector pose including orientation. Supports full 6-DOF targets via Transform or axis constraints for tool direction. ```elixir # Full 6-DOF target via Transform target = Transform.from_position_quaternion( Vec3.new(0.3, 0.2, 0.1), Quaternion.from_axis_angle(Vec3.unit_z(), :math.pi() / 4) ) {:ok, positions, meta} = BB.IK.DLS.solve(robot, state, :gripper, target) # Or with axis constraint (point tool in a direction) target = {Vec3.new(0.3, 0.2, 0.1), {:axis, Vec3.unit_z()}} ``` -------------------------------- ### One-shot IK solve with axis-direction constraint Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Solves for a target pose where the end-effector's tool axis is constrained to a specific direction. ```elixir # ── Axis-direction constraint (point tool along Z) ──────────────────────────── target_axis = {Vec3.new(0.2, 0.1, 0.4), {:axis, Vec3.unit_z()}} {:ok, _positions, _meta} = DLS.solve(robot, state, :gripper, target_axis) ``` -------------------------------- ### BB.IK.DLS.Motion.solve_multi/3 Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Validates the reachability of multiple end-effector targets concurrently without executing any motion. This function solves the IK for each target independently using DLS and returns all solved joint positions for inspection. It's useful for pre-checking complex multi-limb configurations. ```APIDOC ## `BB.IK.DLS.Motion.solve_multi/3` — Validate multiple targets without moving Validates reachability for a set of end-effector targets without moving the robot. Returns all solved positions for inspection. ### Example Usage: ```elixir alias BB.IK.DLS.Motion targets = %{left_foot: {0.1, 0.0, 0.0}, right_foot: {-0.1, 0.0, 0.0}} case Motion.solve_multi(MyRobot, targets) do {:ok, results} -> Enum.each(results, fn {link, {:ok, _pos, meta}} -> IO.puts("#{link}: residual #{meta.residual} m (reached: #{meta.reached})") end) {:error, failed_link, reason, _results} -> IO.puts("#{failed_link} unreachable: #{reason}") end ``` ``` -------------------------------- ### BB.IK.DLS.Motion.move_to_multi/3 Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Performs coordinated motion for multiple end-effectors simultaneously. It solves the IK for all specified targets independently using DLS and dispatches all actuator commands together. This is ideal for tasks requiring synchronized movement, such as bipedal locomotion or dual-arm manipulation. ```APIDOC ## `BB.IK.DLS.Motion.move_to_multi/3` — Coordinated multi-limb motion Solves IK for multiple end-effectors simultaneously and dispatches all actuator commands together. Designed for coordinated motion such as bipedal gait steps or dual-arm manipulation. All targets are solved independently with DLS. ### Example Usage: ```elixir alias BB.IK.DLS.Motion targets = %{ left_foot: {0.10, 0.15, 0.00}, right_foot: {-0.10, 0.15, 0.00} } case Motion.move_to_multi(MyRobot, targets) do {:ok, results} -> Enum.each(results, fn {link, {:ok, _pos, meta}} -> IO.puts("#{link} reached in #{meta.iterations} iterations") end) {:error, failed_link, reason, results} -> IO.puts("#{failed_link} failed: #{reason}") # `results` contains outcomes for the other links end ``` ``` -------------------------------- ### Collision-Aware Inverse Kinematics Solving Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Solves the inverse kinematics problem with optional self-collision detection. This allows for safer robot movements by ensuring the resulting configuration is collision-free. ```APIDOC ## BB.IK.DLS.solve/5 ### Description Solves the inverse kinematics problem for a given target pose. Optionally checks for self-collisions and applies a safety margin. ### Method `solve/5` ### Parameters - `robot`: The robot model. - `state`: The current state of the robot. - `end_effector_name`: The name of the end-effector frame. - `target`: The desired target pose (e.g., a `Vec3.new/1`). - `opts`: A keyword list of options, including: - `:check_collisions` (boolean): Enable self-collision checking (default: `false`). - `:collision_margin` (float): Safety margin in meters (default: `0.0`). ### Request Example ```elixir alias BB.Error.Kinematics.SelfCollision robot = MyRobot.robot() {:ok, state} = BB.Robot.State.new(robot) target = Vec3.new(0.4, 0.0, 0.2) # Default: no collision check {:ok, _positions, _meta} = BB.IK.DLS.solve(robot, state, :tip, target) # With collision checking case BB.IK.DLS.solve(robot, state, :tip, target, check_collisions: true) do {:ok, positions, _meta} -> IO.puts("Solution is collision-free") {:error, %SelfCollision{link_a: a, link_b: b, joint_positions: pos}} -> IO.puts("Collision between #{a} and #{b}") end # With safety margin case BB.IK.DLS.solve(robot, state, :tip, target, check_collisions: true, collision_margin: 0.02) do {:ok, positions, _meta} -> IO.puts("Collision-free with 2 cm margin") {:error, %SelfCollision{} = err} -> IO.puts("Too close: #{err.link_a} ↔ #{err.link_b}") end ``` ### Response #### Success Response (Tuple) - `{:ok, positions, meta}`: Where `positions` are the computed joint angles and `meta` contains additional information. #### Error Response (Tuple) - `{:error, %BB.Error.Kinematics.SelfCollision{}}`: Returned when a self-collision is detected. The error struct contains details about the collision. ### Error Handling - `BB.Error.Kinematics.SelfCollision`: Indicates a detected self-collision, providing the colliding links and joint positions. ``` -------------------------------- ### Compute Numerical Jacobian with BB.IK.DLS.Jacobian Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Computes the Jacobian matrix numerically using central finite differences. Use `compute/4` for position-only Jacobians and `compute_with_orientation/4` for full 6xN Jacobians. These are internal but can be called directly. ```elixir alias BB.IK.DLS.Jacobian robot = MyRobot.robot() positions = %{shoulder_yaw: 0.0, shoulder_pitch: 0.3, elbow_pitch: -0.5} joint_names = [:shoulder_yaw, :shoulder_pitch, :elbow_pitch] # 3×N position-only Jacobian j_pos = Jacobian.compute(robot, positions, :end_effector, joint_names) # => #Nx.Tensor # 6×N full Jacobian (position + orientation) j_full = Jacobian.compute_with_orientation(robot, positions, :end_effector, joint_names) # => #Nx.Tensor # Inspect the Jacobian to understand how joints affect the end-effector IO.inspect(Nx.to_list(j_pos)) ``` -------------------------------- ### Solve Inverse Kinematics with Collision Checking Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Solves for joint angles to reach a target pose. Enable collision checking with `check_collisions: true` and specify a `collision_margin` for a safety buffer. Returns a `BB.Error.Kinematics.SelfCollision` error on detection. ```elixir alias BB.Error.Kinematics.SelfCollision robot = MyRobot.robot() {:ok, state} = BB.Robot.State.new(robot) target = Vec3.new(0.4, 0.0, 0.2) # Default: no collision check {:ok, _positions, _meta} = BB.IK.DLS.solve(robot, state, :tip, target) # With collision checking (exact geometry) case BB.IK.DLS.solve(robot, state, :tip, target, check_collisions: true) do {:ok, positions, _meta} -> IO.puts("Solution is collision-free") {:error, %SelfCollision{link_a: a, link_b: b, joint_positions: pos}} -> IO.puts("Collision between #{a} and #{b}") IO.inspect(pos) end # With safety margin (e.g. 2 cm clearance) case BB.IK.DLS.solve(robot, state, :tip, target, check_collisions: true, collision_margin: 0.02) do {:ok, positions, _meta} -> IO.puts("Collision-free with 2 cm margin") {:error, %SelfCollision{} = err} -> IO.puts("Too close: #{err.link_a} ↔ #{err.link_b}") end ``` -------------------------------- ### DLS Algorithm Jacobian Pseudoinverse Formula Source: https://github.com/beam-bots/bb_ik_dls/blob/main/README.md Illustrates the core mathematical formula used by the Damped Least Squares (DLS) algorithm for computing joint updates, highlighting the role of the Jacobian matrix and damping factor. ```mathematica Δθ = Jᵀ (J Jᵀ + λ²I)⁻¹ e ``` -------------------------------- ### BB.IK.DLS.Motion.solve/4 Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Validates the reachability of a target pose by running the DLS solver without dispatching any actuator commands. This function is useful for checking if a target is reachable before initiating motion. It returns the calculated joint positions and metadata, including whether the target was reached and the residual error. ```APIDOC ## `BB.IK.DLS.Motion.solve/4` — Validate reachability without moving Runs the DLS solver and returns joint positions without dispatching any actuator commands. Use this to check whether a target is reachable before committing to motion. ### Example Usage: ```elixir alias BB.IK.DLS.Motion case Motion.solve(MyRobot, :gripper, {0.3, 0.2, 0.1}) do {:ok, positions, %{reached: true, residual: r}} -> IO.puts("Reachable, residual #{r} m") IO.inspect(positions) {:ok, _positions, %{reached: false, residual: r}} -> IO.puts("Best-effort only, residual #{r} m") {:error, :no_solution, _meta} -> IO.puts("Failed to converge") end ``` ``` -------------------------------- ### Numerical Jacobian Computation Source: https://context7.com/beam-bots/bb_ik_dls/llms.txt Computes the Jacobian matrix numerically using central finite differences. This function can be called directly for custom solver implementations. ```APIDOC ## Jacobian.compute/4 ### Description Computes the Jacobian matrix numerically via central finite differences (ε = 1.0e-6). Returns a 3×N position-only tensor. ### Method `compute/4` ### Parameters - `robot`: The robot model. - `positions`: A map of joint names to their current angular positions. - `end_effector_name`: The name of the end-effector frame. - `joint_names`: A list of joint names to compute derivatives for. ### Request Example ```elixir alias BB.IK.DLS.Jacobian robot = MyRobot.robot() positions = %{shoulder_yaw: 0.0, shoulder_pitch: 0.3, elbow_pitch: -0.5} joint_names = [:shoulder_yaw, :shoulder_pitch, :elbow_pitch] j_pos = Jacobian.compute(robot, positions, :end_effector, joint_names) ``` ### Response #### Success Response (Tensor) - `j_pos` (#Nx.Tensor): A 3xN tensor representing the position-only Jacobian. ### Response Example ```elixir #Nx.Tensor ``` ## Jacobian.compute_with_orientation/4 ### Description Computes the full 6×N Jacobian matrix (position derivatives and angular velocity derivatives) numerically via central finite differences. ### Method `compute_with_orientation/4` ### Parameters - `robot`: The robot model. - `positions`: A map of joint names to their current angular positions. - `end_effector_name`: The name of the end-effector frame. - `joint_names`: A list of joint names to compute derivatives for. ### Request Example ```elixir alias BB.IK.DLS.Jacobian robot = MyRobot.robot() positions = %{shoulder_yaw: 0.0, shoulder_pitch: 0.3, elbow_pitch: -0.5} joint_names = [:shoulder_yaw, :shoulder_pitch, :elbow_pitch] j_full = Jacobian.compute_with_orientation(robot, positions, :end_effector, joint_names) ``` ### Response #### Success Response (Tensor) - `j_full` (#Nx.Tensor): A 6xN tensor representing the full Jacobian. ### Response Example ```elixir #Nx.Tensor ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.