Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ardupilot
GitHub Repository: Ardupilot/ardupilot
Path: blob/master/ArduCopter/autoyaw.cpp
9562 views
1
#include "Copter.h"
2
3
Mode::AutoYaw Mode::auto_yaw;
4
5
// roi_yaw_rad - returns heading towards location held in roi_ned_m
6
float Mode::AutoYaw::roi_yaw_rad() const
7
{
8
Vector2f pos_ne_m;
9
if (AP::ahrs().get_relative_position_NE_origin_float(pos_ne_m)){
10
return get_bearing_rad(pos_ne_m, roi_ned_m.xy());
11
}
12
return copter.attitude_control->get_att_target_euler_rad().z;
13
}
14
15
// Returns the yaw angle (in radians) representing the direction of horizontal motion.
16
float Mode::AutoYaw::look_ahead_yaw_rad()
17
{
18
// Commanded Yaw to automatically look ahead.
19
Vector3f vel_ned_ms;
20
if (copter.position_ok() && AP::ahrs().get_velocity_NED(vel_ned_ms)) {
21
const float speed_ms_sq = vel_ned_ms.xy().length_squared();
22
if (speed_ms_sq > (YAW_LOOK_AHEAD_MIN_SPEED_MS * YAW_LOOK_AHEAD_MIN_SPEED_MS)) {
23
_look_ahead_yaw_rad = atan2f(vel_ned_ms.y,vel_ned_ms.x);
24
}
25
}
26
return _look_ahead_yaw_rad;
27
}
28
29
void Mode::AutoYaw::set_mode_to_default(bool rtl)
30
{
31
set_mode(default_mode(rtl));
32
}
33
34
// default_mode - returns auto_yaw.mode() based on WP_YAW_BEHAVIOR parameter
35
// set rtl parameter to true if this is during an RTL
36
Mode::AutoYaw::Mode Mode::AutoYaw::default_mode(bool rtl) const
37
{
38
switch (copter.g.wp_yaw_behavior) {
39
40
case WP_YAW_BEHAVIOR_NONE:
41
return Mode::HOLD;
42
43
case WP_YAW_BEHAVIOR_LOOK_AT_NEXT_WP_EXCEPT_RTL:
44
if (rtl) {
45
return Mode::HOLD;
46
} else {
47
return Mode::LOOK_AT_NEXT_WP;
48
}
49
50
case WP_YAW_BEHAVIOR_LOOK_AHEAD:
51
return Mode::LOOK_AHEAD;
52
53
case WP_YAW_BEHAVIOR_LOOK_AT_NEXT_WP:
54
default:
55
return Mode::LOOK_AT_NEXT_WP;
56
}
57
}
58
59
// set_mode - sets the yaw mode for auto
60
void Mode::AutoYaw::set_mode(Mode yaw_mode)
61
{
62
// return immediately if no change
63
if (_mode == yaw_mode) {
64
return;
65
}
66
_last_mode = _mode;
67
_mode = yaw_mode;
68
69
// perform initialisation
70
switch (_mode) {
71
72
case Mode::HOLD:
73
break;
74
75
case Mode::LOOK_AT_NEXT_WP:
76
// wpnav will initialise heading when wpnav's set_destination method is called
77
break;
78
79
case Mode::ROI:
80
// look ahead until we know otherwise
81
break;
82
83
case Mode::FIXED:
84
// keep heading pointing in the direction held in fixed_yaw
85
// caller should set the fixed_yaw
86
break;
87
88
case Mode::LOOK_AHEAD:
89
// Commanded Yaw to automatically look ahead.
90
_look_ahead_yaw_rad = copter.ahrs.get_yaw_rad();
91
break;
92
93
case Mode::RESET_TO_ARMED_YAW:
94
// initial_armed_bearing_rad will be set during arming so no init required
95
break;
96
97
case Mode::ANGLE_RATE:
98
break;
99
100
case Mode::RATE:
101
// initialise target yaw rate to zero
102
_yaw_rate_rads = 0.0;
103
break;
104
105
case Mode::CIRCLE:
106
case Mode::PILOT_RATE:
107
case Mode::WEATHERVANE:
108
// no initialisation required
109
break;
110
}
111
}
112
113
// set_fixed_yaw_rad - sets the yaw look at heading for auto mode
114
void Mode::AutoYaw::set_fixed_yaw_rad(float yaw_rad, float yaw_rate_rads, int8_t direction, bool relative_angle)
115
{
116
_last_update_ms = millis();
117
const float angle_rad = yaw_rad;
118
119
// calculate final angle as relative to vehicle heading or absolute
120
if (relative_angle) {
121
if (_mode == Mode::HOLD) {
122
_yaw_angle_rad = copter.ahrs.get_yaw_rad();
123
}
124
_fixed_yaw_offset_rad = angle_rad * (direction >= 0 ? 1.0 : -1.0);
125
} else {
126
// absolute angle
127
_fixed_yaw_offset_rad = wrap_PI(angle_rad - _yaw_angle_rad);
128
if (direction < 0 && is_positive(_fixed_yaw_offset_rad)) {
129
_fixed_yaw_offset_rad -= M_2PI;
130
} else if (direction > 0 && is_negative(_fixed_yaw_offset_rad)) {
131
_fixed_yaw_offset_rad += M_2PI;
132
}
133
}
134
135
// get turn speed
136
if (!is_positive(yaw_rate_rads)) {
137
// default to default slew rate
138
_fixed_yaw_slewrate_rads = copter.attitude_control->get_slew_yaw_max_rads();
139
} else {
140
_fixed_yaw_slewrate_rads = MIN(copter.attitude_control->get_slew_yaw_max_rads(), yaw_rate_rads);
141
}
142
143
// set yaw mode
144
set_mode(Mode::FIXED);
145
}
146
147
// set_fixed_yaw_rad - sets the yaw look at heading for auto mode
148
void Mode::AutoYaw::set_yaw_angle_and_rate_rad(float yaw_angle_rad, float yaw_rate_rads)
149
{
150
_last_update_ms = millis();
151
152
_yaw_angle_rad = yaw_angle_rad;
153
_yaw_rate_rads = yaw_rate_rads;
154
155
// set yaw mode
156
set_mode(Mode::ANGLE_RATE);
157
}
158
159
// set_yaw_angle_offset_deg - sets the yaw look at heading for auto mode, as an offset from the current yaw angle
160
void Mode::AutoYaw::set_yaw_angle_offset_deg(const float yaw_angle_offset_deg)
161
{
162
_last_update_ms = millis();
163
164
_yaw_angle_rad = wrap_2PI(_yaw_angle_rad + radians(yaw_angle_offset_deg));
165
_yaw_rate_rads = 0.0f;
166
167
// set yaw mode
168
set_mode(Mode::ANGLE_RATE);
169
}
170
171
// set_roi - sets the yaw to look at roi_ned_m for auto mode
172
void Mode::AutoYaw::set_roi(const Location &roi_location)
173
{
174
// if location is zero lat, lon and altitude turn off ROI
175
if (!roi_location.initialised()) {
176
// set auto yaw mode back to default assuming the active command is a waypoint command. A more sophisticated method is required to ensure we return to the proper yaw control for the active command
177
auto_yaw.set_mode_to_default(false);
178
#if HAL_MOUNT_ENABLED
179
// switch off the camera tracking if enabled
180
copter.camera_mount.clear_roi_target();
181
#endif // HAL_MOUNT_ENABLED
182
} else {
183
#if HAL_MOUNT_ENABLED
184
// check if mount type requires us to rotate the quad
185
if (!copter.camera_mount.has_pan_control()) {
186
if (roi_location.get_vector_from_origin_NED_m(roi_ned_m)) {
187
auto_yaw.set_mode(Mode::ROI);
188
}
189
}
190
// send the command to the camera mount
191
copter.camera_mount.set_roi_target(roi_location);
192
193
// TO-DO: expand handling of the do_nav_roi to support all modes of the MAVLink. Currently we only handle mode 4 (see below)
194
// 0: do nothing
195
// 1: point at next waypoint
196
// 2: point at a waypoint taken from WP# parameter (2nd parameter?)
197
// 3: point at a location given by alt, lon, lat parameters
198
// 4: point at a target given a target id (can't be implemented)
199
#else
200
// if we have no camera mount aim the quad at the location
201
if (roi_location.get_vector_from_origin_NED_m(roi_ned_m)) {
202
auto_yaw.set_mode(Mode::ROI);
203
}
204
#endif // HAL_MOUNT_ENABLED
205
}
206
}
207
208
// set auto yaw rate in radians per second
209
void Mode::AutoYaw::set_rate_rad(float turn_rate_rads)
210
{
211
set_mode(Mode::RATE);
212
_yaw_rate_rads = turn_rate_rads;
213
}
214
215
// return true if fixed yaw target has been reached
216
bool Mode::AutoYaw::reached_fixed_yaw_target()
217
{
218
if (mode() != Mode::FIXED) {
219
// should not happen, not in the right mode
220
return true;
221
}
222
223
if (!is_zero(_fixed_yaw_offset_rad)) {
224
// still slewing yaw target
225
return false;
226
}
227
228
// Within 2 deg of target
229
return (fabsf(wrap_PI(_yaw_angle_rad - copter.ahrs.get_yaw_rad())) <= radians(2));
230
}
231
232
// yaw_rad - returns target heading depending upon auto_yaw.mode()
233
float Mode::AutoYaw::yaw_rad()
234
{
235
switch (_mode) {
236
237
case Mode::ROI:
238
// point towards a location held in roi_ned_m
239
_yaw_angle_rad = roi_yaw_rad();
240
break;
241
242
case Mode::FIXED: {
243
// keep heading pointing in the direction held in fixed_yaw
244
// with no pilot input allowed
245
const uint32_t now_ms = millis();
246
float dt = (now_ms - _last_update_ms) * 0.001;
247
_last_update_ms = now_ms;
248
float yaw_angle_step_rad = constrain_float(_fixed_yaw_offset_rad, - dt * _fixed_yaw_slewrate_rads, dt * _fixed_yaw_slewrate_rads);
249
_fixed_yaw_offset_rad -= yaw_angle_step_rad;
250
_yaw_angle_rad += yaw_angle_step_rad;
251
break;
252
}
253
254
case Mode::LOOK_AHEAD:
255
// Commanded Yaw to automatically look ahead.
256
_yaw_angle_rad = look_ahead_yaw_rad();
257
break;
258
259
case Mode::RESET_TO_ARMED_YAW:
260
// changes yaw to be same as when quad was armed
261
_yaw_angle_rad = copter.initial_armed_bearing_rad;
262
break;
263
264
case Mode::CIRCLE:
265
#if MODE_CIRCLE_ENABLED
266
if (copter.circle_nav->is_active()) {
267
_yaw_angle_rad = copter.circle_nav->get_yaw_rad();
268
}
269
#endif
270
break;
271
272
case Mode::ANGLE_RATE:{
273
const uint32_t now_ms = millis();
274
float dt = (now_ms - _last_update_ms) * 0.001;
275
_last_update_ms = now_ms;
276
_yaw_angle_rad += _yaw_rate_rads * dt;
277
break;
278
}
279
280
case Mode::RATE:
281
case Mode::WEATHERVANE:
282
case Mode::PILOT_RATE:
283
_yaw_angle_rad = copter.attitude_control->get_att_target_euler_rad().z;
284
break;
285
286
case Mode::LOOK_AT_NEXT_WP:
287
default:
288
// point towards next waypoint.
289
// we don't use wp_bearing_deg because we don't want the copter to turn too much during flight
290
_yaw_angle_rad = copter.pos_control->get_yaw_rad();
291
break;
292
}
293
return _yaw_angle_rad;
294
}
295
296
// returns yaw rate normally set by SET_POSITION_TARGET mavlink
297
// messages (positive is clockwise, negative is counter clockwise)
298
float Mode::AutoYaw::rate_rads()
299
{
300
switch (_mode) {
301
302
case Mode::HOLD:
303
case Mode::ROI:
304
case Mode::FIXED:
305
case Mode::LOOK_AHEAD:
306
case Mode::RESET_TO_ARMED_YAW:
307
case Mode::CIRCLE:
308
_yaw_rate_rads = 0.0f;
309
break;
310
311
case Mode::LOOK_AT_NEXT_WP:
312
_yaw_rate_rads = copter.pos_control->get_yaw_rate_rads();
313
break;
314
315
case Mode::PILOT_RATE:
316
_yaw_rate_rads = _pilot_yaw_rate_rads;
317
break;
318
319
case Mode::ANGLE_RATE:
320
case Mode::RATE:
321
case Mode::WEATHERVANE:
322
break;
323
}
324
325
// return zero turn rate (this should never happen)
326
return _yaw_rate_rads;
327
}
328
329
AC_AttitudeControl::HeadingCommand Mode::AutoYaw::get_heading()
330
{
331
// process pilot's yaw input
332
_pilot_yaw_rate_rads = 0.0;
333
if (rc().has_valid_input() && copter.flightmode->use_pilot_yaw()) {
334
// get pilot's desired yaw rate
335
_pilot_yaw_rate_rads = copter.flightmode->get_pilot_desired_yaw_rate_rads();
336
if (!is_zero(_pilot_yaw_rate_rads)) {
337
auto_yaw.set_mode(AutoYaw::Mode::PILOT_RATE);
338
}
339
} else if (auto_yaw.mode() == AutoYaw::Mode::PILOT_RATE) {
340
// RC failsafe, or disabled make sure not in pilot control
341
auto_yaw.set_mode(AutoYaw::Mode::HOLD);
342
}
343
344
#if WEATHERVANE_ENABLED
345
update_weathervane(_pilot_yaw_rate_rads);
346
#endif
347
348
AC_AttitudeControl::HeadingCommand heading;
349
heading.yaw_angle_rad = auto_yaw.yaw_rad();
350
heading.yaw_rate_rads = auto_yaw.rate_rads();
351
352
switch (auto_yaw.mode()) {
353
case Mode::HOLD:
354
case Mode::RATE:
355
case Mode::PILOT_RATE:
356
case Mode::WEATHERVANE:
357
heading.heading_mode = AC_AttitudeControl::HeadingMode::Rate_Only;
358
break;
359
case Mode::LOOK_AT_NEXT_WP:
360
case Mode::ROI:
361
case Mode::FIXED:
362
case Mode::LOOK_AHEAD:
363
case Mode::RESET_TO_ARMED_YAW:
364
case Mode::ANGLE_RATE:
365
case Mode::CIRCLE:
366
heading.heading_mode = AC_AttitudeControl::HeadingMode::Angle_And_Rate;
367
break;
368
}
369
370
return heading;
371
}
372
373
// handle the interface to the weathervane library
374
// pilot_yaw can be an angle or a rate or rcin from yaw channel. It just needs to represent a pilot's request to yaw the vehicle to enable pilot overrides.
375
#if WEATHERVANE_ENABLED
376
void Mode::AutoYaw::update_weathervane(const float pilot_yaw_rads)
377
{
378
if (!copter.flightmode->allows_weathervaning()) {
379
return;
380
}
381
382
float yaw_rate_cds;
383
if (copter.g2.weathervane.get_yaw_out(yaw_rate_cds, rad_to_cd(pilot_yaw_rads), copter.flightmode->get_alt_above_ground_m(),
384
copter.pos_control->get_roll_cd()-copter.attitude_control->get_roll_trim_cd(),
385
copter.pos_control->get_pitch_cd(),
386
copter.flightmode->is_taking_off(),
387
copter.flightmode->is_landing())) {
388
set_mode(Mode::WEATHERVANE);
389
_yaw_rate_rads = cd_to_rad(yaw_rate_cds);
390
return;
391
}
392
393
// if the weathervane controller has previously been activated we need to ensure we return control back to what was previously set
394
if (mode() == Mode::WEATHERVANE) {
395
_yaw_rate_rads = 0.0;
396
if (_last_mode == Mode::HOLD) {
397
set_mode_to_default(false);
398
} else {
399
set_mode(_last_mode);
400
}
401
}
402
}
403
#endif // WEATHERVANE_ENABLED
404
405