Line data Source code
1 : #include "Plane.h"
2 :
3 : #include "qautotune.h"
4 :
5 67467802 : static void failsafe_check_static()
6 : {
7 67467802 : plane.failsafe_check();
8 67467802 : }
9 :
10 692 : void Plane::init_ardupilot()
11 : {
12 :
13 692 : ins.set_log_raw_bit(MASK_LOG_IMU_RAW);
14 :
15 : // initialise rc channels including setting mode
16 692 : rc().init();
17 :
18 : #if AP_RELAY_ENABLED
19 692 : relay.init();
20 : #endif
21 :
22 : // initialise notify system
23 692 : notify.init();
24 692 : notify_mode(*control_mode);
25 :
26 692 : init_rc_out_main();
27 :
28 : // init baro
29 692 : barometer.init();
30 :
31 : #if AP_RANGEFINDER_ENABLED
32 : // initialise rangefinder
33 692 : rangefinder.set_log_rfnd_bit(MASK_LOG_SONAR);
34 692 : rangefinder.init(ROTATION_PITCH_270);
35 : #endif
36 :
37 : // initialise battery monitoring
38 692 : battery.init();
39 :
40 : #if AP_RSSI_ENABLED
41 692 : rssi.init();
42 : #endif
43 :
44 : // setup telem slots with serial ports
45 692 : gcs().setup_uarts();
46 :
47 :
48 : #if OSD_ENABLED
49 692 : osd.init();
50 : #endif
51 :
52 692 : AP::compass().set_log_bit(MASK_LOG_COMPASS);
53 692 : AP::compass().init();
54 :
55 : #if AP_AIRSPEED_ENABLED
56 692 : airspeed.set_fixedwing_parameters(&aparm);
57 692 : airspeed.set_log_bit(MASK_LOG_IMU);
58 : #endif
59 :
60 : // GPS Initialization
61 692 : gps.set_log_gps_bit(MASK_LOG_GPS);
62 692 : gps.init();
63 :
64 692 : init_rc_in(); // sets up rc channels from radio
65 :
66 : #if HAL_MOUNT_ENABLED
67 : // initialise camera mount
68 692 : camera_mount.init();
69 : #endif
70 :
71 : #if AP_CAMERA_ENABLED
72 : // initialise camera
73 692 : camera.init();
74 : #endif
75 :
76 : #if AP_LANDINGGEAR_ENABLED
77 : // initialise landing gear position
78 692 : g2.landing_gear.init();
79 : #endif
80 :
81 : #if FENCE_TRIGGERED_PIN > 0
82 : hal.gpio->pinMode(FENCE_TRIGGERED_PIN, HAL_GPIO_OUTPUT);
83 : hal.gpio->write(FENCE_TRIGGERED_PIN, 0);
84 : #endif
85 :
86 : /*
87 : * setup the 'main loop is dead' check. Note that this relies on
88 : * the RC library being initialised.
89 : */
90 692 : hal.scheduler->register_timer_failsafe(failsafe_check_static, 1000);
91 :
92 : #if HAL_QUADPLANE_ENABLED
93 692 : quadplane.setup();
94 : #endif
95 :
96 692 : AP_Param::reload_defaults_file(true);
97 :
98 : // ALT_OFFSET always starts at zero, independently of FLIGHT_OPTIONS.
99 692 : reset_alt_offset(true);
100 :
101 692 : set_mode(mode_initializing, ModeReason::INITIALISED);
102 :
103 : #if (GROUND_START_DELAY > 0)
104 : gcs().send_text(MAV_SEVERITY_NOTICE,"Ground start with delay");
105 : delay(GROUND_START_DELAY * 1000);
106 : #else
107 692 : gcs().send_text(MAV_SEVERITY_INFO,"Ground start");
108 : #endif
109 :
110 : //INS ground start
111 : //------------------------
112 : //
113 692 : startup_INS();
114 :
115 : // Save the settings for in-air restart
116 : // ------------------------------------
117 : //save_EEPROM_groundstart();
118 :
119 : // initialise mission library
120 691 : mission.init();
121 : #if HAL_LOGGING_ENABLED
122 691 : mission.set_log_start_mission_item_bit(MASK_LOG_CMD);
123 : #endif
124 :
125 : // initialise AP_Logger library
126 : #if HAL_LOGGING_ENABLED
127 691 : logger.setVehicle_Startup_Writer(
128 : FUNCTOR_BIND(&plane, &Plane::Log_Write_Vehicle_Startup_Messages, void)
129 : );
130 : #endif
131 :
132 : // reset last heartbeat time, so we don't trigger failsafe on slow
133 : // startup
134 691 : gcs().sysid_mygcs_seen(AP_HAL::millis());
135 :
136 : // don't initialise aux rc output until after quadplane is setup as
137 : // that can change initial values of channels
138 691 : init_rc_out_aux();
139 :
140 691 : if (g2.oneshot_mask != 0) {
141 0 : hal.rcout->set_output_mode(g2.oneshot_mask, AP_HAL::RCOutput::MODE_PWM_ONESHOT);
142 : }
143 691 : hal.rcout->set_dshot_esc_type(SRV_Channels::get_dshot_esc_type());
144 :
145 691 : set_mode_by_number((enum Mode::Number)g.initial_mode.get(), ModeReason::INITIALISED);
146 :
147 : // set the correct flight mode
148 : // ---------------------------
149 691 : rc().reset_mode_switch();
150 :
151 : // initialise sensor
152 : #if AP_OPTICALFLOW_ENABLED
153 691 : if (optflow.enabled()) {
154 0 : optflow.init(-1);
155 : }
156 : #endif
157 :
158 : #if AC_PRECLAND_ENABLED
159 : // scheduler table specifies 400Hz, but we can call it no faster
160 : // than the scheduler loop rate:
161 691 : g2.precland.init(MIN(400, scheduler.get_loop_rate_hz()));
162 : #endif
163 :
164 : #if AP_ICENGINE_ENABLED
165 691 : g2.ice_control.init();
166 : #endif
167 :
168 691 : }
169 :
170 : #if AP_FENCE_ENABLED
171 : /*
172 : return true if a mode reason is an automatic mode change due to
173 : landing sequencing.
174 : */
175 27 : static bool mode_reason_is_landing_sequence(const ModeReason reason)
176 : {
177 27 : switch (reason) {
178 2 : case ModeReason::RTL_COMPLETE_SWITCHING_TO_FIXEDWING_AUTOLAND:
179 : case ModeReason::RTL_COMPLETE_SWITCHING_TO_VTOL_LAND_RTL:
180 : case ModeReason::QRTL_INSTEAD_OF_RTL:
181 : case ModeReason::QLAND_INSTEAD_OF_RTL:
182 2 : return true;
183 25 : default:
184 25 : break;
185 : }
186 25 : return false;
187 : }
188 : #endif // AP_FENCE_ENABLED
189 :
190 : // Check if this mode can be entered from the GCS
191 825 : bool Plane::gcs_mode_enabled(const Mode::Number mode_num) const
192 : {
193 : // List of modes that can be blocked, index is bit number in parameter bitmask
194 : static const uint8_t mode_list [] {
195 : (uint8_t)Mode::Number::MANUAL,
196 : (uint8_t)Mode::Number::CIRCLE,
197 : (uint8_t)Mode::Number::STABILIZE,
198 : (uint8_t)Mode::Number::TRAINING,
199 : (uint8_t)Mode::Number::ACRO,
200 : (uint8_t)Mode::Number::FLY_BY_WIRE_A,
201 : (uint8_t)Mode::Number::FLY_BY_WIRE_B,
202 : (uint8_t)Mode::Number::CRUISE,
203 : (uint8_t)Mode::Number::AUTOTUNE,
204 : (uint8_t)Mode::Number::AUTO,
205 : (uint8_t)Mode::Number::LOITER,
206 : (uint8_t)Mode::Number::TAKEOFF,
207 : (uint8_t)Mode::Number::AVOID_ADSB,
208 : (uint8_t)Mode::Number::GUIDED,
209 : (uint8_t)Mode::Number::THERMAL,
210 : #if HAL_QUADPLANE_ENABLED
211 : (uint8_t)Mode::Number::QSTABILIZE,
212 : (uint8_t)Mode::Number::QHOVER,
213 : (uint8_t)Mode::Number::QLOITER,
214 : (uint8_t)Mode::Number::QACRO,
215 : #if QAUTOTUNE_ENABLED
216 : (uint8_t)Mode::Number::QAUTOTUNE,
217 : #else
218 : 0xFF, // Need to use place holders for modes that can be compiled out so the bits do not change
219 : #endif // QAUTOTUNE_ENABLED
220 : (uint8_t)Mode::Number::LOITER_ALT_QLAND,
221 : #else
222 : 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
223 : #endif // HAL_QUADPLANE_ENABLED
224 : #if MODE_AUTOLAND_ENABLED
225 : (uint8_t)Mode::Number::AUTOLAND,
226 : #else
227 : 0xFF,
228 : #endif // MODE_AUTOLAND_ENABLED
229 : };
230 :
231 : // Place holders should mean that array is always the same size
232 : static_assert(ARRAY_SIZE(mode_list) == 22, "mode_list placeholders incorrect");
233 :
234 825 : return !block_GCS_mode_change((uint8_t)mode_num, mode_list, ARRAY_SIZE(mode_list));
235 : }
236 :
237 : // Return mask of enabled modes, order does not matter, its just for tracking changes
238 54357 : uint32_t Plane::get_available_mode_enabled_mask() const
239 : {
240 : // plane does not enable or disable modes at run-time.
241 : // This means that the FLTMODE_GCSBLOCK param is the only way modes will be disabled at runtime.
242 : // Rather than tracking modes we can just track the param itself for changes.
243 54357 : return ~uint32_t(flight_mode_GCS_block);
244 : }
245 :
246 3404 : bool Plane::set_mode(Mode &new_mode, const ModeReason reason)
247 : {
248 :
249 3404 : if (control_mode == &new_mode) {
250 : // don't switch modes if we are already in the correct mode.
251 : // only make happy noise if using a different method to switch, this stops beeping for repeated change mode requests from GCS
252 1452 : if ((reason != control_mode_reason) && (reason != ModeReason::INITIALISED)) {
253 648 : AP_Notify::events.user_mode_change = 1;
254 : }
255 1452 : return true;
256 : }
257 :
258 : #if HAL_QUADPLANE_ENABLED
259 1952 : if (new_mode.is_vtol_mode() && !plane.quadplane.available()) {
260 : // dont try and switch to a Q mode if quadplane is not enabled and initialized
261 0 : gcs().send_text(MAV_SEVERITY_INFO,"Q_ENABLE 0");
262 : // make sad noise
263 0 : if (reason != ModeReason::INITIALISED) {
264 0 : AP_Notify::events.user_mode_change_failed = 1;
265 : }
266 0 : return false;
267 : }
268 :
269 : #else
270 : if (new_mode.is_vtol_mode()) {
271 : INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
272 : gcs().send_text(MAV_SEVERITY_INFO,"HAL_QUADPLANE_ENABLED=0");
273 : // make sad noise
274 : if (reason != ModeReason::INITIALISED) {
275 : AP_Notify::events.user_mode_change_failed = 1;
276 : }
277 : return false;
278 : }
279 : #endif // HAL_QUADPLANE_ENABLED
280 :
281 : #if AP_FENCE_ENABLED
282 : // may not be allowed to change mode if recovering from fence breach
283 2515 : if (hal.util->get_soft_armed() &&
284 656 : fence.enabled() &&
285 185 : fence.option_enabled(AC_Fence::OPTIONS::DISABLE_MODE_CHANGE) &&
286 156 : fence.get_breaches() &&
287 2579 : in_fence_recovery() &&
288 27 : !mode_reason_is_landing_sequence(reason)) {
289 25 : gcs().send_text(MAV_SEVERITY_NOTICE,"Mode change to %s denied, in fence recovery", new_mode.name());
290 25 : AP_Notify::events.user_mode_change_failed = 1;
291 25 : return false;
292 : }
293 : #endif
294 :
295 : // Check if GCS mode change is disabled via parameter
296 1927 : if ((reason == ModeReason::GCS_COMMAND) && !gcs_mode_enabled(new_mode.mode_number())) {
297 0 : gcs().send_text(MAV_SEVERITY_NOTICE,"Mode change to %s denied, GCS entry disabled (FLTMODE_GCSBLOCK)", new_mode.name());
298 0 : return false;
299 : }
300 :
301 : // backup current control_mode and previous_mode
302 1927 : Mode &old_previous_mode = *previous_mode;
303 1927 : Mode &old_mode = *control_mode;
304 :
305 : // update control_mode assuming success
306 : // TODO: move these to be after enter() once start_command_callback() no longer checks control_mode
307 1927 : previous_mode = control_mode;
308 1927 : control_mode = &new_mode;
309 1927 : const ModeReason old_previous_mode_reason = previous_mode_reason;
310 1927 : previous_mode_reason = control_mode_reason;
311 1927 : control_mode_reason = reason;
312 :
313 : // Apply the reset before mode entry so altitude targets use the new value,
314 : // including when mode entry subsequently fails.
315 1927 : reset_alt_offset();
316 :
317 : // attempt to enter new mode
318 1927 : if (!new_mode.enter()) {
319 : // Log error that we failed to enter desired flight mode
320 1 : gcs().send_text(MAV_SEVERITY_WARNING, "Flight mode change failed");
321 :
322 : // we failed entering new mode, roll back to old
323 1 : previous_mode = &old_previous_mode;
324 1 : control_mode = &old_mode;
325 1 : control_mode_reason = previous_mode_reason;
326 1 : previous_mode_reason = old_previous_mode_reason;
327 :
328 : // make sad noise
329 1 : if (reason != ModeReason::INITIALISED) {
330 1 : AP_Notify::events.user_mode_change_failed = 1;
331 : }
332 1 : return false;
333 : }
334 :
335 : // exit previous mode
336 1926 : old_mode.exit();
337 :
338 : // log and notify mode change
339 : #if HAL_LOGGING_ENABLED
340 1926 : logger.Write_Mode(control_mode->mode_number(), control_mode_reason);
341 : #endif
342 1926 : notify_mode(*control_mode);
343 1926 : gcs().send_message(MSG_HEARTBEAT);
344 :
345 : // make happy noise
346 1926 : if (reason != ModeReason::INITIALISED) {
347 1235 : AP_Notify::events.user_mode_change = 1;
348 : }
349 1926 : return true;
350 : }
351 :
352 1153 : bool Plane::set_mode(const uint8_t new_mode, const ModeReason reason)
353 : {
354 : static_assert(sizeof(Mode::Number) == sizeof(new_mode), "The new mode can't be mapped to the vehicles mode number");
355 :
356 1153 : return set_mode_by_number(static_cast<Mode::Number>(new_mode), reason);
357 : }
358 :
359 2550 : bool Plane::set_mode_by_number(const Mode::Number new_mode_number, const ModeReason reason)
360 : {
361 2550 : Mode *new_mode = plane.mode_from_mode_num(new_mode_number);
362 2550 : if (new_mode == nullptr) {
363 0 : notify_no_such_mode(new_mode_number);
364 0 : return false;
365 : }
366 2550 : return set_mode(*new_mode, reason);
367 : }
368 :
369 167812 : void Plane::check_long_failsafe()
370 : {
371 167812 : const uint32_t gcs_last_seen_ms = gcs().sysid_mygcs_last_seen_time_ms();
372 167812 : const uint32_t rc_last_seen_ms = failsafe.last_valid_rc_ms;
373 167812 : const uint32_t tnow = millis();
374 : // only act on changes
375 : // -------------------
376 167812 : if (failsafe.state != FAILSAFE_LONG &&
377 167802 : failsafe.state != FAILSAFE_GCS &&
378 167776 : flight_stage != AP_FixedWing::FlightStage::LAND) {
379 156582 : if (failsafe.rc_failsafe &&
380 77 : (tnow - rc_last_seen_ms) > g.fs_timeout_long*1000) {
381 5 : failsafe_long_on_event(FAILSAFE_LONG, ModeReason::RADIO_FAILSAFE);
382 156500 : } else if (g.gcs_heartbeat_fs_enabled == GCS_FAILSAFE_HB_AUTO && control_mode == &mode_auto &&
383 156500 : gcs_last_seen_ms != 0 &&
384 0 : (tnow - gcs_last_seen_ms) > g.fs_timeout_long*1000) {
385 0 : failsafe_long_on_event(FAILSAFE_GCS, ModeReason::GCS_FAILSAFE);
386 156500 : } else if ((g.gcs_heartbeat_fs_enabled == GCS_FAILSAFE_HEARTBEAT ||
387 156500 : g.gcs_heartbeat_fs_enabled == GCS_FAILSAFE_HB_RSSI) &&
388 313000 : gcs_last_seen_ms != 0 &&
389 312 : (tnow - gcs_last_seen_ms) > g.fs_timeout_long*1000) {
390 5 : failsafe_long_on_event(FAILSAFE_GCS, ModeReason::GCS_FAILSAFE);
391 156495 : } else if (g.gcs_heartbeat_fs_enabled == GCS_FAILSAFE_HB_RSSI &&
392 0 : gcs().chan(0) != nullptr &&
393 156495 : gcs().chan(0)->last_radio_status_remrssi_ms() != 0 &&
394 0 : (tnow - gcs().chan(0)->last_radio_status_remrssi_ms()) > g.fs_timeout_long*1000) {
395 0 : failsafe_long_on_event(FAILSAFE_GCS, ModeReason::GCS_FAILSAFE);
396 : }
397 : } else {
398 11307 : float timeout_seconds = g.fs_timeout_long;
399 11307 : if (failsafe.state == FAILSAFE_GCS &&
400 26 : (tnow - gcs_last_seen_ms) < timeout_seconds*1000) {
401 5 : failsafe_long_off_event(ModeReason::GCS_FAILSAFE);
402 11302 : } else if (failsafe.state == FAILSAFE_LONG &&
403 10 : !failsafe.rc_failsafe) {
404 5 : failsafe_long_off_event(ModeReason::RADIO_FAILSAFE);
405 : }
406 : }
407 167812 : }
408 :
409 2736769 : void Plane::check_short_rc_failsafe()
410 : {
411 2736769 : if (g.fs_action_short != FS_ACTION_SHORT_DISABLED &&
412 5471701 : failsafe.state == FAILSAFE_NONE &&
413 2734932 : flight_stage != AP_FixedWing::FlightStage::LAND) {
414 : // The condition is checked and the flag rc_failsafe is set in radio.cpp
415 2554406 : if (failsafe.rc_failsafe) {
416 5 : rc_failsafe_short_on_event();
417 : }
418 : }
419 :
420 2736769 : if(failsafe.state == FAILSAFE_SHORT) {
421 740 : if(!failsafe.rc_failsafe || g.fs_action_short == FS_ACTION_SHORT_DISABLED) {
422 2 : rc_failsafe_short_off_event();
423 : }
424 : }
425 2736769 : }
426 :
427 :
428 692 : void Plane::startup_INS(void)
429 : {
430 692 : if (ins.gyro_calibration_timing() != AP_InertialSensor::GYRO_CAL_NEVER) {
431 61 : gcs().send_text(MAV_SEVERITY_ALERT, "Beginning INS calibration. Do not move plane");
432 : } else {
433 631 : gcs().send_text(MAV_SEVERITY_ALERT, "Skipping INS calibration");
434 : }
435 :
436 692 : ahrs.init();
437 692 : ahrs.set_fly_forward(true);
438 692 : ahrs.set_vehicle_class(AP_AHRS::VehicleClass::FIXED_WING);
439 692 : ahrs.set_wind_estimation_enabled(true);
440 :
441 692 : ins.init(scheduler.get_loop_rate_hz());
442 692 : ahrs.reset();
443 :
444 : // read Baro pressure at ground
445 : //-----------------------------
446 692 : barometer.set_log_baro_bit(MASK_LOG_IMU);
447 692 : barometer.calibrate();
448 691 : }
449 :
450 : // sets notify object flight mode information
451 2618 : void Plane::notify_mode(const Mode& mode)
452 : {
453 2618 : notify.flags.flight_mode = mode.mode_number();
454 2618 : notify.set_flight_mode_str(mode.name4());
455 2618 : }
456 :
457 : #if HAL_LOGGING_ENABLED
458 : /*
459 : should we log a message type now?
460 : */
461 45817473 : bool Plane::should_log(uint32_t mask)
462 : {
463 45817473 : return logger.should_log(mask);
464 : }
465 : #endif
466 :
467 : /*
468 : return throttle percentage from 0 to 100 for normal use and -100 to 100 when using reverse thrust
469 : */
470 1667524 : int8_t Plane::throttle_percentage(void)
471 : {
472 : #if HAL_QUADPLANE_ENABLED
473 1667524 : if (quadplane.in_vtol_mode() && !quadplane.tailsitter.in_vtol_transition()) {
474 91412 : return quadplane.motors->get_throttle_out() * 100.0;
475 : }
476 : #endif
477 1576112 : float throttle = SRV_Channels::get_output_scaled(SRV_Channel::k_throttle);
478 1576112 : if (!have_reverse_thrust()) {
479 1576112 : return constrain_int16(throttle, 0, 100);
480 : }
481 0 : return constrain_int16(throttle, -100, 100);
482 : }
|