Example #1
0
    def const_buoy_localisation_tree():

        # buoys key = english, value = array indicies
        sides = ['Right', 'Back', 'Left', 'Back']

        # set plans
        localistion_tree = [
            Fallback(
                'FB-{}BuoyLocalised'.format(side),
                children=[
                    C_Buoys_Localised(
                        name='C_{}Buoys_Localised'.format(side),
                        side=side.lower(),
                        localisation_tol=auv_config.BUOY_LOCALISATION_TOL,
                        bb_enum='{}_buoys_localised'.format(
                            side.lower())  # NOTE: dumb
                    ),
                    A_Set_Buoy_Localisation_Plan(
                        name='A_Set{}BuoyPlan'.format(side),
                        side=side.lower(),
                        n_rows=auv_config.BUOY_LOCALISATION_N_ROWS,
                        row_sep=auv_config.BUOY_LOCALISTION_ROW_SEP,
                        row_overshoot=auv_config.
                        BUOY_LOCALISATION_ROW_OVERSHOOT,
                        # should just get this from the buoy poses themselves...
                        buoy_link=auv_config.LOCAL_LINK,
                        clockwise=auv_config.BUOY_LOCALISATION_CLOCKWISE,
                        velocity=auv_config.BUOY_LOCALISATION_VELOCITY,
                        latlon_utm_serv=auv_config.LATLONTOUTM_SERVICE,
                        utm_link=auv_config.UTM_LINK)
                ]) for side in sides
        ]

        localistion_tree = Sequence('SQ-LocalisationTree',
                                    children=localistion_tree)

        # NOTE: this is dumb
        # this is until we can check to covariance
        # matricies of the buoys
        decision_tree = Sequence('SQ-LocalisationDecisions',
                                 children=[
                                     C_PlanCompleted(),
                                     C_Buoy_Localisation_Plan_Set(),
                                     A_Set_Buoy_Decisions()
                                 ])
        localistion_tree = Fallback('FB-LocalisationTree',
                                    children=[
                                        decision_tree,
                                        C_Buoy_Localisation_Plan_Set(),
                                        localistion_tree
                                    ])
        '''
        Look at `py-tree-tree-watcher` to understand what this
        structure does.
        '''

        return localistion_tree
Example #2
0
    def const_autonomous_updates():
        poi_tree = Fallback(name="FB_Poi",
                            children=[
                                C_NoNewPOIDetected(common_globals.POI_DIST),
                                A_UpdateMissonForPOI(
                                    auv_config.UTM_LINK, auv_config.LOCAL_LINK,
                                    auv_config.POI_DETECTOR_LINK)
                            ])

        return Fallback(name="FB_AutonomousUpdates",
                        children=[C_AutonomyDisabled(), poi_tree])
Example #3
0
    def const_execute_mission_tree():

        # waypoint type
        wp_is_goto = C_CheckWaypointType(
            expected_wp_type=imc_enums.MANEUVER_GOTO)
        wp_is_sample = C_CheckWaypointType(
            expected_wp_type=imc_enums.MANEUVER_SAMPLE)
        wp_is = Fallback("FB-IsWaypoint", children=[wp_is_goto, wp_is_sample])
        goto_action = A_GotoWaypoint(
            action_namespace=auv_config.ACTION_NAMESPACE,
            goal_tolerance=auv_config.WAYPOINT_TOLERANCE,
            goal_tf_frame=auv_config.UTM_LINK)
        goto_maneuver = Sequence(name="SQ-GotoWaypoint",
                                 children=[wp_is, goto_action])

        #############################################################################################
        # INSPECT
        #TODO add an inspection maneuver  into bridge and neptus etc.
        # wp_is_inspect = C_CheckWaypointType(expected_wp_type = imc_enums.MANEUVER_INSPECT)
        #inspection_action = A_GotoWaypoint(action_namespace = auv_config.INSPECTION_ACTION_NAMESPACE,
        #                                   goal_tolerance = auv_config.WAYPOINT_TOLERANCE,
        #                                   goal_tf_frame = auv_config.UTM_LINK)
        # inspection_maneuver = Sequence(name="SQ-InspectWP",
        # children=[
        # wp_is_inspect,
        # inspection_action
        # ])
        #############################################################################################

        # put the known plannable maneuvers in here as each others backups
        execute_maneuver = Fallback(name="FB-ExecuteManeuver",
                                    children=[
                                        goto_maneuver,
                                    ])

        # and then execute them in order
        follow_plan = Sequence(name="SQ-FollowMissionPlan",
                               children=[
                                   C_HaveCoarseMission(),
                                   C_StartPlanReceived(),
                                   C_PlanIsNotChanged(), execute_maneuver,
                                   A_SetNextPlanAction()
                               ])

        # until the plan is done
        return Fallback(name="FB-ExecuteMissionPlan",
                        children=[C_PlanCompleted(), follow_plan])
Example #4
0
    def const_safety_tree():
        no_abort = C_NoAbortReceived()
        altOK = C_AltOK(auv_config.MIN_ALTITUDE,
                        auv_config.ABSOLUTE_MIN_ALTITUDE)
        depthOK = C_DepthOK(auv_config.MAX_DEPTH)
        leakOK = C_LeakOK()
        # more safety checks will go here

        safety_checks = Sequence(name="SQ-SafetyChecks",
                                 blackbox_level=1,
                                 children=[no_abort, altOK, depthOK, leakOK])

        surface = Fallback(
            name="FB_Surface",
            children=[
                A_EmergencySurface(auv_config.EMERGENCY_ACTION_NAMESPACE)
                #  A_EmergencySurfaceByForce(auv_config.EMERGENCY_TOPIC,
                #  auv_config.VBS_CMD_TOPIC,
                #  auv_config.RPM_CMD_TOPIC,
                #  auv_config.LCG_PID_ENABLE_TOPIC,
                #  auv_config.VBS_PID_ENABLE_TOPIC,
                #  auv_config.TCG_PID_ENABLE_TOPIC,
                #  auv_config.YAW_PID_ENABLE_TOPIC,
                #  auv_config.DEPTH_PID_ENABLE_TOPIC,
                #  auv_config.VEL_PID_ENABLE_TOPIC)
            ])

        skip_wp = Sequence(
            name='SQ-CountEmergenciesAndSkip',
            children=[
                Counter(n=auv_config.EMERGENCY_TRIALS_BEFORE_GIVING_UP,
                        name="A_EmergencyCounter",
                        reset=True),
                A_SetNextPlanAction()
            ])

        return Fallback(name='FB_SafetyOK',
                        children=[safety_checks, skip_wp, surface])
Example #5
0
    def const_execute_mission_tree():
        gotowp = A_GotoWaypoint(action_namespace=auv_config.ACTION_NAMESPACE,
                                goal_tolerance=auv_config.WAYPOINT_TOLERANCE,
                                goal_tf_frame=auv_config.UTM_LINK)

        follow_plan = Sequence(name="SQ-FollowMissionPlan",
                               children=[
                                   C_HaveCoarseMission(),
                                   C_StartPlanReceived(),
                                   C_PlanIsNotChanged(), gotowp,
                                   A_SetNextPlanAction()
                               ])

        return Fallback(name="FB-ExecuteMissionPlan",
                        children=[C_PlanCompleted(), follow_plan])
Example #6
0
    def const_synch_tree():
        have_refined_mission = C_HaveRefinedMission()
        have_coarse_mission = C_HaveCoarseMission()
        refine_mission = A_RefineMission(config.PATH_PLANNER_NAME,
                                         config.PATH_TOPIC)
        # we need one here too, to initialize the mission in the first place
        # set dont_visit to True so we dont skip the first wp of the plan
        set_next_plan_action = A_SetNextPlanAction(do_not_visit=True)

        refinement_tree = Sequence(name="SQ_Refinement",
                                   children=[
                                       have_coarse_mission, refine_mission,
                                       set_next_plan_action
                                   ])

        return Fallback(name='FB_SynchMission',
                        children=[have_refined_mission, refinement_tree])
Example #7
0
    def const_dvl_tree():
        switch_on = Sequence(name="SQ_SwitchOnDVL",
                             children=[
                                 C_AtDVLDepth(auv_config.DVL_RUNNING_DEPTH),
                                 A_SetDVLRunning(
                                     auv_config.START_STOP_DVL_NAMESPACE, True,
                                     auv_config.DVL_COOLDOWN)
                             ])

        switch_off = Fallback(name="FB_SwitchOffDVL",
                              children=[
                                  switch_on,
                                  A_SetDVLRunning(
                                      auv_config.START_STOP_DVL_NAMESPACE,
                                      False, auv_config.DVL_COOLDOWN)
                              ])

        return switch_off
Example #8
0
    def const_wall_plan_tree():

        tree = Fallback(
            'FB-WallPlanSet',
            children=[
                CheckBlackboardVariableValue(bb_enums.WALL_PLAN_SET, True,
                                             'C_WallPlanSet'),
                A_Set_Wall_Plan(
                    'A_SetWallPlan', auv_config.WALL_SURVEY_ROW_SEP,
                    auv_config.WALL_SURVEY_DEPTH, auv_config.LOCAL_LINK,
                    auv_config.UTM_LINK, auv_config.WALL_SURVEY_VELOCITY,
                    auv_config.LATLONTOUTM_SERVICE,
                    auv_config.LATLONTOUTM_SERVICE_ALTERNATIVE,
                    auv_config.WALL_SURVEY_X0_OVERSHOOT,
                    auv_config.WALL_SURVEY_X1_OVERSHOOT,
                    auv_config.WALL_SURVEY_X0_LINEUP,
                    auv_config.WALL_SURVEY_X1_LINEUP,
                    auv_config.WALL_SURVEY_FIRST_LINEUP,
                    auv_config.WALL_SURVEY_STARBOARD)
            ])
        return tree
Example #9
0
    def const_execute_mission_tree():
        plan_complete = C_PlanCompleted()
        # but still wait for operator to tell us to 'go'
        start_received = C_StartPlanReceived()
        gotowp = A_GotoWaypoint(auv_config.ACTION_NAMESPACE)
        # and this will run after every success of the goto action
        set_next_plan_action = A_SetNextPlanAction()
        plan_is_same = C_PlanIsNotChanged()
        #  idle = pt.behaviours.Running(name="Idle")

        follow_plan = Sequence(name="SQ-FollowMissionPlan",
                               children=[
                                   start_received, plan_is_same, gotowp,
                                   set_next_plan_action
                               ])

        return Fallback(
            name="FB-ExecuteMissionPlan",
            children=[
                plan_complete, follow_plan
                #  idle
            ])
Example #10
0
    def const_safety_tree():
        no_abort = C_NoAbortReceived()
        altOK = C_AltOK(auv_config.MIN_ALTITUDE,
                        auv_config.ABSOLUTE_MIN_ALTITUDE)
        depthOK = C_DepthOK(auv_config.MAX_DEPTH)
        leakOK = C_LeakOK()
        # more safety checks will go here

        safety_checks = Sequence(name="SQ-SafetyChecks",
                                 blackbox_level=1,
                                 children=[no_abort, altOK, depthOK, leakOK])

        skip_wp = Sequence(
            name='SQ-CountEmergenciesAndSkip',
            children=[
                Counter(n=auv_config.EMERGENCY_TRIALS_BEFORE_GIVING_UP,
                        name="A_EmergencyCounter",
                        reset=True),
                A_SetNextPlanAction()
            ])

        abort = Sequence(
            name="SQ-ABORT",
            children=[
                A_SimplePublisher(topic=auv_config.EMERGENCY_TOPIC,
                                  message_object=Empty()),
                A_EmergencySurface(auv_config.EMERGENCY_ACTION_NAMESPACE)
            ])

        return Fallback(
            name='FB_SafetyOK',
            children=[
                safety_checks, skip_wp, abort
                #  publish_abort,
                #  A_EmergencySurface(auv_config.EMERGENCY_ACTION_NAMESPACE)
            ])
Example #11
0
def const_tree(auv_config):
    """
    construct the entire tree.
    the structure of the code reflects the structure of the tree itself.
    sub-trees are constructed in inner functions.
    auv_config is in scope of all these inner functions.

    auv_config is a simple data object with a bunch of UPPERCASE fields in it.
    """
    # slightly hacky way to keep track of 'runnable' actions
    # such actions should add their names to this list in their init
    # just for Neptus vehicle state for now
    bb = pt.blackboard.Blackboard()
    bb.set(bb_enums.MANEUVER_ACTIONS, [])

    def const_data_ingestion_tree():
        read_abort = ptr.subscribers.EventToBlackboard(
            name="A_ReadAbort",
            topic_name=auv_config.ABORT_TOPIC,
            variable_name=bb_enums.ABORT)

        read_depth = ReadTopic(
            name="A_ReadDepth",
            topic_name=auv_config.DEPTH_TOPIC,
            topic_type=Float64,
            blackboard_variables={
                bb_enums.DEPTH: 'data'
            }  # this takes the Float64.data field and puts into the bb
        )

        read_alt = ReadTopic(
            name="A_ReadAlt",
            topic_name=auv_config.ALTITUDE_TOPIC,
            topic_type=DVL,
            blackboard_variables={bb_enums.ALTITUDE: 'altitude'})

        read_leak = ReadTopic(name="A_ReadLeak",
                              topic_name=auv_config.LEAK_TOPIC,
                              topic_type=Leak,
                              blackboard_variables={bb_enums.LEAK: 'value'})

        read_detection = ReadTopic(
            name="A_ReadCameraDetection",
            topic_name=auv_config.CAMERA_DETECTION_TOPIC,
            topic_type=PointStamped,
            blackboard_variables={bb_enums.POI_POINT_STAMPED:
                                  None}  # read the entire message into the bb
        )

        read_gps = ReadTopic(name="A_ReadGPS",
                             topic_name=auv_config.GPS_FIX_TOPIC,
                             topic_type=NavSatFix,
                             blackboard_variables={bb_enums.GPS_FIX: None})

        def const_neptus_tree():
            update_neptus = Sequence(
                name="SQ-UpdateNeptus",
                children=[
                    A_UpdateNeptusEstimatedState(
                        auv_config.ESTIMATED_STATE_TOPIC),
                    A_UpdateNeptusPlanControlState(
                        auv_config.PLAN_CONTROL_STATE_TOPIC),
                    A_UpdateNeptusVehicleState(auv_config.VEHICLE_STATE_TOPIC),
                    A_UpdateNeptusPlanDB(auv_config.PLANDB_TOPIC,
                                         auv_config.UTM_LINK,
                                         auv_config.LOCAL_LINK),
                    A_UpdateNeptusPlanControl(auv_config.PLAN_CONTROL_TOPIC),
                    A_VizPublishPlan(auv_config.PLAN_VIZ_TOPIC)
                ])
            return update_neptus

        update_tf = A_UpdateTF(auv_config.UTM_LINK, auv_config.BASE_LINK)
        update_latlon = A_UpdateLatLon()
        set_utm_from_gps = A_SetUTMFromGPS()
        neptus_tree = const_neptus_tree()

        return Sequence(
            name="SQ-DataIngestion",
            # dont show all the things inside here
            blackbox_level=1,
            children=[
                read_abort, read_leak, read_depth, read_alt, read_detection,
                read_gps, set_utm_from_gps, update_tf, update_latlon,
                neptus_tree
            ])

    def const_dvl_tree():
        switch_on = Sequence(name="SQ_SwitchOnDVL",
                             children=[
                                 C_AtDVLDepth(auv_config.DVL_RUNNING_DEPTH),
                                 A_SetDVLRunning(
                                     auv_config.START_STOP_DVL_NAMESPACE, True,
                                     auv_config.DVL_COOLDOWN)
                             ])

        switch_off = Fallback(name="FB_SwitchOffDVL",
                              children=[
                                  switch_on,
                                  A_SetDVLRunning(
                                      auv_config.START_STOP_DVL_NAMESPACE,
                                      False, auv_config.DVL_COOLDOWN)
                              ])

        return switch_off

    def const_safety_tree():
        no_abort = C_NoAbortReceived()
        altOK = C_AltOK(auv_config.MIN_ALTITUDE,
                        auv_config.ABSOLUTE_MIN_ALTITUDE)
        depthOK = C_DepthOK(auv_config.MAX_DEPTH)
        leakOK = C_LeakOK()
        # more safety checks will go here

        safety_checks = Sequence(name="SQ-SafetyChecks",
                                 blackbox_level=1,
                                 children=[no_abort, altOK, depthOK, leakOK])

        surface = Fallback(
            name="FB_Surface",
            children=[
                A_EmergencySurface(auv_config.EMERGENCY_ACTION_NAMESPACE)
                #  A_EmergencySurfaceByForce(auv_config.EMERGENCY_TOPIC,
                #  auv_config.VBS_CMD_TOPIC,
                #  auv_config.RPM_CMD_TOPIC,
                #  auv_config.LCG_PID_ENABLE_TOPIC,
                #  auv_config.VBS_PID_ENABLE_TOPIC,
                #  auv_config.TCG_PID_ENABLE_TOPIC,
                #  auv_config.YAW_PID_ENABLE_TOPIC,
                #  auv_config.DEPTH_PID_ENABLE_TOPIC,
                #  auv_config.VEL_PID_ENABLE_TOPIC)
            ])

        skip_wp = Sequence(
            name='SQ-CountEmergenciesAndSkip',
            children=[
                Counter(n=auv_config.EMERGENCY_TRIALS_BEFORE_GIVING_UP,
                        name="A_EmergencyCounter",
                        reset=True),
                A_SetNextPlanAction()
            ])

        return Fallback(name='FB_SafetyOK',
                        children=[safety_checks, skip_wp, surface])

    def const_leader_follower():
        return Sequence(
            name="SQ_LeaderFollower",
            children=[
                C_LeaderFollowerEnabled(config.ENABLE_LEADER_FOLLOWER),
                C_LeaderExists(config.BASE_LINK, config.LEADER_LINK),
                C_LeaderIsFarEnough(config.BASE_LINK, config.LEADER_LINK,
                                    config.MIN_DISTANCE_TO_LEADER),
                A_FollowLeader(config.FOLLOW_ACTION_NAMESPACE,
                               config.LEADER_LINK)
            ])

    def const_autonomous_updates():
        poi_tree = Fallback(name="FB_Poi",
                            children=[
                                C_NoNewPOIDetected(common_globals.POI_DIST),
                                A_UpdateMissonForPOI(
                                    auv_config.UTM_LINK, auv_config.LOCAL_LINK,
                                    auv_config.POI_DETECTOR_LINK)
                            ])

        return Fallback(name="FB_AutonomousUpdates",
                        children=[C_AutonomyDisabled(), poi_tree])

    def const_synch_tree():
        have_refined_mission = C_HaveRefinedMission()
        have_coarse_mission = C_HaveCoarseMission()
        refine_mission = A_RefineMission(config.PATH_PLANNER_NAME,
                                         config.PATH_TOPIC)
        # we need one here too, to initialize the mission in the first place
        # set dont_visit to True so we dont skip the first wp of the plan
        set_next_plan_action = A_SetNextPlanAction(do_not_visit=True)

        refinement_tree = Sequence(name="SQ_Refinement",
                                   children=[
                                       have_coarse_mission, refine_mission,
                                       set_next_plan_action
                                   ])

        return Fallback(name='FB_SynchMission',
                        children=[have_refined_mission, refinement_tree])

    def const_execute_mission_tree():
        plan_complete = C_PlanCompleted()
        # but still wait for operator to tell us to 'go'
        start_received = C_StartPlanReceived()
        gotowp = A_GotoWaypoint(auv_config.ACTION_NAMESPACE)
        # and this will run after every success of the goto action
        set_next_plan_action = A_SetNextPlanAction()
        plan_is_same = C_PlanIsNotChanged()
        #  idle = pt.behaviours.Running(name="Idle")

        follow_plan = Sequence(name="SQ-FollowMissionPlan",
                               children=[
                                   start_received, plan_is_same, gotowp,
                                   set_next_plan_action
                               ])

        return Fallback(
            name="FB-ExecuteMissionPlan",
            children=[
                plan_complete, follow_plan
                #  idle
            ])

    # The root of the tree is here

    planned_mission = Sequence(name="SQ_PlannedMission",
                               children=[
                                   const_synch_tree(),
                                   const_autonomous_updates(),
                                   const_execute_mission_tree()
                               ])

    run_tree = Fallback(name="FB-Run",
                        children=[planned_mission,
                                  const_leader_follower()])

    root = Sequence(
        name='SQ-ROOT',
        children=[
            const_data_ingestion_tree(),
            const_safety_tree(),
            #const_dvl_tree(),
            run_tree
        ])

    return ptr.trees.BehaviourTree(root)
Example #12
0
def const_tree(auv_config):
    """
    construct the entire tree.
    the structure of the code reflects the structure of the tree itself.
    sub-trees are constructed in inner functions.
    auv_config is in scope of all these inner functions.

    auv_config is a simple data object with a bunch of UPPERCASE fields in it.
    """
    # slightly hacky way to keep track of 'runnable' actions
    # such actions should add their names to this list in their init
    # just for Neptus vehicle state for now
    bb = pt.blackboard.Blackboard()
    bb.set(bb_enums.MANEUVER_ACTIONS, [])

    # just for clarity when looking at the bb in the field
    bb.set(bb_enums.MISSION_FINALIZED, False)

    def const_data_ingestion_tree():
        read_abort = ptr.subscribers.EventToBlackboard(
            name="A_ReadAbort",
            topic_name=auv_config.ABORT_TOPIC,
            variable_name=bb_enums.ABORT)

        read_alt = ReadTopic(
            name="A_ReadAlt",
            topic_name=auv_config.ALTITUDE_TOPIC,
            topic_type=DVL,
            blackboard_variables={bb_enums.ALTITUDE: 'altitude'})

        read_leak = ReadTopic(name="A_ReadLeak",
                              topic_name=auv_config.LEAK_TOPIC,
                              topic_type=Leak,
                              blackboard_variables={bb_enums.LEAK: 'value'})

        read_detection = ReadTopic(
            name="A_ReadCameraDetection",
            topic_name=auv_config.CAMERA_DETECTION_TOPIC,
            topic_type=PointStamped,
            blackboard_variables={bb_enums.POI_POINT_STAMPED:
                                  None}  # read the entire message into the bb
        )

        read_latlon = ReadTopic(name="A_ReadLatlon",
                                topic_name=auv_config.LATLON_TOPIC,
                                topic_type=GeoPoint,
                                blackboard_variables={
                                    bb_enums.CURRENT_LATITUDE: 'latitude',
                                    bb_enums.CURRENT_LONGITUDE: 'longitude'
                                })

        def const_neptus_tree():
            update_neptus = Sequence(
                name="SQ-UpdateNeptus",
                children=[
                    A_UpdateNeptusEstimatedState(
                        auv_config.ESTIMATED_STATE_TOPIC),
                    A_UpdateNeptusPlanControlState(
                        auv_config.PLAN_CONTROL_STATE_TOPIC),
                    A_UpdateNeptusVehicleState(auv_config.VEHICLE_STATE_TOPIC),
                    A_UpdateNeptusPlanDB(auv_config.PLANDB_TOPIC,
                                         auv_config.UTM_LINK,
                                         auv_config.LOCAL_LINK,
                                         auv_config.LATLONTOUTM_SERVICE),
                    A_UpdateNeptusPlanControl(auv_config.PLAN_CONTROL_TOPIC),
                    A_VizPublishPlan(auv_config.PLAN_VIZ_TOPIC)
                ])
            return update_neptus

        update_tf = A_UpdateTF(auv_config.UTM_LINK, auv_config.BASE_LINK)
        neptus_tree = const_neptus_tree()
        publish_heartbeat = A_SimplePublisher(topic=auv_config.HEARTBEAT_TOPIC,
                                              message_object=Empty())

        return Sequence(
            name="SQ-DataIngestion",
            # dont show all the things inside here
            blackbox_level=1,
            children=[
                read_abort, read_leak, read_alt, read_detection, read_latlon,
                update_tf, neptus_tree, publish_heartbeat
            ])

    def const_dvl_tree():
        switch_on = Sequence(name="SQ_SwitchOnDVL",
                             children=[
                                 C_AtDVLDepth(auv_config.DVL_RUNNING_DEPTH),
                                 A_SetDVLRunning(
                                     auv_config.START_STOP_DVL_NAMESPACE, True,
                                     auv_config.DVL_COOLDOWN)
                             ])

        switch_off = Fallback(name="FB_SwitchOffDVL",
                              children=[
                                  switch_on,
                                  A_SetDVLRunning(
                                      auv_config.START_STOP_DVL_NAMESPACE,
                                      False, auv_config.DVL_COOLDOWN)
                              ])

        return switch_off

    def const_safety_tree():
        no_abort = C_NoAbortReceived()
        altOK = C_AltOK(auv_config.MIN_ALTITUDE,
                        auv_config.ABSOLUTE_MIN_ALTITUDE)
        depthOK = C_DepthOK(auv_config.MAX_DEPTH)
        leakOK = C_LeakOK()
        # more safety checks will go here

        safety_checks = Sequence(name="SQ-SafetyChecks",
                                 blackbox_level=1,
                                 children=[no_abort, altOK, depthOK, leakOK])

        skip_wp = Sequence(
            name='SQ-CountEmergenciesAndSkip',
            children=[
                Counter(n=auv_config.EMERGENCY_TRIALS_BEFORE_GIVING_UP,
                        name="A_EmergencyCounter",
                        reset=True),
                A_SetNextPlanAction()
            ])

        abort = Sequence(
            name="SQ-ABORT",
            children=[
                A_SimplePublisher(topic=auv_config.EMERGENCY_TOPIC,
                                  message_object=Empty()),
                A_EmergencySurface(auv_config.EMERGENCY_ACTION_NAMESPACE)
            ])

        return Fallback(
            name='FB_SafetyOK',
            children=[
                safety_checks, skip_wp, abort
                #  publish_abort,
                #  A_EmergencySurface(auv_config.EMERGENCY_ACTION_NAMESPACE)
            ])

    def const_leader_follower():
        return Sequence(
            name="SQ_LeaderFollower",
            children=[
                C_LeaderFollowerEnabled(config.ENABLE_LEADER_FOLLOWER),
                C_LeaderExists(config.BASE_LINK, config.LEADER_LINK),
                C_LeaderIsFarEnough(config.BASE_LINK, config.LEADER_LINK,
                                    config.MIN_DISTANCE_TO_LEADER),
                A_FollowLeader(config.FOLLOW_ACTION_NAMESPACE,
                               config.LEADER_LINK)
            ])

    def const_autonomous_updates():
        poi_tree = Fallback(name="FB_Poi",
                            children=[
                                C_NoNewPOIDetected(common_globals.POI_DIST),
                                A_UpdateMissonForPOI(
                                    auv_config.UTM_LINK, auv_config.LOCAL_LINK,
                                    auv_config.POI_DETECTOR_LINK,
                                    auv_config.LATLONTOUTM_SERVICE)
                            ])

        return Fallback(name="FB_AutonomousUpdates",
                        children=[C_AutonomyDisabled(), poi_tree])

    def const_synch_tree():
        have_coarse_mission = C_HaveCoarseMission()
        # we need one here too, to initialize the mission in the first place
        # set dont_visit to True so we dont skip the first wp of the plan
        # and simply ready the bb to have the waypoint in it
        set_next_plan_action = A_SetNextPlanAction(do_not_visit=True)

        return Sequence(name="SQ_GotMission",
                        children=[have_coarse_mission, set_next_plan_action])

    def const_execute_mission_tree():
        gotowp = A_GotoWaypoint(action_namespace=auv_config.ACTION_NAMESPACE,
                                goal_tolerance=auv_config.WAYPOINT_TOLERANCE,
                                goal_tf_frame=auv_config.UTM_LINK)

        follow_plan = Sequence(name="SQ-FollowMissionPlan",
                               children=[
                                   C_HaveCoarseMission(),
                                   C_StartPlanReceived(),
                                   C_PlanIsNotChanged(), gotowp,
                                   A_SetNextPlanAction()
                               ])

        return Fallback(name="FB-ExecuteMissionPlan",
                        children=[C_PlanCompleted(), follow_plan])

    def const_finalize_mission():
        publish_complete = A_SimplePublisher(
            topic=auv_config.MISSION_COMPLETE_TOPIC, message_object=Empty())

        set_finalized = pt.blackboard.SetBlackboardVariable(
            variable_name=bb_enums.MISSION_FINALIZED,
            variable_value=True,
            name='A_SetMissionFinalized')

        return Sequence(name="SQ-FinalizeMission",
                        children=[
                            C_HaveCoarseMission(),
                            C_StartPlanReceived(),
                            C_PlanIsNotChanged(),
                            C_PlanCompleted(), publish_complete, set_finalized
                        ])

    # The root of the tree is here

    # planned_mission = Sequence(name="SQ_PlannedMission",
    # children=[
    # const_synch_tree(),
    # XXX stuff in here are not modified to work with utm-frame-everything
    # they _could_ but not tested.
    # const_autonomous_updates(),
    # const_execute_mission_tree()
    # ])

    planned_mission = const_execute_mission_tree()

    # use this to kind of set the tree to 'idle' mode that wont attempt
    # to control anything and just chills as an observer
    finalized = CheckBlackboardVariableValue(bb_enums.MISSION_FINALIZED, True,
                                             "MissionFinalized")

    run_tree = Fallback(
        name="FB-Run",
        children=[
            finalized,
            const_finalize_mission(), planned_mission
            #  const_leader_follower()
        ])

    root = Sequence(
        name='SQ-ROOT',
        children=[
            const_data_ingestion_tree(),
            const_safety_tree(),
            # const_dvl_tree(),
            run_tree
        ])

    return ptr.trees.BehaviourTree(root)
Example #13
0
def const_tree(auv_config):
    """
    construct the entire tree.
    the structure of the code reflects the structure of the tree itself.
    sub-trees are constructed in inner functions.
    auv_config is in scope of all these inner functions.

    auv_config is a simple data object with a bunch of UPPERCASE fields in it.
    """
    # slightly hacky way to keep track of 'runnable' actions
    # such actions should add their names to this list in their init
    # just for Neptus vehicle state for now
    bb = pt.blackboard.Blackboard()
    bb.set(bb_enums.MANEUVER_ACTIONS, [])

    # just for clarity when looking at the bb in the field
    bb.set(bb_enums.MISSION_FINALIZED, False)

    def const_data_ingestion_tree():
        read_abort = ptr.subscribers.EventToBlackboard(
            name="A_ReadAbort",
            topic_name=auv_config.ABORT_TOPIC,
            variable_name=bb_enums.ABORT)

        # ReadTopic
        # name,
        # topic_name,
        # topic_type,
        # blackboard_variables,
        # max_period = None,
        # allow_silence = True
        read_alt = ReadTopic(
            name="A_ReadAlt",
            topic_name=auv_config.ALTITUDE_TOPIC,
            topic_type=DVL,
            blackboard_variables={bb_enums.ALTITUDE: 'altitude'})

        read_leak = ReadTopic(name="A_ReadLeak",
                              topic_name=auv_config.LEAK_TOPIC,
                              topic_type=Leak,
                              blackboard_variables={bb_enums.LEAK: 'value'})

        read_detection = ReadTopic(
            name="A_ReadCameraDetection",
            topic_name=auv_config.CAMERA_DETECTION_TOPIC,
            topic_type=PointStamped,
            # read the entire message into the bb
            blackboard_variables={bb_enums.POI_POINT_STAMPED: None})

        read_latlon = ReadTopic(name="A_ReadLatlon",
                                topic_name=auv_config.LATLON_TOPIC,
                                topic_type=GeoPoint,
                                blackboard_variables={
                                    bb_enums.CURRENT_LATITUDE: 'latitude',
                                    bb_enums.CURRENT_LONGITUDE: 'longitude'
                                })

        read_sample_obs = ReadTopic(
            name="A_ReadSampleObs",
            topic_name=auv_config.SAMPLE_OBS,
            topic_type=Pose,
            blackboard_variables={
                # blackboard variable name: attribute of msg
                bb_enums.SAMPLE_POS:
                'position'
            })

        read_buoys = A_ReadBuoys(auv_config.BUOY_MARKERS,
                                 auv_config.USE_BUOY_PLAN,
                                 auv_config.LOCAL_LINK, auv_config.UTM_LINK,
                                 auv_config.LATLONTOUTM_SERVICE)

        def const_neptus_tree():
            update_neptus = Sequence(
                name="SQ-UpdateNeptus",
                children=[
                    A_UpdateNeptusEstimatedState(
                        auv_config.ESTIMATED_STATE_TOPIC),
                    A_UpdateNeptusPlanControlState(
                        auv_config.PLAN_CONTROL_STATE_TOPIC),
                    A_UpdateNeptusVehicleState(auv_config.VEHICLE_STATE_TOPIC),
                    A_UpdateNeptusPlanDB(
                        auv_config.PLANDB_TOPIC, auv_config.UTM_LINK,
                        auv_config.LOCAL_LINK, auv_config.LATLONTOUTM_SERVICE,
                        auv_config.LATLONTOUTM_SERVICE_ALTERNATIVE),
                    A_UpdateNeptusPlanControl(auv_config.PLAN_CONTROL_TOPIC),
                    A_VizPublishPlan(auv_config.PLAN_VIZ_TOPIC)
                ])
            return update_neptus

        update_tf = A_UpdateTF(auv_config.UTM_LINK, auv_config.BASE_LINK)
        neptus_tree = const_neptus_tree()
        publish_heartbeat = A_SimplePublisher(topic=auv_config.HEARTBEAT_TOPIC,
                                              message_object=Empty())

        return Sequence(
            name="SQ-DataIngestion",
            # dont show all the things inside here
            blackbox_level=1,
            children=[
                read_abort, read_leak, read_alt, read_detection, read_latlon,
                read_buoys, update_tf, neptus_tree, publish_heartbeat
            ])

    def const_dvl_tree():
        switch_on = Sequence(name="SQ_SwitchOnDVL",
                             children=[
                                 C_AtDVLDepth(auv_config.DVL_RUNNING_DEPTH),
                                 A_SetDVLRunning(
                                     auv_config.START_STOP_DVL_NAMESPACE, True,
                                     auv_config.DVL_COOLDOWN)
                             ])

        switch_off = Fallback(name="FB_SwitchOffDVL",
                              children=[
                                  switch_on,
                                  A_SetDVLRunning(
                                      auv_config.START_STOP_DVL_NAMESPACE,
                                      False, auv_config.DVL_COOLDOWN)
                              ])

        return switch_off

    def const_safety_tree():
        no_abort = C_NoAbortReceived()
        altOK = C_AltOK()
        depthOK = C_DepthOK()
        leakOK = C_LeakOK()
        # more safety checks will go here

        safety_checks = Sequence(
            name="SQ-SafetyChecks",
            blackbox_level=1,
            children=[
                no_abort,
                #  altOK,
                depthOK,
                leakOK
            ])

        skip_wp = Sequence(
            name='SQ-CountEmergenciesAndSkip',
            children=[
                Counter(n=auv_config.EMERGENCY_TRIALS_BEFORE_GIVING_UP,
                        name="A_EmergencyCounter",
                        reset=True),
                A_SetNextPlanAction()
            ])

        abort = Sequence(
            name="SQ-ABORT",
            children=[
                A_SimplePublisher(topic=auv_config.EMERGENCY_TOPIC,
                                  message_object=Empty()),
                A_EmergencySurface(auv_config.EMERGENCY_ACTION_NAMESPACE)
            ])

        return Fallback(name='FB_SafetyOK',
                        children=[safety_checks, skip_wp, abort])

    def const_leader_follower():
        return Sequence(
            name="SQ_LeaderFollower",
            children=[
                C_LeaderFollowerEnabled(config.ENABLE_LEADER_FOLLOWER),
                C_LeaderExists(config.BASE_LINK, config.LEADER_LINK),
                C_LeaderIsFarEnough(config.BASE_LINK, config.LEADER_LINK,
                                    config.MIN_DISTANCE_TO_LEADER),
                A_FollowLeader(config.FOLLOW_ACTION_NAMESPACE,
                               config.LEADER_LINK)
            ])

    def const_autonomous_updates():
        poi_tree = Fallback(name="FB_Poi",
                            children=[
                                C_NoNewPOIDetected(common_globals.POI_DIST),
                                A_UpdateMissonForPOI(
                                    auv_config.UTM_LINK, auv_config.LOCAL_LINK,
                                    auv_config.POI_DETECTOR_LINK,
                                    auv_config.LATLONTOUTM_SERVICE)
                            ])

        return Fallback(name="FB_AutonomousUpdates",
                        children=[C_AutonomyDisabled(), poi_tree])

    def const_synch_tree():
        have_coarse_mission = C_HaveCoarseMission()
        # we need one here too, to initialize the mission in the first place
        # set dont_visit to True so we dont skip the first wp of the plan
        # and simply ready the bb to have the waypoint in it
        set_next_plan_action = A_SetNextPlanAction(do_not_visit=True)

        return Sequence(name="SQ_GotMission",
                        children=[have_coarse_mission, set_next_plan_action])

    def const_buoy_localisation_tree():

        # buoys key = english, value = array indicies
        sides = ['Right', 'Back', 'Left', 'Back']

        # set plans
        localistion_tree = [
            Fallback(
                'FB-{}BuoyLocalised'.format(side),
                children=[
                    C_Buoys_Localised(
                        name='C_{}Buoys_Localised'.format(side),
                        side=side.lower(),
                        localisation_tol=auv_config.BUOY_LOCALISATION_TOL,
                        bb_enum='{}_buoys_localised'.format(
                            side.lower())  # NOTE: dumb
                    ),
                    A_Set_Buoy_Localisation_Plan(
                        name='A_Set{}BuoyPlan'.format(side),
                        side=side.lower(),
                        n_rows=auv_config.BUOY_LOCALISATION_N_ROWS,
                        row_sep=auv_config.BUOY_LOCALISTION_ROW_SEP,
                        row_overshoot=auv_config.
                        BUOY_LOCALISATION_ROW_OVERSHOOT,
                        # should just get this from the buoy poses themselves...
                        buoy_link=auv_config.LOCAL_LINK,
                        clockwise=auv_config.BUOY_LOCALISATION_CLOCKWISE,
                        velocity=auv_config.BUOY_LOCALISATION_VELOCITY,
                        latlon_utm_serv=auv_config.LATLONTOUTM_SERVICE,
                        utm_link=auv_config.UTM_LINK)
                ]) for side in sides
        ]

        localistion_tree = Sequence('SQ-LocalisationTree',
                                    children=localistion_tree)

        # NOTE: this is dumb
        # this is until we can check to covariance
        # matricies of the buoys
        decision_tree = Sequence('SQ-LocalisationDecisions',
                                 children=[
                                     C_PlanCompleted(),
                                     C_Buoy_Localisation_Plan_Set(),
                                     A_Set_Buoy_Decisions()
                                 ])
        localistion_tree = Fallback('FB-LocalisationTree',
                                    children=[
                                        decision_tree,
                                        C_Buoy_Localisation_Plan_Set(),
                                        localistion_tree
                                    ])
        '''
        Look at `py-tree-tree-watcher` to understand what this
        structure does.
        '''

        return localistion_tree

    def const_wall_plan_tree():

        tree = Fallback(
            'FB-WallPlanSet',
            children=[
                CheckBlackboardVariableValue(bb_enums.WALL_PLAN_SET, True,
                                             'C_WallPlanSet'),
                A_Set_Wall_Plan(
                    'A_SetWallPlan', auv_config.WALL_SURVEY_ROW_SEP,
                    auv_config.WALL_SURVEY_DEPTH, auv_config.LOCAL_LINK,
                    auv_config.UTM_LINK, auv_config.WALL_SURVEY_VELOCITY,
                    auv_config.LATLONTOUTM_SERVICE,
                    auv_config.LATLONTOUTM_SERVICE_ALTERNATIVE,
                    auv_config.WALL_SURVEY_X0_OVERSHOOT,
                    auv_config.WALL_SURVEY_X1_OVERSHOOT,
                    auv_config.WALL_SURVEY_X0_LINEUP,
                    auv_config.WALL_SURVEY_X1_LINEUP,
                    auv_config.WALL_SURVEY_FIRST_LINEUP,
                    auv_config.WALL_SURVEY_STARBOARD)
            ])
        return tree

    def const_execute_mission_tree():
        # GOTO
        goto_action = A_GotoWaypoint(
            action_namespace=auv_config.ACTION_NAMESPACE,
            goal_tolerance=auv_config.WAYPOINT_TOLERANCE,
            goal_tf_frame=auv_config.UTM_LINK)
        wp_is_goto = C_CheckWaypointType(
            expected_wp_type=imc_enums.MANEUVER_GOTO)
        goto_maneuver = Sequence(name="SQ-GotoWaypoint",
                                 children=[wp_is_goto, goto_action])

    def const_execute_mission_tree():

        # waypoint type
        wp_is_goto = C_CheckWaypointType(
            expected_wp_type=imc_enums.MANEUVER_GOTO)
        wp_is_sample = C_CheckWaypointType(
            expected_wp_type=imc_enums.MANEUVER_SAMPLE)
        wp_is = Fallback("FB-IsWaypoint", children=[wp_is_goto, wp_is_sample])
        goto_action = A_GotoWaypoint(
            action_namespace=auv_config.ACTION_NAMESPACE,
            goal_tolerance=auv_config.WAYPOINT_TOLERANCE,
            goal_tf_frame=auv_config.UTM_LINK)
        goto_maneuver = Sequence(name="SQ-GotoWaypoint",
                                 children=[wp_is, goto_action])

        #############################################################################################
        # INSPECT
        #TODO add an inspection maneuver  into bridge and neptus etc.
        # wp_is_inspect = C_CheckWaypointType(expected_wp_type = imc_enums.MANEUVER_INSPECT)
        #inspection_action = A_GotoWaypoint(action_namespace = auv_config.INSPECTION_ACTION_NAMESPACE,
        #                                   goal_tolerance = auv_config.WAYPOINT_TOLERANCE,
        #                                   goal_tf_frame = auv_config.UTM_LINK)
        # inspection_maneuver = Sequence(name="SQ-InspectWP",
        # children=[
        # wp_is_inspect,
        # inspection_action
        # ])
        #############################################################################################

        # put the known plannable maneuvers in here as each others backups
        execute_maneuver = Fallback(name="FB-ExecuteManeuver",
                                    children=[
                                        goto_maneuver,
                                    ])

        # and then execute them in order
        follow_plan = Sequence(name="SQ-FollowMissionPlan",
                               children=[
                                   C_HaveCoarseMission(),
                                   C_StartPlanReceived(),
                                   C_PlanIsNotChanged(), execute_maneuver,
                                   A_SetNextPlanAction()
                               ])

        # until the plan is done
        return Fallback(name="FB-ExecuteMissionPlan",
                        children=[C_PlanCompleted(), follow_plan])

    def const_finalize_mission():
        publish_complete = A_SimplePublisher(
            topic=auv_config.MISSION_COMPLETE_TOPIC, message_object=Empty())

        set_finalized = pt.blackboard.SetBlackboardVariable(
            variable_name=bb_enums.MISSION_FINALIZED,
            variable_value=True,
            name='A_SetMissionFinalized->True')

        unset_plan_is_go = pt.blackboard.SetBlackboardVariable(
            variable_name=bb_enums.PLAN_IS_GO,
            variable_value=False,
            name='A_SetPlanIsGo->False')

        #surface on plan completion
        #planned_surface = A_GotoWaypoint(action_namespace = auv_config.PLANNED_SURFACE_ACTION_NAMESPACE,
        #                             goal_tolerance = auv_config.WAYPOINT_TOLERANCE,
        #                             goal_tf_frame = auv_config.UTM_LINK)

        #is_submerged = C_AtDVLDepth(0.5)

        return Sequence(
            name="SQ-FinalizeMission",
            children=[
                C_HaveCoarseMission(),
                C_PlanIsNotChanged(),
                C_PlanCompleted(),
                #is_submerged,
                #planned_surface,
                publish_complete,
                unset_plan_is_go,
                set_finalized
            ])

    # The root of the tree is here

    planned_mission = const_execute_mission_tree()

    # use this to kind of set the tree to 'idle' mode that wont attempt
    # to control anything and just chills as an observer
    # finalized = CheckBlackboardVariableValue(bb_enums.MISSION_FINALIZED,
    # True,
    # "C_MissionFinalized")

    def const_sampling_tree():

        # sample
        need_to_sample = C_NeedToSample()
        sample_action = A_Sample(action_namespace=auv_config.SAMPLE_NAMESPACE,
                                 timeout=auv_config.SAMPLE_TIMEOUT)
        sample_maneuver = Sequence(name="SQ-SampleWaypoint",
                                   children=[need_to_sample, sample_action])
        return sample_maneuver

    run_tree = Fallback(
        name="FB-Run",
        children=[
            # finalized,
            const_finalize_mission(),
            # const_sampling_tree(),
            planned_mission
            #  const_leader_follower()
        ])

    root = Sequence(
        name='SQ-ROOT',
        children=[
            const_data_ingestion_tree(),
            const_safety_tree(),
            const_wall_plan_tree(),
            # const_buoy_localisation_tree(),
            # const_dvl_tree(),
            run_tree
        ])

    return ptr.trees.BehaviourTree(root)