#include "Rover.h"
bool ModeGuided::_enter()
{
if (rover.is_boat()) {
if (!start_loiter()) {
start_stop();
}
} else {
start_stop();
}
g2.wp_nav.init();
send_notification = false;
return true;
}
void ModeGuided::update()
{
switch (_guided_mode) {
case SubMode::WP:
{
if (!g2.wp_nav.reached_destination()) {
navigate_to_waypoint();
} else {
if (send_notification) {
send_notification = false;
rover.gcs().send_mission_item_reached_message(0);
}
if (rover.is_boat()) {
if (!start_loiter()) {
stop_vehicle();
}
} else {
stop_vehicle();
}
_distance_to_destination = rover.current_loc.get_distance(g2.wp_nav.get_destination());
}
break;
}
case SubMode::HeadingAndSpeed:
{
if (have_attitude_target && (millis() - _des_att_time_ms) > 3000) {
GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "target not received last 3secs, stopping");
have_attitude_target = false;
}
if (have_attitude_target) {
calc_steering_to_heading(_desired_yaw_cd);
calc_throttle(calc_speed_nudge(_desired_speed, is_negative(_desired_speed)), true);
} else {
if (rover.is_boat()) {
if (!start_loiter()) {
stop_vehicle();
}
} else {
stop_vehicle();
}
}
break;
}
case SubMode::TurnRateAndSpeed:
{
if (have_attitude_target && (millis() - _des_att_time_ms) > 3000) {
GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "target not received last 3secs, stopping");
have_attitude_target = false;
}
if (have_attitude_target) {
float steering_out = attitude_control.get_steering_out_rate(radians(_desired_yaw_rate_cds * 0.01f),
g2.motors.limit.steer_left,
g2.motors.limit.steer_right,
rover.G_Dt);
set_steering(steering_out * 4500.0f);
calc_throttle(calc_speed_nudge(_desired_speed, is_negative(_desired_speed)), true);
} else {
if (rover.is_boat()) {
if (!start_loiter()) {
stop_vehicle();
}
} else {
stop_vehicle();
}
}
break;
}
case SubMode::Loiter:
{
rover.mode_loiter.update();
break;
}
case SubMode::SteeringAndThrottle:
{
if (_have_strthr && (AP_HAL::millis() - _strthr_time_ms) > 3000) {
_have_strthr = false;
GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "target not received last 3secs, stopping");
}
if (_have_strthr) {
g2.motors.set_steering(_strthr_steering * 4500.0f, false);
g2.motors.set_throttle(_strthr_throttle * 100.0f);
} else {
if (rover.is_boat()) {
if (!start_loiter()) {
stop_vehicle();
}
} else {
stop_vehicle();
}
}
break;
}
case SubMode::Stop:
stop_vehicle();
break;
default:
GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "Unknown GUIDED mode");
break;
}
}
float ModeGuided::wp_bearing() const
{
switch (_guided_mode) {
case SubMode::WP:
return g2.wp_nav.wp_bearing_cd() * 0.01f;
case SubMode::HeadingAndSpeed:
case SubMode::TurnRateAndSpeed:
return 0.0f;
case SubMode::Loiter:
return rover.mode_loiter.wp_bearing();
case SubMode::SteeringAndThrottle:
case SubMode::Stop:
return 0.0f;
}
return 0.0f;
}
float ModeGuided::nav_bearing() const
{
switch (_guided_mode) {
case SubMode::WP:
return g2.wp_nav.nav_bearing_cd() * 0.01f;
case SubMode::HeadingAndSpeed:
case SubMode::TurnRateAndSpeed:
return 0.0f;
case SubMode::Loiter:
return rover.mode_loiter.nav_bearing();
case SubMode::SteeringAndThrottle:
case SubMode::Stop:
return 0.0f;
}
return 0.0f;
}
float ModeGuided::crosstrack_error() const
{
switch (_guided_mode) {
case SubMode::WP:
return g2.wp_nav.crosstrack_error();
case SubMode::HeadingAndSpeed:
case SubMode::TurnRateAndSpeed:
return 0.0f;
case SubMode::Loiter:
return rover.mode_loiter.crosstrack_error();
case SubMode::SteeringAndThrottle:
case SubMode::Stop:
return 0.0f;
}
return 0.0f;
}
float ModeGuided::get_desired_lat_accel() const
{
switch (_guided_mode) {
case SubMode::WP:
return g2.wp_nav.get_lat_accel();
case SubMode::HeadingAndSpeed:
case SubMode::TurnRateAndSpeed:
return 0.0f;
case SubMode::Loiter:
return rover.mode_loiter.get_desired_lat_accel();
case SubMode::SteeringAndThrottle:
case SubMode::Stop:
return 0.0f;
}
return 0.0f;
}
float ModeGuided::get_distance_to_destination() const
{
switch (_guided_mode) {
case SubMode::WP:
return _distance_to_destination;
case SubMode::HeadingAndSpeed:
case SubMode::TurnRateAndSpeed:
return 0.0f;
case SubMode::Loiter:
return rover.mode_loiter.get_distance_to_destination();
case SubMode::SteeringAndThrottle:
case SubMode::Stop:
return 0.0f;
}
return 0.0f;
}
bool ModeGuided::reached_destination() const
{
switch (_guided_mode) {
case SubMode::WP:
return g2.wp_nav.reached_destination();
case SubMode::HeadingAndSpeed:
case SubMode::TurnRateAndSpeed:
case SubMode::Loiter:
case SubMode::SteeringAndThrottle:
case SubMode::Stop:
return true;
}
return true;
}
bool ModeGuided::set_desired_speed(float speed)
{
switch (_guided_mode) {
case SubMode::WP:
return g2.wp_nav.set_speed_max(speed);
case SubMode::HeadingAndSpeed:
case SubMode::TurnRateAndSpeed:
return false;
case SubMode::Loiter:
return rover.mode_loiter.set_desired_speed(speed);
case SubMode::SteeringAndThrottle:
case SubMode::Stop:
return false;
}
return false;
}
bool ModeGuided::get_desired_location(Location& destination) const
{
switch (_guided_mode) {
case SubMode::WP:
if (g2.wp_nav.is_destination_valid()) {
destination = g2.wp_nav.get_oa_destination();
return true;
}
return false;
case SubMode::HeadingAndSpeed:
case SubMode::TurnRateAndSpeed:
return false;
case SubMode::Loiter:
return rover.mode_loiter.get_desired_location(destination);
case SubMode::SteeringAndThrottle:
case SubMode::Stop:
break;
}
return false;
}
bool ModeGuided::set_desired_location(const Location &destination, Location next_destination)
{
if (use_scurves_for_navigation()) {
if (!g2.wp_nav.set_desired_location(destination, next_destination)) {
return false;
}
} else {
if (!g2.wp_nav.set_desired_location_expect_fast_update(destination)) {
return false;
}
}
_guided_mode = SubMode::WP;
send_notification = true;
#if HAL_LOGGING_ENABLED
rover.Log_Write_GuidedTarget((uint8_t)_guided_mode, Vector3f(destination.lat, destination.lng, 0), Vector3f(g2.wp_nav.get_speed_max(), 0.0f, 0.0f));
#endif
return true;
}
void ModeGuided::set_desired_heading_and_speed(float yaw_angle_cd, float target_speed)
{
_guided_mode = SubMode::HeadingAndSpeed;
_des_att_time_ms = AP_HAL::millis();
_desired_yaw_cd = yaw_angle_cd;
_desired_speed = target_speed;
have_attitude_target = true;
#if HAL_LOGGING_ENABLED
rover.Log_Write_GuidedTarget((uint8_t)_guided_mode, Vector3f(_desired_yaw_cd, 0.0f, 0.0f), Vector3f(_desired_speed, 0.0f, 0.0f));
#endif
}
void ModeGuided::set_desired_heading_delta_and_speed(float yaw_delta_cd, float target_speed)
{
if (_guided_mode != SubMode::HeadingAndSpeed) {
_guided_mode = SubMode::HeadingAndSpeed;
_desired_yaw_cd = ahrs.yaw_sensor;
}
set_desired_heading_and_speed(wrap_180_cd(_desired_yaw_cd + yaw_delta_cd), target_speed);
}
void ModeGuided::set_desired_turn_rate_and_speed(float turn_rate_cds, float target_speed)
{
_guided_mode = SubMode::TurnRateAndSpeed;
_des_att_time_ms = AP_HAL::millis();
_desired_yaw_rate_cds = turn_rate_cds;
_desired_speed = target_speed;
have_attitude_target = true;
#if HAL_LOGGING_ENABLED
rover.Log_Write_GuidedTarget((uint8_t)_guided_mode, Vector3f(_desired_yaw_rate_cds, 0.0f, 0.0f), Vector3f(_desired_speed, 0.0f, 0.0f));
#endif
}
void ModeGuided::set_steering_and_throttle(float steering, float throttle)
{
_guided_mode = SubMode::SteeringAndThrottle;
_strthr_time_ms = AP_HAL::millis();
_strthr_steering = constrain_float(steering, -1.0f, 1.0f);
_strthr_throttle = constrain_float(throttle, -1.0f, 1.0f);
_have_strthr = true;
}
bool ModeGuided::start_loiter()
{
if (rover.mode_loiter.enter()) {
_guided_mode = SubMode::Loiter;
return true;
}
return false;
}
void ModeGuided::start_stop()
{
_guided_mode = SubMode::Stop;
}
void ModeGuided::limit_set(uint32_t timeout_ms, float horiz_max)
{
limit.timeout_ms = timeout_ms;
limit.horiz_max = horiz_max;
}
void ModeGuided::limit_clear()
{
limit.timeout_ms = 0;
limit.horiz_max = 0.0f;
}
void ModeGuided::limit_init_time_and_location()
{
limit.start_time_ms = AP_HAL::millis();
limit.start_loc = rover.current_loc;
}
bool ModeGuided::limit_breached() const
{
if ((limit.timeout_ms > 0) && (millis() - limit.start_time_ms >= limit.timeout_ms)) {
return true;
}
if (is_positive(limit.horiz_max)) {
return (rover.current_loc.get_distance(limit.start_loc) > limit.horiz_max);
}
return false;
}
bool ModeGuided::use_scurves_for_navigation() const
{
return ((g2.guided_options.get() & uint32_t(Options::SCurvesUsedForNavigation)) != 0);
}