forked from ArduPilot/ardupilot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmode_smart_rtl.cpp
202 lines (177 loc) · 7.16 KB
/
mode_smart_rtl.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#include "Copter.h"
#if MODE_SMARTRTL_ENABLED == ENABLED
/*
* Init and run calls for Smart_RTL flight mode
*
* This code uses the SmartRTL path that is already in memory, and feeds it into WPNav, one point at a time.
* Once the copter is close to home, it will run a standard land controller.
*/
bool ModeSmartRTL::init(bool ignore_checks)
{
if (g2.smart_rtl.is_active()) {
// initialise waypoint and spline controller
wp_nav->wp_and_spline_init();
// set current target to a reasonable stopping point
Vector3p stopping_point;
pos_control->get_stopping_point_xy_cm(stopping_point.xy());
pos_control->get_stopping_point_z_cm(stopping_point.z);
wp_nav->set_wp_destination(stopping_point.tofloat());
// initialise yaw to obey user parameter
auto_yaw.set_mode_to_default(true);
// wait for cleanup of return path
smart_rtl_state = SubMode::WAIT_FOR_PATH_CLEANUP;
return true;
}
return false;
}
// perform cleanup required when leaving smart_rtl
void ModeSmartRTL::exit()
{
g2.smart_rtl.cancel_request_for_thorough_cleanup();
}
void ModeSmartRTL::run()
{
switch (smart_rtl_state) {
case SubMode::WAIT_FOR_PATH_CLEANUP:
wait_cleanup_run();
break;
case SubMode::PATH_FOLLOW:
path_follow_run();
break;
case SubMode::PRELAND_POSITION:
pre_land_position_run();
break;
case SubMode::DESCEND:
descent_run(); // Re-using the descend method from normal rtl mode.
break;
case SubMode::LAND:
land_run(true); // Re-using the land method from normal rtl mode.
break;
}
}
bool ModeSmartRTL::is_landing() const
{
return smart_rtl_state == SubMode::LAND;
}
void ModeSmartRTL::wait_cleanup_run()
{
// hover at current target position
motors->set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
wp_nav->update_wpnav();
pos_control->update_z_controller();
attitude_control->input_thrust_vector_heading(pos_control->get_thrust_vector(), auto_yaw.get_heading());
// check if return path is computed and if yes, begin journey home
if (g2.smart_rtl.request_thorough_cleanup()) {
path_follow_last_pop_fail_ms = 0;
smart_rtl_state = SubMode::PATH_FOLLOW;
}
}
void ModeSmartRTL::path_follow_run()
{
// if we are close to current target point, switch the next point to be our target.
if (wp_nav->reached_wp_destination()) {
Vector3f dest_NED;
// this pop_point can fail if the IO task currently has the
// path semaphore.
if (g2.smart_rtl.pop_point(dest_NED)) {
path_follow_last_pop_fail_ms = 0;
if (g2.smart_rtl.get_num_points() == 0) {
// this is the very last point, add 2m to the target alt and move to pre-land state
dest_NED.z -= 2.0f;
smart_rtl_state = SubMode::PRELAND_POSITION;
wp_nav->set_wp_destination_NED(dest_NED);
} else {
// peek at the next point. this can fail if the IO task currently has the path semaphore
Vector3f next_dest_NED;
if (g2.smart_rtl.peek_point(next_dest_NED)) {
wp_nav->set_wp_destination_NED(dest_NED);
if (g2.smart_rtl.get_num_points() == 1) {
// this is the very last point, add 2m to the target alt
next_dest_NED.z -= 2.0f;
}
wp_nav->set_wp_destination_next_NED(next_dest_NED);
} else {
// this can only happen if peek failed to take the semaphore
// send next point anyway which will cause the vehicle to slow at the next point
wp_nav->set_wp_destination_NED(dest_NED);
INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
}
}
} else if (g2.smart_rtl.get_num_points() == 0) {
// We should never get here; should always have at least
// two points and the "zero points left" is handled above.
INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
smart_rtl_state = SubMode::PRELAND_POSITION;
} else if (path_follow_last_pop_fail_ms == 0) {
// first time we've failed to pop off (ever, or after a success)
path_follow_last_pop_fail_ms = AP_HAL::millis();
} else if (AP_HAL::millis() - path_follow_last_pop_fail_ms > 10000) {
// we failed to pop a point off for 10 seconds. This is
// almost certainly a bug.
INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
smart_rtl_state = SubMode::PRELAND_POSITION;
}
}
// update controllers
motors->set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
wp_nav->update_wpnav();
pos_control->update_z_controller();
// call attitude controller with auto yaw
attitude_control->input_thrust_vector_heading(pos_control->get_thrust_vector(), auto_yaw.get_heading());
}
void ModeSmartRTL::pre_land_position_run()
{
// if we are close to 2m above start point, we are ready to land.
if (wp_nav->reached_wp_destination()) {
// choose descend and hold, or land based on user parameter rtl_alt_final
if (g.rtl_alt_final <= 0 || copter.failsafe.radio) {
land_start();
smart_rtl_state = SubMode::LAND;
} else {
set_descent_target_alt(copter.g.rtl_alt_final);
descent_start();
smart_rtl_state = SubMode::DESCEND;
}
}
// update controllers
motors->set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
wp_nav->update_wpnav();
pos_control->update_z_controller();
attitude_control->input_thrust_vector_heading(pos_control->get_thrust_vector(), auto_yaw.get_heading());
}
// save current position for use by the smart_rtl flight mode
void ModeSmartRTL::save_position()
{
const bool should_save_position = motors->armed() && (copter.flightmode->mode_number() != Mode::Number::SMART_RTL);
copter.g2.smart_rtl.update(copter.position_ok(), should_save_position);
}
bool ModeSmartRTL::get_wp(Location& destination) const
{
// provide target in states which use wp_nav
switch (smart_rtl_state) {
case SubMode::WAIT_FOR_PATH_CLEANUP:
case SubMode::PATH_FOLLOW:
case SubMode::PRELAND_POSITION:
case SubMode::DESCEND:
return wp_nav->get_wp_destination_loc(destination);
case SubMode::LAND:
return false;
}
// we should never get here but just in case
return false;
}
uint32_t ModeSmartRTL::wp_distance() const
{
return wp_nav->get_wp_distance_to_destination();
}
int32_t ModeSmartRTL::wp_bearing() const
{
return wp_nav->get_wp_bearing_to_destination();
}
bool ModeSmartRTL::use_pilot_yaw() const
{
const bool land_repositioning = g.land_repositioning && (smart_rtl_state == SubMode::DESCEND);
const bool final_landing = smart_rtl_state == SubMode::LAND;
return g2.smart_rtl.use_pilot_yaw() || land_repositioning || final_landing;
}
#endif