Statistics
| Branch: | Tag: | Revision:

hlrc / client / python / hlrc_client / MiddlewareRSB.py @ e983fef1

History | View | Annotate | Download (10.215 KB)

1
"""
2
This file is part of hlrc
3

4
Copyright(c) sschulz <AT> techfak.uni-bielefeld.de
5
http://opensource.cit-ec.de/projects/hlrc
6

7
This file may be licensed under the terms of the
8
GNU General Public License Version 3 (the ``GPL''),
9
or (at your option) any later version.
10

11
Software distributed under the License is distributed
12
on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
13
express or implied. See the GPL for the specific language
14
governing rights and limitations.
15

16
You should have received a copy of the GPL along with this
17
program. If not, go to http://www.gnu.org/licenses/gpl.html
18
or write to the Free Software Foundation, Inc.,
19
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20

21
The development of this software was supported by the
22
Excellence Cluster EXC 277 Cognitive Interaction Technology.
23
The Excellence Cluster EXC 277 is a grant of the Deutsche
24
Forschungsgemeinschaft (DFG) in the context of the German
25
Excellence Initiative.
26
"""
27

    
28
from Middleware import *
29
import errno
30

    
31
import rsb
32
import rsb.converter
33
try:
34
    import rst
35
    import rstsandbox
36
    from rst.robot.EmotionState_pb2 import EmotionState
37
    from rst.robot.Animation_pb2    import Animation
38
    from rst.robot.GazeTarget_pb2   import GazeTarget
39
    from rst.robot.MouthTarget_pb2  import MouthTarget
40
except ImportError, e:
41
    print("Warning, RSB could be imported, but the required message types do not exist: ")
42
    print e
43

    
44
#except ImportError as exception:
45
#    sys.stderr.write("ImportError: {}\n> HINT: try to export PYTHONPATH=$PYTHONPATH:$YOUR_PREFIX/lib/python2.7/site-packages/\n\n".format(exception))
46
#    sys.exit(errno.ENOPKG)
47

    
48
class MiddlewareRSB(Middleware):
49
        #######################################################################
50
        def __init__(self, scope, loglevel=logging.WARNING):
51
                """initialise
52
                :param scope: base scope we want to listen on 
53
                """
54
                #init base settings
55
                Middleware.__init__(self,scope,loglevel)
56
                #call mw init
57
                self.init_middleware()
58

    
59
        def __del__(self):
60
                """destructor
61
                """
62
                self.logger.debug("destructor of MiddlewareROS called")
63
        
64
        #######################################################################
65
        def init_middleware(self):
66
                """initialise middleware
67
                """
68
                #mute rsb logging:
69
                logging.getLogger("rsb").setLevel(logging.ERROR)
70
                
71
                #initialise RSB stuff
72
                self.logger.info("initialising RSB middleware connection on scope %s, registering rst converters..." % (self.base_scope))
73
                
74
                self.emotionstate_converter = rsb.converter.ProtocolBufferConverter(messageClass = EmotionState)
75
                rsb.converter.registerGlobalConverter(self.emotionstate_converter)
76
                
77
                self.animation_converter = rsb.converter.ProtocolBufferConverter(messageClass = Animation)
78
                rsb.converter.registerGlobalConverter(self.animation_converter)
79
                
80
                self.gaze_converter = rsb.converter.ProtocolBufferConverter(messageClass = GazeTarget)
81
                rsb.converter.registerGlobalConverter(self.gaze_converter)
82

    
83
                self.mouth_converter = rsb.converter.ProtocolBufferConverter(messageClass = MouthTarget)
84
                rsb.converter.registerGlobalConverter(self.mouth_converter)
85

    
86
                try:
87
                        self.server = rsb.createRemoteServer(self.base_scope + '/set')
88
                except ValueError:
89
                        self.logger.error("ERROR: invalid scope given. server deactivated")
90
                        self.server.deactivate()
91
                        sys.exit(errno.EINVAL)
92

    
93
        #######################################################################
94
        def publish_emotion(self, em_type, emotion, blocking):
95
                """publish an emotion via mw
96
                :param em_type: type of emotion (RobotEmotion::TYPE_DEFAULT or RobotEmotion::TYPE_CURRENT)
97
                :param emotion: emotion to set
98
                :param blocking: True if this call should block until execution finished on robot
99
                """
100
                
101
                #create emotion & fill it with values:
102
                rsb_em = EmotionState()
103

    
104
                #set value
105
                rsb_em.value = self.convert_emotiontype_to_rsbval(emotion.value)
106
                
107
                #set duration
108
                rsb_em.duration = int(emotion.time_ms)
109

    
110
                with rsb.createRemoteServer(self.base_scope + '/set') as server:
111
                        self.logger.debug("calling the emotion rpc (%s)..." % ("BLOCKING" if blocking else "NON-BLOCKING"))
112
                                
113
                        if (blocking):
114
                                #blocking rpc call:
115
                                if (em_type == RobotEmotion.TYPE_DEFAULT):
116
                                        result = server.defaultEmotion(rsb_em)
117
                                else:
118
                                        result = server.currentEmotion(rsb_em)
119
                                        
120
                                self.logger.debug("server reply: '%s'" % result)
121
                        else:
122
                                if (em_type == RobotEmotion.TYPE_DEFAULT):
123
                                        future = server.defaultEmotion.async(rsb_em)
124
                                else:
125
                                        future = server.currentEmotion.async(rsb_em)
126
                        
127
                                #we could block here for a incoming result with a timeout in s
128
                                #print '> server reply: "%s"' % future.get(timeout = 10);
129
                        self.logger.debug("emotion rpc done")
130
        
131
        def publish_head_animation(self, animation, blocking):
132
                """publish an head animation via mw
133
                :param animation: animation to set
134
                :param blocking: True if this call should block until execution finished on robot
135
                """
136
                
137
                self.logger.debug("calling the animation rpc (%s)..." % ("BLOCKING" if blocking else "NON-BLOCKING"))
138
                
139
                #create animation & fill it with values:
140
                rsb_ani = Animation()
141
        
142
                #select ani
143
                rsb_ani.target = self.convert_animationtype_to_rsbval(animation.value)
144
                rsb_ani.repetitions = animation.repetitions
145
                rsb_ani.duration_each = animation.time_ms
146
                rsb_ani.scale       = animation.scale
147
        
148
                if (blocking):
149
                        #blocking:
150
                        result = self.server.animation(rsb_ani)
151
                        self.logger.debug("server reply: '%s'" % result)
152
                else:
153
                        future = self.server.animation.async(rsb_ani)
154
                        #we can block here for a incoming result with a timeout in s
155
                        #print '> server reply: "%s"' % future.get(timeout = 10);
156
                
157
                self.logger.debug("animation rpc done")
158
        
159
        def publish_default_emotion(self, emotion, blocking):
160
                self.publish_emotion(RobotEmotion.TYPE_DEFAULT, emotion, blocking)
161
        
162
        def publish_current_emotion(self, emotion, blocking):
163
                self.publish_emotion(RobotEmotion.TYPE_CURRENT, emotion, blocking)
164
        
165
        def publish_gaze_target(self, gaze, blocking):
166
                """publish a gaze target via mw
167
                :param gaze: gaze to set
168
                :param blocking: True if this call should block until execution finished on robot
169
                """
170
                self.logger.debug("calling the gaze rpc (%s)..." % ("BLOCKING" if blocking else "NON-BLOCKING"))
171
                
172
                #create gaze target & fill it with values:
173
                rsb_gaze = GazeTarget()
174
        
175
                #fill proto
176
                rsb_gaze.pan  = gaze.pan
177
                rsb_gaze.tilt = gaze.tilt
178
                rsb_gaze.roll = gaze.roll
179
                rsb_gaze.vergence = gaze.vergence
180
                rsb_gaze.pan_offset  = gaze.pan_offset
181
                rsb_gaze.tilt_offset = gaze.tilt_offset
182
                
183
                if (blocking):
184
                        #blocking:
185
                        result = self.server.gaze(rsb_gaze)
186
                        self.logger.debug("server reply: '%s'" % result)
187
                else:
188
                        future = self.server.gaze.async(rsb_gaze)
189
                        #we can block here for a incoming result with a timeout in s
190
                        #print '> server reply: "%s"' % future.get(timeout = 10);
191
                
192
                self.logger.debug("gaze rpc done")
193
        
194
        def publish_mouth_target(self, mouth, blocking):
195
                """publish a mouth target via mw
196
                :param mouth: mouth value to set
197
                :param blocking: True if this call should block until execution finished on robot
198
                """
199
                self.logger.debug("calling the mouth rpc (%s)..." % ("BLOCKING" if blocking else "NON-BLOCKING"))
200
                
201
                #create mouth state & fill it with values:
202
                rsb_mouth = MouthTarget()
203
                
204
                #fill proto
205
                rsb_mouth.opening_left   = mouth.opening_left
206
                rsb_mouth.opening_center = mouth.opening_center
207
                rsb_mouth.opening_right  = mouth.opening_right
208
                rsb_mouth.position_left  = mouth.position_left
209
                rsb_mouth.position_center = mouth.position_center
210
                rsb_mouth.position_right = mouth.position_right
211
                
212
                if (blocking):
213
                        #blocking:
214
                        result = self.server.mouth(rsb_mouth)
215
                        self.logger.debug("server reply: '%s'" % result)
216
                else:
217
                        future = self.server.mouth.async(rsb_mouth)
218
                        #we can block here for a incoming result with a timeout in s
219
                        #print '> server reply: "%s"' % future.get(timeout = 10);
220
                
221
                self.logger.debug("mouth rpc done")
222
        
223
        def publish_speech(self, text, blocking):
224
                """publish a tts request via mw
225
                :param text: text to synthesize and speak
226
                :param blocking: True if this call should block until execution finished on robot
227
                """
228
                self.logger.debug("calling the speech rpc (%s)..." % ("BLOCKING" if blocking else "NON-BLOCKING"))
229
                
230
                if (blocking):
231
                        #blocking:
232
                        result = self.server.speech(text)
233
                        self.logger.debug("server reply: '%s'" % result)
234
                else:
235
                        future = self.server.speech.async(text)
236
                        #we can block here for a incoming result with a timeout in s
237
                        #print '> server reply: "%s"' % future.get(timeout = 10);
238
                
239
                self.logger.debug("speech rpc done")
240
        
241
        #######################################################################
242
        # some helpers
243
        def convert_animationtype_to_rsbval(self, value):
244
                """convert RobotAnimation.value to RSB animation value
245
                :param value: RobotAnimation.* id to convert to rsb id
246
                """
247
                #NOTE: this convertion is important as the actual integer values of
248
                #      thy python api and the protobuf might be different
249

    
250
                if (value == RobotAnimation.IDLE):
251
                        return Animation().IDLE
252
                elif (value == RobotAnimation.HEAD_NOD):
253
                        return Animation().HEAD_NOD
254
                elif (value == RobotAnimation.HEAD_SHAKE):
255
                        return Animation().HEAD_SHAKE
256
                elif (value == RobotAnimation.EYEBLINK_L):
257
                        return Animation().EYEBLINK_L
258
                elif (value == RobotAnimation.EYEBLINK_R):
259
                        return  Animation().EYEBLINK_R
260
                elif (value == RobotAnimation.EYEBLINK_BOTH):
261
                        return  Animation().EYEBLINK_BOTH
262
                elif (value == RobotAnimation.EYEBROWS_RAISE):
263
                        return  Animation().EYEBROWS_RAISE
264
                elif (value == RobotAnimation.EYEBROWS_LOWER):
265
                        return  Animation().EYEBROWS_LOWER
266
                else:
267
                        self.logger.error("invalid animation type %d\n" % (value))
268
                        return  Animation().NEUTRAL
269
                
270
        def convert_emotiontype_to_rsbval(self, value):
271
                """convert RobotEmotion.value to RSB animation value
272
                :param value: RobotEmotion.* id to convert to rsb id
273
                """
274
                #NOTE: this convertion is important as the actual integer values of
275
                #      thy python api and the protobuf might be different
276

    
277
                if (value == RobotEmotion.NEUTRAL):
278
                        return EmotionState().NEUTRAL
279
                elif (value == RobotEmotion.HAPPY):
280
                        return EmotionState().HAPPY
281
                elif (value == RobotEmotion.SAD):
282
                        return EmotionState().SAD
283
                elif (value == RobotEmotion.ANGRY):
284
                        return EmotionState().ANGRY
285
                elif (value == RobotEmotion.SURPRISED):
286
                        return  EmotionState().SURPRISED
287
                elif (value == RobotEmotion.FEAR):
288
                        return EmotionState().FEAR
289
                else:
290
                        self.logger.error("invalid emotion type %d\n" % (value))
291
                        return  EmotionState().NEUTRAL