Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/game/hiking.py
169674 views
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
4
# Copyright (C) 2010-2025 German Aerospace Center (DLR) and others.
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 hiking.py
16
# @author Jakob Erdmann
17
# @date 2017-06-12
18
19
"""
20
This script runs an aribtrary sumo simulation and controls the specified person
21
via keyboard input
22
"""
23
from __future__ import absolute_import
24
from __future__ import print_function
25
import os
26
import sys
27
import threading
28
import argparse
29
30
if sys.version_info.major == 3:
31
import queue as Queue
32
from tkinter import Button, Frame, Tk
33
else:
34
import Queue
35
from Tkinter import Button, Frame, Tk
36
37
try:
38
sys.path.append(os.path.join(os.environ.get("SUMO_HOME",
39
os.path.join(os.path.dirname(__file__), '..')), "tools"))
40
from sumolib import checkBinary # noqa
41
import traci # noqa
42
except ImportError:
43
sys.exit(
44
"please declare environment variable 'SUMO_HOME' as the root directory of your sumo installation " +
45
"(it should contain folders 'bin', 'tools' and 'docs')")
46
47
try:
48
import autopy # noqa
49
except ImportError:
50
sys.stderr.write("autopy not installed. Can only use keyboard control.")
51
autopy = None
52
53
54
eventQueue = Queue.Queue()
55
TS = 0.1
56
VERBOSE = False
57
MAX_STEER_ANGLE = 5
58
MIN_SPEED = -5
59
MAX_OFFROAD_SPEED = 7
60
OFFROAD_DECEL_TIME = 2
61
# autopy = None # disable mouse control
62
63
64
def leftKey(event):
65
eventQueue.put(('left', None))
66
if VERBOSE:
67
print("Left key pressed")
68
69
70
def rightKey(event):
71
eventQueue.put(('right', None))
72
if VERBOSE:
73
print("Right key pressed")
74
75
76
def upKey(event):
77
eventQueue.put(('up', None))
78
if VERBOSE:
79
print("Up key pressed")
80
81
82
def downKey(event):
83
eventQueue.put(('down', None))
84
if VERBOSE:
85
print("Down key pressed")
86
87
88
def mouseControl(master, speed, steerAngle, accel=2.6, decel=4.5):
89
try:
90
centerX = master.winfo_screenwidth() / 2.0
91
centerY = master.winfo_screenheight() / 2.0
92
x, y = autopy.mouse.location()
93
dx = (x - centerX) / centerX
94
dy = (y - centerY) / centerY
95
if dy < 0:
96
speed -= dy * TS * accel
97
else:
98
speed -= dy * TS * decel
99
steerAngle = MAX_STEER_ANGLE * dx
100
except Exception: # as e:
101
# print(e)
102
pass
103
return speed, steerAngle
104
105
106
class HikingClient:
107
108
"""
109
Launch the main part of the GUI and the worker thread. periodicCall and
110
endApplication could reside in the GUI part, but putting them here
111
means that you have all the thread controls in a single place.
112
"""
113
114
def __init__(self, master, sumocfg, egoID):
115
self.master = master
116
self.sumocfg = sumocfg
117
self.egoID = egoID
118
self.running = True
119
120
self.thread = threading.Thread(target=self.workerThread)
121
self.thread.start()
122
# Start the periodic call in the GUI to see if it can be closed
123
self.periodicCall()
124
125
def periodicCall(self):
126
if not self.running:
127
sys.exit(1)
128
self.master.after(100, self.periodicCall)
129
130
def workerThread(self):
131
try:
132
traci.start([checkBinary("sumo-gui"), "-c", self.sumocfg,
133
# "-C", "debug.sumocfg",
134
"--step-length", str(TS)])
135
# steal focus for keyboard input after sumo-gui has loaded
136
# self.master.focus_force() # not working on all platforms
137
# make sure ego person is loaded
138
traci.simulationStep()
139
x, y = traci.person.getPosition(self.egoID)
140
# traci.gui.trackVehicle(traci.gui.DEFAULT_VIEW, self.egoID)
141
while True: # traci.simulation.getMinExpectedNumber() > 0:
142
try:
143
while eventQueue.qsize():
144
try:
145
msg = eventQueue.get(0)
146
if len(msg) == 1:
147
direction = msg
148
val = None
149
else:
150
direction, val = msg
151
152
if direction == 'up':
153
y += 1
154
if direction == 'down':
155
y -= 1
156
if direction == 'left':
157
x -= 1
158
if direction == 'right':
159
x += 1
160
except Queue.Empty:
161
pass
162
# if autopy:
163
# speed, steerAngle = mouseControl(self.master, speed, steerAngle)
164
165
# move person
166
traci.person.moveToXY(self.egoID, "dummy", x, y, keepRoute=2)
167
traci.person.setSpeed(self.egoID, 0) # no automatic walking
168
traci.simulationStep()
169
except traci.TraCIException:
170
pass
171
traci.close()
172
except traci.FatalTraCIError:
173
raise
174
self.running = False
175
176
177
def main(sumocfg="hiking/hiking.sumocfg", egoID="ego"):
178
root = Tk()
179
root.geometry('180x100+0+0')
180
frame = Frame(root)
181
Button(frame, text="Click here.\nControl with arrow keys").grid(row=0)
182
root.bind('<Left>', leftKey)
183
root.bind('<Right>', rightKey)
184
root.bind('<Up>', upKey)
185
root.bind('<Down>', downKey)
186
187
root.winfo_screenwidth()
188
root.winfo_screenheight()
189
190
frame.pack()
191
192
HikingClient(root, sumocfg, egoID)
193
root.mainloop()
194
195
196
if len(sys.argv) < 3:
197
parser = argparse.ArgumentParser()
198
parser.add_argument('--sumocfg', default="hiking/hiking.sumocfg", help=".sumocfg file path", required=False)
199
parser.add_argument('--ego', default="ego", help="vehicle ego id", required=False)
200
args = parser.parse_args()
201
main(args.sumocfg, args.ego)
202
else:
203
print("hiking.py --sumocfg=<sumocfg> [--ego=<egoID>]")
204
205