Skip to content

Backend client architecture¤

This document details the architecture used to implement backend clients and backend features. It is aimed at contributors extending compas_fab with a new backend — it is not needed for everyday planning. End users interact with the planner and client classes in compas_fab.backends; each planner already exposes every backend-feature method directly, composing the features below through multiple inheritance.

Clients vs. planners¤

To keep backends consistent and modular, compas_fab defines two interfaces:

Any new backend should inherit from ClientInterface and pair it with a PlannerInterface subclass.

Eventually, execution and control will move to a separate ControlInterface; for now those methods sit on the client.

Backend features¤

PlannerInterface provides default behavior for each planning method. To override a default, implement the appropriate backend feature interface from compas_fab.backends.interfaces.

Backend feature classes are callable: their __call__ magic method delegates to the named method. For example:

from compas.geometry import Frame
from compas_fab.backends.interfaces import InverseKinematics

class ExampleInverseKinematics(InverseKinematics):
    def inverse_kinematics(self, robot, frame_WCF,
                           start_configuration=None,
                           group=None,
                           options=None):
        ...

calculate_example_ik = ExampleInverseKinematics()
frame = Frame([0, 0, 0], [1, 0, 0], [0, 1, 0])
ik_result = calculate_example_ik(robot, frame)
# equivalent to:
ik_result = calculate_example_ik.inverse_kinematics(robot, frame)

The feature interfaces enforce a common signature across all implementations. Adhere to the documented types for arguments and return values.

Mixing features from multiple backends¤

The feature interfaces are designed so a user can mix and match features from different backends. For example, if ClientA is fast at inverse kinematics but lacks motion planning, and ClientB is slow at IK but plans well:

with ClientA() as client_a, ClientB() as client_b:
    inverse_kinematics = ClientAInverseKinematics(client_a)
    plan_motion = ClientBPlanMotion(client_b)

Implemented backend features¤

The following backend feature modules are provided: