pythonpython-3.xeventspepper

Python 3.5 invalid signature | Pepper robot


I'm using Python 3.5.10-slim-buster (Docker) with the Pepper robot from Softbank. The NAOqi version on the robot is 2.5.8 (taken from /var/log/naoqi/servicemanager/system.Naoqi.log). I got qi v. 3.0.0 via pip.

I want to subscribe to events with

pepper = qi.Application()
pepper.start()
session = pepper.session
memory = session.service("ALMemory")

def touch_event(*args, **kwargs):
    pass

subscriber = memory.subscriber("ALTouch/TouchChanged") # throws RuntimeError: Invalid signature
if subscriber:
    subscriber.signal.connect(touch_event)

Creating the session directly like in http://doc.aldebaran.com/libqi/api/python/session.html didn't work either.

Does anyone know how to make this work?

I've referenced this issue in https://github.com/aldebaran/libqi-python/issues/13.

tldr: The issue occurs most likely due to a missmatch between the NaoQi OS and the coresponding libQi library. My workaround for this is to run my code directly on the pepper robot.

Even with the latest version of libqi and the fix from Victor (see https://github.com/victorpaleologue/libqi-python/tree/47df0833c707cfd2a6a4c86765db423f319e029d) it didn't work and resulted in the same error.


Solution

  • There has been a protocol breakage in libQi, that you can only spot on methods that returns QiObjects such as ALMemory.subscriber.

    NAOqi 2.5.x has a libQi version around 1.8.x, and libQi 2.x is already incompatible with that. You are running a libQi 3.x, so you experience the issue too.

    It is going to be hard to recompile an old libqi-python for Python 3, so I recommend that you work around this issue by using the legacy ALMemory.subscribeToEvent.

    To do that with libQi, you will need to register a service hosted on your client machine, and make sure it is accessible to the robot by listening on public addresses on the network:

    # Listen to public addresses on a random port,
    # so that services registered from here are accessible.
    session.listen("tcp://0.0.0.0:0")
    
    # An object that will be registered as a service.
    class MySubscriber:
    
        # It needs at least a callback to get ALMemory events.
        def onTouched(key, value):
            pass
    
    subscriber = MySubscriber()
    
    # Register it with an arbitrary name.
    service_name = "MySubscriber"
    session.registerService(service_name, subscriber)
    
    # Subscribe and tell exactly which service and method to call back.
    memory.subscribeToEvent("TouchChanged", service_name, "onTouched")
    

    Also, note that the right name of the event is TouchedChanged (no ALTouch/ prefix).