BB.Robot.Topology (bb v0.27.0)

Copy Markdown View Source

Pre-computed topology metadata for efficient traversal and kinematic operations.

This struct contains ordering information that allows:

  • Forward kinematics to process joints in the correct order
  • Path lookup between any two nodes
  • Depth information for tree operations

Paths are root-relative and interleave links and joints, starting and ending with the node they name — [:base, :shoulder, :upper_arm, :elbow, :forearm].

Lookups here have no robot name to attribute their errors to. BB.Robot delegates to them and fills the name in.

Summary

Functions

Get the depth of a node in the tree.

Get all leaf links (links with no child joints).

Get the maximum depth of the kinematic tree.

Get the path from a source node down to a target node.

Get the path from root to a node.

Types

t()

@type t() :: %BB.Robot.Topology{
  depth: %{required(atom()) => non_neg_integer()},
  joint_order: [atom()],
  link_order: [atom()],
  paths: %{required(atom()) => [atom()]}
}

Functions

depth_of(topology, name)

@spec depth_of(t(), atom()) ::
  {:ok, non_neg_integer()} | {:error, BB.Error.Kinematics.UnknownLink.t()}

Get the depth of a node in the tree.

The root link has depth 0. Each joint/link pair adds 1 to the depth.

leaf_links(topology, robot)

@spec leaf_links(t(), BB.Robot.t()) :: [atom()]

Get all leaf links (links with no child joints).

max_depth(topology)

@spec max_depth(t()) :: non_neg_integer()

Get the maximum depth of the kinematic tree.

path_between(topology, source, target)

@spec path_between(t(), atom(), atom()) ::
  {:ok, [atom()]}
  | {:error,
     BB.Error.Kinematics.UnknownLink.t() | BB.Error.Kinematics.NotAnAncestor.t()}

Get the path from a source node down to a target node.

Restricted to the case where source is an ancestor of target, which makes this a prefix drop on the precomputed paths. The result starts at source and ends at target; a source equal to the target gives {:ok, [source]}.

Fails with BB.Error.Kinematics.NotAnAncestor when the source sits somewhere other than above the target, carrying their nearest common ancestor. That ancestor always exists: BB.Dsl.TopologyTransformer rejects any topology without exactly one root link and the DSL's nesting makes cycles impossible, so the topology is a single tree in which any two nodes share at least the root.

path_to(topology, name)

@spec path_to(t(), atom()) ::
  {:ok, [atom()]} | {:error, BB.Error.Kinematics.UnknownLink.t()}

Get the path from root to a node.

Returns a list of link/joint names from the root to the given node.