add humble-navigation2

This commit is contained in:
X-lanni
2025-05-27 19:03:40 +08:00
parent 974abb5e1e
commit e74ec539c2
1280 changed files with 204114 additions and 0 deletions
+17
View File
@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.5)
project(nav2_common NONE)
find_package(ament_cmake_core REQUIRED)
find_package(ament_cmake_python REQUIRED)
ament_python_install_package(nav2_common)
ament_package(
CONFIG_EXTRAS "nav2_common-extras.cmake"
)
install(
DIRECTORY cmake
DESTINATION share/${PROJECT_NAME}
)
@@ -0,0 +1,57 @@
# Copyright 2019 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Standard Nav2 project setup
#
# @public
#
macro(nav2_package)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to Release as none was specified.")
set(CMAKE_BUILD_TYPE "Release" CACHE
STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic -Werror -Wdeprecated -fPIC)
endif()
option(COVERAGE_ENABLED "Enable code coverage" FALSE)
if(COVERAGE_ENABLED)
add_compile_options(--coverage)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --coverage")
endif()
# Defaults for Microsoft C++ compiler
if(MSVC)
# https://blog.kitware.com/create-dlls-on-windows-without-declspec-using-new-cmake-export-all-feature/
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
# Enable Math Constants
# https://docs.microsoft.com/en-us/cpp/c-runtime-library/math-constants?view=vs-2019
add_compile_definitions(
_USE_MATH_DEFINES
)
endif()
endmacro()
@@ -0,0 +1,17 @@
# Copyright 2019 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(AMENT_BUILD_CONFIGURATION_KEYWORD_SEPARATOR ":")
include("${nav2_common_DIR}/nav2_package.cmake")
@@ -0,0 +1,18 @@
# Copyright (c) 2019 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from .has_node_params import HasNodeParams
from .rewritten_yaml import RewrittenYaml
from .replace_string import ReplaceString
from .parse_multirobot_pose import ParseMultiRobotPose
@@ -0,0 +1,60 @@
# Copyright (c) 2021 PAL Robotics S.L.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import List
from typing import Text
import yaml
import launch
import sys # delete this
class HasNodeParams(launch.Substitution):
"""
Substitution that checks if a param file contains parameters for a node
Used in launch system
"""
def __init__(self,
source_file: launch.SomeSubstitutionsType,
node_name: Text) -> None:
super().__init__()
"""
Construct the substitution
:param: source_file the parameter YAML file
:param: node_name the name of the node to check
"""
from launch.utilities import normalize_to_list_of_substitutions # import here to avoid loop
self.__source_file = normalize_to_list_of_substitutions(source_file)
self.__node_name = node_name
@property
def name(self) -> List[launch.Substitution]:
"""Getter for name."""
return self.__source_file
def describe(self) -> Text:
"""Return a description of this substitution as a string."""
return ''
def perform(self, context: launch.LaunchContext) -> Text:
yaml_filename = launch.utilities.perform_substitutions(context, self.name)
data = yaml.safe_load(open(yaml_filename, 'r'))
if self.__node_name in data.keys():
return "True"
return "False"
@@ -0,0 +1,82 @@
# Copyright (c) 2023 LG Electronics.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import yaml
import sys
from typing import Text, Dict
class ParseMultiRobotPose():
"""
Parsing argument using sys module
"""
def __init__(self, target_argument: Text):
"""
Parse arguments for multi-robot's pose
for example,
`ros2 launch nav2_bringup bringup_multirobot_launch.py
robots:="robot1={x: 1.0, y: 1.0, yaw: 0.0};
robot2={x: 1.0, y: 1.0, z: 1.0, roll: 0.0, pitch: 1.5707, yaw: 1.5707}"`
`target_argument` shall be 'robots'.
Then, this will parse a string value for `robots` argument.
Each robot name which is corresponding to namespace and pose of it will be separted by `;`.
The pose consists of x, y and yaw with YAML format.
:param: target argument name to parse
"""
self.__args: Text = self.__parse_argument(target_argument)
def __parse_argument(self, target_argument: Text) -> Text:
"""
get value of target argument
"""
if len(sys.argv) > 4:
argv = sys.argv[4:]
for arg in argv:
if arg.startswith(target_argument + ":="):
return arg.replace(target_argument + ":=", "")
return ""
def value(self) -> Dict:
"""
get value of target argument
"""
args = self.__args
parsed_args = list() if len(args) == 0 else args.split(';')
multirobots = dict()
for arg in parsed_args:
key_val = arg.strip().split('=')
if len(key_val) != 2:
continue
key = key_val[0].strip()
val = key_val[1].strip()
robot_pose = yaml.safe_load(val)
if 'x' not in robot_pose:
robot_pose['x'] = 0.0
if 'y' not in robot_pose:
robot_pose['y'] = 0.0
if 'z' not in robot_pose:
robot_pose['z'] = 0.0
if 'roll' not in robot_pose:
robot_pose['roll'] = 0.0
if 'pitch' not in robot_pose:
robot_pose['pitch'] = 0.0
if 'yaw' not in robot_pose:
robot_pose['yaw'] = 0.0
multirobots[key] = robot_pose
return multirobots
@@ -0,0 +1,87 @@
# Copyright (c) 2019 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Dict
from typing import List
from typing import Text
from typing import Optional
import tempfile
import launch
class ReplaceString(launch.Substitution):
"""
Substitution that replaces strings on a given file.
Used in launch system
"""
def __init__(self,
source_file: launch.SomeSubstitutionsType,
replacements: Dict,
condition: Optional[launch.Condition] = None) -> None:
super().__init__()
from launch.utilities import normalize_to_list_of_substitutions # import here to avoid loop
self.__source_file = normalize_to_list_of_substitutions(source_file)
self.__replacements = {}
for key in replacements:
self.__replacements[key] = normalize_to_list_of_substitutions(replacements[key])
self.__condition = condition
@property
def name(self) -> List[launch.Substitution]:
"""Getter for name."""
return self.__source_file
@property
def condition(self) -> Optional[launch.Condition]:
"""Getter for condition."""
return self.__condition
def describe(self) -> Text:
"""Return a description of this substitution as a string."""
return ''
def perform(self, context: launch.LaunchContext) -> Text:
yaml_filename = launch.utilities.perform_substitutions(context, self.name)
if self.__condition is None or self.__condition.evaluate(context):
output_file = tempfile.NamedTemporaryFile(mode='w', delete=False)
replacements = self.resolve_replacements(context)
try:
input_file = open(yaml_filename, 'r')
self.replace(input_file, output_file, replacements)
except Exception as err: # noqa: B902
print('ReplaceString substitution error: ', err)
finally:
input_file.close()
output_file.close()
return output_file.name
else:
return yaml_filename
def resolve_replacements(self, context):
resolved_replacements = {}
for key in self.__replacements:
resolved_replacements[key] = launch.utilities.perform_substitutions(context, self.__replacements[key])
return resolved_replacements
def replace(self, input_file, output_file, replacements):
for line in input_file:
for key, value in replacements.items():
if isinstance(key, str) and isinstance(value, str):
if key in line:
line = line.replace(key, value)
else:
raise TypeError('A provided replacement pair is not a string. Both key and value should be strings.')
output_file.write(line)
@@ -0,0 +1,190 @@
# Copyright (c) 2019 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Dict
from typing import List
from typing import Text
from typing import Optional
import yaml
import tempfile
import launch
class DictItemReference:
def __init__(self, dictionary, key):
self.dictionary = dictionary
self.dictKey = key
def key(self):
return self.dictKey
def setValue(self, value):
self.dictionary[self.dictKey] = value
class RewrittenYaml(launch.Substitution):
"""
Substitution that modifies the given YAML file.
Used in launch system
"""
def __init__(self,
source_file: launch.SomeSubstitutionsType,
param_rewrites: Dict,
root_key: Optional[launch.SomeSubstitutionsType] = None,
key_rewrites: Optional[Dict] = None,
convert_types = False) -> None:
super().__init__()
"""
Construct the substitution
:param: source_file the original YAML file to modify
:param: param_rewrites mappings to replace
:param: root_key if provided, the contents are placed under this key
:param: key_rewrites keys of mappings to replace
:param: convert_types whether to attempt converting the string to a number or boolean
"""
from launch.utilities import normalize_to_list_of_substitutions # import here to avoid loop
self.__source_file = normalize_to_list_of_substitutions(source_file)
self.__param_rewrites = {}
self.__key_rewrites = {}
self.__convert_types = convert_types
self.__root_key = None
for key in param_rewrites:
self.__param_rewrites[key] = normalize_to_list_of_substitutions(param_rewrites[key])
if key_rewrites is not None:
for key in key_rewrites:
self.__key_rewrites[key] = normalize_to_list_of_substitutions(key_rewrites[key])
if root_key is not None:
self.__root_key = normalize_to_list_of_substitutions(root_key)
@property
def name(self) -> List[launch.Substitution]:
"""Getter for name."""
return self.__source_file
def describe(self) -> Text:
"""Return a description of this substitution as a string."""
return ''
def perform(self, context: launch.LaunchContext) -> Text:
yaml_filename = launch.utilities.perform_substitutions(context, self.name)
rewritten_yaml = tempfile.NamedTemporaryFile(mode='w', delete=False)
param_rewrites, keys_rewrites = self.resolve_rewrites(context)
data = yaml.safe_load(open(yaml_filename, 'r'))
self.substitute_params(data, param_rewrites)
self.substitute_keys(data, keys_rewrites)
if self.__root_key is not None:
root_key = launch.utilities.perform_substitutions(context, self.__root_key)
if root_key:
data = {root_key: data}
yaml.dump(data, rewritten_yaml)
rewritten_yaml.close()
return rewritten_yaml.name
def resolve_rewrites(self, context):
resolved_params = {}
for key in self.__param_rewrites:
resolved_params[key] = launch.utilities.perform_substitutions(context, self.__param_rewrites[key])
resolved_keys = {}
for key in self.__key_rewrites:
resolved_keys[key] = launch.utilities.perform_substitutions(context, self.__key_rewrites[key])
return resolved_params, resolved_keys
def substitute_params(self, yaml, param_rewrites):
# substitute leaf-only parameters
for key in self.getYamlLeafKeys(yaml):
if key.key() in param_rewrites:
raw_value = param_rewrites[key.key()]
key.setValue(self.convert(raw_value))
# substitute total path parameters
yaml_paths = self.pathify(yaml)
for path in yaml_paths:
if path in param_rewrites:
# this is an absolute path (ex. 'key.keyA.keyB.val')
rewrite_val = self.convert(param_rewrites[path])
yaml_keys = path.split('.')
yaml = self.updateYamlPathVals(yaml, yaml_keys, rewrite_val)
def updateYamlPathVals(self, yaml, yaml_key_list, rewrite_val):
for key in yaml_key_list:
if key == yaml_key_list[-1]:
yaml[key] = rewrite_val
break
key = yaml_key_list.pop(0)
if isinstance(yaml, list):
yaml[int(key)] = self.updateYamlPathVals(yaml[int(key)], yaml_key_list, rewrite_val)
else:
yaml[key] = self.updateYamlPathVals(yaml.get(key, {}), yaml_key_list, rewrite_val)
return yaml
def substitute_keys(self, yaml, key_rewrites):
if len(key_rewrites) != 0:
for key in list(yaml.keys()):
val = yaml[key]
if key in key_rewrites:
new_key = key_rewrites[key]
yaml[new_key] = yaml[key]
del yaml[key]
if isinstance(val, dict):
self.substitute_keys(val, key_rewrites)
def getYamlLeafKeys(self, yamlData):
try:
for key in yamlData.keys():
for k in self.getYamlLeafKeys(yamlData[key]):
yield k
yield DictItemReference(yamlData, key)
except AttributeError:
return
def pathify(self, d, p=None, paths=None, joinchar='.'):
if p is None:
paths = {}
self.pathify(d, "", paths, joinchar=joinchar)
return paths
pn = p
if p != "":
pn += joinchar
if isinstance(d, dict):
for k in d:
v = d[k]
self.pathify(v, str(pn) + str(k), paths, joinchar=joinchar)
elif isinstance(d, list):
for idx, e in enumerate(d):
self.pathify(e, pn + str(idx), paths, joinchar=joinchar)
else:
paths[p] = d
def convert(self, text_value):
if self.__convert_types:
# try converting to int or float
try:
return float(text_value) if '.' in text_value else int(text_value)
except ValueError:
pass
# try converting to bool
if text_value.lower() == "true":
return True
if text_value.lower() == "false":
return False
# nothing else worked so fall through and return text
return text_value
+25
View File
@@ -0,0 +1,25 @@
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>nav2_common</name>
<version>1.1.18</version>
<description>Common support functionality used throughout the navigation 2 stack</description>
<maintainer email="carl.r.delsey@intel.com">Carl Delsey</maintainer>
<license>Apache-2.0</license>
<depend>launch</depend>
<depend>launch_ros</depend>
<depend>osrf_pycommon</depend>
<depend>rclpy</depend>
<depend>python3-yaml</depend>
<buildtool_depend>ament_cmake_core</buildtool_depend>
<build_depend>ament_cmake_python</build_depend>
<buildtool_export_depend>ament_cmake_core</buildtool_export_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>