Skip to content

Commit bf58870

Browse files
committed
Created example python package AtsushiSakai#724
1 parent a0775ee commit bf58870

File tree

4 files changed

+193
-0
lines changed

4 files changed

+193
-0
lines changed

pyproject.toml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[build-system]
2+
requires = ["setuptools>=61.0"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "atsushi_robotics"
7+
version = "0.0.1"
8+
authors = [
9+
{ name="Atsushi Sakai", email="asakaig@gmail.com" },
10+
{ name="Abinash Satapathy", email="contact@abinash.nl"}
11+
]
12+
description = "Quick robotics algorithms"
13+
readme = "README.md"
14+
requires-python = ">=3.7"
15+
classifiers = [
16+
"Programming Language :: Python :: 3",
17+
"License :: OSI Approved :: MIT License",
18+
"Operating System :: OS Independent",
19+
]
20+
21+
[project.urls]
22+
"Homepage" = "https://github.com/AtsushiSakai/PythonRobotics"
23+
"Bug Tracker" = "https://github.com/AtsushiSakai/PythonRobotics/issues"

src/atsushi_robotics/__init__.py

Whitespace-only changes.

src/atsushi_robotics/angle.py

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import numpy as np
2+
from scipy.spatial.transform import Rotation as Rot
3+
4+
5+
def rot_mat_2d(angle):
6+
"""
7+
Create 2D rotation matrix from an angle
8+
9+
Parameters
10+
----------
11+
angle :
12+
13+
Returns
14+
-------
15+
A 2D rotation matrix
16+
17+
Examples
18+
--------
19+
>>> angle_mod(-4.0)
20+
21+
22+
"""
23+
return Rot.from_euler('z', angle).as_matrix()[0:2, 0:2]
24+
25+
26+
def angle_mod(x, zero_2_2pi=False, degree=False):
27+
"""
28+
Angle modulo operation
29+
Default angle modulo range is [-pi, pi)
30+
31+
Parameters
32+
----------
33+
x : float or array_like
34+
A angle or an array of angles. This array is flattened for
35+
the calculation. When an angle is provided, a float angle is returned.
36+
zero_2_2pi : bool, optional
37+
Change angle modulo range to [0, 2pi)
38+
Default is False.
39+
degree : bool, optional
40+
If True, then the given angles are assumed to be in degrees.
41+
Default is False.
42+
43+
Returns
44+
-------
45+
ret : float or ndarray
46+
an angle or an array of modulated angle.
47+
48+
Examples
49+
--------
50+
>>> angle_mod(-4.0)
51+
2.28318531
52+
53+
>>> angle_mod([-4.0])
54+
np.array(2.28318531)
55+
56+
>>> angle_mod([-150.0, 190.0, 350], degree=True)
57+
array([-150., -170., -10.])
58+
59+
>>> angle_mod(-60.0, zero_2_2pi=True, degree=True)
60+
array([300.])
61+
62+
"""
63+
if isinstance(x, float):
64+
is_float = True
65+
else:
66+
is_float = False
67+
68+
x = np.asarray(x).flatten()
69+
if degree:
70+
x = np.deg2rad(x)
71+
72+
if zero_2_2pi:
73+
mod_angle = x % (2 * np.pi)
74+
else:
75+
mod_angle = (x + np.pi) % (2 * np.pi) - np.pi
76+
77+
if degree:
78+
mod_angle = np.rad2deg(mod_angle)
79+
80+
if is_float:
81+
return mod_angle.item()
82+
else:
83+
return mod_angle

src/atsushi_robotics/plot.py

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"""
2+
Matplotlib based plotting utilities
3+
"""
4+
import math
5+
import matplotlib.pyplot as plt
6+
import numpy as np
7+
8+
9+
def plot_arrow(x, y, yaw, arrow_length=1.0,
10+
origin_point_plot_style="xr",
11+
head_width=0.1, fc="r", ec="k", **kwargs):
12+
"""
13+
Plot an arrow or arrows based on 2D state (x, y, yaw)
14+
15+
All optional settings of matplotlib.pyplot.arrow can be used.
16+
- matplotlib.pyplot.arrow:
17+
https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.arrow.html
18+
19+
Parameters
20+
----------
21+
x : a float or array_like
22+
a value or a list of arrow origin x position.
23+
y : a float or array_like
24+
a value or a list of arrow origin y position.
25+
yaw : a float or array_like
26+
a value or a list of arrow yaw angle (orientation).
27+
arrow_length : a float (optional)
28+
arrow length. default is 1.0
29+
origin_point_plot_style : str (optional)
30+
origin point plot style. If None, not plotting.
31+
head_width : a float (optional)
32+
arrow head width. default is 0.1
33+
fc : string (optional)
34+
face color
35+
ec : string (optional)
36+
edge color
37+
"""
38+
if not isinstance(x, float):
39+
for (i_x, i_y, i_yaw) in zip(x, y, yaw):
40+
plot_arrow(i_x, i_y, i_yaw, head_width=head_width,
41+
fc=fc, ec=ec, **kwargs)
42+
else:
43+
plt.arrow(x, y,
44+
arrow_length * math.cos(yaw),
45+
arrow_length * math.sin(yaw),
46+
head_width=head_width,
47+
fc=fc, ec=ec,
48+
**kwargs)
49+
if origin_point_plot_style is not None:
50+
plt.plot(x, y, origin_point_plot_style)
51+
52+
53+
def plot_curvature(x_list, y_list, heading_list, curvature,
54+
k=0.01, c="-c", label="Curvature"):
55+
"""
56+
Plot curvature on 2D path. This plot is a line from the original path,
57+
the lateral distance from the original path shows curvature magnitude.
58+
Left turning shows right side plot, right turning shows left side plot.
59+
For straight path, the curvature plot will be on the path, because
60+
curvature is 0 on the straight path.
61+
62+
Parameters
63+
----------
64+
x_list : array_like
65+
x position list of the path
66+
y_list : array_like
67+
y position list of the path
68+
heading_list : array_like
69+
heading list of the path
70+
curvature : array_like
71+
curvature list of the path
72+
k : float
73+
curvature scale factor to calculate distance from the original path
74+
c : string
75+
color of the plot
76+
label : string
77+
label of the plot
78+
"""
79+
cx = [x + d * k * np.cos(yaw - np.pi / 2.0) for x, y, yaw, d in
80+
zip(x_list, y_list, heading_list, curvature)]
81+
cy = [y + d * k * np.sin(yaw - np.pi / 2.0) for x, y, yaw, d in
82+
zip(x_list, y_list, heading_list, curvature)]
83+
84+
plt.plot(cx, cy, c, label=label)
85+
for ix, iy, icx, icy in zip(x_list, y_list, cx, cy):
86+
plt.plot([ix, icx], [iy, icy], c)
87+

0 commit comments

Comments
 (0)