Current section
Files
Jump to
Current section
Files
lib/bb/joint_supervisor.ex
# SPDX-FileCopyrightText: 2025 James Harton## SPDX-License-Identifier: Apache-2.0defmodule BB.JointSupervisor do @moduledoc """ Supervisor for a joint and its child link. Supervises: - Joint sensors - Joint actuators - Child link supervisor (if joint has a child link) """ alias BB.Dsl.Info alias BB.Estimator.Wiring @doc """ Starts the joint supervisor. ## Arguments - `robot_module` - The robot module (e.g., `MyRobot`) - `joint` - The `BB.Dsl.Joint` struct - `path` - The path to this joint (e.g., `[:base_link]`) - `opts` - Options passed through to child processes """ @spec start_link({module, BB.Dsl.Joint.t(), [atom], Keyword.t()}) :: Supervisor.on_start() def start_link({robot_module, joint, path, opts}) do settings = Info.settings(robot_module) sup_mod = settings.supervisor_module || Supervisor children = build_children(robot_module, joint, path, opts) sup_mod.start_link(children, strategy: :one_for_one) end @doc false def child_spec({robot_module, joint, path, opts}) do %{ id: joint.name, start: {__MODULE__, :start_link, [{robot_module, joint, path, opts}]}, type: :supervisor } end defp build_children(robot_module, joint, path, opts) do joint_path = path ++ [joint.name] simulation_mode = Keyword.get(opts, :simulation) sensor_children = Enum.map(joint.sensors, fn sensor -> BB.Process.child_spec( robot_module, sensor.name, sensor.child_spec, joint_path, :sensor, opts ) end) sensor_estimator_children = Enum.flat_map(joint.sensors, fn sensor -> sensor_path = [:sensor | joint_path ++ [sensor.name]] Enum.map(sensor.estimators, fn estimator -> Wiring.sensor_nested_child_spec( robot_module, estimator, sensor_path, sensor.name, opts ) end) end) actuator_children = Enum.map(joint.actuators, fn actuator -> BB.Process.child_spec( robot_module, actuator.name, actuator.child_spec, joint_path, :actuator, opts ) end) auto_position_estimators = if simulation_mode do build_auto_position_estimators(robot_module, joint, joint_path, opts) else [] end link_child = if joint.link do [{BB.LinkSupervisor, {robot_module, joint.link, joint_path, opts}}] else [] end sensor_children ++ sensor_estimator_children ++ auto_position_estimators ++ actuator_children ++ link_child end defp build_auto_position_estimators(robot_module, joint, joint_path, opts) do joint.actuators |> Enum.filter(fn actuator -> not has_position_sensor_for_actuator?(joint.sensors, actuator.name) end) |> Enum.map(fn actuator -> sensor_name = :"#{actuator.name}_position_estimator" BB.Process.child_spec( robot_module, sensor_name, {BB.Sensor.OpenLoopPositionEstimator, actuator: actuator.name}, joint_path, :sensor, opts ) end) end defp has_position_sensor_for_actuator?(sensors, actuator_name) do Enum.any?(sensors, fn sensor -> case sensor.child_spec do {BB.Sensor.OpenLoopPositionEstimator, sensor_opts} -> Keyword.get(sensor_opts, :actuator) == actuator_name _ -> false end end) endend