2018-04-28 03:31:31 -03:00
|
|
|
#include "Rover.h"
|
|
|
|
|
|
|
|
bool ModeLoiter::_enter()
|
|
|
|
{
|
|
|
|
// set _destination to reasonable stopping point
|
2019-09-26 16:45:53 -03:00
|
|
|
if (!g2.wp_nav.get_stopping_location(_destination)) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-04-28 03:31:31 -03:00
|
|
|
|
|
|
|
// initialise desired speed to current speed
|
|
|
|
if (!attitude_control.get_forward_speed(_desired_speed)) {
|
|
|
|
_desired_speed = 0.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
// initialise heading to current heading
|
|
|
|
_desired_yaw_cd = ahrs.yaw_sensor;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModeLoiter::update()
|
|
|
|
{
|
|
|
|
// get distance (in meters) to destination
|
2019-02-24 20:10:39 -04:00
|
|
|
_distance_to_destination = rover.current_loc.get_distance(_destination);
|
2018-04-28 03:31:31 -03:00
|
|
|
|
2019-09-07 19:17:09 -03:00
|
|
|
const float loiter_radius = rover.g2.sailboat.tack_enabled() ? g2.sailboat.get_loiter_radius() : g2.loit_radius;
|
|
|
|
|
2018-09-27 21:11:09 -03:00
|
|
|
// if within loiter radius slew desired speed towards zero and use existing desired heading
|
2019-09-07 19:17:09 -03:00
|
|
|
if (_distance_to_destination <= loiter_radius) {
|
2019-05-25 15:42:18 -03:00
|
|
|
// sailboats should not stop unless motoring
|
2019-08-21 03:05:03 -03:00
|
|
|
const float desired_speed_within_radius = rover.g2.sailboat.tack_enabled() ? 0.1f : 0.0f;
|
2018-09-25 10:09:47 -03:00
|
|
|
_desired_speed = attitude_control.get_desired_speed_accel_limited(desired_speed_within_radius, rover.G_Dt);
|
2019-09-07 19:17:09 -03:00
|
|
|
|
|
|
|
// if we have a sail but not trying to use it then point into the wind
|
|
|
|
if (!rover.g2.sailboat.tack_enabled() && rover.g2.sailboat.sail_enabled()) {
|
|
|
|
_desired_yaw_cd = degrees(g2.windvane.get_true_wind_direction_rad()) * 100.0f;
|
|
|
|
}
|
2018-04-28 03:31:31 -03:00
|
|
|
} else {
|
2020-05-23 17:51:49 -03:00
|
|
|
// P controller with hard-coded gain to convert distance to desired speed
|
2019-09-07 19:17:09 -03:00
|
|
|
_desired_speed = MIN((_distance_to_destination - loiter_radius) * g2.loiter_speed_gain, g2.wp_nav.get_default_speed());
|
|
|
|
|
2020-05-23 17:51:49 -03:00
|
|
|
// calculate bearing to destination
|
2019-04-05 10:02:44 -03:00
|
|
|
_desired_yaw_cd = rover.current_loc.get_bearing_to(_destination);
|
2019-05-04 03:29:18 -03:00
|
|
|
float yaw_error_cd = wrap_180_cd(_desired_yaw_cd - ahrs.yaw_sensor);
|
2018-04-28 03:31:31 -03:00
|
|
|
// if destination is behind vehicle, reverse towards it
|
2020-05-23 17:51:49 -03:00
|
|
|
if ((fabsf(yaw_error_cd) > 9000 && g2.loit_type == 0) || g2.loit_type == 2) {
|
2018-04-28 03:31:31 -03:00
|
|
|
_desired_yaw_cd = wrap_180_cd(_desired_yaw_cd + 18000);
|
2019-05-04 03:29:18 -03:00
|
|
|
yaw_error_cd = wrap_180_cd(_desired_yaw_cd - ahrs.yaw_sensor);
|
2018-04-28 03:31:31 -03:00
|
|
|
_desired_speed = -_desired_speed;
|
|
|
|
}
|
|
|
|
|
|
|
|
// reduce desired speed if yaw_error is large
|
2018-06-05 00:33:13 -03:00
|
|
|
// 45deg of error reduces speed to 75%, 90deg of error reduces speed to 50%
|
2019-05-04 03:29:18 -03:00
|
|
|
float yaw_error_ratio = 1.0f - constrain_float(fabsf(yaw_error_cd / 9000.0f), 0.0f, 1.0f) * 0.5f;
|
2018-04-28 03:31:31 -03:00
|
|
|
_desired_speed *= yaw_error_ratio;
|
|
|
|
}
|
|
|
|
|
2022-03-02 19:54:22 -04:00
|
|
|
// 0 turn rate is no limit
|
|
|
|
float turn_rate = 0.0;
|
|
|
|
|
|
|
|
// make sure sailboats don't try and sail directly into the wind
|
|
|
|
if (g2.sailboat.use_indirect_route(_desired_yaw_cd)) {
|
|
|
|
_desired_yaw_cd = g2.sailboat.calc_heading(_desired_yaw_cd);
|
|
|
|
if (g2.sailboat.tacking()) {
|
|
|
|
// use pivot turn rate for tacks
|
|
|
|
turn_rate = g2.wp_nav.get_pivot_rate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-28 03:31:31 -03:00
|
|
|
// run steering and throttle controllers
|
2022-03-02 19:54:22 -04:00
|
|
|
calc_steering_to_heading(_desired_yaw_cd, turn_rate);
|
2019-05-04 00:09:24 -03:00
|
|
|
calc_throttle(_desired_speed, true);
|
2018-04-28 03:31:31 -03:00
|
|
|
}
|
2019-05-17 03:55:31 -03:00
|
|
|
|
|
|
|
// get desired location
|
|
|
|
bool ModeLoiter::get_desired_location(Location& destination) const
|
|
|
|
{
|
|
|
|
destination = _destination;
|
|
|
|
return true;
|
|
|
|
}
|