microsoft / AirSim

Open source simulator for autonomous vehicles built on Unreal Engine / Unity, from Microsoft AI & Research
https://microsoft.github.io/AirSim/
Other
16.45k stars 4.58k forks source link

Reset Quadrotor to Desired Position #4667

Closed dkapur17 closed 2 years ago

dkapur17 commented 2 years ago

Question

What's your question?

Is there a way to spawn the multirotor at a given position, without losing Physics in the simulation?

Include context on what you are trying to achieve

I'm trying to train a Reinforcement Learning agent on an environment built using AirSim. I want to be able to randomly spawn the drone at different locations at the start of every episode, but the reset() method only moves it to its original position (the one set in the game engine before running the simulation) every time. I've read about the simSetVehiclePose method but it seems like that switches the simulation to Computer Vision mode, which disables all physics, and this is not ideal for me. Is there a way to spawn the drone at a random position in space while still keeping Multirotor Mode active?

Context details

Using Unity Engine with AirSim 1.8.1 with Python Bindings 1.7.0 on Windows 10.

Include details of what you already did to find answers

Went through similar issues, especially #1856, but couldn't find the answer.

HarrySoteriou commented 2 years ago
  import gym
  import airsim
  from gym import spaces
  import numpy as np
  import random
  from airgym.envs import AirSimEnv

  class RLEnv(AirSimEnv):

      sim_target = *insert Unreal Engine's tag for the object you need to spawn around* 
      camera_name = '3'
      image_type = airsim.ImageType.Scene
      actions = {
          0: [1, 0, 0],  # front
          1: [0, 1, 0],  # right
          2: [0, 0, 1],  # down
          3: [-1, 0, 0],  # back
          4: [0, -1, 0],  # left
          5: [1, 1, 0],  # forward + right
          6: [1, -1, 0],  # forward + left
          7: [-1, 1, 0],  # backward + right
          8: [-1, -1, 0],  # backward + left
          9: [0, 0, -1]   # up
      }

      def __init__(self, image_shape, lower_xy_bounds, upper_xy_bound):
          super(RLEnv, self).__init__(image_shape)
          """
          Initialize clients, enable API control and arm the drone
          """
          self.lower_xy_bound, self.upper_xy_bound = lower_xy_bound, upper_xy_bound
          self.image_shape=image_shape

          self.client = airsim.MultirotorClient(ip="")
          self.client.enableApiControl(True)
          self.client.armDisarm(True)

          """
          Define ACTION and STATE SPACE of gym env
          """
          self.action_space = spaces.Discrete(10)
          self.observation_space = spaces.Box(low=0, high=255, shape=self.image_shape, dtype=np.uint8)

          """
          Enable Unreal Engine objects to be found by the drone, then get the drone's and target's location
          and teleport the drone at a random location near the target
          """
          # Set detection radius in [cm]
          self.client.simSetDetectionFilterRadius(RLEnv.camera_name, RLEnv.image_type, 200 * 100)
          # Add desired object name to detect in wild card/regex format
          self.client.simAddDetectionFilterMeshName(RLEnv.camera_name, RLEnv.image_type, RLEnv.sim_target)

          self.drone_state = self.client.getMultirotorState()
          self.client.pose = self.initialize_location()
          self.client.simSetVehiclePose(self.client.pose, True)

          self.client.moveToZAsync(-self.height, 10).join() #takeoff

      @staticmethod
      def random_bounded_location(min_bound, max_bound):
          """
          Generate random starting position in the bounds given
          """
          return random.randint(min_bound, max_bound)

      def initialize_location(self):
          x = self.random_bounded_location(self.lower_xy_bound, self.upper_xy_bound)  # x distance from target
          y = self.random_bounded_location(self.lower_xy_bound, self.upper_xy_bound)  # y distance from target

          # Set relative position and orientation wrt to the target, not 100% correct but can't be bothered
          self.client.pose = self.client.simGetVehiclePose()
          obj_loc = [float(i) for i in self.client.simGetObjectPose(RLEnv.sim_target).position][:2]
          x_obj, y_obj = obj_loc[0] + x, obj_loc[1] + y
          self.client.pose.position.x_val = x_obj * random.randint(-1, 1)
          self.client.pose.position.y_val = y_obj * random.randint(-1, 1)
          self.client.pose.position.z_val = 0
          if x_obj == 0:
              x_obj = 1e-4
          self.client.pose.orientation.z_val = np.degrees(np.arctan(y_obj / x_obj)) / 100
          return self.client.pose

      def _get_obs(self):
          # make the api call to get images or readings you need and return them
          return obs

      def _do_action(self):
          # Here you write how you want your drone to move
          pass

      def _compute_reward(self):
          # here you code how you would compute reward for each timestep and return reward and observation
          return reward, done

      def step(self):
          self._do_action(action)
          obs = self._get_obs()
          reward, done = self._compute_reward()
          info ={"extra_info": "Fill in the dictionary with extra info that you need to plot"}
          return obs, reward, done, info

      def reset(self):
          self.reset_initial_state() # Code a function almost identical to __init__() that resets all metrics to the initial state
          return self._get_obs()

This should be decent to get you started, modify as you want and follow the example they have under reinforcement learning + sb3 +openaigym+ youtube examples.

dkapur17 commented 2 years ago

Thanks a lot!