LCOV - code coverage report
Current view: top level - AP_Proximity - AP_Proximity_Boundary_3D.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 187 218 85.8 %
Date: 2026-09-09 11:02:08 Functions: 21 24 87.5 %

          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 "AP_Proximity_Boundary_3D.h"
      17             : 
      18             : #define PROXIMITY_BOUNDARY_3D_TIMEOUT_MS 750 // we should check the 3D boundary faces after this many ms
      19             : 
      20             : /*
      21             :   Constructor. 
      22             :   This incorporates initialisation as well.
      23             : */
      24       62974 : AP_Proximity_Boundary_3D::AP_Proximity_Boundary_3D() 
      25             : {
      26             :     // initialise sector edge vector used for building the boundary fence
      27        1369 :     init();
      28        1369 : }
      29             : 
      30             : // initialise the boundary and sector_edge_vector array used for object avoidance
      31             : //   should be called if the sector_middle_deg or _sector_width_deg arrays are changed
      32        1369 : void AP_Proximity_Boundary_3D::init()
      33             : {
      34        8214 :     for (uint8_t layer=0; layer < PROXIMITY_NUM_LAYERS; layer++) {
      35        6845 :         const float pitch = ((float)_pitch_middle_deg[layer]);
      36       61605 :         for (uint8_t sector=0; sector < PROXIMITY_NUM_SECTORS; sector++) {
      37       54760 :             const float angle_rad = ((float)_sector_middle_deg[sector]+(PROXIMITY_SECTOR_WIDTH_DEG/2.0f));
      38       54760 :             _sector_edge_vector[layer][sector].offset_bearing(angle_rad, pitch, 100.0f);
      39       54760 :             _boundary_points[layer][sector] = _sector_edge_vector[layer][sector] * PROXIMITY_BOUNDARY_DIST_DEFAULT;
      40             :         }
      41             :     }
      42        1369 : }
      43             : 
      44             : // returns face corresponding to the provided yaw and (optionally) pitch
      45             : // pitch is the vertical body-frame angle (in degrees) to the obstacle (0=directly ahead, 90 is above the vehicle)
      46             : // yaw is the horizontal body-frame angle (in degrees) to the obstacle (0=directly ahead of the vehicle, 90 is to the right of the vehicle)
      47      407369 : AP_Proximity_Boundary_3D::Face AP_Proximity_Boundary_3D::get_face(float pitch, float yaw) const
      48             : {
      49      407369 :     const uint8_t sector = wrap_360(yaw + (PROXIMITY_SECTOR_WIDTH_DEG * 0.5f)) / 45.0f;
      50      407369 :     const float pitch_limited = constrain_float(pitch, -75.0f, 74.9f);
      51      407369 :     const uint8_t layer = (pitch_limited + 75.0f)/PROXIMITY_PITCH_WIDTH_DEG;
      52      407369 :     return Face{layer, sector};
      53             : }
      54             : 
      55             : // Set the actual body-frame angle(yaw), pitch, and distance of the detected object.
      56             : // This method will also mark the sector and layer to be "valid",
      57             : // This distance can then be used for Obstacle Avoidance
      58             : // Assume detected obstacle is horizontal (zero pitch), if no pitch is passed
      59             : // prx_instance should be set to the proximity sensor backend instance number
      60      314943 : void AP_Proximity_Boundary_3D::set_face_attributes(const Face &face, float pitch, float angle, float distance, uint8_t prx_instance)
      61             : {
      62      314943 :     if (!face.valid()) {
      63           0 :         return;
      64             :     }
      65             : 
      66             :     // ignore update if another instance has provided a shorter distance within the last 0.2 seconds
      67      314943 :     if ((prx_instance != _prx_instance[face.layer][face.sector]) && _distance_valid[face.layer][face.sector] && (_filtered_distance[face.layer][face.sector].get() < distance)) {
      68             :         // check if recent
      69           0 :         const uint32_t now_ms = AP_HAL::millis();
      70           0 :         if (now_ms - _last_update_ms[face.layer][face.sector] < PROXIMITY_FACE_RESET_MS) {
      71           0 :             return;
      72             :         }
      73             :     }
      74             : 
      75      314943 :     _angle_deg[face.layer][face.sector] = angle;
      76      314943 :     _pitch_deg[face.layer][face.sector] = pitch;
      77      314943 :     _distance[face.layer][face.sector] = distance;
      78      314943 :     _distance_valid[face.layer][face.sector] = true;
      79      314943 :     _prx_instance[face.layer][face.sector] = prx_instance;
      80             : 
      81             :     // apply filter
      82      314943 :     set_filtered_distance(face, distance);
      83             : 
      84             :     // update boundary used for simple avoidance
      85      314943 :     update_boundary(face);
      86             : }
      87             : 
      88             : // apply a new cutoff_freq to low-pass filter
      89          12 : void AP_Proximity_Boundary_3D::apply_filter_freq(float cutoff_freq)
      90             : {
      91          72 :     for (uint8_t layer=0; layer < PROXIMITY_NUM_LAYERS; layer++) {
      92         540 :         for (uint8_t sector=0; sector < PROXIMITY_NUM_SECTORS; sector++) {
      93         480 :             _filtered_distance[layer][sector].set_cutoff_frequency(cutoff_freq);
      94             :         }
      95             :     }
      96          12 : }
      97             : 
      98             : // Apply low pass filter on the raw distance
      99      314943 : void AP_Proximity_Boundary_3D::set_filtered_distance(const Face &face, float distance)
     100             : {
     101      314943 :     if (!face.valid()) {
     102           0 :         return;
     103             :     }
     104      314943 :     if (!is_equal(_filtered_distance[face.layer][face.sector].get_cutoff_freq(), _filter_freq)) {
     105             :         // cutoff freq has changed
     106          12 :         apply_filter_freq(_filter_freq);
     107             :     }
     108             : 
     109      314943 :     const uint32_t now_ms = AP_HAL::millis();
     110      314943 :     const uint32_t dt = now_ms - _last_update_ms[face.layer][face.sector];
     111      314943 :     if (dt < PROXIMITY_FILT_RESET_TIME) {
     112      314761 :         _filtered_distance[face.layer][face.sector].apply(distance, dt* 0.001f);
     113             :     } else {
     114             :         // reset filter since last distance was passed a long time back
     115         182 :         _filtered_distance[face.layer][face.sector].reset(distance);
     116             :     }
     117      314943 :     _last_update_ms[face.layer][face.sector] = now_ms;
     118             : }
     119             : 
     120             : // update boundary points used for object avoidance based on a single sector and pitch distance changing
     121             : //   the boundary points lie on the line between sectors meaning two boundary points may be updated based on a single sector's distance changing
     122             : //   the boundary point is set to the shortest distance found in the two adjacent sectors, this is a conservative boundary around the vehicle
     123      315010 : void AP_Proximity_Boundary_3D::update_boundary(const Face &face)
     124             : {
     125             :     // sanity check
     126      315010 :     if (!face.valid()) {
     127           0 :         return;
     128             :     }
     129             : 
     130      315010 :     const uint8_t layer = face.layer;
     131      315010 :     const uint8_t sector = face.sector;
     132             : 
     133             :     // find adjacent sector (clockwise)
     134      315010 :     const uint8_t next_sector = get_next_sector(sector);
     135             : 
     136             :     // boundary point lies on the line between the two sectors at the shorter distance found in the two sectors
     137      315010 :     float shortest_distance = PROXIMITY_BOUNDARY_DIST_DEFAULT;
     138      315010 :     if (_distance_valid[layer][sector] && _distance_valid[layer][next_sector]) {
     139      314271 :         shortest_distance = MIN(_filtered_distance[layer][sector].get(), _filtered_distance[layer][next_sector].get());
     140         739 :     } else if (_distance_valid[layer][sector]) {
     141         672 :         shortest_distance = _filtered_distance[layer][sector].get();
     142          67 :     } else if (_distance_valid[layer][next_sector]) {
     143          56 :         shortest_distance = _filtered_distance[layer][next_sector].get();
     144             :     }
     145      315010 :     if (shortest_distance < PROXIMITY_BOUNDARY_DIST_MIN) {
     146        9266 :         shortest_distance = PROXIMITY_BOUNDARY_DIST_MIN;
     147             :     }
     148      315010 :     _boundary_points[layer][sector] = _sector_edge_vector[layer][sector] * shortest_distance;
     149             : 
     150             :     // if the next sector (clockwise) has an invalid distance, set boundary to create a cup like boundary
     151      315010 :     if (!_distance_valid[layer][next_sector]) {
     152         683 :         _boundary_points[layer][next_sector] = _sector_edge_vector[layer][next_sector] * shortest_distance;
     153             :     }
     154             : 
     155             :     // repeat for edge between sector and previous sector
     156      315010 :     const uint8_t prev_sector = get_prev_sector(sector);
     157      315010 :     shortest_distance = PROXIMITY_BOUNDARY_DIST_DEFAULT;
     158      315010 :     if (_distance_valid[layer][prev_sector] && _distance_valid[layer][sector]) {
     159      314376 :         shortest_distance = MIN(_filtered_distance[layer][prev_sector].get(), _filtered_distance[layer][sector].get());
     160         634 :     } else if (_distance_valid[layer][prev_sector]) {
     161          30 :         shortest_distance = _filtered_distance[layer][prev_sector].get();
     162         604 :     } else if (_distance_valid[layer][sector]) {
     163         567 :         shortest_distance = _filtered_distance[layer][sector].get();
     164             :     }
     165      315010 :     _boundary_points[layer][prev_sector] = _sector_edge_vector[layer][prev_sector] * shortest_distance;
     166             : 
     167             :     // if the sector counter-clockwise from the previous sector has an invalid distance, set boundary to create a cup-like boundary
     168      315010 :     const uint8_t prev_sector_ccw = get_prev_sector(prev_sector);
     169      315010 :     if (!_distance_valid[layer][prev_sector_ccw]) {
     170         653 :         _boundary_points[layer][prev_sector_ccw] = _sector_edge_vector[layer][prev_sector_ccw] * shortest_distance;
     171             :     }
     172             : }
     173             : 
     174             : // reset boundary.  marks all distances as invalid
     175           3 : void AP_Proximity_Boundary_3D::reset()
     176             : {
     177          18 :     for (uint8_t layer=0; layer < PROXIMITY_NUM_LAYERS; layer++) {
     178         135 :         for (uint8_t sector=0; sector < PROXIMITY_NUM_SECTORS; sector++) {
     179         120 :             _distance_valid[layer][sector] = false;
     180             :         }
     181             :     }
     182           3 : }
     183             : 
     184             : // Reset this location, specified by Face object, back to default
     185             : // i.e Distance is marked as not-valid, and set to a large number.
     186             : // prx_instance should be set to the proximity sensor's backend instance number
     187        3724 : void AP_Proximity_Boundary_3D::reset_face(const Face &face, uint8_t prx_instance)
     188             : {
     189        3724 :     if (!face.valid()) {
     190           4 :         return;
     191             :     }
     192             : 
     193             :     // return immediately if face already has no valid distance
     194        3720 :     if (!_distance_valid[face.layer][face.sector]) {
     195        3713 :         return;
     196             :     }
     197             : 
     198             :     // ignore reset if another instance provided this face's distance within the last 0.2 seconds
     199           7 :     if (prx_instance != _prx_instance[face.layer][face.sector]) {
     200           0 :         const uint32_t now_ms = AP_HAL::millis();
     201           0 :         if (now_ms - _last_update_ms[face.layer][face.sector] < 200) {
     202           0 :             return;
     203             :         }
     204             :     }
     205             : 
     206           7 :     _distance_valid[face.layer][face.sector] = false;
     207             : 
     208             :     // update simple avoidance boundary
     209           7 :     update_boundary(face);
     210             : }
     211             : 
     212             : // check if a face has valid distance even if it was updated a long time back
     213    15835009 : void AP_Proximity_Boundary_3D::check_face_timeout()
     214             : {
     215             :     // exit immediately if already checked recently
     216    15835009 :     const uint32_t now_ms = AP_HAL::millis();
     217    15835009 :     if ((now_ms - _last_check_face_timeout_ms) < PROXIMITY_BOUNDARY_3D_TIMEOUT_MS) {
     218    15716469 :         return;
     219             :     }
     220      118540 :     _last_check_face_timeout_ms = now_ms;
     221             : 
     222      711240 :     for (uint8_t layer=0; layer < PROXIMITY_NUM_LAYERS; layer++) {
     223     5334300 :         for (uint8_t sector=0; sector < PROXIMITY_NUM_SECTORS; sector++) {
     224     4741600 :             if (_distance_valid[layer][sector]) {
     225        4357 :                 if ((now_ms - _last_update_ms[layer][sector]) > PROXIMITY_FACE_RESET_MS) {
     226             :                     // this face has a valid distance but wasn't updated for a long time, reset it
     227          60 :                     _distance_valid[layer][sector] = false;
     228          60 :                     update_boundary(AP_Proximity_Boundary_3D::Face{layer, sector});
     229             :                 }
     230             :             }
     231             :         }
     232             :     }
     233             : }
     234             : 
     235             : // get distance for a face.  returns true on success and fills in distance argument with distance in meters
     236      348192 : bool AP_Proximity_Boundary_3D::get_distance(const Face &face, float &distance) const
     237             : {
     238      348192 :     if (!face.valid()) {
     239           0 :         return false;
     240             :     }
     241      348192 :     if (_distance_valid[face.layer][face.sector]) {
     242       52119 :         distance = _distance[face.layer][face.sector];
     243       52119 :         return true;
     244             :     }
     245             : 
     246      296073 :     return false;
     247             : }
     248             : 
     249             : // get the total number of obstacles 
     250     2006560 : uint8_t AP_Proximity_Boundary_3D::get_obstacle_count() const
     251             : {
     252     2006560 :     return PROXIMITY_NUM_LAYERS * PROXIMITY_NUM_SECTORS;
     253             : }
     254             : 
     255             : // Converts obstacle_num passed from avoidance library into appropriate face of the boundary
     256             : // Returns false if the face is invalid
     257             : // "update_boundary" method manipulates two sectors ccw and one sector cw from any valid face.
     258             : // Any boundary that does not fall into these manipulated faces are useless, and will be marked as false
     259             : // The resultant is packed into a Boundary Location object and returned by reference as "face"
     260    80263576 : bool AP_Proximity_Boundary_3D::convert_obstacle_num_to_face(uint8_t obstacle_num, Face& face) const
     261             : {
     262             :     // obstacle num is just "flattened layers, and sectors"
     263    80263576 :     const uint8_t layer = obstacle_num / PROXIMITY_NUM_SECTORS;
     264    80263576 :     const uint8_t sector = obstacle_num % PROXIMITY_NUM_SECTORS;
     265    80263576 :     face.sector = sector;
     266    80263576 :     face.layer = layer;
     267             : 
     268    80263576 :     uint8_t valid_sector = sector;
     269             :     // check for 3 adjacent sectors
     270   320076598 :     for (uint8_t i=0; i < 3; i++) {
     271   240140243 :         if (_distance_valid[layer][valid_sector]) {
     272             :             // update boundary has manipulated this face
     273      327221 :             return true;
     274             :         }
     275   239813022 :         valid_sector = get_next_sector(valid_sector);
     276             :     }
     277             : 
     278             :     // this face was not manipulated by "update_boundary" and is stale. Don't use it
     279    79936355 :     return false;
     280             : }
     281             : 
     282             : // Appropriate layer and sector are found from the passed obstacle_num
     283             : // This function then draws a line between this sector, and sector + 1 at the given layer
     284             : // Then returns the closest point on this line from vehicle, in body-frame. 
     285             : // Used by GPS based Simple Avoidance  
     286             : // False is returned if the obstacle_num provided does not produce a valid obstacle 
     287    80262400 : bool AP_Proximity_Boundary_3D::get_obstacle(uint8_t obstacle_num, Vector3f& vec_to_obstacle) const
     288             : {
     289    80262400 :     Face face;
     290    80262400 :     if (!convert_obstacle_num_to_face(obstacle_num, face)) {
     291             :         // not a valid face
     292    79936355 :         return false;
     293             :     }
     294      326045 :     const uint8_t sector_end = face.sector;
     295      326045 :     const uint8_t sector_start = get_next_sector(face.sector);
     296             :     
     297      326045 :     const Vector3f start = _boundary_points[face.layer][sector_start];
     298      326045 :     const Vector3f end = _boundary_points[face.layer][sector_end];
     299      326045 :     vec_to_obstacle = Vector3f::point_on_line_closest_to_other_point(start, end, Vector3f{});
     300      326045 :     return true;
     301             : }
     302             : 
     303             : // Appropriate layer and sector are found from the passed obstacle_num
     304             : // This function then draws a line between this sector, and sector + 1 at the given layer
     305             : // Then returns the closest point on this line from the segment that was passed, in body-frame.
     306             : // Addionally a 3-D plane is constructed using the closest point found above as normal, and a point on the line segment in the boundary.
     307             : // True is returned when the passed line segment intersects this plane.
     308             : // This helps us know if the passed line segment was in the direction of the boundary, or going in a different direction.
     309             : // Used by GPS based Simple Avoidance  - for "brake mode"
     310             : // False is returned if the obstacle_num provided does not produce a valid obstacle
     311        1176 : bool AP_Proximity_Boundary_3D::closest_point_from_segment_to_obstacle(uint8_t obstacle_num, const Vector3f& seg_start, const Vector3f& seg_end, Vector3f& closest_point) const
     312             : {
     313        1176 :     Face face;
     314        1176 :     if (!convert_obstacle_num_to_face(obstacle_num, face)) {
     315             :         // not a valid a face
     316           0 :         return false;
     317             :     }
     318             : 
     319        1176 :     const uint8_t sector_end = face.sector;
     320        1176 :     const uint8_t sector_start = get_next_sector(face.sector);
     321        1176 :     const Vector3f start = _boundary_points[face.layer][sector_start];
     322        1176 :     const Vector3f end = _boundary_points[face.layer][sector_end];
     323             : 
     324             :     // closest point between passed line segment and boundary
     325        1176 :     Vector3f::segment_to_segment_closest_point(seg_start, seg_end, start, end, closest_point);
     326        1176 :     if (closest_point == start) {
     327             :         // draw a plane using the closest point as normal vector, and a point on the boundary
     328             :         // return false if the passed segment does not intersect the plane
     329         166 :         return Vector3f::segment_plane_intersect(seg_start, seg_end, closest_point, end);
     330             :     }
     331        1010 :     return Vector3f::segment_plane_intersect(seg_start, seg_end, closest_point, start);
     332             : }
     333             : 
     334             : // get distance and angle to closest object (used for pre-arm check)
     335             : //   returns true on success, false if no valid readings
     336       93666 : bool AP_Proximity_Boundary_3D::get_closest_object(float& angle_deg, float &distance) const
     337             : {
     338       93666 :     bool closest_found = false;
     339       93666 :     uint8_t closest_sector = 0;
     340       93666 :     uint8_t closest_layer = 0;
     341             : 
     342             :     // check boundary for shortest distance
     343             :     // only check for middle layers and higher
     344             :     // lower layers might contain ground, which will give false pre-arm failure
     345      374664 :     for (uint8_t layer=PROXIMITY_MIDDLE_LAYER; layer<PROXIMITY_NUM_LAYERS; layer++) {
     346     2528982 :         for (uint8_t sector=0; sector<PROXIMITY_NUM_SECTORS; sector++) {
     347     2247984 :             if (_distance_valid[layer][sector]) {
     348       34107 :                 if (!closest_found || (_distance[layer][sector] < _distance[closest_layer][closest_sector])) {
     349       11840 :                     closest_layer = layer;
     350       11840 :                     closest_sector = sector;
     351       11840 :                     closest_found = true;
     352             :                 }
     353             :             }
     354             :         }
     355             :     }
     356             : 
     357       93666 :     if (closest_found) {
     358        5426 :         angle_deg = _angle_deg[closest_layer][closest_sector];
     359        5426 :         distance = _distance[closest_layer][closest_sector];
     360             :     }
     361       93666 :     return closest_found;
     362             : }
     363             : 
     364             : // get number of objects, used for non-GPS avoidance
     365           0 : uint8_t AP_Proximity_Boundary_3D::get_horizontal_object_count() const
     366             : {
     367           0 :     return PROXIMITY_NUM_SECTORS;
     368             : }
     369             : 
     370             : // get an object's angle and distance, used for non-GPS avoidance
     371             : // returns false if no angle or distance could be returned for some reason
     372           0 : bool AP_Proximity_Boundary_3D::get_horizontal_object_angle_and_distance(uint8_t object_number, float &angle_deg, float &distance) const
     373             : {
     374           0 :     if ((object_number < PROXIMITY_NUM_SECTORS) && _distance_valid[PROXIMITY_MIDDLE_LAYER][object_number]) {
     375           0 :         angle_deg = _angle_deg[PROXIMITY_MIDDLE_LAYER][object_number];
     376           0 :         distance = _filtered_distance[PROXIMITY_MIDDLE_LAYER][object_number].get();
     377           0 :         return true;
     378             :     }
     379           0 :     return false;
     380             : }
     381             : 
     382             : // get an obstacle info for AP_Periph
     383             : // returns false if no angle or distance could be returned for some reason
     384           0 : bool AP_Proximity_Boundary_3D::get_obstacle_info(uint8_t obstacle_num, float &angle_deg, float &pitch_deg, float &distance) const
     385             : {
     386             :     // obstacle num is just "flattened layers, and sectors"
     387           0 :     const uint8_t layer = obstacle_num / PROXIMITY_NUM_SECTORS;
     388           0 :     const uint8_t sector = obstacle_num % PROXIMITY_NUM_SECTORS;
     389           0 :     if (_distance_valid[layer][sector]) {
     390           0 :         angle_deg = _angle_deg[layer][sector];
     391           0 :         pitch_deg = _pitch_deg[layer][sector];
     392           0 :         distance = _filtered_distance[layer][sector].get();
     393           0 :         return true;
     394             :     }
     395             : 
     396           0 :     return false;
     397             : }
     398             : 
     399             : // Return filtered distance for the passed in face
     400       52119 : bool AP_Proximity_Boundary_3D::get_filtered_distance(const Face &face, float &distance) const
     401             : {
     402       52119 :     if (!face.valid()) {
     403           0 :         return false;
     404             :     }
     405             : 
     406       52119 :     if (!_distance_valid[face.layer][face.sector]) {
     407             :         // invalid distace
     408           0 :         return false;
     409             :     }
     410             : 
     411       52119 :     distance = _filtered_distance[face.layer][face.sector].get();
     412       52119 :     return true;
     413             : }
     414             : 
     415             : // Get raw and filtered distances in 8 directions per layer
     416       43524 : bool AP_Proximity_Boundary_3D::get_layer_distances(uint8_t layer_number, float dist_max, Proximity_Distance_Array &prx_dist_array, Proximity_Distance_Array &prx_filt_dist_array) const
     417             : {
     418             :     // cycle through all sectors filling in distances and orientations
     419             :     // see MAV_SENSOR_ORIENTATION for orientations (0 = forward, 1 = 45 degree clockwise from north, etc)
     420       43524 :     bool valid_distances = false;
     421       43524 :     prx_dist_array.offset_valid = 0;
     422       43524 :     prx_filt_dist_array.offset_valid = 0;
     423      391716 :     for (uint8_t i=0; i<PROXIMITY_MAX_DIRECTION; i++) {
     424      348192 :         prx_dist_array.orientation[i] = i;
     425      348192 :         const AP_Proximity_Boundary_3D::Face face(layer_number, i);
     426      348192 :         if (!face.valid()) {
     427           0 :             return false;
     428             :         }
     429      348192 :         if (get_distance(face, prx_dist_array.distance[i]) && get_filtered_distance(face, prx_filt_dist_array.distance[i])) {
     430       52119 :             valid_distances = true;
     431       52119 :             prx_dist_array.offset_valid |= (1U << i);
     432       52119 :             prx_filt_dist_array.offset_valid |= (1U << i);
     433             :         } else {
     434      296073 :             prx_dist_array.distance[i] = dist_max;
     435      296073 :             prx_filt_dist_array.distance[i] = dist_max;
     436             :         }
     437             :     }
     438             : 
     439       43524 :     return valid_distances;
     440             : }
     441             : 
     442             : // reset the temporary boundary. This fills in distances with FLT_MAX
     443         447 : void AP_Proximity_Temp_Boundary::reset()
     444             : {
     445        2682 :     for (uint8_t layer=0; layer < PROXIMITY_NUM_LAYERS; layer++) {
     446       20115 :         for (uint8_t sector=0; sector < PROXIMITY_NUM_SECTORS; sector++) {
     447       17880 :             _distances[layer][sector] = FLT_MAX;
     448             :         }
     449             :     }
     450         447 : }
     451             : 
     452             : // add a distance to the temp boundary if it is shorter than any other provided distance since the last time the boundary was reset
     453             : // pitch and yaw are in degrees, distance is in meters
     454         457 : void AP_Proximity_Temp_Boundary::add_distance(const AP_Proximity_Boundary_3D::Face &face, float pitch_deg, float yaw_deg, float distance_m)
     455             : {
     456         457 :     if (face.valid() && distance_m < _distances[face.layer][face.sector]) {
     457         457 :         _distances[face.layer][face.sector] = distance_m;
     458         457 :         _angle_deg[face.layer][face.sector] = yaw_deg;
     459         457 :         _pitch_deg[face.layer][face.sector] = pitch_deg;
     460             :     }
     461         457 : }
     462             : 
     463             : // fill the original 3D boundary with the contents of this temporary boundary
     464             : // prx_instance should be set to the proximity sensor's backend instance number
     465         443 : void AP_Proximity_Temp_Boundary::update_3D_boundary(uint8_t prx_instance, AP_Proximity_Boundary_3D &boundary)
     466             : {
     467        2658 :     for (uint8_t layer=0; layer < PROXIMITY_NUM_LAYERS; layer++) {
     468       19935 :         for (uint8_t sector=0; sector < PROXIMITY_NUM_SECTORS; sector++) {
     469       17720 :             if (_distances[layer][sector] < FLT_MAX) {
     470         447 :                 AP_Proximity_Boundary_3D::Face face{layer, sector};
     471         447 :                 boundary.set_face_attributes(face, _pitch_deg[layer][sector], _angle_deg[layer][sector], _distances[layer][sector], prx_instance);
     472             :             }
     473             :         }
     474             :     }
     475         443 : }
     476             : 

Generated by: LCOV version 1.14