flexbe_behavior_engine icon indicating copy to clipboard operation
flexbe_behavior_engine copied to clipboard

How to subscribe and process a joystick

Open grafoteka opened this issue 4 years ago • 6 comments

Hello,

I'm trying to implement a FSM where the transitions are activated depending on the buttons of a joystick.

Following the tutorial, I'm implementing this instruction:

self._sub = ProxySubscriberCached({'/a_topic': MsgType})
self._sub = ProxySubscriberCached({'/joy': Joy})

At this moment, I can only "subscribe" to the /joy topic. But I don't know how to continue, also I'm newbie with python.

Can I create a joy_cb where processing the information of the message like in a normal node? Or the method in flexbe is different?

In the definition I have found something about the callback,

if topic not in ProxySubscriberCached._topics:
            sub = rospy.Subscriber(topic, msg_type, self._callback, callback_args=topic)
            ProxySubscriberCached._topics[topic] = {'subscriber': sub,
                                                    'last_msg': None,
                                                    'buffered': buffered,
                                                    'msg_queue': []}
        if callback is not None:
            ProxySubscriberCached._topics[topic]['subscriber'].impl.add_callback(callback, None)

But if I declare like this:

self._joy_sub = ProxySubscriberCached({'/joy': Joy}, self._joy_cb)

[...]

def _joy_cb(self, msg, topic):

It says: 'ContactoState' object has no attribute '_joy_cb' See onboard terminal for more information.

Thank you.

grafoteka avatar May 12 '21 11:05 grafoteka

Because FlexBE runs it's states at a certain rate, the way you access ROS messages you received is a bit different. There is no need to define a callback for the topic's subscriber, but just check the last received message in the State's execute method:

def __init__(self, topic='/joy'):
    self._topic = topic
    self._sub = ProxySubscriberCached({self._topic: Joy})

def execute(se,f userdata)
        if self._sub.has_msg(self._topic):
            msg = self._sub.get_last_msg(self._topic)
            if matches_some_condition(msg):
                return 'some_condition_matched'
        # else: 
        #     not returning anything means:
        #     do not exit the state, so that `execute` is called in the next 'tick' and hopefully we have received a message by then

LoyVanBeek avatar May 14 '21 07:05 LoyVanBeek

Hi @LoyVanBeek, thank you for your help.

I have try to implement your code, but adapting it to my FSM.

	def __init__(self, topic='/joy'):
		super(ContactoState, self).__init__(outcomes = ['turn_on'])
                self._topic = topic
         	self._joy_sub = ProxySubscriberCached({self._topic: Joy})

	def execute(self, userdata):
		if self._sub.has_msg(self._topic):
			msg = self._sub.get_last_msg(self._topic)

			if(msg.button[9] == 1):
				return 'turn_on' 

But I have the next error:

line 28, in ContactoState
    self._topic = topic
NameError: name 'topic' is not defined"

And I know why the topic is not accepted in the declaration.

Kinds regards, Jorge

grafoteka avatar May 14 '21 09:05 grafoteka

I really don't see why topic would not be defined. But there is no great need to have this as parameter, you can use

self._topic = '/joy'

in the constructor just as well, but makes the state less configurable if you ever have a different topic. Not required at all.

LoyVanBeek avatar May 14 '21 09:05 LoyVanBeek

Note that if you use FlexBE for this application, be aware that is loops at a certain rate (configurable I think). And think about how that afferts interop with your joystick and looking at the last message. If you press the button for a shorter time than the loop rate AND only look at the last message, you could potentially miss a message where the button is pressed that is simply not the last message. Looking at all messages since the last 'tick' can solve that maybe

I don't know anything about your application, but there are other joystick-interpreters in ROS IIRC. FlexBE might not be the optimal choice for what you are doing.

LoyVanBeek avatar May 14 '21 09:05 LoyVanBeek

Hi again Loy,

the application is just for controlling a vehicle with a logitech pad, but not only for the command_vel topic. It also require some commands for the ignition, turn off, ... that's why I would like to use a FSM. But maybe is not the best option.

Also, I try to search for ROS IIRC, but without results, could you give more information about IIRC?

Thank you

grafoteka avatar May 14 '21 09:05 grafoteka

:-) IIRC means "If I Recall Correctly" but maybe that's just old internet slang.

But answering your question: I don't know which repo or package that would be. I made https://github.com/RobotRose/rose_joystick a loooong time ago and might be usable or provide some inspiration. Or not... You might use the ROS wiki or github to search for packages depending on these joystick messages and maybe that turns up something useful too.

A state machine is the way to go after you have a bunch of inputs to process, but you indeed really want to process those directly when they are received and not at a fixed rate. This is possible with FSMs of course, but as far as I understand, FlexBE is not really meant for this kind of FSM, more intended for high-level robot behavior. For your type of application, it might be faster, easier to write your own event processing state machine thing in plain Python.

LoyVanBeek avatar May 14 '21 09:05 LoyVanBeek