Skip to content

Conversation

@filipembedded
Copy link
Contributor

This PR adds motor mixing library for quadcopters and demo that showcases the usage of the library.

@filipembedded filipembedded marked this pull request as draft January 5, 2026 13:44

typedef struct {
ESC_Inst_Type motor_arr[MAX_MOTOR_INSTANCES];
uint8_t motor_instances;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a check that the number of motor matches the expected configuration anywhere. Perhaps we could add a motor config as a discriminated union to the init function and avoid the headaches like this.

// TODO: Add checks here for edge-cases like R=P=0 and Y>T
switch (mixer->uav_config) {
case MIXER_UAV_CFG_QUADROTOR_X:
m1 = limit_min_thrust_values(mixer_mapped.thrust - mixer_mapped.roll +
Copy link
Member

@DNedic DNedic Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Local saturation is a problem, if it happens our thrust vector will be oriented wrongly. @nikolaptr can provide some more insight but I believe thrust should be (dynamically?) capped so that no motor is saturated and we always have control of the vector direction. That way we lose power but gain controlability.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the issue here, thanks for pointing this. I think that @nikolaptr mentioned somewhere that this issue could be solved statically, and that it could be simpler solution.
@nikolaptr Can you point me to some materials or prior implementations related to this issue so I can be sure I approach this correctly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented some solution for saturation based on the way Ardupilot does it. Please check it out @DNedic

int32_t min_receiver_val, max_receiver_val, neutral_receiver_val;

#ifdef CONFIG_MIXER_MINIMAL_RECEIVER_DATA_OFFSET
min_receiver_val = CONFIG_MIXER_MINIMAL_RECEIVER_DATA_VALUE;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK zephyr will ALWAYS define numerical CONFIG_s

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense, thanks a lot!

- Changed input type from int32_t raw SBUS to normalized floats
  - Thrust: 0.0-1.0, Roll/Pitch/Yaw: -1.0 to 1.0
- Implemented matrix-based motor mixing using factor coefficients
  - Single mixing algorithm works for all frame types
  - Easy to add new configurations (hex, octo, etc.)
- Added proper output normalization to handle saturation
  - Maintains control ratios when limits are exceeded
- Improved initialization: MIXER_Init() must be called before MIXER_AddMotor()
- Updated demos to use new float-based API with SBUS normalization
- Removed receiver value normalization from mixer (belongs in input layer)
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.

3 participants