class World(object): """Sets up a world in the simulation with robots, obstacles and a goal. Attributes: period -> float current_dt_target -> float width -> int height -> int physics -> Physics object map_manger -> MapManger object viewer -> Viewer object world_time -> float prev_absolute_time -> float supervisors -> list robots -> list obstacles -> list world_view -> WorldView object Methods: __init__(period=0.05) initialise_world(random=False, loading=False) draw_world() step() add_robot(robot) add_obstacle(obstacle) colliders() solids() stop_robots() """ def __init__(self, period=0.05): """Setup the world, physics and viewer for the simulation.""" # bind the world step rate # - seconds, passed to gui loop self.period = period # - ideal step length, but procees time will vary self.current_dt_target = period # setup the size of the world self.width = DEFAULT_WORLD_M_W self.height = DEFAULT_WORLD_M_H # initialize physics engine self.physics = Physics(self) # create the map manager self.map_manager = MapManager(self) # create the GUI self.viewer = Viewer(self, self.period, DEFAULT_ZOOM, RANDOM) self.viewer.initialise_viewer() def initialise_world(self, random=False, loading=False): """Generate the world in the simulation gui. This function sets up (or resets) the robots, their supervisors, the obstacles and goal and draws this to the gui.""" # initialize world time self.world_time = 0.0 # seconds self.prev_absolute_time = time() # initialize lists of world objects self.supervisors = [] self.robots = [] self.obstacles = [] # create the robot robot_1 = Robot(1, self.viewer, -0.5, -0.5, 270) #robot_2 = Robot(2, self.viewer, -1.0, 0.5, 270) self.add_robot(robot_1) #self.add_robot(robot_2) # generate a random environment if random: self.map_manager.random_map() print("Random Map") elif loading: self.map_manager.apply_to_world() print("Loading Map") else: self.map_manager.custom_map() print("Custom Map") # create the world view self.world_view = WorldView(self, self.viewer) # render the initial world self.draw_world() def reset_world(self): # initialize world time self.world_time = 0.0 # seconds self.prev_absolute_time = time() # initialize lists of world objects for robot in self.robots: robot.setup_robot(robot.x, robot.y, robot.deg) # render the initial world self.draw_world() def draw_world(self): """Refreshes the gui with the newly setup world.""" self.viewer.new_frame() # start a fresh frame self.world_view.draw_world_to_frame() # draw the world onto the frame self.viewer.draw_frame() # render the frame # step the simulation through one time interval def step(self): """Main step function of simulation, to step through time in world. This function first checks if the simulation is lagging or not by comparing the time passed since last called to the ideal time that should be taken between steps. An alarm is printed if lag occurs. The robot is first stepped in time to it's new position. Then physics are applied to these new robot positions to check for collisions and if obstacles are in range of the proximity sensors. The supervisors are then updated with the results of the physics test so controllers can be updated accordingly """ # calculate time since last step iteration time_now = time() self.current_dt = time_now - self.prev_absolute_time # update world_time to the current time self.prev_absolute_time = time_now # increment world time self.world_time += self.current_dt self.viewer._label_world_time.set_text('{0:.2f}'.format( self.world_time)) # Flag if current_dt is lagging by more than 5% if (self.current_dt > (self.current_dt_target * 1.05) or self.current_dt < (self.current_dt_target * 0.95)): print("Simulation lagging: {:.4f}").format(self.current_dt - self.current_dt_target) # read sensor values from all the robots for robot in self.robots: # read encoder values robot.read_encoders() # calculate the appropriate wheel velocities and control state for supervisor in self.supervisors: supervisor.step(self.current_dt) # step all the robots with the wheel velocities received from their # supervisors for robot in self.robots: # step robot motion robot.step_motion(self.current_dt) # check for interactions of robot with obstacles self.physics.apply_physics() def add_robot(self, robot): """Adds new robot to the robot list.""" self.robots.append(robot) self.supervisors.append(robot.supervisor) def add_obstacle(self, obstacle): """Adds new obstacle to the obstacle list.""" self.obstacles.append(obstacle) # return all objects in the world that might collide with other objects # in the world during simulation def colliders(self): """Returns a list of any moving objects in the simulation.""" # moving objects only return self.robots # as obstacles are static we should not test them # against each other # return all solids in the world def solids(self): """Returns a list of any solid objects in the world.""" return self.robots + self.obstacles def stop_robots(self): """Sends command to robot object to cease any motion. This is for sending a stop command to any connected physical robots. """ # stop all the robots for robot in self.robots: # stop robot motion robot.stop_motion()