PX4 Firmware
PX4 Autopilot Software http://px4.io
vtol_att_control_main.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2013-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 /**
35  * @file VTOL_att_control_main.cpp
36  * Implementation of an attitude controller for VTOL airframes. This module receives data
37  * from both the fixed wing- and the multicopter attitude controllers and processes it.
38  * It computes the correct actuator controls depending on which mode the vehicle is in (hover,forward-
39  * flight or transition). It also publishes the resulting controls on the actuator controls topics.
40  *
41  * @author Roman Bapst <bapstr@ethz.ch>
42  * @author Lorenz Meier <lm@inf.ethz.ch>
43  * @author Thomas Gubler <thomasgubler@gmail.com>
44  * @author David Vorsin <davidvorsin@gmail.com>
45  * @author Sander Smeets <sander@droneslab.com>
46  * @author Andreas Antener <andreas@uaventure.com>
47  *
48  */
49 #include "vtol_att_control_main.h"
50 #include <systemlib/mavlink_log.h>
52 
53 using namespace matrix;
54 
56  WorkItem(MODULE_NAME, px4::wq_configurations::rate_ctrl),
57  _loop_perf(perf_alloc(PC_ELAPSED, "vtol_att_control: cycle"))
58 {
59  _vtol_vehicle_status.vtol_in_rw_mode = true; /* start vtol in rotary wing mode*/
60 
63 
64  _params_handles.idle_pwm_mc = param_find("VT_IDLE_PWM_MC");
65  _params_handles.vtol_motor_id = param_find("VT_MOT_ID");
66  _params_handles.vtol_fw_permanent_stab = param_find("VT_FW_PERM_STAB");
67  _params_handles.vtol_type = param_find("VT_TYPE");
68  _params_handles.elevons_mc_lock = param_find("VT_ELEV_MC_LOCK");
69  _params_handles.fw_min_alt = param_find("VT_FW_MIN_ALT");
70  _params_handles.fw_alt_err = param_find("VT_FW_ALT_ERR");
71  _params_handles.fw_qc_max_pitch = param_find("VT_FW_QC_P");
72  _params_handles.fw_qc_max_roll = param_find("VT_FW_QC_R");
73  _params_handles.front_trans_time_openloop = param_find("VT_F_TR_OL_TM");
74  _params_handles.front_trans_time_min = param_find("VT_TRANS_MIN_TM");
75 
76  _params_handles.front_trans_duration = param_find("VT_F_TRANS_DUR");
77  _params_handles.back_trans_duration = param_find("VT_B_TRANS_DUR");
78  _params_handles.transition_airspeed = param_find("VT_ARSP_TRANS");
79  _params_handles.front_trans_throttle = param_find("VT_F_TRANS_THR");
80  _params_handles.back_trans_throttle = param_find("VT_B_TRANS_THR");
81  _params_handles.airspeed_blend = param_find("VT_ARSP_BLEND");
82  _params_handles.airspeed_mode = param_find("FW_ARSP_MODE");
83  _params_handles.front_trans_timeout = param_find("VT_TRANS_TIMEOUT");
84  _params_handles.mpc_xy_cruise = param_find("MPC_XY_CRUISE");
85  _params_handles.fw_motors_off = param_find("VT_FW_MOT_OFFID");
86  _params_handles.diff_thrust = param_find("VT_FW_DIFTHR_EN");
87  _params_handles.diff_thrust_scale = param_find("VT_FW_DIFTHR_SC");
88 
89  /* fetch initial parameter values */
91 
92  if (static_cast<vtol_type>(_params.vtol_type) == vtol_type::TAILSITTER) {
93  _vtol_type = new Tailsitter(this);
94 
95  } else if (static_cast<vtol_type>(_params.vtol_type) == vtol_type::TILTROTOR) {
96  _vtol_type = new Tiltrotor(this);
97 
98  } else if (static_cast<vtol_type>(_params.vtol_type) == vtol_type::STANDARD) {
99  _vtol_type = new Standard(this);
100 
101  } else {
102  exit_and_cleanup();
103  }
104 }
105 
107 {
109 }
110 
111 bool
113 {
115  PX4_ERR("MC actuator controls callback registration failed!");
116  return false;
117  }
118 
120  PX4_ERR("FW actuator controls callback registration failed!");
121  return false;
122  }
123 
124  return true;
125 }
126 
127 /**
128 * Check for command updates.
129 */
130 void
132 {
133  if (_vehicle_cmd_sub.updated()) {
135  handle_command();
136  }
137 }
138 
139 /**
140 * Check received command
141 */
142 void
144 {
145  // update transition command if necessary
146  if (_vehicle_cmd.command == vehicle_command_s::VEHICLE_CMD_DO_VTOL_TRANSITION) {
148 
149  // Report that we have received the command no matter what we actually do with it.
150  // This might not be optimal but is better than no response at all.
151 
153  vehicle_command_ack_s command_ack{};
154  command_ack.timestamp = hrt_absolute_time();
155  command_ack.command = _vehicle_cmd.command;
156  command_ack.result = (uint8_t)vehicle_command_ack_s::VEHICLE_RESULT_ACCEPTED;
157  command_ack.target_system = _vehicle_cmd.source_system;
158  command_ack.target_component = _vehicle_cmd.source_component;
159 
160  uORB::PublicationQueued<vehicle_command_ack_s> command_ack_pub{ORB_ID(vehicle_command_ack)};
161  command_ack_pub.publish(command_ack);
162  }
163  }
164 }
165 
166 /*
167  * Returns true if fixed-wing mode is requested.
168  * Changed either via switch or via command.
169  */
170 bool
172 {
173  bool to_fw = false;
174 
175  if (_manual_control_sp.transition_switch != manual_control_setpoint_s::SWITCH_POS_NONE &&
177  to_fw = (_manual_control_sp.transition_switch == manual_control_setpoint_s::SWITCH_POS_ON);
178 
179  } else {
180  // listen to transition commands if not in manual or mode switch is not mapped
181  to_fw = (_transition_command == vtol_vehicle_status_s::VEHICLE_VTOL_STATE_FW);
182  }
183 
184  // handle abort request
186  if (to_fw) {
187  to_fw = false;
188 
189  } else {
190  // the state changed to mc mode, reset the abort request
191  _abort_front_transition = false;
193  }
194  }
195 
196  return to_fw;
197 }
198 
199 void
201 {
203  mavlink_log_critical(&_mavlink_log_pub, "Abort: %s", reason);
206  }
207 }
208 
209 int
211 {
212  float v;
213  int32_t l;
214  /* idle pwm for mc mode */
216 
217  /* vtol motor count */
219 
220  /* vtol fw permanent stabilization */
221  param_get(_params_handles.vtol_fw_permanent_stab, &l);
223 
224  param_get(_params_handles.vtol_type, &l);
225  _params.vtol_type = l;
226 
227  /* vtol lock elevons in multicopter */
228  param_get(_params_handles.elevons_mc_lock, &l);
229  _params.elevons_mc_lock = (l == 1);
230 
231  /* minimum relative altitude for FW mode (QuadChute) */
232  param_get(_params_handles.fw_min_alt, &v);
233  _params.fw_min_alt = v;
234 
235  /* maximum negative altitude error for FW mode (Adaptive QuadChute) */
236  param_get(_params_handles.fw_alt_err, &v);
237  _params.fw_alt_err = v;
238 
239  /* maximum pitch angle (QuadChute) */
240  param_get(_params_handles.fw_qc_max_pitch, &l);
242 
243  /* maximum roll angle (QuadChute) */
244  param_get(_params_handles.fw_qc_max_roll, &l);
246 
247  param_get(_params_handles.front_trans_time_openloop, &_params.front_trans_time_openloop);
248 
249  param_get(_params_handles.front_trans_time_min, &_params.front_trans_time_min);
250 
251  /*
252  * Minimum transition time can be maximum 90 percent of the open loop transition time,
253  * anything else makes no sense and can potentially lead to numerical problems.
254  */
257 
258 
259  param_get(_params_handles.front_trans_duration, &_params.front_trans_duration);
260  param_get(_params_handles.back_trans_duration, &_params.back_trans_duration);
261  param_get(_params_handles.transition_airspeed, &_params.transition_airspeed);
262  param_get(_params_handles.front_trans_throttle, &_params.front_trans_throttle);
263  param_get(_params_handles.back_trans_throttle, &_params.back_trans_throttle);
265  param_get(_params_handles.airspeed_mode, &l);
266  _params.airspeed_disabled = l != 0;
267  param_get(_params_handles.front_trans_timeout, &_params.front_trans_timeout);
271 
272  param_get(_params_handles.diff_thrust_scale, &v);
274 
275  // make sure parameters are feasible, require at least 1 m/s difference between transition and blend airspeed
277 
278  // update the parameters of the instances of base VtolType
279  if (_vtol_type != nullptr) {
281  }
282 
283  return OK;
284 }
285 
286 void
288 {
289  if (should_exit()) {
292  exit_and_cleanup();
293  return;
294  }
295 
296  if (!_initialized) {
297  parameters_update(); // initialize parameter cache
298 
299  if (_vtol_type->init()) {
300  _initialized = true;
301 
302  } else {
303  exit_and_cleanup();
304  return;
305  }
306  }
307 
309 
310  const bool updated_fw_in = _actuator_inputs_fw.update(&_actuators_fw_in);
311  const bool updated_mc_in = _actuator_inputs_mc.update(&_actuators_mc_in);
312 
313  // run on actuator publications corresponding to VTOL mode
314  bool should_run = false;
315 
316  switch (_vtol_type->get_mode()) {
319  should_run = updated_fw_in || updated_mc_in;
320  break;
321 
322  case mode::ROTARY_WING:
323  should_run = updated_mc_in;
324  break;
325 
326  case mode::FIXED_WING:
327  should_run = updated_fw_in;
328  break;
329  }
330 
331  if (should_run) {
332  // check for parameter updates
334  // clear update
335  parameter_update_s pupdate;
336  _parameter_update_sub.copy(&pupdate);
337 
338  // update parameters from storage
340  }
341 
352 
353  // check if mc and fw sp were updated
354  bool mc_att_sp_updated = _mc_virtual_att_sp_sub.update(&_mc_virtual_att_sp);
355  bool fw_att_sp_updated = _fw_virtual_att_sp_sub.update(&_fw_virtual_att_sp);
356 
357  // update the vtol state machine which decides which mode we are in
358  if (mc_att_sp_updated || fw_att_sp_updated) {
360 
361  // reset transition command if not auto control
364  _transition_command = vtol_vehicle_status_s::VEHICLE_VTOL_STATE_MC;
365 
366  } else if (_vtol_type->get_mode() == mode::FIXED_WING) {
367  _transition_command = vtol_vehicle_status_s::VEHICLE_VTOL_STATE_FW;
368 
369  } else if (_vtol_type->get_mode() == mode::TRANSITION_TO_MC) {
370  /* We want to make sure that a mode change (manual>auto) during the back transition
371  * doesn't result in an unsafe state. This prevents the instant fall back to
372  * fixed-wing on the switch from manual to auto */
373  _transition_command = vtol_vehicle_status_s::VEHICLE_VTOL_STATE_MC;
374  }
375  }
376  }
377 
378 
379 
380  // check in which mode we are in and call mode specific functions
381  switch (_vtol_type->get_mode()) {
384  // vehicle is doing a transition
386  _vtol_vehicle_status.vtol_in_rw_mode = true; // making mc attitude controller work during transition
388 
390 
391  if (mc_att_sp_updated || fw_att_sp_updated) {
394  }
395 
396  break;
397 
398  case mode::ROTARY_WING:
399  // vehicle is in rotary wing mode
403 
406 
407  break;
408 
409  case mode::FIXED_WING:
410  // vehicle is in fw mode
414 
415  if (fw_att_sp_updated) {
418  }
419 
420  break;
421  }
422 
426 
427  // Advertise/Publish vtol vehicle status
430  }
431 
433 }
434 
435 int
436 VtolAttitudeControl::task_spawn(int argc, char *argv[])
437 {
439 
440  if (instance) {
441  _object.store(instance);
442  _task_id = task_id_is_work_queue;
443 
444  if (instance->init()) {
445  return PX4_OK;
446  }
447 
448  } else {
449  PX4_ERR("alloc failed");
450  }
451 
452  delete instance;
453  _object.store(nullptr);
454  _task_id = -1;
455 
456  return PX4_ERROR;
457 }
458 
459 int
460 VtolAttitudeControl::custom_command(int argc, char *argv[])
461 {
462  return print_usage("unknown command");
463 }
464 
465 int
467 {
468  PX4_INFO("Running");
470  return PX4_OK;
471 }
472 
473 int
475 {
476  if (reason) {
477  PX4_WARN("%s\n", reason);
478  }
479 
480  PRINT_MODULE_DESCRIPTION(
481  R"DESCR_STR(
482 ### Description
483 fw_att_control is the fixed wing attitude controller.
484 )DESCR_STR");
485 
486  PRINT_MODULE_USAGE_COMMAND("start");
487  PRINT_MODULE_USAGE_NAME("vtol_att_control", "controller");
488  PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
489 
490  return 0;
491 }
492 
493 int vtol_att_control_main(int argc, char *argv[])
494 {
495  return VtolAttitudeControl::main(argc, argv);
496 }
constexpr _Tp constrain(_Tp val, _Tp min_val, _Tp max_val)
Definition: Limits.hpp:66
float front_trans_timeout
Definition: vtol_type.h:68
float fw_qc_max_pitch
Definition: vtol_type.h:57
uORB::Publication< actuator_controls_s > _actuators_1_pub
vehicle_land_detected_s _land_detected
int32_t diff_thrust
Definition: vtol_type.h:71
measure the time elapsed performing an event
Definition: perf_counter.h:56
uORB::Subscription _parameter_update_sub
vehicle_attitude_s _v_att
float fw_alt_err
Definition: vtol_type.h:56
bool update(void *dst)
Copy the struct if updated.
uORB::Subscription _mc_virtual_att_sp_sub
__EXPORT int param_get(param_t param, void *val)
Copy the value of a parameter.
Definition: parameters.cpp:589
uORB::SubscriptionCallbackWorkItem _actuator_inputs_fw
actuator_controls_s _actuators_out_1
uORB::Subscription _pos_sp_triplet_sub
int main(int argc, char **argv)
Definition: main.cpp:3
float airspeed_blend
Definition: vtol_type.h:66
int32_t fw_motors_off
bitmask of all motors that should be off in fixed wing mode
Definition: vtol_type.h:70
float mpc_xy_cruise
Definition: vtol_type.h:69
uORB::Publication< vtol_vehicle_status_s > _vtol_vehicle_status_pub
vehicle_attitude_setpoint_s _fw_virtual_att_sp
float fw_min_alt
Definition: vtol_type.h:55
perf_counter_t _loop_perf
loop performance counter
LidarLite * instance
Definition: ll40ls.cpp:65
virtual void update_vtol_state()=0
Update vtol state.
actuator_controls_s _actuators_fw_in
vehicle_attitude_setpoint_s _mc_virtual_att_sp
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
uORB::Subscription _land_detected_sub
static int custom_command(int argc, char *argv[])
vehicle_attitude_setpoint_s _v_att_sp
bool publish(const T &data)
Publish the struct.
Definition: Publication.hpp:68
vtol_vehicle_status_s _vtol_vehicle_status
void perf_free(perf_counter_t handle)
Free a counter.
uORB::Subscription _local_pos_sub
uORB::Subscription _tecs_status_sub
uORB::Publication< actuator_controls_s > _actuators_0_pub
airspeed_validated_s _airspeed_validated
float diff_thrust_scale
Definition: vtol_type.h:72
virtual void update_fw_state()
Update fixed wing state.
Definition: vtol_type.cpp:140
#define perf_alloc(a, b)
Definition: px4io.h:59
uORB::Subscription _airspeed_validated_sub
virtual void parameters_update()=0
actuator_controls_s _actuators_mc_in
struct VtolAttitudeControl::@145 _params_handles
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
vehicle_command_s _vehicle_cmd
int vtol_att_control_main(int argc, char *argv[])
void perf_end(perf_counter_t handle)
End a performance event.
bool updated()
Check if there is a new update.
manual_control_setpoint_s _manual_control_sp
constexpr _Tp min(_Tp a, _Tp b)
Definition: Limits.hpp:54
static int task_spawn(int argc, char *argv[])
__EXPORT param_t param_find(const char *name)
Look up a parameter by name.
Definition: parameters.cpp:370
float back_trans_duration
Definition: vtol_type.h:62
bool init()
Initialise.
Definition: vtol_type.cpp:80
vehicle_local_position_setpoint_s _local_pos_sp
uORB::Subscription _fw_virtual_att_sp_sub
void vehicle_cmd_poll()
Check for command updates.
float transition_airspeed
Definition: vtol_type.h:63
uORB::Subscription _vehicle_cmd_sub
vehicle_local_position_s _local_pos
float front_trans_time_openloop
Definition: vtol_type.h:59
uORB::Subscription _manual_control_sp_sub
void perf_print_counter(perf_counter_t handle)
Print one performance counter to stdout.
virtual void update_mc_state()
Update multicopter state.
Definition: vtol_type.cpp:121
vehicle_control_mode_s _v_control_mode
float back_trans_throttle
Definition: vtol_type.h:65
Definition: bst.cpp:62
float fw_qc_max_roll
Definition: vtol_type.h:58
virtual void update_transition_state()=0
Update transition state.
Definition: vtol_type.cpp:176
bool elevons_mc_lock
Definition: vtol_type.h:54
int32_t vtol_type
Definition: vtol_type.h:53
uORB::SubscriptionCallbackWorkItem _actuator_inputs_mc
bool airspeed_disabled
Definition: vtol_type.h:67
#define OK
Definition: uavcan_main.cpp:71
bool update(void *dst)
Update the struct.
uORB::Subscription _local_pos_sp_sub
position_setpoint_triplet_s _pos_sp_triplet
uORB::Subscription _v_att_sub
float front_trans_time_min
Definition: vtol_type.h:60
void handle_command()
Check received command.
actuator_controls_s _actuators_out_0
void abort_front_transition(const char *reason)
uORB::Subscription _v_control_mode_sub
#define PWM_DEFAULT_MIN
Default minimum PWM in us.
float front_trans_duration
Definition: vtol_type.h:61
bool copy(void *dst)
Copy the struct.
void perf_begin(perf_counter_t handle)
Begin a performance event.
int32_t vtol_motor_id
Definition: vtol_type.h:52
mode get_mode()
Definition: vtol_type.h:168
int32_t idle_pwm_mc
Definition: vtol_type.h:51
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
float front_trans_throttle
Definition: vtol_type.h:64
static int print_usage(const char *reason=nullptr)
virtual void fill_actuator_outputs()=0
Write control values to actuator output topics.
uORB::Publication< vehicle_attitude_setpoint_s > _v_att_sp_pub