From 9a9927cc9ae852bb3bb0376f7ed6f9ece9def470 Mon Sep 17 00:00:00 2001
From: Dmytro Mishkin <ducha.aiki@gmail.com>
Date: Thu, 11 Apr 2019 08:13:25 +0200
Subject: [PATCH] Slambased agents (#39)

* ORBSLAM2 agent refactored for new api

* Added monodepth agent
---
 baselines/agents/slam_agents.py               | 623 ++++++++++++++++++
 baselines/config/default.py                   |  27 +-
 baselines/slambased/README.md                 |  39 ++
 baselines/slambased/data/mp3d3_small1k.yaml   |  69 ++
 baselines/slambased/data/slam-based-agent.png | Bin 0 -> 72060 bytes
 baselines/slambased/install_deps.sh           |  62 ++
 baselines/slambased/mappers.py                | 122 ++++
 baselines/slambased/monodepth.py              | 573 ++++++++++++++++
 baselines/slambased/path_planners.py          | 512 ++++++++++++++
 baselines/slambased/reprojection.py           | 289 ++++++++
 baselines/slambased/utils.py                  |  43 ++
 configs/tasks/pointnav_rgbd.yaml              |  24 +
 12 files changed, 2381 insertions(+), 2 deletions(-)
 create mode 100644 baselines/agents/slam_agents.py
 create mode 100644 baselines/slambased/README.md
 create mode 100644 baselines/slambased/data/mp3d3_small1k.yaml
 create mode 100644 baselines/slambased/data/slam-based-agent.png
 create mode 100755 baselines/slambased/install_deps.sh
 create mode 100644 baselines/slambased/mappers.py
 create mode 100644 baselines/slambased/monodepth.py
 create mode 100644 baselines/slambased/path_planners.py
 create mode 100644 baselines/slambased/reprojection.py
 create mode 100644 baselines/slambased/utils.py
 create mode 100644 configs/tasks/pointnav_rgbd.yaml

diff --git a/baselines/agents/slam_agents.py b/baselines/agents/slam_agents.py
new file mode 100644
index 000000000..741718639
--- /dev/null
+++ b/baselines/agents/slam_agents.py
@@ -0,0 +1,623 @@
+import argparse
+import numpy as np
+import torch
+import random
+import time
+import os
+import PIL
+from math import pi
+import torch.nn.functional as F
+import orbslam2
+import habitat
+from baselines.slambased.utils import (
+    generate_2dgrid,
+)
+from baselines.slambased.reprojection import (
+    homogenize_p,
+    get_distance,
+    project_tps_into_worldmap,
+    get_direction,
+    habitat_goalpos_to_mapgoal_pos,
+    planned_path2tps,
+    angle_to_pi_2_minus_pi_2
+)
+from baselines.slambased.reprojection import (
+    angle_to_pi_2_minus_pi_2 as norm_ang
+)
+from habitat.sims.habitat_simulator import (
+    SimulatorActions,
+    SIM_ACTION_TO_NAME,
+    SIM_NAME_TO_ACTION,
+)
+from baselines.slambased.mappers import DirectDepthMapper
+from baselines.slambased.path_planners import DifferentiableStarPlanner
+
+from baselines.config.default import cfg
+from habitat.config.default import get_config
+
+from baselines.slambased.monodepth import MonoDepthEstimator
+
+# https://sumit-ghosh.com/articles/python-download-progress-bar/
+import sys
+import requests
+def download(url, filename):
+    with open(filename, 'wb') as f:
+        response = requests.get(url, stream=True)
+        total = response.headers.get('content-length')
+        if total is None:
+            f.write(response.content)
+        else:
+            downloaded = 0
+            total = int(total)
+            for data in response.iter_content(chunk_size=max(int(total/1000), 1024*1024)):
+                downloaded += len(data)
+                f.write(data)
+                done = int(50*downloaded/total)
+                sys.stdout.write('\r[{}{}]'.format('â–ˆ' * done, '.' * (50-done)))
+                sys.stdout.flush()
+    sys.stdout.write('\n')
+
+
+def ResizePIL2(np_img, size = 256):
+    im1 = PIL.Image.fromarray(np_img)
+    return np.array(im1.resize((size,size)))
+
+def make_good_config_for_orbslam2(config):
+    config.SIMULATOR.AGENT_0.SENSORS = ["RGB_SENSOR", "DEPTH_SENSOR"]
+    config.SIMULATOR.RGB_SENSOR.WIDTH = 256
+    config.SIMULATOR.RGB_SENSOR.HEIGHT = 256
+    config.SIMULATOR.DEPTH_SENSOR.WIDTH = 256
+    config.SIMULATOR.DEPTH_SENSOR.HEIGHT = 256
+    config.BASELINE.ORBSLAM2.CAMERA_HEIGHT = config.SIMULATOR.DEPTH_SENSOR.POSITION[1]
+    config.BASELINE.ORBSLAM2.H_OBSTACLE_MIN = 0.3 * config.BASELINE.ORBSLAM2.CAMERA_HEIGHT
+    config.BASELINE.ORBSLAM2.H_OBSTACLE_MAX = 1.0 * config.BASELINE.ORBSLAM2.CAMERA_HEIGHT
+    config.BASELINE.ORBSLAM2.MIN_PTS_IN_OBSTACLE = config.SIMULATOR.DEPTH_SENSOR.WIDTH/2.0
+    return
+
+class RandomAgent(object):
+    r"""Simplest agent, which returns random actions,
+    until reach the goal
+    """
+
+    def __init__(
+        self,
+        config
+    ):
+        super(RandomAgent, self).__init__()
+        self.num_actions = config.NUM_ACTIONS
+        self.dist_threshold_to_stop = config.DIST_TO_STOP
+        self.reset()
+        return
+
+    def reset(self):
+        self.steps = 0
+        return
+
+    def update_internal_state(self, habitat_observation):
+        self.obs = habitat_observation
+        self.steps += 1
+        return
+
+    def is_goal_reached(self):
+        dist = self.obs["pointgoal"][0]
+        return dist <= self.dist_threshold_to_stop
+
+    def act(self, habitat_observation=None, random_prob=1.0):
+        self.update_internal_state(habitat_observation)
+        # Act
+        # Check if we are done
+        if self.is_goal_reached():
+            action = SIM_NAME_TO_ACTION[SimulatorActions.STOP.value]
+        else:
+            action = random.randint(0, self.num_actions - 1)
+        return action
+
+
+class BlindAgent(RandomAgent):
+    def __init__(
+        self,
+        config
+    ):
+        super(BlindAgent, self).__init__()
+        self.pos_th = config.DIST_TO_STOP
+        self.angle_th = config.ANGLE_TH
+        self.reset()
+        return
+
+    def decide_what_to_do(self):
+        distance_to_goal = self.obs["pointgoal"][0]
+        angle_to_goal = norm_ang(np.array(self.obs["pointgoal"][1]))
+        command = SIM_NAME_TO_ACTION[SimulatorActions.STOP.value]
+        if distance_to_goal <= self.pos_th:
+            return command
+        if abs(angle_to_goal) < self.angle_th:
+            command = "move_forward"
+        else:
+            if (angle_to_goal > 0) and (angle_to_goal < pi):
+                command = "look_left"
+            elif angle_to_goal > pi:
+                command = "look_right"
+            elif (angle_to_goal < 0) and (angle_to_goal > -pi):
+                command = "look_right"
+            else:
+                command = "look_left"
+        return command
+
+    def act(self, habitat_observation=None, random_prob=0.1):
+        self.update_internal_state(habitat_observation)
+        # Act
+        if self.is_goal_reached():
+            return SIM_NAME_TO_ACTION[SimulatorActions.STOP.value]
+        command = self.decide_what_to_do()
+        random_action = random.randint(0, self.num_actions - 1)
+        act_randomly = np.random.uniform(0, 1, 1) < random_prob
+        if act_randomly:
+            action = random_action
+        else:
+            action = SIM_NAME_TO_ACTION[command]
+        return action
+
+
+class ORBSLAM2Agent(RandomAgent):
+    def __init__(
+        self,
+        config,
+        device=torch.device("cuda:0"),
+    ):
+        self.num_actions = config.NUM_ACTIONS
+        self.dist_threshold_to_stop = config.DIST_TO_STOP
+        self.slam_vocab_path = config.SLAM_VOCAB_PATH
+        assert os.path.isfile(self.slam_vocab_path)
+        self.slam_settings_path = config.SLAM_SETTINGS_PATH
+        assert os.path.isfile(self.slam_settings_path)
+        self.slam = orbslam2.System(
+            self.slam_vocab_path, self.slam_settings_path, orbslam2.Sensor.RGBD
+        )
+        self.slam.set_use_viewer(False)
+        self.slam.initialize()
+        self.device = device
+        self.map_size_meters = config.MAP_SIZE
+        self.map_cell_size = config.MAP_CELL_SIZE
+        self.pos_th = config.DIST_REACHED_TH
+        self.next_wp_th = config.NEXT_WAYPOINT_TH
+        self.angle_th = config.ANGLE_TH
+        self.obstacle_th = config.MIN_PTS_IN_OBSTACLE
+        self.depth_denorm = config.DEPTH_DENORM
+        self.planned_waypoints = []
+        self.mapper = DirectDepthMapper(
+                      camera_height = config.CAMERA_HEIGHT,
+                      near_th = config.D_OBSTACLE_MIN,
+                      far_th = config.D_OBSTACLE_MAX,
+                      h_min = config.H_OBSTACLE_MIN,
+                      h_max = config.H_OBSTACLE_MAX,
+                      map_size = config.MAP_SIZE,
+                      map_cell_size = config.MAP_CELL_SIZE,
+                      device = device)
+        self.planner = DifferentiableStarPlanner(
+                      max_steps = config.PLANNER_MAX_STEPS,
+                      preprocess = config.PREPROCESS_MAP,
+                      beta = config.BETA,
+                      device = device)
+        self.slam_to_world = 1.0
+        self.timestep = 0.1
+        self.timing = False
+        self.reset()
+        return
+
+    def reset(self):
+        super(ORBSLAM2Agent, self).reset()
+        self.offset_to_goal = None
+        self.tracking_is_OK = False
+        self.waypointPose6D = None
+        self.unseen_obstacle = False
+        self.action_history = []
+        self.planned_waypoints = []
+        self.map2DObstacles = self.init_map2d()
+        n, ch, height, width = self.map2DObstacles.size()
+        self.coordinatesGrid = generate_2dgrid(height, width, False).to(
+            self.device
+        )
+        self.pose6D = self.init_pose6d()
+        self.action_history = []
+        self.pose6D_history = []
+        self.position_history = []
+        self.planned2Dpath = torch.zeros((0))
+        self.slam.reset()
+        self.cur_time = 0
+        self.toDoList = []
+        self.waypoint_id = 0
+        if self.device != torch.device("cpu"):
+            torch.cuda.empty_cache()
+        return
+
+    def update_internal_state(self, habitat_observation):
+        super(ORBSLAM2Agent, self).update_internal_state(
+            habitat_observation
+        )
+        self.cur_time += self.timestep
+        rgb, depth = self.rgb_d_from_observation(habitat_observation)
+        t = time.time()
+        try:
+            self.slam.process_image_rgbd(rgb, depth, self.cur_time)
+            if self.timing:
+                print(time.time() - t, "ORB_SLAM2")
+            self.tracking_is_OK = str(self.slam.get_tracking_state()) == "OK"
+        except BaseException:
+            print("Warning!!!! ORBSLAM processing frame error")
+            self.tracking_is_OK = False
+        if not self.tracking_is_OK:
+            self.reset()
+        t = time.time()
+        self.set_offset_to_goal(habitat_observation)
+        if self.tracking_is_OK:
+            trajectory_history = np.array(self.slam.get_trajectory_points())
+            self.pose6D = homogenize_p(
+                torch.from_numpy(trajectory_history[-1])[1:]
+                .view(3, 4)
+                .to(self.device)
+            ).view(1, 4, 4)
+            self.trajectory_history = trajectory_history
+            if len(self.position_history) > 1:
+                previous_step = get_distance(
+                    self.pose6D.view(4, 4),
+                    torch.from_numpy(self.position_history[-1])
+                    .view(4, 4)
+                    .to(self.device),
+                )
+                if (
+                    SIM_ACTION_TO_NAME[self.action_history[-1]]
+                    == "move_forward"
+                ):
+                    self.unseen_obstacle = (
+                        previous_step.item() <= 0.001
+                    )  # hardcoded threshold for not moving
+        current_obstacles = self.mapper(
+            torch.from_numpy(depth).to(self.device).squeeze(), self.pose6D
+        ).to(self.device)
+        self.current_obstacles = current_obstacles
+        self.map2DObstacles = torch.max(
+            self.map2DObstacles, current_obstacles.unsqueeze(0).unsqueeze(0)
+        )
+        if self.timing:
+            print(time.time() - t, "Mapping")
+        return True
+
+    def init_pose6d(self):
+        return torch.eye(4).float().to(self.device)
+
+    def map_size_in_cells(self):
+        return int(self.map_size_meters / self.map_cell_size)
+
+    def init_map2d(self):
+        return (
+            torch.zeros(1,
+                        1,
+                        self.map_size_in_cells(),
+                        self.map_size_in_cells())
+            .float()
+            .to(self.device)
+        )
+
+    def get_orientation_on_map(self):
+        self.pose6D = self.pose6D.view(1, 4, 4)
+        return torch.tensor(
+            [
+                [self.pose6D[0, 0, 0], self.pose6D[0, 0, 2]],
+                [self.pose6D[0, 2, 0], self.pose6D[0, 2, 2]],
+            ]
+        )
+
+    def get_position_on_map(self, do_floor=True):
+        return project_tps_into_worldmap(
+            self.pose6D.view(1, 4, 4),
+            self.map_cell_size,
+            self.map_size_meters,
+            do_floor,
+        )
+
+    def act(self, habitat_observation, random_prob=0.1):
+        # Update internal state
+        t = time.time()
+        cc = 0
+        update_is_ok = self.update_internal_state(habitat_observation)
+        while not update_is_ok:
+            update_is_ok = self.update_internal_state(habitat_observation)
+            cc += 1
+            if cc > 2:
+                break
+        if self.timing:
+            print(time.time() - t, " s, update internal state")
+        self.position_history.append(
+            self.pose6D.detach().cpu().numpy().reshape(1, 4, 4)
+        )
+        success = self.is_goal_reached()
+        if success:
+            action = SIM_NAME_TO_ACTION[SimulatorActions.STOP.value]
+            self.action_history.append(action)
+            return action
+        # Plan action
+        t = time.time()
+        self.planned2Dpath, self.planned_waypoints = self.plan_path()
+        if self.timing:
+            print(time.time() - t, " s, Planning")
+        t = time.time()
+        # Act
+        if self.waypointPose6D is None:
+            self.waypointPose6D = self.get_valid_waypoint_pose6d()
+        if (
+            self.is_waypoint_reached(self.waypointPose6D)
+            or not self.tracking_is_OK
+        ):
+            self.waypointPose6D = self.get_valid_waypoint_pose6d()
+            self.waypoint_id += 1
+        action = self.decide_what_to_do()
+        # May be random?
+        random_action = random.randint(0, self.num_actions - 1)
+        what_to_do = np.random.uniform(0, 1, 1)
+        if what_to_do < random_prob:
+            action = random_action
+        if self.timing:
+            print(time.time() - t, " s, get action")
+        self.action_history.append(action)
+        return action
+
+    def is_waypoint_good(self, pose6d):
+        p_init = self.pose6D.squeeze()
+        dist_diff = get_distance(p_init, pose6d)
+        valid = dist_diff > self.next_wp_th
+        return valid.item()
+
+    def is_waypoint_reached(self, pose6d):
+        p_init = self.pose6D.squeeze()
+        dist_diff = get_distance(p_init, pose6d)
+        reached = dist_diff <= self.pos_th
+        return reached.item()
+
+    def get_waypoint_dist_dir(self):
+        angle = get_direction(
+            self.pose6D.squeeze(), self.waypointPose6D.squeeze(), 0, 0
+        )
+        dist = get_distance(
+            self.pose6D.squeeze(), self.waypointPose6D.squeeze()
+        )
+        return torch.cat(
+            [
+                dist.view(1, 1),
+                torch.sin(angle).view(1, 1),
+                torch.cos(angle).view(1, 1),
+            ],
+            dim=1,
+        )
+
+    def get_valid_waypoint_pose6d(self):
+        p_next = self.planned_waypoints[0]
+        while not self.is_waypoint_good(p_next):
+            if len(self.planned_waypoints) > 1:
+                self.planned_waypoints = self.planned_waypoints[1:]
+                p_next = self.planned_waypoints[0]
+            else:
+                p_next = self.estimatedGoalPos6D.squeeze()
+                break
+        return p_next
+
+    def set_offset_to_goal(self, observation):
+        self.offset_to_goal = (
+            torch.from_numpy(observation["pointgoal"]).float().to(self.device)
+        )
+        self.estimatedGoalPos2D = habitat_goalpos_to_mapgoal_pos(
+            self.offset_to_goal,
+            self.pose6D.squeeze(),
+            self.map_cell_size,
+            self.map_size_meters,
+        )
+        self.estimatedGoalPos6D = planned_path2tps(
+            [self.estimatedGoalPos2D],
+            self.map_cell_size,
+            self.map_size_meters,
+            1.0,
+        ).to(self.device)[0]
+        return
+
+    def rgb_d_from_observation(self, habitat_observation):
+        rgb = habitat_observation["rgb"]
+        depth = None
+        if "depth" in habitat_observation:
+            depth = (
+                self.depth_denorm * habitat_observation["depth"]
+            )  
+        return rgb, depth
+
+    def prev_plan_is_not_valid(self):
+        if len(self.planned2Dpath) == 0:
+            return True
+        pp = torch.cat(self.planned2Dpath).detach().cpu().view(-1, 2)
+        binary_map = self.map2DObstacles.squeeze().detach() >= self.obstacle_th
+        obstacles_on_path = (
+            binary_map[pp[:, 0].long(), pp[:, 1].long()]
+        ).long().sum().item() > 0
+        return obstacles_on_path  # obstacles_nearby or  obstacles_on_path
+
+    def rawmap2_planner_ready(self, rawmap, start_map, goal_map):
+        map1 = (rawmap / float(self.obstacle_th)) ** 2
+        map1 = (
+            torch.clamp(map1, min=0, max=1.0)
+            - start_map
+            - F.max_pool2d(goal_map, 3, stride=1, padding=1)
+        )
+        return torch.relu(map1)
+
+    def plan_path(self, overwrite=False):
+        t = time.time()
+        if (
+            (not self.prev_plan_is_not_valid())
+            and (not overwrite)
+            and (len(self.planned_waypoints) > 0)
+        ):
+            return self.planned2Dpath, self.planned_waypoints
+        self.waypointPose6D = None
+        current_pos = self.get_position_on_map()
+        start_map = torch.zeros_like(self.map2DObstacles).to(self.device)
+        start_map[
+            0, 0, current_pos[0, 0].long(), current_pos[0, 1].long()
+        ] = 1.0
+        goal_map = torch.zeros_like(self.map2DObstacles).to(self.device)
+        goal_map[
+            0,
+            0,
+            self.estimatedGoalPos2D[0, 0].long(),
+            self.estimatedGoalPos2D[0, 1].long(),
+        ] = 1.0
+        path, cost = self.planner(
+            self.rawmap2_planner_ready(
+                self.map2DObstacles, start_map, goal_map
+            ).to(self.device),
+            self.coordinatesGrid.to(self.device),
+            goal_map.to(self.device),
+            start_map.to(self.device),
+        )
+        if len(path) == 0:
+            return path, []
+        if self.timing:
+            print(time.time() - t, " s, Planning")
+        t = time.time()
+        planned_waypoints = planned_path2tps(
+            path, self.map_cell_size, self.map_size_meters, 1.0, False
+        ).to(self.device)
+        return path, planned_waypoints
+
+    def planner_prediction_to_command(self, p_next):
+        command = "stop"
+        p_init = self.pose6D.squeeze()
+        d_angle_rot_th = self.angle_th
+        pos_th = self.pos_th
+        if get_distance(p_init, p_next) <= pos_th:
+            return command
+        d_angle = angle_to_pi_2_minus_pi_2(
+            get_direction(p_init, p_next, ang_th=d_angle_rot_th, pos_th=pos_th)
+        )
+        if abs(d_angle) < d_angle_rot_th:
+            command = "move_forward"
+        else:
+            if (d_angle > 0) and (d_angle < pi):
+                command = "look_left"
+            elif d_angle > pi:
+                command = "look_right"
+            elif (d_angle < 0) and (d_angle > -pi):
+                command = "look_right"
+            else:
+                command = "look_left"
+        return command
+
+    def decide_what_to_do(self):
+        action = None
+        if self.is_goal_reached():
+            action = SIM_NAME_TO_ACTION[SimulatorActions.STOP.value]
+            return action
+        if self.unseen_obstacle:
+            command = "look_right"
+            return SIM_NAME_TO_ACTION[command]
+        command = "stop"
+        command = self.planner_prediction_to_command(self.waypointPose6D)
+        return SIM_NAME_TO_ACTION[command]
+
+class ORBSLAM2MonodepthAgent(ORBSLAM2Agent):
+    def __init__(
+        self,
+        config,
+        device=torch.device("cuda:0"),
+        monocheckpoint = 'baselines/slambased/data/mp3d_resnet50.pth',
+    ):
+        self.num_actions = config.NUM_ACTIONS
+        self.dist_threshold_to_stop = config.DIST_TO_STOP
+        self.slam_vocab_path = config.SLAM_VOCAB_PATH
+        assert os.path.isfile(self.slam_vocab_path)
+        self.slam_settings_path = config.SLAM_SETTINGS_PATH
+        assert os.path.isfile(self.slam_settings_path)
+        self.slam = orbslam2.System(
+            self.slam_vocab_path, self.slam_settings_path, orbslam2.Sensor.RGBD
+        )
+        self.slam.set_use_viewer(False)
+        self.slam.initialize()
+        self.device = device
+        self.map_size_meters = config.MAP_SIZE
+        self.map_cell_size = config.MAP_CELL_SIZE
+        self.pos_th = config.DIST_REACHED_TH
+        self.next_wp_th = config.NEXT_WAYPOINT_TH
+        self.angle_th = config.ANGLE_TH
+        self.obstacle_th = config.MIN_PTS_IN_OBSTACLE
+        self.depth_denorm = config.DEPTH_DENORM
+        self.planned_waypoints = []
+        self.mapper = DirectDepthMapper(
+                      camera_height = config.CAMERA_HEIGHT,
+                      near_th = config.D_OBSTACLE_MIN,
+                      far_th = config.D_OBSTACLE_MAX,
+                      h_min = config.H_OBSTACLE_MIN,
+                      h_max = config.H_OBSTACLE_MAX,
+                      map_size = config.MAP_SIZE,
+                      map_cell_size = config.MAP_CELL_SIZE,
+                      device = device)
+        self.planner = DifferentiableStarPlanner(
+                      max_steps = config.PLANNER_MAX_STEPS,
+                      preprocess = config.PREPROCESS_MAP,
+                      beta = config.BETA,
+                      device = device)
+        self.slam_to_world = 1.0
+        self.timestep = 0.1
+        self.timing = False
+        self.checkpoint = monocheckpoint
+        if not os.path.isfile(self.checkpoint):
+            mp3d_url = 'http://cmp.felk.cvut.cz/~mishkdmy/navigation/mp3d_ft_monodepth_resnet50.pth'
+            suncg_me_url = 'http://cmp.felk.cvut.cz/~mishkdmy/navigation/suncg_me_resnet.pth'
+            suncg_mf_url = 'http://cmp.felk.cvut.cz/~mishkdmy/navigation/suncg_mf_resnet.pth'
+            url = mp3d_url
+            print ("No monodepth checkpoint found. Downloading...", url)
+            download(url, self.checkpoint)
+        self.monodepth = MonoDepthEstimator(self.checkpoint)
+        self.reset()
+        return
+
+    def rgb_d_from_observation(self, habitat_observation):
+        rgb = habitat_observation["rgb"]
+        depth = ResizePIL2(self.monodepth.compute_depth(PIL.Image.fromarray(rgb).resize((320,320))), 256)#/1.75
+        depth[depth > 3.0] = 0
+        depth[depth < 0.1] = 0
+        return rgb, np.array(depth).astype(np.float32)
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        "--agent-type",
+        default="orbslam2-rgbd",
+        choices=["blind",
+                 "orbslam2-rgbd",
+                 "orbslam2-rgb-monod"],
+    )
+    parser.add_argument(
+        "--task-config", type=str, default="tasks/pointnav_rgbd.yaml"
+    )
+    args = parser.parse_args()
+
+    config = get_config()
+    agent_config = cfg()
+    config.defrost()
+    config.BASELINE = agent_config.BASELINE
+    make_good_config_for_orbslam2(config)
+
+    if args.agent_type == 'blind':
+        agent = BlindAgent(config.BASELINE.ORBSLAM2)
+    elif args.agent_type == 'orbslam2-rgbd':
+        agent = ORBSLAM2Agent(config.BASELINE.ORBSLAM2)
+    elif args.agent_type == 'orbslam2-rgb-monod':
+        agent = ORBSLAM2MonodepthAgent(config.BASELINE.ORBSLAM2)
+    else:
+        raise ValueError(args.agent_type, 'is unknown type of agent')
+    benchmark = habitat.Benchmark(args.task_config)
+    metrics = benchmark.evaluate(agent)
+    for k, v in metrics.items():
+        habitat.logger.info("{}: {:.3f}".format(k, v))
+
+
+if __name__ == "__main__":
+    main()
+
diff --git a/baselines/config/default.py b/baselines/config/default.py
index fe44c9396..d100fd79b 100644
--- a/baselines/config/default.py
+++ b/baselines/config/default.py
@@ -5,8 +5,9 @@
 # LICENSE file in the root directory of this source tree.
 
 import os
+import numpy as np
 from typing import Optional
-
+from habitat import get_config
 from habitat.config import Config as CN
 
 DEFAULT_CONFIG_DIR = "configs/"
@@ -17,7 +18,7 @@ DEFAULT_CONFIG_DIR = "configs/"
 _C = CN()
 _C.SEED = 100
 # -----------------------------------------------------------------------------
-# BASELINES
+# BASELINE
 # -----------------------------------------------------------------------------
 _C.BASELINE = CN()
 # -----------------------------------------------------------------------------
@@ -27,6 +28,28 @@ _C.BASELINE.RL = CN()
 _C.BASELINE.RL.SUCCESS_REWARD = 10.0
 _C.BASELINE.RL.SLACK_REWARD = -0.01
 # -----------------------------------------------------------------------------
+# ORBSLAM2 BASELINE
+# -----------------------------------------------------------------------------
+_C.BASELINE.ORBSLAM2 = CN()
+_C.BASELINE.ORBSLAM2.SLAM_VOCAB_PATH = "baselines/slambased/data/ORBvoc.txt"
+_C.BASELINE.ORBSLAM2.SLAM_SETTINGS_PATH = "baselines/slambased/data/mp3d3_small1k.yaml"
+_C.BASELINE.ORBSLAM2.MAP_CELL_SIZE = 0.1
+_C.BASELINE.ORBSLAM2.MAP_SIZE = 40
+_C.BASELINE.ORBSLAM2.CAMERA_HEIGHT = get_config().SIMULATOR.DEPTH_SENSOR.POSITION[1]
+_C.BASELINE.ORBSLAM2.BETA = 100
+_C.BASELINE.ORBSLAM2.H_OBSTACLE_MIN = 0.3 * _C.BASELINE.ORBSLAM2.CAMERA_HEIGHT
+_C.BASELINE.ORBSLAM2.H_OBSTACLE_MAX = 1.0 * _C.BASELINE.ORBSLAM2.CAMERA_HEIGHT
+_C.BASELINE.ORBSLAM2.D_OBSTACLE_MIN = 0.1
+_C.BASELINE.ORBSLAM2.D_OBSTACLE_MAX = 4.0
+_C.BASELINE.ORBSLAM2.PREPROCESS_MAP = True
+_C.BASELINE.ORBSLAM2.MIN_PTS_IN_OBSTACLE = get_config().SIMULATOR.DEPTH_SENSOR.WIDTH/2.0
+_C.BASELINE.ORBSLAM2.ANGLE_TH = float(np.deg2rad(15))
+_C.BASELINE.ORBSLAM2.DIST_REACHED_TH = 0.15
+_C.BASELINE.ORBSLAM2.NEXT_WAYPOINT_TH = 0.5
+_C.BASELINE.ORBSLAM2.NUM_ACTIONS = 3
+_C.BASELINE.ORBSLAM2.DIST_TO_STOP = 0.05
+_C.BASELINE.ORBSLAM2.PLANNER_MAX_STEPS = 500
+_C.BASELINE.ORBSLAM2.DEPTH_DENORM = get_config().SIMULATOR.DEPTH_SENSOR.MAX_DEPTH
 
 
 def cfg(
diff --git a/baselines/slambased/README.md b/baselines/slambased/README.md
new file mode 100644
index 000000000..d70d3ade3
--- /dev/null
+++ b/baselines/slambased/README.md
@@ -0,0 +1,39 @@
+### Handcrafted agent baseline adopted from the paper "Benchmarking Classic and Learned Navigation in Complex 3D Environments"
+
+Project website: https://sites.google.com/view/classic-vs-learned-navigation
+Paper: https://arxiv.org/abs/1901.10915
+
+If you use this code or the provided environments in your research, please cite the following:
+
+    @ARTICLE{Navigation2019,
+           author = {{Mishkin}, Dmytro and {Dosovitskiy}, Alexey and {Koltun}, Vladlen},
+            title = "{Benchmarking Classic and Learned Navigation in Complex 3D Environments}",
+             year = 2019,
+            month = Jan,
+    archivePrefix = {arXiv},
+           eprint = {1901.10915},
+    }
+
+
+    
+## Dependencies:
+
+- conda
+- numpy
+- pytorch
+- ORBSLAM2
+
+
+## Tested with: 
+- Ubuntu 16.04
+- python 3.6
+- pytorch 0.4, 1.0
+
+
+- Install Anaconda https://www.anaconda.com/download/#linux
+
+- Install dependencies via ./install_deps.sh.  It should install everything except the datasets.
+
+Simple example of working with agents is shown in (../handcrafted-agent-example.ipynb)
+
+
diff --git a/baselines/slambased/data/mp3d3_small1k.yaml b/baselines/slambased/data/mp3d3_small1k.yaml
new file mode 100644
index 000000000..c814c080d
--- /dev/null
+++ b/baselines/slambased/data/mp3d3_small1k.yaml
@@ -0,0 +1,69 @@
+%YAML:1.0
+
+#--------------------------------------------------------------------------------------------
+# Camera Parameters. Adjust them!
+#--------------------------------------------------------------------------------------------
+
+# Camera calibration and distortion parameters (OpenCV) 
+#For resolution 256x256, FOV 90 deg
+Camera.fx: 128.0 
+Camera.fy: 128.0
+Camera.cx: 127.0
+Camera.cy: 127.0
+
+
+Camera.k1: 0.0
+Camera.k2: 0.0
+Camera.p1: 0.0
+Camera.p2: 0.0
+
+# Camera frames per second 
+Camera.fps: 30.0
+
+# IR projector baseline times fx (aprox.)
+Camera.bf: 50.0
+
+# Color order of the images (0: BGR, 1: RGB. It is ignored if images are grayscale)
+Camera.RGB: 1
+
+# Close/Far threshold. Baseline times.
+#ThDepth: 40.0
+ThDepth: 70.0
+
+# Deptmap values factor
+DepthMapFactor: 1.0
+
+#--------------------------------------------------------------------------------------------
+# ORB Parameters
+#--------------------------------------------------------------------------------------------
+
+# ORB Extractor: Number of features per image
+ORBextractor.nFeatures: 1000
+
+# ORB Extractor: Scale factor between levels in the scale pyramid 	
+ORBextractor.scaleFactor: 1.2
+
+# ORB Extractor: Number of levels in the scale pyramid	
+ORBextractor.nLevels: 8
+
+# ORB Extractor: Fast threshold
+# Image is divided in a grid. At each cell FAST are extracted imposing a minimum response.
+# Firstly we impose iniThFAST. If no corners are detected we impose a lower value minThFAST
+# You can lower these values if your images have low contrast			
+ORBextractor.iniThFAST: 5
+ORBextractor.minThFAST: 1
+
+#--------------------------------------------------------------------------------------------
+# Viewer Parameters
+#--------------------------------------------------------------------------------------------
+Viewer.KeyFrameSize: 0.1
+Viewer.KeyFrameLineWidth: 1
+Viewer.GraphLineWidth: 1
+Viewer.PointSize:2
+Viewer.CameraSize: 0.15
+Viewer.CameraLineWidth: 2
+Viewer.ViewpointX: 0
+Viewer.ViewpointY: -10
+Viewer.ViewpointZ: -0.1
+Viewer.ViewpointF: 2000
+
diff --git a/baselines/slambased/data/slam-based-agent.png b/baselines/slambased/data/slam-based-agent.png
new file mode 100644
index 0000000000000000000000000000000000000000..3aafc634fa034e68bb4fea5f50a72406a554db56
GIT binary patch
literal 72060
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
AWB>pF

literal 0
HcmV?d00001

diff --git a/baselines/slambased/install_deps.sh b/baselines/slambased/install_deps.sh
new file mode 100755
index 000000000..75002474f
--- /dev/null
+++ b/baselines/slambased/install_deps.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+DIR1=$(pwd)
+MAINDIR=$(pwd)/3rdparty
+mkdir ${MAINDIR}
+cd ${MAINDIR}
+#conda create -y -n "HandcraftedAgents" python=3.6
+source activate HandcraftedAgents
+conda install opencv -y
+conda install pytorch torchvision -c pytorch -y
+conda install -c conda-forge imageio -y
+conda install ffmpeg -c conda-forge -y
+cd ${MAINDIR}
+mkdir eigen3
+cd eigen3
+wget http://bitbucket.org/eigen/eigen/get/3.3.5.tar.gz
+tar -xzf 3.3.5.tar.gz
+cd eigen-eigen-b3f3d4950030
+mkdir build
+cd build
+cmake .. -DCMAKE_INSTALL_PREFIX=${MAINDIR}/eigen3_installed/
+make install
+cd ${MAINDIR}
+wget https://sourceforge.net/projects/glew/files/glew/2.1.0/glew-2.1.0.zip
+unzip glew-2.1.0.zip
+cd glew-2.1.0/
+cd build
+cmake ./cmake  -DCMAKE_INSTALL_PREFIX=${MAINDIR}/glew_installed
+make -j4
+make install
+cd ${MAINDIR}
+#pip install numpy --upgrade
+rm Pangolin -rf
+git clone https://github.com/stevenlovegrove/Pangolin.git
+cd Pangolin
+mkdir build
+cd build
+cmake .. -DCMAKE_PREFIX_PATH=${MAINDIR}/glew_installed/ -DCMAKE_LIBRARY_PATH=${MAINDIR}/glew_installed/lib/ -DCMAKE_INSTALL_PREFIX=${MAINDIR}/pangolin_installed
+cmake --build .
+cd ${MAINDIR}
+rm ORB_SLAM2 -rf
+rm ORB_SLAM2-PythonBindings -rf
+git clone https://github.com/ducha-aiki/ORB_SLAM2
+git clone https://github.com/ducha-aiki/ORB_SLAM2-PythonBindings
+cd ${MAINDIR}/ORB_SLAM2
+sed -i "s,cmake .. -DCMAKE_BUILD_TYPE=Release,cmake .. -DCMAKE_BUILD_TYPE=Release -DEIGEN3_INCLUDE_DIR=${MAINDIR}/eigen3_installed/include/eigen3/ -DCMAKE_INSTALL_PREFIX=${MAINDIR}/ORBSLAM2_installed ,g" build.sh
+ln -s ${MAINDIR}/eigen3_installed/include/eigen3/Eigen ${MAINDIR}/ORB_SLAM2/Thirdparty/g2o/g2o/core/Eigen
+./build.sh
+cd build
+make install
+cd ${MAINDIR}
+cd ORB_SLAM2-PythonBindings/src
+ln -s ${MAINDIR}/eigen3_installed/include/eigen3/Eigen Eigen
+cd ${MAINDIR}/ORB_SLAM2-PythonBindings
+mkdir build
+cd build
+CONDA_DIR=$(dirname $(dirname $(which conda)))
+sed -i "s,lib/python3.5/dist-packages,${CONDA_DIR}/envs/HandcraftedAgents/lib/python3.6/site-packages/,g" ../CMakeLists.txt
+cmake .. -DPYTHON_INCLUDE_DIR=$(python -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())") -DPYTHON_LIBRARY=$(python -c "import distutils.sysconfig as sysconfig; print(sysconfig.get_config_var('LIBDIR'))")/libpython3.6m.so -DPYTHON_EXECUTABLE:FILEPATH=`which python` -DCMAKE_LIBRARY_PATH=${MAINDIR}/ORBSLAM2_installed/lib -DCMAKE_INCLUDE_PATH=${MAINDIR}/ORBSLAM2_installed/include;${MAINDIR}/eigen3_installed/include/eigen3 -DCMAKE_INSTALL_PREFIX=${MAINDIR}/pyorbslam2_installed 
+make
+make install
+cp ${MAINDIR}/ORB_SLAM2/Vocabulary/ORBvoc.txt ${DIR1}/data/
diff --git a/baselines/slambased/mappers.py b/baselines/slambased/mappers.py
new file mode 100644
index 000000000..4e873ba68
--- /dev/null
+++ b/baselines/slambased/mappers.py
@@ -0,0 +1,122 @@
+import numpy as np
+import torch
+import torch.nn as nn
+from baselines.slambased.reprojection import (
+    get_map_size_in_cells,
+    project2d_pcl_into_worldmap,
+    reproject_local_to_global,
+)
+
+
+def depth2local3d(depth, fx, fy, cx, cy):
+    """Projects depth map to 3d point cloud
+    with origin in the camera focus
+    """
+    device = depth.device
+    h, w = depth.squeeze().size()
+    x = torch.linspace(0, w - 1, w).to(device)
+    y = torch.linspace(0, h - 1, h).to(device)
+    xv, yv = torch.meshgrid([x, y])
+    dfl = depth.t().flatten()
+    return torch.cat(
+        [
+            (dfl * (xv.flatten() - cx) / fx).unsqueeze(-1),  # x
+            (dfl * (yv.flatten() - cy) / fy).unsqueeze(-1),  # y
+            dfl.unsqueeze(-1),
+        ],
+        dim=1,
+    )  # z
+
+
+def pcl_to_obstacles(pts3d, map_size=40, cell_size=0.2, min_pts= 10):
+    """Counts number of 3d points in 2d map cell.
+    Height is sum-pooled.
+    """
+    device = pts3d.device
+    map_size_in_cells = get_map_size_in_cells(map_size, cell_size) - 1
+    init_map = torch.zeros(
+        (map_size_in_cells, map_size_in_cells), device=device
+    )
+    if len(pts3d) <= 1:
+        return init_map
+    num_pts, dim = pts3d.size()
+    pts2d = torch.cat([pts3d[:, 2:3], pts3d[:, 0:1]], dim=1)
+    data_idxs = torch.round(
+        project2d_pcl_into_worldmap(pts2d, map_size, cell_size)
+    )
+    if len(data_idxs) > min_pts:
+        u, counts = np.unique(
+            data_idxs.detach().cpu().numpy(), axis=0, return_counts=True
+        )
+        init_map[u[:, 0], u[:, 1]] = torch.from_numpy(counts).to(
+            dtype=torch.float32, device=device
+        )
+    return init_map
+
+
+class DirectDepthMapper(nn.Module):
+    """Estimates obstacle map given the depth image
+    ToDo: replace numpy histogram counting with differentiable
+    pytorch soft count like in
+    https://papers.nips.cc/paper/7545-unsupervised-learning-of-shape-and-pose-with-differentiable-point-clouds.pdf
+    """
+
+    def __init__(
+        self,
+        camera_height=0,
+        near_th=0.1,
+        far_th=4.0,
+        h_min=0.0,
+        h_max=1.0,
+        map_size=40,
+        map_cell_size=0.1,
+        device=torch.device("cpu"),
+        **kwargs
+    ):
+        super(DirectDepthMapper, self).__init__()
+        self.device = device
+        self.near_th = near_th
+        self.far_th = far_th
+        self.h_min_th = h_min
+        self.h_max_th = h_max
+        self.camera_height = camera_height
+        self.map_size_meters = map_size
+        self.map_cell_size = map_cell_size
+        return
+
+    def forward(self, depth, pose=torch.eye(4).float()):
+        self.device = depth.device
+        # Works for FOV = 90 degrees
+        # Should be adjusted, if FOV changed
+        self.fx = float(depth.size(1)) / 2.0
+        self.fy = float(depth.size(0)) / 2.0
+        self.cx = int(self.fx) - 1
+        self.cy = int(self.fy) - 1
+        pose = pose.to(self.device)
+        local_3d_pcl = depth2local3d(
+            depth, self.fx, self.fy, self.cx, self.cy
+        )
+        idxs = (torch.abs(local_3d_pcl[:, 2]) < self.far_th) * (
+            torch.abs(local_3d_pcl[:, 2]) >= self.near_th
+        )
+        survived_points = local_3d_pcl[idxs]
+        if len(survived_points) < 20:
+            map_size_in_cells = (
+                get_map_size_in_cells(self.map_size_meters,
+                                      self.map_cell_size) - 1
+            )
+            init_map = torch.zeros(
+                (map_size_in_cells, map_size_in_cells), device=self.device
+            )
+            return init_map
+        global_3d_pcl = reproject_local_to_global(survived_points, pose)[:, :3]
+        # Because originally y looks down and from agent camera height
+        global_3d_pcl[:, 1] = -global_3d_pcl[:, 1] + self.camera_height
+        idxs = (global_3d_pcl[:, 1] > self.h_min_th) * (
+            global_3d_pcl[:, 1] < self.h_max_th
+        )
+        global_3d_pcl = global_3d_pcl[idxs]
+        obstacle_map = pcl_to_obstacles(
+            global_3d_pcl, self.map_size_meters, self.map_cell_size
+        )
+        return obstacle_map
diff --git a/baselines/slambased/monodepth.py b/baselines/slambased/monodepth.py
new file mode 100644
index 000000000..d047a6170
--- /dev/null
+++ b/baselines/slambased/monodepth.py
@@ -0,0 +1,573 @@
+"""
+The code below is taked from https://github.com/JunjH/Revisiting_Single_Depth_Estimation
+Revisiting Single Image Depth Estimation: Toward Higher Resolution Maps With Accurate Object Boundaries
+Junjie Hu and Mete Ozay and Yan Zhang and Takayuki Okatani
+WACV 2019
+"""
+
+
+import torch
+import torch.nn.parallel
+"""
+ResNet code gently borrowed from
+https://github.com/pytorch/vision/blob/master/torchvision/models/py
+"""
+
+import torch.nn as nn
+import math
+import torch.utils.model_zoo as model_zoo
+import torch.nn.functional as F
+import torch
+import numpy as np
+import pdb
+import os
+from PIL import Image
+accimage = None
+from torchvision import transforms, utils
+
+
+__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101',
+           'resnet152']
+
+
+model_urls = {
+    'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',
+    'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',
+    'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
+    'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',
+    'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
+}
+
+
+def conv3x3(in_planes, out_planes, stride=1):
+    "3x3 convolution with padding"
+    return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+                     padding=1, bias=False)
+
+class BasicBlock(nn.Module):
+    expansion = 1
+
+    def __init__(self, inplanes, planes, stride=1, downsample=None):
+        super(BasicBlock, self).__init__()
+        self.conv1 = conv3x3(inplanes, planes, stride)
+        self.bn1 = nn.BatchNorm2d(planes)
+        self.relu = nn.ReLU(inplace=True)
+        self.conv2 = conv3x3(planes, planes)
+        self.bn2 = nn.BatchNorm2d(planes)
+        self.downsample = downsample
+        self.stride = stride
+
+    def forward(self, x):
+        residual = x
+
+        out = self.conv1(x)
+        out = self.bn1(out)
+        out = self.relu(out)
+
+        out = self.conv2(out)
+        out = self.bn2(out)
+
+        if self.downsample is not None:
+            residual = self.downsample(x)
+
+        out += residual
+        out = self.relu(out)
+
+        return out
+
+
+class Bottleneck(nn.Module):
+    expansion = 4
+
+    def __init__(self, inplanes, planes, stride=1, downsample=None):
+        super(Bottleneck, self).__init__()
+        self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
+        self.bn1 = nn.BatchNorm2d(planes)
+        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride,
+                               padding=1, bias=False)
+        self.bn2 = nn.BatchNorm2d(planes)
+        self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)
+        self.bn3 = nn.BatchNorm2d(planes * 4)
+        self.relu = nn.ReLU(inplace=True)
+        self.downsample = downsample
+        self.stride = stride
+
+    def forward(self, x):
+        residual = x
+
+        out = self.conv1(x)
+        out = self.bn1(out)
+        out = self.relu(out)
+
+        out = self.conv2(out)
+        out = self.bn2(out)
+        out = self.relu(out)
+
+        out = self.conv3(out)
+        out = self.bn3(out)
+
+        if self.downsample is not None:
+            residual = self.downsample(x)
+
+        out += residual
+        out = self.relu(out)
+
+        return out
+
+
+class ResNet(nn.Module):
+
+    def __init__(self, block, layers, num_classes=1000):
+        self.inplanes = 64
+        super(ResNet, self).__init__()
+        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3,
+                               bias=False)
+        self.bn1 = nn.BatchNorm2d(64)
+        self.relu = nn.ReLU(inplace=True)
+        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
+        self.layer1 = self._make_layer(block, 64, layers[0])
+        self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
+        self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
+        self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
+        self.avgpool = nn.AvgPool2d(7, stride=1)
+        self.fc = nn.Linear(512 * block.expansion, num_classes)
+
+        for m in self.modules():
+            if isinstance(m, nn.Conv2d):
+                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
+                m.weight.data.normal_(0, math.sqrt(2. / n))
+            elif isinstance(m, nn.BatchNorm2d):
+                m.weight.data.fill_(1)
+                m.bias.data.zero_()
+
+    def _make_layer(self, block, planes, blocks, stride=1):
+        downsample = None
+        if stride != 1 or self.inplanes != planes * block.expansion:
+            downsample = nn.Sequential(
+                nn.Conv2d(self.inplanes, planes * block.expansion,
+                          kernel_size=1, stride=stride, bias=False),
+                nn.BatchNorm2d(planes * block.expansion),
+            )
+
+        layers = []
+        layers.append(block(self.inplanes, planes, stride, downsample))
+        self.inplanes = planes * block.expansion
+        for i in range(1, blocks):
+            layers.append(block(self.inplanes, planes))
+
+        return nn.Sequential(*layers)
+
+    def forward(self, x):
+        x = self.conv1(x)
+        x = self.bn1(x)
+        x = self.relu(x)
+        x = self.maxpool(x)
+
+        x = self.layer1(x)
+        x = self.layer2(x)
+        x = self.layer3(x)
+        x = self.layer4(x)
+
+        x = self.avgpool(x)
+        x = x.view(x.size(0), -1)
+        x = self.fc(x)
+
+        return x
+
+def resnet18(pretrained=False, **kwargs):
+    """Constructs a ResNet-18 model.
+    Args:
+        pretrained (bool): If True, returns a model pre-trained on ImageNet
+    """
+    model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs)
+    if pretrained:
+        model.load_state_dict(model_zoo.load_url(model_urls['resnet18']))
+    return model
+
+
+def resnet34(pretrained=False, **kwargs):
+    """Constructs a ResNet-34 model.
+    Args:
+        pretrained (bool): If True, returns a model pre-trained on ImageNet
+    """
+    model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs)
+    if pretrained:
+        model.load_state_dict(model_zoo.load_url(model_urls['resnet34']))
+    return model
+
+
+def resnet50(pretrained=False, **kwargs):
+    """Constructs a ResNet-50 model.
+    Args:
+        pretrained (bool): If True, returns a model pre-trained on ImageNet
+    """
+    model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs)
+    if pretrained:
+        model.load_state_dict(model_zoo.load_url(model_urls['resnet50'], 'pretrained_model/encoder'))
+    return model
+
+
+def resnet101(pretrained=False, **kwargs):
+    """Constructs a ResNet-101 model.
+    Args:
+        pretrained (bool): If True, returns a model pre-trained on ImageNet
+    """
+    model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs)
+    if pretrained:
+        model.load_state_dict(model_zoo.load_url(model_urls['resnet101']))
+    return model
+
+
+def resnet152(pretrained=False, **kwargs):
+    """Constructs a ResNet-152 model.
+    Args:
+        pretrained (bool): If True, returns a model pre-trained on ImageNet
+    """
+    model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs)
+    if pretrained:
+        model.load_state_dict(model_zoo.load_url(model_urls['resnet152']))
+    return model
+
+
+class model(nn.Module):
+    def __init__(self, Encoder, num_features, block_channel):
+
+        super(model, self).__init__()
+
+        self.E = Encoder
+        self.D = D(num_features)
+        self.MFF = MFF(block_channel)
+        self.R = R(block_channel)
+
+
+    def forward(self, x):
+        x_block1, x_block2, x_block3, x_block4 = self.E(x)
+        x_decoder = self.D(x_block1, x_block2, x_block3, x_block4)
+        x_mff = self.MFF(x_block1, x_block2, x_block3, x_block4,[x_decoder.size(2),x_decoder.size(3)])
+        out = self.R(torch.cat((x_decoder, x_mff), 1))
+
+        return out
+
+
+class _UpProjection(nn.Sequential):
+
+    def __init__(self, num_input_features, num_output_features):
+        super(_UpProjection, self).__init__()
+
+        self.conv1 = nn.Conv2d(num_input_features, num_output_features,
+                               kernel_size=5, stride=1, padding=2, bias=False)
+        self.bn1 = nn.BatchNorm2d(num_output_features)
+        self.relu = nn.ReLU(inplace=True)
+        self.conv1_2 = nn.Conv2d(num_output_features, num_output_features,
+                                 kernel_size=3, stride=1, padding=1, bias=False)
+        self.bn1_2 = nn.BatchNorm2d(num_output_features)
+
+        self.conv2 = nn.Conv2d(num_input_features, num_output_features,
+                               kernel_size=5, stride=1, padding=2, bias=False)
+        self.bn2 = nn.BatchNorm2d(num_output_features)
+
+    def forward(self, x, size):
+        x = F.upsample(x, size=size, mode='bilinear')
+        x_conv1 = self.relu(self.bn1(self.conv1(x)))
+        bran1 = self.bn1_2(self.conv1_2(x_conv1))
+        bran2 = self.bn2(self.conv2(x))
+
+        out = self.relu(bran1 + bran2)
+
+        return out
+
+class E_resnet(nn.Module):
+
+    def __init__(self, original_model, num_features = 2048):
+        super(E_resnet, self).__init__()
+        self.conv1 = original_model.conv1
+        self.bn1 = original_model.bn1
+        self.relu = original_model.relu
+        self.maxpool = original_model.maxpool
+
+        self.layer1 = original_model.layer1
+        self.layer2 = original_model.layer2
+        self.layer3 = original_model.layer3
+        self.layer4 = original_model.layer4
+
+
+    def forward(self, x):
+        x = self.conv1(x)
+        x = self.bn1(x)
+        x = self.relu(x)
+        x = self.maxpool(x)
+
+        x_block1 = self.layer1(x)
+        x_block2 = self.layer2(x_block1)
+        x_block3 = self.layer3(x_block2)
+        x_block4 = self.layer4(x_block3)
+
+        return x_block1, x_block2, x_block3, x_block4
+
+
+class D(nn.Module):
+
+    def __init__(self, num_features = 2048):
+        super(D, self).__init__()
+        self.conv = nn.Conv2d(num_features, num_features //
+                               2, kernel_size=1, stride=1, bias=False)
+        num_features = num_features // 2
+        self.bn = nn.BatchNorm2d(num_features)
+
+        self.up1 = _UpProjection(
+            num_input_features=num_features, num_output_features=num_features // 2)
+        num_features = num_features // 2
+
+        self.up2 = _UpProjection(
+            num_input_features=num_features, num_output_features=num_features // 2)
+        num_features = num_features // 2
+
+        self.up3 = _UpProjection(
+            num_input_features=num_features, num_output_features=num_features // 2)
+        num_features = num_features // 2
+
+        self.up4 = _UpProjection(
+            num_input_features=num_features, num_output_features=num_features // 2)
+        num_features = num_features // 2
+
+
+    def forward(self, x_block1, x_block2, x_block3, x_block4):
+        x_d0 = F.relu(self.bn(self.conv(x_block4)))
+        x_d1 = self.up1(x_d0, [x_block3.size(2), x_block3.size(3)])
+        x_d2 = self.up2(x_d1, [x_block2.size(2), x_block2.size(3)])
+        x_d3 = self.up3(x_d2, [x_block1.size(2), x_block1.size(3)])
+        x_d4 = self.up4(x_d3, [x_block1.size(2)*2, x_block1.size(3)*2])
+
+        return x_d4
+
+class MFF(nn.Module):
+
+    def __init__(self, block_channel, num_features=64):
+
+        super(MFF, self).__init__()
+
+        self.up1 = _UpProjection(
+            num_input_features=block_channel[0], num_output_features=16)
+
+        self.up2 = _UpProjection(
+            num_input_features=block_channel[1], num_output_features=16)
+
+        self.up3 = _UpProjection(
+            num_input_features=block_channel[2], num_output_features=16)
+
+        self.up4 = _UpProjection(
+            num_input_features=block_channel[3], num_output_features=16)
+
+        self.conv = nn.Conv2d(
+            num_features, num_features, kernel_size=5, stride=1, padding=2, bias=False)
+        self.bn = nn.BatchNorm2d(num_features)
+
+
+    def forward(self, x_block1, x_block2, x_block3, x_block4, size):
+        x_m1 = self.up1(x_block1, size)
+        x_m2 = self.up2(x_block2, size)
+        x_m3 = self.up3(x_block3, size)
+        x_m4 = self.up4(x_block4, size)
+
+        x = self.bn(self.conv(torch.cat((x_m1, x_m2, x_m3, x_m4), 1)))
+        x = F.relu(x)
+
+        return x
+
+
+class R(nn.Module):
+    def __init__(self, block_channel):
+
+        super(R, self).__init__()
+
+        num_features = 64 + block_channel[3]//32
+        self.conv0 = nn.Conv2d(num_features, num_features,
+                               kernel_size=5, stride=1, padding=2, bias=False)
+        self.bn0 = nn.BatchNorm2d(num_features)
+
+        self.conv1 = nn.Conv2d(num_features, num_features,
+                               kernel_size=5, stride=1, padding=2, bias=False)
+        self.bn1 = nn.BatchNorm2d(num_features)
+
+        self.conv2 = nn.Conv2d(
+            num_features, 1, kernel_size=5, stride=1, padding=2, bias=True)
+
+    def forward(self, x):
+        x0 = self.conv0(x)
+        x0 = self.bn0(x0)
+        x0 = F.relu(x0)
+
+        x1 = self.conv1(x0)
+        x1 = self.bn1(x1)
+        x1 = F.relu(x1)
+
+        x2 = self.conv2(x1)
+
+        return x2
+def _is_pil_image(img):
+    return isinstance(img, Image.Image)
+
+def _is_numpy_image(img):
+    return isinstance(img, np.ndarray) and (img.ndim in {2, 3})
+
+class Scale(object):
+    def __init__(self, size):
+        self.size = size
+
+    def __call__(self, image):
+        image = self.changeScale(image,self.size)
+
+        return image
+
+    def changeScale(self, img, size, interpolation=Image.BILINEAR):
+        ow, oh = size
+
+        return img.resize((ow, oh), interpolation)
+
+class CenterCrop(object):
+    def __init__(self, size):
+        self.size = size
+
+    def __call__(self, image):
+        image = self.centerCrop(image,self.size)
+
+        return image
+
+    def centerCrop(self,image, size):
+        w1, h1 = image.size
+        tw, th = size
+
+        if w1 == tw and h1 == th:
+            return image
+
+        x1 = int(round((w1 - tw) / 2.))
+        y1 = int(round((h1 - th) / 2.))
+
+        image = image.crop((x1, y1, tw+x1, th+y1))
+
+        return image
+
+
+class ToTensor(object):
+    """Convert a ``PIL.Image`` or ``numpy.ndarray`` to tensor.
+    Converts a PIL.Image or numpy.ndarray (H x W x C) in the range
+    [0, 255] to a torch.FloatTensor of shape (C x H x W) in the range [0.0, 1.0].
+    """
+
+    def __call__(self, image):
+        image = self.to_tensor(image)
+
+        return image
+
+
+    def to_tensor(self,pic):
+        if not(_is_pil_image(pic) or _is_numpy_image(pic)):
+            raise TypeError('pic should be PIL Image or ndarray. Got {}'.format(type(pic)))
+
+        if isinstance(pic, np.ndarray):
+
+            img = torch.from_numpy(pic.transpose((2, 0, 1)))
+            return img.float().div(255)
+
+
+        if accimage is not None and isinstance(pic, accimage.Image):
+            nppic = np.zeros([pic.channels, pic.height, pic.width], dtype=np.float32)
+            pic.copyto(nppic)
+            return torch.from_numpy(nppic)
+
+        # handle PIL Image
+        if pic.mode == 'I':
+            img = torch.from_numpy(np.array(pic, np.int32, copy=False))
+        elif pic.mode == 'I;16':
+            img = torch.from_numpy(np.array(pic, np.int16, copy=False))
+        else:
+            img = torch.ByteTensor(torch.ByteStorage.from_buffer(pic.tobytes()))
+        # PIL image mode: 1, L, P, I, F, RGB, YCbCr, RGBA, CMYK
+        if pic.mode == 'YCbCr':
+            nchannel = 3
+        elif pic.mode == 'I;16':
+            nchannel = 1
+        else:
+            nchannel = len(pic.mode)
+        img = img.view(pic.size[1], pic.size[0], nchannel)
+        # put it from HWC to CHW format
+        # yikes, this transpose takes 80% of the loading time/CPU
+        img = img.transpose(0, 1).transpose(0, 2).contiguous()
+        if isinstance(img, torch.ByteTensor):
+            return img.float().div(255)
+        else:
+            return img
+
+
+
+class Normalize(object):
+    def __init__(self, mean, std):
+        self.mean = mean
+        self.std = std
+
+    def __call__(self, image):
+        image = self.normalize(image, self.mean, self.std)
+
+        return image
+
+    def normalize(self, tensor, mean, std):
+        for t, m, s in zip(tensor, mean, std):
+            t.sub_(m).div_(s)
+
+        return tensor
+
+
+
+def define_model(is_resnet, is_densenet, is_senet):
+    if is_resnet:
+        original_model = resnet50(pretrained = False)
+        Encoder = E_resnet(original_model)
+        model1 = model(Encoder, num_features=2048, block_channel = [256, 512, 1024, 2048])
+    if is_densenet:
+        original_model = dendensenet161(pretrained=False)
+        Encoder = E_densenet(original_model)
+        model1 = model(Encoder, num_features=2208, block_channel = [192, 384, 1056, 2208])
+    if is_senet:
+        original_model = senet154(pretrained=False)
+        Encoder = E_senet(original_model)
+        model1 = model(Encoder, num_features=2048, block_channel = [256, 512, 1024, 2048])
+
+    return model1
+
+
+class MonoDepthEstimator:
+    def __init__(self, checkpoint='./pretrained_model/model_resnet'):
+        self.model = define_model(is_resnet=True, is_densenet=False, is_senet=False)
+        self.model = torch.nn.DataParallel(self.model).cuda()
+        cpt = torch.load(checkpoint)
+        if 'state_dict' in cpt.keys():
+            cpt = cpt['state_dict']
+        self.model.load_state_dict(cpt)
+        self.model.eval()
+        self.init_preprocessor()
+
+    def init_preprocessor(self):
+        __imagenet_stats = {'mean': [0.485, 0.456, 0.406],
+                            'std': [0.229, 0.224, 0.225]}
+
+        self.transform = transforms.Compose([
+                            Scale([320, 240]),
+                            #CenterCrop([304, 228]),
+                            ToTensor(),
+                            Normalize(__imagenet_stats['mean'],
+                                      __imagenet_stats['std'])
+                         ])
+
+    def preprocess(self, image):
+        image_torch = self.transform(image).unsqueeze(0)
+        return image_torch.cuda()
+
+    def compute_depth(self, image):
+        # Input: image is a PIL image
+        # Output: depth is a numpy array
+        image_torch = self.preprocess(image)
+        #print(image_torch.size())
+        depth_torch = self.model(image_torch)
+        depth = depth_torch.view(depth_torch.size(2),depth_torch.size(3)).data.cpu().numpy()
+        return depth
+
diff --git a/baselines/slambased/path_planners.py b/baselines/slambased/path_planners.py
new file mode 100644
index 000000000..adc2eb97b
--- /dev/null
+++ b/baselines/slambased/path_planners.py
@@ -0,0 +1,512 @@
+import numpy as np
+import torch
+import torch.nn.functional as F
+import torch.nn as nn
+import matplotlib.pyplot as plt
+from baselines.slambased.utils import generate_2dgrid
+
+
+def safe_roi_2d(array2d, ymin, ymax, xmin, xmax):
+    (h, w) = array2d.shape
+    return max(0, ymin), min(ymax, h), max(0, xmin), min(xmax, w)
+
+
+def f2ind(ten, i):
+    # Float to index
+    return torch.round(ten[i]).long()
+
+
+def init_neights_to_channels(ks=3):
+    r"""Convolutional kernel,
+    which maps nighborhood into channels
+    """
+    weights = np.zeros((ks * ks, 1, ks, ks), dtype=np.float32)
+    for y in range(ks):
+        for x in range(ks):
+            weights[x * ks + y, 0, y, x] = 1.0
+    return weights
+
+
+class SoftArgMin(nn.Module):
+    def __init__(self, beta=5):
+        super(SoftArgMin, self).__init__()
+        self.beta = beta
+        return
+
+    def forward(self, x, coords2d=None):
+        bx_sm = F.softmax(self.beta * (-x).view(1, -1), dim=1)
+        if coords2d is None:
+            coords2d = generate_2dgrid(x.size(2), x.size(3), False)
+        coords2d_flat = coords2d.view(2, -1)
+        return (bx_sm.expand_as(coords2d_flat) * coords2d_flat).sum(
+            dim=1
+        ) / bx_sm.sum(dim=1)
+
+
+class HardArgMin(nn.Module):
+    def __init__(self):
+        super(HardArgMin, self).__init__()
+        return
+
+    def forward(self, x, coords2d=None):
+        val, idx = x.view(-1).min(dim=0)
+        if coords2d is None:
+            coords2d = generate_2dgrid(x.size(2), x.size(3), False)
+        coords2d_flat = coords2d.view(2, -1)
+        return coords2d_flat[:, idx].view(2)
+
+
+class DifferentiableStarPlanner(nn.Module):
+    def __init__(
+        self,
+        max_steps=500,
+        visualize=False,
+        preprocess=False,
+        beta=100,
+        connectivity="eight",
+        device=torch.device("cpu"),
+        **kwargs
+    ):
+        super(DifferentiableStarPlanner, self).__init__()
+        self.eps = 1e-12
+        self.max_steps = max_steps
+        self.visualize = visualize
+        self.inf = 1e7
+        self.ob_cost = 10000.0
+        self.device = device
+        self.beta = beta
+        self.preprocess = preprocess
+        # self.argmin = SoftArgMin(beta)
+        self.argmin = HardArgMin()
+        self.neights2channels = nn.Conv2d(1, 9, kernel_size=(3, 3), bias=False)
+        self.neights2channels.weight.data = torch.from_numpy(
+            init_neights_to_channels(3)
+        )
+        self.neights2channels.to(device)
+        self.preprocessNet = nn.Conv2d(
+            1, 1, kernel_size=(3, 3), padding=1, bias=False
+        )
+        self.preprocessNet.weight.data = torch.from_numpy(
+            np.array(
+                [
+                    [
+                        [
+                            [0.00001, 0.0001, 0.00001],
+                            [0.0001, 1, 0.0001],
+                            [0.00001, 0.0001, 0.00001],
+                        ]
+                    ]
+                ],
+                dtype=np.float32,
+            )
+        )
+        self.preprocessNet.to(device)
+        if connectivity == "eight":
+            self.gx_to_right = nn.Conv2d(1, 1, kernel_size=(1, 3), bias=False)
+            self.gx_to_right.weight.data = torch.from_numpy(
+                np.array([[[[0, 1, -1]]]], dtype=np.float32)
+            )
+            self.gx_to_right.to(device)
+
+            self.gx_to_left = nn.Conv2d(1, 1, kernel_size=(1, 3), bias=False)
+            self.gx_to_left.weight.data = torch.from_numpy(
+                np.array([[[[-1, 1, 0]]]], dtype=np.float32)
+            )
+            self.gx_to_left.to(device)
+
+            self.gy_to_up = nn.Conv2d(1, 1, kernel_size=(3, 1), bias=False)
+            self.gy_to_up.weight.data = torch.from_numpy(
+                np.array([[[[0], [1], [-1]]]], dtype=np.float32)
+            )
+            self.gy_to_up.to(device)
+
+            self.gy_to_down = nn.Conv2d(1, 1, kernel_size=(3, 1), bias=False)
+            self.gy_to_down.weight.data = torch.from_numpy(
+                np.array([[[[-1], [1], [0]]]], dtype=np.float32)
+            )
+            self.gy_to_down.to(device)
+        else:
+            raise ValueError('Only "eight" connectivity now supported')
+        return
+
+    def preprocess_obstacle_map(self, obstacle_map):
+        if self.preprocess:
+            return self.preprocessNet(
+                obstacle_map
+            )
+        return obstacle_map
+
+    def coords2grid(self, node_coords, h, w):
+        grid = node_coords.squeeze() - torch.FloatTensor(
+            (h / 2.0, w / 2.0)
+        ).to(self.device)
+        grid = grid / torch.FloatTensor((h / 2.0, w / 2.0)).to(self.device)
+        return grid.view(1, 1, 1, 2).flip(3)
+
+    def init_closelistmap(self):
+        return torch.zeros_like(
+            self.start_map
+        ).float()
+
+    def init_openlistmap(self):
+        return self.start_map.clone()
+
+    def init_g_map(self):
+        return torch.clamp(
+            self.inf
+            * (torch.ones_like(self.start_map) - self.start_map.clone()),
+            min=0,
+            max=self.inf,
+        )
+
+    def safe_roi_2d(self, ymin, ymax, xmin, xmax):
+        return (
+            int(max(0, torch.round(ymin).item())),
+            int(min(torch.round(ymax).item(), self.height)),
+            int(max(0, torch.round(xmin).item())),
+            int(min(torch.round(xmax).item(), self.width)),
+        )
+
+    def forward(
+        self,
+        obstacles,
+        coords,
+        start_map,
+        goal_map,
+        non_obstacle_cost_map=None,
+        additional_steps=50,
+        return_path=True,
+    ):
+        self.trav_init_time = 0
+        self.trav_mask_time = 0
+        self.trav_soft_time = 0
+        self.conv_time = 0
+        self.close_time = 0
+
+        self.obstacles = self.preprocess_obstacle_map(
+            obstacles.to(self.device)
+        )
+        self.start_map = start_map.to(self.device)
+        self.been_there = torch.zeros_like(self.start_map).to(
+            torch.device("cpu")
+        )
+        self.coords = coords.to(self.device)
+        self.goal_map = goal_map.to(self.device)
+        self.been_there = torch.zeros_like(self.goal_map).to(self.device)
+        self.height = obstacles.size(2)
+        self.width = obstacles.size(3)
+        m, goal_idx = torch.max(self.goal_map.view(-1), 0)
+        c_map = self.calculate_local_path_costs(
+            non_obstacle_cost_map
+        )
+        # c_map might be non persistent in map update
+        self.g_map = self.init_g_map()
+        self.close_list_map = self.init_closelistmap()
+        self.open_list_map = self.init_openlistmap()
+        not_done = False
+        step = 0
+        stopped_by_max_iter = False
+        if self.visualize:
+            self.fig, self.ax = plt.subplots(1, 1)
+            self.image = self.ax.imshow(
+                self.g_map.squeeze().cpu().detach().numpy().astype(np.float32),
+                animated=True,
+            )
+            self.fig.canvas.draw()
+        not_done = (self.close_list_map.view(-1)[goal_idx].item() < 1.0) or (
+            self.g_map.view(-1)[goal_idx].item() >= 0.9 * self.ob_cost
+        )
+        rad = 1
+        self.start_coords = (
+            (self.coords * self.start_map.expand_as(self.coords))
+            .sum(dim=2)
+            .sum(dim=2)
+            .squeeze()
+        )
+        node_coords = self.start_coords
+        self.goal_coords = (
+            (self.coords * self.goal_map.expand_as(self.coords))
+            .sum(dim=2)
+            .sum(dim=2)
+            .squeeze()
+        )
+        self.max_steps = 4 * int(
+            torch.sqrt(
+                ((self.start_coords - self.goal_coords) ** 2).sum() + 1e-6
+            ).item()
+        )
+        while not_done:
+            ymin, ymax, xmin, xmax = self.safe_roi_2d(
+                node_coords[0] - rad,
+                node_coords[0] + rad + 1,
+                node_coords[1] - rad,
+                node_coords[1] + rad + 1,
+            )
+            if (
+                (ymin - 1 > 0)
+                and (xmin - 1 > 0)
+                and (ymax + 1 < self.height)
+                and (xmax + 1 < self.width)
+            ):
+                n2c = self.neights2channels(
+                    self.g_map[:, :, ymin - 1:ymax + 1, xmin - 1:xmax + 1]
+                )
+                self.g_map[:, :, ymin:ymax, xmin:xmax] = torch.min(
+                    self.g_map[:, :, ymin:ymax, xmin:xmax].clone(),
+                    (n2c + c_map[:, :, ymin:ymax, xmin:xmax]).min(
+                        dim=1, keepdim=True
+                    )[0],
+                )
+                self.close_list_map[:, :, ymin:ymax, xmin:xmax] = torch.max(
+                    self.close_list_map[:, :, ymin:ymax, xmin:xmax],
+                    self.open_list_map[:, :, ymin:ymax, xmin:xmax],
+                )
+                self.open_list_map[:, :, ymin:ymax, xmin:xmax] = F.relu(
+                    F.max_pool2d(
+                        self.open_list_map[
+                            :, :, ymin - 1:ymax + 1, xmin - 1:xmax + 1
+                        ],
+                        3,
+                        stride=1,
+                        padding=0,
+                    )
+                    - self.close_list_map[:, :, ymin:ymax, xmin:xmax]
+                    - self.obstacles[:, :, ymin:ymax, xmin:xmax]
+                )
+            else:
+                self.g_map = torch.min(
+                    self.g_map,
+                    (
+                        self.neights2channels(
+                            F.pad(self.g_map, (1, 1, 1, 1), "replicate")
+                        )
+                        + c_map
+                    ).min(dim=1, keepdim=True)[0],
+                )
+                self.close_list_map = torch.max(
+                    self.close_list_map, self.open_list_map
+                )
+                self.open_list_map = F.relu(
+                    F.max_pool2d(self.open_list_map, 3, stride=1, padding=1)
+                    - self.close_list_map
+                    - self.obstacles
+                )
+            step += 1
+            if step >= self.max_steps:
+                stopped_by_max_iter = True
+                break
+            not_done = (
+                self.close_list_map.view(-1)[goal_idx].item() < 1.0
+            ) or (self.g_map.view(-1)[goal_idx].item() >= 0.1 * self.inf)
+            rad += 1
+        if not stopped_by_max_iter:
+            for i in range(additional_steps):
+                # now propagating beyong start point
+                self.g_map = torch.min(
+                    self.g_map,
+                    (
+                        self.neights2channels(
+                            F.pad(self.g_map, (1, 1, 1, 1), "replicate")
+                        )
+                        + c_map
+                    ).min(dim=1, keepdim=True)[0],
+                )
+                self.close_list_map = torch.max(
+                    self.close_list_map, self.open_list_map
+                )
+                self.open_list_map = F.relu(
+                    F.max_pool2d(self.open_list_map, 3, stride=1, padding=1)
+                    - self.close_list_map
+                    - self.obstacles
+                )
+        if return_path:
+            out_path, cost = self.reconstruct_path()
+            return out_path, cost
+        return
+
+    def calculate_local_path_costs(self, non_obstacle_cost_map=None):
+        coords = self.coords
+        h = coords.size(2)
+        w = coords.size(3)
+        obstacles_pd = F.pad(self.obstacles, (1, 1, 1, 1), "replicate")
+        if non_obstacle_cost_map is None:
+            learned_bias = torch.ones_like(self.obstacles).to(
+                obstacles_pd.device
+            )
+        else:
+            learned_bias = non_obstacle_cost_map.to(obstacles_pd.device)
+        left_diff_sq = (
+            self.gx_to_left(
+                F.pad(coords[:, 1:2, :, :], (1, 1, 0, 0), "replicate")
+            )
+            ** 2
+        )
+        right_diff_sq = (
+            self.gx_to_right(
+                F.pad(coords[:, 1:2, :, :], (1, 1, 0, 0), "replicate")
+            )
+            ** 2
+        )
+        up_diff_sq = (
+            self.gy_to_up(
+                F.pad(coords[:, 0:1, :, :], (0, 0, 1, 1), "replicate")
+            )
+            ** 2
+        )
+        down_diff_sq = (
+            self.gy_to_down(
+                F.pad(coords[:, 0:1, :, :], (0, 0, 1, 1), "replicate")
+            )
+            ** 2
+        )
+        out = torch.cat([
+                # Order in from up to down, from left to right
+                # hopefully same as in PyTorch
+                torch.sqrt(left_diff_sq + up_diff_sq + self.eps)
+                + self.ob_cost
+                * torch.max(
+                    obstacles_pd[:, :, 0:h, 0:w],
+                    obstacles_pd[:, :, 1:h + 1, 1:w + 1],
+                ),
+                torch.sqrt(left_diff_sq + self.eps)
+                + self.ob_cost
+                * torch.max(
+                    obstacles_pd[:, :, 0:h, 1:w + 1],
+                    obstacles_pd[:, :, 1:h + 1, 1:w + 1],
+                ),
+                torch.sqrt(left_diff_sq + down_diff_sq + self.eps)
+                + self.ob_cost
+                * torch.max(
+                    obstacles_pd[:, :, 2:h + 2, 0:w],
+                    obstacles_pd[:, :, 1:h + 1, 1:w + 1],
+                ),
+                torch.sqrt(up_diff_sq + self.eps)
+                + self.ob_cost
+                * torch.max(
+                    obstacles_pd[:, :, 0:h, 1:w + 1],
+                    obstacles_pd[:, :, 1:h + 1, 1:w + 1],
+                ),
+                0 * right_diff_sq
+                + self.ob_cost
+                * obstacles_pd[:, :, 1:h + 1, 1:w + 1],  # current center
+                torch.sqrt(down_diff_sq + self.eps)
+                + self.ob_cost
+                * torch.max(
+                    obstacles_pd[:, :, 2:h + 2, 1:w + 1],
+                    obstacles_pd[:, :, 1:h + 1, 1:w + 1],
+                ),
+                torch.sqrt(right_diff_sq + up_diff_sq + self.eps)
+                + self.ob_cost
+                * torch.max(
+                    obstacles_pd[:, :, 0:h, 2:w + 2],
+                    obstacles_pd[:, :, 1:h + 1, 1:w + 1],
+                ),
+                torch.sqrt(right_diff_sq + self.eps)
+                + self.ob_cost
+                * torch.max(
+                    obstacles_pd[:, :, 1:h + 1, 2:w + 2],
+                    obstacles_pd[:, :, 1:h + 1, 1:w + 1],
+                ),
+                torch.sqrt(right_diff_sq + down_diff_sq + self.eps)
+                + self.ob_cost
+                * torch.max(
+                    obstacles_pd[:, :, 2:h + 2, 2:w + 2],
+                    obstacles_pd[:, :, 1:h + 1, 1:w + 1],
+                ),
+            ],
+            dim=1,
+        )
+        return out + torch.clamp(
+            learned_bias.expand_as(out), min=0, max=self.ob_cost
+        )
+
+    def propagate_traversal(self, node_coords, close, g, coords):
+        ymin, ymax, xmin, xmax = self.safe_roi_2d(
+            node_coords[0] - 1,
+            node_coords[0] + 2,
+            node_coords[1] - 1,
+            node_coords[1] + 2,
+        )
+        mask = close[:, :, ymin:ymax, xmin:xmax] > 0
+        mask[
+            :, :, f2ind(node_coords, 0) - ymin, f2ind(node_coords, 1) - xmin
+        ] = 0
+        mask = mask > 0
+        current_g_cost = g[:, :, ymin:ymax, xmin:xmax][mask].clone()
+        if len(current_g_cost.view(-1)) == 0:
+            # we are kind surrounded by obstacles,
+            # but still need to output something
+            mask = torch.relu(
+                1.0 - self.been_there[:, :, ymin:ymax, xmin:xmax]
+            )
+            mask[
+                :,
+                :,
+                f2ind(node_coords, 0) - ymin,
+                f2ind(node_coords, 1) - xmin,
+            ] = 0
+            mask = mask > 0
+            current_g_cost = g[:, :, ymin:ymax, xmin:xmax][mask].clone()
+        if len(current_g_cost.view(-1)) > 1:
+            current_g_cost = current_g_cost - torch.min(current_g_cost).item()
+            current_g_cost = current_g_cost + 0.41 * torch.randperm(
+                len(current_g_cost),
+                dtype=torch.float32,
+                device=torch.device("cpu"),
+            ) / (len(current_g_cost))
+        #
+        coords_roi = coords[:, :, ymin:ymax, xmin:xmax]
+        out = self.argmin(
+            current_g_cost, coords_roi[mask.expand_as(coords_roi)]
+        )
+        return out
+
+    def get_clean_costmap_and_goodmask(self):
+        good_mask = 1 - F.max_pool2d(self.obstacles, 3, stride=1, padding=1)
+        costmap = self.g_map
+        obstacle_cost_corrected = 10000.0
+        sampling_map = torch.clamp(costmap, min=0, max=obstacle_cost_corrected)
+        return sampling_map, good_mask
+
+    def reconstruct_path(self):
+        out_path = []
+        goal_coords = (
+            self.goal_coords.cpu()
+        )
+        start_coords = (
+            self.start_coords.cpu()
+        )
+
+        cost = self.g_map[:, :, f2ind(goal_coords, 0), f2ind(goal_coords, 1)]
+        # Traversing
+        done = False
+        node_coords = goal_coords.cpu()
+        out_path.append(node_coords)
+        self.been_there = 0 * self.been_there.cpu()
+        self.been_there[
+            :, :, f2ind(node_coords, 0), f2ind(node_coords, 1)
+        ] = 1.0
+        self.close_list_map = self.close_list_map.cpu()
+        self.g_map = self.g_map.cpu()
+        self.coords = self.coords.cpu()
+        count1 = 0
+        while not done:
+            node_coords = self.propagate_traversal(
+                node_coords, self.close_list_map, self.g_map, self.coords
+            )
+            self.been_there[
+                :, :, f2ind(node_coords, 0), f2ind(node_coords, 1)
+            ] = 1.0
+            if torch.norm(node_coords - out_path[-1], 2).item() < 0.3:
+                y = node_coords.flatten()[0].long()
+                x = node_coords.flatten()[1].long()
+                print(self.g_map[0, 0, y - 2:y + 3, x - 2:x + 3])
+                print("loop in out_path", node_coords)
+                raise ValueError("loop in out_path")
+                return out_path, cost
+            out_path.append(node_coords)
+            done = torch.norm(node_coords - start_coords.cpu(), 2).item() < 0.3
+            count1 += 1
+            if count1 > 250:
+                break
+        return out_path, cost
diff --git a/baselines/slambased/reprojection.py b/baselines/slambased/reprojection.py
new file mode 100644
index 000000000..566b47745
--- /dev/null
+++ b/baselines/slambased/reprojection.py
@@ -0,0 +1,289 @@
+import numpy as np
+import torch
+from math import ceil, floor
+
+
+
+def p_zx(p):
+    return p[(0, 2), 3]
+
+
+def get_map_size_in_cells(map_size_in_meters, cell_size_in_meters):
+    return int(ceil(map_size_in_meters / cell_size_in_meters)) + 1
+
+
+def get_pos_diff(p_init, p_fin):
+    return p_zx(p_fin) - p_zx(p_init)
+
+
+def get_distance(p_init, p_fin):
+    return torch.norm(get_pos_diff(p_init, p_fin))
+
+
+def get_pos_diffs(ps):
+    return ps[1:, (0, 2), 3] - ps[: (ps.size(0) - 1), (0, 2), 3]
+
+
+def angle_to_pi_2_minus_pi_2(angle):
+    if angle < -np.pi:
+        angle = 2.0 * np.pi + angle
+    if angle > np.pi:
+        angle = -2.0 * np.pi + angle
+    return angle
+
+
+def get_direction(p_init, p_fin, ang_th=0.2, pos_th=0.1):
+    pos_diff = get_pos_diff(p_init, p_fin)
+    if torch.norm(pos_diff, 2).item() < pos_th:
+        return 0
+    else:
+        needed_angle = torch.atan2(pos_diff[1], pos_diff[0])
+        current_angle = torch.atan2(p_init[2, 0], p_init[0, 0])
+    to_rotate = angle_to_pi_2_minus_pi_2(
+        -np.pi / 2.0 + needed_angle - current_angle
+    )
+    if torch.abs(to_rotate).item() < ang_th:
+        return 0
+    return to_rotate
+
+
+def reproject_local_to_global(xyz_local, p):
+    device = xyz_local.device
+    num, dim = xyz_local.size()
+    if dim == 3:
+        xyz = torch.cat(
+            [
+                xyz_local,
+                torch.ones((num, 1), dtype=torch.float32, device=device),
+            ],
+            dim=1,
+        )
+    elif dim == 4:
+        xyz = xyz_local
+    else:
+        raise ValueError(
+            "3d point cloud dim is neighter 3, or 4 (homogenious)"
+        )
+    # print(xyz.shape, P.shape)
+    xyz_global = torch.mm(p.squeeze(), xyz.t())
+    return xyz_global.t()
+
+
+def project2d_pcl_into_worldmap(zx, map_size, cell_size):
+    device = zx.device
+    shift = int(floor(get_map_size_in_cells(map_size, cell_size) / 2.0))
+    topdown2index = torch.tensor(
+        [[1.0 / cell_size, 0, shift], [0, 1.0 / cell_size, shift], [0, 0, 1]],
+        device=device,
+    )
+    world_coords_h = torch.cat(
+        [zx.view(-1, 2), torch.ones((len(zx), 1), device=device)], dim=1
+    )
+    world_coords = torch.mm(topdown2index, world_coords_h.t())
+    return world_coords.t()[:, :2]
+
+
+def get_pose2d(poses6d):
+    poses6d = poses6d.view(-1, 4, 4)
+    poses2d = poses6d[:, (0, 2)]
+    poses2d = poses2d[:, :, (0, 2, 3)]
+    return poses2d
+
+
+def get_rotation_matrix(angle_in_radians):
+    angle_in_radians = angle_in_radians.view(-1, 1, 1)
+    sin_a = torch.sin(angle_in_radians)
+    cos_a = torch.cos(angle_in_radians)
+    a1x = torch.cat([cos_a, sin_a], dim=2)
+    a2x = torch.cat([-sin_a, cos_a], dim=2)
+    transform = torch.cat([a1x, a2x], dim=1)
+    return transform
+
+
+def normalize_zx_ori(p):
+    p2d = get_pose2d(p)
+    norms = torch.norm(p2d[:, 0, :2], dim=1).view(-1, 1, 1)
+    out = torch.cat(
+        [
+            torch.cat(
+                [p[:, :3, :3] / norms.expand(p.size(0), 3, 3), p[:, 3:, :3]],
+                dim=1,
+            ),
+            p[:, :, 3:],
+        ],
+        dim=2,
+    )
+    return out
+
+
+def add_rot_wps(p):
+    planned_tps_norm = normalize_zx_ori(p)
+    pos_diffs = get_pos_diffs(planned_tps_norm)
+
+    angles = torch.atan2(pos_diffs[:, 1], pos_diffs[:, 0])
+    rotmats = get_rotation_matrix(angles)
+    planned_tps_norm[:p.size(0) - 1, 0, 0] = rotmats[:, 0, 0]
+    planned_tps_norm[:p.size(0) - 1, 0, 2] = rotmats[:, 0, 1]
+    planned_tps_norm[:p.size(0) - 1, 2, 0] = rotmats[:, 1, 0]
+    planned_tps_norm[:p.size(0) - 1, 2, 2] = rotmats[:, 1, 1]
+
+    planned_points2 = planned_tps_norm.clone()
+
+    planned_points2[1:, 0, 0] = planned_tps_norm[:p.size(0) - 1, 0, 0]
+    planned_points2[1:, 0, 2] = planned_tps_norm[:p.size(0) - 1, 0, 2]
+    planned_points2[1:, 2, 0] = planned_tps_norm[:p.size(0) - 1, 2, 0]
+    planned_points2[1:, 2, 2] = planned_tps_norm[:p.size(0) - 1, 2, 2]
+    out = torch.stack(
+        (planned_points2.unsqueeze(0), planned_tps_norm.unsqueeze(0)), dim=0
+    ).squeeze()
+    out = out.permute(1, 0, 2, 3).contiguous().view(-1, 4, 4)
+    return out
+
+
+def planned_path2tps(path, cell_size, map_size, agent_h, add_rot=False):
+    '''Path is list of 2d coordinates from planner, in map cells. 
+    tp is trajectory pose, 4x4 matrix - same format,
+    as in localization module
+    '''
+    path = torch.cat(path).view(-1, 2)
+    # print(path.size())
+    num_pts = len(path)
+    planned_tps = torch.eye(4).unsqueeze(0).repeat((num_pts, 1, 1))
+    planned_tps[:, 0, 3] = path[:, 1]  # switch back x and z
+    planned_tps[:, 1, 3] = agent_h
+    planned_tps[:, 2, 3] = path[:, 0]  # switch back x and z
+    shift = int(floor(get_map_size_in_cells(map_size, cell_size) / 2.0))
+    planned_tps[:, 0, 3] = planned_tps[:, 0, 3] - shift
+    planned_tps[:, 2, 3] = planned_tps[:, 2, 3] - shift
+    p = torch.tensor(
+        [
+            [1.0 / cell_size, 0, 0, 0],
+            [0, 1.0 / cell_size, 0, 0],
+            [0, 0, 1.0 / cell_size, 0],
+            [0, 0, 0, 1],
+        ]
+    )
+    planned_tps = torch.bmm(
+        p.inverse().unsqueeze(0).expand(num_pts, 4, 4), planned_tps
+    )
+    if add_rot:
+        return add_rot_wps(planned_tps)
+    return planned_tps
+
+
+def habitat_goalpos_to_tp(ro_phi, p_curr):
+    '''Convert distance and azimuth to 
+    trajectory pose, 4x4 matrix - same format,
+    as in localization module
+    '''
+    device = ro_phi.device
+    offset = torch.tensor(
+        [
+            -ro_phi[0] * torch.sin(ro_phi[1]),
+            0,
+            ro_phi[0] * torch.cos(ro_phi[1]),
+        ]
+    ).to(device)
+    if p_curr.size(1) == 3:
+        p_curr = homogenize_p(p_curr)
+    goal_tp = torch.mm(
+        p_curr.to(device),
+        torch.cat(
+            [
+                offset
+                * torch.tensor(
+                    [1.0, 1.0, 1.0], dtype=torch.float32, device=device
+                ),
+                torch.tensor([1.0], device=device),
+            ]
+        ).reshape(4, 1),
+    )
+    return goal_tp
+
+
+def habitat_goalpos_to_mapgoal_pos(offset, p_curr, cell_size, map_size):
+    '''Convert distance and azimuth to 
+    map cell coordinates
+    '''
+    device = offset.device
+    goal_tp = habitat_goalpos_to_tp(offset, p_curr)
+    goal_tp1 = torch.eye(4).to(device)
+    goal_tp1[:, 3:] = goal_tp
+    projected_p = project_tps_into_worldmap(
+        goal_tp1.view(1, 4, 4), cell_size, map_size
+    )
+    return projected_p
+
+
+
+def homogenize_p(tps):
+    device = tps.device
+    tps = tps.view(-1, 3, 4)
+    return torch.cat(
+        [
+            tps.float(),
+            torch.tensor([0, 0, 0, 1.0])
+            .view(1, 1, 4)
+            .expand(tps.size(0), 1, 4)
+            .to(device),
+        ],
+        dim=1,
+    )
+
+
+def project_tps_into_worldmap(tps, cell_size, map_size, do_floor=True):
+    '''Convert 4x4 pose matrices (trajectory poses) to 
+    map cell coordinates
+    '''
+    if len(tps) == 0:
+        return []
+    if isinstance(tps, list):
+        return []
+    device = tps.device
+    topdown_p = torch.tensor([[1.0, 0, 0, 0], [0, 0, 1.0, 0]]).to(device)
+    world_coords = torch.bmm(
+        topdown_p.view(1, 2, 4).expand(tps.size(0), 2, 4),
+        tps[:, :, 3:].view(-1, 4, 1),
+    )
+    shift = int(floor(get_map_size_in_cells(map_size, cell_size) / 2.0))
+    topdown2index = torch.tensor(
+        [[1.0 / cell_size, 0, shift], [0, 1.0 / cell_size, shift], [0, 0, 1]]
+    ).to(device)
+    world_coords_h = torch.cat(
+        [world_coords, torch.ones((len(world_coords), 1, 1)).to(device)], dim=1
+    )
+    world_coords = torch.bmm(
+        topdown2index.unsqueeze(0).expand(world_coords_h.size(0), 3, 3),
+        world_coords_h,
+    )[:, :2, 0]
+    if do_floor:
+        return (
+            torch.floor(world_coords.flip(1)) + 1
+        )  # for having revesrve (z,x) ordering
+    return world_coords.flip(1)
+
+
+def project_tps_into_worldmap_numpy(tps, slam_to_world, cell_size, map_size):
+    if len(tps) == 0:
+        return []
+    if isinstance(tps, list):
+        return []
+    # tps is expected in [n,4,4] format
+    topdown_p = np.array([[slam_to_world, 0, 0, 0], [0, 0, slam_to_world, 0]])
+    try:
+        world_coords = np.matmul(
+            topdown_p.reshape(1, 2, 4), tps[:, :, 3:].reshape(-1, 4, 1)
+        )
+    except BaseException:
+        return []
+    shift = int(floor(get_map_size_in_cells(map_size, cell_size) / 2.0))
+    topdown2index = np.array(
+        [[1.0 / cell_size, 0, shift], [0, 1.0 / cell_size, shift], [0, 0, 1]]
+    )
+    world_coords_h = np.concatenate(
+        [world_coords, np.ones((len(world_coords), 1, 1))], axis=1
+    )
+    world_coords = np.matmul(topdown2index, world_coords_h)[:, :2, 0]
+    return (
+        world_coords[:, ::-1].astype(np.int32) + 1
+    )  # for having revesrve (z,x) ordering
diff --git a/baselines/slambased/utils.py b/baselines/slambased/utils.py
new file mode 100644
index 000000000..8b39671c7
--- /dev/null
+++ b/baselines/slambased/utils.py
@@ -0,0 +1,43 @@
+import numpy as np
+import torch
+import time
+from PIL import Image
+
+
+def generate_2dgrid(h, w, centered=False):
+    if centered:
+        x = torch.linspace(-w / 2 + 1, w / 2, w)
+        y = torch.linspace(-h / 2 + 1, h / 2, h)
+    else:
+        x = torch.linspace(0, w - 1, w)
+        y = torch.linspace(0, h - 1, h)
+    grid2d = torch.stack(
+        [y.repeat(w, 1).t().contiguous().view(-1), x.repeat(h)], 1
+    )
+    return grid2d.view(1, h, w, 2).permute(0, 3, 1, 2)
+
+
+def str2bool(v):
+    if v.lower() in ("yes", "true", "t", "y", "1"):
+        return True
+    elif v.lower() in ("no", "false", "f", "n", "0"):
+        return False
+
+
+def resize_pil(np_img, size=128):
+    im1 = Image.fromarray(np_img)
+    im1.thumbnail((size, size))
+    return np.array(im1)
+
+
+def find_map_size(h, w):
+    map_size_in_meters = int(0.1 * 3 * max(h, w))
+    if map_size_in_meters % 10 != 0:
+        map_size_in_meters = map_size_in_meters + (
+            10 - (map_size_in_meters % 10)
+        )
+    return map_size_in_meters
+
+
+def gettimestr():
+    return time.strftime("%Y-%m-%d--%H_%M_%S", time.gmtime())
diff --git a/configs/tasks/pointnav_rgbd.yaml b/configs/tasks/pointnav_rgbd.yaml
new file mode 100644
index 000000000..9635a93b0
--- /dev/null
+++ b/configs/tasks/pointnav_rgbd.yaml
@@ -0,0 +1,24 @@
+ENVIRONMENT:
+  MAX_EPISODE_STEPS: 500
+SIMULATOR:
+  AGENT_0:
+    SENSORS: ['RGB_SENSOR', 'DEPTH_SENSOR']
+  HABITAT_SIM_V0:
+    GPU_DEVICE_ID: 0
+  RGB_SENSOR:
+    WIDTH: 256
+    HEIGHT: 256
+  DEPTH_SENSOR:
+    WIDTH: 256
+    HEIGHT: 256
+TASK:
+  TYPE: Nav-v0
+  SUCCESS_DISTANCE: 0.2
+  SENSORS: ['POINTGOAL_SENSOR']
+  POINTGOAL_SENSOR:
+    TYPE: PointGoalSensor
+    GOAL_FORMAT: POLAR
+  MEASUREMENTS: ['SPL']
+  SPL:
+    TYPE: SPL
+    SUCCESS_DISTANCE: 0.2
-- 
GitLab