Exemple #1
0
def provider_vehicle(position, heading, speed):
    return VehicleState(
        vehicle_id="sv-132",
        vehicle_config_type="truck",
        pose=Pose.from_center(position, heading),
        dimensions=Dimensions(length=3, width=1, height=2),
        speed=speed,
        source="TESTS",
    )
Exemple #2
0
 def _agent_spec_callback(self, ros_agent_spec: AgentSpec):
     assert (len(ros_agent_spec.tasks) == 1
             ), "more than 1 task per agent is not yet supported"
     task = ros_agent_spec.tasks[0]
     task_params = json.loads(task.params_json) if task.params_json else {}
     task_version = task.task_ver or "latest"
     agent_locator = f"{self._zoo_module}:{task.task_ref}-{task_version}"
     agent_spec = None
     try:
         agent_spec = registry.make(agent_locator, **task_params)
     except ImportError as ie:
         rospy.logerr(
             f"Unable to locate agent with locator={agent_locator}:  {ie}")
     if not agent_spec:
         rospy.logwarn(
             f"got unknown task_ref '{task.task_ref}' in AgentSpec message with params='{task.param_json}'.  ignoring."
         )
         return
     if (ros_agent_spec.end_pose.position.x != 0.0
             or ros_agent_spec.end_pose.position.y != 0.0):
         goal = PositionalGoal(
             (
                 ros_agent_spec.end_pose.position.x,
                 ros_agent_spec.end_pose.position.y,
             ),
             ros_agent_spec.veh_length,
         )
     else:
         goal = EndlessGoal()
     mission = Mission(
         start=Start.from_pose(
             ROSDriver._pose_from_ros(ros_agent_spec.start_pose)),
         goal=goal,
         # TODO:  how to prevent them from spawning on top of another existing vehicle? (see how it's done in SUMO traffic)
         entry_tactic=default_entry_tactic(ros_agent_spec.start_speed),
         vehicle_spec=VehicleSpec(
             veh_id=f"veh_for_agent_{ros_agent_spec.agent_id}",
             veh_config_type=ROSDriver._decode_vehicle_type(
                 ros_agent_spec.veh_type),
             dimensions=Dimensions(
                 ros_agent_spec.veh_length,
                 ros_agent_spec.veh_width,
                 ros_agent_spec.veh_height,
             ),
         ),
     )
     with self._reset_lock:
         if (ros_agent_spec.agent_id in self._agents
                 or ros_agent_spec.agent_id in self._agents_to_add):
             rospy.logwarn(
                 f"trying to add new agent with existing agent_id '{ros_agent_spec.agent_id}'.  ignoring."
             )
             return
         self._agents_to_add[ros_agent_spec.agent_id] = (agent_spec,
                                                         mission)
Exemple #3
0
 def update_vehicle_state(self):
     """Update this vehicle state."""
     assert len(self.vector) == 20
     self.vs.pose = Pose.from_center(
         self.vector[1:4], Heading(self.vector[4] % (2 * math.pi)))
     self.vs.dimensions = Dimensions(*self.vector[5:8])
     self.linear_velocity = self.vector[8:11]
     self.angular_velocity = self.vector[11:14]
     self.linear_acceleration = self.vector[14:17]
     self.angular_acceleration = self.vector[17:]
     self.vs.speed = np.linalg.norm(self.linear_velocity)
Exemple #4
0
def test_vehicle_bounding_box(bullet_client):
    pose = Pose.from_center((1, 1, 0), Heading(0))
    chassis = BoxChassis(
        pose=pose,
        speed=0,
        dimensions=Dimensions(length=3, width=1, height=1),
        bullet_client=bullet_client,
    )

    vehicle = Vehicle(
        id="vehicle-0",
        chassis=chassis,
        vehicle_config_type="passenger",
    )
    for coordinates in zip(vehicle.bounding_box, [[0.5, 2.5], (1.5, 2.5),
                                                  (1.5, -0.5), (0.5, -0.5)]):
        assert np.array_equal(coordinates[0], coordinates[1])
    def vehicle_dims(self, vehicle_id: str) -> Dimensions:
        """Get the vehicle dimensions of the specified vehicle."""
        # do import here to break circular dependency chain
        from smarts.core.vehicle import VEHICLE_CONFIGS

        query = "SELECT length, width, height, type FROM Vehicle WHERE id = ?"
        length, width, height, veh_type = self._query_val(
            tuple, query, params=(vehicle_id, ))
        default_dims = VEHICLE_CONFIGS[self.decode_vehicle_type(
            veh_type)].dimensions
        if not length:
            length = default_dims.length
        if not width:
            width = default_dims.width
        if not height:
            height = default_dims.height
        return Dimensions(length, width, height)
Exemple #6
0
def test_create_social_vehicle(bullet_client):
    chassis = BoxChassis(
        pose=Pose.from_center((0, 0, 0), Heading(0)),
        speed=0,
        dimensions=Dimensions(length=3, width=1, height=1),
        bullet_client=bullet_client,
    )

    car = Vehicle(
        id="sv-132",
        chassis=chassis,
        vehicle_config_type="passenger",
    )
    assert car.vehicle_type == "car"

    truck = Vehicle(
        id="sv-132",
        chassis=chassis,
        vehicle_config_type="truck",
    )
    assert truck.vehicle_type == "truck"
Exemple #7
0
 def _entity_to_vs(entity: EntityState) -> VehicleState:
     veh_id = entity.entity_id
     veh_type = ROSDriver._decode_entity_type(entity.entity_type)
     veh_dims = Dimensions(entity.length, entity.width, entity.height)
     vs = VehicleState(
         source="EXTERNAL",
         vehicle_id=veh_id,
         vehicle_config_type=veh_type,
         pose=Pose(
             ROSDriver._xyz_to_vect(entity.pose.position),
             ROSDriver._xyzw_to_vect(entity.pose.orientation),
         ),
         dimensions=veh_dims,
         linear_velocity=ROSDriver._xyz_to_vect(entity.velocity.linear),
         angular_velocity=ROSDriver._xyz_to_vect(entity.velocity.angular),
         linear_acceleration=ROSDriver._xyz_to_vect(
             entity.acceleration.linear),
         angular_acceleration=ROSDriver._xyz_to_vect(
             entity.acceleration.angular),
     )
     vs.set_privileged()
     vs.speed = np.linalg.norm(vs.linear_velocity)
     return vs
Exemple #8
0
    def _sync(self, provider_state: ProviderState):
        provider_vehicles = {v.vehicle_id: v for v in provider_state.vehicles}
        external_vehicles = [
            v for v in provider_state.vehicles if v.source != "SUMO"
        ]
        external_vehicle_ids = {v.vehicle_id for v in external_vehicles}

        # Represents current state
        traffic_vehicle_states = self._traci_conn.vehicle.getAllSubscriptionResults(
        )
        traffic_vehicle_ids = set(traffic_vehicle_states)

        # State / ownership changes
        external_vehicles_that_have_left = (self._non_sumo_vehicle_ids -
                                            external_vehicle_ids -
                                            traffic_vehicle_ids)
        external_vehicles_that_have_joined = (external_vehicle_ids -
                                              self._non_sumo_vehicle_ids -
                                              traffic_vehicle_ids)
        vehicles_that_have_become_external = (
            traffic_vehicle_ids
            & external_vehicle_ids - self._non_sumo_vehicle_ids)
        # XXX: They may have become internal because they've been relinquished or
        #      because they've been destroyed from a collision. Presently we're not
        #      differentiating and will take over as social vehicles regardless.
        vehicles_that_have_become_internal = (
            self._non_sumo_vehicle_ids -
            external_vehicle_ids) & traffic_vehicle_ids

        log = ""
        if external_vehicles_that_have_left:
            log += (
                f"external_vehicles_that_have_left={external_vehicles_that_have_left}\n"
            )
        if external_vehicles_that_have_joined:
            log += f"external_vehicles_that_have_joined={external_vehicles_that_have_joined}\n"
        if vehicles_that_have_become_external:
            log += f"vehicles_that_have_become_external={vehicles_that_have_become_external}\n"
        if vehicles_that_have_become_internal:
            log += f"vehicles_that_have_become_internal={vehicles_that_have_become_internal}\n"

        if log:
            self._log.debug(log)

        for vehicle_id in external_vehicles_that_have_left:
            self._log.debug("Non SUMO vehicle %s left simulation", vehicle_id)
            self._non_sumo_vehicle_ids.remove(vehicle_id)
            self._traci_conn.vehicle.remove(vehicle_id)

        for vehicle_id in external_vehicles_that_have_joined:
            vehicle_state = provider_vehicles[vehicle_id]
            dimensions = Dimensions.copy_with_defaults(
                vehicle_state.dimensions,
                VEHICLE_CONFIGS[vehicle_state.vehicle_config_type].dimensions,
            )
            self._create_vehicle(vehicle_id, dimensions)
            no_checks = 0b00000
            self._traci_conn.vehicle.setSpeedMode(vehicle_id, no_checks)

        # update the state of all current managed vehicles
        for vehicle_id in self._non_sumo_vehicle_ids:
            provider_vehicle = provider_vehicles[vehicle_id]

            pos, sumo_heading = provider_vehicle.pose.as_sumo(
                provider_vehicle.dimensions.length, Heading(0))

            # See https://sumo.dlr.de/docs/TraCI/Change_Vehicle_State.html#move_to_xy_0xb4
            # for flag values
            try:
                self._move_vehicle(
                    provider_vehicle.vehicle_id,
                    pos,
                    sumo_heading,
                    provider_vehicle.speed,
                )
            except TraCIException as e:
                # Likely as a result of https://github.com/eclipse/sumo/issues/3993
                # the vehicle got removed because we skipped a moveToXY call between
                # internal stepSimulations, so we add the vehicle back here.
                self._log.warning(
                    "Attempted to (TraCI) SUMO.moveToXY(...) on missing "
                    f"vehicle(id={vehicle_id})")
                self._create_vehicle(vehicle_id, provider_vehicle.dimensions)
                self._move_vehicle(
                    provider_vehicle.vehicle_id,
                    pos,
                    sumo_heading,
                    provider_vehicle.speed,
                )

        for vehicle_id in vehicles_that_have_become_external:
            no_checks = 0b00000
            self._traci_conn.vehicle.setSpeedMode(vehicle_id, no_checks)
            self._traci_conn.vehicle.setColor(
                vehicle_id,
                SumoTrafficSimulation._social_agent_vehicle_color())
            self._non_sumo_vehicle_ids.add(vehicle_id)

        for vehicle_id in vehicles_that_have_become_internal:
            self._traci_conn.vehicle.setColor(
                vehicle_id, SumoTrafficSimulation._social_vehicle_color())
            self._non_sumo_vehicle_ids.remove(vehicle_id)
            # Let sumo take over speed again
            # For setSpeedMode look at: https://sumo.dlr.de/docs/TraCI/Change_Vehicle_State.html#speed_mode_0xb3
            all_checks = 0b11111
            self._traci_conn.vehicle.setSpeedMode(vehicle_id, all_checks)
            self._traci_conn.vehicle.setSpeed(vehicle_id, -1)

        if self._endless_traffic:
            self._reroute_vehicles(traffic_vehicle_states)
            self._teleport_exited_vehicles()
Exemple #9
0
    def __init__(
        self,
        pose: Pose,
        bullet_client: bc.BulletClient,
        vehicle_filepath=DEFAULT_VEHICLE_FILEPATH,
        tire_parameters_filepath=None,
        friction_map=None,
        controller_parameters=DEFAULT_CONTROLLER_PARAMETERS,
        initial_speed=None,
    ):
        assert isinstance(pose, Pose)
        self._log = logging.getLogger(self.__class__.__name__)

        # XXX: Parameterize these vehicle properties?
        self._client = bullet_client
        self._chassis_aero_force_gain = controller_parameters["chassis"][
            "chassis_aero_force_gain"]
        self._max_brake_gain = controller_parameters["chassis"][
            "max_brake_gain"]
        # This value was found emperically. It causes the wheel steer joints to
        # reach their maximum. We use this value to map to the -1, 1 steering range.
        # If it were larger we'd cap out our turning radius before we hit -1, or 1.
        # If it were smaller we'd never reach the tightest turning radius we could.
        self._max_turn_radius = controller_parameters["chassis"][
            "max_turn_radius"]
        self._wheel_radius = controller_parameters["chassis"]["wheel_radius"]
        self._max_torque = controller_parameters["chassis"]["max_torque"]
        self._max_btorque = controller_parameters["chassis"]["max_btorque"]
        # 720 is the maximum driver steering wheel angle
        # which equals to two full rotation of steering wheel.
        # This corresponds to maximum 41.3 deg angle at tires.
        self._max_steering = controller_parameters["chassis"]["max_steering"]
        self._steering_gear_ratio = controller_parameters["chassis"][
            "steering_gear_ratio"]
        self._tire_model = None
        self._lat_forces = np.zeros(4)
        self._lon_forces = np.zeros(4)
        self._plane_id = None
        self._friction_map = friction_map
        self._tire_parameters = None
        self._road_wheel_frictions = None

        self._bullet_id = self._client.loadURDF(
            vehicle_filepath,
            [0, 0, 0],
            [0, 0, 0, 1],
            useFixedBase=False,
            # We use cylinders for wheels, If we don't provide this flag, bullet
            # will subdivide the cylinder resulting in bouncy ride
            flags=pybullet.URDF_USE_IMPLICIT_CYLINDER
            | pybullet.URDF_ENABLE_CACHED_GRAPHICS_SHAPES,
        )
        for i in range(self._client.getNumBodies()):
            if self._client.getBodyInfo(i)[1].decode("ascii") == "plane":
                self._plane_id = self._client.getBodyUniqueId(i)
                self._road_wheel_frictions = {
                    "road_friction":
                    self._client.getDynamicsInfo(
                        self._plane_id,
                        -1,
                    )[1],
                    "wheel_friction":
                    self._client.getDynamicsInfo(
                        self._bullet_id,
                        2,
                    )[1],
                }
                break

        self._controller_parameters = controller_parameters["control"]

        if (tire_parameters_filepath
                is not None) and os.path.exists(tire_parameters_filepath):
            self._client.changeDynamics(
                self._plane_id,
                -1,
                lateralFriction=1e-16,
            )
            with open(tire_parameters_filepath, "r") as tire_file:
                self._tire_parameters = yaml.safe_load(tire_file)
                self._tire_model = TireForces.build_tire_model(
                    [
                        self._tire_parameters["C_alpha_front"],
                        self._tire_parameters["C_alpha_rear"],
                        self._tire_parameters["C_x_front"],
                        self._tire_parameters["C_x_rear"],
                    ],
                    self._tire_parameters["tire_model"],
                    self._tire_parameters["road_friction"],
                )
            for j in [2, 4, 5, 6]:
                self._client.setCollisionFilterPair(self._bullet_id,
                                                    self._plane_id, j, -1, 0)

        for _id in range(len(self._load_joints(self._bullet_id)) + 1):
            self._client.changeDynamics(
                self._bullet_id,
                _id - 1,
                linearDamping=0,
                angularDamping=0.00001,
                maxJointVelocity=
                300,  # This is a limit after which the pybullet interfer with the dynamics to ensure the bound.
            )

        width, length, height = np.array(
            self._client.getCollisionShapeData(self._bullet_id, 0)[0][3])
        self._dimensions = Dimensions(length=length,
                                      width=width,
                                      height=height)
        chassis_pos = self._client.getLinkState(self._bullet_id, 0)[4]
        center_offset = np.array(
            self._client.getVisualShapeData(self._bullet_id, 0)[0][5])

        self._joints = self._load_joints(self._bullet_id)

        # 2,4,5,6 are the indices of wheels (FL,FR,RL,RR) and 1,3 are the
        # indices for front left and front right steer joints, 0 is
        # the index of the base link.
        link_states = self._client.getLinkStates(self._bullet_id,
                                                 [0, 2, 4, 5, 6])
        link_positions = [np.array(state[0]) for state in link_states]
        base_pos = link_positions[0] + self._client.getLinkState(
            self._bullet_id, 0)[2]
        front_left_wheel_pos = link_positions[1]
        front_right_wheel_pos = link_positions[2]
        back_left_wheel_pos = link_positions[3]
        back_right_wheel_pos = link_positions[4]
        self._front_track_width = np.linalg.norm(front_left_wheel_pos -
                                                 front_right_wheel_pos)
        self._rear_track_width = np.linalg.norm(back_left_wheel_pos -
                                                back_right_wheel_pos)
        self._front_distant_CG = np.linalg.norm(
            0.5 * (front_left_wheel_pos[0:2] + front_right_wheel_pos[0:2]) -
            base_pos[0:2])
        self._rear_distant_CG = np.linalg.norm(
            0.5 * (back_left_wheel_pos[0:2] + back_right_wheel_pos[0:2]) -
            base_pos[0:2])

        # distance between axles
        front_axle_pos = (front_left_wheel_pos + front_right_wheel_pos) / 2
        back_axle_pos = (back_left_wheel_pos + back_right_wheel_pos) / 2
        self._wheel_base_length = np.linalg.norm(front_axle_pos -
                                                 back_axle_pos)
        self._clear_joint_forces()

        self.set_pose(pose)

        if initial_speed is not None:
            self._initialize_speed(initial_speed)