Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 """
00033 ROS specific specializations of rgoap classes
00034 """
00035
00036
00037 import roslib; roslib.load_manifest('rgoap_ros')
00038 import rospy
00039 import rostopic
00040
00041 from rgoap import Condition, Action
00042
00043
00044 import logging
00045 _logger = logging.getLogger('rgoap.ros')
00046
00047
00048
00049 class ROSTopicCondition(Condition):
00050 """Mirrors a ROS message field of a topic as its value.
00051 Note that this Condition's value remains None until a message is received.
00052 """
00053 def __init__(self, state_name, topic, topic_class, field=None, msgeval=None):
00054 Condition.__init__(self, state_name)
00055 self._topic = topic
00056 self._field = field
00057 self._subscriber = rospy.Subscriber(topic, topic_class, self._callback)
00058 if msgeval is None:
00059 assert field is not None
00060 msgeval = rostopic.msgevalgen(field)
00061 self._msgeval = msgeval
00062
00063 self._value = None
00064
00065 def __repr__(self):
00066 return '<%s topic=%s field=%s>' % (self.__class__.__name__, self._topic, self._field)
00067
00068 def _callback(self, msg):
00069 self._value = self._msgeval(msg)
00070
00071
00072 def get_value(self):
00073 return self._value
00074
00075
00076 class ROSTopicAction(Action):
00077
00078 def __init__(self, topic, topic_class,
00079 preconditions, effects,
00080 msg_args=None, msg_cb=None, **kwargs):
00081 """
00082 :param topic_class: Message type, ``Class``
00083 :param msg_args: Arguments to initialize message that is published, ``[val]``
00084 :param msg_cb: callback to replace the default _msg_cb, useful with lambda expressions
00085 """
00086 assert msg_args is None or msg_cb is None, \
00087 "Only either msg_args or msg_cb may be given, not both"
00088 Action.__init__(self, preconditions, effects, **kwargs)
00089 self._topic = topic
00090 self._topic_class = topic_class
00091 self._msg_args = msg_args
00092 if msg_cb is not None:
00093 self._msg_cb = msg_cb
00094 self._publisher = rospy.Publisher(topic, topic_class, **kwargs)
00095
00096 def __str__(self):
00097 s = '%s:%s' % (self.__class__.__name__, self._topic)
00098 if self._msg_args is not None:
00099 s += '=%s' % self._msg_args
00100 return s
00101
00102 def _msg_cb(self, message, next_worldstate):
00103 """Fill and return the given (or a created) message as desired
00104
00105 Must be implemented and is concerned only if neither msg_args nor msg_cb is given.
00106 """
00107 raise NotImplementedError
00108
00109 def check_freeform_context(self):
00110 return self._publisher.get_num_connections() > 0
00111
00112 def run(self, next_worldstate):
00113 _logger.debug("num of subscribers to %s: %d",
00114 self.__class__.__name__,
00115 self._publisher.get_num_connections())
00116 if self._msg_args is None:
00117 _logger.info("%s publishes message..", self)
00118 self._publisher.publish(self._msg_cb(self._topic_class(), next_worldstate))
00119 rospy.sleep(1)
00120 else:
00121 _logger.info("%s publishes message via rostopic..", self)
00122 rostopic.publish_message(self._publisher, self._topic_class, self._msg_args, once=True)
00123
00124
00125