Skip to content

Commit

Permalink
Remove Cython dependency (#80)
Browse files Browse the repository at this point in the history
* format

* fix docs
  • Loading branch information
PENG Zhenghao committed Sep 16, 2021
1 parent d08d430 commit c72fa56
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 354 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ Install MetaDrive via:
```bash
git clone https://github.com/decisionforce/metadrive.git
cd metadrive
pip install numpy cython
pip install -e .
```

Expand Down
1 change: 0 additions & 1 deletion documentation/source/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ We recommend to use the command following to install::

git clone https://github.com/decisionforce/metadrive.git
cd metadrive
pip install numpy cython
pip install -e .


Expand Down
75 changes: 70 additions & 5 deletions metadrive/component/vehicle_module/distance_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,83 @@
from panda3d.bullet import BulletGhostNode, BulletSphereShape
from panda3d.core import NodePath

from metadrive.constants import Mask
from metadrive.constants import CamMask, CollisionGroup
from metadrive.engine.asset_loader import AssetLoader
from metadrive.engine.engine_utils import get_engine
from metadrive.utils import import_cutils
from metadrive.utils.coordinates_shift import panda_position

cutils = import_cutils()
from metadrive.utils.math_utils import panda_position, get_laser_end

detect_result = namedtuple("detect_result", "cloud_points detected_objects")


def add_cloud_point_vis(
point_x, point_y, height, num_lasers, laser_index, ANGLE_FACTOR, MARK_COLOR0, MARK_COLOR1, MARK_COLOR2
):
f = laser_index / num_lasers if ANGLE_FACTOR else 1
return laser_index, (point_x, point_y, height), (f * MARK_COLOR0, f * MARK_COLOR1, f * MARK_COLOR2)


def perceive(
cloud_points, detector_mask, mask, lidar_range, perceive_distance, heading_theta, vehicle_position_x,
vehicle_position_y, num_lasers, height, physics_world, extra_filter_node, require_colors, ANGLE_FACTOR, MARK_COLOR0,
MARK_COLOR1, MARK_COLOR2
):
cloud_points.fill(1.0)
detected_objects = []
colors = []
pg_start_position = panda_position(vehicle_position_x, vehicle_position_y, height)

for laser_index in range(num_lasers):
if (detector_mask is not None) and (not detector_mask[laser_index]):
# update vis
if require_colors:
point_x, point_y = get_laser_end(
lidar_range, perceive_distance, laser_index, heading_theta, vehicle_position_x, vehicle_position_y
)
point_x, point_y, point_z = panda_position(point_x, point_y, height)
colors.append(
add_cloud_point_vis(
point_x, point_y, height, num_lasers, laser_index, ANGLE_FACTOR, MARK_COLOR0, MARK_COLOR1,
MARK_COLOR2
)
)
continue

# # coordinates problem here! take care
point_x, point_y = get_laser_end(
lidar_range, perceive_distance, laser_index, heading_theta, vehicle_position_x, vehicle_position_y
)
laser_end = panda_position(point_x, point_y, height)
result = physics_world.rayTestClosest(pg_start_position, laser_end, mask)
node = result.getNode()
if node in extra_filter_node:
# Fall back to all tests.
results = physics_world.rayTestAll(pg_start_position, laser_end, mask)
hits = results.getHits()
hits = sorted(hits, key=lambda ret: ret.getHitFraction())
for result in hits:
if result.getNode() in extra_filter_node:
continue
detected_objects.append(result)
cloud_points[laser_index] = result.getHitFraction()
laser_end = result.getHitPos()
break
else:
cloud_points[laser_index] = result.getHitFraction()
if result.hasHit():
laser_end = result.getHitPos()
if node:
detected_objects.append(result)
if require_colors:
colors.append(
add_cloud_point_vis(
laser_end[0], laser_end[1], height, num_lasers, laser_index, ANGLE_FACTOR, MARK_COLOR0, MARK_COLOR1,
MARK_COLOR2
)
)
return cloud_points, detected_objects, colors


class DistanceDetector:
"""
It is a module like lidar, used to detect sidewalk/center line or other static things
Expand Down Expand Up @@ -68,7 +133,7 @@ def perceive(self, base_vehicle, physics_world, detector_mask: np.ndarray = None
vehicle_position = base_vehicle.position
heading_theta = base_vehicle.heading_theta
assert not isinstance(detector_mask, str), "Please specify detector_mask either with None or a numpy array."
cloud_points, detected_objects, colors = cutils.cutils_perceive(
cloud_points, detected_objects, colors = perceive(
cloud_points=np.ones((self.num_lasers, ), dtype=float),
detector_mask=detector_mask.astype(dtype=np.uint8) if detector_mask is not None else None,
mask=self.mask,
Expand Down
160 changes: 4 additions & 156 deletions metadrive/tests/test_component/test_detector_mask.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
import copy
import logging
import math
from collections import defaultdict
from collections import namedtuple

from metadrive.utils import import_cutils

cutils = import_cutils()

detect_result = namedtuple("detect_result", "cloud_points detected_objects")
from collections import defaultdict, namedtuple

import numpy as np

from metadrive.component.vehicle.base_vehicle import BaseVehicle
from metadrive.envs import MetaDriveEnv

from metadrive.utils import panda_position
detect_result = namedtuple("detect_result", "cloud_points detected_objects")


class DetectorMask:
Expand Down Expand Up @@ -319,151 +312,6 @@ def test_detector_mask_in_lidar():
env.close()


def test_cutils_lidar():
def _old_perceive(
self,
vehicle_position,
heading_theta,
physics_world,
extra_filter_node: set = None,
detector_mask: np.ndarray = None
):
"""
Call me to update the perception info
"""
assert detector_mask is not "WRONG"
# coordinates problem here! take care
extra_filter_node = extra_filter_node or set()
pg_start_position = panda_position(vehicle_position, self.height)

# init
self.cloud_points = np.array([1.0 for _ in range(self.num_lasers)])
self.cloud_points.fill(1.0)
self.detected_objects = []

# lidar calculation use pg coordinates
mask = self.mask
# laser_heading = self._lidar_range + heading_theta
# point_x = self.perceive_distance * np.cos(laser_heading) + vehicle_position[0]
# point_y = self.perceive_distance * np.sin(laser_heading) + vehicle_position[1]

# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
for laser_index in range(self.num_lasers):
# # coordinates problem here! take care

if (detector_mask is not None) and (not detector_mask[laser_index]):
# update vis
if self.cloud_points_vis is not None:
laser_end = self._get_laser_end(laser_index, heading_theta, vehicle_position)
self._add_cloud_point_vis(laser_index, laser_end)
continue

laser_end = self._get_laser_end(laser_index, heading_theta, vehicle_position)
result = physics_world.rayTestClosest(pg_start_position, laser_end, mask)
node = result.getNode()
if node in extra_filter_node:
# Fall back to all tests.
results = physics_world.rayTestAll(pg_start_position, laser_end, mask)
hits = results.getHits()
hits = sorted(hits, key=lambda ret: ret.getHitFraction())
for result in hits:
if result.getNode() in extra_filter_node:
continue
self.detected_objects.append(result)
self.cloud_points[laser_index] = result.getHitFraction()
break
else:
hits = result.hasHit()
self.cloud_points[laser_index] = result.getHitFraction()
if node:
self.detected_objects.append(result)

# update vis
if self.cloud_points_vis is not None:
self._add_cloud_point_vis(laser_index, result.getHitPos() if hits else laser_end)
return self.cloud_points

from metadrive.utils.cutils import _get_fake_cutils
_fake_cutils = _get_fake_cutils()

def fake_cutils_perceive(
self,
vehicle_position,
heading_theta,
physics_world,
extra_filter_node: set = None,
detector_mask: np.ndarray = None
):
cloud_points, _, _ = _fake_cutils.cutils_perceive(
cloud_points=self.cloud_points,
detector_mask=detector_mask.astype(dtype=np.uint8) if detector_mask is not None else None,
mask=self.mask,
lidar_range=self._lidar_range,
perceive_distance=self.perceive_distance,
heading_theta=heading_theta,
vehicle_position_x=vehicle_position[0],
vehicle_position_y=vehicle_position[1],
num_lasers=self.num_lasers,
height=self.height,
physics_world=physics_world,
extra_filter_node=extra_filter_node if extra_filter_node else set(),
require_colors=self.cloud_points_vis is not None,
ANGLE_FACTOR=self.ANGLE_FACTOR,
MARK_COLOR0=self.MARK_COLOR[0],
MARK_COLOR1=self.MARK_COLOR[1],
MARK_COLOR2=self.MARK_COLOR[2]
)
return cloud_points.tolist(), _

env = MetaDriveEnv({"map": "C", "traffic_density": 1.0, "environment_num": 10, "use_render": False})
env.reset()
env.vehicle.lidar.cloud_points = np.ones((env.vehicle.lidar.num_lasers, ), dtype=np.float32)
env.vehicle.lidar.detected_objects = []
try:
for _ in range(3):
env.reset()
ep_count = 0
for _ in range(3000):
o, r, d, i = env.step([0, 1])
#
v = env.vehicle
new_cloud_points, _ = v.lidar.perceive(v, detector_mask=None)
new_cloud_points = np.array(copy.deepcopy(new_cloud_points))
old_cloud_points = _old_perceive(
v.lidar, v.position, v.heading_theta, v.engine.physics_world.dynamic_world, {v.chassis.node()}, None
)
np.testing.assert_almost_equal(new_cloud_points, old_cloud_points)

fake_cutils_cloud_points, _ = fake_cutils_perceive(
v.lidar,
v.position,
v.heading_theta,
v.engine.physics_world.dynamic_world,
extra_filter_node={v.chassis.node()},
detector_mask=None
)
np.testing.assert_almost_equal(new_cloud_points, fake_cutils_cloud_points)

# assert sum(abs(mask.astype(int) - real_mask.astype(int))) <= 3
v = env.vehicle
c_p, _ = v.lidar.perceive(v)
old_cloud_points = _old_perceive(
v.lidar, v.position, v.heading_theta, v.engine.physics_world.dynamic_world, {v.chassis.node()},
v.lidar._get_lidar_mask(v)[0]
)
new_cloud_points = np.array(copy.deepcopy(c_p))
np.testing.assert_almost_equal(old_cloud_points, new_cloud_points)

if d:
env.reset()
ep_count += 1
if ep_count == 3:
break
finally:
env.close()


if __name__ == '__main__':
# test_detector_mask()
# test_detector_mask_in_lidar()
test_cutils_lidar()
test_detector_mask()
test_detector_mask_in_lidar()
29 changes: 0 additions & 29 deletions metadrive/tests/test_component/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,5 @@
import numpy as np

from metadrive.utils.cutils import import_cutils


def _test_cutils(cutils):
for _ in range(20):
pos = np.random.normal(1000, 1000, size=(2, ))
n = cutils.cutils_norm(*pos.tolist())
assert abs(n - abs(np.linalg.norm(pos, ord=2))) < 1e-4

clip0 = cutils.cutils_clip(pos[0], 999, 1001)
clip1 = cutils.cutils_clip(pos[1], 999, 1001)
assert np.array_equal(np.clip(pos, 999, 1001), np.array([clip0, clip1]))

ppos = cutils.cutils_panda_position(*pos.tolist())
assert ppos[0] == pos[0]
assert ppos[1] == -pos[1]


def test_cutils():
cutils = import_cutils(use_fake_cutils=False)
_test_cutils(cutils)


def test_fake_cutils():
cutils = import_cutils(use_fake_cutils=True)
_test_cutils(cutils)


def test_utils():
from metadrive.utils.math_utils import safe_clip, safe_clip_for_small_array, get_vertical_vector, distance_greater
Expand All @@ -45,6 +18,4 @@ def test_utils():


if __name__ == '__main__':
test_cutils()
test_fake_cutils()
test_utils()
5 changes: 0 additions & 5 deletions metadrive/tests/test_env/test_ma_roundabout_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,11 +395,6 @@ def test_ma_roundabout_reward_done_alignment_1():
assert iii[TerminationState.CRASH_VEHICLE]
if iii[TerminationState.CRASH_VEHICLE]:
assert iii[TerminationState.CRASH]
# #assert r[kkk] == -1.7777
for kkk, ddd in d.items():
if ddd and kkk != "__all__":
assert i[kkk][TerminationState.OUT_OF_ROAD], i[kkk]
# print('{} done passed!'.format(kkk))
for kkk, rrr in r.items():
if rrr == -1.7777:
# assert d[kkk]
Expand Down
8 changes: 4 additions & 4 deletions metadrive/tests/test_functionality/test_distance_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ def test_original_lidar(render=False):
for hit in env.observations[DEFAULT_AGENT].detected_objects:
if isinstance(hit, BaseVehicle):
detect_base_vehicle = True
if d:
break
# if d:
# break
if not (detect_traffic_vehicle and detect_base_vehicle):
print("Lidar detection failed")
assert detect_traffic_vehicle and detect_base_vehicle, "Lidar detection failed"
Expand Down Expand Up @@ -110,5 +110,5 @@ def test_lidar_with_mask(render=False):


if __name__ == "__main__":
test_lidar_with_mask(render=False)
test_original_lidar(render=False)
# test_lidar_with_mask(render=False)
test_original_lidar(render=True)
1 change: 0 additions & 1 deletion metadrive/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from metadrive.utils.config import Config, merge_config_with_unknown_keys, merge_config
from metadrive.utils.coordinates_shift import panda_heading, panda_position, metadrive_heading, metadrive_position
from metadrive.utils.cutils import import_cutils
from metadrive.utils.math_utils import safe_clip, clip, norm, distance_greater, safe_clip_for_small_array, Vector
from metadrive.utils.random_utils import get_np_random, random_string
from metadrive.utils.utils import is_mac, import_pygame, recursive_equal, setup_logger, merge_dicts, \
Expand Down

0 comments on commit c72fa56

Please sign in to comment.