1
1
import math
2
- from typing import List , Optional , Tuple
2
+ from typing import Optional
3
3
4
4
import numpy as np
5
5
import tf2_ros as tf2
@@ -53,7 +53,7 @@ def __init__(self, node, blackboard):
53
53
self .calc_base_costmap ()
54
54
self .calc_gradients ()
55
55
56
- def robot_callback (self , msg : RobotArray ):
56
+ def robot_callback (self , msg : RobotArray ) -> None :
57
57
"""
58
58
Callback with new robot detections
59
59
"""
@@ -77,10 +77,11 @@ def robot_callback(self, msg: RobotArray):
77
77
# Publish debug costmap
78
78
self .publish_costmap ()
79
79
80
- def publish_costmap (self ):
80
+ def publish_costmap (self ) -> None :
81
81
"""
82
82
Publishes the costmap for rviz
83
83
"""
84
+ assert self .costmap is not None , "Costmap is not initialized"
84
85
# Normalize costmap to match the rviz color scheme in a good way
85
86
normalized_costmap = (
86
87
(255 - ((self .costmap - np .min (self .costmap )) / (np .max (self .costmap ) - np .min (self .costmap ))) * 255 / 2.1 )
@@ -131,7 +132,7 @@ def get_pass_regions(self) -> np.ndarray:
131
132
# Smooth obstacle map
132
133
return gaussian_filter (costmap , pass_smooth )
133
134
134
- def field_2_costmap_coord (self , x : float , y : float ) -> Tuple [ float , float ]:
135
+ def field_2_costmap_coord (self , x : float , y : float ) -> tuple [ int , int ]:
135
136
"""
136
137
Converts a field position to the corresponding indices for the costmap.
137
138
@@ -153,10 +154,11 @@ def field_2_costmap_coord(self, x: float, y: float) -> Tuple[float, float]:
153
154
)
154
155
return idx_x , idx_y
155
156
156
- def calc_gradients (self ):
157
+ def calc_gradients (self ) -> None :
157
158
"""
158
159
Recalculates the gradient map based on the current costmap.
159
160
"""
161
+ assert self .base_costmap is not None , "Base costmap is not initialized"
160
162
gradient = np .gradient (self .base_costmap )
161
163
norms = np .linalg .norm (gradient , axis = 0 )
162
164
@@ -186,7 +188,7 @@ def cost_at_relative_xy(self, x: float, y: float) -> float:
186
188
187
189
return self .get_cost_at_field_position (point .point .x , point .point .y )
188
190
189
- def calc_base_costmap (self ):
191
+ def calc_base_costmap (self ) -> None :
190
192
"""
191
193
Builds the base costmap based on the behavior parameters.
192
194
This costmap includes a gradient towards the enemy goal and high costs outside the playable area
@@ -203,11 +205,11 @@ def calc_base_costmap(self):
203
205
204
206
# Create Grid
205
207
grid_x , grid_y = np .mgrid [
206
- 0 : self .field_length + self .map_margin * 2 : (self .field_length + self .map_margin * 2 ) * 10j ,
207
- 0 : self .field_width + self .map_margin * 2 : (self .field_width + self .map_margin * 2 ) * 10j ,
208
+ 0 : self .field_length + self .map_margin * 2 : (self .field_length + self .map_margin * 2 ) * 10j , # type: ignore[misc]
209
+ 0 : self .field_width + self .map_margin * 2 : (self .field_width + self .map_margin * 2 ) * 10j , # type: ignore[misc]
208
210
]
209
211
210
- fix_points : List [ Tuple [ Tuple [float , float ], float ]] = []
212
+ fix_points : list [ tuple [ tuple [float , float ], float ]] = []
211
213
212
214
# Add base points
213
215
fix_points .extend (
@@ -278,15 +280,17 @@ def calc_base_costmap(self):
278
280
)
279
281
280
282
# Smooth the costmap to get more continuous gradients
281
- self .base_costmap = gaussian_filter (interpolated , self .body_config ["base_costmap_smoothing_sigma" ])
283
+ base_costmap : np .ndarray = gaussian_filter (interpolated , self .body_config ["base_costmap_smoothing_sigma" ])
284
+ self .base_costmap = base_costmap
282
285
self .costmap = self .base_costmap .copy ()
283
286
284
- def get_gradient_at_field_position (self , x : float , y : float ) -> Tuple [float , float ]:
287
+ def get_gradient_at_field_position (self , x : float , y : float ) -> tuple [float , float ]:
285
288
"""
286
289
Gets the gradient tuple at a given field position
287
290
:param x: Field coordinate in the x direction
288
291
:param y: Field coordinate in the y direction
289
292
"""
293
+ assert self .gradient_map is not None , "Gradient map is not initialized"
290
294
idx_x , idx_y = self .field_2_costmap_coord (x , y )
291
295
return - self .gradient_map [0 ][idx_x , idx_y ], - self .gradient_map [1 ][idx_x , idx_y ]
292
296
@@ -296,10 +300,11 @@ def get_cost_at_field_position(self, x: float, y: float) -> float:
296
300
:param x: Field coordinate in the x direction
297
301
:param y: Field coordinate in the y direction
298
302
"""
303
+ assert self .costmap is not None , "Costmap is not initialized"
299
304
idx_x , idx_y = self .field_2_costmap_coord (x , y )
300
305
return self .costmap [idx_x , idx_y ]
301
306
302
- def get_gradient_direction_at_field_position (self , x : float , y : float ):
307
+ def get_gradient_direction_at_field_position (self , x : float , y : float ) -> float :
303
308
"""
304
309
Returns the gradient direction at the given position
305
310
:param x: Field coordinate in the x direction
@@ -318,7 +323,9 @@ def get_gradient_direction_at_field_position(self, x: float, y: float):
318
323
grad = self .get_gradient_at_field_position (x , y )
319
324
return math .atan2 (grad [1 ], grad [0 ])
320
325
321
- def get_cost_of_kick_relative (self , x : float , y : float , direction : float , kick_length : float , angular_range : float ):
326
+ def get_cost_of_kick_relative (
327
+ self , x : float , y : float , direction : float , kick_length : float , angular_range : float
328
+ ) -> float :
322
329
"""
323
330
Returns the cost of a kick at the given position and direction in base footprint frame
324
331
:param x: Field coordinate in the x direction
@@ -356,6 +363,7 @@ def get_cost_of_kick(self, x: float, y: float, direction: float, kick_length: fl
356
363
:param kick_length: The length of the kick
357
364
:param angular_range: The angular range of the kick
358
365
"""
366
+ assert self .costmap is not None , "Costmap is not initialized"
359
367
360
368
# create a mask in the size of the costmap consisting of 8-bit values initialized as 0
361
369
mask = Image .new ("L" , (self .costmap .shape [1 ], self .costmap .shape [0 ]))
@@ -386,7 +394,7 @@ def get_cost_of_kick(self, x: float, y: float, direction: float, kick_length: fl
386
394
# This should contribute way less than the max and should have an impact if the max values are similar in all directions.
387
395
return masked_costmap .max () * 0.75 + masked_costmap .min () * 0.25
388
396
389
- def get_current_cost_of_kick (self , direction : float , kick_length : float , angular_range : float ):
397
+ def get_current_cost_of_kick (self , direction : float , kick_length : float , angular_range : float ) -> float :
390
398
"""
391
399
Returns the cost of the kick at the current position
392
400
:param direction: The direction of the kick
0 commit comments