Revision 013997fb

View differences:

client/python/hlrc_client/simple-robot-gaze.py
1
#!/usr/bin/python
2

  
3
__author__ = 'fl@techfak'
4

  
5
# STD IMPORTS
6
import sys
7
import time
8
import signal
9
import logging
10
import operator
11

  
12
# HLRC
13
from hlrc_client import *
14

  
15
# ROS IMPORTS
16
import rospy
17
import roslib
18
from std_msgs.msg import Header
19
from std_msgs.msg import String
20
from people_msgs.msg import Person
21
from people_msgs.msg import People
22

  
23

  
24
class RobotDriver():
25
    """
26
    This class holds the robot controller.
27
    Provides better encapsulation though...
28
    """
29
    def __init__(self, _mw, _outscope):
30
        print(">>> Initializing Robot Controller")
31
        self.mw               = _mw
32
        self.outscope         = _outscope
33
        self.robot_controller = RobotController(self.mw, self.outscope, logging.INFO)
34

  
35

  
36
class GazeController():
37
    """
38
    The GazeController receives person messages (ROS) and derives
39
    the nearest person identified. Based on this, the robot's
40
    joint angle target's are derived using the transformation
41
    class below
42
    """
43
    def __init__(self, _robot_controller, _affine_transform, _inscope):
44
        print(">>> Initializing Gaze Controller")
45
        self.run      = True
46
        self.inscope  = _inscope
47
        self.rc       = _robot_controller
48
        self.at       = _affine_transform
49
        self.nearest_person_x = 0.0
50
        self.nearest_person_y = 0.0
51
        signal.signal(signal.SIGINT, self.signal_handler)
52

  
53
    def signal_handler(self, signal, frame):
54
            print ">>> ROS is about to exit (signal %s)..." % str(signal)
55
            self.run = False
56

  
57
    def people_callback(self, ros_data):
58
        # Determine the nearest person
59
        idx = -1
60
        max_distance = {}
61
        for person in ros_data.people:
62
            idx += 1
63
            max_distance[str(idx)] = person.position.z
64
        print ">> Persons found {idx, distance}: ", max_distance
65
        sort = sorted(max_distance.items(), key=operator.itemgetter(1), reverse=True)
66
        print ">> Nearest Face: ", sort
67
        print ">> Index: ", sort[0][0]
68
        print ">> Distance in pixels: ", sort[0][1]
69
        self.nearest_person_x = ros_data.people[int(sort[0][0])].position.x
70
        self.nearest_person_y = ros_data.people[int(sort[0][0])].position.y
71
        print ">> Position in pixels x:", self.nearest_person_x
72
        print ">> Position in pixels y:", self.nearest_person_y
73
        point = [self.nearest_person_x, self.nearest_person_y]
74
        # Derive coordinate mapping
75
        angles = self.at.derive_mapping_coords(point)
76
        print "----------------"
77
        if angles is not None:
78
            # Set the robot gaze
79
            g = RobotGaze()
80
            g.gaze_type = RobotGaze.GAZETARGET_ABSOLUTE
81
            g.pan = angles[0]
82
            g.tilt = angles[1]
83
            print ">> Sending Gaze Type:", g
84
            self.rc.robot_controller.set_gaze_target(g, False)
85

  
86
    def run_subscriber(self):
87
        print(">>> Initializing Gaze Subscriber")
88
        person_subscriber = rospy.Subscriber(self.inscope, People, self.people_callback, queue_size=1)
89
        while self.run:
90
            time.sleep(1)
91
        person_subscriber.unregister()
92
        print ">>> Deactivating ROS Subscriber"
93

  
94
    def derive_gaze_angle(self):
95
        pass
96

  
97

  
98
class AffineTransform:
99
    """
100
    Derives the transformation between screen
101
    coordinates in pixels and joint axis angles in degree.
102
    """
103
    def __init__(self):
104
        print(">>> Initializing Affine Transform")
105
        # Target ---> The ones you want to map to
106
        self.target0 = [1.0, 1.0]
107
        self.target1 = [1.0, 1.0]
108
        self.target2 = [1.0, 1.0]
109
        self.target3 = [1.0, 1.0]
110

  
111
        # Origin ---> The ones that are mapped to [target0, target1, target2, target3]
112
        self.origin0 = [1.0, 1.0]
113
        self.origin1 = [1.0, 1.0]
114
        self.origin2 = [1.0, 1.0]
115
        self.origin3 = [1.0, 1.0]
116

  
117
        # Divider
118
        self.divider = 1.0
119

  
120
        # Calculated and mapped Coordinates
121
        mappedCoords = [1.0, 1.0]
122

  
123
        # Affine transformation coefficients
124
        self.An = 1.0
125
        self.Bn = 1.0
126
        self.Cn = 1.0
127
        self.Dn = 1.0
128
        self.En = 1.0
129
        self.Fn = 1.0
130

  
131
        # Test coord
132
        self.test = [1.0, 1.0]
133

  
134
    def set_coords(self):
135

  
136
        # This is the target coordinate system
137
        # Upper left corner
138
        self.target0[0] = -45.0
139
        self.target0[1] = 45.0
140

  
141
        # Lower left corner
142
        self.target1[0] = -45.0
143
        self.target1[1] = -45.0
144

  
145
        # Upper right corner
146
        self.target2[0] = 45.0
147
        self.target2[1] = 45.0
148

  
149
        # Lower right corner
150
        self.target3[0] = 45.0
151
        self.target3[1] = -45.0
152

  
153
        # This is the origin system, is mapped to [t0,t1,t2,t3]
154
        # Upper left corner
155
        self.origin0[0] = 0.0
156
        self.origin0[1] = 0.0
157

  
158
        # Lower left corner
159
        self.origin1[0] = 0.0
160
        self.origin1[1] = 240.0
161

  
162
         # Upper right corner
163
        self.origin2[0] = 320.0
164
        self.origin2[1] = 0.0
165

  
166
         # Lower right corner
167
        self.origin3[0] = 320.0
168
        self.origin3[1] = 240.0
169

  
170
        # And finally the test coordinate
171
        self.test[0] = 512.0
172
        self.test[1] = 384.0
173

  
174
    def calculate_divider(self):
175
        result = ((self.origin0[0] - self.origin2[0]) * (self.origin1[1] - self.origin2[1])) - \
176
                 ((self.origin1[0] - self.origin2[0]) * (self.origin0[1] - self.origin2[1]))
177

  
178
        if result == 0.0:
179
            print(">> Divider is ZERO - Check your Coordinates?")
180
            sys.exit(1)
181
        else:
182
            self.divider = result
183
            print(">> Divider " + str(self.divider))
184
            self.calculateAn()
185
            self.calculateBn()
186
            self.calculateCn()
187
            self.calculateDn()
188
            self.calculateEn()
189
            self.calculateFn()
190

  
191
        return result
192

  
193
    def calculateAn(self):
194
        result = ((self.target0[0] - self.target2[0]) * (self.origin1[1] - self.origin2[1])) - \
195
                 ((self.target1[0] - self.target2[0]) * (self.origin0[1] - self.origin2[1]))
196
        self.An = result
197
        print(">> An " + str(self.An))
198
        return result
199

  
200
    def calculateBn(self):
201
        result = ((self.origin0[0] - self.origin2[0]) * (self.target1[0] - self.target2[0])) - \
202
                 ((self.target0[0] - self.target2[0]) * (self.origin1[0] - self.origin2[0]))
203
        self.Bn = result
204
        print(">> Bn " + str(self.Bn))
205
        return result
206

  
207
    def calculateCn(self):
208
        result = (self.origin2[0] * self.target1[0] - self.origin1[0] * self.target2[0]) * self.origin0[1] + \
209
                 (self.origin0[0] * self.target2[0] - self.origin2[0] * self.target0[0]) * self.origin1[1] + \
210
                 (self.origin1[0] * self.target0[0] - self.origin0[0] * self.target1[0]) * self.origin2[1]
211
        self.Cn = result
212
        print(">> Cn " + str(self.Cn))
213
        return result
214

  
215
    def calculateDn(self):
216
        result = ((self.target0[1] - self.target2[1]) * (self.origin1[1] - self.origin2[1])) - \
217
                 ((self.target1[1] - self.target2[1]) * (self.origin0[1] - self.origin2[1]))
218
        self.Dn = result
219
        print(">> Dn " + str(self.Dn))
220
        return result
221

  
222
    def calculateEn(self):
223
        result = ((self.origin0[0] - self.origin2[0]) * (self.target1[1] - self.target2[1])) - \
224
                 ((self.target0[1] - self.target2[1]) * (self.origin1[0] - self.origin2[0]))
225
        self.En = result
226
        print(">> En " + str(self.En))
227
        return result
228

  
229
    def calculateFn(self):
230
        result = (self.origin2[0] * self.target1[1] - self.origin1[0] * self.target2[1]) * self.origin0[1] + \
231
                 (self.origin0[0] * self.target2[1] - self.origin2[0] * self.target0[1]) * self.origin1[1] + \
232
                 (self.origin1[0] * self.target0[1] - self.origin0[0] * self.target1[1]) * self.origin2[1]
233
        self.Fn = result
234
        print(">> Fn " + str(self.Fn))
235
        return result
236

  
237
    def derive_mapping_coords(self, point):
238
        # r->x = ((matrixPtr->An * ad->x) + (matrixPtr->Bn * ad->y) + matrixPtr->Cn) / matrixPtr->Divider
239
        # r->y = ((matrixPtr->Dn * ad->x) + (matrixPtr->En * ad->y) + matrixPtr->Fn) / matrixPtr->Divider
240
        if self.divider != 0.0:
241
            x = ((self.An * point[0]) + (self.Bn * point[1]) + self.Cn) / self.divider
242
            y = ((self.Dn * point[0]) + (self.En * point[1]) + self.Fn) / self.divider
243
            result = [x, y]
244
            # print ">> Current Coordinate (Face):", point
245
            print ">> x-pixels were mapped to angle: %s \n>> y-pixels were mapped to angle: %s" % (str(x), str(y))
246
            return result
247
        else:
248
            return None
249

  
250

  
251
def runner(arguments):
252
    if len(arguments) != 3:
253
        print(">>> Usage: simple-robot-gaze.py <inscope 'persons_scope'> <outscope 'gaze_target_scope'>\n\n")
254
        sys.exit(1)
255

  
256
    rd = RobotDriver("ROS", sys.argv[2])
257
    at = AffineTransform()
258
    at.set_coords()
259
    at.calculate_divider()
260
    gc = GazeController(rd, at, sys.argv[1])
261
    gc.run_subscriber()
262

  
263
if __name__ == '__main__':
264
    runner(sys.argv)
265

  
client/python/hlrc_client/simple_robot_gaze.py
1
#!/usr/bin/python
2

  
3
__author__ = 'fl@techfak'
4

  
5
# STD IMPORTS
6
import sys
7
import time
8
import signal
9
import logging
10
import operator
11

  
12
# HLRC
13
from hlrc_client import *
14

  
15
# ROS IMPORTS
16
import rospy
17
import roslib
18
from std_msgs.msg import Header
19
from std_msgs.msg import String
20
from people_msgs.msg import Person
21
from people_msgs.msg import People
22

  
23

  
24
class RobotDriver():
25
    """
26
    This class holds the robot controller.
27
    Provides better encapsulation though...
28
    """
29
    def __init__(self, _mw, _outscope):
30
        print(">>> Initializing Robot Controller")
31
        self.mw               = _mw
32
        self.outscope         = _outscope
33
        self.robot_controller = RobotController(self.mw, self.outscope, logging.INFO)
34

  
35

  
36
class GazeController():
37
    """
38
    The GazeController receives person messages (ROS) and derives
39
    the nearest person identified. Based on this, the robot's
40
    joint angle target's are derived using the transformation
41
    class below
42
    """
43
    def __init__(self, _robot_controller, _affine_transform, _inscope):
44
        print(">>> Initializing Gaze Controller")
45
        self.run      = True
46
        self.inscope  = _inscope
47
        self.rc       = _robot_controller
48
        self.at       = _affine_transform
49
        self.nearest_person_x = 0.0
50
        self.nearest_person_y = 0.0
51
        signal.signal(signal.SIGINT, self.signal_handler)
52

  
53
    def signal_handler(self, signal, frame):
54
            print ">>> ROS is about to exit (signal %s)..." % str(signal)
55
            self.run = False
56

  
57
    def people_callback(self, ros_data):
58
        # Determine the nearest person
59
        idx = -1
60
        max_distance = {}
61
        for person in ros_data.people:
62
            idx += 1
63
            max_distance[str(idx)] = person.position.z
64
        print ">> Persons found {idx, distance}: ", max_distance
65
        sort = sorted(max_distance.items(), key=operator.itemgetter(1), reverse=True)
66
        print ">> Nearest Face: ", sort
67
        print ">> Index: ", sort[0][0]
68
        print ">> Distance in pixels: ", sort[0][1]
69
        self.nearest_person_x = ros_data.people[int(sort[0][0])].position.x
70
        self.nearest_person_y = ros_data.people[int(sort[0][0])].position.y
71
        print ">> Position in pixels x:", self.nearest_person_x
72
        print ">> Position in pixels y:", self.nearest_person_y
73
        point = [self.nearest_person_x, self.nearest_person_y]
74
        # Derive coordinate mapping
75
        angles = self.at.derive_mapping_coords(point)
76
        print "----------------"
77
        if angles is not None:
78
            # Set the robot gaze
79
            g = RobotGaze()
80
            g.gaze_type = RobotGaze.GAZETARGET_ABSOLUTE
81
            g.pan = angles[0]
82
            g.tilt = angles[1]
83
            print ">> Sending Gaze Type:", g
84
            self.rc.robot_controller.set_gaze_target(g, False)
85

  
86
    def run_subscriber(self):
87
        print(">>> Initializing Gaze Subscriber")
88
        person_subscriber = rospy.Subscriber(self.inscope, People, self.people_callback, queue_size=1)
89
        while self.run:
90
            time.sleep(1)
91
        person_subscriber.unregister()
92
        print ">>> Deactivating ROS Subscriber"
93

  
94
    def derive_gaze_angle(self):
95
        pass
96

  
97

  
98
class AffineTransform:
99
    """
100
    Derives the transformation between screen
101
    coordinates in pixels and joint axis angles in degree.
102
    """
103
    def __init__(self):
104
        print(">>> Initializing Affine Transform")
105
        # Target ---> The ones you want to map to
106
        self.target0 = [1.0, 1.0]
107
        self.target1 = [1.0, 1.0]
108
        self.target2 = [1.0, 1.0]
109
        self.target3 = [1.0, 1.0]
110

  
111
        # Origin ---> The ones that are mapped to [target0, target1, target2, target3]
112
        self.origin0 = [1.0, 1.0]
113
        self.origin1 = [1.0, 1.0]
114
        self.origin2 = [1.0, 1.0]
115
        self.origin3 = [1.0, 1.0]
116

  
117
        # Divider
118
        self.divider = 1.0
119

  
120
        # Calculated and mapped Coordinates
121
        mappedCoords = [1.0, 1.0]
122

  
123
        # Affine transformation coefficients
124
        self.An = 1.0
125
        self.Bn = 1.0
126
        self.Cn = 1.0
127
        self.Dn = 1.0
128
        self.En = 1.0
129
        self.Fn = 1.0
130

  
131
        # Test coord
132
        self.test = [1.0, 1.0]
133

  
134
    def set_coords(self):
135

  
136
        # This is the target coordinate system
137
        # Upper left corner
138
        self.target0[0] = -45.0
139
        self.target0[1] = 45.0
140

  
141
        # Lower left corner
142
        self.target1[0] = -45.0
143
        self.target1[1] = -45.0
144

  
145
        # Upper right corner
146
        self.target2[0] = 45.0
147
        self.target2[1] = 45.0
148

  
149
        # Lower right corner
150
        self.target3[0] = 45.0
151
        self.target3[1] = -45.0
152

  
153
        # This is the origin system, is mapped to [t0,t1,t2,t3]
154
        # Upper left corner
155
        self.origin0[0] = 0.0
156
        self.origin0[1] = 0.0
157

  
158
        # Lower left corner
159
        self.origin1[0] = 0.0
160
        self.origin1[1] = 240.0
161

  
162
         # Upper right corner
163
        self.origin2[0] = 320.0
164
        self.origin2[1] = 0.0
165

  
166
         # Lower right corner
167
        self.origin3[0] = 320.0
168
        self.origin3[1] = 240.0
169

  
170
        # And finally the test coordinate
171
        self.test[0] = 512.0
172
        self.test[1] = 384.0
173

  
174
    def calculate_divider(self):
175
        result = ((self.origin0[0] - self.origin2[0]) * (self.origin1[1] - self.origin2[1])) - \
176
                 ((self.origin1[0] - self.origin2[0]) * (self.origin0[1] - self.origin2[1]))
177

  
178
        if result == 0.0:
179
            print(">> Divider is ZERO - Check your Coordinates?")
180
            sys.exit(1)
181
        else:
182
            self.divider = result
183
            print(">> Divider " + str(self.divider))
184
            self.calculateAn()
185
            self.calculateBn()
186
            self.calculateCn()
187
            self.calculateDn()
188
            self.calculateEn()
189
            self.calculateFn()
190

  
191
        return result
192

  
193
    def calculateAn(self):
194
        result = ((self.target0[0] - self.target2[0]) * (self.origin1[1] - self.origin2[1])) - \
195
                 ((self.target1[0] - self.target2[0]) * (self.origin0[1] - self.origin2[1]))
196
        self.An = result
197
        print(">> An " + str(self.An))
198
        return result
199

  
200
    def calculateBn(self):
201
        result = ((self.origin0[0] - self.origin2[0]) * (self.target1[0] - self.target2[0])) - \
202
                 ((self.target0[0] - self.target2[0]) * (self.origin1[0] - self.origin2[0]))
203
        self.Bn = result
204
        print(">> Bn " + str(self.Bn))
205
        return result
206

  
207
    def calculateCn(self):
208
        result = (self.origin2[0] * self.target1[0] - self.origin1[0] * self.target2[0]) * self.origin0[1] + \
209
                 (self.origin0[0] * self.target2[0] - self.origin2[0] * self.target0[0]) * self.origin1[1] + \
210
                 (self.origin1[0] * self.target0[0] - self.origin0[0] * self.target1[0]) * self.origin2[1]
211
        self.Cn = result
212
        print(">> Cn " + str(self.Cn))
213
        return result
214

  
215
    def calculateDn(self):
216
        result = ((self.target0[1] - self.target2[1]) * (self.origin1[1] - self.origin2[1])) - \
217
                 ((self.target1[1] - self.target2[1]) * (self.origin0[1] - self.origin2[1]))
218
        self.Dn = result
219
        print(">> Dn " + str(self.Dn))
220
        return result
221

  
222
    def calculateEn(self):
223
        result = ((self.origin0[0] - self.origin2[0]) * (self.target1[1] - self.target2[1])) - \
224
                 ((self.target0[1] - self.target2[1]) * (self.origin1[0] - self.origin2[0]))
225
        self.En = result
226
        print(">> En " + str(self.En))
227
        return result
228

  
229
    def calculateFn(self):
230
        result = (self.origin2[0] * self.target1[1] - self.origin1[0] * self.target2[1]) * self.origin0[1] + \
231
                 (self.origin0[0] * self.target2[1] - self.origin2[0] * self.target0[1]) * self.origin1[1] + \
232
                 (self.origin1[0] * self.target0[1] - self.origin0[0] * self.target1[1]) * self.origin2[1]
233
        self.Fn = result
234
        print(">> Fn " + str(self.Fn))
235
        return result
236

  
237
    def derive_mapping_coords(self, point):
238
        # r->x = ((matrixPtr->An * ad->x) + (matrixPtr->Bn * ad->y) + matrixPtr->Cn) / matrixPtr->Divider
239
        # r->y = ((matrixPtr->Dn * ad->x) + (matrixPtr->En * ad->y) + matrixPtr->Fn) / matrixPtr->Divider
240
        if self.divider != 0.0:
241
            x = ((self.An * point[0]) + (self.Bn * point[1]) + self.Cn) / self.divider
242
            y = ((self.Dn * point[0]) + (self.En * point[1]) + self.Fn) / self.divider
243
            result = [x, y]
244
            # print ">> Current Coordinate (Face):", point
245
            print ">> x-pixels were mapped to angle: %s \n>> y-pixels were mapped to angle: %s" % (str(x), str(y))
246
            return result
247
        else:
248
            return None
249

  
250

  
251
def runner(arguments):
252
    if len(arguments) != 3:
253
        print(">>> Usage: simple_robot_gaze.py <inscope 'persons_scope'> <outscope 'gaze_target_scope'>\n\n")
254
        sys.exit(1)
255

  
256
    rd = RobotDriver("ROS", sys.argv[2])
257
    at = AffineTransform()
258
    at.set_coords()
259
    at.calculate_divider()
260
    gc = GazeController(rd, at, sys.argv[1])
261
    gc.run_subscriber()
262

  
263
if __name__ == '__main__':
264
    runner(sys.argv)
265

  
client/python/setup.py
108 108
    entry_points={
109 109
        'console_scripts': [
110 110
            'hlrc_test_gui=hlrc_client.hlrc_test_gui:main',
111
            'simple_robot_gaze=hlrc_client.simple-robot-gaze:main'
111
            'simple_robot_gaze=hlrc_client.simple_robot_gaze:main'
112 112
        ],
113 113
    },
114 114
)

Also available in: Unified diff