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

Does move_base_flex global replanning constantly require GetPathAction state calls? [closed]

asked 2020-11-04 06:52:41 -0500

harshal gravatar image

Hi, I am using Ros Melodic on Ubuntu 18.04.

Am I correct in my understanding that for global planners to re-plan with a given frequency, a concurrent GetPathAction state is required to be existing even alongside the ExePathAction? Meaning, is there no intrinsic calling of GetPathAction repeatedly by simply setting a planner frequency? And that my state machine should explicitly be modeled to re-plan (when required) by calling GetPathAction repeatedly?

Thank you for the clarifications in advance!!

edit retag flag offensive reopen merge delete

Closed for the following reason the question is answered, right answer was accepted by harshal
close date 2022-06-27 10:19:12.243827

Comments

Found the following issue #145 which pretty much answers my own question. Any further details/insight in this is still appreciated!

harshal gravatar image harshal  ( 2020-11-05 06:33:20 -0500 )edit

Also refer to issues #70 and #64.

harshal gravatar image harshal  ( 2020-11-05 06:34:09 -0500 )edit

@Tider's method uses the node reuse approach(very ROSy?!) to run GetPath and ExePath simultaneously. Plus, as he points out the code segments only stop the Controller when cancelling goal, not when updating the Goal as discussed in issues #64, #70 and #145.

TO SUMMARIZE: Another state needs to be running in parallel that Gets an updated path while the ExePath is working for the path to be updated. This doesn't need calling ExePath again as long as the same controller and concurrency slot is used.

harshal gravatar image harshal  ( 2020-11-06 06:00:49 -0500 )edit

1 Answer

Sort by ยป oldest newest most voted
2

answered 2020-11-04 19:30:52 -0500

Tider gravatar image

This method works. Run the tutorial smacc program twice, so there will be two seperate statemachine node. And whenever you publish a new goal, one of them will work to reach the goal and the other one will be preempted! I reviesed the program slightly as below:

  #!/usr/bin/env python3
import rospy
import smach
import smach_ros

from geometry_msgs.msg import PoseStamped
from nav_msgs.msg import Path

from mbf_msgs.msg import ExePathAction
from mbf_msgs.msg import GetPathAction
from mbf_msgs.msg import RecoveryAction

import threading

def main():
    rospy.init_node('mbf_state_machine',anonymous=True)

    # Create SMACH state machine
    sm = smach.StateMachine(outcomes=['succeeded', 'aborted', 'preempted'])

    # Define userdata
    sm.userdata.goal = None
    sm.userdata.path = None
    sm.userdata.error = None
    sm.userdata.clear_costmap_flag = False
    sm.userdata.error_status = None

    with sm:
        # Goal callback for state WAIT_FOR_GOAL
        def goal_cb(userdata, msg):
            userdata.goal = msg
            return False

        # Monitor topic to get MeshGoal from RViz plugin
        smach.StateMachine.add(
            'WAIT_FOR_GOAL',
            smach_ros.MonitorState(
                '/move_base_simple/goal',
                PoseStamped,
                goal_cb,
                output_keys=['goal']
            ),
            transitions={
                'invalid': 'GET_PATH',
                'valid': 'WAIT_FOR_GOAL',
                'preempted': 'preempted'
            }
        )

        # Get path
        smach.StateMachine.add(
            'GET_PATH',
            smach_ros.SimpleActionState(
                '/move_base/get_path',
                GetPathAction,
                goal_slots=['target_pose'],
                result_slots=['path']
            ),
            transitions={
                'succeeded': 'EXE_PATH',
                'aborted': 'WAIT_FOR_GOAL',
                'preempted': 'preempted'
            },
            remapping={
                'target_pose': 'goal'
            }
        )

        # Execute path
        smach.StateMachine.add(
            'EXE_PATH',
            smach_ros.SimpleActionState(
                '/move_base/exe_path',
                ExePathAction,
                goal_slots=['path']
            ),
            transitions={
                'succeeded': 'WAIT_FOR_GOAL',
                'aborted': 'RECOVERY',
                #'preempted': 'preempted'
                'preempted': 'WAIT_FOR_GOAL'
            }
        )

        # Goal callback for state RECOVERY
        def recovery_path_goal_cb(userdata, goal):
            if userdata.clear_costmap_flag == False:
                goal.behavior = 'clear_costmap'
                userdata.clear_costmap_flag = True
            else:
                goal.behavior = 'straf_recovery'
                userdata.clear_costmap_flag = False

        # Recovery
        smach.StateMachine.add(
            'RECOVERY',
             smach_ros.SimpleActionState(
                'move_base/recovery',
                RecoveryAction,
                goal_cb=recovery_path_goal_cb,
                input_keys=["error", "clear_costmap_flag"],
                output_keys = ["error_status", 'clear_costmap_flag']
            ),
            transitions={
                #'succeeded': 'GET_PATH',
                'succeeded': 'WAIT_FOR_GOAL',
                #'aborted': 'aborted',
                'aborted': 'WAIT_FOR_GOAL',
                #'preempted': 'preempted'
                'preempted': 'WAIT_FOR_GOAL'
            }
        )

    # Create and start introspection server
    sis = smach_ros.IntrospectionServer('smach_server', sm, '/SM_ROOT')
    sis.start()

    # Execute SMACH plan
    sm_t = threading.Thread(target=sm.execute)
    sm_t.start()
    # sm.execute()
    # Wait for interrupt and stop introspection server
    rospy.spin()
    sis.stop()
    sm.preempt_requested()
    rospy.loginfo("wait sm exit!")
    sm.request_preempt()
    sm_t.join()

if __name__=="__main__":
    main()
edit flag offensive delete link more

Comments

Thanks! But with a new goal and path, does the preempted path execution not stop the robot for an instant(i.e., zero vel msg for the local planner)?

Also, my question is more concerned about replanning related to the same goal (G1, that is not published again). Sorry for any confusion caused!!

harshal gravatar image harshal  ( 2020-11-05 05:45:07 -0500 )edit
1

During path executinon runtime,setting a new plan would not publish zero velocity (related code: abstract_controller_execution.cpp line 306 & line 326). And whether or not goal is the same, you need to call the planning action with source and dest to get the new plan. For example, using the script above, you can publish the topic '/move_base_simple/goal' whenever you want to replan.

Tider gravatar image Tider  ( 2020-11-05 18:39:47 -0500 )edit

I see the code part here! Thanks! Also, basically, the stopping behavior I see is a by-product of my implementation, but doesn't trigger zero velocity when I give a new plan/update plan in the way you describe in the state-machine! Thanks for your help and patience!

harshal gravatar image harshal  ( 2020-11-06 05:53:19 -0500 )edit

Question Tools

1 follower

Stats

Asked: 2020-11-04 06:52:41 -0500

Seen: 217 times

Last updated: Nov 06 '20