forked from ArduPilot/ardupilot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathavoidance_adsb.cpp
254 lines (219 loc) · 8.48 KB
/
avoidance_adsb.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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#include "Copter.h"
#include <AP_Notify/AP_Notify.h>
#if ADSB_ENABLED == ENABLED
void Copter::avoidance_adsb_update(void)
{
adsb.update();
avoidance_adsb.update();
}
#include <stdio.h>
MAV_COLLISION_ACTION AP_Avoidance_Copter::handle_avoidance(const AP_Avoidance::Obstacle *obstacle, MAV_COLLISION_ACTION requested_action)
{
MAV_COLLISION_ACTION actual_action = requested_action;
bool failsafe_state_change = false;
// check for changes in failsafe
if (!copter.failsafe.adsb) {
copter.failsafe.adsb = true;
failsafe_state_change = true;
// record flight mode in case it's required for the recovery
prev_control_mode = copter.control_mode;
}
// take no action in some flight modes
if (copter.control_mode == LAND ||
#if MODE_THROW_ENABLED == ENABLED
copter.control_mode == THROW ||
#endif
copter.control_mode == FLIP) {
actual_action = MAV_COLLISION_ACTION_NONE;
}
// if landed and we will take some kind of action, just disarm
if ((actual_action > MAV_COLLISION_ACTION_REPORT) && copter.should_disarm_on_failsafe()) {
copter.arming.disarm();
actual_action = MAV_COLLISION_ACTION_NONE;
} else {
// take action based on requested action
switch (actual_action) {
case MAV_COLLISION_ACTION_RTL:
// attempt to switch to RTL, if this fails (i.e. flying in manual mode with bad position) do nothing
if (failsafe_state_change) {
if (!copter.set_mode(RTL, MODE_REASON_AVOIDANCE)) {
actual_action = MAV_COLLISION_ACTION_NONE;
}
}
break;
case MAV_COLLISION_ACTION_HOVER:
// attempt to switch to Loiter, if this fails (i.e. flying in manual mode with bad position) do nothing
if (failsafe_state_change) {
if (!copter.set_mode(LOITER, MODE_REASON_AVOIDANCE)) {
actual_action = MAV_COLLISION_ACTION_NONE;
}
}
break;
case MAV_COLLISION_ACTION_ASCEND_OR_DESCEND:
// climb or descend to avoid obstacle
if (!handle_avoidance_vertical(obstacle, failsafe_state_change)) {
actual_action = MAV_COLLISION_ACTION_NONE;
}
break;
case MAV_COLLISION_ACTION_MOVE_HORIZONTALLY:
// move horizontally to avoid obstacle
if (!handle_avoidance_horizontal(obstacle, failsafe_state_change)) {
actual_action = MAV_COLLISION_ACTION_NONE;
}
break;
case MAV_COLLISION_ACTION_MOVE_PERPENDICULAR:
if (!handle_avoidance_perpendicular(obstacle, failsafe_state_change)) {
actual_action = MAV_COLLISION_ACTION_NONE;
}
break;
// unsupported actions and those that require no response
case MAV_COLLISION_ACTION_NONE:
return actual_action;
case MAV_COLLISION_ACTION_REPORT:
default:
break;
}
}
if (failsafe_state_change) {
AP::logger().Write_Error(LogErrorSubsystem::FAILSAFE_ADSB,
LogErrorCode(actual_action));
}
// return with action taken
return actual_action;
}
void AP_Avoidance_Copter::handle_recovery(uint8_t recovery_action)
{
// check we are coming out of failsafe
if (copter.failsafe.adsb) {
copter.failsafe.adsb = false;
AP::logger().Write_Error(LogErrorSubsystem::FAILSAFE_ADSB,
LogErrorCode::ERROR_RESOLVED);
// restore flight mode if requested and user has not changed mode since
if (copter.control_mode_reason == MODE_REASON_AVOIDANCE) {
switch (recovery_action) {
case AP_AVOIDANCE_RECOVERY_REMAIN_IN_AVOID_ADSB:
// do nothing, we'll stay in the AVOID_ADSB mode which is guided which will loiter forever
break;
case AP_AVOIDANCE_RECOVERY_RESUME_PREVIOUS_FLIGHTMODE:
set_mode_else_try_RTL_else_LAND(prev_control_mode);
break;
case AP_AVOIDANCE_RECOVERY_RTL:
set_mode_else_try_RTL_else_LAND(RTL);
break;
case AP_AVOIDANCE_RECOVERY_RESUME_IF_AUTO_ELSE_LOITER:
if (prev_control_mode == AUTO) {
set_mode_else_try_RTL_else_LAND(AUTO);
}
break;
default:
break;
} // switch
}
}
}
void AP_Avoidance_Copter::set_mode_else_try_RTL_else_LAND(control_mode_t mode)
{
if (!copter.set_mode(mode, MODE_REASON_AVOIDANCE_RECOVERY)) {
// on failure RTL or LAND
if (!copter.set_mode(RTL, MODE_REASON_AVOIDANCE_RECOVERY)) {
copter.set_mode(LAND, MODE_REASON_AVOIDANCE_RECOVERY);
}
}
}
// check flight mode is avoid_adsb
bool AP_Avoidance_Copter::check_flightmode(bool allow_mode_change)
{
// ensure copter is in avoid_adsb mode
if (allow_mode_change && copter.control_mode != AVOID_ADSB) {
if (!copter.set_mode(AVOID_ADSB, MODE_REASON_AVOIDANCE)) {
// failed to set mode so exit immediately
return false;
}
}
// check flight mode
return (copter.control_mode == AVOID_ADSB);
}
bool AP_Avoidance_Copter::handle_avoidance_vertical(const AP_Avoidance::Obstacle *obstacle, bool allow_mode_change)
{
// ensure copter is in avoid_adsb mode
if (!check_flightmode(allow_mode_change)) {
return false;
}
// decide on whether we should climb or descend
bool should_climb = false;
Location my_loc;
if (AP::ahrs().get_position(my_loc)) {
should_climb = my_loc.alt > obstacle->_location.alt;
}
// get best vector away from obstacle
Vector3f velocity_neu;
if (should_climb) {
velocity_neu.z = copter.wp_nav->get_default_speed_up();
} else {
velocity_neu.z = -copter.wp_nav->get_default_speed_down();
// do not descend if below RTL alt
if (copter.current_loc.alt < copter.g.rtl_altitude) {
velocity_neu.z = 0.0f;
}
}
// send target velocity
copter.mode_avoid_adsb.set_velocity(velocity_neu);
return true;
}
bool AP_Avoidance_Copter::handle_avoidance_horizontal(const AP_Avoidance::Obstacle *obstacle, bool allow_mode_change)
{
// ensure copter is in avoid_adsb mode
if (!check_flightmode(allow_mode_change)) {
return false;
}
// get best vector away from obstacle
Vector3f velocity_neu;
if (get_vector_perpendicular(obstacle, velocity_neu)) {
// remove vertical component
velocity_neu.z = 0.0f;
// check for divide by zero
if (is_zero(velocity_neu.x) && is_zero(velocity_neu.y)) {
return false;
}
// re-normalise
velocity_neu.normalize();
// convert horizontal components to velocities
velocity_neu.x *= copter.wp_nav->get_default_speed_xy();
velocity_neu.y *= copter.wp_nav->get_default_speed_xy();
// send target velocity
copter.mode_avoid_adsb.set_velocity(velocity_neu);
return true;
}
// if we got this far we failed to set the new target
return false;
}
bool AP_Avoidance_Copter::handle_avoidance_perpendicular(const AP_Avoidance::Obstacle *obstacle, bool allow_mode_change)
{
// ensure copter is in avoid_adsb mode
if (!check_flightmode(allow_mode_change)) {
return false;
}
// get best vector away from obstacle
Vector3f velocity_neu;
if (get_vector_perpendicular(obstacle, velocity_neu)) {
// convert horizontal components to velocities
velocity_neu.x *= copter.wp_nav->get_default_speed_xy();
velocity_neu.y *= copter.wp_nav->get_default_speed_xy();
// use up and down waypoint speeds
if (velocity_neu.z > 0.0f) {
velocity_neu.z *= copter.wp_nav->get_default_speed_up();
} else {
velocity_neu.z *= copter.wp_nav->get_default_speed_down();
// do not descend if below RTL alt
if (copter.current_loc.alt < copter.g.rtl_altitude) {
velocity_neu.z = 0.0f;
}
}
// send target velocity
copter.mode_avoid_adsb.set_velocity(velocity_neu);
return true;
}
// if we got this far we failed to set the new target
return false;
}
#endif