PX4 Firmware
PX4 Autopilot Software http://px4.io
MultirotorMixer.hpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (C) 2012-2019 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 #pragma once
35 
36 #include <mixer/Mixer/Mixer.hpp>
37 
38 /**
39  * Supported multirotor geometries.
40  *
41  * Values are generated by the px_generate_mixers.py script and placed to mixer_multirotor_normalized.generated.h
42  */
44 enum class MultirotorGeometry : MultirotorGeometryUnderlyingType;
45 
46 /**
47  * Multi-rotor mixer for pre-defined vehicle geometries.
48  *
49  * Collects four inputs (roll, pitch, yaw, thrust) and mixes them to
50  * a set of outputs based on the configured geometry.
51  */
52 class MultirotorMixer : public Mixer
53 {
54 public:
55  /**
56 
57  * Precalculated rotor mix.
58  */
59  struct Rotor {
60  float roll_scale; /**< scales roll for this rotor */
61  float pitch_scale; /**< scales pitch for this rotor */
62  float yaw_scale; /**< scales yaw for this rotor */
63  float thrust_scale; /**< scales thrust for this rotor */
64  };
65 
66  /**
67  * Constructor.
68  *
69  * @param control_cb Callback invoked to read inputs.
70  * @param cb_handle Passed to control_cb.
71  * @param geometry The selected geometry.
72  * @param roll_scale Scaling factor applied to roll inputs
73  * compared to thrust.
74  * @param pitch_scale Scaling factor applied to pitch inputs
75  * compared to thrust.
76  * @param yaw_wcale Scaling factor applied to yaw inputs compared
77  * to thrust.
78  * @param idle_speed Minimum rotor control output value; usually
79  * tuned to ensure that rotors never stall at the
80  * low end of their control range.
81  */
82  MultirotorMixer(ControlCallback control_cb, uintptr_t cb_handle, MultirotorGeometry geometry,
83  float roll_scale, float pitch_scale, float yaw_scale, float idle_speed);
84 
85  /**
86  * Constructor (for testing).
87  *
88  * @param control_cb Callback invoked to read inputs.
89  * @param cb_handle Passed to control_cb.
90  * @param rotors control allocation matrix
91  * @param rotor_count length of rotors array (= number of motors)
92  */
93  MultirotorMixer(ControlCallback control_cb, uintptr_t cb_handle, const Rotor *rotors, unsigned rotor_count);
94  virtual ~MultirotorMixer();
95 
96  // no copy, assignment, move, move assignment
97  MultirotorMixer(const MultirotorMixer &) = delete;
98  MultirotorMixer &operator=(const MultirotorMixer &) = delete;
99  MultirotorMixer(MultirotorMixer &&) = delete;
100  MultirotorMixer &operator=(MultirotorMixer &&) = delete;
101 
102  /**
103  * Factory method.
104  *
105  * Given a pointer to a buffer containing a text description of the mixer,
106  * returns a pointer to a new instance of the mixer.
107  *
108  * @param control_cb The callback to invoke when fetching a
109  * control value.
110  * @param cb_handle Handle passed to the control callback.
111  * @param buf Buffer containing a text description of
112  * the mixer.
113  * @param buflen Length of the buffer in bytes, adjusted
114  * to reflect the bytes consumed.
115  * @return A new MultirotorMixer instance, or nullptr
116  * if the text format is bad.
117  */
118  static MultirotorMixer *from_text(Mixer::ControlCallback control_cb, uintptr_t cb_handle, const char *buf,
119  unsigned &buflen);
120 
121  unsigned mix(float *outputs, unsigned space) override;
122 
123  uint16_t get_saturation_status() override { return _saturation_status.value; }
124 
125  void groups_required(uint32_t &groups) override { groups |= (1 << 0); }
126 
127  /**
128  * @brief Update slew rate parameter. This tells the multicopter mixer
129  * the maximum allowed change of the output values per cycle.
130  * The value is only valid for one cycle, in order to have continuous
131  * slew rate limiting this function needs to be called before every call
132  * to mix().
133  *
134  * @param[in] delta_out_max Maximum delta output.
135  *
136  */
137  void set_max_delta_out_once(float delta_out_max) override { _delta_out_max = delta_out_max; }
138 
139  unsigned set_trim(float trim) override { return _rotor_count; }
140  unsigned get_trim(float *trim) override { return _rotor_count; }
141 
142  /**
143  * @brief Sets the thrust factor used to calculate mapping from desired thrust to motor control signal output.
144  *
145  * @param[in] val The value
146  */
147  void set_thrust_factor(float val) override { _thrust_factor = math::constrain(val, 0.0f, 1.0f); }
148 
149  void set_airmode(Airmode airmode) override { _airmode = airmode; }
150 
151  unsigned get_multirotor_count() override { return _rotor_count; }
152 
154  struct {
155  uint16_t valid : 1; // 0 - true when the saturation status is used
156  uint16_t motor_pos : 1; // 1 - true when any motor has saturated in the positive direction
157  uint16_t motor_neg : 1; // 2 - true when any motor has saturated in the negative direction
158  uint16_t roll_pos : 1; // 3 - true when a positive roll demand change will increase saturation
159  uint16_t roll_neg : 1; // 4 - true when a negative roll demand change will increase saturation
160  uint16_t pitch_pos : 1; // 5 - true when a positive pitch demand change will increase saturation
161  uint16_t pitch_neg : 1; // 6 - true when a negative pitch demand change will increase saturation
162  uint16_t yaw_pos : 1; // 7 - true when a positive yaw demand change will increase saturation
163  uint16_t yaw_neg : 1; // 8 - true when a negative yaw demand change will increase saturation
164  uint16_t thrust_pos : 1; // 9 - true when a positive thrust demand change will increase saturation
165  uint16_t thrust_neg : 1; //10 - true when a negative thrust demand change will increase saturation
166  } flags;
167  uint16_t value;
168  };
169 
170 private:
171  /**
172  * Computes the gain k by which desaturation_vector has to be multiplied
173  * in order to unsaturate the output that has the greatest saturation.
174  * @see also minimize_saturation().
175  *
176  * @return desaturation gain
177  */
178  float compute_desaturation_gain(const float *desaturation_vector, const float *outputs, saturation_status &sat_status,
179  float min_output, float max_output) const;
180 
181  /**
182  * Minimize the saturation of the actuators by adding or substracting a fraction of desaturation_vector.
183  * desaturation_vector is the vector that added to the output outputs, modifies the thrust or angular
184  * acceleration on a specific axis.
185  * For example, if desaturation_vector is given to slide along the vertical thrust axis (thrust_scale), the
186  * saturation will be minimized by shifting the vertical thrust setpoint, without changing the
187  * roll/pitch/yaw accelerations.
188  *
189  * Note that as we only slide along the given axis, in extreme cases outputs can still contain values
190  * outside of [min_output, max_output].
191  *
192  * @param desaturation_vector vector that is added to the outputs, e.g. thrust_scale
193  * @param outputs output vector that is modified
194  * @param sat_status saturation status output
195  * @param min_output minimum desired value in outputs
196  * @param max_output maximum desired value in outputs
197  * @param reduce_only if true, only allow to reduce (substract) a fraction of desaturation_vector
198  */
199  void minimize_saturation(const float *desaturation_vector, float *outputs, saturation_status &sat_status,
200  float min_output = 0.f, float max_output = 1.f, bool reduce_only = false) const;
201 
202  /**
203  * Mix roll, pitch, yaw, thrust and set the outputs vector.
204  *
205  * Desaturation behavior: airmode for roll/pitch:
206  * thrust is increased/decreased as much as required to meet the demanded roll/pitch.
207  * Yaw is not allowed to increase the thrust, @see mix_yaw() for the exact behavior.
208  */
209  inline void mix_airmode_rp(float roll, float pitch, float yaw, float thrust, float *outputs);
210 
211  /**
212  * Mix roll, pitch, yaw, thrust and set the outputs vector.
213  *
214  * Desaturation behavior: full airmode for roll/pitch/yaw:
215  * thrust is increased/decreased as much as required to meet demanded the roll/pitch/yaw,
216  * while giving priority to roll and pitch over yaw.
217  */
218  inline void mix_airmode_rpy(float roll, float pitch, float yaw, float thrust, float *outputs);
219 
220  /**
221  * Mix roll, pitch, yaw, thrust and set the outputs vector.
222  *
223  * Desaturation behavior: no airmode, thrust is NEVER increased to meet the demanded
224  * roll/pitch/yaw. Instead roll/pitch/yaw is reduced as much as needed.
225  * Thrust can be reduced to unsaturate the upper side.
226  * @see mix_yaw() for the exact yaw behavior.
227  */
228  inline void mix_airmode_disabled(float roll, float pitch, float yaw, float thrust, float *outputs);
229 
230  /**
231  * Mix yaw by updating an existing output vector (that already contains roll/pitch/thrust).
232  *
233  * Desaturation behavior: thrust is allowed to be decreased up to 15% in order to allow
234  * some yaw control on the upper end. On the lower end thrust will never be increased,
235  * but yaw is decreased as much as required.
236  *
237  * @param yaw demanded yaw
238  * @param outputs output vector that is updated
239  */
240  inline void mix_yaw(float yaw, float *outputs);
241 
242  void update_saturation_status(unsigned index, bool clipping_high, bool clipping_low_roll_pitch, bool clipping_low_yaw);
243 
244  float _roll_scale{1.0f};
245  float _pitch_scale{1.0f};
246  float _yaw_scale{1.0f};
247  float _idle_speed{0.0f};
248  float _delta_out_max{0.0f};
249  float _thrust_factor{0.0f};
250 
251  Airmode _airmode{Airmode::disabled};
252 
253  saturation_status _saturation_status{};
254 
255  unsigned _rotor_count;
256  const Rotor *_rotors;
257 
258  float *_outputs_prev{nullptr};
259  float *_tmp_array{nullptr};
260 };
const Rotor * _rotors
constexpr _Tp constrain(_Tp val, _Tp min_val, _Tp max_val)
Definition: Limits.hpp:66
float thrust_scale
scales thrust for this rotor
void set_thrust_factor(float val) override
Sets the thrust factor used to calculate mapping from desired thrust to motor control signal output...
Generic, programmable, procedural control signal mixers.
uint8_t MultirotorGeometryUnderlyingType
Supported multirotor geometries.
uint16_t get_saturation_status() override
Get the saturation status.
int(* ControlCallback)(uintptr_t handle, uint8_t control_group, uint8_t control_index, float &control)
Fetch a control value.
Definition: Mixer.hpp:154
void set_max_delta_out_once(float delta_out_max) override
Update slew rate parameter.
void set_airmode(Airmode airmode) override
Set airmode.
Precalculated rotor mix.
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
Airmode
Definition: Mixer.hpp:139
unsigned get_multirotor_count() override
float pitch_scale
scales pitch for this rotor
float roll_scale
scales roll for this rotor
void groups_required(uint32_t &groups) override
Analyses the mix configuration and updates a bitmask of groups that are required. ...
unsigned get_trim(float *trim) override
Get trim offset for this mixer.
Multi-rotor mixer for pre-defined vehicle geometries.
unsigned set_trim(float trim) override
Set trim offset for this mixer.
float yaw_scale
scales yaw for this rotor
Abstract class defining a mixer mixing zero or more inputs to one or more outputs.
Definition: Mixer.hpp:136