PX4 Firmware
PX4 Autopilot Software http://px4.io
test_mixer_multirotor.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2018 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 /**
35  * testing binary that runs the multirotor mixer through test cases given
36  * via file or stdin and compares the mixer output against expected values.
37  */
38 
39 #include "MultirotorMixer.hpp"
40 
41 #include <cstdio>
42 #include <math.h>
43 
44 static const unsigned output_max = 16;
45 static float actuator_controls[output_max] {};
46 
47 static int mixer_callback(uintptr_t handle,
48  uint8_t control_group,
49  uint8_t control_index,
50  float &control);
51 
52 static int
53 mixer_callback(uintptr_t handle, uint8_t control_group, uint8_t control_index, float &control)
54 {
55  control = actuator_controls[control_index];
56  return 0;
57 }
58 
59 int main(int argc, char *argv[])
60 {
61  FILE *file_in = stdin;
62 
63  if (argc > 1) {
64  file_in = fopen(argv[1], "r");
65  }
66 
67  unsigned rotor_count = 0;
69  float actuator_outputs[output_max];
70 
71  // read airmode
72  int airmode;
73  fscanf(file_in, "%i", &airmode);
74 
75  // read the motor count & control allocation matrix
76  fscanf(file_in, "%i", &rotor_count);
77 
78  if (rotor_count > output_max) {
79  return -1;
80  }
81 
82  for (unsigned i = 0; i < rotor_count; ++i) {
83  fscanf(file_in, "%f %f %f %f", &rotors[i].roll_scale, &rotors[i].pitch_scale,
84  &rotors[i].yaw_scale, &rotors[i].thrust_scale);
85  }
86 
87  MultirotorMixer mixer(mixer_callback, 0, rotors, rotor_count);
88  mixer.set_airmode((Mixer::Airmode)airmode);
89 
90  int test_counter = 0;
91  int num_failed = 0;
92 
93  while (!feof(file_in)) {
94 
95  // read actuator controls
96  unsigned count = 0;
97 
98  while (count < 4 && fscanf(file_in, "%f", &actuator_controls[count]) == 1) {
99  ++count;
100  }
101 
102  if (count < 4) {
103  break;
104  }
105 
106  // do the mixing
107  if (mixer.mix(actuator_outputs, output_max) != rotor_count) {
108  return -1;
109  }
110 
111  // read expected outputs
112  count = 0;
113  float expected_output[output_max];
114  bool failed = false;
115 
116  while (count < rotor_count && fscanf(file_in, "%f", &expected_output[count]) == 1) {
117  if (fabsf(expected_output[count] - actuator_outputs[count]) > 0.00001f) {
118  failed = true;
119  }
120 
121  ++count;
122  }
123 
124  if (count < rotor_count) {
125  break;
126  }
127 
128  if (failed) {
129  printf("test %i failed:\n", test_counter + 1);
130  printf("control input : %.3f %.3f %.3f %.3f\n", (double)actuator_controls[0], (double)actuator_controls[1],
131  (double)actuator_controls[2], (double)actuator_controls[3]);
132  printf("mixer output : ");
133 
134  for (unsigned i = 0; i < rotor_count; ++i) {
135  printf("%.3f ", (double)actuator_outputs[i]);
136  }
137 
138  printf("\n");
139  printf("expected output: ");
140 
141  for (unsigned i = 0; i < rotor_count; ++i) {
142  printf("%.3f ", (double)expected_output[i]);
143  }
144 
145  printf("\n");
146  printf("diff : ");
147 
148  for (unsigned i = 0; i < rotor_count; ++i) {
149  printf("%.3f ", (double)(expected_output[i] - actuator_outputs[i]));
150  }
151 
152  printf("\n");
153  ++num_failed;
154  }
155 
156  ++test_counter;
157  }
158 
159  printf("tested %i cases: %i success, %i failed\n", test_counter,
160  test_counter - num_failed, num_failed);
161 
162 
163  if (file_in != stdin) {
164  fclose(file_in);
165  }
166 
167  return num_failed > 0 ? -1 : 0;
168 }
static const unsigned output_max
testing binary that runs the multirotor mixer through test cases given via file or stdin and compares...
static int mixer_callback(uintptr_t handle, uint8_t control_group, uint8_t control_index, float &control)
static MultirotorMixer * mixer
mixer initialization
void set_airmode(Airmode airmode) override
Set airmode.
Precalculated rotor mix.
Airmode
Definition: Mixer.hpp:139
unsigned mix(float *outputs, unsigned space) override
Perform the mixing function.
static float actuator_controls[output_max]
Multi-rotor mixer for pre-defined vehicle geometries.
int main(int argc, char *argv[])