Skip to content

Conversation

@Williangalvani
Copy link
Member

@Williangalvani Williangalvani commented Dec 8, 2025

adds custom widgets/optiosn for:

regular servo
motors
actuators
lights
gpio
relays

fix #3267 ?

Summary by Sourcery

Introduce specialized editors for different servo function types in the parameter editor dialog to support motor- and GPIO-specific PWM configuration while keeping a generic range editor for other functions.

Enhancements:

  • Refactor ServoFunctionEditorDialog to dynamically render a function-specific editor component based on the selected servo function option.
  • Add a reusable ServoFunctionRangeEditor component for configuring generic servo PWM ranges via slider and inline parameter editors.
  • Add a ServoFunctionMotorEditor with motor-specific PWM range handling that integrates MOT_PWM_TYPE, MOT_PWM_MIN, and MOT_PWM_MAX parameters and supports angle-based configurations.
  • Introduce placeholder ServoFunctionActuatorEditor and ServoFunctionGpioEditor components to support future specialized UIs for actuators and GPIO outputs.

@sourcery-ai
Copy link

sourcery-ai bot commented Dec 8, 2025

Reviewer's Guide

Refactors the servo function editor to delegate to specialized widgets based on the selected function type (motor, generic servo range, GPIO, actuator), introducing new dedicated Vue components for PWM range and motor configuration while preserving and adapting the existing slider-based min/trim/max editor logic.

Sequence diagram for motor PWM editing and persistence

sequenceDiagram
  actor User
  participant ServoFunctionMotorEditor
  participant AutopilotStore as AutopilotStore
  participant Parameter
  participant Mavlink2Rest as Mavlink2Rest

  User->>ServoFunctionMotorEditor: Open servo function dialog
  ServoFunctionMotorEditor->>AutopilotStore: parameter(MOT_PWM_TYPE)
  AutopilotStore-->>ServoFunctionMotorEditor: mot_pwm_type_param
  ServoFunctionMotorEditor->>AutopilotStore: parameter(MOT_PWM_MIN, MOT_PWM_MAX or *_MIN, *_MAX)
  AutopilotStore-->>ServoFunctionMotorEditor: min_param, max_param, trim_param
  ServoFunctionMotorEditor->>ServoFunctionMotorEditor: initializeSliderValues()

  User->>ServoFunctionMotorEditor: Drag slider thumb
  ServoFunctionMotorEditor->>ServoFunctionMotorEditor: onSliderMouseDown(event)
  ServoFunctionMotorEditor->>ServoFunctionMotorEditor: calculateValueFromEvent()
  ServoFunctionMotorEditor->>ServoFunctionMotorEditor: findClosestThumb()
  loop While dragging
    User->>ServoFunctionMotorEditor: Move pointer
    ServoFunctionMotorEditor->>ServoFunctionMotorEditor: onSliderMouseMove(event)
    ServoFunctionMotorEditor->>ServoFunctionMotorEditor: updateThumbValue(event)
    ServoFunctionMotorEditor->>ServoFunctionMotorEditor: updateValueBasedOnThumb(value)
    ServoFunctionMotorEditor->>ServoFunctionMotorEditor: updateMinTrimMax()
    ServoFunctionMotorEditor->>Parameter: update local Parameter.value
  end

  User->>ServoFunctionMotorEditor: Release mouse button
  ServoFunctionMotorEditor->>ServoFunctionMotorEditor: onSliderMouseUp()
  ServoFunctionMotorEditor->>Parameter: resolve selected param
  ServoFunctionMotorEditor->>Mavlink2Rest: setParam(param.name, value, AutopilotStore.system_id, param.paramType.type)
  Mavlink2Rest-->>ServoFunctionMotorEditor: ack
  ServoFunctionMotorEditor->>Parameter: param.value = value
Loading

Class diagram for new servo function editor components

classDiagram
  class ServoFunctionEditorDialog {
    +Parameter param
    +boolean value
    +function_type() VueConstructor
  }

  class ServoFunctionRangeEditor {
    +Parameter param
    -number minValue
    -number trimValue
    -number maxValue
    -number activeThumb
    -boolean isDragging
    +trim_param() Parameter
    +max_param() Parameter
    +min_param() Parameter
    +minPercent() number
    +trimPercent() number
    +maxPercent() number
    +getParamByType(type string) Parameter
    +calculatePercentage(value number) number
    +updateParamValue(type ParamType, newValue number) void
    +initializeSliderValues() void
    +getThumbPosition(index number) number
    +getThumbValue(index number) number
    +startDragging(index number) void
    +onSliderMouseDown(event MouseEvent) void
    +calculateValueFromEvent(event MouseEvent, container HTMLElement) object
    +findClosestThumb(value number) number
    +onSliderMouseMove(event MouseEvent) void
    +onSliderMouseUp() void
    +updateThumbValue(event MouseEvent) void
    +updateValueBasedOnThumb(value number) void
    +updateMin(value string) void
    +updateTrim(value string) void
    +updateMax(value string) void
    +updateParamWithConstraints(value string, param Parameter, min number, max number, property string) void
    +onTouchStart(event TouchEvent) void
    +onTouchMove(event TouchEvent) void
    +onTouchEnd() void
  }

  class ServoFunctionMotorEditor {
    +Parameter param
    -number minValue
    -number trimValue
    -number maxValue
    -number activeThumb
    -boolean isDragging
    +trim_param() Parameter
    +max_param() Parameter
    +min_param() Parameter
    +mot_pwm_type_param() Parameter
    +mot_pwm_type() PwmTypes
    +mot_pwm_type_is_supported() boolean
    +minPercent() number
    +trimPercent() number
    +maxPercent() number
    +getParamByType(type string) Parameter
    +calculatePercentage(value number) number
    +updateParamValue(type ParamType, newValue number) void
    +initializeSliderValues() void
    +getThumbPosition(index number) number
    +getThumbValue(index number) number
    +startDragging(index number) void
    +onSliderMouseDown(event MouseEvent) void
    +calculateValueFromEvent(event MouseEvent, container HTMLElement) object
    +findClosestThumb(value number) number
    +onSliderMouseMove(event MouseEvent) void
    +onSliderMouseUp() void
    +updateThumbValue(event MouseEvent) void
    +updateValueBasedOnThumb(value number) void
    +updateMin(value string) void
    +updateTrim(value string) void
    +updateMax(value string) void
    +updateParamWithConstraints(value string, param Parameter, min number, max number, property string) void
    +onTouchStart(event TouchEvent) void
    +onTouchMove(event TouchEvent) void
    +onTouchEnd() void
  }

  class ServoFunctionGpioEditor {
    +Parameter param
  }

  class ServoFunctionActuatorEditor {
    +Parameter param
  }

  class InlineParameterEditor {
    +boolean autoSet
    +string label
    +Parameter param
  }

  class Parameter {
    +string name
    +number value
    +object paramType
  }

  class AutopilotStore {
    +number system_id
    +parameter(name string) Parameter
  }

  class Mavlink2Rest {
    +setParam(name string, value number, systemId number, paramType any) void
  }

  ServoFunctionEditorDialog --> Parameter : uses
  ServoFunctionEditorDialog ..> ServoFunctionRangeEditor : selects
  ServoFunctionEditorDialog ..> ServoFunctionMotorEditor : selects
  ServoFunctionEditorDialog ..> ServoFunctionGpioEditor : selects
  ServoFunctionEditorDialog ..> ServoFunctionActuatorEditor : selects

  ServoFunctionRangeEditor *-- InlineParameterEditor : embeds
  ServoFunctionMotorEditor *-- InlineParameterEditor : embeds

  ServoFunctionRangeEditor ..> Parameter : reads_writes
  ServoFunctionMotorEditor ..> Parameter : reads_writes

  ServoFunctionRangeEditor ..> AutopilotStore : getParamByType
  ServoFunctionMotorEditor ..> AutopilotStore : getParamByType

  ServoFunctionRangeEditor ..> Mavlink2Rest : setParam
  ServoFunctionMotorEditor ..> Mavlink2Rest : setParam

  AutopilotStore <.. ServoFunctionRangeEditor
  AutopilotStore <.. ServoFunctionMotorEditor
  Mavlink2Rest <.. ServoFunctionRangeEditor
  Mavlink2Rest <.. ServoFunctionMotorEditor
Loading

Flow diagram for selecting specialized servo function widget

flowchart TD
  A[Start with selected servo function param] --> B[Read param.value]
  B --> C[Lookup selected option name in param.options]
  C --> D{Lowercased name contains substring?}
  D -->|contains 'motor'| E[Return ServoFunctionMotorEditor]
  D -->|contains 'gpio'| F[Return ServoFunctionGpioEditor]
  D -->|contains 'actuator'| G[Return ServoFunctionActuatorEditor]
  D -->|contains 'disabled'| H[Return undefined and render no widget]
  D -->|none of the above| I[Return ServoFunctionRangeEditor]
  E --> J[Dynamic component renders motor editor]
  F --> J
  G --> J
  H --> K[No specialized widget shown]
  I --> J
  J --> L[User edits PWM via selected widget]
  K --> L
Loading

File-Level Changes

Change Details Files
Refactor ServoFunctionEditorDialog to dynamically render specialized widgets based on the selected servo function type.
  • Replace inlined PWM range slider + min/trim/max parameter cards with a dynamic that chooses a widget based on the current param option label (motor, gpio, actuator, generic range).
  • Introduce a function_type computed property that inspects param.options[param.value] and returns the corresponding widget component, falling back to the generic range editor and skipping rendering when the function is disabled.
  • Register new ServoFunctionRangeEditor, ServoFunctionMotorEditor, ServoFunctionGpioEditor, and ServoFunctionActuatorEditor components for use within the dialog.
core/frontend/src/components/parameter-editor/ServoFunctionEditorDialog.vue
Extract the generic PWM range configuration UI and logic from the dialog into a reusable ServoFunctionRangeEditor component.
  • Create a standalone component that renders the existing three-thumb PWM slider and the associated min/trim/max InlineParameterEditor cards.
  • Reuse the MIN/MAX/DEFAULT constants and slider interaction logic (mouse/touch events, constraint enforcement, percentage mapping) previously embedded in ServoFunctionEditorDialog.
  • Continue to derive *_MIN/_TRIM/_MAX parameters from the base param name using autopilot.parameter and commit changes via mavlink2rest.setParam on slider release.
core/frontend/src/components/parameter-editor/ServoFunctionRangeEditor.vue
Add a motor-specific PWM editor that adapts the range UI based on MOT_PWM_TYPE and global motor PWM parameters.
  • Introduce ServoFunctionMotorEditor with the same slider UX but sourcing parameters from either channel-specific *_MIN/_TRIM/_MAX (for PWMAngle) or global MOT_PWM_MIN/MOT_PWM_MAX, plus a MOT_PWM_TYPE selector.
  • Implement PWM type handling with a PwmTypes enum and a mot_pwm_type_is_supported guard to show either the slider or a warning when BlueOS does not support the selected type.
  • Allow the trim thumb and card to be hidden/disabled when no trim parameter is present, updating slider constraints and label behaviour accordingly.
  • Wire all slider interactions to update underlying autopilot parameters and send changes to the backend via mavlink2rest.setParam, with boundary checks and thumb ordering constraints.
core/frontend/src/components/parameter-editor/ServoFunctionMotorEditor.vue
Introduce placeholder editors for GPIO- and actuator-based servo functions.
  • Add ServoFunctionGpioEditor component that currently just renders a basic placeholder bound to the passed param.
  • Add ServoFunctionActuatorEditor component with similar placeholder behaviour for actuator functions, ready for future expansion.
core/frontend/src/components/parameter-editor/ServoFunctionGpioEditor.vue
core/frontend/src/components/parameter-editor/ServoFunctionActuatorEditor.vue

Assessment against linked issues

Issue Objective Addressed Explanation
#3267 Update the vehicle-setup output pin UI so each function type (servo, motor, actuator, relay, leak detector, GPIO, etc.) shows appropriate function-specific parameters instead of always using standard servo min/trim/max. The PR introduces function-specific widgets and logic to select them (ServoFunctionRangeEditor for default/servo, ServoFunctionMotorEditor for motors, ServoFunctionGpioEditor and ServoFunctionActuatorEditor stubs). Motors now correctly use MOT_PWM_MIN/MOT_PWM_MAX (or channel MIN/MAX for PWMAngle), partially addressing the requirement. However, actuator, relay, leak-detector, and full GPIO handling are not implemented beyond placeholders, and there is no UI for relay defaults or leak detector inputs. Therefore the overall objective is only partially implemented and not fully addressed.
#3267 For GPIO-like outputs (relays, leak detectors, generic GPIO), display the correct function and state in the UI (e.g., GPIO (Relay X)), allow selection of these functions in the dropdown in a way that configures the underlying RELAYx_PIN/SERVO_GPIO_MASK/SERVOn_FUNCTION parameters appropriately, and show their on/off/default levels. The PR adds ServoFunctionGpioEditor.vue but it only renders the text 'GPIO!' and does not interact with any GPIO/relay/leak-detector parameters or display on/off state, default levels, or function labels like 'GPIO (Relay X)'. There are no changes to the selection dropdown behavior or to RELAYx_PIN/SERVO_GPIO_MASK handling. Leak detector UI is not present. Thus this objective is not addressed.
#3267 Enhance the output pin configuration UI with a reversal toggle and a space for misconfiguration warnings (e.g., overlapping leak detector and servo functions). The diff contains no reversal toggle control and no warning or validation logic or UI elements for misconfiguration. The new widgets focus on PWM range editors and simple stubs, without any warning system. This objective is not implemented.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@Williangalvani Williangalvani force-pushed the custom_pwm_output_widgets branch from 43a2e67 to 12798b7 Compare December 9, 2025 20:37
@Williangalvani Williangalvani force-pushed the custom_pwm_output_widgets branch from 12798b7 to 19f2852 Compare December 9, 2025 20:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

core: frontend: vehicle-setup: reflect output pin function

1 participant