Making a Python module - Reacting to events

Here we want the robot say ‘Hello, you’ every time it detects a human face.

To do this, we need to subscribe to the ‘FaceDetected’ event, raised by the ALFacedetection module.

If you read the documentation of ALMemoryProxy::subscribeToEvent(), you will see you need a module name and the name of a callback.

So we need to write a NAOqi module in Python.

To create a module in Python, we also need a broker.

The example can be found below.

See also

reacting_to_events.py


# -*- encoding: UTF-8 -*-
""" Say 'hello, you' each time a human face is detected

"""

import sys
import time

from naoqi import ALProxy
from naoqi import ALBroker
from naoqi import ALModule

from optparse import OptionParser

NAO_IP = "nao.local"


# Global variable to store the HumanGreeter module instance
HumanGreeter = None
memory = None


class HumanGreeterModule(ALModule):
    """ A simple module able to react
    to facedetection events

    """
    def __init__(self, name):
        ALModule.__init__(self, name)
        # No need for IP and port here because
        # we have our Python broker connected to NAOqi broker

        # Create a proxy to ALTextToSpeech for later use
        self.tts = ALProxy("ALTextToSpeech")

        # Subscribe to the FaceDetected event:
        global memory
        memory = ALProxy("ALMemory")
        memory.subscribeToEvent("FaceDetected",
            "HumanGreeter",
            "onFaceDetected")

    def onFaceDetected(self, *_args):
        """ This will be called each time a face is
        detected.

        """
        # Unsubscribe to the event when talking,
        # to avoid repetitions
        memory.unsubscribeToEvent("FaceDetected",
            "HumanGreeter")

        self.tts.say("Hello, you")

        # Subscribe again to the event
        memory.subscribeToEvent("FaceDetected",
            "HumanGreeter",
            "onFaceDetected")


def main():
    """ Main entry point

    """
    parser = OptionParser()
    parser.add_option("--pip",
        help="Parent broker port. The IP address or your robot",
        dest="pip")
    parser.add_option("--pport",
        help="Parent broker port. The port NAOqi is listening to",
        dest="pport",
        type="int")
    parser.set_defaults(
        pip=NAO_IP,
        pport=9559)

    (opts, args_) = parser.parse_args()
    pip   = opts.pip
    pport = opts.pport

    # We need this broker to be able to construct
    # NAOqi modules and subscribe to other modules
    # The broker must stay alive until the program exists
    myBroker = ALBroker("myBroker",
       "0.0.0.0",   # listen to anyone
       0,           # find a free port and use it
       pip,         # parent broker IP
       pport)       # parent broker port


    # Warning: HumanGreeter must be a global variable
    # The name given to the constructor must be the name of the
    # variable
    global HumanGreeter
    HumanGreeter = HumanGreeterModule("HumanGreeter")

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print
        print "Interrupted by user, shutting down"
        myBroker.shutdown()
        sys.exit(0)



if __name__ == "__main__":
    main()

Few notes:

  • Make sure to use a global variable for the module instance.
  • Make sure the name you pass to the constructor of ALModule matches the name of your variable.
  • The method of your class are automatically transform into bound methods, providing that you wrote a doc string for this method, and it does not start with an underscore.

class MyModule:

  # This method will be bound:
  def myMethod(self):
    """ does this and that """
    pass

  # This will NOT be bound:
  def myMethod(self):
    if foo:
      pass

  # This will also NOT be bound
  def _myMethod(self):
    pass

  • Once you have built a ALBroker object, you need to keep the object alive for the subscribing to work, hence the while(True) loop. You also need the broker object to be alive in order to create proxies without specifying an IP or a port.
  • The script must be run with --pip and --pport options to work.

Run the script, and put your face in front of the robot : you should hear ‘Hello, you’.