Project

General

Profile

Revision 01f09975

ID01f099754e133bbee3cf40762d55c0db11fca2e4
Parent daf6a575
Child 9a4d8398

Added by Yuyang Guo about 11 years ago

Partially done GUI rewriting GUI
now can only add and kill scouts freely but can do nothing else

View differences:

scout/scoutsim/GUI.py
1
#!/usr/bin/python
2

  
3
# Behavior GUI
4

  
5
# shell subprocess libs
6
import subprocess
7
import shlex  #for converting string commands to tokens
8

  
9
# GUI libs
10
import wx
11
import wx.lib.intctrl
12
import wx.lib.agw.floatspin
13

  
14
# not sure why these 2 are here
15
import string
16
import signal
17

  
18
# ros imports for spawning and killing scout
19
import rospy
20
import roslib
21
roslib.load_manifest("scoutsim")
22

  
23
# scoutsim imports
24
from scoutsim.srv import *
25

  
26
from collections import defaultdict
27

  
28
# each scout is represented by this class
29
class Scout(object):
30
    numOfScouts = 0 # class variable keeping track of scouts
31
    
32
    def __init__(self, x=0, y=0, theta=0, name=u"",
33
                       Scouts=None, oninit = False):
34
        print (len(name))
35
        Scout.numOfScouts += 1 # reverted if not successful
36
        if len(name) == 0:
37
            # automatically give name according to numOfScouts
38
            name = self.autoNameGen(Scouts)
39
        # set vars
40
        self.name = name
41
        self.behavior = "chilling"
42
        self.process =  None# used to keep track of all processes
43
                        # related to this scout  
44
        self.valid = False
45
        # these vars are right now just the original position
46
        # but when ODOMETRY is done, we could actually use them
47
        self.x, self.y = x, y 
48
        self.theta = theta
49
        
50
        # spawn the scout if it is not scout1 (automatically spawned)
51
        if (not oninit): 
52
            if (self.SpawnInSimulator()):
53
                # spawned correctly
54
                self.valid = True
55
            else:
56
                Scout.numOfScouts -= 1;
57
        
58

  
59
    def autoNameGen(self, Scouts):
60
        i = 1
61
        while (True):
62
            if not (("scout%d"%i) in Scouts):
63
                return "scout%d"%i
64
            i+=1
65

  
66

  
67
        # update the classvariable
68
        
69

  
70
    def SpawnInSimulator(self):
71
        print "trying to spawn scout!!!"
72
        try:
73
            # ros spawn routine
74
            rospy.wait_for_service('/spawn');
75
            service = rospy.ServiceProxy('/spawn', Spawn);
76
            response = service(self.x, self.y, self.theta, self.name)
77
            return True
78
        except rospy.ServiceException as Error:
79
            print "things are bad!!!"
80
            print Error
81
            return False
82
    
83
    def changeBehavior(self, behavior):
84
        self.behavior = behavior
85

  
86
        # WARNING: Check this but ROS kills the old behavior for us
87
            # kill the old behavior
88
#        if self.process != None:
89
#            self.process.terminate() #TODO: this kills the process
90
#                                     #      but maybe not the rosnode
91
#                                     #      change to "rosnode kill" instead
92
#        # make sure the old behavior is terminated before we run the new one
93
#        self.process.wait()
94
        
95
        # do rosprocess calls for new behavior
96
        roscommand = shlex.split("rosrun libscout libscout %s %s"%
97
                                            (self.name, self.behavior))
98
        subprocess.Popen(roscommand, shell=False)
99

  
100
    def killSelf(self):
101
        # terminate its current behavior
102
        if self.process != None:
103
            self.process.terminate() # TODO: same here, try "rosnode kill"
104
            self.process.wait()
105
        # ros call to kill scout in simulator
106
        try:
107
            rospy.wait_for_service("/kill")
108
            service = rospy.ServiceProxy("/kill", Kill)
109
            response = service(self.name)
110
            Scout.numOfScouts -= 1
111
            self.valid = False
112
        except rospy.ServiceException, e:
113
            print "warning: kill scout unsuccessful" # TODO: change to alert
114
            self.valid = True
115
        # remove from the class
116

  
117

  
118
# a wrapper for wx Frame
119
class Window(wx.App):
120
    def __init__(self, title=""):
121
        super(Window, self).__init__()
122
        self.initUIFrame()
123

  
124
    def initUIFrame(self):
125
        self.GUIFrame = GUI(None, "hallo!")
126

  
127

  
128
# actual GUI frame
129
class GUI(wx.Frame):
130
    def __init__(self, parent, title):
131
        super(GUI, self).__init__(parent, title=title,
132
            style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER, size=(600, 600))
133
        
134
        # open up scoutsim race
135
        command = shlex.split("rosrun scoutsim scoutsim_node race")
136
        self.simWindowProcess = subprocess.Popen(command, shell=False)
137
        #rospy.wait_for_service('/spawn') #don't know why this is here
138
        
139
        # register call back for on close cleanup
140
        self.Bind(wx.EVT_CLOSE, self.onClose) 
141

  
142

  
143
        self.initData()
144
        self.initUI()
145
        self.Show(True)     
146
    
147
    # do clean up after user close the window
148
    def onClose(self, event):
149
        print "Cleaning up all Processes"
150
        
151
        # kill all the behavior processes
152
        for scout in self.scouts:
153
            process = self.scouts[scout].process
154
            if (process != None):
155
                process.terminate()
156

  
157
        # kill the scout sim window
158
        self.simWindowProcess.terminate()
159
        print "done"
160
        self.Destroy()
161

  
162
    def initData(self):
163
        self.scouts = {}
164
        self.scouts["scout1"] = Scout(x=0, y=0, theta=0, name="scout1",
165
                                      Scouts = self.scouts, oninit=True)
166
        #TODO: these arguments are not right...fix them!!!
167

  
168
    # addButton callback
169
    def addScout(self, x_wx, y_wx, theta_wx, name_wx):
170
        # x, y, theta, name are given as wx Inputs
171
        x = x_wx.GetValue()
172
        y = y_wx.GetValue()
173
        theta = theta_wx.GetValue()
174
        name = name_wx.GetValue()
175
        print "in GUI trying to add scout!"
176
        newSc = Scout(x, y, theta, name, self.scouts)
177
        if (newSc.valid):
178
            # successful
179
            self.scouts[newSc.name] = newSc
180
            self.addScoutBox(newSc.name)
181
            # alert user spawn successful
182
            wx.MessageBox(u"Scout '%s' created successfully at (%d,%d,%d\u00B0)"
183
                            %(newSc.name, newSc.x, newSc.y, newSc.theta), 
184
                            "Scout Created", wx.OK | wx.ICON_INFORMATION)
185

  
186
        else:
187
            #failed to create scout
188
            wx.MessageBox("Scout Creation failed :( Check for duplicate name",
189
                            "Add Scout failed", wx.OK | wx.ICON_ERROR)
190

  
191
    def removeScout(self, name):
192
        sct = self.scouts[name]
193
        print "removing scout %s"%name
194
        sct.killSelf()
195
        if (sct.valid == False):
196
            # successful, remove from the dictionary
197
            del self.scouts[name]
198
            # refresh the display
199
            print self.mainArea.Hide(self.sizer[name])
200
            print self.mainArea.Remove(self.sizer[name])
201
            del self.sizer[name]
202
            self.window.Layout()
203
            self.window.Refresh()
204
            self.window.Update()
205
        else:
206
            raise Exception
207

  
208
    ############################ UI stuff here ###########################
209
    
210
    def initUI(self):
211
        self.initAddScoutArea()
212

  
213
    # the labels and input boxes for adding a scout through GUI
214
    def initAddScoutArea(self):
215
        # all the layout stuff copied over: using grid layout
216
        # button callbacks are changed
217
        self.totalCols = 8
218
        self.window = wx.ScrolledWindow(self, style=wx.VSCROLL)
219
        self.mainArea = wx.GridSizer(cols=1)
220
        sizer = wx.FlexGridSizer(rows=4, cols=self.totalCols, hgap=5, vgap=5)
221

  
222
        # Labels
223
        blankText = wx.StaticText(self.window, label="")
224
        newScout = wx.StaticText(self.window, label="New Scout")
225
        newScoutName = wx.StaticText(self.window, label="Name:")
226
        startXTitle = wx.StaticText(self.window, label="X:")
227
        startYTitle = wx.StaticText(self.window, label="Y:")
228
        startThetaTitle = wx.StaticText(self.window, label="Rad:")
229

  
230
        # Inputs
231
        newScoutInput = wx.TextCtrl(self.window)
232
        startX = wx.lib.agw.floatspin.FloatSpin(self.window, min_val=0, digits=5)
233
        startY = wx.lib.agw.floatspin.FloatSpin(self.window, min_val=0, digits=5)
234
        startTheta = wx.lib.agw.floatspin.FloatSpin(self.window, min_val=0, digits=5)
235
        addButton = wx.Button(self.window, id=wx.ID_ADD)
236

  
237
        # Pretty Stuff
238
        hLine = wx.StaticLine(self.window, size=(600, 5))
239
        bottomHLine = wx.StaticLine(self.window, size=(600, 5))
240
        
241
        # Row 0: just the label add scout
242
        sizer.Add(newScout)
243
        for i in range(7):
244
            sizer.AddStretchSpacer(1)
245
        # Row 1: input(name), x coord, y coord, rad, 
246
        sizer.AddMany([newScoutName, (newScoutInput, 0, wx.EXPAND), startXTitle,
247
            startX, startYTitle, startY, startThetaTitle, startTheta])
248
        # Row 2: just the add button to the right
249
        for i in range(7):
250
            sizer.AddStretchSpacer(1)
251
        sizer.Add(addButton)
252
        # Row 3
253
        
254
        # Events
255
        addButton.Bind(wx.EVT_BUTTON, lambda event: self.addScout(
256
            startX, startY, startTheta, newScoutInput))
257

  
258
        sizer.AddGrowableCol(idx=1)
259
        self.mainArea.Add(sizer, proportion=1, flag=wx.ALL|wx.EXPAND, border=10)
260
        self.window.SetSizer(self.mainArea)
261
        self.sizer = defaultdict()
262
        self.window.Layout()
263
        
264
        # make the scout1's controller
265
        self.addScoutBox("scout1");
266
        
267
    # copied over from old GUI
268
    def addScoutBox(self, name):
269
        self.sizer[name] = wx.FlexGridSizer(rows=2, cols=5, hgap=5, vgap=5)
270
        # Labels
271
        scoutName = wx.StaticText(self.window, label="Scout: " + name)
272
        behaviorLabel = wx.StaticText(self.window, label="Behavior: ")
273
        currBehaviorLabel = wx.StaticText(self.window,
274
            label="  |  Current Behavior: Slacking off")
275

  
276
        # Inputs
277
        # drop down menue
278
        scoutChoices = wx.Choice(self.window) #choices=GetBehaviors())
279
        #   buttons
280
        pauseButton = wx.ToggleButton(self.window, label="Pause")
281
        runButton = wx.Button(self.window, label="Run")
282
        killButton = wx.Button(self.window, label="Kill")
283
        teleopButton = wx.ToggleButton(self.window, label="Teleop")
284

  
285
        # row 0
286
        self.sizer[name].Add(scoutName)
287
        self.sizer[name].Add(currBehaviorLabel, wx.EXPAND | wx.ALIGN_RIGHT)
288
        self.sizer[name].AddStretchSpacer(1)
289
        self.sizer[name].AddStretchSpacer(1)
290
        self.sizer[name].Add(killButton, wx.ALIGN_RIGHT)
291

  
292
        # row 1
293
        self.sizer[name].Add(behaviorLabel)
294
        self.sizer[name].Add(scoutChoices, wx.EXPAND)
295
        self.sizer[name].Add(runButton)
296
        self.sizer[name].Add(pauseButton, wx.ALIGN_RIGHT)
297
        self.sizer[name].Add(teleopButton) 
298
        # Events
299
        killButton.Bind(wx.EVT_BUTTON, lambda event: self.removeScout(name))
300

  
301
        self.mainArea.Add(self.sizer[name], proportion=1,
302
            flag=wx.ALL | wx.EXPAND, border=10)
303
        self.window.Layout()
304
        return True
305

  
306

  
307

  
308
if __name__ == '__main__':
309
    # open up GUI
310
    window = Window(title="Colony Scout Manager")
311
    window.MainLoop()

Also available in: Unified diff