6 from rospy
import ROSException
11 from threading
import Thread
12 from rosservice
import ROSServiceException
20 Generic joystick teleoperation node. 21 Will not start without configuration, has to be stored in 'teleop' parameter. 22 See config/joy_teleop.yaml for an example. 25 if not rospy.has_param(
"teleop"):
26 rospy.logfatal(
"no configuration was found, taking node down")
40 teleop_cfg = rospy.get_param(
"teleop")
44 rospy.logerr(
"command {} was duplicated".format(i))
46 action_type = teleop_cfg[i][
'type']
48 if action_type ==
'topic':
50 elif action_type ==
'action':
52 elif action_type ==
'service':
55 rospy.logerr(
"unknown type '%s' for command '%s'", action_type, i)
58 rospy.Subscriber(
'joy', sensor_msgs.msg.Joy, self.
joy_callback)
68 except JoyTeleopException
as e:
69 rospy.logerr(
"error while parsing joystick input: %s", str(e))
73 """Add a topic publisher for a joystick command""" 74 topic_name = command[
'topic_name']
77 self.
publishers[topic_name] = rospy.Publisher(topic_name, topic_type, queue_size=1)
78 except JoyTeleopException
as e:
79 rospy.logerr(
"could not register topic for command {}: {}".format(name, str(e)))
82 """Add an action client for a joystick command""" 83 action_name = command[
'action_name']
89 except JoyTeleopException:
94 def __init__(self, name, service_class, persistent):
96 rospy.wait_for_service(name, timeout=2.0)
119 """ Add an AsyncServiceProxy for a joystick command """ 120 service_name = command[
'service_name']
121 if 'service_persistent' not in command:
122 command[
'service_persistent'] =
False 123 service_persistent = command[
'service_persistent']
133 except JoyTeleopException:
138 """Find a command matching a joystick configuration""" 140 if b < 0
or len(buttons) <= b
or buttons[b] != 1:
143 return sum(buttons) >= len(self.
command_list[c][
'buttons'])
145 return sum(buttons) == len(self.
command_list[c][
'buttons'])
148 """Add a command to the command list""" 149 if command[
'type'] ==
'topic':
150 if 'deadman_buttons' not in command:
151 command[
'deadman_buttons'] = []
152 command[
'buttons'] = command[
'deadman_buttons']
153 elif command[
'type'] ==
'action':
154 if 'action_goal' not in command:
155 command[
'action_goal'] = {}
156 elif command[
'type'] ==
'service':
157 if 'service_request' not in command:
158 command[
'service_request'] = {}
159 command[
'allow_combinations'] = command.get(
'allow_multiple_commands',
True)
163 """Run a joystick command""" 165 if cmd[
'type'] ==
'topic':
167 elif cmd[
'type'] ==
'action':
169 rospy.logerr(
"command {} was not played because the action " 170 "server was unavailable. Trying to reconnect..." 171 .format(cmd[
'action_name']))
176 elif cmd[
'type'] ==
'service':
178 rospy.logerr(
"command {} was not played because the service " 179 "server was unavailable. Trying to reconnect..." 180 .format(cmd[
'service_name']))
186 raise JoyTeleopException(
'command {} is neither a topic publisher nor an action or service client' 193 if 'message_value' in cmd:
194 for param
in cmd[
'message_value']:
195 self.
set_member(msg, param[
'target'], param[
'value'])
198 for mapping
in cmd[
'axis_mappings']:
199 if 'axis' in mapping:
200 if len(joy_state.axes) > mapping[
'axis']:
201 val = joy_state.axes[mapping[
'axis']] * mapping.get(
'scale', 1.0) + mapping.get(
'offset', 0.0)
203 rospy.logerr(
'Joystick has only {} axes (indexed from 0), but #{} was referenced in config.'.format(len(joy_state.axes), mapping[
'axis']))
205 elif 'button' in mapping:
206 if len(joy_state.buttons) > mapping[
'button']:
207 val = joy_state.buttons[mapping[
'button']] * mapping.get(
'scale', 1.0) + mapping.get(
'offset', 0.0)
209 rospy.logerr(
'Joystick has only {} buttons (indexed from 0), but #{} was referenced in config.'.format(len(joy_state.buttons), mapping[
'button']))
212 rospy.logerr(
'No Supported axis_mappings type found in: {}'.format(mapping))
218 if hasattr(msg,
'header'):
219 msg.header.stamp = rospy.Time.now()
221 self.
publishers[cmd[
'topic_name']].publish(msg)
226 genpy.message.fill_message_args(goal, [cmd[
'action_goal']])
227 self.
al_clients[cmd[
'action_name']].send_goal(goal)
233 genpy.message.fill_message_args(request, [cmd[
'service_request']])
234 if not self.
srv_clients[cmd[
'service_name']](request):
235 rospy.loginfo(
'Not sending new service request for command {} because previous request has not finished' 239 ml = member.split(
'.')
244 target = getattr(target, i)
245 setattr(target, ml[-1], value)
250 package, message = type_name.split(
'/')
251 mod = importlib.import_module(package +
'.msg')
257 except AttributeError:
258 raise JoyTeleopException(
"message {} could not be loaded from module {}".format(package, message))
263 return rostopic._get_topic_type(rospy.resolve_name(action_name) +
'/goal')[0][:-4]
270 self.
service_types[service_name] = rosservice.get_service_class_by_name(service_name)
271 except ROSServiceException
as e:
272 raise JoyTeleopException(
"service {} could not be loaded: {}".format(service_name, str(e)))
277 if cmd[
'type'] !=
'action':
283 if __name__ ==
"__main__":
285 rospy.init_node(
'joy_teleop')
288 except JoyTeleopException:
290 except rospy.ROSInterruptException:
def run_service(self, c, joy_state)
def register_topic(self, name, command)
def get_message_type(self, type_name)
def run_topic(self, c, joy_state)
def get_action_type(self, action_name)
def update_actions(self, evt=None)
def get_service_type(self, service_name)
def set_member(self, msg, member, value)
def joy_callback(self, data)
def __init__(self, name, service_class, persistent)
def run_command(self, command, joy_state)
def run_action(self, c, joy_state)
def __call__(self, request)
def add_command(self, name, command)
def register_action(self, name, command)
def match_command(self, c, buttons)
def register_service(self, name, command)