0

How can I subscribe to an event using ALMemory's subscribeToEvent function, which requires the correct Python scope while using ROS (rospy) that initiates modules outside my code?

This question is similar to this Naoqi subscription question, but differs in the sense that rospy was not used, which is critical to the implementation.

My current code is as such;
mainBehaviour.py

from nao.nao import Nao


class mainBehaviour(AbstractBehaviour):
    def init(self):
        global mainBehaviourMethod
        mainBehaviourMethod = self
        self.nao.setCallOnFall("mainBehaviourMethod", "robotHasFallen")

    def update(self):
        print("Update")

    def robotHasFallen(self, eventName, val, subscriberIdentifier):
        print("FALLING")

nao.py

from naoqi import ALProxy, ALModule, ALBroker
import rospy
from math import radians
import weakref
class Nao(object):

    def __init__(self):
        self.nao_ip = rospy.get_param("nao_ip")
        self.port = 9559
        self.memory_proxy = ALProxy("ALMemory", self.nao_ip, self.port)

    def setCallOnFall(self, module, method):
        self.memory_proxy.subscribeToEvent("robotHasFallen", module, method)

What I want is that mainBehaviour.py, using nao.py, has its function robotHasFallen fire when the robot has fallen. However, the current code does not produce this behaviour (it ignores any fall), but does not produce an error either. I attempted to implement this using this ALMemory tutorial. However, this tutorial makes use of a single python file, in which methods aren't instantiated by ROS. Therefore I cannot make use of the line pythonModule = myModule("pythonModule"). I attempted to still obtain this Python scope (on which the answer to the previously linked question states "the python variable must have the same name than the module name you create"), by declaring a global variable pointing to self.

How can I create the desired behaviour, detecting a fallen robot using subscribeToEvent, using ROS with its consequences of not initiating modules myself and therefore not being able to pass its constructor?
I cannot install any further libraries because I use a university computer.

Isaiah
  • 1,852
  • 4
  • 23
  • 48
  • hello, could you try with a initial declaration at the beginning of your mainBehavior.py of a variable: "mainBehaviourMethod = None" (because just saying global later should not be enough to really create the variable with global scope) – Alexandre Mazel Mar 18 '19 at 21:51

1 Answers1

2

Your example code uses the "naoqi" library, but it's now more convenient to use the "qi" library (you can get it with "pip install qi", it's already present on your robot in versions 2.1 or above). In that version you can directly pass a callback, see here for a helper library that allows you to do events.connect("MyALMemoryKey", my_callback) (you pass the function and not just it's name - and it doesn't care where the function comes from).

Under the hood, it does this:

ALMemory.subscriber("MyALMemoryKey").signal.connect(my_callback)

(note that here ALMemory is a Service (qi framework) and not a module (naoqi framework).

You can directly use that helper lib (see the doc here, and some samples using it here), or use the same logic in your code (it's not very complicated, once you have a working example to start from).

Emile
  • 2,946
  • 2
  • 19
  • 22
  • Thanks! Unfortunately we're using university computers and cannot install any other libraries. With "use the same logic in your code" you mean to also use the connect() function? How do I obtain the subscriber then (using naoQi)? – Isaiah Mar 18 '19 at 10:37
  • You can't even install other libraries with pip install --user ? That doesn't require any superuser rights; you can also just download the Python SDK on here: https://community.ald.softbankrobotics.com/en/resources/software/language/en-gb (you may get "not allowed" if you didn't register a (free) account) – Emile Mar 25 '19 at 08:26