Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (10.075 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
import rst
34
import rstsandbox
35
from   rst.robot.EmotionState_pb2 import EmotionState
36
from   rst.robot.Animation_pb2    import Animation
37
from   rst.robot.GazeTarget_pb2   import GazeTarget
38
from   rst.robot.MouthTarget_pb2  import MouthTarget
39
    
40
#except ImportError as exception:
41
#    sys.stderr.write("ImportError: {}\n> HINT: try to export PYTHONPATH=$PYTHONPATH:$YOUR_PREFIX/lib/python2.7/site-packages/\n\n".format(exception))
42
#    sys.exit(errno.ENOPKG)
43

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

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

    
79
                self.mouth_converter = rsb.converter.ProtocolBufferConverter(messageClass = MouthTarget)
80
                rsb.converter.registerGlobalConverter(self.mouth_converter)
81

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

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

    
100
                #set value
101
                rsb_em.value = self.convert_emotiontype_to_rsbval(emotion.value)
102
                
103
                #set duration
104
                rsb_em.duration = int(emotion.time_ms)
105

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

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

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