Project

General

Profile

Statistics
| Branch: | Revision:

root / scout / scoutsim / BehaviorGUI.py @ 594c3bb9

History | View | Annotate | Download (7.04 KB)

1
#!/usr/bin/python
2

    
3
import wx
4
import wx.lib.intctrl 
5
import string
6
import subprocess
7
import signal
8
from collections import defaultdict
9
# ROS imports
10
import roslib; roslib.load_manifest("scoutsim")
11
import rospy
12
from scoutsim.srv import *
13

    
14
# Everyone global variables (PLEASE REFACTOR ME)
15
scouts = defaultdict(str) # Associative array in the form [scout_name: current_behavior]
16
processes = defaultdict() # Associative array in the form [scout_name: process_handler]
17

    
18
#
19
# ROS functions
20
#
21
def AddToSimulator(name, x, y, theta):
22
        if name in scouts:
23
                return False
24
        scouts[name] = ""
25
        print "Calling ROS function to create scout "+name
26
        try:
27
                rospy.wait_for_service('/spawn');
28
                service = rospy.ServiceProxy('/spawn', Spawn);
29
                resp = service(x, y, theta, name)
30
                return True
31
        except rospy.ServiceException, e:
32
                return False
33

    
34
def GetBehaviors():
35
        return ["CW Circle", "CCW Circle", "Odometry", "Navigation Map", "Scheduler", "Warehouse", "Line Follow", "WL Test"]
36

    
37
def SetBehavior(name, behaviorLabel, behaviorButton=False, behavior="Pause"):
38
        if behavior == "Pause":
39
                if name not in processes:
40
                        return False
41
                if not behaviorButton.GetValue():
42
                        processes[name].send_signal(signal.SIGCONT)
43
                        print "Scout "+name+" was resumed."
44
                        behaviorButton.SetLabel("Pause")
45
                        behaviorLabel.SetLabel("  |  Current Behavior: "+scouts[name])
46
                else:
47
                        processes[name].send_signal(signal.SIGSTOP)
48
                        subprocess.Popen("rosrun libscout libscout "+name+" 8", shell=True) 
49
                        print "Scout "+name+" was paused."
50
                        behaviorButton.SetLabel("Resume")
51
                        behaviorLabel.SetLabel("  |  Current Behavior: Paused")
52
                return True
53
        if name in processes:
54
                processes[name].kill()
55
        processes[name] = subprocess.Popen("rosrun libscout libscout "+name+" "+str(GetBehaviors().index(behavior))+"", shell=True) 
56
        behaviorButton.SetValue(False)
57
        behaviorButton.SetLabel("Pause")
58
        print "Scout "+name+" was set to behavior: "+behavior
59
        behaviorLabel.SetLabel("  |  Current Behavior: "+behavior)
60
        scouts[name] = behavior
61

    
62
def KillScout(name):
63
        try:
64
                rospy.wait_for_service('/kill');
65
                service = rospy.ServiceProxy('/kill', Kill);
66
                if name in processes:
67
                        processes[name].kill() # This is perhaps not working
68
                resp = service(name)
69
                del scouts[name]
70
                del processes[name]
71
                return True
72
        except rospy.ServiceException, e:
73
                return False
74

    
75
def PauseScout(name, behaviorLabel, behaviorButton):
76
        return SetBehavior(name, behaviorLabel, behaviorButton)
77
#
78
# End ROS functions
79
#
80

    
81
class GUI(wx.Frame):
82
        def __init__(self, parent, title):
83
                super(GUI, self).__init__(parent, title=title, style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER, size=(600, 600))
84
                self.InitUI()
85
                self.Show()     
86

    
87
        def InitUI(self):
88
                self.window = wx.ScrolledWindow(self, style=wx.VSCROLL)
89
                self.mainArea = wx.GridSizer(cols=1)
90
                sizer = wx.FlexGridSizer(rows=4, cols=8, hgap=5, vgap=5)
91

    
92
                # Labels
93
                blankText = wx.StaticText(self.window, label="")
94
                newScout = wx.StaticText(self.window, label="New Scout")
95
                newScoutName = wx.StaticText(self.window, label="Name:")
96
                startXTitle = wx.StaticText(self.window, label="X:")
97
                startYTitle = wx.StaticText(self.window, label="Y:")
98
                startThetaTitle = wx.StaticText(self.window, label="Rad:")
99

    
100
                # Inputs
101
                newScoutInput = wx.TextCtrl(self.window)
102
                startX = wx.lib.intctrl.IntCtrl(self.window, min=0)
103
                startY = wx.lib.intctrl.IntCtrl(self.window, min=0)
104
                startTheta = wx.lib.intctrl.IntCtrl(self.window, min=0, max=100)
105
                addButton = wx.Button(self.window, id=wx.ID_ADD)
106

    
107
                # Pretty Stuff
108
                hLine = wx.StaticLine(self.window, size=(600, 5))
109
                bottomHLine = wx.StaticLine(self.window, size=(600, 5))
110

    
111
                # Row 0
112
                sizer.Add(newScout)
113
                for i in range(7):
114
                        sizer.AddStretchSpacer(1)
115
                # Row 1
116
                sizer.AddMany([newScoutName, (newScoutInput, 0, wx.EXPAND), startXTitle, startX, startYTitle, startY, startThetaTitle, startTheta])
117
                # Row 2
118
                for i in range(7):
119
                        sizer.AddStretchSpacer(1)
120
                sizer.Add(addButton)
121
                # Row 3
122

    
123
                # Events
124
                addButton.Bind(wx.EVT_BUTTON, lambda event: self.NewScout(event, newScoutInput, startX, startY, startTheta))
125

    
126
                sizer.AddGrowableCol(idx=1)
127
                self.mainArea.Add(sizer, proportion=1, flag=wx.ALL|wx.EXPAND, border=10)
128
                self.window.SetSizer(self.mainArea)
129
                self.sizer = defaultdict()
130

    
131
        def NewScout(self, e, name, x, y, theta):
132
                if (name):
133
                        scoutCreated = self.AddScout(name.GetValue(), x.GetValue(), y.GetValue(), theta.GetValue())
134
                        if (scoutCreated):
135
                                wx.MessageBox("Scout '"+name.GetValue()+"' created successfully at ("+str(x.GetValue())+", "+str(y.GetValue())+") facing "+str(theta.GetValue())+u"\u00B0.", 'Scout Created', wx.OK | wx.ICON_INFORMATION)
136
                                name.SetValue("")
137
                                x.SetValue(0)
138
                                y.SetValue(0)
139
                                theta.SetValue(0)
140
                                return True
141
                wx.MessageBox('Error creating scout.  Please check that all information was entered properly and there are no duplicate scout names.', 'Info', wx.OK | wx.ICON_ERROR)
142
        
143
        def AddScoutBox(self, name):
144
                self.sizer[name] = wx.FlexGridSizer(rows=2, cols=4, hgap=5, vgap=5)
145
                # Labels
146
                scoutName = wx.StaticText(self.window, label="Scout: "+name)
147
                behaviorLabel = wx.StaticText(self.window, label="Behavior: ")
148
                currBehaviorLabel = wx.StaticText(self.window, label="  |  Current Behavior: Slacking off")
149

    
150
                # Inputs
151
                scoutChoices = wx.Choice(self.window, choices=GetBehaviors())
152
                pauseButton = wx.ToggleButton(self.window, label="Pause")
153
                runButton = wx.Button(self.window, label="Run")
154
                killButton = wx.Button(self.window, label="Kill")
155

    
156
                self.sizer[name].Add(scoutName)
157
                self.sizer[name].Add(currBehaviorLabel, wx.EXPAND|wx.ALIGN_RIGHT)
158
                self.sizer[name].AddStretchSpacer(1)
159
                self.sizer[name].Add(killButton, wx.ALIGN_RIGHT)
160

    
161
                self.sizer[name].Add(behaviorLabel)
162
                self.sizer[name].Add(scoutChoices, wx.EXPAND)
163
                self.sizer[name].Add(runButton)
164
                self.sizer[name].Add(pauseButton, wx.ALIGN_RIGHT)
165
                
166
                # Events
167
                pauseButton.Bind(wx.EVT_TOGGLEBUTTON, lambda event: PauseScout(name, currBehaviorLabel, pauseButton))
168
                runButton.Bind(wx.EVT_BUTTON, lambda event: SetBehavior(name, currBehaviorLabel, pauseButton, scoutChoices.GetStringSelection()))
169
                killButton.Bind(wx.EVT_BUTTON, lambda event: self.RemoveScout(name))
170

    
171
                self.mainArea.Add(self.sizer[name], proportion=1, flag=wx.ALL|wx.EXPAND, border=10)
172
                self.window.Layout()
173
                return True
174

    
175
        def AddScout(self, name, x, y, theta):
176
                if AddToSimulator(name, x, y, theta):
177
                        return self.AddScoutBox(name)
178
                wx.MessageBox("ROS call failed!", 'ROS Error', wx.OK | wx.ICON_ERROR)
179
                return False
180

    
181
        def RemoveScout(self, name):
182
                # I don't trust this bit. Remove() should work by itself, but it doesn't want to.
183
                # Hide()ing before Remove()ing does work for some reason though. It makes me think 
184
                # the sizer is still around somewhere, sneakily leaking memory.
185
                # Alas, such is life.
186
                print "Hidden scoutLayout for "+name+": "+str(self.mainArea.Hide(self.sizer[name], True))
187
                print "Removed scoutLayout for "+name+": "+str(self.mainArea.Remove(self.sizer[name]))+" (Maybe...)"
188
                del self.sizer[name]
189
                if KillScout(name):
190
                        self.window.Layout()
191
                        self.window.Refresh()
192
                        self.window.Update()
193
                return
194

    
195
if __name__ == '__main__':
196
        subprocess.Popen("rosrun scoutsim scoutsim_node race", shell=True)
197
        app = wx.App()
198
        GUI(None, title='Colony Scout Manager')
199
        app.MainLoop()