PX4 Firmware
PX4 Autopilot Software http://px4.io
standard.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2015 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 standard.cpp
36  *
37  * @author Simon Wilks <simon@uaventure.com>
38  * @author Roman Bapst <bapstroman@gmail.com>
39  * @author Andreas Antener <andreas@uaventure.com>
40  * @author Sander Smeets <sander@droneslab.com>
41  *
42 */
43 
44 #include "standard.h"
45 #include "vtol_att_control_main.h"
46 
47 #include <float.h>
48 
49 using namespace matrix;
50 
52  VtolType(attc)
53 {
54  _vtol_schedule.flight_mode = vtol_mode::MC_MODE;
55  _vtol_schedule.transition_start = 0;
56  _pusher_active = false;
57 
58  _mc_roll_weight = 1.0f;
59  _mc_pitch_weight = 1.0f;
60  _mc_yaw_weight = 1.0f;
61  _mc_throttle_weight = 1.0f;
62 
63  _params_handles_standard.pusher_ramp_dt = param_find("VT_PSHER_RMP_DT");
64  _params_handles_standard.back_trans_ramp = param_find("VT_B_TRANS_RAMP");
65  _params_handles_standard.down_pitch_max = param_find("VT_DWN_PITCH_MAX");
66  _params_handles_standard.forward_thrust_scale = param_find("VT_FWD_THRUST_SC");
67  _params_handles_standard.pitch_setpoint_offset = param_find("FW_PSP_OFF");
68  _params_handles_standard.reverse_output = param_find("VT_B_REV_OUT");
69  _params_handles_standard.reverse_delay = param_find("VT_B_REV_DEL");
70 }
71 
72 void
74 {
75  float v;
76 
77  /* duration of a forwards transition to fw mode */
78  param_get(_params_handles_standard.pusher_ramp_dt, &v);
79  _params_standard.pusher_ramp_dt = math::constrain(v, 0.0f, 20.0f);
80 
81  /* MC ramp up during back transition to mc mode */
82  param_get(_params_handles_standard.back_trans_ramp, &v);
84 
86 
87  /* maximum down pitch allowed */
88  param_get(_params_handles_standard.down_pitch_max, &v);
89  _params_standard.down_pitch_max = math::radians(v);
90 
91  /* scale for fixed wing thrust used for forward acceleration in multirotor mode */
92  param_get(_params_handles_standard.forward_thrust_scale, &_params_standard.forward_thrust_scale);
93 
94  /* pitch setpoint offset */
95  param_get(_params_handles_standard.pitch_setpoint_offset, &v);
96  _params_standard.pitch_setpoint_offset = math::radians(v);
97 
98  /* reverse output */
99  param_get(_params_handles_standard.reverse_output, &v);
100  _params_standard.reverse_output = math::constrain(v, 0.0f, 1.0f);
101 
102  /* reverse output */
103  param_get(_params_handles_standard.reverse_delay, &v);
104  _params_standard.reverse_delay = math::constrain(v, 0.0f, 10.0f);
105 
106 }
107 
109 {
110  /* After flipping the switch the vehicle will start the pusher (or tractor) motor, picking up
111  * forward speed. After the vehicle has picked up enough speed the rotors shutdown.
112  * For the back transition the pusher motor is immediately stopped and rotors reactivated.
113  */
114 
115  float mc_weight = _mc_roll_weight;
116  float time_since_trans_start = (float)(hrt_absolute_time() - _vtol_schedule.transition_start) * 1e-6f;
117 
118  if (!_attc->is_fixed_wing_requested()) {
119 
120  // the transition to fw mode switch is off
121  if (_vtol_schedule.flight_mode == vtol_mode::MC_MODE) {
122  // in mc mode
123  _vtol_schedule.flight_mode = vtol_mode::MC_MODE;
124  mc_weight = 1.0f;
125  _pusher_throttle = 0.0f;
126  _reverse_output = 0.0f;
127 
128  } else if (_vtol_schedule.flight_mode == vtol_mode::FW_MODE) {
129  // transition to mc mode
131  // Failsafe event, engage mc motors immediately
132  _vtol_schedule.flight_mode = vtol_mode::MC_MODE;
133  _pusher_throttle = 0.0f;
134  _reverse_output = 0.0f;
135 
136 
137  } else {
138  // Regular backtransition
140  _vtol_schedule.transition_start = hrt_absolute_time();
141  _reverse_output = _params_standard.reverse_output;
142 
143  }
144 
145  } else if (_vtol_schedule.flight_mode == vtol_mode::TRANSITION_TO_FW) {
146  // failsafe back to mc mode
147  _vtol_schedule.flight_mode = vtol_mode::MC_MODE;
148  mc_weight = 1.0f;
149  _pusher_throttle = 0.0f;
150  _reverse_output = 0.0f;
151 
152 
153  } else if (_vtol_schedule.flight_mode == vtol_mode::TRANSITION_TO_MC) {
154  // transition to MC mode if transition time has passed or forward velocity drops below MPC cruise speed
155 
156  const Dcmf R_to_body(Quatf(_v_att->q).inversed());
157  const Vector3f vel = R_to_body * Vector3f(_local_pos->vx, _local_pos->vy, _local_pos->vz);
158 
159  float x_vel = vel(0);
160 
161  if (time_since_trans_start > _params->back_trans_duration ||
162  (_local_pos->v_xy_valid && x_vel <= _params->mpc_xy_cruise)) {
163  _vtol_schedule.flight_mode = vtol_mode::MC_MODE;
164  }
165 
166  }
167 
168  } else {
169  // the transition to fw mode switch is on
170  if (_vtol_schedule.flight_mode == vtol_mode::MC_MODE || _vtol_schedule.flight_mode == vtol_mode::TRANSITION_TO_MC) {
171  // start transition to fw mode
172  /* NOTE: The failsafe transition to fixed-wing was removed because it can result in an
173  * unsafe flying state. */
175  _vtol_schedule.transition_start = hrt_absolute_time();
176 
177  } else if (_vtol_schedule.flight_mode == vtol_mode::FW_MODE) {
178  // in fw mode
179  _vtol_schedule.flight_mode = vtol_mode::FW_MODE;
180  mc_weight = 0.0f;
181 
182  } else if (_vtol_schedule.flight_mode == vtol_mode::TRANSITION_TO_FW) {
183  // continue the transition to fw mode while monitoring airspeed for a final switch to fw mode
184 
185  const bool airspeed_triggers_transition = PX4_ISFINITE(_airspeed_validated->equivalent_airspeed_m_s)
187  const bool minimum_trans_time_elapsed = time_since_trans_start > _params->front_trans_time_min;
188 
189  bool transition_to_fw = false;
190 
191  if (minimum_trans_time_elapsed) {
192  if (airspeed_triggers_transition) {
194 
195  } else {
196  transition_to_fw = true;
197  }
198  }
199 
200  transition_to_fw |= can_transition_on_ground();
201 
202  if (transition_to_fw) {
203  _vtol_schedule.flight_mode = vtol_mode::FW_MODE;
204 
205  // don't set pusher throttle here as it's being ramped up elsewhere
207  }
208  }
209  }
210 
211  _mc_roll_weight = mc_weight;
212  _mc_pitch_weight = mc_weight;
213  _mc_yaw_weight = mc_weight;
214  _mc_throttle_weight = mc_weight;
215 
216  // map specific control phases to simple control modes
217  switch (_vtol_schedule.flight_mode) {
218  case vtol_mode::MC_MODE:
220  break;
221 
222  case vtol_mode::FW_MODE:
224  break;
225 
228  break;
229 
232  break;
233  }
234 }
235 
237 {
238  float mc_weight = 1.0f;
239  float time_since_trans_start = (float)(hrt_absolute_time() - _vtol_schedule.transition_start) * 1e-6f;
240 
242 
243  // copy virtual attitude setpoint to real attitude setpoint
245 
246  if (_vtol_schedule.flight_mode == vtol_mode::TRANSITION_TO_FW) {
247  if (_params_standard.pusher_ramp_dt <= 0.0f) {
248  // just set the final target throttle value
250 
251  } else if (_pusher_throttle <= _params->front_trans_throttle) {
252  // ramp up throttle to the target throttle value
253  _pusher_throttle = _params->front_trans_throttle * time_since_trans_start / _params_standard.pusher_ramp_dt;
254  }
255 
256  // do blending of mc and fw controls if a blending airspeed has been provided and the minimum transition time has passed
257  if (_airspeed_trans_blend_margin > 0.0f &&
261  time_since_trans_start > _params->front_trans_time_min) {
262 
263  mc_weight = 1.0f - fabsf(_airspeed_validated->equivalent_airspeed_m_s - _params->airspeed_blend) /
265  // time based blending when no airspeed sensor is set
266 
267  } else if (_params->airspeed_disabled || !PX4_ISFINITE(_airspeed_validated->equivalent_airspeed_m_s)) {
268  mc_weight = 1.0f - time_since_trans_start / _params->front_trans_time_min;
269  mc_weight = math::constrain(2.0f * mc_weight, 0.0f, 1.0f);
270 
271  }
272 
273  // ramp up FW_PSP_OFF
274  _v_att_sp->pitch_body = _params_standard.pitch_setpoint_offset * (1.0f - mc_weight);
276  q_sp.copyTo(_v_att_sp->q_d);
277  _v_att_sp->q_d_valid = true;
278 
279  // check front transition timeout
281  if (time_since_trans_start > _params->front_trans_timeout) {
282  // transition timeout occured, abort transition
283  _attc->abort_front_transition("Transition timeout");
284  }
285  }
286 
287  } else if (_vtol_schedule.flight_mode == vtol_mode::TRANSITION_TO_MC) {
288 
289  // maintain FW_PSP_OFF
290  _v_att_sp->pitch_body = _params_standard.pitch_setpoint_offset;
292  q_sp.copyTo(_v_att_sp->q_d);
293  _v_att_sp->q_d_valid = true;
294 
295  _pusher_throttle = 0.0f;
296 
297  if (time_since_trans_start >= _params_standard.reverse_delay) {
298  // Handle throttle reversal for active breaking
299  float thrscale = (time_since_trans_start - _params_standard.reverse_delay) / (_params_standard.pusher_ramp_dt);
300  thrscale = math::constrain(thrscale, 0.0f, 1.0f);
302  }
303 
304  // continually increase mc attitude control as we transition back to mc mode
305  if (_params_standard.back_trans_ramp > FLT_EPSILON) {
306  mc_weight = time_since_trans_start / _params_standard.back_trans_ramp;
307 
308  }
309 
310  // in back transition we need to start the MC motors again
313  }
314  }
315 
316  mc_weight = math::constrain(mc_weight, 0.0f, 1.0f);
317 
318  _mc_roll_weight = mc_weight;
319  _mc_pitch_weight = mc_weight;
320  _mc_yaw_weight = mc_weight;
321  _mc_throttle_weight = mc_weight;
322 }
323 
325 {
327 
328  // if the thrust scale param is zero or the drone is on manual mode,
329  // then the pusher-for-pitch strategy is disabled and we can return
330  if (_params_standard.forward_thrust_scale < FLT_EPSILON ||
332  return;
333  }
334 
335  // Do not engage pusher assist during a failsafe event
336  // There could be a problem with the fixed wing drive
338  return;
339  }
340 
341  // disable pusher assist during landing
343  && _attc->get_pos_sp_triplet()->current.type == position_setpoint_s::SETPOINT_TYPE_LAND) {
344  return;
345  }
346 
347  const Dcmf R(Quatf(_v_att->q));
348  const Dcmf R_sp(Quatf(_v_att_sp->q_d));
349  const Eulerf euler(R);
350  const Eulerf euler_sp(R_sp);
351  _pusher_throttle = 0.0f;
352 
353  // direction of desired body z axis represented in earth frame
354  Vector3f body_z_sp(R_sp(0, 2), R_sp(1, 2), R_sp(2, 2));
355 
356  // rotate desired body z axis into new frame which is rotated in z by the current
357  // heading of the vehicle. we refer to this as the heading frame.
358  Dcmf R_yaw = Eulerf(0.0f, 0.0f, -euler(2));
359  body_z_sp = R_yaw * body_z_sp;
360  body_z_sp.normalize();
361 
362  // calculate the desired pitch seen in the heading frame
363  // this value corresponds to the amount the vehicle would try to pitch forward
364  float pitch_forward = atan2f(body_z_sp(0), body_z_sp(2));
365 
366  // only allow pitching forward up to threshold, the rest of the desired
367  // forward acceleration will be compensated by the pusher
368  if (pitch_forward < -_params_standard.down_pitch_max) {
369  // desired roll angle in heading frame stays the same
370  float roll_new = -asinf(body_z_sp(1));
371 
372  _pusher_throttle = (sinf(-pitch_forward) - sinf(_params_standard.down_pitch_max))
373  * _params_standard.forward_thrust_scale;
374 
375  // return the vehicle to level position
376  float pitch_new = 0.0f;
377 
378  // create corrected desired body z axis in heading frame
379  const Dcmf R_tmp = Eulerf(roll_new, pitch_new, 0.0f);
380  Vector3f tilt_new(R_tmp(0, 2), R_tmp(1, 2), R_tmp(2, 2));
381 
382  // rotate the vector into a new frame which is rotated in z by the desired heading
383  // with respect to the earh frame.
384  const float yaw_error = wrap_pi(euler_sp(2) - euler(2));
385  const Dcmf R_yaw_correction = Eulerf(0.0f, 0.0f, -yaw_error);
386  tilt_new = R_yaw_correction * tilt_new;
387 
388  // now extract roll and pitch setpoints
389  _v_att_sp->pitch_body = atan2f(tilt_new(0), tilt_new(2));
390  _v_att_sp->roll_body = -asinf(tilt_new(1));
391 
392  const Quatf q_sp(Eulerf(_v_att_sp->roll_body, _v_att_sp->pitch_body, euler_sp(2)));
393  q_sp.copyTo(_v_att_sp->q_d);
394  _v_att_sp->q_d_valid = true;
395  }
396 
398 }
399 
401 {
403 }
404 
405 /**
406  * Prepare message to acutators with data from mc and fw attitude controllers. An mc attitude weighting will determine
407  * what proportion of control should be applied to each of the control groups (mc and fw).
408  */
410 {
411  // multirotor controls
414 
415  // roll
416  _actuators_out_0->control[actuator_controls_s::INDEX_ROLL] =
417  _actuators_mc_in->control[actuator_controls_s::INDEX_ROLL] * _mc_roll_weight;
418  // pitch
419  _actuators_out_0->control[actuator_controls_s::INDEX_PITCH] =
420  _actuators_mc_in->control[actuator_controls_s::INDEX_PITCH] * _mc_pitch_weight;
421  // yaw
422  _actuators_out_0->control[actuator_controls_s::INDEX_YAW] =
423  _actuators_mc_in->control[actuator_controls_s::INDEX_YAW] * _mc_yaw_weight;
424  // throttle
425  _actuators_out_0->control[actuator_controls_s::INDEX_THROTTLE] =
426  _actuators_mc_in->control[actuator_controls_s::INDEX_THROTTLE] * _mc_throttle_weight;
427 
428 
429  // fixed wing controls
432 
433  if (_vtol_schedule.flight_mode != vtol_mode::MC_MODE) {
434  // roll
435  _actuators_out_1->control[actuator_controls_s::INDEX_ROLL] =
436  _actuators_fw_in->control[actuator_controls_s::INDEX_ROLL];
437 
438  // pitch
439  _actuators_out_1->control[actuator_controls_s::INDEX_PITCH] =
440  _actuators_fw_in->control[actuator_controls_s::INDEX_PITCH];
441  // yaw
442  _actuators_out_1->control[actuator_controls_s::INDEX_YAW] =
443  _actuators_fw_in->control[actuator_controls_s::INDEX_YAW];
444 
445  _actuators_out_1->control[actuator_controls_s::INDEX_AIRBRAKES] = _reverse_output;
446 
447  } else {
448 
449  if (_params->elevons_mc_lock) {
450  // zero outputs when inactive
451  _actuators_out_1->control[actuator_controls_s::INDEX_ROLL] = 0.0f;
452  _actuators_out_1->control[actuator_controls_s::INDEX_PITCH] = 0.0f;
453  _actuators_out_1->control[actuator_controls_s::INDEX_YAW] = 0.0f;
454  _actuators_out_1->control[actuator_controls_s::INDEX_AIRBRAKES] = 0.0f;
455 
456  } else {
457  // roll
458  _actuators_out_1->control[actuator_controls_s::INDEX_ROLL] =
459  _actuators_fw_in->control[actuator_controls_s::INDEX_ROLL];
460 
461  // pitch
462  _actuators_out_1->control[actuator_controls_s::INDEX_PITCH] =
463  _actuators_fw_in->control[actuator_controls_s::INDEX_PITCH];
464 
465  _actuators_out_1->control[actuator_controls_s::INDEX_YAW] = 0.0f;
466  _actuators_out_1->control[actuator_controls_s::INDEX_AIRBRAKES] = 0.0f;
467  }
468  }
469 
470  // set the fixed wing throttle control
471  if (_vtol_schedule.flight_mode == vtol_mode::FW_MODE) {
472 
473  // take the throttle value commanded by the fw controller
474  _actuators_out_1->control[actuator_controls_s::INDEX_THROTTLE] =
475  _actuators_fw_in->control[actuator_controls_s::INDEX_THROTTLE];
476 
477  } else {
478  // otherwise we may be ramping up the throttle during the transition to fw mode
479  _actuators_out_1->control[actuator_controls_s::INDEX_THROTTLE] = _pusher_throttle;
480  }
481 
482 
483 }
484 
485 void
487 {
488  // keep thrust from transition
490 };
hrt_abstime _trans_finished_ts
Definition: vtol_type.h:212
constexpr _Tp constrain(_Tp val, _Tp min_val, _Tp max_val)
Definition: Limits.hpp:66
float _airspeed_trans_blend_margin
Definition: standard.h:103
float front_trans_timeout
Definition: vtol_type.h:68
void waiting_on_tecs() override
Special handling opportunity for the time right after transition to FW before TECS is running...
Definition: standard.cpp:486
motor_state _motor_state
Definition: vtol_type.h:217
float _reverse_output
Definition: standard.h:102
float _mc_pitch_weight
Definition: vtol_type.h:200
__EXPORT int param_get(param_t param, void *val)
Copy the value of a parameter.
Definition: parameters.cpp:589
float _mc_yaw_weight
Definition: vtol_type.h:201
float airspeed_blend
Definition: vtol_type.h:66
struct Standard::@138 _vtol_schedule
struct actuator_controls_s * _actuators_mc_in
Definition: vtol_type.h:186
void normalize()
Definition: Vector.hpp:87
struct vehicle_attitude_s * _v_att
Definition: vtol_type.h:178
mode _vtol_mode
Definition: vtol_type.h:174
void copyTo(Type dst[M *N]) const
Definition: Matrix.hpp:115
#define FLT_EPSILON
Quaternion class.
Definition: Dcm.hpp:24
VtolAttitudeControl * _attc
Definition: vtol_type.h:173
struct Params * _params
Definition: vtol_type.h:194
struct actuator_controls_s * _actuators_out_0
Definition: vtol_type.h:184
struct position_setpoint_s current
struct vehicle_local_position_s * _local_pos
Definition: vtol_type.h:188
virtual void update_fw_state()
Update fixed wing state.
Definition: vtol_type.cpp:140
void update_vtol_state() override
Update vtol state.
Definition: standard.cpp:108
struct actuator_controls_s * _actuators_fw_in
Definition: vtol_type.h:187
float _mc_throttle_weight
Definition: vtol_type.h:202
struct vehicle_attitude_setpoint_s * _v_att_sp
Definition: vtol_type.h:179
constexpr T radians(T degrees)
Definition: Limits.hpp:85
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
Euler< float > Eulerf
Definition: Euler.hpp:156
void update_fw_state() override
Update fixed wing state.
Definition: standard.cpp:400
float _pusher_throttle
Definition: standard.h:101
void parameters_update() override
Definition: standard.cpp:73
struct vehicle_attitude_setpoint_s * _mc_virtual_att_sp
Definition: vtol_type.h:180
void update_mc_state() override
Update multicopter state.
Definition: standard.cpp:324
Euler angles class.
Definition: AxisAngle.hpp:18
motor_state set_motor_state(const motor_state current_state, const motor_state next_state, const int value=0)
Sets state of a selection of motors, see struct motor_state.
Definition: vtol_type.cpp:312
struct Standard::@137 _params_handles_standard
struct Standard::@136 _params_standard
struct vtol_vehicle_status_s * get_vtol_vehicle_status()
Type wrap_pi(Type x)
Wrap value in range [-π, π)
__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
struct vehicle_control_mode_s * _v_control_mode
Definition: vtol_type.h:182
Vector3< float > Vector3f
Definition: Vector3.hpp:136
float _mc_roll_weight
Definition: vtol_type.h:199
float transition_airspeed
Definition: vtol_type.h:63
Quaternion< float > Quatf
Definition: Quaternion.hpp:544
virtual void update_mc_state()
Update multicopter state.
Definition: vtol_type.cpp:121
void fill_actuator_outputs() override
Prepare message to acutators with data from mc and fw attitude controllers.
Definition: standard.cpp:409
bool _pusher_active
Definition: vtol_type.h:198
float back_trans_throttle
Definition: vtol_type.h:65
struct airspeed_validated_s * _airspeed_validated
Definition: vtol_type.h:190
virtual void update_transition_state()=0
Update transition state.
Definition: vtol_type.cpp:176
bool elevons_mc_lock
Definition: vtol_type.h:54
struct actuator_controls_s * _actuators_out_1
Definition: vtol_type.h:185
bool airspeed_disabled
Definition: vtol_type.h:67
struct position_setpoint_triplet_s * get_pos_sp_triplet()
float front_trans_time_min
Definition: vtol_type.h:60
void abort_front_transition(const char *reason)
struct vtol_vehicle_status_s * _vtol_vehicle_status
Definition: vtol_type.h:183
bool can_transition_on_ground()
Returns true if we&#39;re allowed to do a mode transition on the ground.
Definition: vtol_type.cpp:181
VTOL with fixed multirotor motor configurations (such as quad) and a pusher (or puller aka tractor) m...
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
void update_transition_state() override
Update transition state.
Definition: standard.cpp:236
float front_trans_throttle
Definition: vtol_type.h:64
Standard(VtolAttitudeControl *_att_controller)
Definition: standard.cpp:51