basic implementation
parent
11a2b947e0
commit
444f248d28
@ -1 +1,2 @@
|
|||||||
|
numpy
|
||||||
pygame
|
pygame
|
@ -0,0 +1,88 @@
|
|||||||
|
"""Module containing simulated robot sensors"""
|
||||||
|
import math
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
def add_noise(distance, angle, sigma):
|
||||||
|
mean = np.array[distance, angle]
|
||||||
|
# Noise for distance or angle are not correlated
|
||||||
|
covariance = np.diag(sigma ** 2)
|
||||||
|
new_distance, new_angle = np.random.multivariate_normal(mean, covariance)
|
||||||
|
# Don't want negative values
|
||||||
|
new_distance = max(new_distance, 0)
|
||||||
|
new_angle = max(new_angle, 0)
|
||||||
|
return [new_distance, new_angle]
|
||||||
|
|
||||||
|
|
||||||
|
class Lidar2DSensor:
|
||||||
|
|
||||||
|
def __init__(self, senor_range, environment_map, uncertainty, speed=4, colors=None):
|
||||||
|
"""
|
||||||
|
:param range: range of the sensor
|
||||||
|
:param map: the map
|
||||||
|
:param uncertainty: uncertainty of sensor measurements
|
||||||
|
:param speed: revolutions per second
|
||||||
|
"""
|
||||||
|
self.range = senor_range
|
||||||
|
self.map = environment_map
|
||||||
|
self._uncertainty = uncertainty
|
||||||
|
self.speed = speed
|
||||||
|
# The sensor noise represented as a distance and an angle
|
||||||
|
self.sigma = np.array([self._uncertainty[0], self._uncertainty[1]])
|
||||||
|
# TODO make this a value of the robot.
|
||||||
|
self.position = (0, 0)
|
||||||
|
self.map_width, self.map_height = self.map.get_surface().get_size()
|
||||||
|
self.sensor_point_cloud = []
|
||||||
|
self.colors = colors
|
||||||
|
|
||||||
|
def calc_distance(self, obstacle_position):
|
||||||
|
"""Calculates the distance from robot position to obstacle.
|
||||||
|
|
||||||
|
Uses the Euclidean distance calculation.
|
||||||
|
distance = sqrt((Xb - Xa)^2 + (Yb-Ya)^2)
|
||||||
|
"""
|
||||||
|
px = (obstacle_position[0] - self.position[0]) ** 2
|
||||||
|
py = (obstacle_position[1] - self.position[1]) ** 2
|
||||||
|
return math.sqrt(px + py)
|
||||||
|
|
||||||
|
def sense_obstacles(self):
|
||||||
|
data = []
|
||||||
|
x1, y1 = self.position[0], self.position[1]
|
||||||
|
|
||||||
|
# 360 degrees == 2Pi radians
|
||||||
|
# np.linspace's use allows up to set the number of values which affects the simulated map resolution.
|
||||||
|
for angle in np.linspace(0, 2 * math.pi, 60, False):
|
||||||
|
# Calculate the end point of the lidar range's line segment in the 2D plane
|
||||||
|
x2, y2 = (x1 + self.range * math.cos(angle), y1 - self.range * math.sin(angle))
|
||||||
|
# Sample the line segment and detext if the sampled point is "black" when overlayed on the simulated map
|
||||||
|
for i in range(0, 100):
|
||||||
|
# TODO break this out to a function
|
||||||
|
u = i / 100
|
||||||
|
# TODO add comment explaining this calculation
|
||||||
|
x = int(x2 * u + x1 * (1 - u))
|
||||||
|
y = int(y2 * u + y1 * (1 - u))
|
||||||
|
# TODO an optimization could be performed to not sample any further
|
||||||
|
# if the point has fallen off the map.
|
||||||
|
# Check if the sampled point is on the map
|
||||||
|
if 0 < x < self.map_width and 0 < y < self.map_height:
|
||||||
|
map_point_color = self.map.get_at((x, y))
|
||||||
|
if (map_point_color[0], map_point_color[1], map_point_color[2]) == (0, 0, 0):
|
||||||
|
# if black add some noise
|
||||||
|
distance = self.calc_distance((x, y))
|
||||||
|
noised_distance = add_noise(distance, angle, self.sigma)
|
||||||
|
# TODO there is definitely a better datastructure to use. Maybe a named tuple?
|
||||||
|
noised_distance.append(self.position)
|
||||||
|
data.append(noised_distance)
|
||||||
|
# if obstacle found stop further sampling this line
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# line fell off of map break this loop iteration
|
||||||
|
break
|
||||||
|
# TODO OMG I hate this guys code
|
||||||
|
# Callers of this function need to check truthiness not in the return statement
|
||||||
|
# if len(data)>0:
|
||||||
|
# return data
|
||||||
|
# else:
|
||||||
|
# return False
|
||||||
|
return data
|
Loading…
Reference in New Issue