ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

ROS2 Python: Add arguments to callback

asked 2020-03-16 08:05:40 -0500

ninamwa gravatar image

Hi. I am using Python and ROS2 and I want to create two action clients: One for opening a gripper and one for closing it. The goal_response_callback is completely similar for both, and the result callback is very similar, it just changes what parameter to set to true/false. Instead of having two goal_callbacks and two result_callbacks, i was hoping to just give in an argument saying if the goal was to open or close the gripper, but i can't seem to find the correct way to use the callback together with an argument. I have tried to just give the argument as normal (self.goal_response_callback("open"), and as a partial function shown in the code below. Nothing seems to work.

Anyone who can tell me the best way to do this? Thanks!

 def send_close_gripper_goal(self):
    goal_msg = CloseGripper.Goal()
    self.closegripper_action_client.wait_for_server()
    self._send_goal_future = self.closegripper_action_client.send_goal_async(goal_msg)
    self._send_goal_future.add_done_callback(partial(self.goal_response_callback,"close"))

def goal_response_callback(self, future,type):
    goal_handle = future.result()
    if not goal_handle.accepted:
        self.get_logger().info('Goal rejected :(')
        return

    self.get_logger().info('Goal accepted :)')
    self._get_result_future = goal_handle.get_result_async()
    self._get_result_future.add_done_callback(self.get_result_callback(type))

def get_result_callback(self,future,type):
    result = future.result().result
    if type == "open":
        GripperOpen = result.success
        GripperClose = not result.success
    if type == "close":
        GripperClose = result.success
        GripperOpen = not result.success
    print(GripperClose)
    print(GripperOpen)
edit retag flag offensive close merge delete

2 Answers

Sort by ยป oldest newest most voted
5

answered 2020-03-16 11:58:19 -0500

sloretz gravatar image

I think the problem is functools.partial is providing the first argument instead of the second. Use keyword arguments to disambiguate.

>>> import functools
>>> def my_func(result, type):
...    print(f'Got {result} and {type}')
... 
>>> my_func('foo', 'bar')
Got foo and bar
>>> functools.partial(my_func, 'close')('foo')
Got close and foo
>>> functools.partial(my_func, type='close')('foo')
Got foo and close

More specifically, change the call to add_done_callback to:

self._send_goal_future.add_done_callback(partial(self.goal_response_callback, type="close"))
edit flag offensive delete link more

Comments

Thank you, this worked exactly as I wanted! :-)

ninamwa gravatar image ninamwa  ( 2020-03-17 04:43:16 -0500 )edit
1

answered 2022-03-01 08:13:41 -0500

George V gravatar image

If you don't want to import 'functools' you can also do it with lambda functions:

>>> def foobar(a,b):
...     return a+b
>>> foobar(1,2) # call normal function
3

>>> bind = lambda x: foobar(x, 2) # bind 2 to foobar
>>> bind(1) 
3

>>> bind = lambda: foobar(1,2) # bind all elements  
>>> bind()  
3

So in your case it would look like:

self._send_goal_future.add_done_callback( lambda future: self.goal_response_callback(future, "close"))
edit flag offensive delete link more

Question Tools

2 followers

Stats

Asked: 2020-03-16 08:05:40 -0500

Seen: 1,987 times

Last updated: Mar 16 '20