axclient.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
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 io import BytesIO
52 from actionlib_tools.library import to_yaml, yaml_msg_str
53 from actionlib_tools.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 = BytesIO()
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  action_name = args[1].rstrip('/')
238  topic_type = rostopic._get_topic_type("%s/goal" % action_name)[0]
239  if topic_type is None:
240  parser.error("unable to retrieve the topic type for goal topic '{0}/goal'\nAre you sure the action server for '{0}' is running?".format(action_name))
241  # remove "Goal" string from action type
242  if not topic_type.endswith("ActionGoal"):
243  parser.error("topic '%s/goal' is not an action goal topic" % action_name)
244  action_type = topic_type[:-4]
245  elif len(args) == 3:
246  action_type = args[2]
247  print(action_type)
248  action_suffix = "Action"
249  if not action_type.endswith(action_suffix):
250  parser.error("the action type provided '%s' doesn't end with the '%s' suffix" % (action_type, action_suffix))
251  else:
252  parser.error("You must specify the action topic name (and optionally type) Eg: ./axclient.py action_topic actionlib/TwoIntsAction ")
253 
254  action = DynamicAction(action_type)
255  app = AXClientApp(action, args[1])
256  app.MainLoop()
257  app.OnQuit()
258  rospy.signal_shutdown('GUI shutdown')
259 
260 
261 if __name__ == '__main__':
262  main()
axclient.AXClientApp.set_result
def set_result(self, result)
Definition: axclient.py:119
axclient.AXClientApp.feedback_cb
def feedback_cb(self, feedback)
Definition: axclient.py:153
axclient.AXClientApp.result_st
result_st
Definition: axclient.py:185
actionlib_tools.library.yaml_msg_str
def yaml_msg_str(type_, yaml_str, filename=None)
Definition: library.py:90
axclient.AXClientApp.action_name
action_name
Definition: axclient.py:60
actionlib_tools.dynamic_action
Definition: dynamic_action.py:1
axclient.AXClientApp.send_goal
send_goal
Definition: axclient.py:188
actionlib_tools.library.to_yaml
def to_yaml(obj)
Definition: library.py:82
axclient.AXClientApp.set_status
def set_status(self, label, color)
Definition: axclient.py:69
axclient.AXClientApp.goal_st
goal_st
Definition: axclient.py:173
axclient.AXClientApp.result_st_bx
result_st_bx
Definition: axclient.py:184
axclient.AXClientApp.OnQuit
def OnQuit(self)
Definition: axclient.py:156
axclient.AXClientApp.on_cancel
def on_cancel(self, event)
Definition: axclient.py:96
axclient.AXClientApp.server_status
server_status
Definition: axclient.py:202
axclient.AXClientApp.done_cb
def done_cb(self, state, result)
Definition: axclient.py:137
axclient.main
def main()
Definition: axclient.py:225
axclient.AXClientApp.OnInit
def OnInit(self)
Definition: axclient.py:159
axclient.AXClientApp.server_check
def server_check(self, event)
Definition: axclient.py:87
axclient.AXClientApp.goal
goal
Definition: axclient.py:170
axclient.AXClientApp.result
result
Definition: axclient.py:182
axclient.AXClientApp.feedback
feedback
Definition: axclient.py:176
actionlib::SimpleActionClient
axclient.AXClientApp.on_goal
def on_goal(self, event)
Definition: axclient.py:101
axclient.AXClientApp.action_type
action_type
Definition: axclient.py:59
axclient.AXClientApp.status_gui
def status_gui(self, status)
Definition: axclient.py:125
axclient.AXClientApp.__init__
def __init__(self, action_type, action_name)
Definition: axclient.py:58
axclient.AXClientApp.set_server_status
def set_server_status(self, label, color, enabled)
Definition: axclient.py:79
axclient.AXClientApp.server_check_timer
server_check_timer
Definition: axclient.py:214
axclient.AXClientApp.status
status
Definition: axclient.py:198
axclient.AXClientApp.goal_st_bx
goal_st_bx
Definition: axclient.py:172
axclient.AXClientApp.frame
frame
Definition: axclient.py:161
axclient.AXClientApp.sz
sz
Definition: axclient.py:166
axclient.AXClientApp.feedback_st
feedback_st
Definition: axclient.py:179
actionlib_tools.library
Definition: library.py:1
axclient.AXClientApp.active_cb
def active_cb(self)
Definition: axclient.py:144
axclient.AXClientApp.cancel_goal
cancel_goal
Definition: axclient.py:192
axclient.AXClientApp.set_cancel_button
def set_cancel_button(self, enabled)
Definition: axclient.py:73
axclient.AXClientApp.execute_type
execute_type
Definition: axclient.py:67
axclient.AXClientApp
Definition: axclient.py:57
axclient.AXClientApp.status_bg
status_bg
Definition: axclient.py:196
axclient.AXClientApp.server_status_bg
server_status_bg
Definition: axclient.py:200
axclient.AXClientApp.client
client
Definition: axclient.py:63
axclient.AXClientApp.feedback_st_bx
feedback_st_bx
Definition: axclient.py:178
axclient.AXClientApp.set_feedback
def set_feedback(self, feedback)
Definition: axclient.py:147
axclient.AXClientApp.goal_msg
goal_msg
Definition: axclient.py:66
actionlib_tools.dynamic_action.DynamicAction
Definition: dynamic_action.py:41
axclient.AXClientApp.condition
condition
Definition: axclient.py:65


actionlib_tools
Author(s): Eitan Marder-Eppstein, Vijay Pradeep, Mikael Arguedas
autogenerated on Thu Apr 10 2025 02:37:15