Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/contributed/sumopy/coremodules/simulation/simplaconfig.py
169689 views
1
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
2
# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.
3
# SUMOPy module
4
# Copyright (C) 2012-2021 University of Bologna - DICAM
5
# This program and the accompanying materials are made available under the
6
# terms of the Eclipse Public License 2.0 which is available at
7
# https://www.eclipse.org/legal/epl-2.0/
8
# This Source Code may also be made available under the following Secondary
9
# Licenses when the conditions for such availability set forth in the Eclipse
10
# Public License 2.0 are satisfied: GNU General Public License, version 2
11
# or later which is available at
12
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
13
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
14
15
# @file simplaconfig.py
16
# @author Joerg Schweizer
17
# @date 2012
18
19
"""
20
simpla is a configurable, platooning plugin for the TraCI Python client. It manages the spontaneous formation of vehicle platoons and allows you to define specific behavior for vehicles that travel inside a platoon.
21
22
This is achieved by defining additional vehicle types which represent platooning modes, and by providing information, which type (mode) to use for normal, solitary travel, and which one to use when platooning is activated. Further, 'catch-up' modes may be specified, which are used when a potential platooning partner is farther ahead downstream.
23
24
For platooning up to four operational modes may be specified apart from the normal traveling mode (see section Configuration for the details):
25
26
* Platoon leader mode (parametrization of a vehicle driving at the front of a platoon)
27
* Platoon follower mode (parametrization of a vehicle driving behind another vehicle within a platoon)
28
* Platoon catch-up mode (parametrization of a vehicle in range of a platoon, which is feasible for joining)
29
* Platoon catch-up follower mode (parametrization of a vehicle traveling in a platoon, with a platoon leader in catchup mode)
30
"""
31
import os
32
import sys
33
import numpy as np
34
# print 'module simplaconfig SUMO_HOME',os.environ['SUMO_HOME'],'SUMO_HOME' in os.environ
35
try:
36
if 'SUMO_HOME' in os.environ:
37
tools = os.path.join(os.environ['SUMO_HOME'], 'tools')
38
sys.path.append(tools)
39
else:
40
print("please declare environment variable 'SUMO_HOME'")
41
42
import simpla
43
44
except:
45
print 'WARNING: No module simpla in syspath. Please provide SUMO_HOME.'
46
47
simpla = None
48
49
# local simpla
50
#import simpla
51
52
from agilepy.lib_base.processes import Process
53
#from xml.sax import saxutils, parse, handler
54
55
import agilepy.lib_base.classman as cm
56
import agilepy.lib_base.arrayman as am
57
import agilepy.lib_base.xmlman as xm
58
from coremodules.demand.demandbase import DemandobjMixin
59
60
61
class SimplaConfig(DemandobjMixin, cm.BaseObjman):
62
def __init__(self, simulation,
63
name='Simple Platooning configuration',
64
info='Configuration of simple platooning service. Simpla is a service that allows to crate platoons in any simulation. The platooning option must be enabled in the Traci micro simulation.',
65
xmltag='configuration',
66
version=0.2,
67
**kwargs):
68
# print 'SimplaConfig.__init__',name
69
70
self._init_objman(ident='simplaconfig', parent=simulation,
71
name=name, info=info, xmltag=xmltag,
72
version=0.3,
73
**kwargs)
74
75
attrsman = self.set_attrsman(cm.Attrsman(self))
76
self._init_attributes()
77
self._init_constants()
78
79
# make PRTservice a demand object as link
80
self.get_scenario().demand.add_demandobject(obj=self)
81
82
def get_scenario(self):
83
return self.parent.parent
84
85
def _init_constants(self):
86
self._typemap = {}
87
self.get_attrsman().do_not_save_attrs(['_typemap', ])
88
89
def _init_attributes(self):
90
# print 'PrtService._init_attributes',hasattr(self,'prttransit')
91
attrsman = self.get_attrsman()
92
scenario = self.get_scenario()
93
94
is_update = False
95
if not hasattr(self, '_version'):
96
# crazy simpla has no version???
97
is_update = True
98
self._version = 0.0
99
100
elif self.get_version() < 0.2:
101
is_update = True
102
103
if is_update:
104
# there were config errors in the 0.0 version
105
attrsman.delete('tau_follower')
106
if hasattr(self, 'dist_min_follower'):
107
attrsman.delete('dist_min_follower')
108
if hasattr(self, 'sigma_follower'):
109
attrsman.delete('sigma_follower')
110
111
if self.get_version() < 0.3:
112
# this would remove _private entirely
113
# self.is_enabled.del_groupname('_private')
114
attrsman.delete('is_enabled')
115
116
self.is_enabled = attrsman.add(cm.AttrConf('is_enabled', False,
117
groupnames=['options'],
118
name='Enabled',
119
info="""Enable platooning""",
120
), is_prepend=True)
121
122
# here we ged classes not vehicle type
123
# specific vehicle type within a class will be generated later
124
# these are the mode choices which have a defined vehicle type
125
modechoices = scenario.demand.vtypes.get_modechoices()
126
127
# print ' modechoices',modechoices
128
129
self.ids_platoonmodes = attrsman.add(cm.ListConf('ids_platoonmodes', [scenario.net.modes.get_id_mode('passenger')],
130
groupnames=['options'],
131
choices=modechoices,
132
name='Platooned modes',
133
info="""Transport modes to platoon.
134
A vehicle is controlled by simpla if its vehicle type ID is part of the given mode IDs.
135
""",
136
#xmltag = 'vehicleSelectors',
137
))
138
139
# self.testlist = attrsman.add(cm.ListConf( 'testlist', ['1','dd','cvc'],
140
# groupnames = ['state'],
141
# choices = ['1','dd','cvc','dddd','eeeee'],
142
# perm='rw',
143
# is_save = True,
144
# name = 'Test list',
145
# info = 'This is a test list',
146
# xmltag = 'testList',
147
# ))
148
149
self.time_update = attrsman.add(cm.AttrConf('time_update', 1.0,
150
groupnames=['options'],
151
name='Man. update time',
152
info="Update time for vehicle management.",
153
unit='s',
154
xmltag='controlRate',
155
))
156
157
self.platoongap_max = attrsman.add(cm.AttrConf('platoongap_max', 15.0,
158
groupnames=['options'],
159
name='Max. platoon gap',
160
info="""Gap (in m.) below which vehicles are considered as a platoon (if their vType parameters allow safe traveling for the actual situation).""",
161
unit='m',
162
xmltag='maxPlatoonGap',
163
))
164
165
self.time_platoon_splitup = attrsman.add(cm.AttrConf('time_platoon_splitup', 3.0,
166
groupnames=['options'],
167
name='Platoon splitup time',
168
info="Time until a vehicle which maintains a distance larger than max Platoon Gap from its leader within the platoon (or travels on a different lane or behind a vehicle not belonging to its platoon) is split off. Defaults to 3.0 secs.",
169
unit='s',
170
xmltag='platoonSplitTime',
171
))
172
173
self.dist_catchup = attrsman.add(cm.AttrConf('dist_catchup', 100.0,
174
groupnames=['options'],
175
name='catchup distance',
176
info="""If a catch-up mode was defined, vehicles switch their type to the corresponding catch-up vehicle type as soon as a platoon is ahead closer than the given value (in m.).""",
177
unit='m',
178
xmltag='catchupDist',
179
))
180
181
self.factor_switch_impatience = attrsman.add(cm.AttrConf('factor_switch_impatience', -1.0,
182
groupnames=['options'],
183
name='switch impatience factor ',
184
info="""The switch impatience factor determines the magnitude of the effect that an increasing waiting time for a mode switch (due to safety constraints) has on the active speed factor of a vehicle. The active speed factor is calculated as activeSpeedFactor = modeSpecificSpeedFactor/(1+impatienceFactor*waitingTime). The default value for the switch impatience factor is 0.1. Providing values <= 0 will deactivate the impatience mechanism.""",
185
xmltag='switchImpatienceFactor',
186
))
187
188
# self.lanechangemode_original = attrsman.add(cm.AttrConf( 'lanechangemode_original', 594,
189
# groupnames = ['options','lanechange-modes'],
190
# name = 'Lane-change mode original',
191
# info = """Specifies the binary lane-change mode to be used as original.""",
192
# ))
193
194
self.lanechangemode_leader = attrsman.add(cm.AttrConf('lanechangemode_leader', 594,
195
groupnames=['options', 'lanechange-modes'],
196
name='Lane-change mode leader',
197
info="""Specifies the binary lane-change mode to be used as leader.""",
198
))
199
self.lanechangemode_follower = attrsman.add(cm.AttrConf('lanechangemode_follower', 514,
200
groupnames=['options', 'lanechange-modes'],
201
name='Lane-change mode follower',
202
info="""Specifies the binary lane-change mode to be used as follower.""",
203
))
204
self.lanechangemode_catchup = attrsman.add(cm.AttrConf('lanechangemode_catchup', 514,
205
groupnames=['options', 'lanechange-modes'],
206
name='Lane-change mode catchup',
207
info="""Specifies the binary lane-change mode to be used as catchup.""",
208
))
209
210
self.lanechangemode_catchup_follower = attrsman.add(cm.AttrConf('lanechangemode_catchup_follower', 514,
211
groupnames=['options', 'lanechange-modes'],
212
name='Lane-change mode catchup-follower',
213
info="""Specifies the binary lane-change mode to be used as catchup-follower.""",
214
))
215
216
self.speedfactor_original = attrsman.add(cm.AttrConf('speedfactor_original', 1.0,
217
groupnames=['options', 'speedfactors'],
218
name='Speed factor original',
219
info="""Specifies the speed factor to be used as original.""",
220
))
221
self.speedfactor_leader = attrsman.add(cm.AttrConf('speedfactor_leader', 1.0,
222
groupnames=['options', 'speedfactors'],
223
name='Speed factor leader',
224
info="""Specifies the speed factor to be used as leader.""",
225
))
226
self.speedfactor_follower = attrsman.add(cm.AttrConf('speedfactor_follower', 2.0,
227
groupnames=['options', 'speedfactors'],
228
name='Speed factor follower',
229
info="""Specifies the speed factor to be used as follower. Must be greater than one.""",
230
))
231
self.speedfactor_catchup = attrsman.add(cm.AttrConf('speedfactor_catchup', 2.5,
232
groupnames=['options', 'speedfactors'],
233
name='Speed factor catchup',
234
info="""Specifies the speed factor to be used as catchup. Must be greater than one.""",
235
))
236
self.speedfactor_catchup_follower = attrsman.add(cm.AttrConf('speedfactor_catchup_follower', 3.0,
237
groupnames=['options', 'speedfactors'],
238
name='Speed factor catchup follower',
239
info="""Specifies the speed factor to be used as follower. Must be greater than one.""",
240
))
241
242
self.accelfactor_follower = attrsman.add(cm.AttrConf('accelfactor_follower', 1.0,
243
groupnames=['options', 'dynamics'],
244
name='Accel. factor follower',
245
info="""Specifies the acceleration factor to be used as follower.""",
246
))
247
248
self.decelfactor_follower = attrsman.add(cm.AttrConf('decelfactor_follower', 1.0,
249
groupnames=['options', 'dynamics'],
250
name='Decel. factor follower',
251
info="""Specifies the deceleration factor to be used as follower.""",
252
))
253
254
self.tau_follower = attrsman.add(cm.AttrConf('tau_follower', 0.2,
255
groupnames=['options', 'dynamics'],
256
name='Reaction time follower',
257
info="Follower's reaction time.",
258
unit='s',
259
))
260
261
self.dist_min_follower = attrsman.add(cm.AttrConf('dist_min_follower', 0.3,
262
groupnames=['options', 'dynamics'],
263
name='Min. gap follower',
264
info="Follower's reaction time.",
265
unit='m',
266
))
267
268
self.sigma_follower = attrsman.add(cm.AttrConf('sigma_follower', 0.0,
269
groupnames=['options', 'dynamics'],
270
name='Driver follower',
271
info="Follower's driver imperfection in driving (between 0 and 1). Used only in follower models SUMOKrauss, SKOrig.",
272
unit='s',
273
))
274
275
self.is_keep_vtypes = attrsman.add(cm.AttrConf('is_keep_vtypes', False,
276
groupnames=['options', 'misc'],
277
name='Keep platoon vtypes',
278
info="Keep platoon specific vtypes after simulation in the vehicle type database. This for reviewing purpose and not required.",
279
))
280
self.set_version(0.3)
281
282
def enable(self, is_enabled):
283
"""Enables simulation with platoons. Must be called before preparing simulation."""
284
self.is_enabled = is_enabled
285
286
def prepare_sim(self):
287
if self.is_enabled:
288
# self.add_vtypes()# done in get_writexmlinfo means in get_vtypes()
289
self.export_config()
290
print 'Simplaconfig.prepare_sim', self.configfilepath, self.is_enabled
291
simpla.load(self.configfilepath)
292
293
def finish_sim(self):
294
if self.is_enabled:
295
if not self.is_keep_vtypes:
296
self.del_vtypes()
297
298
def export_config(self):
299
self.configfilepath = self.parent.get_scenario().get_rootfilepath()+'.simpla.xml'
300
xm.write_obj_to_xml(self, self.configfilepath)
301
302
def write_xml(self, fd, indent=0):
303
"""
304
Write simpla xml config file
305
"""
306
print 'Simplaconfig.write_xml'
307
fd.write(xm.begin(self.xmltag, indent))
308
attrsman = self.get_attrsman()
309
vtypes = self.parent.get_scenario().demand.vtypes
310
ids_sumo_vtypes = vtypes.ids_sumo
311
# <controlRate value="0.5" />
312
# <maxPlatoonGap value="15.0" />
313
# <catchupDist value="100.0" />
314
# <switchImpatienceFactor value="0.1" />
315
# <platoonSplitTime value="3.0" />
316
# <lcMode original="597" leader="597" follower="514" catchup="514" catchupFollower="514" />
317
# <speedFactor original="1.0" leader="1.0" follower="2.0" catchup="2.5" catchupFollower="3.0" />
318
# <verbosity value="1" />
319
# <vTypeMap original="passenger1" leader="leaderVTypeID" follower="followerVTypeID" catchup="catchupVTypeID" catchupFollower="catchupFollowerVTypeID" />
320
321
#ids_plattypes = ['catchup','follower','original']
322
#ids_plattypes = self._typemap.keys()
323
#ids_vtypes_plat_sumo = []
324
# for id_mode in self.ids_platoonmodes:
325
# ids_vtype_sumo= ids_sumo_vtypes[vtypes.select_by_mode(id_mode=id_mode)]
326
# #print ' id_mode',id_mode,'ids_vtype',ids_vtype.tolist()
327
# for id_vtype_sumo in ids_vtype_sumo:
328
# if id_vtype in ids_plattypes
329
# #if id_vtype_sumo.split('_')[-1] not in plattypes:
330
# ids_vtypes_plat_sumo.append(id_vtype_sumo)
331
332
ids_vtypes_plat_sumo = ids_sumo_vtypes[self._typemap.keys()]
333
fd.write(xm.start('vehicleSelectors', indent+2))
334
fd.write(xm.arr('value', ids_vtypes_plat_sumo, sep=','))
335
fd.write(xm.stopit())
336
337
fd.write(xm.start('lcMode', indent+2))
338
fd.write(xm.num('leader', self.lanechangemode_leader))
339
fd.write(xm.num('follower', self.lanechangemode_follower))
340
fd.write(xm.num('catchup', self.lanechangemode_catchup))
341
fd.write(xm.num('catchupFollower', self.lanechangemode_catchup_follower))
342
fd.write(xm.stopit())
343
344
fd.write(xm.start('speedFactor', indent+2))
345
fd.write(xm.num('original', 1.0))
346
fd.write(xm.num('leader', self.speedfactor_leader))
347
fd.write(xm.num('follower', self.speedfactor_follower))
348
fd.write(xm.num('catchup', self.speedfactor_catchup))
349
fd.write(xm.num('catchupFollower', self.speedfactor_catchup_follower))
350
fd.write(xm.stopit())
351
352
for plattypes in self._typemap.values():
353
fd.write(xm.start('vTypeMap', indent+2))
354
for plattype, id_vtype in plattypes.iteritems():
355
fd.write(xm.num(plattype, ids_sumo_vtypes[id_vtype]))
356
fd.write(xm.stopit())
357
358
for attrconfig in attrsman.get_configs():
359
if attrconfig.xmltag is not None:
360
if (attrconfig.xmltag == 'switchImpatienceFactor') & (attrconfig.get_value() < 0):
361
pass
362
else:
363
fd.write(xm.start(attrconfig.xmltag, indent+2))
364
fd.write(xm.num('value', attrconfig.format_value()))
365
fd.write(xm.stopit())
366
367
fd.write(xm.end(self.xmltag, indent))
368
369
def add_vtypes(self):
370
"""
371
Add necessary vtypes.
372
This function is called before writing vtypes.
373
These vtypes should be deleted after the export.
374
"""
375
print 'Simplaconfig.add_vtypes'
376
self._typemap = {}
377
vtypes = self.get_scenario().demand.vtypes
378
for id_mode in self.ids_platoonmodes:
379
ids_vtype = vtypes.select_by_mode(id_mode=id_mode)
380
381
# original is not created but points to the
382
#self._add_vtypes(vtypes, ids_vtype, 'original')
383
plattype_original = 'original'
384
for _id in ids_vtype:
385
self._typemap[_id] = {plattype_original: _id}
386
387
co = 0.1 # default coloroffset
388
cf = 1.2 # default colorfactor
389
self._add_vtypes(vtypes, ids_vtype, 'leader',
390
coloroffset=np.array([co, 0, 0, 1], dtype=np.float32),
391
colorfactor=np.array([cf, 0, 0, 1], dtype=np.float32),
392
carfollowermodel='ACC',
393
)
394
395
self._add_vtypes(vtypes, ids_vtype, 'follower',
396
accelfactor=self.accelfactor_follower,
397
decelfactor=self.decelfactor_follower,
398
tau=self.tau_follower,
399
sigma=self.sigma_follower,
400
dist_min=self.dist_min_follower,
401
coloroffset=np.array([0, co, 0, 1], dtype=np.float32),
402
colorfactor=np.array([0, cf, 0, 1], dtype=np.float32),
403
carfollowermodel='CACC',
404
)
405
406
self._add_vtypes(vtypes, ids_vtype, 'catchup',
407
accelfactor=self.accelfactor_follower,
408
decelfactor=self.decelfactor_follower,
409
tau=self.tau_follower,
410
sigma=self.sigma_follower,
411
dist_min=self.dist_min_follower,
412
coloroffset=np.array([co, co, co, 1], dtype=np.float32),
413
colorfactor=np.array([0, 0, cf, 1], dtype=np.float32),
414
carfollowermodel='ACC',
415
)
416
417
self._add_vtypes(vtypes, ids_vtype, 'catchupFollower',
418
accelfactor=self.accelfactor_follower,
419
decelfactor=self.decelfactor_follower,
420
tau=self.tau_follower,
421
sigma=self.sigma_follower,
422
dist_min=self.dist_min_follower,
423
coloroffset=np.array([0, co, 0, 1], dtype=np.float32),
424
colorfactor=np.array([0, cf, cf, 1], dtype=np.float32),
425
carfollowermodel='CACC',
426
)
427
428
def get_vtypes(self):
429
"""
430
Returns used vtypes for export
431
"""
432
# ATTENTION: here the platoon vtypes are actually added
433
if not self.is_enabled:
434
return []
435
436
print 'Simpla.get_vtypes'
437
plattype_original = 'original'
438
# add vtypes for platooning here
439
self.add_vtypes()
440
# here we return only the additional vtypes
441
ids_vtypes_plat = []
442
for plattypes in self._typemap.values():
443
for plattype, id_vtype in plattypes.iteritems():
444
if plattype != plattype_original:
445
ids_vtypes_plat.append(id_vtype)
446
# print ' ids_vtypes_plat',ids_vtypes_plat
447
return ids_vtypes_plat
448
449
def del_vtypes(self):
450
"""Delete all necessary vtypes for platooning from vtype database."""
451
452
vtypes = self.get_scenario().demand.vtypes
453
plattype_original = 'original'
454
ids_vtypes_plat = []
455
for plattypes in self._typemap.values():
456
for plattype, id_vtype in plattypes.iteritems():
457
if plattype != plattype_original:
458
ids_vtypes_plat.append(id_vtype)
459
460
print 'del_vtypes', ids_vtypes_plat
461
vtypes.del_rows(ids_vtypes_plat)
462
self._typemap = {}
463
464
def _add_vtypes(self, vtypes, ids, plattype,
465
accelfactor=1.0, decelfactor=1.0,
466
tau=np.nan, sigma=np.nan, dist_min=np.nan,
467
coloroffset=np.zeros(4, np.float32),
468
colorfactor=np.ones(4, np.float32),
469
carfollowermodel='Krauss'):
470
print '_add_vtypes', ids, plattype
471
n = len(ids)
472
ids_new = vtypes.add_rows(n=len(ids))
473
for colconfig in vtypes.get_attrsman()._colconfigs:
474
values = colconfig[ids].copy()
475
476
attrname = colconfig.attrname
477
if attrname == 'ids_sumo':
478
values += '_'+plattype
479
elif attrname == 'accels':
480
values *= accelfactor
481
elif attrname == 'decels':
482
values *= decelfactor
483
484
elif attrname == 'colors':
485
values = np.clip((values+coloroffset)*colorfactor, 0, 1)
486
487
elif (not np.isnan(tau)) & (attrname == 'taus'):
488
values = np.ones(len(values), dtype=np.float32)*tau
489
490
elif (not np.isnan(sigma)) & (attrname == 'sigmas'):
491
values = np.ones(len(values), dtype=np.float32)*sigma
492
493
colconfig.set(ids_new, values=values)
494
495
# adjust emergency breake deceleration to
496
# comfort deceleration
497
# this reduces headway
498
vtypes.decels_apparent[ids_new] = vtypes.decels[ids_new]+0.1
499
vtypes.decels_emergency[ids_new] = vtypes.decels[ids_new]+0.1
500
# update typemap database
501
for _id, _id_new in zip(ids, ids_new):
502
if self._typemap.has_key(_id):
503
self._typemap[_id][plattype] = _id_new
504
else:
505
self._typemap[_id] = {plattype: _id_new}
506
507
return ids_new
508
509