feat: gestures to ri
This commit is contained in:
@@ -7,6 +7,7 @@ from robot_interface.endpoints.receiver_base import ReceiverBase
|
|||||||
from robot_interface.state import state
|
from robot_interface.state import state
|
||||||
|
|
||||||
from robot_interface.core.config import settings
|
from robot_interface.core.config import settings
|
||||||
|
from robot_interface.endpoints.gesture_settings import GestureTags
|
||||||
|
|
||||||
|
|
||||||
class ActuationReceiver(ReceiverBase):
|
class ActuationReceiver(ReceiverBase):
|
||||||
@@ -21,12 +22,16 @@ class ActuationReceiver(ReceiverBase):
|
|||||||
|
|
||||||
:ivar _tts_service: The text-to-speech service object from the Qi session.
|
:ivar _tts_service: The text-to-speech service object from the Qi session.
|
||||||
:vartype _tts_service: qi.Session | None
|
:vartype _tts_service: qi.Session | None
|
||||||
|
|
||||||
|
:ivar _animation_service: The animation/gesture service object from the Qi session.
|
||||||
|
:vartype _animation_service: qi.Session | None
|
||||||
"""
|
"""
|
||||||
def __init__(self, zmq_context, port=settings.agent_settings.actuation_receiver_port):
|
def __init__(self, zmq_context, port=settings.agent_settings.actuation_receiver_port):
|
||||||
super(ActuationReceiver, self).__init__("actuation")
|
super(ActuationReceiver, self).__init__("actuation")
|
||||||
self.create_socket(zmq_context, zmq.SUB, port)
|
self.create_socket(zmq_context, zmq.SUB, port)
|
||||||
self.socket.setsockopt_string(zmq.SUBSCRIBE, u"") # Causes block if given in options
|
self.socket.setsockopt_string(zmq.SUBSCRIBE, u"") # Causes block if given in options
|
||||||
self._tts_service = None
|
self._tts_service = None
|
||||||
|
self._animation_service = None
|
||||||
|
|
||||||
def _handle_speech(self, message):
|
def _handle_speech(self, message):
|
||||||
"""
|
"""
|
||||||
@@ -54,7 +59,54 @@ class ActuationReceiver(ReceiverBase):
|
|||||||
self._tts_service = state.qi_session.service("ALTextToSpeech")
|
self._tts_service = state.qi_session.service("ALTextToSpeech")
|
||||||
|
|
||||||
# Returns instantly. Messages received while speaking will be queued.
|
# Returns instantly. Messages received while speaking will be queued.
|
||||||
qi.async(self._tts_service.say, text)
|
getattr(qi, "async")(self._tts_service.say, text)
|
||||||
|
|
||||||
|
def _handle_gesture(self, message, is_single):
|
||||||
|
"""
|
||||||
|
Handle a gesture actuation request.
|
||||||
|
|
||||||
|
:param message: The gesture to do, must contain properties "endpoint" and "data".
|
||||||
|
:type message: dict
|
||||||
|
|
||||||
|
:param is_single: Whether it's a specific single gesture or a gesture tag.
|
||||||
|
:type is_single: bool
|
||||||
|
"""
|
||||||
|
|
||||||
|
gesture = message.get("data")
|
||||||
|
if not gesture:
|
||||||
|
logging.warn("Received gesture to do, but it lacks data.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not isinstance(gesture, (str, unicode)):
|
||||||
|
logging.warn("Received gesture to do but it is not a string.")
|
||||||
|
return
|
||||||
|
|
||||||
|
logging.debug("Received gesture to do: {}".format(gesture))
|
||||||
|
|
||||||
|
if is_single:
|
||||||
|
if gesture not in GestureTags.single_gestures:
|
||||||
|
logging.warn("Received single gesture to do, but it does not exist in settings")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
if gesture not in GestureTags.tags:
|
||||||
|
logging.warn("Received single tag to do, but it does not exist in settings")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not state.qi_session: return
|
||||||
|
# If state has a qi_session, we know that we can import qi
|
||||||
|
import qi # Takes a while only the first time it's imported
|
||||||
|
|
||||||
|
if not self._animation_service:
|
||||||
|
self._animation_service = state.qi_session.service("ALAnimationPlayer")
|
||||||
|
|
||||||
|
# Play the gesture. Pepper comes with predefined animations like "Wave", "Greet", "Clap"
|
||||||
|
# You can also create custom animations using Choregraphe and upload them to the robot.
|
||||||
|
if is_single:
|
||||||
|
logging.debug("Playing single gesture: {}".format(gesture))
|
||||||
|
getattr(qi, "async")(self._animation_service.run, gesture)
|
||||||
|
else:
|
||||||
|
logging.debug("Playing tag gesture: {}".format(gesture))
|
||||||
|
getattr(qi, "async")(self._animation_service.runTag, gesture)
|
||||||
|
|
||||||
def handle_message(self, message):
|
def handle_message(self, message):
|
||||||
"""
|
"""
|
||||||
@@ -65,3 +117,17 @@ class ActuationReceiver(ReceiverBase):
|
|||||||
"""
|
"""
|
||||||
if message["endpoint"] == "actuate/speech":
|
if message["endpoint"] == "actuate/speech":
|
||||||
self._handle_speech(message)
|
self._handle_speech(message)
|
||||||
|
if message["endpoint"] == "actuate/gesture/tag":
|
||||||
|
self._handle_gesture(message, False)
|
||||||
|
if message["endpoint"] == "actuate/gesture/single":
|
||||||
|
self._handle_gesture(message, True)
|
||||||
|
|
||||||
|
def endpoint_description(self):
|
||||||
|
"""
|
||||||
|
Extend the default endpoint description with gesture tags.
|
||||||
|
Returned during negotiate/ports so the CB knows available gestures.
|
||||||
|
"""
|
||||||
|
desc = super(ActuationReceiver, self).endpoint_description()
|
||||||
|
desc["gestures"] = GestureTags.tags
|
||||||
|
desc["single_gestures"] = GestureTags.single_gestures
|
||||||
|
return desc
|
||||||
|
|||||||
412
src/robot_interface/endpoints/gesture_settings.py
Normal file
412
src/robot_interface/endpoints/gesture_settings.py
Normal file
@@ -0,0 +1,412 @@
|
|||||||
|
class GestureTags:
|
||||||
|
tags = ["above", "affirmative", "afford", "agitated", "all", "allright", "alright", "any",
|
||||||
|
"assuage", "assuage", "attemper", "back", "bashful", "beg", "beseech", "blank",
|
||||||
|
"body language", "bored", "bow", "but", "call", "calm", "choose", "choice", "cloud",
|
||||||
|
"cogitate", "cool", "crazy", "disappointed", "down", "earth", "empty", "embarrassed",
|
||||||
|
"enthusiastic", "entire", "estimate", "except", "exalted", "excited", "explain", "far",
|
||||||
|
"field", "floor", "forlorn", "friendly", "front", "frustrated", "gentle", "gift",
|
||||||
|
"give", "ground", "happy", "hello", "her", "here", "hey", "hi", "him", "hopeless",
|
||||||
|
"hysterical", "I", "implore", "indicate", "joyful", "me", "meditate", "modest",
|
||||||
|
"negative", "nervous", "no", "not know", "nothing", "offer", "ok", "once upon a time",
|
||||||
|
"oppose", "or", "pacify", "pick", "placate", "please", "present", "proffer", "quiet",
|
||||||
|
"reason", "refute", "reject", "rousing", "sad", "select", "shamefaced", "show",
|
||||||
|
"show sky", "sky", "soothe", "sun", "supplicate", "tablet", "tall", "them", "there",
|
||||||
|
"think", "timid", "top", "unless", "up", "upstairs", "void", "warm", "winner", "yeah",
|
||||||
|
"yes", "yoo-hoo", "you", "your", "zero", "zestful"]
|
||||||
|
|
||||||
|
single_gestures = [
|
||||||
|
"animations/Stand/BodyTalk/Listening/Listening_1",
|
||||||
|
"animations/Stand/BodyTalk/Listening/Listening_2",
|
||||||
|
"animations/Stand/BodyTalk/Listening/Listening_3",
|
||||||
|
"animations/Stand/BodyTalk/Listening/Listening_4",
|
||||||
|
"animations/Stand/BodyTalk/Listening/Listening_5",
|
||||||
|
"animations/Stand/BodyTalk/Listening/Listening_6",
|
||||||
|
"animations/Stand/BodyTalk/Listening/Listening_7",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_1",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_10",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_11",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_12",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_13",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_14",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_15",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_16",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_2",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_3",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_4",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_5",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_6",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_7",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_8",
|
||||||
|
"animations/Stand/BodyTalk/Speaking/BodyTalk_9",
|
||||||
|
"animations/Stand/BodyTalk/Thinking/Remember_1",
|
||||||
|
"animations/Stand/BodyTalk/Thinking/Remember_2",
|
||||||
|
"animations/Stand/BodyTalk/Thinking/Remember_3",
|
||||||
|
"animations/Stand/BodyTalk/Thinking/ThinkingLoop_1",
|
||||||
|
"animations/Stand/BodyTalk/Thinking/ThinkingLoop_2",
|
||||||
|
"animations/Stand/Emotions/Negative/Angry_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Angry_2",
|
||||||
|
"animations/Stand/Emotions/Negative/Angry_3",
|
||||||
|
"animations/Stand/Emotions/Negative/Angry_4",
|
||||||
|
"animations/Stand/Emotions/Negative/Anxious_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Bored_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Bored_2",
|
||||||
|
"animations/Stand/Emotions/Negative/Disappointed_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Exhausted_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Exhausted_2",
|
||||||
|
"animations/Stand/Emotions/Negative/Fear_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Fear_2",
|
||||||
|
"animations/Stand/Emotions/Negative/Fearful_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Frustrated_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Humiliated_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Hurt_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Hurt_2",
|
||||||
|
"animations/Stand/Emotions/Negative/Late_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Sad_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Sad_2",
|
||||||
|
"animations/Stand/Emotions/Negative/Shocked_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Sorry_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Surprise_1",
|
||||||
|
"animations/Stand/Emotions/Negative/Surprise_2",
|
||||||
|
"animations/Stand/Emotions/Negative/Surprise_3",
|
||||||
|
"animations/Stand/Emotions/Neutral/Alienated_1",
|
||||||
|
"animations/Stand/Emotions/Neutral/AskForAttention_1",
|
||||||
|
"animations/Stand/Emotions/Neutral/AskForAttention_2",
|
||||||
|
"animations/Stand/Emotions/Neutral/AskForAttention_3",
|
||||||
|
"animations/Stand/Emotions/Neutral/Cautious_1",
|
||||||
|
"animations/Stand/Emotions/Neutral/Confused_1",
|
||||||
|
"animations/Stand/Emotions/Neutral/Determined_1",
|
||||||
|
"animations/Stand/Emotions/Neutral/Embarrassed_1",
|
||||||
|
"animations/Stand/Emotions/Neutral/Hesitation_1",
|
||||||
|
"animations/Stand/Emotions/Neutral/Innocent_1",
|
||||||
|
"animations/Stand/Emotions/Neutral/Lonely_1",
|
||||||
|
"animations/Stand/Emotions/Neutral/Mischievous_1",
|
||||||
|
"animations/Stand/Emotions/Neutral/Puzzled_1",
|
||||||
|
"animations/Stand/Emotions/Neutral/Sneeze",
|
||||||
|
"animations/Stand/Emotions/Neutral/Stubborn_1",
|
||||||
|
"animations/Stand/Emotions/Neutral/Suspicious_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Amused_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Confident_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Ecstatic_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Enthusiastic_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Excited_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Excited_2",
|
||||||
|
"animations/Stand/Emotions/Positive/Excited_3",
|
||||||
|
"animations/Stand/Emotions/Positive/Happy_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Happy_2",
|
||||||
|
"animations/Stand/Emotions/Positive/Happy_3",
|
||||||
|
"animations/Stand/Emotions/Positive/Happy_4",
|
||||||
|
"animations/Stand/Emotions/Positive/Hungry_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Hysterical_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Interested_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Interested_2",
|
||||||
|
"animations/Stand/Emotions/Positive/Laugh_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Laugh_2",
|
||||||
|
"animations/Stand/Emotions/Positive/Laugh_3",
|
||||||
|
"animations/Stand/Emotions/Positive/Mocker_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Optimistic_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Peaceful_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Proud_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Proud_2",
|
||||||
|
"animations/Stand/Emotions/Positive/Proud_3",
|
||||||
|
"animations/Stand/Emotions/Positive/Relieved_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Shy_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Shy_2",
|
||||||
|
"animations/Stand/Emotions/Positive/Sure_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Winner_1",
|
||||||
|
"animations/Stand/Emotions/Positive/Winner_2",
|
||||||
|
"animations/Stand/Gestures/Angry_1",
|
||||||
|
"animations/Stand/Gestures/Angry_2",
|
||||||
|
"animations/Stand/Gestures/Angry_3",
|
||||||
|
"animations/Stand/Gestures/BowShort_1",
|
||||||
|
"animations/Stand/Gestures/BowShort_2",
|
||||||
|
"animations/Stand/Gestures/BowShort_3",
|
||||||
|
"animations/Stand/Gestures/But_1",
|
||||||
|
"animations/Stand/Gestures/CalmDown_1",
|
||||||
|
"animations/Stand/Gestures/CalmDown_2",
|
||||||
|
"animations/Stand/Gestures/CalmDown_3",
|
||||||
|
"animations/Stand/Gestures/CalmDown_4",
|
||||||
|
"animations/Stand/Gestures/CalmDown_5",
|
||||||
|
"animations/Stand/Gestures/CalmDown_6",
|
||||||
|
"animations/Stand/Gestures/Choice_1",
|
||||||
|
"animations/Stand/Gestures/ComeOn_1",
|
||||||
|
"animations/Stand/Gestures/Confused_1",
|
||||||
|
"animations/Stand/Gestures/Confused_2",
|
||||||
|
"animations/Stand/Gestures/CountFive_1",
|
||||||
|
"animations/Stand/Gestures/CountFour_1",
|
||||||
|
"animations/Stand/Gestures/CountMore_1",
|
||||||
|
"animations/Stand/Gestures/CountOne_1",
|
||||||
|
"animations/Stand/Gestures/CountThree_1",
|
||||||
|
"animations/Stand/Gestures/CountTwo_1",
|
||||||
|
"animations/Stand/Gestures/Desperate_1",
|
||||||
|
"animations/Stand/Gestures/Desperate_2",
|
||||||
|
"animations/Stand/Gestures/Desperate_3",
|
||||||
|
"animations/Stand/Gestures/Desperate_4",
|
||||||
|
"animations/Stand/Gestures/Desperate_5",
|
||||||
|
"animations/Stand/Gestures/DontUnderstand_1",
|
||||||
|
"animations/Stand/Gestures/Enthusiastic_3",
|
||||||
|
"animations/Stand/Gestures/Enthusiastic_4",
|
||||||
|
"animations/Stand/Gestures/Enthusiastic_5",
|
||||||
|
"animations/Stand/Gestures/Everything_1",
|
||||||
|
"animations/Stand/Gestures/Everything_2",
|
||||||
|
"animations/Stand/Gestures/Everything_3",
|
||||||
|
"animations/Stand/Gestures/Everything_4",
|
||||||
|
"animations/Stand/Gestures/Everything_6",
|
||||||
|
"animations/Stand/Gestures/Excited_1",
|
||||||
|
"animations/Stand/Gestures/Explain_1",
|
||||||
|
"animations/Stand/Gestures/Explain_10",
|
||||||
|
"animations/Stand/Gestures/Explain_11",
|
||||||
|
"animations/Stand/Gestures/Explain_2",
|
||||||
|
"animations/Stand/Gestures/Explain_3",
|
||||||
|
"animations/Stand/Gestures/Explain_4",
|
||||||
|
"animations/Stand/Gestures/Explain_5",
|
||||||
|
"animations/Stand/Gestures/Explain_6",
|
||||||
|
"animations/Stand/Gestures/Explain_7",
|
||||||
|
"animations/Stand/Gestures/Explain_8",
|
||||||
|
"animations/Stand/Gestures/Far_1",
|
||||||
|
"animations/Stand/Gestures/Far_2",
|
||||||
|
"animations/Stand/Gestures/Far_3",
|
||||||
|
"animations/Stand/Gestures/Follow_1",
|
||||||
|
"animations/Stand/Gestures/Give_1",
|
||||||
|
"animations/Stand/Gestures/Give_2",
|
||||||
|
"animations/Stand/Gestures/Give_3",
|
||||||
|
"animations/Stand/Gestures/Give_4",
|
||||||
|
"animations/Stand/Gestures/Give_5",
|
||||||
|
"animations/Stand/Gestures/Give_6",
|
||||||
|
"animations/Stand/Gestures/Great_1",
|
||||||
|
"animations/Stand/Gestures/HeSays_1",
|
||||||
|
"animations/Stand/Gestures/HeSays_2",
|
||||||
|
"animations/Stand/Gestures/HeSays_3",
|
||||||
|
"animations/Stand/Gestures/Hey_1",
|
||||||
|
"animations/Stand/Gestures/Hey_10",
|
||||||
|
"animations/Stand/Gestures/Hey_2",
|
||||||
|
"animations/Stand/Gestures/Hey_3",
|
||||||
|
"animations/Stand/Gestures/Hey_4",
|
||||||
|
"animations/Stand/Gestures/Hey_6",
|
||||||
|
"animations/Stand/Gestures/Hey_7",
|
||||||
|
"animations/Stand/Gestures/Hey_8",
|
||||||
|
"animations/Stand/Gestures/Hey_9",
|
||||||
|
"animations/Stand/Gestures/Hide_1",
|
||||||
|
"animations/Stand/Gestures/Hot_1",
|
||||||
|
"animations/Stand/Gestures/Hot_2",
|
||||||
|
"animations/Stand/Gestures/IDontKnow_1",
|
||||||
|
"animations/Stand/Gestures/IDontKnow_2",
|
||||||
|
"animations/Stand/Gestures/IDontKnow_3",
|
||||||
|
"animations/Stand/Gestures/IDontKnow_4",
|
||||||
|
"animations/Stand/Gestures/IDontKnow_5",
|
||||||
|
"animations/Stand/Gestures/IDontKnow_6",
|
||||||
|
"animations/Stand/Gestures/Joy_1",
|
||||||
|
"animations/Stand/Gestures/Kisses_1",
|
||||||
|
"animations/Stand/Gestures/Look_1",
|
||||||
|
"animations/Stand/Gestures/Look_2",
|
||||||
|
"animations/Stand/Gestures/Maybe_1",
|
||||||
|
"animations/Stand/Gestures/Me_1",
|
||||||
|
"animations/Stand/Gestures/Me_2",
|
||||||
|
"animations/Stand/Gestures/Me_4",
|
||||||
|
"animations/Stand/Gestures/Me_7",
|
||||||
|
"animations/Stand/Gestures/Me_8",
|
||||||
|
"animations/Stand/Gestures/Mime_1",
|
||||||
|
"animations/Stand/Gestures/Mime_2",
|
||||||
|
"animations/Stand/Gestures/Next_1",
|
||||||
|
"animations/Stand/Gestures/No_1",
|
||||||
|
"animations/Stand/Gestures/No_2",
|
||||||
|
"animations/Stand/Gestures/No_3",
|
||||||
|
"animations/Stand/Gestures/No_4",
|
||||||
|
"animations/Stand/Gestures/No_5",
|
||||||
|
"animations/Stand/Gestures/No_6",
|
||||||
|
"animations/Stand/Gestures/No_7",
|
||||||
|
"animations/Stand/Gestures/No_8",
|
||||||
|
"animations/Stand/Gestures/No_9",
|
||||||
|
"animations/Stand/Gestures/Nothing_1",
|
||||||
|
"animations/Stand/Gestures/Nothing_2",
|
||||||
|
"animations/Stand/Gestures/OnTheEvening_1",
|
||||||
|
"animations/Stand/Gestures/OnTheEvening_2",
|
||||||
|
"animations/Stand/Gestures/OnTheEvening_3",
|
||||||
|
"animations/Stand/Gestures/OnTheEvening_4",
|
||||||
|
"animations/Stand/Gestures/OnTheEvening_5",
|
||||||
|
"animations/Stand/Gestures/Please_1",
|
||||||
|
"animations/Stand/Gestures/Please_2",
|
||||||
|
"animations/Stand/Gestures/Please_3",
|
||||||
|
"animations/Stand/Gestures/Reject_1",
|
||||||
|
"animations/Stand/Gestures/Reject_2",
|
||||||
|
"animations/Stand/Gestures/Reject_3",
|
||||||
|
"animations/Stand/Gestures/Reject_4",
|
||||||
|
"animations/Stand/Gestures/Reject_5",
|
||||||
|
"animations/Stand/Gestures/Reject_6",
|
||||||
|
"animations/Stand/Gestures/Salute_1",
|
||||||
|
"animations/Stand/Gestures/Salute_2",
|
||||||
|
"animations/Stand/Gestures/Salute_3",
|
||||||
|
"animations/Stand/Gestures/ShowFloor_1",
|
||||||
|
"animations/Stand/Gestures/ShowFloor_2",
|
||||||
|
"animations/Stand/Gestures/ShowFloor_3",
|
||||||
|
"animations/Stand/Gestures/ShowFloor_4",
|
||||||
|
"animations/Stand/Gestures/ShowFloor_5",
|
||||||
|
"animations/Stand/Gestures/ShowSky_1",
|
||||||
|
"animations/Stand/Gestures/ShowSky_10",
|
||||||
|
"animations/Stand/Gestures/ShowSky_11",
|
||||||
|
"animations/Stand/Gestures/ShowSky_12",
|
||||||
|
"animations/Stand/Gestures/ShowSky_2",
|
||||||
|
"animations/Stand/Gestures/ShowSky_3",
|
||||||
|
"animations/Stand/Gestures/ShowSky_4",
|
||||||
|
"animations/Stand/Gestures/ShowSky_5",
|
||||||
|
"animations/Stand/Gestures/ShowSky_6",
|
||||||
|
"animations/Stand/Gestures/ShowSky_7",
|
||||||
|
"animations/Stand/Gestures/ShowSky_8",
|
||||||
|
"animations/Stand/Gestures/ShowSky_9",
|
||||||
|
"animations/Stand/Gestures/ShowTablet_1",
|
||||||
|
"animations/Stand/Gestures/ShowTablet_2",
|
||||||
|
"animations/Stand/Gestures/ShowTablet_3",
|
||||||
|
"animations/Stand/Gestures/Shy_1",
|
||||||
|
"animations/Stand/Gestures/Stretch_1",
|
||||||
|
"animations/Stand/Gestures/Stretch_2",
|
||||||
|
"animations/Stand/Gestures/Surprised_1",
|
||||||
|
"animations/Stand/Gestures/TakePlace_1",
|
||||||
|
"animations/Stand/Gestures/TakePlace_2",
|
||||||
|
"animations/Stand/Gestures/Take_1",
|
||||||
|
"animations/Stand/Gestures/Thinking_1",
|
||||||
|
"animations/Stand/Gestures/Thinking_2",
|
||||||
|
"animations/Stand/Gestures/Thinking_3",
|
||||||
|
"animations/Stand/Gestures/Thinking_4",
|
||||||
|
"animations/Stand/Gestures/Thinking_5",
|
||||||
|
"animations/Stand/Gestures/Thinking_6",
|
||||||
|
"animations/Stand/Gestures/Thinking_7",
|
||||||
|
"animations/Stand/Gestures/Thinking_8",
|
||||||
|
"animations/Stand/Gestures/This_1",
|
||||||
|
"animations/Stand/Gestures/This_10",
|
||||||
|
"animations/Stand/Gestures/This_11",
|
||||||
|
"animations/Stand/Gestures/This_12",
|
||||||
|
"animations/Stand/Gestures/This_13",
|
||||||
|
"animations/Stand/Gestures/This_14",
|
||||||
|
"animations/Stand/Gestures/This_15",
|
||||||
|
"animations/Stand/Gestures/This_2",
|
||||||
|
"animations/Stand/Gestures/This_3",
|
||||||
|
"animations/Stand/Gestures/This_4",
|
||||||
|
"animations/Stand/Gestures/This_5",
|
||||||
|
"animations/Stand/Gestures/This_6",
|
||||||
|
"animations/Stand/Gestures/This_7",
|
||||||
|
"animations/Stand/Gestures/This_8",
|
||||||
|
"animations/Stand/Gestures/This_9",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_1",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_10",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_11",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_12",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_13",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_14",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_15",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_16",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_2",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_3",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_4",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_5",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_6",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_7",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_8",
|
||||||
|
"animations/Stand/Gestures/WhatSThis_9",
|
||||||
|
"animations/Stand/Gestures/Whisper_1",
|
||||||
|
"animations/Stand/Gestures/Wings_1",
|
||||||
|
"animations/Stand/Gestures/Wings_2",
|
||||||
|
"animations/Stand/Gestures/Wings_3",
|
||||||
|
"animations/Stand/Gestures/Wings_4",
|
||||||
|
"animations/Stand/Gestures/Wings_5",
|
||||||
|
"animations/Stand/Gestures/Yes_1",
|
||||||
|
"animations/Stand/Gestures/Yes_2",
|
||||||
|
"animations/Stand/Gestures/Yes_3",
|
||||||
|
"animations/Stand/Gestures/YouKnowWhat_1",
|
||||||
|
"animations/Stand/Gestures/YouKnowWhat_2",
|
||||||
|
"animations/Stand/Gestures/YouKnowWhat_3",
|
||||||
|
"animations/Stand/Gestures/YouKnowWhat_4",
|
||||||
|
"animations/Stand/Gestures/YouKnowWhat_5",
|
||||||
|
"animations/Stand/Gestures/YouKnowWhat_6",
|
||||||
|
"animations/Stand/Gestures/You_1",
|
||||||
|
"animations/Stand/Gestures/You_2",
|
||||||
|
"animations/Stand/Gestures/You_3",
|
||||||
|
"animations/Stand/Gestures/You_4",
|
||||||
|
"animations/Stand/Gestures/You_5",
|
||||||
|
"animations/Stand/Gestures/Yum_1",
|
||||||
|
"animations/Stand/Reactions/EthernetOff_1",
|
||||||
|
"animations/Stand/Reactions/EthernetOn_1",
|
||||||
|
"animations/Stand/Reactions/Heat_1",
|
||||||
|
"animations/Stand/Reactions/Heat_2",
|
||||||
|
"animations/Stand/Reactions/LightShine_1",
|
||||||
|
"animations/Stand/Reactions/LightShine_2",
|
||||||
|
"animations/Stand/Reactions/LightShine_3",
|
||||||
|
"animations/Stand/Reactions/LightShine_4",
|
||||||
|
"animations/Stand/Reactions/SeeColor_1",
|
||||||
|
"animations/Stand/Reactions/SeeColor_2",
|
||||||
|
"animations/Stand/Reactions/SeeColor_3",
|
||||||
|
"animations/Stand/Reactions/SeeSomething_1",
|
||||||
|
"animations/Stand/Reactions/SeeSomething_3",
|
||||||
|
"animations/Stand/Reactions/SeeSomething_4",
|
||||||
|
"animations/Stand/Reactions/SeeSomething_5",
|
||||||
|
"animations/Stand/Reactions/SeeSomething_6",
|
||||||
|
"animations/Stand/Reactions/SeeSomething_7",
|
||||||
|
"animations/Stand/Reactions/SeeSomething_8",
|
||||||
|
"animations/Stand/Reactions/ShakeBody_1",
|
||||||
|
"animations/Stand/Reactions/ShakeBody_2",
|
||||||
|
"animations/Stand/Reactions/ShakeBody_3",
|
||||||
|
"animations/Stand/Reactions/TouchHead_1",
|
||||||
|
"animations/Stand/Reactions/TouchHead_2",
|
||||||
|
"animations/Stand/Reactions/TouchHead_3",
|
||||||
|
"animations/Stand/Reactions/TouchHead_4",
|
||||||
|
"animations/Stand/Waiting/AirGuitar_1",
|
||||||
|
"animations/Stand/Waiting/BackRubs_1",
|
||||||
|
"animations/Stand/Waiting/Bandmaster_1",
|
||||||
|
"animations/Stand/Waiting/Binoculars_1",
|
||||||
|
"animations/Stand/Waiting/BreathLoop_1",
|
||||||
|
"animations/Stand/Waiting/BreathLoop_2",
|
||||||
|
"animations/Stand/Waiting/BreathLoop_3",
|
||||||
|
"animations/Stand/Waiting/CallSomeone_1",
|
||||||
|
"animations/Stand/Waiting/Drink_1",
|
||||||
|
"animations/Stand/Waiting/DriveCar_1",
|
||||||
|
"animations/Stand/Waiting/Fitness_1",
|
||||||
|
"animations/Stand/Waiting/Fitness_2",
|
||||||
|
"animations/Stand/Waiting/Fitness_3",
|
||||||
|
"animations/Stand/Waiting/FunnyDancer_1",
|
||||||
|
"animations/Stand/Waiting/HappyBirthday_1",
|
||||||
|
"animations/Stand/Waiting/Helicopter_1",
|
||||||
|
"animations/Stand/Waiting/HideEyes_1",
|
||||||
|
"animations/Stand/Waiting/HideHands_1",
|
||||||
|
"animations/Stand/Waiting/Innocent_1",
|
||||||
|
"animations/Stand/Waiting/Knight_1",
|
||||||
|
"animations/Stand/Waiting/KnockEye_1",
|
||||||
|
"animations/Stand/Waiting/KungFu_1",
|
||||||
|
"animations/Stand/Waiting/LookHand_1",
|
||||||
|
"animations/Stand/Waiting/LookHand_2",
|
||||||
|
"animations/Stand/Waiting/LoveYou_1",
|
||||||
|
"animations/Stand/Waiting/Monster_1",
|
||||||
|
"animations/Stand/Waiting/MysticalPower_1",
|
||||||
|
"animations/Stand/Waiting/PlayHands_1",
|
||||||
|
"animations/Stand/Waiting/PlayHands_2",
|
||||||
|
"animations/Stand/Waiting/PlayHands_3",
|
||||||
|
"animations/Stand/Waiting/Relaxation_1",
|
||||||
|
"animations/Stand/Waiting/Relaxation_2",
|
||||||
|
"animations/Stand/Waiting/Relaxation_3",
|
||||||
|
"animations/Stand/Waiting/Relaxation_4",
|
||||||
|
"animations/Stand/Waiting/Rest_1",
|
||||||
|
"animations/Stand/Waiting/Robot_1",
|
||||||
|
"animations/Stand/Waiting/ScratchBack_1",
|
||||||
|
"animations/Stand/Waiting/ScratchBottom_1",
|
||||||
|
"animations/Stand/Waiting/ScratchEye_1",
|
||||||
|
"animations/Stand/Waiting/ScratchHand_1",
|
||||||
|
"animations/Stand/Waiting/ScratchHead_1",
|
||||||
|
"animations/Stand/Waiting/ScratchLeg_1",
|
||||||
|
"animations/Stand/Waiting/ScratchTorso_1",
|
||||||
|
"animations/Stand/Waiting/ShowMuscles_1",
|
||||||
|
"animations/Stand/Waiting/ShowMuscles_2",
|
||||||
|
"animations/Stand/Waiting/ShowMuscles_3",
|
||||||
|
"animations/Stand/Waiting/ShowMuscles_4",
|
||||||
|
"animations/Stand/Waiting/ShowMuscles_5",
|
||||||
|
"animations/Stand/Waiting/ShowSky_1",
|
||||||
|
"animations/Stand/Waiting/ShowSky_2",
|
||||||
|
"animations/Stand/Waiting/SpaceShuttle_1",
|
||||||
|
"animations/Stand/Waiting/Stretch_1",
|
||||||
|
"animations/Stand/Waiting/Stretch_2",
|
||||||
|
"animations/Stand/Waiting/TakePicture_1",
|
||||||
|
"animations/Stand/Waiting/Taxi_1",
|
||||||
|
"animations/Stand/Waiting/Think_1",
|
||||||
|
"animations/Stand/Waiting/Think_2",
|
||||||
|
"animations/Stand/Waiting/Think_3",
|
||||||
|
"animations/Stand/Waiting/Think_4",
|
||||||
|
"animations/Stand/Waiting/Waddle_1",
|
||||||
|
"animations/Stand/Waiting/Waddle_2",
|
||||||
|
"animations/Stand/Waiting/WakeUp_1",
|
||||||
|
"animations/Stand/Waiting/Zombie_1"]
|
||||||
@@ -5,6 +5,7 @@ import pytest
|
|||||||
import zmq
|
import zmq
|
||||||
|
|
||||||
from robot_interface.endpoints.actuation_receiver import ActuationReceiver
|
from robot_interface.endpoints.actuation_receiver import ActuationReceiver
|
||||||
|
from robot_interface.endpoints.gesture_settings import GestureTags
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -94,7 +95,159 @@ def test_speech(zmq_context, mocker):
|
|||||||
|
|
||||||
mock_state.qi_session.service.assert_called_once_with("ALTextToSpeech")
|
mock_state.qi_session.service.assert_called_once_with("ALTextToSpeech")
|
||||||
|
|
||||||
mock_qi.async.assert_called_once()
|
getattr(mock_qi, "async").assert_called_once()
|
||||||
call_args = mock_qi.async.call_args[0]
|
call_args = getattr(mock_qi, "async").call_args[0]
|
||||||
assert call_args[0] == mock_tts_service.say
|
assert call_args[0] == mock_tts_service.say
|
||||||
assert call_args[1] == "Some message to speak."
|
assert call_args[1] == "Some message to speak."
|
||||||
|
|
||||||
|
|
||||||
|
def test_gesture_no_data(zmq_context, mocker):
|
||||||
|
receiver = ActuationReceiver(zmq_context)
|
||||||
|
receiver._handle_gesture({"endpoint": "actuate/gesture/single", "data": ""}, True)
|
||||||
|
# Just ensuring no crash
|
||||||
|
|
||||||
|
|
||||||
|
def test_gesture_invalid_data(zmq_context, mocker):
|
||||||
|
receiver = ActuationReceiver(zmq_context)
|
||||||
|
receiver._handle_gesture({"endpoint": "actuate/gesture/single", "data": 123}, True)
|
||||||
|
# No crash expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_gesture_single_not_found(zmq_context, mocker):
|
||||||
|
mock_tags = mocker.patch("robot_interface.endpoints.actuation_receiver.GestureTags")
|
||||||
|
mock_tags.single_gestures = ["wave", "bow"] # allowed single gestures
|
||||||
|
|
||||||
|
receiver = ActuationReceiver(zmq_context)
|
||||||
|
receiver._handle_gesture({"endpoint": "actuate/gesture/single", "data": "unknown_gesture"}, True)
|
||||||
|
# No crash expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_gesture_tag_not_found(zmq_context, mocker):
|
||||||
|
mock_tags = mocker.patch("robot_interface.endpoints.actuation_receiver.GestureTags")
|
||||||
|
mock_tags.tags = ["happy", "sad"]
|
||||||
|
|
||||||
|
receiver = ActuationReceiver(zmq_context)
|
||||||
|
receiver._handle_gesture({"endpoint": "actuate/gesture/tag", "data": "not_a_tag"}, False)
|
||||||
|
# No crash expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_gesture_no_qi_session(zmq_context, mocker):
|
||||||
|
mock_state = mocker.patch("robot_interface.endpoints.actuation_receiver.state")
|
||||||
|
mock_state.qi_session = None
|
||||||
|
|
||||||
|
mock_tags = mocker.patch("robot_interface.endpoints.actuation_receiver.GestureTags")
|
||||||
|
mock_tags.single_gestures = ["hello"]
|
||||||
|
|
||||||
|
receiver = ActuationReceiver(zmq_context)
|
||||||
|
receiver._handle_gesture({"endpoint": "actuate/gesture/single", "data": "hello"}, True)
|
||||||
|
# No crash, path returns early
|
||||||
|
|
||||||
|
|
||||||
|
def test_gesture_single_success(zmq_context, mocker):
|
||||||
|
mock_state = mocker.patch("robot_interface.endpoints.actuation_receiver.state")
|
||||||
|
mock_qi = mock.Mock()
|
||||||
|
sys.modules["qi"] = mock_qi
|
||||||
|
|
||||||
|
# Setup gesture settings
|
||||||
|
mock_tags = mocker.patch("robot_interface.endpoints.actuation_receiver.GestureTags")
|
||||||
|
mock_tags.single_gestures = ["wave"]
|
||||||
|
|
||||||
|
mock_animation_service = mock.Mock()
|
||||||
|
mock_state.qi_session = mock.Mock()
|
||||||
|
mock_state.qi_session.service.return_value = mock_animation_service
|
||||||
|
|
||||||
|
receiver = ActuationReceiver(zmq_context)
|
||||||
|
receiver._handle_gesture({"endpoint": "actuate/gesture/single", "data": "wave"}, True)
|
||||||
|
|
||||||
|
mock_state.qi_session.service.assert_called_once_with("ALAnimationPlayer")
|
||||||
|
getattr(mock_qi, "async").assert_called_once()
|
||||||
|
assert getattr(mock_qi, "async").call_args[0][0] == mock_animation_service.run
|
||||||
|
assert getattr(mock_qi, "async").call_args[0][1] == "wave"
|
||||||
|
|
||||||
|
|
||||||
|
def test_gesture_tag_success(zmq_context, mocker):
|
||||||
|
mock_state = mocker.patch("robot_interface.endpoints.actuation_receiver.state")
|
||||||
|
mock_qi = mock.Mock()
|
||||||
|
sys.modules["qi"] = mock_qi
|
||||||
|
|
||||||
|
mock_tags = mocker.patch("robot_interface.endpoints.actuation_receiver.GestureTags")
|
||||||
|
mock_tags.tags = ["greeting"]
|
||||||
|
|
||||||
|
mock_animation_service = mock.Mock()
|
||||||
|
mock_state.qi_session = mock.Mock()
|
||||||
|
mock_state.qi_session.service.return_value = mock_animation_service
|
||||||
|
|
||||||
|
receiver = ActuationReceiver(zmq_context)
|
||||||
|
receiver._handle_gesture({"endpoint": "actuate/gesture/tag", "data": "greeting"}, False)
|
||||||
|
|
||||||
|
mock_state.qi_session.service.assert_called_once_with("ALAnimationPlayer")
|
||||||
|
getattr(mock_qi, "async").assert_called_once()
|
||||||
|
assert getattr(mock_qi, "async").call_args[0][0] == mock_animation_service.runTag
|
||||||
|
assert getattr(mock_qi, "async").call_args[0][1] == "greeting"
|
||||||
|
|
||||||
|
|
||||||
|
def test_handle_message_all_routes(zmq_context, mocker):
|
||||||
|
"""
|
||||||
|
Ensures all handle_message endpoint branches route correctly.
|
||||||
|
"""
|
||||||
|
receiver = ActuationReceiver(zmq_context)
|
||||||
|
|
||||||
|
mock_speech = mocker.patch.object(receiver, "_handle_speech")
|
||||||
|
mock_gesture = mocker.patch.object(receiver, "_handle_gesture")
|
||||||
|
|
||||||
|
receiver.handle_message({"endpoint": "actuate/speech", "data": "hi"})
|
||||||
|
receiver.handle_message({"endpoint": "actuate/gesture/tag", "data": "greeting"})
|
||||||
|
receiver.handle_message({"endpoint": "actuate/gesture/single", "data": "wave"})
|
||||||
|
|
||||||
|
mock_speech.assert_called_once()
|
||||||
|
assert mock_gesture.call_count == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_endpoint_description(zmq_context, mocker):
|
||||||
|
mock_tags = mocker.patch("robot_interface.endpoints.actuation_receiver.GestureTags")
|
||||||
|
mock_tags.tags = ["happy"]
|
||||||
|
mock_tags.single_gestures = ["wave"]
|
||||||
|
|
||||||
|
receiver = ActuationReceiver(zmq_context)
|
||||||
|
desc = receiver.endpoint_description()
|
||||||
|
|
||||||
|
assert "gestures" in desc
|
||||||
|
assert desc["gestures"] == ["happy"]
|
||||||
|
|
||||||
|
assert "single_gestures" in desc
|
||||||
|
assert desc["single_gestures"] == ["wave"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_gesture_single_real_gesturetags(zmq_context, mocker):
|
||||||
|
"""
|
||||||
|
Uses the real GestureTags (no mocking) to ensure the receiver
|
||||||
|
references GestureTags.single_gestures correctly.
|
||||||
|
"""
|
||||||
|
# Ensure qi session exists so we pass the early return
|
||||||
|
mock_state = mocker.patch("robot_interface.endpoints.actuation_receiver.state")
|
||||||
|
mock_state.qi_session = mock.Mock()
|
||||||
|
|
||||||
|
# Mock qi.async to avoid real async calls
|
||||||
|
mock_qi = mock.Mock()
|
||||||
|
sys.modules["qi"] = mock_qi
|
||||||
|
|
||||||
|
# Mock animation service
|
||||||
|
mock_animation_service = mock.Mock()
|
||||||
|
mock_state.qi_session.service.return_value = mock_animation_service
|
||||||
|
|
||||||
|
receiver = ActuationReceiver(zmq_context)
|
||||||
|
|
||||||
|
# Pick a real gesture from GestureTags.single_gestures
|
||||||
|
assert len(GestureTags.single_gestures) > 0, "GestureTags.single_gestures must not be empty"
|
||||||
|
gesture = GestureTags.single_gestures[0]
|
||||||
|
|
||||||
|
receiver._handle_gesture(
|
||||||
|
{"endpoint": "actuate/gesture/single", "data": gesture},
|
||||||
|
is_single=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_state.qi_session.service.assert_called_once_with("ALAnimationPlayer")
|
||||||
|
getattr(mock_qi, "async").assert_called_once()
|
||||||
|
assert getattr(mock_qi, "async").call_args[0][0] == mock_animation_service.run
|
||||||
|
assert getattr(mock_qi, "async").call_args[0][1] == gesture
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user