Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
246f35e
adding row operation action
GPrathap Feb 8, 2024
3ea7a15
updating qos values
GPrathap Feb 8, 2024
453890c
Merge pull request #1 from GPrathap/row_operation
GPrathap Feb 9, 2024
e821ef9
adding row operation mission profile
GPrathap Feb 9, 2024
2c0307e
Adding workaround for https://github.com/ros2/rclpy/issues/878
GPrathap Feb 10, 2024
d029a5a
Adding workaround for https://github.com/ros2/rclpy/issues/878
GPrathap Feb 11, 2024
c2ddc30
Merge pull request #2 from GPrathap/row_operation
GPrathap Feb 11, 2024
4e631d3
fixing next goal obtaining logic
GPrathap Feb 12, 2024
893b05c
if navigation is aborted terminated inrow navigation
GPrathap Feb 13, 2024
00c62e0
setting proper id for param processing node
GPrathap Feb 15, 2024
33f8e6e
adding inrow recovery behavior
GPrathap Feb 16, 2024
9292e62
fixing several bugs in row operations
GPrathap Feb 23, 2024
0c75e28
fixing several bugs in row operations
GPrathap Feb 23, 2024
3e85853
adding current robot status
GPrathap Mar 12, 2024
1418468
fixing issues with tf
GPrathap Mar 13, 2024
49c3015
Merge branch 'humble-dev' into humble-dev
Iranaphor Mar 28, 2024
f4b9ece
trying to fix ros spin issue
GPrathap Mar 29, 2024
5ca30e4
wrap edge action type
GPrathap Apr 7, 2024
59069ce
retrieving path for reverse route navigation
GPrathap Apr 9, 2024
f0ed2cb
enable reverse edge traversal
GPrathap Apr 9, 2024
f09a306
fixing typo
GPrathap Apr 22, 2024
8c7a104
publish current nav area
GPrathap Apr 23, 2024
07a4f96
adding pole poses finder
GPrathap Apr 24, 2024
db33d37
removing pole finder
GPrathap Apr 25, 2024
b97db4a
inrow preparation make it optional
GPrathap Jun 6, 2024
5de9a8e
extract boundary row edges
GPrathap Jun 13, 2024
d99fdd1
change type
GPrathap Jun 16, 2024
31cec2d
Add manual population node for topological navigation nodes [ROS2]
ibrahimhroob Jul 13, 2024
881f2a8
adding launch file
ibrahimhroob Jul 13, 2024
f59c07f
Merge pull request #3 from LCAS/poop_topo_nodes
GPrathap Jul 15, 2024
8b1c001
Update manual_topomapping.py with rotation
ibrahimhroob Jul 19, 2024
f457e62
Update manual_topomapping.py - bug fix
ibrahimhroob Jul 19, 2024
177bd0b
Merge pull request #189 from GPrathap/humble-dev
GPrathap Jul 24, 2024
3c20880
adding logging for bt path
GPrathap Sep 16, 2024
d58d23c
pd regulator params
GPrathap Sep 17, 2024
a6766cb
Merge pull request #190 from GPrathap/aoc
GPrathap Sep 17, 2024
2172c02
setting pd params for planner
GPrathap Sep 19, 2024
dc22293
Merge pull request #191 from GPrathap/aoc
GPrathap Sep 19, 2024
69da603
publish node tag
ibrahimhroob Oct 3, 2024
c42a688
Merge pull request #193 from LCAS/node_tag
GPrathap Oct 3, 2024
247cc91
Update localisation2.py - comment this warning: Unexpected error whil…
ibrahimhroob Nov 6, 2024
94ae517
Comment out warning logs for missing 'meta' or 'tag' fields in locali…
ibrahimhroob Feb 10, 2025
0ecad3e
replaced all the topological_map_2 subscription callback with custom …
arsh09 Apr 28, 2025
0c21b35
Humble-dev (#202)
ibrahimhroob May 11, 2025
1843860
Refactor goal cancel error handling and remove unused parameters in E…
ibrahimhroob May 11, 2025
90faf08
Remove unused planner PD parameters from TopologicalNavServer
ibrahimhroob May 11, 2025
355f2c8
Merge branch 'aoc' into safe-yml-loader
ibrahimhroob May 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion topological_navigation/config/bt_tree_default.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<RecoveryNode number_of_retries="0" name="ComputePathThroughPoses">
<ReactiveSequence>
<RemovePassedGoals input_goals="{goals}" output_goals="{goals}" radius="1.5"/>
<ComputePathThroughPoses goals="{goals}" path="{path}" planner_id="GoalAligned"/>
<ComputePathThroughPoses goals="{goals}" path="{path}" planner_id="GridBased"/>
</ReactiveSequence>
<ReactiveFallback name="ComputePathThroughPosesRecoveryFallback">
<GoalUpdated/>
Expand Down
10 changes: 10 additions & 0 deletions topological_navigation/config/bt_tree_in_row_operation.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<root main_tree_to_execute="MainTree">
<BehaviorTree ID="MainTree">
<RecoveryNode number_of_retries="0" name="Harvesting">
<Wait wait_duration="5"/>
<ReactiveFallback name="ComputePathToPoseRecoveryFallback">
<ClearEntireCostmap name="ClearGlobalCostmap-Context" service_name="global_costmap/clear_entirely_global_costmap"/>
</ReactiveFallback>
</RecoveryNode>
</BehaviorTree>
</root>
10 changes: 10 additions & 0 deletions topological_navigation/config/bt_tree_in_row_recovery.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<root main_tree_to_execute="MainTree">
<BehaviorTree ID="MainTree">
<RecoveryNode number_of_retries="0" name="Harvesting">
<Wait wait_duration="5"/>
<ReactiveFallback name="ComputePathToPoseRecoveryFallback">
<ClearEntireCostmap name="ClearGlobalCostmap-Context" service_name="global_costmap/clear_entirely_global_costmap"/>
</ReactiveFallback>
</RecoveryNode>
</BehaviorTree>
</root>
19,889 changes: 19,889 additions & 0 deletions topological_navigation/cyclonedds.log

Large diffs are not rendered by default.

761 changes: 650 additions & 111 deletions topological_navigation/topological_navigation/edge_action_manager2.py

Large diffs are not rendered by default.

22 changes: 20 additions & 2 deletions topological_navigation/topological_navigation/policy_marker2.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python3

import math

import yaml
import rclpy, json
from rclpy.node import Node
from rclpy.qos import QoSProfile, DurabilityPolicy
Expand All @@ -17,6 +17,23 @@
from topological_navigation_msgs.msg import TopologicalMap, NavRoute
from std_msgs.msg import String

# this ensures that all the poses and translates
# are float-type and not int-type as there is an
# assertion in ros2 messages (vector3, pose etc.)
# for float-type [x,y,z,w] keys.
class CustomSafeLoader(yaml.SafeLoader):
def construct_mapping(self, node, deep=False):
mapping = super().construct_mapping(node, deep=deep)

# this can be extended to test the validity of the tmap2
# as well at load time (or add missing keys)
for key in ['x', 'y', 'z', 'w']:
if key in mapping and isinstance(mapping[key], int):
mapping[key] = float(mapping[key])

return mapping


class PoliciesVis(Node):

def __init__(self):
Expand All @@ -34,7 +51,8 @@ def __init__(self):
def map_callback(self, msg):
self.get_logger().info('map callback triggered')
# self.map = msg
self.lnodes = json.loads(msg.data)
# self.lnodes = json.loads(msg.data)
self.lnodes = yaml.load( msg.data, Loader = CustomSafeLoader)
self.topol_map = self.lnodes["pointset"]
self.rsearch = TopologicalRouteSearch2(self.lnodes)

Expand Down
112 changes: 100 additions & 12 deletions topological_navigation/topological_navigation/scripts/actions_bt.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,72 @@ def __init__(self):
self.DRIVE_ON_HEADING = "DriveOnHeading"

self.ROW_TRAVERSAL = "row_traversal"
self.ROW_OPERATION = "row_operation"
self.ROW_RECOVERY = "row_recovery"
self.ROW_CHANGE = "row_change"
self.GOAL_ALIGN = "goal_align"
self.GOAL_ALIGN_INDEX = ["ca"]
self.GOAL_ALIGN_GOAL = ["cb"]
self.ABORT_NOT_CONTINUE = [self.GOAL_ALIGN, self.ROW_CHANGE, self.ROW_TRAVERSAL, self.NAVIGATE_TO_POSE, self.NAVIGATE_THROUGH_POSES]
self.ROW_START_INDEX = "a"
self.ROW_COLUMN_START_INDEX = "c"
self.ROW_COLUMN_START_NEXT_INDEX = "b"
self.OUTSIDE_EDGE_START_INDEX = "WayPoint"

self.INSIDE_POLYTUNNEL = "INSIDE_POLYTUNNEL"
self.OUTSIDE_POLYTUNNEL = "OUTSIDE_POLYTUNNEL"
self.TRANSITION_INTO_POLYTUNNEL = "TRANSITION_INTO_POLYTUNNEL"


self.ROBOT_STATUS_PREPARATION_STATE = "PREPARATION_STATE"
self.ROBOT_STATUS_AUTONOMOUS_NAVIGATION_STATE = "AUTONOMOUS_NAVIGATION_STATE"
self.ROBOT_STATUS_AUTONOMOUS_HARVESTING_STATE = "AUTONOMOUS_HARVESTING_STATE"
self.ROBOT_STATUS_AUTONOMOUS_RECOVERY_STATE = "AUTONOMOUS_RECOVERY_STATE"
self.ROBOT_STATUS_DISABLE_STATE = "DISABLE_STATE"
self.ROBOT_STATUS_NATURAL_STATE = "NATURAL_STATE"

self.ROBOT_CURRENT_STATUS = {}
self.ROBOT_CURRENT_STATUS[self.ROBOT_STATUS_PREPARATION_STATE] = 0
self.ROBOT_CURRENT_STATUS[self.ROBOT_STATUS_AUTONOMOUS_NAVIGATION_STATE] = 1
self.ROBOT_CURRENT_STATUS[self.ROBOT_STATUS_AUTONOMOUS_HARVESTING_STATE] = 2
self.ROBOT_CURRENT_STATUS[self.ROBOT_STATUS_AUTONOMOUS_RECOVERY_STATE] = 3
self.ROBOT_CURRENT_STATUS[self.ROBOT_STATUS_DISABLE_STATE] = 4
self.ROBOT_CURRENT_STATUS[self.ROBOT_STATUS_NATURAL_STATE] = 5

self.ABORT_NOT_CONTINUE = [self.GOAL_ALIGN, self.ROW_CHANGE, self.ROW_TRAVERSAL
, self.NAVIGATE_TO_POSE, self.NAVIGATE_THROUGH_POSES
, self.ROW_OPERATION, self.ROW_RECOVERY]

self.BT_DEFAULT = "bt_tree_default"
self.BT_IN_ROW = "bt_tree_in_row"
self.BT_GOAL_ALIGN = "bt_tree_goal_align"

self.BT_IN_ROW = "bt_tree_in_row"
self.BT_IN_ROW_OPERATION = "bt_tree_in_row_operation"
self.BT_IN_ROW_RECOVERY = "bt_tree_in_row_recovery"

self.navigation_actions = [
self.NAVIGATE_TO_POSE,
self.NAVIGATE_THROUGH_POSES,
self.DRIVE_ON_HEADING,
self.ROW_CHANGE,
self.ROW_TRAVERSAL
self.ROW_TRAVERSAL,
self.ROW_OPERATION,
self.ROW_RECOVERY
]

self.bt_tree_types = [
self.BT_IN_ROW,
self.BT_DEFAULT,
self.BT_GOAL_ALIGN
self.BT_GOAL_ALIGN,
self.BT_IN_ROW_OPERATION,
self.BT_IN_ROW_RECOVERY,
]

self.bt_tree_with_actions = {}
self.bt_tree_with_actions[self.ROW_TRAVERSAL] = self.BT_IN_ROW
self.bt_tree_with_actions[self.NAVIGATE_THROUGH_POSES] = self.BT_DEFAULT
self.bt_tree_with_actions[self.NAVIGATE_TO_POSE] = self.BT_DEFAULT
self.bt_tree_with_actions[self.GOAL_ALIGN] = self.BT_GOAL_ALIGN
self.bt_tree_with_actions[self.ROW_TRAVERSAL] = self.BT_IN_ROW
self.bt_tree_with_actions[self.ROW_OPERATION] = self.BT_IN_ROW_OPERATION
self.bt_tree_with_actions[self.ROW_RECOVERY] = self.BT_IN_ROW_RECOVERY

self.status_mapping = {}
self.status_mapping[0] = "STATUS_UNKNOWN"
Expand All @@ -46,11 +83,11 @@ def __init__(self):
self.status_mapping[5] = "STATUS_CANCELED"
self.status_mapping[6] = "STATUS_ABORTED"

self.goal_cancle_error_codes = {}
self.goal_cancle_error_codes[0] = "ERROR_NONE"
self.goal_cancle_error_codes[1] = "ERROR_REJECTED"
self.goal_cancle_error_codes[2] = "ERROR_UNKNOWN_GOAL_ID"
self.goal_cancle_error_codes[3] = "ERROR_GOAL_TERMINATED"
self.goal_cancel_error_codes = {}
self.goal_cancel_error_codes[0] = "ERROR_NONE"
self.goal_cancel_error_codes[1] = "ERROR_REJECTED"
self.goal_cancel_error_codes[2] = "ERROR_UNKNOWN_GOAL_ID"
self.goal_cancel_error_codes[3] = "ERROR_GOAL_TERMINATED"

self.planner_with_goal_checker_config = {
"dwb_core::DWBLocalPlanner": {
Expand All @@ -61,13 +98,55 @@ def __init__(self):
"goal_checker.xy_goal_tolerance": 0.1,
"goal_checker.yaw_goal_tolerance": 0.05,
},
"rownav_local_planner::TebLocalPlannerROS":{
"goal_checker.xy_goal_tolerance": 0.1,
"goal_checker.yaw_goal_tolerance": 0.6,
},
"behavioral_controller::BehavioralController":{
"goal_checker.xy_goal_tolerance": 0.1,
"goal_checker.yaw_goal_tolerance": 0.6,
}
}

self.bt_tree_with_control_server_config = {}
self.bt_tree_with_control_server_config[self.ROW_TRAVERSAL] = "dwb_core::DWBLocalPlanner"
self.bt_tree_with_control_server_config[self.NAVIGATE_THROUGH_POSES] = "dwb_core::DWBLocalPlanner"
self.bt_tree_with_control_server_config[self.NAVIGATE_TO_POSE] = "dwb_core::DWBLocalPlanner"
self.bt_tree_with_control_server_config[self.GOAL_ALIGN] = "dwb_core::DWBLocalPlanner"
self.bt_tree_with_control_server_config[self.ROW_RECOVERY] = "dwb_core::DWBLocalPlanner"

self.planner_with_pd_regulator_config = {
"dwb_core::DWBLocalPlanner": {
"kp_v": 40.0,
"kd_v": 0.1,
"kp_w": 12.0,
"kd_w": 0.1,
},
"teb_local_planner::TebLocalPlannerROS": {
"kp_v": 40.0,
"kd_v": 0.1,
"kp_w": 12.0,
"kd_w": 0.1,
},
"rownav_local_planner::TebLocalPlannerROS":{
"kp_v": 40.0,
"kd_v": 0.1,
"kp_w": 12.0,
"kd_w": 0.1,
},
"behavioral_controller::BehavioralController":{
"kp_v": 40.0,
"kd_v": 0.1,
"kp_w": 12.0,
"kd_w": 0.1,
}
}

def getCodeForRobotCurrentStatus(self, msg):
if msg not in self.ROBOT_CURRENT_STATUS:
print("The {} is not one of configured robot status types".format(msg))
return self.ROBOT_CURRENT_STATUS[self.ROBOT_STATUS_DISABLE_STATE]
return self.ROBOT_CURRENT_STATUS[msg]

def setPlanner(self, planner_name, action_type):
self.bt_tree_with_control_server_config[action_type] = planner_name
Expand All @@ -78,4 +157,13 @@ def setPlannerParams(self, planner_name, xy_goal_tolerance, yaw_goal_tolerance):
return
self.planner_with_goal_checker_config[planner_name]["goal_checker.xy_goal_tolerance"] = xy_goal_tolerance
self.planner_with_goal_checker_config[planner_name]["goal_checker.yaw_goal_tolerance"] = yaw_goal_tolerance
print("Setting planner {} params xy_goal_tolerance: {}, yaw_goal_tolerance: {}".format(planner_name, xy_goal_tolerance, yaw_goal_tolerance))
print("Setting planner {} params xy_goal_tolerance: {}, yaw_goal_tolerance: {}".format(planner_name, xy_goal_tolerance, yaw_goal_tolerance))

def setPDRegulstorParams(self, planner_name, pd_params, robot_controller_name):
if not planner_name in self.planner_with_goal_checker_config:
print("The planner {} is not one of configured types".format(planner_name))
return
parmas_names = ["kp_v", "kd_v", "kp_w", "kd_w"]
for index, val in zip(parmas_names, pd_params):
self.planner_with_pd_regulator_config[planner_name][index] = val
print("Setting planner {} params kp_v: {} kd_v: {} kp_w: {} kd_w: {} ".format(planner_name, pd_params[0], pd_params[1], pd_params[2], pd_params[3]))
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,30 @@
"""

import sys
import rclpy, json
import rclpy, json , yaml
from std_msgs.msg import String
from topological_navigation_msgs.srv import GetRouteTo, GetRouteBetween
from topological_navigation.route_search2 import RouteChecker, TopologicalRouteSearch2, get_route_distance
from rclpy.qos import QoSProfile, HistoryPolicy, ReliabilityPolicy, DurabilityPolicy
from rclpy.executors import MultiThreadedExecutor

# this ensures that all the poses and translates
# are float-type and not int-type as there is an
# assertion in ros2 messages (vector3, pose etc.)
# for float-type [x,y,z,w] keys.
class CustomSafeLoader(yaml.SafeLoader):
def construct_mapping(self, node, deep=False):
mapping = super().construct_mapping(node, deep=deep)

# this can be extended to test the validity of the tmap2
# as well at load time (or add missing keys)
for key in ['x', 'y', 'z', 'w']:
if key in mapping and isinstance(mapping[key], int):
mapping[key] = float(mapping[key])

return mapping


class SearchPolicyServer(rclpy.node.Node):

def __init__(self, name):
Expand Down Expand Up @@ -57,7 +74,8 @@ def get_routeb_cb(self, req, res):
return res

def map_callback(self, msg) :
self.lnodes = json.loads(msg.data)
# self.lnodes = json.loads(msg.data)
self.lnodes = yaml.load( msg.data, Loader=CustomSafeLoader)
self.topol_map = self.lnodes["pointset"]
self.rsearch = TopologicalRouteSearch2(self.lnodes)
self._map_received = True
Expand Down
Loading