ardupilot/APMrover2/mode_guided.cpp

257 lines
8.1 KiB
C++

#include "mode.h"
#include "Rover.h"
bool ModeGuided::_enter()
{
// set desired location to reasonable stopping point
if (!g2.wp_nav.set_desired_location_to_stopping_location()) {
return false;
}
_guided_mode = Guided_WP;
// initialise waypoint speed
g2.wp_nav.set_desired_speed_to_default();
sent_notification = false;
return true;
}
void ModeGuided::update()
{
switch (_guided_mode) {
case Guided_WP:
{
// check if we've reached the destination
if (!g2.wp_nav.reached_destination()) {
// update navigation controller
navigate_to_waypoint();
} else {
// send notification
if (!sent_notification) {
sent_notification = true;
rover.gcs().send_mission_item_reached_message(0);
}
// we have reached the destination so stay here
if (rover.is_boat()) {
if (!start_loiter()) {
stop_vehicle();
}
} else {
stop_vehicle();
}
// update distance to destination
_distance_to_destination = rover.current_loc.get_distance(g2.wp_nav.get_destination());
}
break;
}
case Guided_HeadingAndSpeed:
{
// stop vehicle if target not updated within 3 seconds
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) {
// run steering and throttle controllers
calc_steering_to_heading(_desired_yaw_cd);
calc_throttle(calc_speed_nudge(_desired_speed, is_negative(_desired_speed)), true);
} else {
// we have reached the destination so stay here
if (rover.is_boat()) {
if (!start_loiter()) {
stop_vehicle();
}
} else {
stop_vehicle();
}
}
break;
}
case Guided_TurnRateAndSpeed:
{
// stop vehicle if target not updated within 3 seconds
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) {
// run steering and throttle controllers
float steering_out = attitude_control.get_steering_out_rate(radians(_desired_yaw_rate_cds / 100.0f),
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 {
// we have reached the destination so stay here
if (rover.is_boat()) {
if (!start_loiter()) {
stop_vehicle();
}
} else {
stop_vehicle();
}
}
break;
}
case Guided_Loiter:
{
rover.mode_loiter.update();
break;
}
default:
gcs().send_text(MAV_SEVERITY_WARNING, "Unknown GUIDED mode");
break;
}
}
// return distance (in meters) to destination
float ModeGuided::get_distance_to_destination() const
{
switch (_guided_mode) {
case Guided_WP:
return _distance_to_destination;
case Guided_HeadingAndSpeed:
case Guided_TurnRateAndSpeed:
return 0.0f;
case Guided_Loiter:
rover.mode_loiter.get_distance_to_destination();
break;
}
// we should never reach here but just in case, return 0
return 0.0f;
}
// return true if vehicle has reached or even passed destination
bool ModeGuided::reached_destination() const
{
switch (_guided_mode) {
case Guided_WP:
return _reached_destination;
case Guided_HeadingAndSpeed:
case Guided_TurnRateAndSpeed:
case Guided_Loiter:
return true;
}
// we should never reach here but just in case, return true is the safer option
return true;
}
// set desired location
bool ModeGuided::set_desired_location(const struct Location& destination,
float next_leg_bearing_cd)
{
if (g2.wp_nav.set_desired_location(destination, next_leg_bearing_cd)) {
// handle guided specific initialisation and logging
_guided_mode = ModeGuided::Guided_WP;
sent_notification = false;
rover.Log_Write_GuidedTarget(_guided_mode, Vector3f(destination.lat, destination.lng, 0), Vector3f(g2.wp_nav.get_desired_speed(), 0.0f, 0.0f));
return true;
}
return false;
}
// set desired attitude
void ModeGuided::set_desired_heading_and_speed(float yaw_angle_cd, float target_speed)
{
// call parent
Mode::set_desired_heading_and_speed(yaw_angle_cd, target_speed);
// handle guided specific initialisation and logging
_guided_mode = ModeGuided::Guided_HeadingAndSpeed;
_des_att_time_ms = AP_HAL::millis();
_reached_destination = false;
// record targets
_desired_yaw_cd = yaw_angle_cd;
_desired_speed = target_speed;
have_attitude_target = true;
// log new target
rover.Log_Write_GuidedTarget(_guided_mode, Vector3f(_desired_yaw_cd, 0.0f, 0.0f), Vector3f(_desired_speed, 0.0f, 0.0f));
}
void ModeGuided::set_desired_heading_delta_and_speed(float yaw_delta_cd, float target_speed)
{
// handle initialisation
if (_guided_mode != ModeGuided::Guided_HeadingAndSpeed) {
_guided_mode = ModeGuided::Guided_HeadingAndSpeed;
_desired_yaw_cd = ahrs.yaw_sensor;
}
set_desired_heading_and_speed(wrap_180_cd(_desired_yaw_cd + yaw_delta_cd), target_speed);
}
// set desired velocity
void ModeGuided::set_desired_turn_rate_and_speed(float turn_rate_cds, float target_speed)
{
// handle initialisation
_guided_mode = ModeGuided::Guided_TurnRateAndSpeed;
_des_att_time_ms = AP_HAL::millis();
_reached_destination = false;
// record targets
_desired_yaw_rate_cds = turn_rate_cds;
_desired_speed = target_speed;
have_attitude_target = true;
// log new target
rover.Log_Write_GuidedTarget(_guided_mode, Vector3f(_desired_yaw_rate_cds, 0.0f, 0.0f), Vector3f(_desired_speed, 0.0f, 0.0f));
}
bool ModeGuided::start_loiter()
{
if (rover.mode_loiter.enter()) {
_guided_mode = Guided_Loiter;
return true;
}
return false;
}
// set guided timeout and movement limits
void ModeGuided::limit_set(uint32_t timeout_ms, float horiz_max)
{
limit.timeout_ms = timeout_ms;
limit.horiz_max = horiz_max;
}
// clear/turn off guided limits
void ModeGuided::limit_clear()
{
limit.timeout_ms = 0;
limit.horiz_max = 0.0f;
}
// initialise guided start time and location as reference for limit checking
// only called from AUTO mode's start_guided method
void ModeGuided::limit_init_time_and_location()
{
limit.start_time_ms = AP_HAL::millis();
limit.start_loc = rover.current_loc;
}
// returns true if guided mode has breached a limit
bool ModeGuided::limit_breached() const
{
// check if we have passed the timeout
if ((limit.timeout_ms > 0) && (millis() - limit.start_time_ms >= limit.timeout_ms)) {
return true;
}
// check if we have gone beyond horizontal limit
if (is_positive(limit.horiz_max)) {
return (rover.current_loc.get_distance(limit.start_loc) > limit.horiz_max);
}
// if we got this far we must be within limits
return false;
}