Beispiel #1
0
 def generate_new_vehicle(self, vehicleClass):
     """Generate and import a new vehicle that will be controlled by SUMO."""
     # load the new vehicle
     vehicleString, defName = Vehicle.generate_vehicle_string(self.vehicleNumber, vehicleClass)
     self.rootChildren.importMFNodeFromString(-1, vehicleString)
     self.vehicles[self.vehicleNumber] = Vehicle(self.getFromDef(defName))
     self.vehicleNumber += 1
Beispiel #2
0
 def get_vehicle_index(self, id, generateIfneeded=True):
     """Look for the vehicle index corresponding to this id (and optionnaly create it if required)."""
     for i in range(0, self.vehicleNumber):
         if self.vehicles[i].currentID == id:
             # the vehicle was already here at last step
             return i
     if not generateIfneeded:
         return -1
     # the vehicle was not present last step
     # check if a corresponding vehicle is already in the simulation
     node = self.getFromDef(id)
     if node and (node.getTypeName() in Vehicle.get_car_models_list() or
                  node.getTypeName() in Vehicle.get_bus_models_list() or
                  node.getTypeName() in Vehicle.get_truck_models_list() or
                  node.getTypeName() in Vehicle.get_motorcycle_models_list()):
         self.vehicles[self.vehicleNumber] = Vehicle(node)
         self.vehicles[self.vehicleNumber].currentID = id
         self.vehicleNumber += 1
         return (self.vehicleNumber - 1)
     # check if a vehicle is available
     vehicleClass = self.get_vehicle_class(id)
     for i in range(0, self.vehicleNumber):
         if not self.vehicles[i].inUse and self.vehicles[i].vehicleClass == vehicleClass:
             # if a vehicle is available assign it to this id
             self.vehicles[i].currentID = id
             self.vehicles[i].name.setSFString(id)
             return i
     # no vehicle available => generate a new one if limit is not reached
     if self.vehicleNumber < self.vehiclesLimit:
         vehicleClass = self.get_vehicle_class(id)
         self.generate_new_vehicle(vehicleClass)
         return (self.vehicleNumber - 1)
     else:
         return -1
Beispiel #3
0
 def get_vehicle_class(self, id):
     """Get the class of the vehicle associated to this id."""
     if id in self.vehiclesClass:
         return self.vehiclesClass[id]
     vehicleClass = Vehicle.get_corresponding_vehicle_class(self.traci.vehicle.getVehicleClass(id))
     self.vehiclesClass[id] = vehicleClass
     return vehicleClass
Beispiel #4
0
 def get_initial_vehicles(self):
     """Get all the vehicles (both controlled by SUMO and Webots) already present in the world."""
     for i in range(0, self.vehiclesLimit):
         defName = "SUMO_VEHICLE%d" % self.vehicleNumber
         node = self.getFromDef(defName)
         if node:
             self.vehicles[i] = Vehicle(node)
             self.vehicles[i].name.setSFString("SUMO vehicle %i" % self.vehicleNumber)
             self.vehicleNumber += 1
         else:
             break
     for i in range(0, self.vehiclesLimit):
         defName = "WEBOTS_VEHICLE%d" % self.webotsVehicleNumber
         node = self.getFromDef(defName)
         if node:
             self.webotsVehicles[i] = WebotsVehicle(node, self.webotsVehicleNumber)
             self.webotsVehicleNumber += 1
         else:
             break
Beispiel #5
0
    def get_vehicles_position(self, subscriptionResult, step, xOffset, yOffset,
                              maximumLateralSpeed, maximumAngularSpeed, laneChangeDelay):
        """Compute the new desired position and orientation for all the vehicles controlled by SUMO."""
        for id in subscriptionResult.keys():
            height = 0.4
            roll = 0.0
            pitch = 0.0
            sumoPos = subscriptionResult[id][self.traci.constants.VAR_POSITION]
            sumoAngle = subscriptionResult[id][self.traci.constants.VAR_ANGLE]
            pos = [-sumoPos[0] + xOffset, height, sumoPos[1] - yOffset]
            angle = math.pi * sumoAngle / 180
            dx = -math.cos(angle)
            dy = -math.sin(angle)
            yaw = -math.atan2(dy, -dx)
            # correct position (origin of the car is not the same in Webots / sumo)
            vehicleLength = subscriptionResult[id][self.traci.constants.VAR_LENGTH]
            pos[0] += 0.5 * vehicleLength * math.sin(angle)
            pos[2] -= 0.5 * vehicleLength * math.cos(angle)
            # if needed check the vehicle is in the visibility radius
            if self.radius > 0:
                viewpointPosition = self.viewpointPosition.getSFVec3f()
                xDiff = viewpointPosition[0] - pos[0]
                yDiff = viewpointPosition[1]
                zDiff = viewpointPosition[2] - pos[2]
                distance = math.sqrt(xDiff * xDiff + yDiff * yDiff + zDiff * zDiff)
                if distance > self.radius:
                    index = self.get_vehicle_index(id, generateIfneeded=False)
                    if index >= 0:
                        self.vehicles[index].inUse = False
                        self.vehicles[index].currentID = ""
                        self.vehicles[index].name.setSFString("SUMO vehicle %i" % index)
                    continue
            index = self.get_vehicle_index(id)
            if index >= 0:
                vehicle = self.vehicles[index]
                height = vehicle.wheelRadius
                if self.enableHeight:
                    roadID = subscriptionResult[id][self.traci.constants.VAR_ROAD_ID]
                    roadPos = subscriptionResult[id][self.traci.constants.VAR_LANEPOSITION]
                    if roadID.startswith(":"):
                        # this is a lane change it does not contains edge information
                        # in that case, use previous height, roll and pitch
                        height = vehicle.currentPos[1]
                        roll = vehicle.roll
                        pitch = vehicle.pitch
                    else:
                        tags = roadID.split('_')
                        del tags[0]  # remove the first one which is the 'id' of the road
                        for tag in tags:
                            if tag.startswith('height'):
                                height = height + float(tag.split('height', 1)[1])
                            elif tag.startswith('roll'):
                                roll = float(tag.split('roll', 1)[1])
                            elif tag.startswith('pitch'):
                                pitch = float(tag.split('pitch', 1)[1])
                        vehicle.pitch = pitch
                        vehicle.roll = roll
                        # ajust height according to the pitch
                        if not pitch == 0:
                            height += (roadPos - 0.5 * vehicleLength) * math.sin(pitch)
                        # ajust height according to the roll and lateral position of the vehicle
                        if not roll == 0.0:
                            laneIndex = subscriptionResult[id][self.traci.constants.VAR_LANE_INDEX]
                            laneID = subscriptionResult[id][self.traci.constants.VAR_LANE_ID]
                            laneWidth = self.traci.lane.getWidth(laneID)
                            edge = self.net.getEdge(roadID)
                            numberOfLane = edge.getLaneNumber()
                            # compute lateral distance from the center of the lane
                            distance = math.fabs((laneIndex - numberOfLane / 2) + 0.5) * laneWidth
                            if laneIndex >= (numberOfLane / 2):
                                height = height - distance * math.sin(roll)
                            else:
                                height = height + distance * math.sin(roll)
                pos[1] = height
                if vehicle.inUse:
                    # TODO: once the lane change model of SUMO has been improved
                    #       (sub-lane model currently in development phase) we will be able to remove this corrections

                    # compute lateral (x) and longitudinal (z) displacement
                    diffX = pos[0] - vehicle.targetPos[0]
                    diffZ = pos[2] - vehicle.targetPos[2]
                    x1 = math.cos(-angle) * diffX - math.sin(-angle) * diffZ
                    z1 = math.sin(-angle) * diffX + math.cos(-angle) * diffZ
                    # check for lane change
                    if (vehicle.currentRoad is not None and
                            vehicle.currentRoad == subscriptionResult[id][self.traci.constants.VAR_ROAD_ID] and
                            vehicle.currentLane is not None and
                            vehicle.currentLane != subscriptionResult[id][self.traci.constants.VAR_LANE_INDEX]):
                        vehicle.laneChangeStartTime = self.getTime()
                        vehicle.laneChangeDistance = x1
                    x2 = x1
                    # artificially add an angle depending on the lateral speed
                    artificialAngle = 0
                    if z1 > 0.0001:  # don't add the angle if speed is very small as atan2(0.0, 0.0) is unstable
                        # the '0.15' factor was found empirically and should not depend on the simulation
                        artificialAngle = 0.15 * math.atan2(x1, z1)
                    if (vehicle.laneChangeStartTime is not None and
                            vehicle.laneChangeStartTime > self.getTime() - laneChangeDelay and
                            abs(vehicle.laneChangeDistance) >= abs(x1)):  # lane change case
                        ratio = (self.getTime() - vehicle.laneChangeStartTime) / laneChangeDelay
                        ratio = (0.5 + 0.5 * math.sin((ratio - 0.5) * math.pi))
                        p = vehicle.laneChangeDistance * ratio
                        x2 = x1 - (vehicle.laneChangeDistance - p)
                        artificialAngle = math.atan2(x2, z1)
                    # limit lateral speed
                    threshold = 0.001 * step * maximumLateralSpeed
                    x2 = min(max(x2, -threshold), threshold)
                    x3 = math.cos(angle) * x2 - math.sin(angle) * z1
                    z3 = math.sin(angle) * x2 + math.cos(angle) * z1
                    pos = [x3 + vehicle.targetPos[0], pos[1], z3 + vehicle.targetPos[2]]
                    diffYaw = yaw - vehicle.targetAngles[1] - artificialAngle
                    # limit angular speed
                    while diffYaw > math.pi:
                        diffYaw -= 2 * math.pi
                    while diffYaw < -math.pi:
                        diffYaw += 2 * math.pi
                    threshold = 0.001 * step * maximumAngularSpeed
                    diffYaw = min(max(diffYaw, -threshold), threshold)
                    yaw = diffYaw + vehicle.targetAngles[1]
                    # tilt motorcycle depending on the angluar speed
                    if vehicle.type in Vehicle.get_motorcycle_models_list():
                        threshold = 0.001 * step * maximumLateralSpeed
                        roll -= min(max(diffYaw / (0.001 * step), -0.2), 0.2)
                rot = rotation_from_yaw_pitch_roll(yaw, pitch, roll)
                if not vehicle.inUse:
                    # this vehicle was previously not used, move it directly to the correct initial location
                    vehicle.inUse = True
                    vehicle.currentPos = pos
                    vehicle.currentRot = rot
                    vehicle.currentAngles = [roll, yaw, pitch]
                else:
                    vehicle.currentPos = vehicle.targetPos
                    vehicle.currentRot = vehicle.targetRot
                    vehicle.currentAngles = vehicle.targetAngles
                # update target and wheels speed
                vehicle.targetPos = pos
                vehicle.targetRot = rot
                vehicle.targetAngles = [roll, yaw, pitch]
                if self.traci.constants.VAR_SPEED in subscriptionResult[id]:
                    vehicle.speed = subscriptionResult[id][self.traci.constants.VAR_SPEED]
                vehicle.currentRoad = subscriptionResult[id][self.traci.constants.VAR_ROAD_ID]
                vehicle.currentLane = subscriptionResult[id][self.traci.constants.VAR_LANE_INDEX]