Skip to content

Commit c7589c9

Browse files
Add warehouse routes for nav2 route server (#5160)
* Added routes for warehouse map. Signed-off-by: Leander Stephen D'Souza <[email protected]> * Renamed routes for the depot warehouse to match naming convention. Signed-off-by: Leander Stephen D'Souza <[email protected]> * Rename turtlebot4 geojson graphs to remove the turtlebot4 prefix. Signed-off-by: Leander Stephen D'Souza <[email protected]> * Restructured warehouse_graph to enable bidirectional navigation. Signed-off-by: Leander Stephen D'Souza <[email protected]> * Improved connectivity of the warehouse graph. Signed-off-by: Leander Stephen D'Souza <[email protected]> * Added keepout and speed zones to the route example. Signed-off-by: Leander Stephen D'Souza <[email protected]> * Added flexibility in setting goals for the route example. Signed-off-by: Leander Stephen D'Souza <[email protected]> * Move euler to quaternion function to utils.py. Signed-off-by: Leander Stephen D'Souza <[email protected]> * Added additional routes to the warehouse graph. Signed-off-by: Leander Stephen D'Souza <[email protected]> * Shift warehouse spawn location to match start of graph node. Signed-off-by: Leander Stephen D'Souza <[email protected]> * Added parameters to control enabling of costmap filters. Signed-off-by: Leander Stephen D'Souza <[email protected]> * Added node information to the route example launch file. Signed-off-by: Leander Stephen D'Souza <[email protected]> --------- Signed-off-by: Leander Stephen D'Souza <[email protected]>
1 parent 7436bbe commit c7589c9

File tree

7 files changed

+420
-21
lines changed

7 files changed

+420
-21
lines changed

nav2_bringup/graphs/turtlebot4_graph.geojson renamed to nav2_bringup/graphs/depot_graph.geojson

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"type": "FeatureCollection",
3-
"name": "turtlebot4_graph",
3+
"name": "depot_graph",
44
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } },
55
"features": [
66
{ "type": "Feature", "properties": { "id": 0 }, "geometry": { "type": "Point", "coordinates": [ 0.624282608695647, 12.880652173913044 ] } },

nav2_bringup/graphs/warehouse_graph.geojson

Lines changed: 276 additions & 0 deletions
Large diffs are not rendered by default.

nav2_bringup/launch/tb4_loopback_simulation_launch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def generate_launch_description() -> LaunchDescription:
6363

6464
declare_graph_file_cmd = DeclareLaunchArgument(
6565
'graph',
66-
default_value=os.path.join(bringup_dir, 'graphs', 'turtlebot4_graph.geojson'),
66+
default_value=os.path.join(bringup_dir, 'graphs', 'depot_graph.geojson'),
6767
)
6868

6969
declare_params_file_cmd = DeclareLaunchArgument(

nav2_bringup/launch/tb4_simulation_launch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
'R': 0.00, 'P': 0.00, 'Y': 0.00
3535
},
3636
'warehouse': {
37-
'x': 2.12, 'y': -21.3, 'z': 0.01,
37+
'x': 2.00, 'y': -19.65, 'z': 0.01,
3838
'R': 0.00, 'P': 0.00, 'Y': 1.57
3939
}
4040
}
@@ -114,7 +114,7 @@ def generate_launch_description() -> LaunchDescription:
114114

115115
declare_graph_file_cmd = DeclareLaunchArgument(
116116
'graph',
117-
default_value=os.path.join(bringup_dir, 'graphs', 'turtlebot4_graph.geojson'),
117+
default_value=os.path.join(bringup_dir, 'graphs', f'{MAP_TYPE}_graph.geojson'),
118118
)
119119

120120
declare_use_sim_time_cmd = DeclareLaunchArgument(

nav2_simple_commander/launch/route_example_launch.py

Lines changed: 90 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,80 @@
2626
from launch.substitutions import Command, LaunchConfiguration, PythonExpression
2727
from launch_ros.actions import Node
2828

29+
# Define local map types
30+
MAP_POSES_DICT = {
31+
'depot': {
32+
'x': -8.00, 'y': 0.00, 'z': 0.01,
33+
'R': 0.00, 'P': 0.00, 'Y': 0.00
34+
},
35+
'warehouse': {
36+
'x': 2.00, 'y': -19.65, 'z': 0.01,
37+
'R': 0.00, 'P': 0.00, 'Y': 0.00
38+
}
39+
}
40+
41+
ROUTE_POSES_DICT = {
42+
'start': {
43+
'depot': {
44+
'x': 7.5, 'y': 7.5, 'yaw': 0.00 # 3rd node
45+
},
46+
'warehouse': {
47+
'x': 2.00, 'y': -19.65, 'yaw': 0.00 # 0th node
48+
}
49+
},
50+
'goal': {
51+
'depot': {
52+
'x': 20.12, 'y': 11.83, 'yaw': 0.00 # 13th node
53+
},
54+
'warehouse': {
55+
'x': -13.5, 'y': -3.15, 'yaw': 0.00 # 61st node
56+
}
57+
}
58+
}
59+
MAP_TYPE = 'depot' # Change this to 'warehouse' for warehouse map
60+
2961

3062
def generate_launch_description() -> LaunchDescription:
3163
nav2_bringup_dir = get_package_share_directory('nav2_bringup')
3264
sim_dir = get_package_share_directory('nav2_minimal_tb4_sim')
3365
desc_dir = get_package_share_directory('nav2_minimal_tb4_description')
3466

3567
robot_sdf = os.path.join(desc_dir, 'urdf', 'standard', 'turtlebot4.urdf.xacro')
36-
world = os.path.join(sim_dir, 'worlds', 'depot.sdf')
37-
map_yaml_file = os.path.join(nav2_bringup_dir, 'maps', 'depot.yaml')
38-
graph_filepath = os.path.join(nav2_bringup_dir, 'graphs', 'turtlebot4_graph.geojson')
68+
world = os.path.join(sim_dir, 'worlds', f'{MAP_TYPE}.sdf')
69+
map_yaml_file = os.path.join(nav2_bringup_dir, 'maps', f'{MAP_TYPE}.yaml')
70+
graph_filepath = os.path.join(
71+
nav2_bringup_dir, 'graphs', f'{MAP_TYPE}_graph.geojson')
3972

4073
# Launch configuration variables
4174
headless = LaunchConfiguration('headless')
75+
use_keepout_zones = LaunchConfiguration('use_keepout_zones')
76+
use_speed_zones = LaunchConfiguration('use_speed_zones')
77+
keepout_mask_yaml_file = LaunchConfiguration('keepout_mask')
78+
speed_mask_yaml_file = LaunchConfiguration('speed_mask')
4279

4380
# Declare the launch arguments
4481
declare_headless_cmd = DeclareLaunchArgument(
4582
'headless', default_value='False', description='Whether to execute gzclient)'
4683
)
84+
declare_use_keepout_zones_cmd = DeclareLaunchArgument(
85+
'use_keepout_zones', default_value='True',
86+
description='Whether to enable keepout zones or not'
87+
)
88+
89+
declare_use_speed_zones_cmd = DeclareLaunchArgument(
90+
'use_speed_zones', default_value='True',
91+
description='Whether to enable speed zones or not'
92+
)
93+
declare_keepout_mask_yaml_cmd = DeclareLaunchArgument(
94+
'keepout_mask',
95+
default_value=os.path.join(nav2_bringup_dir, 'maps', f'{MAP_TYPE}_keepout.yaml'),
96+
description='Full path to keepout mask file to load',
97+
)
98+
declare_speed_mask_yaml_cmd = DeclareLaunchArgument(
99+
'speed_mask',
100+
default_value=os.path.join(nav2_bringup_dir, 'maps', f'{MAP_TYPE}_speed.yaml'),
101+
description='Full path to speed mask file to load',
102+
)
47103

48104
# start the simulation
49105
world_sdf = tempfile.mktemp(prefix='nav2_', suffix='.sdf')
@@ -79,12 +135,13 @@ def generate_launch_description() -> LaunchDescription:
79135
os.path.join(sim_dir, 'launch', 'spawn_tb4.launch.py')),
80136
launch_arguments={'use_sim_time': 'True',
81137
'robot_sdf': robot_sdf,
82-
'x_pose': '-8.0',
83-
'y_pose': '0.0',
84-
'z_pose': '0.0',
85-
'roll': '0.0',
86-
'pitch': '0.0',
87-
'yaw': '0.0'}.items())
138+
'x_pose': str(MAP_POSES_DICT[MAP_TYPE]['x']),
139+
'y_pose': str(MAP_POSES_DICT[MAP_TYPE]['y']),
140+
'z_pose': str(MAP_POSES_DICT[MAP_TYPE]['z']),
141+
'roll': str(MAP_POSES_DICT[MAP_TYPE]['R']),
142+
'pitch': str(MAP_POSES_DICT[MAP_TYPE]['P']),
143+
'yaw': str(MAP_POSES_DICT[MAP_TYPE]['Y']),
144+
}.items())
88145

89146
start_robot_state_publisher_cmd = Node(
90147
package='robot_state_publisher',
@@ -107,12 +164,31 @@ def generate_launch_description() -> LaunchDescription:
107164
bringup_cmd = IncludeLaunchDescription(
108165
PythonLaunchDescriptionSource(
109166
os.path.join(nav2_bringup_dir, 'launch', 'bringup_launch.py')),
110-
launch_arguments={'map': map_yaml_file, 'graph': graph_filepath}.items())
167+
launch_arguments={
168+
'map': map_yaml_file,
169+
'graph': graph_filepath,
170+
'use_keepout_zones': use_keepout_zones,
171+
'use_speed_zones': use_speed_zones,
172+
'keepout_mask': keepout_mask_yaml_file,
173+
'speed_mask': speed_mask_yaml_file,
174+
}.items())
111175

112176
# start the demo autonomy task
113177
demo_cmd = Node(
114178
package='nav2_simple_commander',
115179
executable='example_route',
180+
parameters=[{
181+
'start_pose': {
182+
'x': ROUTE_POSES_DICT['start'][MAP_TYPE]['x'],
183+
'y': ROUTE_POSES_DICT['start'][MAP_TYPE]['y'],
184+
'yaw': ROUTE_POSES_DICT['start'][MAP_TYPE]['yaw']
185+
},
186+
'goal_pose': {
187+
'x': ROUTE_POSES_DICT['goal'][MAP_TYPE]['x'],
188+
'y': ROUTE_POSES_DICT['goal'][MAP_TYPE]['y'],
189+
'yaw': ROUTE_POSES_DICT['goal'][MAP_TYPE]['yaw']
190+
},
191+
}],
116192
emulate_tty=True,
117193
output='screen')
118194

@@ -122,6 +198,10 @@ def generate_launch_description() -> LaunchDescription:
122198

123199
ld = LaunchDescription()
124200
ld.add_action(declare_headless_cmd)
201+
ld.add_action(declare_use_keepout_zones_cmd)
202+
ld.add_action(declare_use_speed_zones_cmd)
203+
ld.add_action(declare_keepout_mask_yaml_cmd)
204+
ld.add_action(declare_speed_mask_yaml_cmd)
125205
ld.add_action(set_env_vars_resources)
126206
ld.add_action(world_sdf_xacro)
127207
ld.add_action(remove_temp_sdf_file)

nav2_simple_commander/nav2_simple_commander/example_route.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from geometry_msgs.msg import Pose, PoseStamped
1717
from nav2_simple_commander.robot_navigator import BasicNavigator, RunningTask, TaskResult
18+
from nav2_simple_commander.utils import euler_to_quaternion
1819
import rclpy
1920
from std_msgs.msg import Header
2021

@@ -34,16 +35,35 @@ def toPoseStamped(pt: Pose, header: Header) -> PoseStamped:
3435
def main() -> None:
3536
rclpy.init()
3637

38+
node = rclpy.create_node('route_example')
39+
40+
node.declare_parameter('start_pose.x', 0.0)
41+
node.declare_parameter('start_pose.y', 0.0)
42+
node.declare_parameter('start_pose.yaw', 0.0)
43+
44+
node.declare_parameter('goal_pose.x', 0.0)
45+
node.declare_parameter('goal_pose.y', 0.0)
46+
node.declare_parameter('goal_pose.yaw', 0.0)
47+
48+
start_x = node.get_parameter('start_pose.x').value
49+
start_y = node.get_parameter('start_pose.y').value
50+
start_yaw = node.get_parameter('start_pose.yaw').value
51+
52+
goal_x = node.get_parameter('goal_pose.x').value
53+
goal_y = node.get_parameter('goal_pose.y').value
54+
goal_yaw = node.get_parameter('goal_pose.yaw').value
55+
56+
node.destroy_node()
57+
3758
navigator = BasicNavigator()
3859

3960
# Set our demo's initial pose
4061
initial_pose = PoseStamped()
4162
initial_pose.header.frame_id = 'map'
4263
initial_pose.header.stamp = navigator.get_clock().now().to_msg()
43-
initial_pose.pose.position.x = 7.5
44-
initial_pose.pose.position.y = 7.5
45-
initial_pose.pose.orientation.z = 0.0
46-
initial_pose.pose.orientation.w = 1.0
64+
initial_pose.pose.position.x = start_x
65+
initial_pose.pose.position.y = start_y
66+
initial_pose.pose.orientation = euler_to_quaternion(0.0, 0.0, start_yaw)
4767
navigator.setInitialPose(initial_pose)
4868

4969
# Activate navigation, if not autostarted. This should be called after setInitialPose()
@@ -66,9 +86,9 @@ def main() -> None:
6686
goal_pose = PoseStamped()
6787
goal_pose.header.frame_id = 'map'
6888
goal_pose.header.stamp = navigator.get_clock().now().to_msg()
69-
goal_pose.pose.position.x = 20.12
70-
goal_pose.pose.position.y = 11.83
71-
goal_pose.pose.orientation.w = 1.0
89+
goal_pose.pose.position.x = goal_x
90+
goal_pose.pose.position.y = goal_y
91+
goal_pose.pose.orientation = euler_to_quaternion(0.0, 0.0, goal_yaw)
7292

7393
# Sanity check a valid route exists using PoseStamped.
7494
# May also use NodeIDs on the graph if they are known by passing them instead as `int`

nav2_simple_commander/nav2_simple_commander/utils.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
1616

1717
"""General utility functions."""
1818

19+
import math
1920
import os
2021
import signal
2122
import subprocess
2223

24+
from geometry_msgs.msg import Quaternion
25+
2326

2427
def find_os_processes(name: str) -> list[tuple[str, str]]:
2528
"""Find all the processes that are running gz sim."""
@@ -53,3 +56,23 @@ def kill_os_processes(name: str) -> None:
5356
kill_process(pid)
5457
else:
5558
print(f'No processes found starting with {name}')
59+
60+
61+
def euler_to_quaternion(
62+
roll: float = 0.0, pitch: float = 0.0,
63+
yaw: float = 0.0) -> Quaternion:
64+
"""Convert euler angles to quaternion."""
65+
cy = math.cos(yaw * 0.5)
66+
sy = math.sin(yaw * 0.5)
67+
cp = math.cos(pitch * 0.5)
68+
sp = math.sin(pitch * 0.5)
69+
cr = math.cos(roll * 0.5)
70+
sr = math.sin(roll * 0.5)
71+
72+
q = Quaternion()
73+
q.w = cr * cp * cy + sr * sp * sy
74+
q.x = sr * cp * cy - cr * sp * sy
75+
q.y = cr * sp * cy + sr * cp * sy
76+
q.z = cr * cp * sy - sr * sp * cy
77+
78+
return q

0 commit comments

Comments
 (0)