mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-20 18:03:33 +08:00
More work on the mixer architecture.
Solve the multiple publishers issue with 'control groups', one group per controller. Mixer inputs now specify both group and control offset within the group. Avoid using %f when loading/saving mixers; use scaled integers instead.
This commit is contained in:
+90
-29
@@ -50,46 +50,54 @@
|
||||
#include "mixer.h"
|
||||
|
||||
static int
|
||||
scale_check(struct MixScaler *scale)
|
||||
scale_check(struct scaler_s *scale)
|
||||
{
|
||||
if (scale->offset > 1.0f)
|
||||
if (scale->offset > 1.1f)
|
||||
return 1;
|
||||
|
||||
if (scale->offset < -1.0f)
|
||||
if (scale->offset < -1.1f)
|
||||
return 2;
|
||||
|
||||
if (scale->lower_limit > scale->upper_limit)
|
||||
return 3;
|
||||
|
||||
if (scale->lower_limit < -1.0f)
|
||||
if (scale->lower_limit < -1.1f)
|
||||
return 4;
|
||||
|
||||
if (scale->upper_limit > 1.0f)
|
||||
if (scale->upper_limit > 1.1f)
|
||||
return 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mixer_check(struct MixMixer *mixer, unsigned control_count)
|
||||
mixer_check(struct mixer_s *mixer, unsigned group_count, unsigned control_count)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (mixer->control_count < 1)
|
||||
return -1;
|
||||
|
||||
if (mixer->control_count > control_count)
|
||||
/* sanity that presumes that a mixer includes a control no more than once */
|
||||
if (mixer->control_count > (group_count * control_count))
|
||||
return -2;
|
||||
|
||||
/* validate the output scaler */
|
||||
ret = scale_check(&mixer->output_scaler);
|
||||
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* validate input scalers */
|
||||
for (unsigned i = 0; i < mixer->control_count; i++) {
|
||||
if (mixer->control_scaler[i].control >= control_count)
|
||||
|
||||
/* range-check input controls */
|
||||
if (mixer->control_scaler[i].control_group >= group_count)
|
||||
return -3;
|
||||
|
||||
if (mixer->control_scaler[i].control_index >= control_count)
|
||||
return -3;
|
||||
|
||||
/* validate the scaler */
|
||||
ret = scale_check(&mixer->control_scaler[i]);
|
||||
|
||||
if (ret != 0)
|
||||
return (10 * i + ret);
|
||||
}
|
||||
@@ -97,8 +105,22 @@ mixer_check(struct MixMixer *mixer, unsigned control_count)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
mixer_requires(struct mixer_s *mixer, uint32_t *groups)
|
||||
{
|
||||
for (unsigned i = 0; i < mixer->control_count; i++)
|
||||
*groups |= 1 << mixer->control_scaler[i].control_group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a scaler to a value.
|
||||
*
|
||||
* @param scaler The applied scaler.
|
||||
* @param input The value to scale.
|
||||
* @output The scaled value.
|
||||
*/
|
||||
static float
|
||||
scale(struct MixScaler *scaler, float input)
|
||||
scale(struct scaler_s *scaler, float input)
|
||||
{
|
||||
float output;
|
||||
|
||||
@@ -120,19 +142,24 @@ scale(struct MixScaler *scaler, float input)
|
||||
}
|
||||
|
||||
float
|
||||
mixer_mix(struct MixMixer *mixer, float *controls)
|
||||
mixer_mix(struct mixer_s *mixer, float **controls)
|
||||
{
|
||||
struct MixScaler *scaler;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (unsigned i = 0; i < mixer->control_count; i++) {
|
||||
scaler = &mixer->control_scaler[i];
|
||||
sum += scale(scaler, controls[scaler->control]);
|
||||
|
||||
struct scaler_s *scaler = &mixer->control_scaler[i];
|
||||
float *cg = controls[scaler->control_group];
|
||||
|
||||
sum += scale(scaler, cg[scaler->control_index]);
|
||||
}
|
||||
|
||||
return scale(&mixer->output_scaler, sum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Effectively fdgets()
|
||||
*/
|
||||
static int
|
||||
mixer_getline(int fd, char *line, unsigned maxlen)
|
||||
{
|
||||
@@ -141,37 +168,52 @@ mixer_getline(int fd, char *line, unsigned maxlen)
|
||||
|
||||
while (--maxlen) {
|
||||
ret = read(fd, &c, 1);
|
||||
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
if (c == '\r')
|
||||
continue;
|
||||
|
||||
if (c == '\n') {
|
||||
*line = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
*line++ = c;
|
||||
}
|
||||
|
||||
/* line too long */
|
||||
puts("line too long");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
mixer_load_scaler(const char *buf, struct MixScaler *scaler)
|
||||
mixer_load_scaler(const char *buf, struct scaler_s *scaler)
|
||||
{
|
||||
if (sscanf(buf, "S: %u %f %f %f %f %f",
|
||||
&scaler->control, &scaler->negative_scale, &scaler->positive_scale,
|
||||
&scaler->offset, &scaler->lower_limit, &scaler->upper_limit) != 6)
|
||||
unsigned u[2];
|
||||
int s[5];
|
||||
|
||||
if (sscanf(buf, "S: %u %u %d %d %d %d %d",
|
||||
&u[0], &u[1], &s[0], &s[1], &s[2], &s[3], &s[4]) != 7)
|
||||
return -1;
|
||||
|
||||
scaler->control_group = u[0];
|
||||
scaler->control_index = u[1];
|
||||
scaler->negative_scale = s[0] / 10000.0f;
|
||||
scaler->positive_scale = s[1] / 10000.0f;
|
||||
scaler->offset = s[2] / 10000.0f;
|
||||
scaler->lower_limit = s[3] / 10000.0f;
|
||||
scaler->upper_limit = s[4] / 10000.0f;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mixer_load(int fd, struct MixMixer **mp)
|
||||
mixer_load(int fd, struct mixer_s **mp)
|
||||
{
|
||||
int ret, result = -1;
|
||||
struct MixMixer *mixer = NULL;
|
||||
struct mixer_s *mixer = NULL;
|
||||
char buf[100];
|
||||
unsigned scalers;
|
||||
|
||||
@@ -194,7 +236,7 @@ mixer_load(int fd, struct MixMixer **mp)
|
||||
|
||||
/* allocate mixer */
|
||||
scalers--;
|
||||
mixer = (struct MixMixer *)malloc(MIXER_SIZE(scalers));
|
||||
mixer = (struct mixer_s *)malloc(MIXER_SIZE(scalers));
|
||||
|
||||
if (mixer == NULL)
|
||||
goto out;
|
||||
@@ -211,40 +253,56 @@ mixer_load(int fd, struct MixMixer **mp)
|
||||
|
||||
for (unsigned i = 0; i < scalers; i++) {
|
||||
ret = mixer_getline(fd, buf, sizeof(buf));
|
||||
|
||||
if (ret < 1)
|
||||
goto out;
|
||||
|
||||
if (mixer_load_scaler(buf, &mixer->control_scaler[i]))
|
||||
goto out;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* we return NULL for the mixer, which is interpreted elsewhere as "no mixer" */
|
||||
}
|
||||
|
||||
result = 1;
|
||||
|
||||
out:
|
||||
|
||||
/* on error, discard allocated mixer */
|
||||
if ((result <= 0) && (mixer != NULL))
|
||||
free(mixer);
|
||||
|
||||
*mp = mixer;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
mixer_save_scaler(char *buf, struct MixScaler *scaler)
|
||||
mixer_save_scaler(char *buf, struct scaler_s *scaler)
|
||||
{
|
||||
return sprintf(buf, "S: %u %f %f %f %f %f\n",
|
||||
scaler->control, scaler->negative_scale, scaler->positive_scale,
|
||||
scaler->offset, scaler->lower_limit, scaler->upper_limit);
|
||||
int s[5];
|
||||
|
||||
s[0] = 10000.0f * scaler->negative_scale;
|
||||
s[1] = 10000.0f * scaler->positive_scale;
|
||||
s[2] = 10000.0f * scaler->offset;
|
||||
s[3] = 10000.0f * scaler->lower_limit;
|
||||
s[4] = 10000.0f * scaler->upper_limit;
|
||||
|
||||
return sprintf(buf, "S: %u %u %d %d %d %d %d\n",
|
||||
scaler->control_group, scaler->control_index,
|
||||
s[0], s[1], s[2], s[3], s[4]);
|
||||
}
|
||||
|
||||
int
|
||||
mixer_save(int fd, struct MixMixer *mixer)
|
||||
mixer_save(int fd, struct mixer_s *mixer)
|
||||
{
|
||||
char buf[100];
|
||||
int len, ret;
|
||||
|
||||
|
||||
/* write the mixer header */
|
||||
len = sprintf(buf, "M: %u\n", (mixer != NULL) ? mixer->control_count : 0);
|
||||
ret = write(fd, buf, len);
|
||||
|
||||
if (ret != len)
|
||||
return -1;
|
||||
|
||||
@@ -252,6 +310,7 @@ mixer_save(int fd, struct MixMixer *mixer)
|
||||
/* write the output scaler */
|
||||
len = mixer_save_scaler(buf, &mixer->output_scaler);
|
||||
write(fd, buf, len);
|
||||
|
||||
if (ret != len)
|
||||
return -1;
|
||||
|
||||
@@ -259,9 +318,11 @@ mixer_save(int fd, struct MixMixer *mixer)
|
||||
for (unsigned j = 0; j < mixer->control_count; j++) {
|
||||
len = mixer_save_scaler(buf, &mixer->control_scaler[j]);
|
||||
write(fd, buf, len);
|
||||
|
||||
if (ret != len)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+45
-20
@@ -36,7 +36,7 @@
|
||||
|
||||
/**
|
||||
* @file mixer.h
|
||||
*
|
||||
*
|
||||
* Generic control value mixing library.
|
||||
*
|
||||
* This library implements a generic mixer function that can be used
|
||||
@@ -46,10 +46,13 @@
|
||||
* Terminology
|
||||
* ===========
|
||||
*
|
||||
* control
|
||||
* 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.
|
||||
*
|
||||
@@ -124,49 +127,68 @@
|
||||
* 3 | primary thrust
|
||||
*/
|
||||
|
||||
struct MixScaler {
|
||||
unsigned control; /**< control consumed by this scaler */
|
||||
struct scaler_s {
|
||||
float negative_scale; /**< scale for inputs < 0 */
|
||||
float positive_scale; /**< scale for inputs > 0 */
|
||||
float offset; /**< bias applied to output */
|
||||
float lower_limit; /**< minimum output value */
|
||||
float upper_limit; /**< maximum output value */
|
||||
uint8_t control_group; /**< control group this scaler reads from */
|
||||
uint8_t control_index; /**< control index within the group */
|
||||
};
|
||||
|
||||
struct MixMixer {
|
||||
unsigned control_count; /**< number of control scalers */
|
||||
struct MixScaler output_scaler; /**< scaler applied to mixer output */
|
||||
struct MixScaler control_scaler[0]; /**< array of control scalers */
|
||||
struct mixer_s {
|
||||
unsigned control_count; /**< number of control scalers */
|
||||
struct scaler_s output_scaler; /**< scaler applied to mixer output */
|
||||
struct scaler_s control_scaler[0]; /**< array of control scalers */
|
||||
};
|
||||
|
||||
/**
|
||||
* Handy macro for determining the allocation size of a mixer.
|
||||
*/
|
||||
#define MIXER_SIZE(_num_scalers) (sizeof(struct MixMixer) + ((_num_scalers) * sizeof(struct MixScaler)))
|
||||
#define MIXER_SIZE(_num_scalers) (sizeof(struct mixer_s) + ((_num_scalers) * sizeof(struct scaler_s)))
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* Perform a mixer calculation.
|
||||
*
|
||||
* Note that the controls array is assumed to be sufficiently large for any control
|
||||
* index in the mixer.
|
||||
* Note that the controls array, and the arrays it indexes, are assumed
|
||||
* to be sufficiently large for any control index in the mixer.
|
||||
*
|
||||
* @param mixer Mixer configuration.
|
||||
* @param controls Array of input control values.
|
||||
* @param controls Array of pointers to control group values.
|
||||
* @return The mixed output.
|
||||
*/
|
||||
__EXPORT float mixer_mix(struct MixMixer *mixer, float *controls);
|
||||
__EXPORT float mixer_mix(struct mixer_s *mixer, float **controls);
|
||||
|
||||
/**
|
||||
* Check a mixer configuration for sanity.
|
||||
*
|
||||
* @param mixer The mixer configuration to be checked.
|
||||
* @param control_count The number of controls in the system.
|
||||
* @param group_count The highest-numbered control group that
|
||||
* should be considered legal.
|
||||
* @param control_count The highest control index that should be
|
||||
* considered legal.
|
||||
* @return Zero if the mixer configuration is sane,
|
||||
* nonzero otherwise.
|
||||
*/
|
||||
__EXPORT int mixer_check(struct MixMixer *mixer, unsigned control_count);
|
||||
__EXPORT int mixer_check(struct mixer_s *mixer, unsigned group_count, unsigned control_count);
|
||||
|
||||
/**
|
||||
* Evaluate the control inputs to a mixer and update the bitmask of
|
||||
* required control groups.
|
||||
*
|
||||
* This function allows an actuator driver to selectively fetch just
|
||||
* the control groups required to support a particular mixer or set of
|
||||
* mixers.
|
||||
*
|
||||
* @param mixer The mixer being evaluated.
|
||||
* @param groups Pointer to a bitmask to be updated with set bits
|
||||
* corresponding to the control groups used by the
|
||||
* mixer.
|
||||
*/
|
||||
__EXPORT void mixer_requires(struct mixer_s *mixer, uint32_t *groups);
|
||||
|
||||
/**
|
||||
* Read a mixer definition from a file.
|
||||
@@ -178,13 +200,16 @@ __EXPORT int mixer_check(struct MixMixer *mixer, unsigned control_count);
|
||||
* scalers.
|
||||
*
|
||||
* M: <scaler count>
|
||||
* S: <control> <negative_scale> <positive_scale> <offset> <lower_limit> <upper_limit>
|
||||
* S: <control group> <control index> <negative_scale*> <positive_scale*> <offset*> <lower_limit*> <upper_limit*>
|
||||
* S: ...
|
||||
*
|
||||
* The <control> value for the output scaler is ignored by the mixer.
|
||||
* The <control ...> 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.
|
||||
* 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
|
||||
@@ -194,7 +219,7 @@ __EXPORT int mixer_check(struct MixMixer *mixer, unsigned control_count);
|
||||
* @param mixer Mixer is returned here.
|
||||
* @return 1 if a mixer was read, zero on EOF or negative on error.
|
||||
*/
|
||||
__EXPORT int mixer_load(int fd, struct MixMixer **mixer);
|
||||
__EXPORT int mixer_load(int fd, struct mixer_s **mixer);
|
||||
|
||||
/**
|
||||
* Save a mixer definition to a file.
|
||||
@@ -203,7 +228,7 @@ __EXPORT int mixer_load(int fd, struct MixMixer **mixer);
|
||||
* @param mixer The mixer definition to save.
|
||||
* @return Zero on success, negative on error.
|
||||
*/
|
||||
__EXPORT int mixer_save(int fd, struct MixMixer *mixers);
|
||||
__EXPORT int mixer_save(int fd, struct mixer_s *mixers);
|
||||
|
||||
|
||||
__END_DECLS
|
||||
|
||||
Reference in New Issue
Block a user