Nav2 Navigation Stack - rolling  main
ROS 2 Navigation Stack
helper.py
1 # Copyright (c) 2021, Matthew Booker
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License. Reserved.
14 
15 from typing import Any, Optional
16 
17 import numpy as np
18 from numpy.typing import NDArray
19 
20 
21 def normalize_angle(angle: float) -> float:
22  """
23  Normalize the angle to between [0, 2pi).
24 
25  Args:
26  angle: float
27  The angle to normalize in radians
28 
29  Returns
30  -------
31  The normalized angle in the range [0,2pi)
32 
33  """
34  while angle >= 2 * np.pi:
35  angle -= 2 * np.pi
36 
37  while angle < 0:
38  angle += 2 * np.pi
39 
40  return angle
41 
42 
43 def angle_difference(angle_1: float, angle_2: float,
44  left_turn: Optional[float] = None) -> float:
45  """
46  Calculate the difference between two angles based on a given direction.
47 
48  Args:
49  angle_1: float
50  The starting angle in radians
51  angle_2: float
52  The ending angle in radians
53  left_turn: bool
54  The direction of turn. True if left, false if right
55  and None if smallest angular difference should be
56  returned
57 
58  Returns
59  -------
60  The angular difference between the two angles according to
61  the specified turn direction
62 
63  """
64  if left_turn is None:
65  dif = abs(angle_1 - angle_2)
66 
67  return dif if dif <= np.pi else 2 * np.pi - dif
68 
69  elif left_turn:
70 
71  if angle_2 >= angle_1:
72  return abs(angle_1 - angle_2)
73  else:
74  return 2 * np.pi - abs(angle_1 - angle_2)
75 
76  else:
77  if angle_1 >= angle_2:
78  return abs(angle_1 - angle_2)
79  else:
80  return 2 * np.pi - abs(angle_1 - angle_2)
81 
82 
83 def interpolate_yaws(start_angle: float, end_angle: float,
84  left_turn: bool, steps: int) -> Any:
85  """
86  Create equally spaced yaws between two angles.
87 
88  Args:
89  start_angle: float
90  The starting angle
91  end_angle: float
92  The ending angle
93  left_turn: bool
94  The direction of turn. True if left, False otherwise
95  steps: int
96  The number of yaws to generate between start and end
97  angle
98 
99  Returns
100  -------
101  An array of yaws starting at start angle and ending at end
102  angle with steps number of angles between them
103 
104  """
105  if left_turn:
106  if start_angle > end_angle:
107  end_angle += 2 * np.pi
108  else:
109  if end_angle > start_angle:
110  end_angle -= 2 * np.pi
111 
112  yaws = np.linspace(start_angle, end_angle, steps)
113  yaws = np.vectorize(normalize_angle)(yaws)
114 
115  return yaws
116 
117 
118 def get_rotation_matrix(angle: float) -> NDArray[np.floating[Any]]:
119  """
120  Return a rotation matrix that is equivalent to a 2D rotation of angle.
121 
122  Args:
123  angle: float
124  The angle to create a rotation matrix for
125 
126  Returns
127  -------
128  A 2x2 matrix representing a 2D rotation by angle
129 
130  """
131  return np.array([[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]])