Files
2022-11-10 21:29:11 +09:00

141 lines
3.7 KiB
Python

"""
Simulator
author: Atsushi Sakai
"""
import sys
import pathlib
sys.path.append(str(pathlib.Path(__file__).parent.parent.parent))
import numpy as np
import matplotlib.pyplot as plt
import math
import random
from utils.angle import rot_mat_2d
class VehicleSimulator:
def __init__(self, i_x, i_y, i_yaw, i_v, max_v, w, L):
self.x = i_x
self.y = i_y
self.yaw = i_yaw
self.v = i_v
self.max_v = max_v
self.W = w
self.L = L
self._calc_vehicle_contour()
def update(self, dt, a, omega):
self.x += self.v * np.cos(self.yaw) * dt
self.y += self.v * np.sin(self.yaw) * dt
self.yaw += omega * dt
self.v += a * dt
if self.v >= self.max_v:
self.v = self.max_v
def plot(self):
plt.plot(self.x, self.y, ".b")
# convert global coordinate
gx, gy = self.calc_global_contour()
plt.plot(gx, gy, "--b")
def calc_global_contour(self):
gxy = np.stack([self.vc_x, self.vc_y]).T @ rot_mat_2d(self.yaw)
gx = gxy[:, 0] + self.x
gy = gxy[:, 1] + self.y
return gx, gy
def _calc_vehicle_contour(self):
self.vc_x = []
self.vc_y = []
self.vc_x.append(self.L / 2.0)
self.vc_y.append(self.W / 2.0)
self.vc_x.append(self.L / 2.0)
self.vc_y.append(-self.W / 2.0)
self.vc_x.append(-self.L / 2.0)
self.vc_y.append(-self.W / 2.0)
self.vc_x.append(-self.L / 2.0)
self.vc_y.append(self.W / 2.0)
self.vc_x.append(self.L / 2.0)
self.vc_y.append(self.W / 2.0)
self.vc_x, self.vc_y = self._interpolate(self.vc_x, self.vc_y)
@staticmethod
def _interpolate(x, y):
rx, ry = [], []
d_theta = 0.05
for i in range(len(x) - 1):
rx.extend([(1.0 - theta) * x[i] + theta * x[i + 1]
for theta in np.arange(0.0, 1.0, d_theta)])
ry.extend([(1.0 - theta) * y[i] + theta * y[i + 1]
for theta in np.arange(0.0, 1.0, d_theta)])
rx.extend([(1.0 - theta) * x[len(x) - 1] + theta * x[1]
for theta in np.arange(0.0, 1.0, d_theta)])
ry.extend([(1.0 - theta) * y[len(y) - 1] + theta * y[1]
for theta in np.arange(0.0, 1.0, d_theta)])
return rx, ry
class LidarSimulator:
def __init__(self):
self.range_noise = 0.01
def get_observation_points(self, v_list, angle_resolution):
x, y, angle, r = [], [], [], []
# store all points
for v in v_list:
gx, gy = v.calc_global_contour()
for vx, vy in zip(gx, gy):
v_angle = math.atan2(vy, vx)
vr = np.hypot(vx, vy) * random.uniform(1.0 - self.range_noise,
1.0 + self.range_noise)
x.append(vx)
y.append(vy)
angle.append(v_angle)
r.append(vr)
# ray casting filter
rx, ry = self.ray_casting_filter(angle, r, angle_resolution)
return rx, ry
@staticmethod
def ray_casting_filter(theta_l, range_l, angle_resolution):
rx, ry = [], []
range_db = [float("inf") for _ in range(
int(np.floor((np.pi * 2.0) / angle_resolution)) + 1)]
for i in range(len(theta_l)):
angle_id = int(round(theta_l[i] / angle_resolution))
if range_db[angle_id] > range_l[i]:
range_db[angle_id] = range_l[i]
for i in range(len(range_db)):
t = i * angle_resolution
if range_db[i] != float("inf"):
rx.append(range_db[i] * np.cos(t))
ry.append(range_db[i] * np.sin(t))
return rx, ry