Merge remote-tracking branch 'origin/master'

This commit is contained in:
David Eder 2021-06-18 07:28:19 +02:00
commit afc919a21d
25 changed files with 480 additions and 122 deletions

View File

@ -1,3 +1,4 @@
import os
from bson import json_util from bson import json_util
from flask import Flask, request from flask import Flask, request
from flask_pymongo import PyMongo from flask_pymongo import PyMongo
@ -6,6 +7,38 @@ app = Flask(__name__)
app.config["MONGO_URI"] = "mongodb://mongo:27017/entities" app.config["MONGO_URI"] = "mongodb://mongo:27017/entities"
mongo = PyMongo(app) mongo = PyMongo(app)
CAR1_SV = int(os.environ.get('DSE2021_CAR1_SV', 130))
CAR2_SV = int(os.environ.get('DSE2021_CAR2_SV', 130))
CAR3_SV = int(os.environ.get('DSE2021_CAR3_SV', 130))
CAR1_SD = int(os.environ.get('DSE2021_CAR1_SD', 300))
CAR2_SD = int(os.environ.get('DSE2021_CAR2_SD', 500))
CAR3_SD = int(os.environ.get('DSE2021_CAR3_SD', 400))
CAR1_ST = int(os.environ.get('DSE2021_CAR1_ST', 10))
CAR2_ST = int(os.environ.get('DSE2021_CAR2_ST', 15))
CAR3_ST = int(os.environ.get('DSE2021_CAR3_ST', 25))
TL1_R = int(os.environ.get('DSE2021_TL1_R', 2000))
TL2_R = int(os.environ.get('DSE2021_TL2_R', 800))
TL3_R = int(os.environ.get('DSE2021_TL3_R', 1000))
mongo.db.trafficLights.update_one({"id": "1"}, {"$set": {"range": TL1_R}})
mongo.db.trafficLights.update_one({"id": "2"}, {"$set": {"range": TL2_R}})
mongo.db.trafficLights.update_one({"id": "3"}, {"$set": {"range": TL3_R}})
mongo.db.cars.update_one({"vin": "SCBFR7ZA5CC072256"}, {"$set": {"startingVelocity": CAR1_SV}})
mongo.db.cars.update_one({"vin": "5GZCZ43D13S812715"}, {"$set": {"startingVelocity": CAR2_SV}})
mongo.db.cars.update_one({"vin": "5GZCZ43D13S812716"}, {"$set": {"startingVelocity": CAR3_SV}})
mongo.db.cars.update_one({"vin": "SCBFR7ZA5CC072256"}, {"$set": {"startingDistance": CAR1_SD}})
mongo.db.cars.update_one({"vin": "5GZCZ43D13S812715"}, {"$set": {"startingDistance": CAR2_SD}})
mongo.db.cars.update_one({"vin": "5GZCZ43D13S812716"}, {"$set": {"startingDistance": CAR3_SD}})
mongo.db.cars.update_one({"vin": "SCBFR7ZA5CC072256"}, {"$set": {"startingTime": CAR1_ST}})
mongo.db.cars.update_one({"vin": "5GZCZ43D13S812715"}, {"$set": {"startingTime": CAR2_ST}})
mongo.db.cars.update_one({"vin": "5GZCZ43D13S812716"}, {"$set": {"startingTime": CAR3_ST}})
@app.route('/api/v1/resources/cars', methods=['GET']) @app.route('/api/v1/resources/cars', methods=['GET'])
def get_cars(): def get_cars():

View File

@ -2,25 +2,16 @@
{ {
"oem": "BENTLEY", "oem": "BENTLEY",
"modelType": "Continental", "modelType": "Continental",
"vin": "SCBFR7ZA5CC072256", "vin": "SCBFR7ZA5CC072256"
"startingVelocity": 130,
"startingDistance": 300,
"startingTime": 10
}, },
{ {
"oem": "SATURN", "oem": "SATURN",
"modelType": "Vue", "modelType": "Vue",
"vin": "5GZCZ43D13S812715", "vin": "5GZCZ43D13S812715"
"startingVelocity": 130,
"startingDistance": 500,
"startingTime": 15
}, },
{ {
"oem": "SATURN", "oem": "SATURN",
"modelType": "Vue2", "modelType": "Vue2",
"vin": "5GZCZ43D13S812716", "vin": "5GZCZ43D13S812716"
"startingVelocity": 130,
"startingDistance": 100,
"startingTime": 25
} }
] ]

View File

@ -2,22 +2,19 @@
{ {
"id": "1", "id": "1",
"location": [16.20719, 47.89584], "location": [16.20719, 47.89584],
"range": 2000, "switchingTime": 26,
"switchingTime": 5,
"color": "RED" "color": "RED"
}, },
{ {
"id": "2", "id": "2",
"location": [16.20814, 47.90937], "location": [16.20814, 47.90937],
"range": 800, "switchingTime": 16,
"switchingTime": 15,
"color": "GREEN" "color": "GREEN"
}, },
{ {
"id": "3", "id": "3",
"location": [16.20917, 47.92703], "location": [16.20917, 47.92703],
"range": 1000, "switchingTime": 20,
"switchingTime": 10,
"color": "RED" "color": "RED"
} }
] ]

View File

@ -16,7 +16,7 @@ from event_logger import EventLogger
class TestEventLogger(unittest.TestCase): class TestEventLogger(unittest.TestCase):
def setUp(self) -> None: def setUp(self) -> None:
self.el = EventLogger(StrictRedis(), False, False) self.el = EventLogger(StrictRedis(), False, False)
self.timestamp = datetime.datetime.now() self.timestamp = datetime.datetime.utcnow()
def test_unpack_daf(self): def test_unpack_daf(self):
daf = DAF(vehicle_identification_number='my_vin', daf = DAF(vehicle_identification_number='my_vin',
@ -60,7 +60,7 @@ class TestEventLogger(unittest.TestCase):
self.assertEqual(message, json.dumps(unknown)) self.assertEqual(message, json.dumps(unknown))
def test_unpack_unknown_object(self): def test_unpack_unknown_object(self):
obj = datetime.datetime.now() obj = datetime.datetime.utcnow()
key, message = self.el._unpack_message_to_log(pickle.dumps(obj)) key, message = self.el._unpack_message_to_log(pickle.dumps(obj))

View File

@ -1,6 +1,7 @@
import pickle import pickle
import threading import threading
import time import time
import os
from datetime import datetime from datetime import datetime
from circuitbreaker import circuit from circuitbreaker import circuit
@ -13,7 +14,7 @@ from pika.exceptions import AMQPConnectionError
SWITCHING_TIME = 15 SWITCHING_TIME = 15
# Scale speed of switching by factor x # Scale speed of switching by factor x
SCALING = 1 SCALING = int(os.environ.get('DSE2021_SCALING', 1))
class TrafficLight: class TrafficLight:
@ -56,23 +57,10 @@ class TrafficLight:
def start(self): def start(self):
""" """
Starts the traffic light by spawning a new thread. It toggles its state every self.switching_time / SCALING Starts the traffic light by spawning a new thread..
seconds. When it switches, it notifies the orchestrator with self.send_status_update().
""" """
self.running = True self.running = True
self._t = threading.Thread(target=self._switcher)
def switcher():
num_colors = len(TrafficLightColor)
# set current color to the one before starting color, because switch immediately happens in loop
# therefore it sleeps on the end of the loop and first status is immediately sent to msg broker
self.current_color = TrafficLightColor((self._starting_color.value - 1) % num_colors)
while self.running:
self.current_color = TrafficLightColor((self.current_color.value + 1) % num_colors)
self.last_switch = datetime.now()
self.send_status_update()
time.sleep(self.switching_time / SCALING)
self._t = threading.Thread(target=switcher)
self._t.start() self._t.start()
def stop(self): def stop(self):
@ -91,6 +79,21 @@ class TrafficLight:
self._tl_mb.send(pickle.dumps( self._tl_mb.send(pickle.dumps(
TrafficLightState(tlid=self.tlid, color=self.current_color, last_switch=self.last_switch))) TrafficLightState(tlid=self.tlid, color=self.current_color, last_switch=self.last_switch)))
def _switcher(self):
"""
Toggles the traffic lights state every self.switching_time / SCALING seconds.
When it switches, it notifies the orchestrator with self.send_status_update()
"""
num_colors = len(TrafficLightColor)
# set current color to the one before starting color, because switch immediately happens in loop
# therefore it sleeps on the end of the loop and first status is immediately sent to msg broker
self.current_color = TrafficLightColor((self._starting_color.value - 1) % num_colors)
while self.running:
self.current_color = TrafficLightColor((self.current_color.value + 1) % num_colors)
self.last_switch = datetime.utcnow()
self.send_status_update()
time.sleep(self.switching_time / SCALING)
if __name__ == '__main__': if __name__ == '__main__':
... ...

View File

@ -1,6 +1,7 @@
import pickle import pickle
import threading import threading
import time import time
import os
from datetime import datetime from datetime import datetime
from typing import Union from typing import Union
@ -19,11 +20,13 @@ STARTING_POINT = geopy.Point(47.89053, 16.20703)
# Driving direction in degrees: 0=N, 90=E, 180=S, 270=W # Driving direction in degrees: 0=N, 90=E, 180=S, 270=W
BEARING = 2 BEARING = 2
# Scale speed of vehicles by factor x # Scale speed of vehicles by factor x
SCALING = 1 SCALING = int(os.environ.get('DSE2021_SCALING', 1))
# in km/h # in km/h
STARTING_VELOCITY = 130 * SCALING STARTING_VELOCITY = 130 * SCALING
# Interval between status updates in seconds (is not scaled) # Interval between status updates in seconds (is not scaled)
UPDATE_INTERVAL = 1 UPDATE_INTERVAL = 1
# Specify if NCE should happen
NCE = int(os.environ.get('DSE2021_NCE', 1))
# At x km the NCE shall happen # At x km the NCE shall happen
NCE_KM = 2.4 NCE_KM = 2.4
# Time in seconds to recover from NCE (will be scaled) # Time in seconds to recover from NCE (will be scaled)
@ -104,8 +107,12 @@ class Vehicle:
:return: True if NCE invoked, otherwise False :return: True if NCE invoked, otherwise False
""" """
if self._nce_possible and not self._nce_happened: d = geopy.distance.distance(kilometers=0.4)
if self._driven_kms >= NCE_KM: tl2_loc = geopy.Point(47.90937, 16.20814)
# Calculate point 400m south of traffic light 2
nce_point = d.destination(point=tl2_loc, bearing=182)
if NCE == 1 and self._nce_possible and not self._nce_happened:
if self._gps_location.latitude >= nce_point.latitude:
self._nce_happened = True self._nce_happened = True
self._last_velocity = self.velocity self._last_velocity = self.velocity
self.velocity = 0 self.velocity = 0
@ -163,14 +170,14 @@ class Vehicle:
# Get old and updated timestamps # Get old and updated timestamps
old_timestamp = self.last_update old_timestamp = self.last_update
updated_timestamp = datetime.now() updated_timestamp = datetime.utcnow()
self.last_update = updated_timestamp self.last_update = updated_timestamp
# get driving time between timestamps (in seconds) # get driving time between timestamps (in seconds)
driving_time = (updated_timestamp - old_timestamp).total_seconds() driving_time = (updated_timestamp - old_timestamp).total_seconds()
# reached distance in kilometers: convert km/h to km/s and multiply by driving time # reached distance in kilometers: convert km/h to km/s and multiply by driving time
kilometers = self.velocity / 3600 * driving_time * SCALING kilometers = self.velocity / 3600 * driving_time
# Define a general distance object, initialized with a distance of k km. # Define a general distance object, initialized with a distance of k km.
d = geopy.distance.distance(kilometers=kilometers) d = geopy.distance.distance(kilometers=kilometers)
@ -196,7 +203,7 @@ class Vehicle:
informs the message broker about the current state (DAF) of the vehicle. informs the message broker about the current state (DAF) of the vehicle.
""" """
print('{} starts driving ... SCALING: x{}\n\n'.format(self.vin, SCALING)) print('{} starts driving ... SCALING: x{}\n\n'.format(self.vin, SCALING))
self.last_update = datetime.now() self.last_update = datetime.utcnow()
self._driven_kms = 0 self._driven_kms = 0
self._t = threading.Thread(target=self.drive) self._t = threading.Thread(target=self.drive)
@ -223,14 +230,16 @@ class Vehicle:
def check_reset(self): def check_reset(self):
""" """
Checks if end of route is reached and resets vehicle to starting conditions. Checks if end of route is reached and resets vehicle to starting conditions.
It also resets on malicious coordinates.
Afterwards, the vehicle is still driving, but again from start. Afterwards, the vehicle is still driving, but again from start.
""" """
if self._driven_kms >= RESET_KM: if self._driven_kms >= RESET_KM:
print('\n\nEnd of route reached ... resetting and restarting vehicle') self._reset()
self._gps_location = self._starting_point
self._driven_kms = 0 if self._gps_location.latitude < self._starting_point.latitude or \
self.last_update = datetime.now() self._gps_location.longitude < self._starting_point.longitude:
self.nce = False self._reset()
@circuit(failure_threshold=10, expected_exception=AMQPConnectionError) @circuit(failure_threshold=10, expected_exception=AMQPConnectionError)
def send_status_update(self): def send_status_update(self):
@ -255,6 +264,14 @@ class Vehicle:
else: else:
print('We are still recovering ... ignoring new target velocity.') print('We are still recovering ... ignoring new target velocity.')
def _reset(self):
print('\n\nEnd of route reached ... resetting and restarting vehicle')
self._gps_location = self._starting_point
self._driven_kms = 0
self.last_update = datetime.utcnow()
self.nce = False
self.velocity = STARTING_VELOCITY
if __name__ == "__main__": if __name__ == "__main__":
... ...

View File

@ -0,0 +1,113 @@
import datetime
import pickle
import time
import unittest
from unittest.mock import patch
import geopy
from dse_shared_libs.daf import DAF
from dse_shared_libs.mock.datetime import MyDate
from dse_shared_libs.target_velocity import TargetVelocity
from dse_shared_libs.traffic_light_color import TrafficLightColor
from devices.traffic_light import TrafficLight
from devices.vehicle import Vehicle
from dse_shared_libs.mock.rabbit_mq_mocks import MyBlockingConnection
class TestVehicle(unittest.TestCase):
def setUp(self) -> None:
with patch('pika.BlockingConnection', MyBlockingConnection):
self.vin = 'my_vin'
self.starting_velocity = 130
self.starting_point = geopy.Point(0, 0, 0)
self.timestamp = datetime.datetime.utcnow()
self.v = Vehicle(
vin=self.vin,
starting_point=self.starting_point,
starting_velocity=self.starting_velocity
)
self.v.last_update = self.timestamp
self.v._driven_kms = 0
def tearDown(self) -> None:
time.sleep(0.1)
def test_nce_prop(self):
with patch('time.sleep', return_value=None):
# initially false
self.assertEqual(self.v.nce, False)
# get past nce km
self.v._gps_location.latitude = 48
# now nce should fire
self.assertEqual(self.v.nce, True)
# second call is false again
self.assertEqual(self.v.nce, False)
def test_daf_prop(self):
with patch('devices.vehicle.datetime', MyDate):
MyDate.set_timestamp(self.timestamp)
# test if daf object created properly
daf = DAF(vehicle_identification_number=self.vin,
gps_location=self.starting_point,
velocity=self.starting_velocity,
timestamp=self.timestamp,
near_crash_event=False)
self.assertEqual(self.v.daf, daf)
def test_current_location_prop(self):
with patch('devices.vehicle.datetime', MyDate):
MyDate.set_timestamp(self.timestamp)
# initial position should be starting point
self.assertEqual(self.v.gps_location, self.starting_point)
# lets say last time was about an hour ago
self.v.last_update = self.timestamp - datetime.timedelta(hours=1)
# we drive "almost" directly north
loc = self.v.gps_location
self.assertEqual(round(loc.latitude, 2), 1.17)
self.assertEqual(round(loc.longitude, 2), 0.04)
def test_driven_kms_prop(self):
# initial driven kms are 0
self.assertEqual(self.v.driven_kms, '0km')
# alter driven kms
self.v._driven_kms = 44.24552
# will be rounded to 2 digits
self.assertEqual(self.v.driven_kms, '44.25km')
def test_new_velocity(self):
# starting velocity is set to 130
self.assertEqual(self.v.velocity, 130)
# we get a new velocity, lets say 55 ...
tv = TargetVelocity(vin='my_vin', target_velocity=55, timestamp=self.timestamp)
self.v.new_velocity(pickle.dumps(tv))
# then the vehicle should comply with that
self.assertEqual(self.v.velocity, 55)
class TestTrafficLight(unittest.TestCase):
def setUp(self) -> None:
with patch('pika.BlockingConnection', MyBlockingConnection):
self.tl = TrafficLight(tlid='my_tl',
switching_time=1,
starting_color=TrafficLightColor.RED)
def tearDown(self) -> None:
self.tl.stop()
def test_switching(self):
self.assertFalse(hasattr(self.tl, 'current_color'))
self.tl.start()
self.assertEqual(self.tl.current_color, TrafficLightColor.RED)
time.sleep(1.2)
self.assertEqual(self.tl.current_color, TrafficLightColor.GREEN)
time.sleep(1)
self.assertEqual(self.tl.current_color, TrafficLightColor.RED)

View File

@ -1,9 +1,10 @@
import datetime import datetime
import pickle import pickle
import sys import sys
import os
from typing import List, Dict from typing import List, Dict
from datetime import datetime, timedelta from datetime import datetime, timedelta
from math import floor, ceil from math import floor
import requests import requests
from dse_shared_libs import daf, traffic_light_state, traffic_light_color, target_velocity from dse_shared_libs import daf, traffic_light_state, traffic_light_color, target_velocity
@ -22,7 +23,7 @@ sys.modules['target_velocity'] = target_velocity
ENTITY_IDENT_URL = 'http://entityident:5002/api/v1/resources/' ENTITY_IDENT_URL = 'http://entityident:5002/api/v1/resources/'
SCALING = 1 SCALING = int(os.environ.get('DSE2021_SCALING', 1))
class Orchestrator: class Orchestrator:
@ -60,7 +61,7 @@ class Orchestrator:
for traffic_light in traffic_lights['cursor']: for traffic_light in traffic_lights['cursor']:
self.tls[traffic_light['id']] = {'color': traffic_light['color'], self.tls[traffic_light['id']] = {'color': traffic_light['color'],
'switching_time': traffic_light['switchingTime'], 'switching_time': traffic_light['switchingTime'],
'last_switch': datetime.now()} 'last_switch': datetime.utcnow()}
def setup_msg_queues(self): def setup_msg_queues(self):
""" """
@ -88,7 +89,7 @@ class Orchestrator:
""" """
Gets the daf object's pickle binary dump. Gets the daf object's pickle binary dump.
Unpickle, calculate new target velocity based on daf and current tl data and Unpickle, calculate new target velocity based on daf and current tl data and
respond new target velicity for this vehicle. respond new target velocity for this vehicle.
:param pickle_binary: daf object pickle binary dump :param pickle_binary: daf object pickle binary dump
""" """
@ -100,55 +101,14 @@ class Orchestrator:
params={'lat': loc.latitude, 'lon': loc.longitude}) params={'lat': loc.latitude, 'lon': loc.longitude})
traffic_lights_geo = response.json() traffic_lights_geo = response.json()
current_vel = received_daf_object.velocity current_vel = received_daf_object.velocity
target_vel = 130 * SCALING
print('Nearest traffic lights: {}'.format(traffic_lights_geo['cursor'])) target_vel = self._compute_velocity(traffic_lights_geo, current_vel)
for traffic_light in traffic_lights_geo['cursor']:
# Should only ever contain one traffic light (the next in line)
tl_id = traffic_light['id']
distance = traffic_light['calculatedRange']
switching_time = self.tls[tl_id]['switching_time'] / float(SCALING)
# Time until next switch must be scaled accordingly
next_switch_time = self.tls[tl_id]['last_switch'] + timedelta(seconds=switching_time)
time_until_switch = (next_switch_time - datetime.now()).total_seconds()
print('Distance to TL: {}'.format(distance))
print('Time until switch in seconds: {}'.format(time_until_switch))
if self.tls[tl_id]['color'] is TrafficLightColor.RED:
speed_needed_max = (distance / float(time_until_switch)) * 3.6
if speed_needed_max < 130 * SCALING:
if current_vel < speed_needed_max:
target_vel = current_vel
else:
target_vel = floor(speed_needed_max)
else:
# Cannot make it on next green
i = 2
while speed_needed_max > 130 * SCALING:
next_green_phase_start = time_until_switch + switching_time * i
speed_needed_max = (distance / float(next_green_phase_start)) * 3.6
i = i + 2
target_vel = floor(speed_needed_max)
else:
# Check if we can reach TL in time
speed_needed_min = (distance / float(time_until_switch)) * 3.6
if speed_needed_min < 130 * SCALING:
if current_vel < speed_needed_min:
target_vel = 130 * SCALING
else:
target_vel = current_vel
else:
i = 1
speed_needed_max = 132 * SCALING
while speed_needed_max > 130 * SCALING:
next_green_phase_start = time_until_switch + switching_time * i
speed_needed_max = (distance / float(next_green_phase_start)) * 3.6
i = i + 2
target_vel = floor(speed_needed_max)
response_channel = self._velocity_mbs[received_daf_object.vehicle_identification_number] response_channel = self._velocity_mbs[received_daf_object.vehicle_identification_number]
print('Target velocity: {}'.format(target_vel)) print('Target velocity: {}'.format(target_vel))
response_channel.send(pickle.dumps( response_channel.send(pickle.dumps(
TargetVelocity(vin=received_daf_object.vehicle_identification_number, target_velocity=target_vel, TargetVelocity(vin=received_daf_object.vehicle_identification_number, target_velocity=target_vel,
timestamp=datetime.now()))) timestamp=datetime.utcnow())))
def handle_tl_state_receive(self, msg): def handle_tl_state_receive(self, msg):
""" """
@ -164,3 +124,55 @@ class Orchestrator:
self.tls[tl_state.tlid]['color'] = tl_state.color self.tls[tl_state.tlid]['color'] = tl_state.color
self.tls[tl_state.tlid]['last_switch'] = tl_state.last_switch self.tls[tl_state.tlid]['last_switch'] = tl_state.last_switch
print(tl_state) print(tl_state)
def _compute_velocity(self, traffic_lights_geo, current_vel):
target_vel = 130 * SCALING
print('Nearest traffic lights: {}'.format(traffic_lights_geo['cursor']))
for traffic_light in traffic_lights_geo['cursor']:
# Should only ever contain one traffic light (the next in line)
tl_id = traffic_light['id']
distance = traffic_light['calculatedRange']
switching_time = self.tls[tl_id]['switching_time'] / float(SCALING)
# Time until next switch must be scaled accordingly
next_switch_time = self.tls[tl_id]['last_switch'] + timedelta(seconds=switching_time)
time_until_switch = (next_switch_time - datetime.utcnow()).total_seconds()
print('Distance to TL: {}'.format(distance))
print('Time until switch in seconds: {}'.format(time_until_switch))
if self.tls[tl_id]['color'] is TrafficLightColor.RED:
speed_needed_max = (distance / float(time_until_switch)) * 3.6
if speed_needed_max < 130 * SCALING:
if current_vel < speed_needed_max:
target_vel = current_vel
else:
target_vel = floor(speed_needed_max)
else:
# Cannot make it on next green
i = 2
while speed_needed_max > 130 * SCALING:
next_green_phase_start = time_until_switch + switching_time * i
speed_needed_max = (distance / float(next_green_phase_start)) * 3.6
i = i + 2
target_vel = floor(speed_needed_max)
elif self.tls[tl_id]['color'] is TrafficLightColor.GREEN:
# Check if we can reach TL in time
speed_needed_min = (distance / float(time_until_switch)) * 3.6
if speed_needed_min < 130 * SCALING:
if current_vel < speed_needed_min:
target_vel = 130 * SCALING
else:
target_vel = current_vel
else:
i = 1
speed_needed_max = 132 * SCALING
while speed_needed_max > 130 * SCALING:
next_green_phase_start = time_until_switch + switching_time * i
speed_needed_max = (distance / float(next_green_phase_start)) * 3.6
i = i + 2
target_vel = floor(speed_needed_max)
else:
print('Unknown Traffic Light Color!')
return target_vel

View File

@ -0,0 +1,54 @@
import datetime
import unittest
from unittest.mock import patch
from dse_shared_libs.mock.response import MyResponse
from dse_shared_libs.traffic_light_color import TrafficLightColor
from orchestrator import Orchestrator
class TestOrchestrator(unittest.TestCase):
def setUp(self) -> None:
self.timestamp = datetime.datetime.utcnow()
with patch('requests.sessions.Session.get', MyResponse):
self.orc = Orchestrator()
def test_full_speed_if_nothing_in_range(self):
tl_geo = {'cursor': []}
current_vel = 55.0
target_vel = self.orc._compute_velocity(tl_geo, current_vel)
self.assertEqual(130, target_vel)
def test_keep_speed_if_far_away_and_green(self):
self.orc.tls = {'1': {'color': TrafficLightColor.GREEN, 'switching_time': 1000, 'last_switch': self.timestamp}}
tl_geo = {'cursor': [
{'id': '1', 'calculatedRange': 1000}
]}
current_vel = 55.0
target_vel = self.orc._compute_velocity(tl_geo, current_vel)
self.assertEqual(current_vel, target_vel)
def test_slow_down_if_passing_RED_not_possible(self):
self.orc.tls = {'1': {'color': TrafficLightColor.RED, 'switching_time': 100000, 'last_switch': self.timestamp}}
tl_geo = {'cursor': [
{'id': '1', 'calculatedRange': 1}
]}
current_vel = 130.0
target_vel = self.orc._compute_velocity(tl_geo, current_vel)
self.assertNotEqual(current_vel, target_vel)
self.assertEqual(0, target_vel)
def test_adjust_speed_to_get_over_on_green_if_currently_red(self):
self.orc.tls = {'1': {'color': TrafficLightColor.RED, 'switching_time': 100, 'last_switch': self.timestamp}}
tl_geo = {'cursor': [
{'id': '1', 'calculatedRange': 1000}
]}
current_vel = 130.0
target_vel = self.orc._compute_velocity(tl_geo, current_vel)
self.assertNotEqual(current_vel, target_vel)
self.assertEqual(36.0, target_vel)

View File

@ -0,0 +1,10 @@
class MyDate:
timestamp = None
@classmethod
def set_timestamp(cls, timestamp):
cls.timestamp = timestamp
@classmethod
def utcnow(cls):
return cls.timestamp

View File

@ -0,0 +1,43 @@
class MyQueue:
@property
def queue(self):
return None
class MyMethod:
method = MyQueue()
class MyChannel:
@staticmethod
def exchange_declare(*args, **kwargs):
return None
@staticmethod
def queue_declare(*args, **kwargs):
return MyMethod
@staticmethod
def queue_bind(*args, **kwargs):
return None
@staticmethod
def basic_consume(*args, **kwargs):
return None
@staticmethod
def basic_publish(*args, **kwargs):
return None
@staticmethod
def start_consuming(*args, **kwargs):
return None
class MyBlockingConnection:
def __init__(self, *args, **kwargs):
...
@staticmethod
def channel():
return MyChannel()

View File

@ -0,0 +1,7 @@
class MyResponse:
def __init__(self, *args, **kwargs):
...
@staticmethod
def json(*args, **kwargs):
return {'cursor': []}

View File

@ -1,4 +1,4 @@
flask flask==1.1.4
Flask-Cors Flask-Cors
requests requests
Flask-PyMongo Flask-PyMongo

View File

@ -5,7 +5,7 @@ from bson import json_util
from flask import Flask, jsonify from flask import Flask, jsonify
from flask_cors import CORS from flask_cors import CORS
from flask import request from flask import request
import json; import json
app = Flask(__name__) app = Flask(__name__)
CORS(app) CORS(app)

View File

@ -1,6 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: scaling-configmap
data:
scaling: "1"

View File

@ -0,0 +1,19 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: simulation-parameters-configmap
data:
DSE2021_SCALING: "2"
DSE2021_NCE: "1"
DSE2021_CAR1_SV: "130"
DSE2021_CAR2_SV: "130"
DSE2021_CAR3_SV: "130"
DSE2021_CAR1_SD: "300"
DSE2021_CAR2_SD: "500"
DSE2021_CAR3_SD: "400"
DSE2021_CAR1_ST: "10"
DSE2021_CAR2_ST: "15"
DSE2021_CAR3_ST: "25"
DSE2021_TL1_R: "2000"
DSE2021_TL2_R: "800"
DSE2021_TL3_R: "1000"

View File

@ -23,11 +23,11 @@ spec:
- containerPort: 80 - containerPort: 80
resources: {} resources: {}
env: env:
- name: SCALING - name: DSE2021_SCALING
valueFrom: valueFrom:
configMapKeyRef: configMapKeyRef:
name: scaling-configmap name: simulation-parameters-configmap
key: scaling key: DSE2021_SCALING
restartPolicy: Always restartPolicy: Always
serviceAccountName: "" serviceAccountName: ""
volumes: null volumes: null

View File

@ -23,11 +23,71 @@ spec:
- containerPort: 5002 - containerPort: 5002
resources: {} resources: {}
env: env:
- name: SCALING - name: DSE2021_SCALING
valueFrom: valueFrom:
configMapKeyRef: configMapKeyRef:
name: scaling-configmap name: simulation-parameters-configmap
key: scaling key: DSE2021_SCALING
- name: DSE2021_CAR1_SV
valueFrom:
configMapKeyRef:
name: simulation-parameters-configmap
key: DSE2021_CAR1_SV
- name: DSE2021_CAR2_SV
valueFrom:
configMapKeyRef:
name: simulation-parameters-configmap
key: DSE2021_CAR2_SV
- name: DSE2021_CAR3_SV
valueFrom:
configMapKeyRef:
name: simulation-parameters-configmap
key: DSE2021_CAR3_SV
- name: DSE2021_CAR1_SD
valueFrom:
configMapKeyRef:
name: simulation-parameters-configmap
key: DSE2021_CAR1_SD
- name: DSE2021_CAR2_SD
valueFrom:
configMapKeyRef:
name: simulation-parameters-configmap
key: DSE2021_CAR2_SD
- name: DSE2021_CAR3_SD
valueFrom:
configMapKeyRef:
name: simulation-parameters-configmap
key: DSE2021_CAR3_SD
- name: DSE2021_CAR1_ST
valueFrom:
configMapKeyRef:
name: simulation-parameters-configmap
key: DSE2021_CAR1_ST
- name: DSE2021_CAR2_ST
valueFrom:
configMapKeyRef:
name: simulation-parameters-configmap
key: DSE2021_CAR2_ST
- name: DSE2021_CAR3_ST
valueFrom:
configMapKeyRef:
name: simulation-parameters-configmap
key: DSE2021_CAR3_ST
- name: DSE2021_TL1_R
valueFrom:
configMapKeyRef:
name: simulation-parameters-configmap
key: DSE2021_TL1_R
- name: DSE2021_TL2_R
valueFrom:
configMapKeyRef:
name: simulation-parameters-configmap
key: DSE2021_TL2_R
- name: DSE2021_TL3_R
valueFrom:
configMapKeyRef:
name: simulation-parameters-configmap
key: DSE2021_TL3_R
restartPolicy: Always restartPolicy: Always
serviceAccountName: "" serviceAccountName: ""
volumes: null volumes: null

View File

@ -23,11 +23,11 @@ spec:
- containerPort: 5001 - containerPort: 5001
resources: {} resources: {}
env: env:
- name: SCALING - name: DSE2021_SCALING
valueFrom: valueFrom:
configMapKeyRef: configMapKeyRef:
name: scaling-configmap name: simulation-parameters-configmap
key: scaling key: DSE2021_SCALING
restartPolicy: Always restartPolicy: Always
serviceAccountName: "" serviceAccountName: ""
volumes: null volumes: null

View File

@ -21,11 +21,16 @@ spec:
name: ifeed name: ifeed
resources: {} resources: {}
env: env:
- name: SCALING - name: DSE2021_SCALING
valueFrom: valueFrom:
configMapKeyRef: configMapKeyRef:
name: scaling-configmap name: simulation-parameters-configmap
key: scaling key: DSE2021_SCALING
- name: DSE2021_NCE
valueFrom:
configMapKeyRef:
name: simulation-parameters-configmap
key: DSE2021_NCE
restartPolicy: Always restartPolicy: Always
serviceAccountName: "" serviceAccountName: ""
volumes: null volumes: null

View File

@ -21,11 +21,11 @@ spec:
name: orchestration name: orchestration
resources: {} resources: {}
env: env:
- name: SCALING - name: DSE2021_SCALING
valueFrom: valueFrom:
configMapKeyRef: configMapKeyRef:
name: scaling-configmap name: simulation-parameters-configmap
key: scaling key: DSE2021_SCALING
restartPolicy: Always restartPolicy: Always
serviceAccountName: "" serviceAccountName: ""
volumes: null volumes: null

View File

@ -23,11 +23,11 @@ spec:
- containerPort: 5004 - containerPort: 5004
resources: {} resources: {}
env: env:
- name: SCALING - name: DSE2021_SCALING
valueFrom: valueFrom:
configMapKeyRef: configMapKeyRef:
name: scaling-configmap name: simulation-parameters-configmap
key: scaling key: DSE2021_SCALING
restartPolicy: Always restartPolicy: Always
serviceAccountName: "" serviceAccountName: ""
volumes: null volumes: null

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB