/**************************************************************************** * * Copyright (C) 2012 PX4 Development Team. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name PX4 nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /** * @file mixer.h * * Generic, programmable, procedural control signal mixers. * * This library implements a generic mixer interface that can be used * by any driver or subsytem that wants to combine several control signals * into a single output. * * Terminology * =========== * * control value * A mixer input value, typically provided by some controlling * component of the system. * * control group * A collection of controls provided by a single controlling component. * * actuator * The mixer output value. * * * Mixing basics * ============= * * An actuator derives its value from the combination of one or more * control values. Each of the control values is scaled according to * the actuator's configuration and then combined to produce the * actuator value, which may then be further scaled to suit the specific * output type. * * Internally, all scaling is performed using floating point values. * Inputs and outputs are clamped to the range -1.0 to 1.0. * * control control control * | | | * v v v * scale scale scale * | | | * | v | * +-------> mix <------+ * | * scale * | * v * out * * Scaling * ------- * * Each scaler allows the input value to be scaled independently for * inputs greater/less than zero. An offset can be applied to the output, * as well as lower and upper boundary constraints. * Negative scaling factors cause the output to be inverted (negative input * produces positive output). * * Scaler pseudocode: * * if (input < 0) * output = (input * NEGATIVE_SCALE) + OFFSET * else * output = (input * POSITIVE_SCALE) + OFFSET * * if (output < LOWER_LIMIT) * output = LOWER_LIMIT * if (output > UPPER_LIMIT) * output = UPPER_LIMIT * * * Mixing * ------ * * Mixing behaviour varies based on the specific mixer class; each * mixer class describes its behaviour in more detail. * * * Controls * -------- * * The precise assignment of controls may vary depending on the * application, but the following assignments should be used * when appropriate. Some mixer classes have specific assumptions * about the assignment of controls. * * control | standard meaning * --------+----------------------- * 0 | roll * 1 | pitch * 2 | yaw * 3 | primary thrust */ #ifndef _SYSTEMLIB_MIXER_MIXER_H #define _SYSTEMLIB_MIXER_MIXER_H value #include "drivers/drv_mixer.h" /** * Abstract class defining a mixer mixing zero or more inputs to * one or more outputs. */ class __EXPORT Mixer { public: /** next mixer in a list */ Mixer *_next; /** * Fetch a control value. * * @param handle Token passed when the callback is registered. * @param control_group The group to fetch the control from. * @param control_index The group-relative index to fetch the control from. * @param control The returned control * @return Zero if the value was fetched, nonzero otherwise. */ typedef int (* ControlCallback)(uintptr_t handle, uint8_t control_group, uint8_t control_index, float &control); /** * Constructor. * * @param control_cb Callback invoked when reading controls. */ Mixer(ControlCallback control_cb, uintptr_t cb_handle); ~Mixer() {}; /** * Perform the mixing function. * * @param outputs Array into which mixed output(s) should be placed. * @param space The number of available entries in the output array; * @return The number of entries in the output array that were populated. */ virtual unsigned mix(float *outputs, unsigned space) = 0; /** * Analyses the mix configuration and updates a bitmask of groups * that are required. * * @param groups A bitmask of groups (0-31) that the mixer requires. */ virtual void groups_required(uint32_t &groups) = 0; protected: /** client-supplied callback used when fetching control values */ ControlCallback _control_cb; uintptr_t _cb_handle; /** * Perform simpler linear scaling. * * @param scaler The scaler configuration. * @param input The value to be scaled. * @return The scaled value. */ static float scale(const mixer_scaler_s &scaler, float input); /** * Validate a scaler * * @param scaler The scaler to be validated. * @return Zero if good, nonzero otherwise. */ static int scale_check(struct mixer_scaler_s &scaler); private: }; /** * Group of mixers, built up from single mixers and processed * in order when mixing. */ class __EXPORT MixerGroup : public Mixer { public: MixerGroup(ControlCallback control_cb, uintptr_t cb_handle); ~MixerGroup(); virtual unsigned mix(float *outputs, unsigned space); virtual void groups_required(uint32_t &groups); /** * Add a mixer to the group. * * @param mixer The mixer to be added. */ void add_mixer(Mixer *mixer); /** * Reads a mixer definition from a file and configures a corresponding * group. * * The mixer group must be empty when this function is called. * * A mixer definition is a text representation of the configuration of a * mixer. Definition lines begin with a capital letter followed by a colon. * * Null Mixer: * * Z: * * This mixer generates a constant zero output, and is normally used to * skip over outputs that are not in use. * * Simple Mixer: * * M: * S: * S: ... * * The definition consists of a single-line header indicating the * number of scalers and then one line defining each scaler. The first * scaler in the file is always the output scaler, followed by the input * scalers. * * The values for the output scaler are ignored by the mixer. * * * * Values marked * are integers representing floating point values; values are * scaled by 10000 on load/save. * * Multiple mixer definitions may be stored in a single file; it is assumed that * the reader will know how many to expect and read accordingly. * * A mixer entry with a scaler count of zero indicates a disabled mixer. This * will return NULL for the mixer when processed by this function, and will be * generated by passing NULL as the mixer to mixer_save. * * @param path The mixer configuration file to read. * @return Zero on successful load, nonzero otherwise. */ int load_from_file(const char *path); private: Mixer *_first; /**< linked list of mixers */ }; /** * Null mixer; returns zero. * * Used as a placeholder for output channels that are unassigned in groups. */ class __EXPORT NullMixer : public Mixer { public: NullMixer(); ~NullMixer() {}; virtual unsigned mix(float *outputs, unsigned space); virtual void groups_required(uint32_t &groups); }; /** * Simple summing mixer. * * Collects zero or more inputs and mixes them to a single output. */ class __EXPORT SimpleMixer : public Mixer { public: /** * Constructor * * @param mixinfo Mixer configuration. The pointer passed * becomes the property of the mixer and * will be freed when the mixer is deleted. */ SimpleMixer(ControlCallback control_cb, uintptr_t cb_handle, mixer_simple_s *mixinfo); ~SimpleMixer(); virtual unsigned mix(float *outputs, unsigned space); virtual void groups_required(uint32_t &groups); /** * Check that the mixer configuration as loaded is sensible. * * Note that this function will call control_cb, but only cares about * error returns, not the input value. * * @return Zero if the mixer makes sense, nonzero otherwise. */ int check(); protected: private: mixer_simple_s *_info; }; /** * Multi-rotor mixer. * * Collects four inputs (roll, pitch, yaw, thrust) and mixes them to * a set of outputs based on the configured geometry. */ class __EXPORT MultirotorMixer : public Mixer { public: enum Geometry { MULTIROTOR_QUAD_PLUS, MULTIROTOR_QUAD_X /* XXX add more here */ }; MultirotorMixer(ControlCallback control_cb, uintptr_t cb_handle, Geometry geom); ~MultirotorMixer(); virtual unsigned mix(float *outputs, unsigned space); virtual void groups_required(uint32_t &groups); private: Geometry _geometry; }; #endif