Nav2 Navigation Stack - rolling  main
ROS 2 Navigation Stack
occupancy_grid.py
1 #! /usr/bin/env python3
2 # Copyright 2025 Arjo Chakravarty
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 """
17 This is a Python3 API for costmap 2d messages from the stack.
18 
19 It provides the basic conversion, get/set,
20 and handling semantics found in the costmap 2d C++ API.
21 """
22 
23 
24 from nav_msgs.msg import OccupancyGrid
25 import numpy as np
26 
27 
29  """
30  PyOccupancyGrid.
31 
32  Occupancy grid Python3 API for OccupancyGrids to populate from published messages
33  """
34 
35  def __init__(self, occupancy_map: OccupancyGrid):
36  """
37  Initialize costmap2D.
38 
39  Args
40  ----
41  occupancy_map (OccupancyGrid): 2D OccupancyGrid Map
42 
43  Returns
44  -------
45  None
46 
47  """
48  self.size_xsize_x = occupancy_map.info.width
49  self.size_ysize_y = occupancy_map.info.height
50  self.resolutionresolution = occupancy_map.info.resolution
51  self.origin_xorigin_x = occupancy_map.info.origin.position.x
52  self.origin_yorigin_y = occupancy_map.info.origin.position.y
53  self.global_frame_idglobal_frame_id = occupancy_map.header.frame_id
54  self.costmap_timestampcostmap_timestamp = occupancy_map.header.stamp
55  # Extract costmap
56  self.costmapcostmap = np.array(occupancy_map.data, dtype=np.int8)
57 
58  def getSizeInCellsX(self):
59  """Get map width in cells."""
60  return self.size_xsize_x
61 
62  def getSizeInCellsY(self):
63  """Get map height in cells."""
64  return self.size_ysize_y
65 
66  def getSizeInMetersX(self):
67  """Get x axis map size in meters."""
68  return self.size_xsize_x * self.resolutionresolution
69 
70  def getSizeInMetersY(self):
71  """Get y axis map size in meters."""
72  return self.size_ysize_y * self.resolutionresolution
73 
74  def getOriginX(self):
75  """Get the origin x axis of the map [m]."""
76  return self.origin_xorigin_x
77 
78  def getOriginY(self):
79  """Get the origin y axis of the map [m]."""
80  return self.origin_yorigin_y
81 
82  def getResolution(self):
83  """Get map resolution [m/cell]."""
84  return self.resolutionresolution
85 
86  def getGlobalFrameID(self):
87  """Get global frame_id."""
88  return self.global_frame_idglobal_frame_id
89 
91  """Get costmap timestamp."""
92  return self.costmap_timestampcostmap_timestamp
93 
94  def getCostXY(self, mx: int, my: int):
95  """
96  Get the cost of a cell in the costmap using map coordinate XY.
97 
98  Args
99  ----
100  mx (int): map coordinate X to get cost
101  my (int): map coordinate Y to get cost
102 
103  Returns
104  -------
105  np.int8: cost of a cell
106 
107  """
108  return np.int8(self.costmapcostmap[self.getIndexgetIndex(mx, my)])
109 
110  def getCostIdx(self, index: int):
111  """
112  Get the cost of a cell in the costmap using Index.
113 
114  Args
115  ----
116  index (int): index of cell to get cost
117 
118  Returns
119  -------
120  np.int8: cost of a cell
121 
122  """
123  return np.int8(self.costmapcostmap[index])
124 
125  def setCost(self, mx: int, my: int, cost: np.int8):
126  """
127  Set the cost of a cell in the costmap using map coordinate XY.
128 
129  Args
130  ----
131  mx (int): map coordinate X to get cost
132  my (int): map coordinate Y to get cost
133  cost (np.int8): The cost to set the cell
134 
135  Returns
136  -------
137  None
138 
139  """
140  self.costmapcostmap[self.getIndexgetIndex(mx, my)] = cost
141 
142  def mapToWorld(self, mx: int, my: int):
143  """
144  Get the world coordinate XY using map coordinate XY.
145 
146  Args
147  ----
148  mx (int): map coordinate X to get world coordinate
149  my (int): map coordinate Y to get world coordinate
150 
151  Returns
152  -------
153  tuple of float: wx, wy
154  wx (float) [m]: world coordinate X
155  wy (float) [m]: world coordinate Y
156 
157  """
158  wx = self.origin_xorigin_x + (mx + 0.5) * self.resolutionresolution
159  wy = self.origin_yorigin_y + (my + 0.5) * self.resolutionresolution
160  return (wx, wy)
161 
162  def worldToMapValidated(self, wx: float, wy: float):
163  """
164  Get the map coordinate XY using world coordinate XY.
165 
166  Args
167  ----
168  wx (float) [m]: world coordinate X to get map coordinate
169  wy (float) [m]: world coordinate Y to get map coordinate
170 
171  Returns
172  -------
173  (None, None): if coordinates are invalid
174  tuple of int: mx, my (if coordinates are valid)
175  mx (int): map coordinate X
176  my (int): map coordinate Y
177 
178  """
179  if wx < self.origin_xorigin_x or wy < self.origin_yorigin_y:
180  return (None, None)
181  mx = int((wx - self.origin_xorigin_x) // self.resolutionresolution)
182  my = int((wy - self.origin_yorigin_y) // self.resolutionresolution)
183  if mx < self.size_xsize_x and my < self.size_ysize_y:
184  return (mx, my)
185  return (None, None)
186 
187  def getIndex(self, mx: int, my: int):
188  """
189  Get the index of the cell using map coordinate XY.
190 
191  Args
192  ----
193  mx (int): map coordinate X to get Index
194  my (int): map coordinate Y to get Index
195 
196  Returns
197  -------
198  int: The index of the cell
199 
200  """
201  return my * self.size_xsize_x + mx
def __init__(self, OccupancyGrid occupancy_map)
def setCost(self, int mx, int my, np.int8 cost)