Skip to content

Commit 0a29bdf

Browse files
committed
Fix rendering eyes
1 parent a86309d commit 0a29bdf

File tree

1 file changed

+69
-58
lines changed

1 file changed

+69
-58
lines changed

coffee_ws/src/coffee_expressions/coffee_expressions/plaipin_expressive_eyes.py

Lines changed: 69 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -48,43 +48,48 @@ def __init__(self):
4848
base_screen_height=400 # Match our display
4949
)
5050

51-
# Initialize Plaipin application and controller
52-
self.app = Application(self.screen_width, self.screen_height, config)
51+
# Get package share directory path
52+
from ament_index_python.packages import get_package_share_directory
53+
package_share_dir = get_package_share_directory('coffee_expressions')
54+
55+
# Get absolute path to expressions.json in the package share directory
56+
expressions_path = os.path.join(package_share_dir, 'plaipin', 'display_pi', 'src', 'expressions.json')
57+
58+
# Initialize Plaipin application and controller with expressions file path
59+
self.app = Application(self.screen_width, self.screen_height, config, expressions_file=expressions_path)
5360
self.eye_controller = VizEyeController(self.app)
5461

5562
# Initialize state
56-
self.current_expression = "neutral"
57-
self.last_update = self.get_clock().now()
63+
self.current_expression = "base_blob" # Default neutral expression
64+
self.eye_controller.set_expression(self.current_expression)
65+
self.running = True
5866

5967
# Create subscription
6068
self.subscription = self.create_subscription(
6169
AffectiveState,
6270
'affective_state',
6371
self.affective_state_callback,
6472
10)
65-
66-
# Create timer for animation updates
67-
self.create_timer(0.016, self.update_animation) # ~60 FPS
68-
73+
6974
def affective_state_callback(self, msg: AffectiveState):
7075
"""Handle incoming affective state messages."""
71-
# Map ROS expression to plaipin expression
76+
# Map ROS2 expressions to plaipin expressions
7277
expression = msg.expression.lower()
7378
if expression == "happy":
7479
plaipin_expression = "joy1"
75-
elif expression == "curious":
76-
plaipin_expression = "curious"
7780
elif expression == "angry":
7881
plaipin_expression = "ang"
7982
elif expression == "sad":
80-
plaipin_expression = "sad_tired"
83+
plaipin_expression = "sad_1"
8184
elif expression == "loving":
82-
plaipin_expression = "leftheart"
85+
plaipin_expression = "base_waitingforyoutobuy"
8386
else:
84-
plaipin_expression = "neutral"
85-
86-
# Set the expression
87-
self.eye_controller.set_expression(plaipin_expression)
87+
plaipin_expression = "base_blob"
88+
89+
# Only update if expression changed
90+
if plaipin_expression != self.current_expression:
91+
self.current_expression = plaipin_expression
92+
self.eye_controller.set_expression(plaipin_expression)
8893

8994
# Update gaze target if not idle
9095
if not msg.is_idle:
@@ -97,58 +102,64 @@ def affective_state_callback(self, msg: AffectiveState):
97102
# Return to center when idle
98103
self.eye_controller.set_eye_positions((0.0, 0.0))
99104

100-
def update_animation(self):
101-
"""Update the animation state"""
102-
# Handle events
103-
for event in pygame.event.get():
104-
if event.type == pygame.QUIT:
105-
self.destroy_node()
106-
return
107-
elif event.type == pygame.KEYDOWN:
108-
if event.key == pygame.K_ESCAPE:
109-
self.destroy_node()
110-
return
105+
def run(self):
106+
"""Main animation loop"""
107+
clock = pygame.time.Clock()
108+
109+
while self.running and rclpy.ok():
110+
# Handle events
111+
for event in pygame.event.get():
112+
if event.type == pygame.QUIT:
113+
self.running = False
114+
break
115+
elif event.type == pygame.KEYDOWN:
116+
if event.key == pygame.K_ESCAPE:
117+
self.running = False
118+
break
119+
120+
# Let the application handle other events
121+
self.app.input_handler.handle_keyboard(event)
122+
123+
# Handle UI events
124+
ui_result = self.app.ui_manager.handle_event(event)
125+
if ui_result:
126+
if ui_result == "control_points_changed":
127+
self.app.animated_eyes.update_control_points()
128+
elif ui_result == "config_changed":
129+
self.app.animated_eyes.update_eye_positions()
111130

112-
# Let the application handle other events
113-
self.app.input_handler.handle_keyboard(event)
131+
# Update the eye controller
132+
self.eye_controller.update()
114133

115-
# Handle UI events
116-
ui_result = self.app.ui_manager.handle_event(event)
117-
if ui_result:
118-
if ui_result == "control_points_changed":
119-
self.app.animated_eyes.update_control_points()
120-
elif ui_result == "config_changed":
121-
self.app.animated_eyes.update_eye_positions()
122-
123-
# Update the eye controller
124-
self.eye_controller.update()
125-
126-
# Update animated eyes
127-
self.app.animated_eyes.update()
128-
129-
# Drawing
130-
self.app.screen.fill(self.app.config.background_color)
131-
self.app.ui_manager.draw_grid()
132-
self.app.animated_eyes.draw()
133-
134-
# Update display
135-
pygame.display.flip()
134+
# Update animated eyes
135+
self.app.animated_eyes.update()
136+
137+
# Drawing
138+
self.app.screen.fill(self.app.config.background_color)
139+
self.app.ui_manager.draw_grid()
140+
self.app.animated_eyes.draw()
141+
142+
# Update display
143+
pygame.display.flip()
144+
145+
# Maintain frame rate and process ROS callbacks
146+
clock.tick(60)
147+
rclpy.spin_once(self, timeout_sec=0)
136148

137149
def destroy_node(self):
138150
"""Clean up resources."""
151+
self.running = False
139152
pygame.quit()
140153
super().destroy_node()
141154

142155
def main(args=None):
143156
rclpy.init(args=args)
157+
144158
node = PlaipinExpressiveEyes()
145-
try:
146-
rclpy.spin(node)
147-
except KeyboardInterrupt:
148-
pass
149-
finally:
150-
node.destroy_node()
151-
rclpy.shutdown()
159+
node.run()
160+
161+
node.destroy_node()
162+
rclpy.shutdown()
152163

153164
if __name__ == '__main__':
154165
main()

0 commit comments

Comments
 (0)