Skip to content

Commit a59ae28

Browse files
committed
Add plainpin display integraton
1 parent 0b42382 commit a59ae28

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#!/usr/bin/env python3
2+
import rclpy
3+
from rclpy.node import Node
4+
import pygame
5+
import time
6+
from geometry_msgs.msg import Point
7+
from coffee_expressions_msgs.msg import AffectiveState
8+
import os
9+
import sys
10+
11+
# Add the src directory to Python path
12+
src_path = os.path.join(os.path.dirname(__file__), 'plaipin', 'display_pi', 'src')
13+
if src_path not in sys.path:
14+
sys.path.insert(0, src_path)
15+
16+
# Import plaipin modules
17+
from viz.application import Application
18+
from viz.config import EyeConfig
19+
from viz.state_manager import StateManager
20+
from viz_eye_controller import VizEyeController
21+
22+
class PlaipinExpressiveEyes(Node):
23+
"""ROS2 node for controlling expressive eyes using the plaipin visualization package."""
24+
25+
def __init__(self):
26+
super().__init__('plaipin_expressive_eyes')
27+
28+
# Initialize Pygame and Plaipin components
29+
pygame.init()
30+
self.screen_width = 800
31+
self.screen_height = 400
32+
self.screen = pygame.display.set_mode((self.screen_width, self.screen_height))
33+
pygame.display.set_caption("Coffee Buddy - Plaipin Eyes")
34+
35+
# Initialize Plaipin application and controller
36+
self.app = Application(self.screen, self.screen_height)
37+
self.eye_controller = VizEyeController(self.app)
38+
39+
# Initialize state
40+
self.current_expression = "neutral"
41+
self.last_update = self.get_clock().now()
42+
43+
# Create subscription
44+
self.subscription = self.create_subscription(
45+
AffectiveState,
46+
'affective_state',
47+
self.affective_state_callback,
48+
10)
49+
50+
# Create timer for animation updates
51+
self.create_timer(0.016, self.update_animation) # ~60 FPS
52+
53+
def affective_state_callback(self, msg: AffectiveState):
54+
"""Handle incoming affective state messages."""
55+
# Map ROS expression to plaipin expression
56+
expression = msg.expression.lower()
57+
if expression == "happy":
58+
plaipin_expression = "joy1"
59+
elif expression == "curious":
60+
plaipin_expression = "curious"
61+
elif expression == "angry":
62+
plaipin_expression = "ang"
63+
elif expression == "sad":
64+
plaipin_expression = "sad_tired"
65+
elif expression == "loving":
66+
plaipin_expression = "leftheart"
67+
else:
68+
plaipin_expression = "neutral"
69+
70+
# Set the expression
71+
self.eye_controller.set_expression(plaipin_expression)
72+
73+
# Update gaze target if not idle
74+
if not msg.is_idle:
75+
# Convert ROS Point to normalized coordinates for plaipin
76+
# Assuming gaze_target is in the range [-1, 1] for x and y
77+
self.eye_controller.set_target_position(
78+
(msg.gaze_target.x, msg.gaze_target.y)
79+
)
80+
else:
81+
# Return to center when idle
82+
self.eye_controller.set_target_position((0.0, 0.0))
83+
84+
def update_animation(self):
85+
"""Update the animation state and render."""
86+
# Handle Pygame events
87+
for event in pygame.event.get():
88+
if event.type == pygame.QUIT:
89+
self.destroy_node()
90+
pygame.quit()
91+
rclpy.shutdown()
92+
return
93+
94+
# Update plaipin animation
95+
self.app.update()
96+
97+
# Render
98+
self.screen.fill((0, 0, 0)) # Clear screen
99+
self.app.render()
100+
pygame.display.flip()
101+
102+
def destroy_node(self):
103+
"""Clean up resources."""
104+
pygame.quit()
105+
super().destroy_node()
106+
107+
def main(args=None):
108+
rclpy.init(args=args)
109+
node = PlaipinExpressiveEyes()
110+
try:
111+
rclpy.spin(node)
112+
except KeyboardInterrupt:
113+
pass
114+
finally:
115+
node.destroy_node()
116+
rclpy.shutdown()
117+
118+
if __name__ == '__main__':
119+
main()

coffee_ws/src/coffee_expressions/setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
entry_points={
2525
'console_scripts': [
2626
'expressive_eyes = coffee_expressions.expressive_eyes:main',
27+
'plaipin_expressive_eyes = coffee_expressions.plaipin_expressive_eyes:main',
2728
],
2829
},
2930
)

0 commit comments

Comments
 (0)