PX4 Firmware
PX4 Autopilot Software http://px4.io
follow_target.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2013-2016 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  * @file followme.cpp
35  *
36  * Helper class to track and follow a given position
37  *
38  * @author Jimmy Johnson <catch22@fastmail.net>
39  */
40 
41 #include "follow_target.h"
42 
43 #include <string.h>
44 #include <stdlib.h>
45 #include <stdbool.h>
46 #include <math.h>
47 #include <fcntl.h>
48 
49 #include <systemlib/err.h>
50 
51 #include <uORB/uORB.h>
54 #include <lib/ecl/geo/geo.h>
56 
57 #include "navigator.h"
58 
59 using namespace matrix;
60 
61 constexpr float FollowTarget::_follow_position_matricies[4][9];
62 
64  MissionBlock(navigator),
65  ModuleParams(navigator)
66 {
68  _step_vel.zero();
73 }
74 
76 {
78 }
79 
81 {
82  _follow_offset = _param_nav_ft_dst.get() < 1.0F ? 1.0F : _param_nav_ft_dst.get();
83 
84  _responsiveness = math::constrain((float) _param_nav_ft_rs.get(), .1F, 1.0F);
85 
86  _follow_target_position = _param_nav_ft_fs.get();
87 
88  if ((_follow_target_position > FOLLOW_FROM_LEFT) || (_follow_target_position < FOLLOW_FROM_RIGHT)) {
89  _follow_target_position = FOLLOW_FROM_BEHIND;
90  }
91 
92  _rot_matrix = Dcmf(_follow_position_matricies[_follow_target_position]);
93 }
94 
96 {
97  struct map_projection_reference_s target_ref;
98  follow_target_s target_motion_with_offset = {};
99  uint64_t current_time = hrt_absolute_time();
100  bool _radius_entered = false;
101  bool _radius_exited = false;
102  bool updated = false;
103  float dt_ms = 0;
104 
105  if (_follow_target_sub.updated()) {
106  follow_target_s target_motion;
107 
108  _target_updates++;
109 
110  // save last known motion topic
111 
113 
114  _follow_target_sub.copy(&target_motion);
115 
117  _current_target_motion = target_motion;
118  }
119 
121  _current_target_motion.lat = (_current_target_motion.lat * (double)_responsiveness) + target_motion.lat * (double)(
122  1 - _responsiveness);
123  _current_target_motion.lon = (_current_target_motion.lon * (double)_responsiveness) + target_motion.lon * (double)(
124  1 - _responsiveness);
125 
126  } else if (((current_time - _current_target_motion.timestamp) / 1000) > TARGET_TIMEOUT_MS && target_velocity_valid()) {
128  }
129 
130  // update distance to target
131 
132  if (target_position_valid()) {
133 
134  // get distance to target
135 
138  &_target_distance(1));
139 
140  }
141 
142  // update target velocity
143 
144  if (target_velocity_valid() && updated) {
145 
147 
148  // ignore a small dt
149  if (dt_ms > 10.0F) {
150  // get last gps known reference for target
152 
153  // calculate distance the target has moved
156 
157  // update the average velocity of the target based on the position
158  _est_target_vel = _target_position_delta / (dt_ms / 1000.0f);
159 
160  // if the target is moving add an offset and rotation
161  if (_est_target_vel.length() > .5F) {
163  }
164 
165  // are we within the target acceptance radius?
166  // give a buffer to exit/enter the radius to give the velocity controller
167  // a chance to catch up
168 
169  _radius_exited = ((_target_position_offset + _target_distance).length() > (float) TARGET_ACCEPTANCE_RADIUS_M * 1.5f);
170  _radius_entered = ((_target_position_offset + _target_distance).length() < (float) TARGET_ACCEPTANCE_RADIUS_M);
171 
172  // to keep the velocity increase/decrease smooth
173  // calculate how many velocity increments/decrements
174  // it will take to reach the targets velocity
175  // with the given amount of steps also add a feed forward input that adjusts the
176  // velocity as the position gap increases since
177  // just traveling at the exact velocity of the target will not
178  // get any closer or farther from the target
179 
181  _step_vel /= (dt_ms / 1000.0F * (float) INTERPOLATION_PNTS);
182  _step_time_in_ms = (dt_ms / (float) INTERPOLATION_PNTS);
183 
184  // if we are less than 1 meter from the target don't worry about trying to yaw
185  // lock the yaw until we are at a distance that makes sense
186 
187  if ((_target_distance).length() > 1.0F) {
188 
189  // yaw rate smoothing
190 
191  // this really needs to control the yaw rate directly in the attitude pid controller
192  // but seems to work ok for now since the yaw rate cannot be controlled directly in auto mode
193 
198 
199  _yaw_rate = wrap_pi((_yaw_angle - _navigator->get_global_position()->yaw) / (dt_ms / 1000.0f));
200 
201  } else {
202  _yaw_angle = _yaw_rate = NAN;
203  }
204  }
205 
206 // warnx(" _step_vel x %3.6f y %3.6f cur vel %3.6f %3.6f tar vel %3.6f %3.6f dist = %3.6f (%3.6f) mode = %d yaw rate = %3.6f",
207 // (double) _step_vel(0),
208 // (double) _step_vel(1),
209 // (double) _current_vel(0),
210 // (double) _current_vel(1),
211 // (double) _est_target_vel(0),
212 // (double) _est_target_vel(1),
213 // (double) (_target_distance).length(),
214 // (double) (_target_position_offset + _target_distance).length(),
215 // _follow_target_state,
216 // (double) _yaw_rate);
217  }
218 
219  if (target_position_valid()) {
220 
221  // get the target position using the calculated offset
222 
225  &target_motion_with_offset.lat, &target_motion_with_offset.lon);
226  }
227 
228  // clamp yaw rate smoothing if we are with in
229  // 3 degrees of facing target
230 
231  if (PX4_ISFINITE(_yaw_rate)) {
232  if (fabsf(fabsf(_yaw_angle) - fabsf(_navigator->get_global_position()->yaw)) < math::radians(3.0F)) {
233  _yaw_rate = NAN;
234  }
235  }
236 
237  // update state machine
238 
239  switch (_follow_target_state) {
240 
241  case TRACK_POSITION: {
242 
243  if (_radius_entered) {
244  _follow_target_state = TRACK_VELOCITY;
245 
246  } else if (target_velocity_valid()) {
247  set_follow_target_item(&_mission_item, _param_nav_min_ft_ht.get(), target_motion_with_offset, _yaw_angle);
248  // keep the current velocity updated with the target velocity for when it's needed
250 
251  update_position_sp(true, true, _yaw_rate);
252 
253  } else {
254  _follow_target_state = SET_WAIT_FOR_TARGET_POSITION;
255  }
256 
257  break;
258  }
259 
260  case TRACK_VELOCITY: {
261 
262  if (_radius_exited) {
263  _follow_target_state = TRACK_POSITION;
264 
265  } else if (target_velocity_valid()) {
266 
267  if ((float)(current_time - _last_update_time) / 1000.0f >= _step_time_in_ms) {
269  _last_update_time = current_time;
270  }
271 
272  set_follow_target_item(&_mission_item, _param_nav_min_ft_ht.get(), target_motion_with_offset, _yaw_angle);
273 
274  update_position_sp(true, false, _yaw_rate);
275 
276  } else {
277  _follow_target_state = SET_WAIT_FOR_TARGET_POSITION;
278  }
279 
280  break;
281  }
282 
284 
285  // Climb to the minimum altitude
286  // and wait until a position is received
287 
288  follow_target_s target = {};
289 
290  // for now set the target at the minimum height above the uav
291 
292  target.lat = _navigator->get_global_position()->lat;
293  target.lon = _navigator->get_global_position()->lon;
294  target.alt = 0.0F;
295 
296  set_follow_target_item(&_mission_item, _param_nav_min_ft_ht.get(), target, _yaw_angle);
297 
298  update_position_sp(false, false, _yaw_rate);
299 
300  _follow_target_state = WAIT_FOR_TARGET_POSITION;
301  }
302 
303  /* FALLTHROUGH */
304 
306 
309  _follow_target_state = TRACK_POSITION;
310  }
311 
312  break;
313  }
314  }
315 }
316 
317 void FollowTarget::update_position_sp(bool use_velocity, bool use_position, float yaw_rate)
318 {
319  // convert mission item to current setpoint
320 
322 
323  // activate line following in pos control if position is valid
324 
325  pos_sp_triplet->previous.valid = use_position;
326  pos_sp_triplet->previous = pos_sp_triplet->current;
329  pos_sp_triplet->current.type = position_setpoint_s::SETPOINT_TYPE_FOLLOW_TARGET;
330  pos_sp_triplet->current.position_valid = use_position;
331  pos_sp_triplet->current.velocity_valid = use_velocity;
332  pos_sp_triplet->current.vx = _current_vel(0);
333  pos_sp_triplet->current.vy = _current_vel(1);
334  pos_sp_triplet->next.valid = false;
335  pos_sp_triplet->current.yawspeed_valid = PX4_ISFINITE(yaw_rate);
336  pos_sp_triplet->current.yawspeed = yaw_rate;
338 }
339 
341 {
342  _yaw_rate = NAN;
345  _target_updates = 0;
346  _current_vel.zero();
347  _step_vel.zero();
352  _follow_target_state = SET_WAIT_FOR_TARGET_POSITION;
353 }
354 
356 {
357  // need at least 2 continuous data points for velocity estimate
358  return (_target_updates >= 2);
359 }
360 
362 {
363  // need at least 1 continuous data points for position estimate
364  return (_target_updates >= 1);
365 }
366 
367 void
368 FollowTarget::set_follow_target_item(struct mission_item_s *item, float min_clearance, follow_target_s &target,
369  float yaw)
370 {
372  /* landed, don't takeoff, but switch to IDLE mode */
373  item->nav_cmd = NAV_CMD_IDLE;
374 
375  } else {
376 
378 
379  /* use current target position */
380  item->lat = target.lat;
381  item->lon = target.lon;
383 
384  if (min_clearance > 8.0f) {
385  item->altitude += min_clearance;
386 
387  } else {
388  item->altitude += 8.0f; // if min clearance is bad set it to 8.0 meters (well above the average height of a person)
389  }
390  }
391 
392  item->altitude_is_relative = false;
393  item->yaw = yaw;
396  item->time_inside = 0.0f;
397  item->autocontinue = false;
398  item->origin = ORIGIN_ONBOARD;
399 }
matrix::Dcmf _rot_matrix
constexpr _Tp constrain(_Tp val, _Tp min_val, _Tp max_val)
Definition: Limits.hpp:66
Global position setpoint in WGS84 coordinates.
Definition: navigation.h:145
static constexpr int INTERPOLATION_PNTS
Definition: follow_target.h:68
static constexpr float FF_K
Definition: follow_target.h:69
float get_acceptance_radius()
Get the acceptance radius.
API for the uORB lightweight object broker.
Definition of geo / math functions to perform geodesic calculations.
float altitude
altitude in meters (AMSL)
Definition: navigation.h:160
matrix::Vector3f _target_position_offset
Dcm< float > Dcmf
Definition: Dcm.hpp:185
uint16_t autocontinue
true if next waypoint should follow after this one
Definition: navigation.h:177
float acceptance_radius
default radius in which the mission is accepted as reached in meters
Definition: navigation.h:155
bool target_velocity_valid()
struct position_setpoint_s next
void set_follow_target_item(struct mission_item_s *item, float min_clearance, follow_target_s &target, float yaw)
Set follow_target item.
struct home_position_s * get_home_position()
Getters.
Definition: navigator.h:151
void on_active() override
This function is called while the mode is active.
FollowTarget(Navigator *navigator)
Limiting / constrain helper functions.
uint16_t origin
how the mission item was generated
Definition: navigation.h:177
struct position_setpoint_s previous
struct vehicle_land_detected_s * get_land_detected()
Definition: navigator.h:157
int _follow_target_position
double lon
longitude in degrees
Definition: navigation.h:147
Navigator * _navigator
matrix::Vector3f _step_vel
void on_inactive() override
This function is called while the mode is inactive.
uORB::Subscription _follow_target_sub
bool target_position_valid()
struct position_setpoint_s current
int map_projection_reproject(const struct map_projection_reference_s *ref, float x, float y, double *lat, double *lon)
Transforms a point in the local azimuthal equidistant plane to the geographic coordinate system using...
Definition: geo.cpp:166
struct vehicle_global_position_s * get_global_position()
Definition: navigator.h:156
mission_item_s _mission_item
uint16_t nav_cmd
navigation command
Definition: navigation.h:165
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
void mission_apply_limitation(mission_item_s &item)
General function used to adjust the mission item based on vehicle specific limitations.
Type length() const
Definition: Vector.hpp:83
follow_target_s _current_target_motion
Simple error/warning functions, heavily inspired by the BSD functions of the same names...
float get_bearing_to_next_waypoint(double lat_now, double lon_now, double lat_next, double lon_next)
Returns the bearing to the next waypoint in radians.
Definition: geo.cpp:320
uint64_t _target_updates
void reset_mission_item_reached()
Reset all reached flags.
void reset_target_validity()
void zero()
Definition: Matrix.hpp:421
float time_inside
time that the MAV should stay inside the radius before advancing in seconds
Definition: navigation.h:151
bool updated()
Check if there is a new update.
void update_position_sp(bool velocity_valid, bool position_valid, float yaw_rate)
static constexpr int TARGET_TIMEOUT_MS
Definition: follow_target.h:66
float _follow_offset
Type wrap_pi(Type x)
Wrap value in range [-π, π)
matrix::Vector3f _current_vel
struct position_setpoint_triplet_s * get_position_setpoint_triplet()
Definition: navigator.h:153
matrix::Vector3f _target_distance
Vector3 normalized() const
Definition: Vector3.hpp:104
void on_activation() override
This function is called one time when mode becomes active, pos_sp_triplet must be initialized here...
static constexpr int TARGET_ACCEPTANCE_RADIUS_M
Definition: follow_target.h:67
uint64_t _last_update_time
float _responsiveness
int map_projection_project(const struct map_projection_reference_s *ref, double lat, double lon, float *x, float *y)
Definition: geo.cpp:132
bool mission_item_to_position_setpoint(const mission_item_s &item, position_setpoint_s *sp)
Convert a mission item to a position setpoint.
bool is_mission_item_reached()
Check if mission item has been reached.
float get_loiter_radius()
Definition: navigator.h:171
matrix::Vector3f _target_position_delta
float _step_time_in_ms
uint64_t timestamp
Definition: follow_target.h:53
matrix::Vector3f _est_target_vel
int map_projection_init(struct map_projection_reference_s *ref, double lat_0, double lon_0)
Initializes the map transformation given by the argument and sets the timestamp to now...
Definition: geo.cpp:105
static constexpr float _follow_position_matricies[4][9]
Definition: follow_target.h:86
bool copy(void *dst)
Copy the struct.
float yaw
in radians NED -PI..+PI, NAN means don&#39;t change yaw
Definition: navigation.h:157
float loiter_radius
loiter radius in meters, 0 for a VTOL to hover, negative for counter-clockwise
Definition: navigation.h:156
void set_position_setpoint_triplet_updated()
Definition: navigator.h:145
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
follow_target_s _previous_target_motion
uint16_t altitude_is_relative
true if altitude is relative from start point
Definition: navigation.h:177
double lat
latitude in degrees
Definition: navigation.h:146