/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "SIM_Precland.h"
#include "AP_HAL/AP_HAL.h"
#include "AP_Math/AP_Math.h"
#include "AP_Common/Location.h"
#include
using namespace SITL;
// table of user settable parameters
const AP_Param::GroupInfo SIM_Precland::var_info[] = {
// @Param: ENABLE
// @DisplayName: Preland device Sim enable/disable
// @Description: Allows you to enable (1) or disable (0) the Preland simulation
// @Values: 0:Disabled,1:Enabled
// @User: Advanced
AP_GROUPINFO("ENABLE", 0, SIM_Precland, _enable, 0),
// @Param: LAT
// @DisplayName: Precland device origin's latitude
// @Description: Precland device origin's latitude
// @Units: deg
// @Increment: 0.000001
// @Range: -90 90
// @User: Advanced
AP_GROUPINFO("LAT", 1, SIM_Precland, _origin_lat, 0),
// @Param: LON
// @DisplayName: Precland device origin's longitude
// @Description: Precland device origin's longitude
// @Units: deg
// @Increment: 0.000001
// @Range: -180 180
// @User: Advanced
AP_GROUPINFO("LON", 2, SIM_Precland, _origin_lon, 0),
// @Param: HEIGHT
// @DisplayName: Precland device origin's height above sealevel
// @Description: Precland device origin's height above sealevel assume a 2x2m square as station base
// @Units: cm
// @Increment: 1
// @Range: 0 10000
// @User: Advanced
AP_GROUPINFO("HEIGHT", 3, SIM_Precland, _origin_height, 0),
// @Param: YAW
// @DisplayName: Precland device systems rotation from north
// @Description: Precland device systems rotation from north
// @Units: deg
// @Increment: 1
// @Range: -180 +180
// @User: Advanced
AP_GROUPINFO("YAW", 4, SIM_Precland, _orient_yaw, 0),
// @Param: RATE
// @DisplayName: Precland device update rate
// @Description: Precland device rate. e.g led patter refresh rate, RF message rate, etc.
// @Units: Hz
// @Range: 0 200
// @User: Advanced
AP_GROUPINFO("RATE", 5, SIM_Precland, _rate, 100),
// @Param: TYPE
// @DisplayName: Precland device radiance type
// @Description: Precland device radiance type: it can be a cylinder, a cone, or a sphere.
// @Values: 0:cylinder,1:cone,2:sphere
// @User: Advanced
AP_GROUPINFO("TYPE", 6, SIM_Precland, _type, SIM_Precland::PRECLAND_TYPE_CYLINDER),
// @Param: ALT_LIMIT
// @DisplayName: Precland device alt range
// @Description: Precland device maximum range altitude
// @Units: m
// @Range: 0 100
// @User: Advanced
AP_GROUPINFO("ALT_LMT", 7, SIM_Precland, _alt_limit, 15),
// @Param: DIST_LIMIT
// @DisplayName: Precland device lateral range
// @Description: Precland device maximum lateral range
// @Units: m
// @Range: 5 100
// @User: Advanced
AP_GROUPINFO("DIST_LMT", 8, SIM_Precland, _dist_limit, 10),
AP_GROUPEND
};
void SIM_Precland::update(const Location &loc, const Vector3f &position)
{
if (!_enable) {
_healthy = false;
return;
}
if (is_zero(_alt_limit) || _dist_limit < 1.0f) {
_healthy = false;
return;
}
const float distance_z = -position.z;
const float origin_height_m = _origin_height * 0.01f;
if (distance_z > _alt_limit + origin_height_m) {
_healthy = false;
return;
}
const Location origin_center(static_cast(_origin_lat * 1.0e7f),
static_cast(_origin_lon * 1.0e7f),
static_cast(_origin_height),
Location::AltFrame::ABOVE_HOME);
Vector2f center;
if (!origin_center.get_vector_xy_from_origin_NE(center)) {
_healthy = false;
return;
}
center = center * 0.01f; // cm to m
_over_precland_base = origin_center.get_distance(loc) <= 2.0f;
const uint32_t now = AP_HAL::millis();
if (now - _last_update_ms < 1000.0f * (1.0f / _rate)) {
return;
}
_last_update_ms = now;
switch (_type) {
case PRECLAND_TYPE_CONE: {
const float in_radius = distance_z * _dist_limit / (_alt_limit + origin_height_m);
if (norm(position.x - center.x, position.y - center.y) > in_radius) {
_healthy = false;
return;
}
break;
}
case PRECLAND_TYPE_SPHERE: {
if (norm(position.x - center.x, position.y - center.y, distance_z - _origin_height) > (_alt_limit + origin_height_m)) {
_healthy = false;
return;
}
break;
}
default:
case PRECLAND_TYPE_CYLINDER: {
if (norm(position.x - center.x, position.y - center.y) > _dist_limit) {
_healthy = false;
return;
}
break;
}
}
_target_pos = position - Vector3f(center.x, center.y, origin_height_m);
_healthy = true;
}
void SIM_Precland::set_default_location(float lat, float lon, int16_t yaw) {
if (is_zero(_origin_lat) && is_zero(_origin_lon)) {
_origin_lat = lat;
_origin_lon = lon;
_orient_yaw = yaw;
}
}