axclient.py
Go to the documentation of this file.
1 #! /usr/bin/python
2 # **********************************************************
3 # Software License Agreement (BSD License)
4 #
5 # Copyright (c) 2009, Willow Garage, Inc.
6 # All rights reserved.
7 #
8 # Redistribution and use in source and binary forms, with or without
9 # modification, are permitted provided that the following conditions
10 # are met:
11 #
12 # * Redistributions of source code must retain the above copyright
13 # notice, this list of conditions and the following disclaimer.
14 # * Redistributions in binary form must reproduce the above
15 # copyright notice, this list of conditions and the following
16 # disclaimer in the documentation and/or other materials provided
17 # with the distribution.
18 # * Neither the name of Willow Garage, Inc. nor the names of its
19 # contributors may be used to endorse or promote products derived
20 # from this software without specific prior written permission.
21 #
22 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 # POSSIBILITY OF SUCH DAMAGE.
34 #
35 # Author: Eitan Marder-Eppstein
36 # **********************************************************
37 """
38 usage: %prog /action_name action_type
39 """
40 
41 PKG = 'actionlib'
42 
43 import roslib.message
44 
45 from optparse import OptionParser
46 import wx
47 import rospy
48 import actionlib
49 import threading
50 import rostopic
51 from cStringIO import StringIO
52 from library import to_yaml, yaml_msg_str
53 from dynamic_action import DynamicAction
54 from actionlib_msgs.msg import GoalStatus
55 
56 
57 class AXClientApp(wx.App):
58  def __init__(self, action_type, action_name):
59  self.action_type = action_type
60  self.action_name = action_name
61  wx.App.__init__(self)
62 
64  self.action_name, self.action_type.action)
65  self.condition = threading.Condition()
66  self.goal_msg = None
67  self.execute_type = None
68 
69  def set_status(self, label, color):
70  self.status_bg.SetBackgroundColour(color)
71  self.status.SetLabel(label)
72 
73  def set_cancel_button(self, enabled):
74  if enabled:
75  self.cancel_goal.Enable()
76  else:
77  self.cancel_goal.Disable()
78 
79  def set_server_status(self, label, color, enabled):
80  self.server_status_bg.SetBackgroundColour(color)
81  self.server_status.SetLabel(label)
82  if enabled:
83  self.send_goal.Enable()
84  else:
85  self.send_goal.Disable()
86 
87  def server_check(self, event):
88  TIMEOUT = 0.01
89  if self.client.wait_for_server(rospy.Duration.from_sec(TIMEOUT)):
90  wx.CallAfter(self.set_server_status, "Connected to server",
91  wx.Colour(192, 252, 253), True)
92  else:
93  wx.CallAfter(self.set_server_status, "Disconnected from server",
94  wx.Colour(200, 0, 0), False)
95 
96  def on_cancel(self, event):
97  # we'll cancel the current goal
98  self.client.cancel_goal()
99  self.set_status("Canceling goal", wx.Colour(211, 34, 243))
100 
101  def on_goal(self, event):
102  try:
103  self.goal_msg = yaml_msg_str(self.action_type.goal,
104  self.goal.GetValue())
105  buff = StringIO()
106  self.goal_msg.serialize(buff)
107 
108  # send the goal to the action server and register the relevant
109  # callbacks
110  self.client.send_goal(self.goal_msg, self.done_cb, self.active_cb,
111  self.feedback_cb)
112  self.set_status("Goal is pending", wx.Colour(255, 174, 59))
113  self.set_cancel_button(True)
114 
115  except roslib.message.SerializationError as e:
116  self.goal_msg = None
117  wx.MessageBox(str(e), "Error serializing goal", wx.OK)
118 
119  def set_result(self, result):
120  try:
121  self.result.SetValue(to_yaml(result))
122  except UnicodeDecodeError:
123  self.result.SetValue("Cannot display result due to unprintable characters")
124 
125  def status_gui(self, status):
126  return {GoalStatus.PENDING: ['PENDING', wx.Colour(255, 174, 59)],
127  GoalStatus.ACTIVE: ['ACTIVE', wx.Colour(0, 255, 0)],
128  GoalStatus.PREEMPTED: ['PREEMPTED', wx.Colour(255, 252, 16)],
129  GoalStatus.SUCCEEDED: ['SUCCEEDED', wx.Colour(38, 250, 253)],
130  GoalStatus.ABORTED: ['ABORTED', wx.Colour(200, 0, 0)],
131  GoalStatus.REJECTED: ['REJECTED', wx.Colour(253, 38, 159)],
132  GoalStatus.PREEMPTING: ['PREEMPTING', wx.Colour(253, 38, 159)],
133  GoalStatus.RECALLING: ['RECALLING', wx.Colour(230, 38, 253)],
134  GoalStatus.RECALLED: ['RECALLED', wx.Colour(230, 38, 253)],
135  GoalStatus.LOST: ['LOST', wx.Colour(255, 0, 0)]}[status]
136 
137  def done_cb(self, state, result):
138  status_string, status_color = self.status_gui(state)
139  wx.CallAfter(self.set_status, ''.join(["Goal finished with status: ",
140  status_string]), status_color)
141  wx.CallAfter(self.set_result, result)
142  wx.CallAfter(self.set_cancel_button, False)
143 
144  def active_cb(self):
145  wx.CallAfter(self.set_status, "Goal is active", wx.Colour(0, 200, 0))
146 
147  def set_feedback(self, feedback):
148  try:
149  self.feedback.SetValue(to_yaml(feedback))
150  except UnicodeDecodeError:
151  self.feedback.SetValue("Cannot display feedback due to unprintable characters")
152 
153  def feedback_cb(self, feedback):
154  wx.CallAfter(self.set_feedback, feedback)
155 
156  def OnQuit(self):
157  self.server_check_timer.Stop()
158 
159  def OnInit(self):
160 
161  self.frame = wx.Frame(
162  None, -1,
163  self.action_name + ' - ' + self.action_type.name + ' - GUI Client'
164  )
165 
166  self.sz = wx.BoxSizer(wx.VERTICAL)
167 
168  tmp_goal = self.action_type.goal()
169 
170  self.goal = wx.TextCtrl(self.frame, -1, style=wx.TE_MULTILINE)
171  self.goal.SetValue(to_yaml(tmp_goal))
172  self.goal_st_bx = wx.StaticBox(self.frame, -1, "Goal")
173  self.goal_st = wx.StaticBoxSizer(self.goal_st_bx, wx.VERTICAL)
174  self.goal_st.Add(self.goal, 1, wx.EXPAND)
175 
176  self.feedback = wx.TextCtrl(self.frame, -1, style=(wx.TE_MULTILINE |
177  wx.TE_READONLY))
178  self.feedback_st_bx = wx.StaticBox(self.frame, -1, "Feedback")
179  self.feedback_st = wx.StaticBoxSizer(self.feedback_st_bx, wx.VERTICAL)
180  self.feedback_st.Add(self.feedback, 1, wx.EXPAND)
181 
182  self.result = wx.TextCtrl(self.frame, -1, style=(wx.TE_MULTILINE |
183  wx.TE_READONLY))
184  self.result_st_bx = wx.StaticBox(self.frame, -1, "Result")
185  self.result_st = wx.StaticBoxSizer(self.result_st_bx, wx.VERTICAL)
186  self.result_st.Add(self.result, 1, wx.EXPAND)
187 
188  self.send_goal = wx.Button(self.frame, -1, label="SEND GOAL")
189  self.send_goal.Bind(wx.EVT_BUTTON, self.on_goal)
190  self.send_goal.Disable()
191 
192  self.cancel_goal = wx.Button(self.frame, -1, label="CANCEL GOAL")
193  self.cancel_goal.Bind(wx.EVT_BUTTON, self.on_cancel)
194  self.cancel_goal.Disable()
195 
196  self.status_bg = wx.Panel(self.frame, -1)
197  self.status_bg.SetBackgroundColour(wx.Colour(200, 0, 0))
198  self.status = wx.StaticText(self.status_bg, -1, label="No Goal")
199 
200  self.server_status_bg = wx.Panel(self.frame, -1)
201  self.server_status_bg.SetBackgroundColour(wx.Colour(200, 0, 0))
202  self.server_status = wx.StaticText(self.server_status_bg, -1, label="Disconnected from server.")
203 
204  self.sz.Add(self.goal_st, 1, wx.EXPAND)
205  self.sz.Add(self.feedback_st, 1, wx.EXPAND)
206  self.sz.Add(self.result_st, 1, wx.EXPAND)
207  self.sz.Add(self.send_goal, 0, wx.EXPAND)
208  self.sz.Add(self.cancel_goal, 0, wx.EXPAND)
209  self.sz.Add(self.status_bg, 0, wx.EXPAND)
210  self.sz.Add(self.server_status_bg, 0, wx.EXPAND)
211 
212  self.frame.SetSizer(self.sz)
213 
214  self.server_check_timer = wx.Timer(self.frame)
215  self.frame.Bind(wx.EVT_TIMER, self.server_check,
216  self.server_check_timer)
217  self.server_check_timer.Start(1000)
218 
219  self.sz.Layout()
220  self.frame.Show()
221 
222  return True
223 
224 
225 def main():
226  rospy.init_node('axclient', anonymous=True)
227 
228  parser = OptionParser(__doc__.strip())
229 # parser.add_option("-t","--test",action="store_true", dest="test",default=False,
230 # help="A testing flag")
231 # parser.add_option("-v","--var",action="store",type="string", dest="var",default="blah")
232 
233  (options, args) = parser.parse_args(rospy.myargv())
234 
235  if (len(args) == 2):
236  # get action type via rostopic
237  topic_type = rostopic._get_topic_type("%s/goal" % args[1])[0]
238  # remove "Goal" string from action type
239  assert("Goal" in topic_type)
240  topic_type = topic_type[0:len(topic_type)-4]
241  elif (len(args) == 3):
242  topic_type = args[2]
243  print(topic_type)
244  assert("Action" in topic_type)
245  else:
246  parser.error("You must specify the action topic name (and optionally type) Eg: ./axclient.py action_topic actionlib/TwoIntsAction ")
247 
248  action = DynamicAction(topic_type)
249  app = AXClientApp(action, args[1])
250  app.MainLoop()
251  app.OnQuit()
252  rospy.signal_shutdown('GUI shutdown')
253 
254 
255 if __name__ == '__main__':
256  main()
def main()
Definition: axclient.py:225
def set_status(self, label, color)
Definition: axclient.py:69
def done_cb(self, state, result)
Definition: axclient.py:137
def OnQuit(self)
Definition: axclient.py:156
def on_cancel(self, event)
Definition: axclient.py:96
def OnInit(self)
Definition: axclient.py:159
def server_check(self, event)
Definition: axclient.py:87
def on_goal(self, event)
Definition: axclient.py:101
def status_gui(self, status)
Definition: axclient.py:125
def __init__(self, action_type, action_name)
Definition: axclient.py:58
def set_server_status(self, label, color, enabled)
Definition: axclient.py:79
A Simple client implementation of the ActionInterface which supports only one goal at a time...
def active_cb(self)
Definition: axclient.py:144
def set_cancel_button(self, enabled)
Definition: axclient.py:73
def set_feedback(self, feedback)
Definition: axclient.py:147
def yaml_msg_str(type_, yaml_str, filename=None)
Definition: library.py:85
def feedback_cb(self, feedback)
Definition: axclient.py:153
def set_result(self, result)
Definition: axclient.py:119
def to_yaml(obj)
Definition: library.py:77


actionlib
Author(s): Eitan Marder-Eppstein, Vijay Pradeep, Mikael Arguedas
autogenerated on Mon Feb 18 2019 03:59:59