44"""
55
66import math
7+ from enum import Enum
78
89from .. import merged_odometry_detections
910from ..common .modules .logger import logger
1011
1112
13+ class DetectionSelectionStrategy (Enum ):
14+ """
15+ Strategies for selecting which detection to use when multiple targets are detected.
16+ """
17+
18+ FIRST_DETECTION = "first_detection" # Use first detection in list (original behavior)
19+ HIGHEST_CONFIDENCE = "highest_confidence" # Choose detection with highest confidence
20+
21+
1222class AutoLandingInformation :
1323 """
1424 Information necessary for the LANDING_TARGET MAVLink command.
@@ -44,17 +54,21 @@ def create(
4454 im_h : float ,
4555 im_w : float ,
4656 local_logger : logger .Logger ,
57+ selection_strategy : DetectionSelectionStrategy = DetectionSelectionStrategy .FIRST_DETECTION ,
4758 ) -> "tuple [bool, AutoLanding | None ]" :
4859 """
4960 fov_x: The horizontal camera field of view in degrees.
5061 fov_y: The vertical camera field of view in degrees.
5162 im_w: Width of image.
5263 im_h: Height of image.
64+ selection_strategy: Strategy for selecting which detection to use when multiple targets are detected.
5365
5466 Returns an AutoLanding object.
5567 """
5668
57- return True , AutoLanding (cls .__create_key , fov_x , fov_y , im_h , im_w , local_logger )
69+ return True , AutoLanding (
70+ cls .__create_key , fov_x , fov_y , im_h , im_w , local_logger , selection_strategy
71+ )
5872
5973 def __init__ (
6074 self ,
@@ -64,6 +78,7 @@ def __init__(
6478 im_h : float ,
6579 im_w : float ,
6680 local_logger : logger .Logger ,
81+ selection_strategy : DetectionSelectionStrategy ,
6782 ) -> None :
6883 """
6984 Private constructor, use create() method.
@@ -75,10 +90,41 @@ def __init__(
7590 self .im_h = im_h
7691 self .im_w = im_w
7792 self .__logger = local_logger
93+ self .__selection_strategy = selection_strategy
94+
95+ def _select_detection (self , detections : list ) -> int | None :
96+ """
97+ Select which detection to use based on the configured strategy.
98+
99+ Returns the index of the selected detection, or None if no suitable detection found.
100+ """
101+ if not detections :
102+ return None
103+
104+ if (
105+ len (detections ) == 1
106+ or self .__selection_strategy == DetectionSelectionStrategy .FIRST_DETECTION
107+ ):
108+ return 0
109+
110+ if self .__selection_strategy == DetectionSelectionStrategy .HIGHEST_CONFIDENCE :
111+ # Find detection with highest confidence
112+ max_confidence = 0
113+ selected_index = 0
114+
115+ for i , detection in enumerate (detections ):
116+ if detection .confidence > max_confidence :
117+ max_confidence = detection .confidence
118+ selected_index = i
119+
120+ return selected_index
121+
122+ # Default fallback
123+ return 0
78124
79125 def run (
80126 self , odometry_detections : merged_odometry_detections .MergedOdometryDetections
81- ) -> "tuple[bool, AutoLandingInformation]" :
127+ ) -> "tuple[bool, AutoLandingInformation | None ]" :
82128 """
83129 Calculates the x and y angles in radians of the bounding box based on its center.
84130
@@ -87,8 +133,26 @@ def run(
87133 Returns an AutoLandingInformation object.
88134 """
89135
90- # TODO: Devise better algorithm to pick which detection to land at if several are detected
91- x_center , y_center = odometry_detections .detections [0 ].get_centre ()
136+ # Check if we have any detections
137+ if not odometry_detections .detections :
138+ self .__logger .warning ("No detections available for auto-landing" , True )
139+ return False , None
140+
141+ # Select which detection to use
142+ selected_index = self ._select_detection (odometry_detections .detections )
143+ if selected_index is None :
144+ self .__logger .error ("Failed to select detection for auto-landing" , True )
145+ return False , None
146+
147+ selected_detection = odometry_detections .detections [selected_index ]
148+
149+ # Log selection information
150+ self .__logger .info (
151+ f"Selected detection { selected_index + 1 } /{ len (odometry_detections .detections )} using strategy: { self .__selection_strategy .value } " ,
152+ True ,
153+ )
154+
155+ x_center , y_center = selected_detection .get_centre ()
92156
93157 angle_x = (x_center - self .im_w / 2 ) * (self .fov_x * (math .pi / 180 )) / self .im_w
94158 angle_y = (y_center - self .im_h / 2 ) * (self .fov_y * (math .pi / 180 )) / self .im_h
0 commit comments