Skip to content

Commit

Permalink
Added classes instead of parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicolasalan committed Sep 28, 2024
1 parent 578c88d commit 0768092
Show file tree
Hide file tree
Showing 6 changed files with 336 additions and 298 deletions.
60 changes: 27 additions & 33 deletions rnl/environment/environment_navigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,64 +6,58 @@
from mpl_toolkits.mplot3d import Axes3D, art3d

from rnl.algorithms.rainbow import RainbowDQN
from rnl.configs.config import RobotConfig, SensorConfig
from rnl.configs.config import EnvConfig, RenderConfig, RobotConfig, SensorConfig
from rnl.engine.collision import Collision
from rnl.engine.utils import min_laser # normalize)
from rnl.engine.utils import min_laser # normalize
from rnl.engine.utils import angle_to_goal, distance_to_goal, get_reward
from rnl.environment.generate_world import Generator
from rnl.environment.robot import Robot
from rnl.environment.sensor import SensorRobot


class NaviEnv(gym.Env):
def __init__(
self,
robot_config: RobotConfig,
sensor_config: SensorConfig,
state_size: int = 24,
action_size: int = 6,
max_timestep: int = 1000, # max step
threshold: float = 0.05, # 0.1 threshold
grid_lenght: int = 5, # TODO: error < 5 -> [5 - 15]
rgb_array: bool = False,
fps: int = 100, # 10 frames per second
mode: str = "normal",
controller: bool = False,
env_config: EnvConfig,
render_config: RenderConfig,
):
super().__init__()
self.action_space = spaces.Discrete(action_size)
state_size = sensor_config.num_rays + 4 # (action, distance, angle, reward)
self.action_space = spaces.Discrete(6) # action
self.observation_space = spaces.Box(
low=-np.inf, high=np.inf, shape=(state_size,), dtype=np.float32
)

self.generator = Generator(grid_lenght=grid_lenght, mode=mode)
self.collision = Collision()
self.robot = Robot(
self.collision,
fov=sensor_config.fov,
num_rays=sensor_config.num_rays,
max_range=sensor_config.max_range,
min_range=sensor_config.min_range,
self.generator = Generator(
env_config.grid_dimension,
env_config.porcentage_obstacles,
env_config.random_mode,
)
self.collision = Collision()
self.robot = Robot(robot_config)
self.sensor = SensorRobot(sensor_config)

self.space = self.robot.create_space()
self.body = self.robot.create_robot(self.space)

self.last_states = np.zeros(state_size)

self.rgb_array = rgb_array
self.rgb_array = render_config.rgb_array
self.timestep = 0
self.max_timestep = max_timestep
self.step_anim = max_timestep
self.fps = fps
self.threshold = threshold
self.grid_lenght = grid_lenght
self.xmax = grid_lenght - 0.25
self.ymax = grid_lenght - 0.25
self.max_timestep = env_config.max_step
self.step_anim = env_config.max_step
self.fps = render_config.fps
self.threshold = robot_config.threshold
self.grid_lenght = env_config.grid_dimension
self.xmax = env_config.grid_dimension - 0.25
self.ymax = env_config.grid_dimension - 0.25
self.dist_max = np.sqrt(self.xmax**2 + self.ymax**2)

self.segments = []
# TODO
self.controller = controller
self.controller = render_config.controller
self.cumulated_reward = 0.0

self.target_x = 0
Expand All @@ -87,7 +81,7 @@ def __init__(
device="mps",
)

if rgb_array:
if self.rgb_array:
self.fig, self.ax = plt.subplots(1, 1, figsize=(6, 6))
self.ax.remove()
self.ax = self.fig.add_subplot(1, 1, 1, projection="3d")
Expand Down Expand Up @@ -180,7 +174,7 @@ def step_animation(self, i):
self.robot.move_robot(self.space, self.body, self.vl, self.vr)
x, y = self.body.position.x, self.body.position.y

intersections, lidar_measurements = self.robot.sensor(
intersections, lidar_measurements = self.sensor.sensor(
x=x, y=y, segments=self.segments
)

Expand Down Expand Up @@ -296,7 +290,7 @@ def step(self, action):
self.robot.move_robot(self.space, self.body, self.vl, self.vr)
x, y = self.body.position.x, self.body.position.y

intersections, lidar_measurements = self.robot.sensor(
intersections, lidar_measurements = self.sensor.sensor(
x=x, y=y, segments=self.segments
)

Expand Down Expand Up @@ -382,7 +376,7 @@ def reset(self, seed=None, options=None):
break

self.robot.reset_robot(self.body, x, y)
intersections, measurement = self.robot.sensor(
intersections, measurement = self.sensor.sensor(
x=self.robot.body.position.x, y=self.robot.body.position.y, segments=all_seg
)

Expand Down
2 changes: 1 addition & 1 deletion rnl/environment/generate_world.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Generator:
def __init__(
self,
grid_lenght: int = 5,
random: int = 1300,
random: float = 0.1, # 1300
mode: str = "normal",
):
self.grid_lenght = grid_lenght
Expand Down
61 changes: 32 additions & 29 deletions rnl/environment/robot.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
from dataclasses import dataclass
from typing import Tuple, List

import numpy as np
import pymunk
from pymunk import Vec2d

from rnl.configs.config import RobotConfig


@dataclass
class Robot:
"""
A class representing a robot with physical and sensor properties.
"""
collision: 'Collision'
robot_radius: float = 0.033
wheel_base: float = 0.16
fov: float = 4 * np.pi
num_rays: int = 20
max_range: float = 6.0
min_range: float = 1.0
mass: float = 1.0
inertia: float = 0.3

def __post_init__(self):
def __init__(self, robot_config: RobotConfig):
"""
Initialize additional attributes after dataclass initialization.
"""
self.lidar_angle = np.linspace(0, self.fov, self.num_rays)
# Constant acceleration due to gravity
g = 9.81 # m/s²

# Calculating the mass of the robot
self.mass = robot_config.weight / g # kg
self.robot_radius = robot_config.base_radius
self.wheel_base = robot_config.wheel_distance

# Calculating the moment of inertia of the robot
# I = (1/2) * m * r²
self.inertia = 0.5 * self.mass * self.robot_radius**2
self.body = pymunk.Body(self.mass, self.inertia)

@staticmethod
Expand All @@ -35,7 +38,14 @@ def create_space() -> pymunk.Space:
space.gravity = (0.0, 0.0)
return space

def create_robot(self, space: pymunk.Space, friction: float = 0.4, damping: float = 0.1, position_x: float = 0.0, position_y: float = 0.0) -> pymunk.Body:
def create_robot(
self,
space: pymunk.Space,
friction: float = 0.4,
damping: float = 0.1,
position_x: float = 0.0,
position_y: float = 0.0,
) -> pymunk.Body:
"""
Create and add the robot to the given pymunk space.
"""
Expand All @@ -47,11 +57,17 @@ def create_robot(self, space: pymunk.Space, friction: float = 0.4, damping: floa
space.add(body, shape)
return body

def move_robot(self, space: pymunk.Space, robot_body: pymunk.Body, v_linear: float, v_angular: float) -> None:
def move_robot(
self,
space: pymunk.Space,
robot_body: pymunk.Body,
v_linear: float,
v_angular: float,
) -> None:
"""
Move the robot in the space with given linear and angular velocities.
"""
direction = Vec2d(np.cos(robot_body.angle), np.sin(robot_body.angle))
direction = pymunk.Vec2d(np.cos(robot_body.angle), np.sin(robot_body.angle))
robot_body.velocity = v_linear * direction
robot_body.angular_velocity = v_angular
space.step(1 / 60)
Expand All @@ -64,16 +80,3 @@ def reset_robot(self, robot_body: pymunk.Body, x: float, y: float) -> None:
robot_body.angle = 0
robot_body.velocity = (0, 0)
robot_body.angular_velocity = 0

def sensor(self, x: float, y: float, segments: List) -> Tuple[np.ndarray, np.ndarray]:
"""
Perform sensor measurements based on the robot's position and environment segments.
"""
seg = self.collision.filter_segments(segments, x, y, 6)
intersections = self.collision.lidar_intersection(
x, y, self.max_range, self.lidar_angle, seg
)
measurements = self.collision.lidar_measurement(
x, y, self.max_range, self.lidar_angle, seg
)
return intersections, measurements
30 changes: 30 additions & 0 deletions rnl/environment/sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from dataclasses import dataclass
from typing import List, Tuple

import numpy as np

from rnl.configs.config import SensorConfig
from rnl.engine.collision import Collision


@dataclass
class SensorRobot:
def __init__(self, sensor_config: SensorConfig):
self.collision = Collision()
self.max_range = sensor_config.max_range
self.lidar_angle = np.linspace(0, sensor_config.fov, sensor_config.num_rays)

def sensor(
self, x: float, y: float, segments: List
) -> Tuple[np.ndarray, np.ndarray]:
"""
Perform sensor measurements based on the robot's position and environment segments.
"""
seg = self.collision.filter_segments(segments, x, y, 6)
intersections = self.collision.lidar_intersection(
x, y, self.max_range, self.lidar_angle, seg
)
measurements = self.collision.lidar_measurement(
x, y, self.max_range, self.lidar_angle, seg
)
return intersections, measurements
Loading

0 comments on commit 0768092

Please sign in to comment.