45 #include <px4_platform_common/px4_config.h> 61 uint8_t control_group,
62 uint8_t control_index,
70 #define MIXER_DIFFERENCE_THRESHOLD 30 72 #define MIXER_DIFFERENCE_THRESHOLD 2 83 #if defined(CONFIG_ARCH_BOARD_PX4_SITL) 84 #define MIXER_PATH(_file) "etc/mixers/"#_file 85 #define MIXER_ONBOARD_PATH "etc/mixers" 87 #define MIXER_ONBOARD_PATH "/etc/mixers" 88 #define MIXER_PATH(_file) MIXER_ONBOARD_PATH"/"#_file 108 bool load_mixer(
const char *filename,
unsigned expected_count,
bool verbose =
false);
109 bool load_mixer(
const char *filename,
const char *buf,
unsigned loaded,
unsigned expected_count,
110 const unsigned chunk_size,
bool verbose);
162 PX4_ERR(
"File open failed");
166 struct dirent *result =
nullptr;
170 result = readdir(dp);
173 if (result ==
nullptr) {
175 PX4_ERR(
"readdir failed");
186 switch (result->d_type) {
193 if (strncmp(result->d_name,
".", 1) != 0) {
198 PX4_ERR(
"mixer path too long %s", result->d_name);
206 PX4_ERR(
"Error testing mixer %s", buf);
229 unsigned loaded = strlen(buf);
232 PX4_INFO(
"loaded: \n\"%s\"\n (file: %s, %d chars)", &buf[0], filename, loaded);
237 bool ret =
load_mixer(filename, buf, loaded, expected_count, chunk_size, verbose);
240 PX4_ERR(
"Mixer load failed with chunk size %u", chunk_size);
249 const unsigned chunk_size,
bool verbose)
257 unsigned xx = loaded;
261 if (expected_count > 0) {
265 unsigned empty_load = 2;
273 PX4_INFO(
"empty buffer load: loaded %u mixers, used: %u",
mixer_group.
count(), empty_load);
276 ut_compare(
"empty buffer load", empty_load, 0);
283 unsigned transmitted = 0;
286 while (transmitted < loaded) {
288 unsigned text_length = (loaded - transmitted > chunk_size) ? chunk_size : loaded - transmitted;
291 if ((mixer_text_length + text_length + 1) >
sizeof(
mixer_text)) {
292 PX4_ERR(
"Mixer text length overflow for file: %s. Is PX4IO_MAX_MIXER_LENGTH too small? (curr len: %d)", filename,
298 memcpy(&mixer_text[mixer_text_length], &buf[transmitted], text_length);
299 mixer_text_length += text_length;
308 if (resid != mixer_text_length) {
313 memmove(&mixer_text[0], &mixer_text[mixer_text_length - resid], resid);
315 mixer_text[resid] =
'\0';
318 mixer_text_length = resid;
321 transmitted += text_length;
324 PX4_INFO(
"transmitted: %d, loaded: %d", transmitted, loaded);
333 PX4_ERR(
"Load of mixer failed, last chunk: %s, transmitted: %u, text length: %u, resid: %u", mixer_text, transmitted,
334 mixer_text_length, resid);
353 int16_t reverse_pwm_mask = 0;
384 r_page_servo_control_max, outputs, r_page_servos, &output_limit);
388 for (
unsigned i = 0; i < mixed; i++) {
391 if (i != actuator_controls_s::INDEX_THROTTLE) {
392 if (r_page_servos[i] < r_page_servo_control_min[i]) {
393 PX4_ERR(
"active servo < min");
398 if (r_page_servos[i] != r_page_servo_disarmed[i]) {
399 PX4_ERR(
"throttle output != 0 (this check assumed the IO pass mixer!)");
414 unsigned sleep_quantum_us = 10000;
417 unsigned sleepcount = 0;
425 r_page_servo_control_max, outputs, r_page_servos, &output_limit);
428 for (
unsigned i = 0; i < mixed; i++) {
434 r_page_servos[i] != r_page_servo_disarmed[i]) {
435 PX4_ERR(
"disarmed servo value mismatch: %d vs %d", r_page_servos[i], r_page_servo_disarmed[i]);
440 r_page_servos[i] + 1 <= r_page_servo_disarmed[i]) {
441 PX4_ERR(
"ramp servo value mismatch");
446 px4_usleep(sleep_quantum_us);
449 if (sleepcount % 10 == 0) {
456 for (
int j = -jmax; j <= jmax; j++) {
469 r_page_servo_control_max, outputs, r_page_servos, &output_limit);
473 for (
unsigned i = 0; i < mixed; i++) {
474 servo_predicted[i] = 1500 + outputs[i] * (r_page_servo_control_max[i] - r_page_servo_control_min[i]) / 2.0
f;
477 fprintf(stderr,
"\t %d: %8.4f predicted: %d, servo: %d\n", i, (
double)outputs[i], servo_predicted[i],
478 (
int)r_page_servos[i]);
479 PX4_ERR(
"mixer violated predicted value");
497 r_page_servo_control_max, outputs, r_page_servos, &output_limit);
500 for (
unsigned i = 0; i < mixed; i++) {
505 if (r_page_servos[i] != r_page_servo_disarmed[i]) {
506 PX4_ERR(
"disarmed servo value mismatch");
511 px4_usleep(sleep_quantum_us);
514 if (sleepcount % 10 == 0) {
534 r_page_servo_control_max, outputs, r_page_servos, &output_limit);
537 for (
unsigned i = 0; i < mixed; i++) {
539 servo_predicted[i] = 1500 + outputs[i] * (r_page_servo_control_max[i] - r_page_servo_control_min[i]) / 2.0
f;
546 (r_page_servos[i] + 1 <= r_page_servo_disarmed[i] ||
547 r_page_servos[i] > servo_predicted[i])) {
548 PX4_ERR(
"ramp servo value mismatch");
554 abs(servo_predicted[i] - r_page_servos[i]) > 2) {
555 printf(
"\t %d: %8.4f predicted: %d, servo: %d\n", i, (
double)outputs[i], servo_predicted[i], (
int)r_page_servos[i]);
556 PX4_ERR(
"mixer violated predicted value");
561 px4_usleep(sleep_quantum_us);
564 if (sleepcount % 10 == 0) {
578 if (control_group != 0) {
588 if (
should_prearm && control_group == actuator_controls_s::GROUP_INDEX_ATTITUDE &&
589 control_index == actuator_controls_s::INDEX_THROTTLE) {
#define PWM_DEFAULT_MAX
Default maximum PWM in us.
int load_from_buf(Mixer::ControlCallback control_cb, uintptr_t cb_handle, const char *buf, unsigned &buflen)
Adds mixers to the group based on a text description in a buffer.
bool load_mixer(const char *filename, unsigned expected_count, bool verbose=false)
static unsigned mixer_text_length
void reset()
Remove all the mixers from the group.
void output_limit_calc(const bool armed, const bool pre_armed, const unsigned num_channels, const uint16_t reverse_mask, const uint16_t *disarmed_output, const uint16_t *min_output, const uint16_t *max_output, const float *output, uint16_t *effective_output, output_limit_t *limit)
int test_mixer(int argc, char *argv[])
static char mixer_text[PX4IO_MAX_MIXER_LENGTH]
static volatile bool should_arm
unsigned count() const
Count the mixers in the group.
Base class to be used for unit tests.
ut_declare_test_c(test_mixer, MixerTest) bool MixerTest
PX4IO interface protocol.
High-resolution timer with callouts and timekeeping.
static int mixer_callback(uintptr_t handle, uint8_t control_group, uint8_t control_index, float &control)
int _tests_failed
The number of unit tests which failed.
uint16_t r_page_servo_control_max[]
PAGE 107.
#define MIXER_DIFFERENCE_THRESHOLD
static bool should_prearm
#define MIXER_PATH(_file)
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
static hrt_abstime hrt_elapsed_time(const hrt_abstime *then)
Compute the delta between a timestamp taken in the past and now.
virtual bool run_tests()
Override to run your unit tests.
uint16_t r_page_servo_disarmed[]
PAGE 109.
int load_mixer_file(const char *fname, char *buf, unsigned maxlen)
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
#define PX4IO_MAX_TRANSFER_LEN
#define PX4IO_MAX_MIXER_LENGTH
uint16_t r_page_servo_control_min[]
PAGE 106.
#define MIXER_ONBOARD_PATH
static const unsigned output_max
uint16_t r_page_servos[]
PAGE 3.
void output_limit_init(output_limit_t *limit)
#define ut_compare(message, v1, v2)
Used to compare two integer values within a unit test.
static float actuator_controls[output_max]
unsigned mix(float *outputs, unsigned space)
#define PWM_MOTOR_OFF
Default value for a shutdown motor.
#define ut_run_test(test)
Runs a single unit test.
Group of mixers, built up from single mixers and processed in order when mixing.
Dual< Scalar, N > abs(const Dual< Scalar, N > &a)
#define PWM_DEFAULT_MIN
Default minimum PWM in us.
Library for output limiting (PWM for example)
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
#define PWM_LOWEST_MIN
Lowest minimum PWM in us.