LCOV - code coverage report
Current view: top level - SITL - SIM_Precland.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 55 63 87.3 %
Date: 2026-09-09 11:02:08 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /*
       2             :    This program is free software: you can redistribute it and/or modify
       3             :    it under the terms of the GNU General Public License as published by
       4             :    the Free Software Foundation, either version 3 of the License, or
       5             :    (at your option) any later version.
       6             : 
       7             :    This program is distributed in the hope that it will be useful,
       8             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10             :    GNU General Public License for more details.
      11             : 
      12             :    You should have received a copy of the GNU General Public License
      13             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      14             :  */
      15             : 
      16             : #include "SIM_config.h"
      17             : 
      18             : #include "SIM_Precland.h"
      19             : #include "AP_HAL/AP_HAL.h"
      20             : #include "AP_Math/AP_Math.h"
      21             : #include "AP_Common/Location.h"
      22             : #include "SITL.h"
      23             : #include <stdio.h>
      24             : #include <GCS_MAVLink/GCS.h>
      25             : 
      26             : using namespace SITL;
      27             : 
      28             : // table of user settable parameters
      29             : const AP_Param::GroupInfo SIM_Precland::var_info[] = {
      30             : 
      31             :     // @Param: ENABLE
      32             :     // @DisplayName: Preland device Sim enable/disable
      33             :     // @Description: Allows you to enable (1) or disable (0) the Preland simulation
      34             :     // @Values: 0:Disabled,1:Enabled
      35             :     // @User: Advanced
      36             :     AP_GROUPINFO("ENABLE",  0, SIM_Precland, _enable, 0),
      37             : 
      38             :     // @Param: LAT
      39             :     // @DisplayName: Precland device center's latitude
      40             :     // @Description: Precland device center's latitude
      41             :     // @Units: deg
      42             :     // @Increment: 0.000001
      43             :     // @Range: -90 90
      44             :     // @User: Advanced
      45             :     AP_GROUPINFO("LAT", 1, SIM_Precland, _device_lat, 0),
      46             : 
      47             :     // @Param: LON
      48             :     // @DisplayName: Precland device center's longitude
      49             :     // @Description: Precland device center's longitude
      50             :     // @Units: deg
      51             :     // @Increment: 0.000001
      52             :     // @Range: -180 180
      53             :     // @User: Advanced
      54             :     AP_GROUPINFO("LON", 2, SIM_Precland, _device_lon, 0),
      55             : 
      56             :     // @Param: HEIGHT
      57             :     // @DisplayName: Precland device center's height SITL origin
      58             :     // @Description: Precland device center's height above SITL origin. Assumes a 2x2m square as station base
      59             :     // @Units: m
      60             :     // @Increment: 1
      61             :     // @Range: 0 10000
      62             :     // @User: Advanced
      63             :     AP_GROUPINFO("HEIGHT", 3, SIM_Precland, _device_height, 0),
      64             : 
      65             :     // @Param: YAW
      66             :     // @DisplayName: Precland device systems rotation from north
      67             :     // @Description: Precland device systems rotation from north
      68             :     // @Units: deg
      69             :     // @Increment: 1
      70             :     // @Range: -180 +180
      71             :     // @User: Advanced
      72             :     AP_GROUPINFO("YAW", 4, SIM_Precland, _orient_yaw, 0),
      73             : 
      74             :     // @Param: RATE
      75             :     // @DisplayName: Precland device update rate
      76             :     // @Description: Precland device rate. e.g led patter refresh rate, RF message rate, etc.
      77             :     // @Units: Hz
      78             :     // @Range: 0 200
      79             :     // @User: Advanced
      80             :     AP_GROUPINFO("RATE", 5, SIM_Precland, _rate, 100),
      81             : 
      82             :     // @Param: TYPE
      83             :     // @DisplayName: Precland device radiance type
      84             :     // @Description: Precland device radiance type: it can be a cylinder, a cone, or a sphere.
      85             :     // @Values: 0:cylinder,1:cone,2:sphere
      86             :     // @User: Advanced
      87             :     AP_GROUPINFO("TYPE", 6, SIM_Precland, _type, SIM_Precland::PRECLAND_TYPE_CYLINDER),
      88             : 
      89             :     // @Param: ALT_LMT
      90             :     // @DisplayName: Precland device alt range
      91             :     // @Description: Precland device maximum range altitude
      92             :     // @Units: m
      93             :     // @Range: 0 100
      94             :     // @User: Advanced
      95             :     AP_GROUPINFO("ALT_LMT", 7, SIM_Precland, _alt_limit, 15),
      96             : 
      97             :     // @Param: DIST_LMT
      98             :     // @DisplayName: Precland device lateral range
      99             :     // @Description: Precland device maximum lateral range
     100             :     // @Units: m
     101             :     // @Range: 5 100
     102             :     // @User: Advanced
     103             :     AP_GROUPINFO("DIST_LMT", 8, SIM_Precland, _dist_limit, 10),
     104             : 
     105             :     // @Param: ORIENT
     106             :     // @DisplayName: Precland device orientation
     107             :     // @Description: Precland device orientation vector
     108             :     // @Values: 0:Front, 4:Back, 24:Up
     109             :     // @User: Advanced
     110             :     AP_GROUPINFO("ORIENT", 9, SIM_Precland, _orient, ROTATION_PITCH_90),
     111             : 
     112             :     // @Param: OPTIONS
     113             :     // @DisplayName: SIM_Precland extra options
     114             :     // @Description: SIM_Precland extra options
     115             :     // @Bitmask: 0: Enable target distance
     116             :     // @User: Advanced
     117             :     AP_GROUPINFO("OPTIONS",  10, SIM_Precland, _options, 0),
     118             : 
     119             : #if AP_SIM_SHIP_ENABLED
     120             :     // @Param: SHIP
     121             :     // @DisplayName: SIM_Precland follow ship
     122             :     // @Description: This makes the position of the landing beacon follow the simulated ship from SIM_SHIP. The ship movement is controlled with the SIM_SHIP parameters
     123             :     // @Values: 0:Disabled,1:Enabled
     124             :     // @User: Advanced
     125             :     AP_GROUPINFO("SHIP",  11, SIM_Precland, _ship, 0),
     126             : #endif
     127             :     
     128             :     AP_GROUPEND
     129             : };
     130             : 
     131      946580 : void SIM_Precland::update(const Location &loc)
     132             : {
     133      946580 :     if (!_enable) {
     134           0 :         _healthy = false;
     135      912863 :         return;
     136             :     }
     137      946580 :     if (is_zero(_alt_limit) || _dist_limit < 1.0f) {
     138           0 :         _healthy = false;
     139           0 :         return;
     140             :     }
     141             : 
     142     1893160 :     Location device_center(static_cast<int32_t>(_device_lat * 1.0e7f),
     143     1893160 :                            static_cast<int32_t>(_device_lon * 1.0e7f),
     144      946580 :                            static_cast<int32_t>(_device_height*100),
     145      946580 :                            Location::AltFrame::ABOVE_ORIGIN);
     146             : 
     147      946580 :     if (device_center.lat == 0 && device_center.lng == 0 && device_center.alt == 0) {
     148        7185 :         const uint32_t now_ms = AP_HAL::millis();
     149        7185 :         if (now_ms - last_set_parameters_warning_ms > 5000) {
     150           2 :             GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Set SIM_PLD_LAT, SIM_PLD_LAT and SIM_PLD_ALT");
     151           2 :             last_set_parameters_warning_ms = now_ms;
     152             :         }
     153        7185 :         _healthy = false;
     154        7185 :         return;
     155             :     }
     156             : 
     157             : #if AP_SIM_SHIP_ENABLED
     158      939395 :     if (_ship == 1) {
     159             :         /*
     160             :           make precland target follow the simulated ship if the ship is enabled
     161             :          */
     162           0 :         auto *sitl = AP::sitl();
     163           0 :         Location shiploc;
     164           0 :         if (sitl != nullptr && sitl->models.shipsim.get_location(shiploc) && !shiploc.is_zero()) {
     165           0 :             shiploc.change_alt_frame(Location::AltFrame::ABOVE_ORIGIN);
     166           0 :             device_center = shiploc;
     167             :         }
     168             :     }
     169             : #endif
     170             : 
     171             :     // axis of cone or cylinder inside which the vehicle receives signals from simulated precland device
     172      939395 :     Vector3d axis{1, 0, 0};
     173      939395 :     axis.rotate((Rotation)_orient.get());   // unit vector in direction of axis of cone or cylinder
     174             : 
     175      939395 :     device_center.change_alt_frame(loc.get_alt_frame());
     176             : 
     177      939395 :     Vector3d position_wrt_device = device_center.get_distance_NED_double(loc);  // position of vehicle with respect to preland device center
     178             :     
     179             :     // longitudinal distance of vehicle from the precland device
     180             :     // this is the distance of vehicle from the plane which is passing through precland device center and perpendicular to axis of cone/cylinder
     181             :     // this plane is the ground plane when the axis has PITCH_90 rotation
     182      939395 :     Vector3d projection_on_axis = position_wrt_device.projected(axis);
     183      939395 :     const float longitudinal_dist = projection_on_axis.length();
     184             : 
     185             :     // lateral distance of vehicle from the precland device
     186             :     // this is the perpendicular distance of vehicle from the axis of cone/cylinder
     187      939395 :     const float lateral_distance = safe_sqrt(MAX(0, position_wrt_device.length_squared() - longitudinal_dist*longitudinal_dist));
     188             : 
     189             :     // sign of projection's dot product with axis tells if vehicle is in front of beacon
     190             :     // return false if vehicle if vehicle is  longitudinally too far away from precland device
     191             :     // for PITCH_90 orientation, longitudinal distance = alt of vehicle - device_height (in m)
     192      939395 :     if (projection_on_axis.dot(axis) <= 0 || longitudinal_dist > _alt_limit) {
     193      515621 :         _healthy = false;
     194      515621 :         return;
     195             :     }
     196             : 
     197      423774 :     const uint32_t now = AP_HAL::millis();
     198      423774 :     if (now - _last_update_ms < 1000.0f * (1.0f / _rate)) {
     199      388470 :         return;
     200             :     }
     201       35304 :     _last_update_ms = now;
     202             : 
     203       35304 :     switch (_type) {
     204       14656 :         case PRECLAND_TYPE_CONE: {
     205             :             // lateral_limit is the limit of how far the vehicle can laterally be from precland_device
     206             :             // in case of cone, this limit increases gradually as the vehicle moves longitudinally far away from precland device
     207       14656 :             const float lateral_limit = longitudinal_dist * _dist_limit / _alt_limit;
     208       14656 :             if (lateral_distance > lateral_limit) {
     209        1546 :                 _healthy = false;
     210        1546 :                 return;
     211             :             }
     212       13110 :             break;
     213             :         }
     214        4882 :         case PRECLAND_TYPE_SPHERE: {
     215        4882 :             if (position_wrt_device.length() > _dist_limit) {
     216           2 :                 _healthy = false;
     217           2 :                 return;
     218             :             }
     219        4880 :             break;
     220             :         }
     221       15766 :         default:
     222             :         case PRECLAND_TYPE_CYLINDER: {
     223       15766 :             if (lateral_distance > _dist_limit) {
     224          39 :                 _healthy = false;
     225          39 :                 return;
     226             :             }
     227       15727 :             break;
     228             :         }
     229             :     }
     230       33717 :     _target_pos = position_wrt_device;
     231       33717 :     _healthy = true;
     232             : }
     233             : 
     234        2094 : void SIM_Precland::set_default_location(float lat, float lon, int16_t yaw) {
     235        2094 :     if (is_zero(_device_lat) && is_zero(_device_lon)) {
     236        2094 :         _device_lat.set(lat);
     237        2094 :         _device_lon.set(lon);
     238        2094 :         _orient_yaw.set(yaw);
     239             :     }
     240        2094 : }

Generated by: LCOV version 1.14