PX4 Firmware
PX4 Autopilot Software http://px4.io
precland.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2017 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 precland.cpp
35  *
36  * Helper class to do precision landing with a landing target
37  *
38  * @author Nicolas de Palezieux (Sunflower Labs) <ndepal@gmail.com>
39  */
40 
41 #include "precland.h"
42 #include "navigator.h"
43 
44 #include <string.h>
45 #include <stdlib.h>
46 #include <stdbool.h>
47 #include <math.h>
48 #include <fcntl.h>
49 
50 #include <systemlib/err.h>
51 #include <systemlib/mavlink_log.h>
52 
53 #include <uORB/uORB.h>
57 
58 #define SEC2USEC 1000000.0f
59 
60 #define STATE_TIMEOUT 10000000 // [us] Maximum time to spend in any state
61 
63  MissionBlock(navigator),
64  ModuleParams(navigator)
65 {
66  _handle_param_acceleration_hor = param_find("MPC_ACC_HOR");
67  _handle_param_xy_vel_cruise = param_find("MPC_XY_CRUISE");
68 
69  updateParams();
70 }
71 
72 void
74 {
76  _search_cnt = 0;
78 
79  vehicle_local_position_s *vehicle_local_position = _navigator->get_local_position();
80 
82  map_projection_init(&_map_ref, vehicle_local_position->ref_lat, vehicle_local_position->ref_lon);
83  }
84 
86 
87  pos_sp_triplet->next.valid = false;
88 
89  // Check that the current position setpoint is valid, otherwise land at current position
90  if (!pos_sp_triplet->current.valid) {
91  PX4_WARN("Resetting landing position to current position");
92  pos_sp_triplet->current.lat = _navigator->get_global_position()->lat;
93  pos_sp_triplet->current.lon = _navigator->get_global_position()->lon;
94  pos_sp_triplet->current.alt = _navigator->get_global_position()->alt;
95  pos_sp_triplet->current.valid = true;
96  pos_sp_triplet->current.timestamp = hrt_absolute_time();
97  }
98 
99  _sp_pev = matrix::Vector2f(0, 0);
102 
104 }
105 
106 void
108 {
109  // get new target measurement
111 
112  if (_target_pose_updated) {
113  _target_pose_valid = true;
114  }
115 
116  if ((hrt_elapsed_time(&_target_pose.timestamp) / 1e6f) > _param_pld_btout.get()) {
117  _target_pose_valid = false;
118  }
119 
120  // stop if we are landed
123  }
124 
125  switch (_state) {
127  run_state_start();
128  break;
129 
132  break;
133 
136  break;
137 
140  break;
141 
144  break;
145 
148  break;
149 
150  case PrecLandState::Done:
151  // nothing to do
152  break;
153 
154  default:
155  // unknown state
156  break;
157  }
158 
159 }
160 
161 void
163 {
164  ModuleParams::updateParams();
165 
166  if (_handle_param_acceleration_hor != PARAM_INVALID) {
167  param_get(_handle_param_acceleration_hor, &_param_acceleration_hor);
168  }
169 
172  }
173 }
174 
175 void
177 {
178  // check if target visible and go to horizontal approach
180  return;
181  }
182 
184  // could not see the target immediately, so just fall back to normal landing
185  if (!switch_to_state_fallback()) {
186  PX4_ERR("Can't switch to search or fallback landing");
187  }
188  }
189 
191  float dist = get_distance_to_next_waypoint(pos_sp_triplet->current.lat, pos_sp_triplet->current.lon,
193 
194  // check if we've reached the start point
195  if (dist < _navigator->get_acceptance_radius()) {
196  if (!_point_reached_time) {
198  }
199 
200  // if we don't see the target after 1 second, search for it
201  if (_param_pld_srch_tout.get() > 0) {
202 
203  if (hrt_absolute_time() - _point_reached_time > 2000000) {
204  if (!switch_to_state_search()) {
205  if (!switch_to_state_fallback()) {
206  PX4_ERR("Can't switch to search or fallback landing");
207  }
208  }
209  }
210 
211  } else {
212  if (!switch_to_state_fallback()) {
213  PX4_ERR("Can't switch to search or fallback landing");
214  }
215  }
216  }
217 }
218 
219 void
221 {
223 
224  // check if target visible, if not go to start
226  PX4_WARN("Lost landing target while landing (horizontal approach).");
227 
228  // Stay at current position for searching for the landing target
229  pos_sp_triplet->current.lat = _navigator->get_global_position()->lat;
230  pos_sp_triplet->current.lon = _navigator->get_global_position()->lon;
231  pos_sp_triplet->current.alt = _navigator->get_global_position()->alt;
232 
233  if (!switch_to_state_start()) {
234  if (!switch_to_state_fallback()) {
235  PX4_ERR("Can't switch to fallback landing");
236  }
237  }
238 
239  return;
240  }
241 
243  if (!_point_reached_time) {
245  }
246 
247  if (hrt_absolute_time() - _point_reached_time > 2000000) {
248  // if close enough for descent above target go to descend above target
250  return;
251  }
252  }
253 
254  }
255 
257  PX4_ERR("Precision landing took too long during horizontal approach phase.");
258 
259  if (switch_to_state_fallback()) {
260  return;
261  }
262 
263  PX4_ERR("Can't switch to fallback landing");
264  }
265 
266  float x = _target_pose.x_abs;
267  float y = _target_pose.y_abs;
268 
269  slewrate(x, y);
270 
271  // XXX need to transform to GPS coords because mc_pos_control only looks at that
272  double lat, lon;
273  map_projection_reproject(&_map_ref, x, y, &lat, &lon);
274 
275  pos_sp_triplet->current.lat = lat;
276  pos_sp_triplet->current.lon = lon;
277  pos_sp_triplet->current.alt = _approach_alt;
278  pos_sp_triplet->current.type = position_setpoint_s::SETPOINT_TYPE_POSITION;
279 
281 }
282 
283 void
285 {
287 
288  // check if target visible
291  PX4_WARN("Lost landing target while landing (descending).");
292 
293  // Stay at current position for searching for the target
294  pos_sp_triplet->current.lat = _navigator->get_global_position()->lat;
295  pos_sp_triplet->current.lon = _navigator->get_global_position()->lon;
296  pos_sp_triplet->current.alt = _navigator->get_global_position()->alt;
297 
298  if (!switch_to_state_start()) {
299  if (!switch_to_state_fallback()) {
300  PX4_ERR("Can't switch to fallback landing");
301  }
302  }
303  }
304 
305  return;
306  }
307 
308  // XXX need to transform to GPS coords because mc_pos_control only looks at that
309  double lat, lon;
311 
312  pos_sp_triplet->current.lat = lat;
313  pos_sp_triplet->current.lon = lon;
314 
315  pos_sp_triplet->current.type = position_setpoint_s::SETPOINT_TYPE_LAND;
316 
318 }
319 
320 void
322 {
323  // nothing to do, will land
324 }
325 
326 void
328 {
329  // check if we can see the target
331  if (!_target_acquired_time) {
332  // target just became visible. Stop climbing, but give it some margin so we don't stop too apruptly
335  float new_alt = _navigator->get_global_position()->alt + 1.0f;
336  pos_sp_triplet->current.alt = new_alt < pos_sp_triplet->current.alt ? new_alt : pos_sp_triplet->current.alt;
338  }
339 
340  }
341 
342  // stay at that height for a second to allow the vehicle to settle
344  // try to switch to horizontal approach
346  return;
347  }
348  }
349 
350  // check if search timed out and go to fallback
351  if (hrt_absolute_time() - _state_start_time > _param_pld_srch_tout.get()*SEC2USEC) {
352  PX4_WARN("Search timed out");
353 
354  if (!switch_to_state_fallback()) {
355  PX4_ERR("Can't switch to fallback landing");
356  }
357  }
358 }
359 
360 void
362 {
363  // nothing to do, will land
364 }
365 
366 bool
368 {
371  pos_sp_triplet->current.type = position_setpoint_s::SETPOINT_TYPE_POSITION;
373  _search_cnt++;
374 
376 
379  return true;
380  }
381 
382  return false;
383 }
384 
385 bool
387 {
390 
392 
395  return true;
396  }
397 
398  return false;
399 }
400 
401 bool
403 {
407  return true;
408  }
409 
410  return false;
411 }
412 
413 bool
415 {
419  return true;
420  }
421 
422  return false;
423 }
424 
425 bool
427 {
428  PX4_INFO("Climbing to search altitude.");
429  vehicle_local_position_s *vehicle_local_position = _navigator->get_local_position();
430 
432  pos_sp_triplet->current.alt = vehicle_local_position->ref_alt + _param_pld_srch_alt.get();
433  pos_sp_triplet->current.type = position_setpoint_s::SETPOINT_TYPE_POSITION;
435 
437 
440  return true;
441 }
442 
443 bool
445 {
446  PX4_WARN("Falling back to normal land.");
448  pos_sp_triplet->current.lat = _navigator->get_global_position()->lat;
449  pos_sp_triplet->current.lon = _navigator->get_global_position()->lon;
450  pos_sp_triplet->current.alt = _navigator->get_global_position()->alt;
451  pos_sp_triplet->current.type = position_setpoint_s::SETPOINT_TYPE_LAND;
453 
456  return true;
457 }
458 
459 bool
461 {
464  return true;
465 }
466 
468 {
469  vehicle_local_position_s *vehicle_local_position = _navigator->get_local_position();
470 
471  switch (state) {
473  return _search_cnt <= _param_pld_max_srch.get();
474 
476 
477  // if we're already in this state, only want to make it invalid if we reached the target but can't see it anymore
479  if (fabsf(_target_pose.x_abs - vehicle_local_position->x) < _param_pld_hacc_rad.get()
480  && fabsf(_target_pose.y_abs - vehicle_local_position->y) < _param_pld_hacc_rad.get()) {
481  // we've reached the position where we last saw the target. If we don't see it now, we need to do something
483 
484  } else {
485  // We've seen the target sometime during horizontal approach.
486  // Even if we don't see it as we're moving towards it, continue approaching last known location
487  return true;
488  }
489  }
490 
491  // If we're trying to switch to this state, the target needs to be visible
493 
495 
496  // if we're already in this state, only leave it if target becomes unusable, don't care about horizontall offset to target
498  // if we're close to the ground, we're more critical of target timeouts so we quickly go into descend
500  return hrt_absolute_time() - _target_pose.timestamp < 500000; // 0.5s
501 
502  } else {
504  }
505 
506  } else {
507  // if not already in this state, need to be above target to enter it
509  && fabsf(_target_pose.x_abs - vehicle_local_position->x) < _param_pld_hacc_rad.get()
510  && fabsf(_target_pose.y_abs - vehicle_local_position->y) < _param_pld_hacc_rad.get();
511  }
512 
515  && (_target_pose.z_abs - vehicle_local_position->z) < _param_pld_fappr_alt.get();
516 
518  return true;
519 
521  return true;
522 
523  default:
524  return false;
525  }
526 }
527 
528 void PrecLand::slewrate(float &sp_x, float &sp_y)
529 {
530  matrix::Vector2f sp_curr(sp_x, sp_y);
531  uint64_t now = hrt_absolute_time();
532 
533  float dt = (now - _last_slewrate_time);
534 
535  if (dt < 1) {
536  // bad dt, can't divide by it
537  return;
538  }
539 
540  dt /= SEC2USEC;
541 
542  if (!_last_slewrate_time) {
543  // running the first time since switching to precland
544 
545  // assume dt will be about 50000us
546  dt = 50000 / SEC2USEC;
547 
548  // set a best guess for previous setpoints for smooth transition
553  }
554 
555  _last_slewrate_time = now;
556 
557  // limit the setpoint speed to the maximum cruise speed
558  matrix::Vector2f sp_vel = (sp_curr - _sp_pev) / dt; // velocity of the setpoints
559 
560  if (sp_vel.length() > _param_xy_vel_cruise) {
561  sp_vel = sp_vel.normalized() * _param_xy_vel_cruise;
562  sp_curr = _sp_pev + sp_vel * dt;
563  }
564 
565  // limit the setpoint acceleration to the maximum acceleration
566  matrix::Vector2f sp_acc = (sp_curr - _sp_pev * 2 + _sp_pev_prev) / (dt * dt); // acceleration of the setpoints
567 
568  if (sp_acc.length() > _param_acceleration_hor) {
569  sp_acc = sp_acc.normalized() * _param_acceleration_hor;
570  sp_curr = _sp_pev * 2 - _sp_pev_prev + sp_acc * (dt * dt);
571  }
572 
573  // limit the setpoint speed such that we can stop at the setpoint given the maximum acceleration/deceleration
574  float max_spd = sqrtf(_param_acceleration_hor * ((matrix::Vector2f)(_sp_pev - matrix::Vector2f(sp_x,
575  sp_y))).length());
576  sp_vel = (sp_curr - _sp_pev) / dt; // velocity of the setpoints
577 
578  if (sp_vel.length() > max_spd) {
579  sp_vel = sp_vel.normalized() * max_spd;
580  sp_curr = _sp_pev + sp_vel * dt;
581  }
582 
584  _sp_pev = sp_curr;
585 
586  sp_x = sp_curr(0);
587  sp_y = sp_curr(1);
588 }
uint64_t _state_start_time
time when we entered current state
Definition: precland.h:113
#define PARAM_INVALID
Handle returned when a parameter cannot be found.
Definition: param.h:103
void run_state_fallback()
Definition: precland.cpp:361
bool _target_pose_valid
whether we have received a landing target position message
Definition: precland.h:108
uint64_t _target_acquired_time
time when we first saw the landing target during search
Definition: precland.h:115
PrecLand(Navigator *navigator)
Definition: precland.cpp:62
Helper class to do precision landing with a landing target.
#define STATE_TIMEOUT
Definition: precland.cpp:60
static enum @74 state
__EXPORT int param_get(param_t param, void *val)
Copy the value of a parameter.
Definition: parameters.cpp:589
API for the uORB lightweight object broker.
bool map_projection_initialized(const struct map_projection_reference_s *ref)
Checks if projection given as argument was initialized.
Definition: geo.cpp:68
float get_distance_to_next_waypoint(double lat_now, double lon_now, double lat_next, double lon_next)
Returns the distance to the next waypoint in meters.
Definition: geo.cpp:270
reference for local/global projections
Definition: precland.h:111
struct position_setpoint_s next
bool switch_to_state_search()
Definition: precland.cpp:426
int _search_cnt
counter of how many times we had to search for the landing target
Definition: precland.h:118
#define SEC2USEC
Definition: precland.cpp:58
bool switch_to_state_fallback()
Definition: precland.cpp:444
struct vehicle_land_detected_s * get_land_detected()
Definition: navigator.h:157
uORB::Subscription _target_pose_sub
Definition: precland.h:107
bool switch_to_state_start()
Definition: precland.cpp:367
PrecLandState _state
Definition: precland.h:124
bool switch_to_state_horizontal_approach()
Definition: precland.cpp:386
bool switch_to_state_done()
Definition: precland.cpp:460
float _param_acceleration_hor
Definition: precland.h:140
Navigator * _navigator
bool _target_pose_updated
wether the landing target position message is updated
Definition: precland.h:109
bool switch_to_state_final_approach()
Definition: precland.cpp:414
Vector normalized() const
Definition: Vector.hpp:103
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
matrix::Vector2f _sp_pev
Definition: precland.h:121
struct vehicle_global_position_s * get_global_position()
Definition: navigator.h:156
void on_active() override
This function is called while the mode is active.
Definition: precland.cpp:107
uint64_t _point_reached_time
time when we reached a setpoint
Definition: precland.h:116
Vector2< float > Vector2f
Definition: Vector2.hpp:69
static hrt_abstime hrt_elapsed_time(const hrt_abstime *then)
Compute the delta between a timestamp taken in the past and now.
Definition: drv_hrt.h:102
void slewrate(float &sp_x, float &sp_y)
Definition: precland.cpp:528
bool check_state_conditions(PrecLandState state)
Definition: precland.cpp:467
Type length() const
Definition: Vector.hpp:83
void run_state_descend_above_target()
Definition: precland.cpp:284
Simple error/warning functions, heavily inspired by the BSD functions of the same names...
param_t _handle_param_xy_vel_cruise
Definition: precland.h:139
matrix::Vector2f _sp_pev_prev
Definition: precland.h:122
float _param_xy_vel_cruise
Definition: precland.h:141
PrecLandState
Definition: precland.h:52
void run_state_horizontal_approach()
Definition: precland.cpp:220
__EXPORT param_t param_find(const char *name)
Look up a parameter by name.
Definition: parameters.cpp:370
struct position_setpoint_triplet_s * get_position_setpoint_triplet()
Definition: navigator.h:153
void on_activation() override
This function is called one time when mode becomes active, pos_sp_triplet must be initialized here...
Definition: precland.cpp:73
float _approach_alt
altitude at which to stay during horizontal approach
Definition: precland.h:119
landing_target_pose_s _target_pose
precision landing target position
Definition: precland.h:105
void run_state_start()
Definition: precland.cpp:176
int map_projection_project(const struct map_projection_reference_s *ref, double lat, double lon, float *x, float *y)
Definition: geo.cpp:132
void run_state_search()
Definition: precland.cpp:327
float dt
Definition: px4io.c:73
void updateParams() override
Definition: precland.cpp:162
bool switch_to_state_descend_above_target()
Definition: precland.cpp:402
PrecLandMode _mode
Definition: precland.h:126
void run_state_final_approach()
Definition: precland.cpp:321
bool update(void *dst)
Update the struct.
uint64_t _last_slewrate_time
time when we last limited setpoint changes
Definition: precland.h:114
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
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).
struct vehicle_local_position_s * get_local_position()
Definition: navigator.h:158