diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 75cd32f3d..62403bb76 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: check-added-large-files # mesh files has to be taken into account @@ -23,7 +23,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/PyCQA/isort - rev: 5.12.0 + rev: 5.13.2 hooks: - id: isort args: ["--profile", "black"] @@ -51,23 +51,24 @@ repos: "--ignore-words-list", "ned" # north, east, down (NED) ] + exclude_types: [rst] language: python types: [text] - repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt - rev: 0.2.1 + rev: 0.2.3 hooks: - id: yamlfmt files: ^.github|./\.yaml - repo: https://github.com/psf/black - rev: 23.10.1 + rev: 24.4.0 hooks: - id: black - args: ["--line-length=99", "--experimental-string-processing"] + args: ["--line-length=99"] - repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 + rev: 7.0.0 hooks: - id: flake8 args: diff --git a/panther/panther_hardware.repos b/panther/panther_hardware.repos index fbf3839dd..1d1790618 100644 --- a/panther/panther_hardware.repos +++ b/panther/panther_hardware.repos @@ -1,21 +1,25 @@ repositories: + behaviortree_ros2: + type: git + url: https://github.com/BehaviorTree/BehaviorTree.ROS2 + version: ce923e19c12d28f4734a41b1442c123f2d4a41d2 + husarion_controllers: + type: git + url: https://github.com/husarion/husarion_controllers + version: main panther_msgs: type: git url: https://github.com/husarion/panther_msgs.git version: ros2 + robot_localization: # Caused by this error https://github.com/cra-ros-pkg/robot_localization/pull/876, it can be removed after the next synchronization of apt packages. + type: git + url: https://github.com/cra-ros-pkg/robot_localization.git + version: humble-devel ros_components_description: type: git url: https://github.com/husarion/ros_components_description.git version: ros2 - husarion_controllers: - type: git - url: https://github.com/husarion/husarion_controllers - version: main - behaviortree_ros2: - type: git - url: https://github.com/BehaviorTree/BehaviorTree.ROS2 - version: ce923e19c12d28f4734a41b1442c123f2d4a41d2 - ros2_controllers: + ros2_controllers: # Caused by two error: 1. https://github.com/ros-controls/ros2_controllers/pull/1104 2. There is no nice way to change `sensor_name` imu_bradcaster param when spawning multiple robots -> ros2_control refer only to single imu entity type: git - url: https://github.com/delihus/ros2_controllers - version: 60919d60fb02eb920b0bf42e4d86853db23233cc + url: https://github.com/rafal-gorecki/ros2_controllers.git + version: humble diff --git a/panther_battery/launch/battery.launch.py b/panther_battery/launch/battery.launch.py index d144dfa09..d0ae887aa 100644 --- a/panther_battery/launch/battery.launch.py +++ b/panther_battery/launch/battery.launch.py @@ -28,7 +28,7 @@ def generate_launch_description(): declare_namespace_arg = DeclareLaunchArgument( "namespace", default_value=EnvironmentVariable("ROBOT_NAMESPACE", default_value=""), - description="Add namespace to all launched nodes", + description="Add namespace to all launched nodes.", ) battery_node = Node( diff --git a/panther_bringup/launch/bringup.launch.py b/panther_bringup/launch/bringup.launch.py index 735d12b86..180d26279 100644 --- a/panther_bringup/launch/bringup.launch.py +++ b/panther_bringup/launch/bringup.launch.py @@ -74,7 +74,7 @@ def generate_launch_description(): declare_namespace_arg = DeclareLaunchArgument( "namespace", default_value=EnvironmentVariable("ROBOT_NAMESPACE", default_value=""), - description="Add namespace to all launched nodes", + description="Add namespace to all launched nodes.", ) use_sim = LaunchConfiguration("use_sim") @@ -145,11 +145,7 @@ def generate_launch_description(): declare_led_config_file_arg = DeclareLaunchArgument( "led_config_file", default_value=PathJoinSubstitution( - [ - FindPackageShare("panther_lights"), - "config", - PythonExpression(["'led_config.yaml'"]), - ] + [FindPackageShare("panther_lights"), "config", "led_config.yaml"] ), description="Path to a YAML file with a description of led configuration", ) @@ -287,9 +283,10 @@ def generate_launch_description(): executable="ekf_node", name="ekf_node", output="screen", - parameters=[ekf_config_path], + parameters=[ekf_config_path, {"tf_prefix": namespace}], namespace=namespace, remappings=[ + ("/diagnostics", "diagnostics"), ("enable", "ekf_node/enable"), ("set_pose", "ekf_node/set_pose"), ("toggle", "ekf_node/toggle"), @@ -316,7 +313,7 @@ def generate_launch_description(): ) other_action_timer = TimerAction( - period=10.0, + period=7.0, actions=[ battery_launch, lights_launch, @@ -325,18 +322,6 @@ def generate_launch_description(): ], ) - waiting_msg = TimerAction( - period=7.0, - actions=[ - LogInfo( - msg=( - "We're working on ensuring everything functions properly... Please wait a few" - " seconds more!" - ) - ) - ], - ) - actions = [ declare_namespace_arg, declare_use_sim_arg, @@ -356,7 +341,6 @@ def generate_launch_description(): welcome_msg, controller_launch, system_status_node, - waiting_msg, other_action_timer, ] diff --git a/panther_controller/config/WH01_controller.yaml b/panther_controller/config/WH01_controller.yaml index 519cd9907..d1ca2783c 100644 --- a/panther_controller/config/WH01_controller.yaml +++ b/panther_controller/config/WH01_controller.yaml @@ -14,7 +14,6 @@ imu_broadcaster: ros__parameters: use_namespace_as_sensor_name_prefix: true - tf_frame_prefix_enable: false sensor_name: imu frame_id: imu_link @@ -29,7 +28,6 @@ ros__parameters: left_wheel_names: ["fl_wheel_joint", "rl_wheel_joint"] right_wheel_names: ["fr_wheel_joint", "rr_wheel_joint"] - tf_frame_prefix_enable: false wheel_separation: 0.697 wheel_radius: 0.1825 diff --git a/panther_controller/config/WH02_controller.yaml b/panther_controller/config/WH02_controller.yaml index 8b86ac421..9f3e11a6e 100644 --- a/panther_controller/config/WH02_controller.yaml +++ b/panther_controller/config/WH02_controller.yaml @@ -14,7 +14,6 @@ imu_broadcaster: ros__parameters: use_namespace_as_sensor_name_prefix: true - tf_frame_prefix_enable: false sensor_name: imu frame_id: imu_link @@ -31,7 +30,6 @@ front_right_wheel_name: fr_wheel_joint rear_left_wheel_name: rl_wheel_joint rear_right_wheel_name: rr_wheel_joint - tf_frame_prefix_enable: false wheel_separation_x: 0.44 wheel_separation_y: 0.6785 diff --git a/panther_controller/config/WH04_controller.yaml b/panther_controller/config/WH04_controller.yaml index ad30d720c..10881ab8d 100644 --- a/panther_controller/config/WH04_controller.yaml +++ b/panther_controller/config/WH04_controller.yaml @@ -14,7 +14,6 @@ imu_broadcaster: ros__parameters: use_namespace_as_sensor_name_prefix: true - tf_frame_prefix_enable: false sensor_name: imu frame_id: imu_link @@ -29,7 +28,6 @@ ros__parameters: left_wheel_names: ["fl_wheel_joint", "rl_wheel_joint"] right_wheel_names: ["fr_wheel_joint", "rr_wheel_joint"] - tf_frame_prefix_enable: false wheel_separation: 0.616 wheel_radius: 0.1016 diff --git a/panther_controller/launch/controller.launch.py b/panther_controller/launch/controller.launch.py index ef40f8bff..3732c72cd 100644 --- a/panther_controller/launch/controller.launch.py +++ b/panther_controller/launch/controller.launch.py @@ -27,6 +27,7 @@ FindExecutable, LaunchConfiguration, PathJoinSubstitution, + PythonExpression, ) from launch_ros.actions import Node, SetParameter from launch_ros.substitutions import FindPackageShare @@ -87,7 +88,7 @@ def generate_launch_description(): declare_namespace_arg = DeclareLaunchArgument( "namespace", default_value=EnvironmentVariable("ROBOT_NAMESPACE", default_value=""), - description="Add namespace to all launched nodes", + description="Add namespace to all launched nodes.", ) # Get URDF via xacro @@ -135,7 +136,7 @@ def generate_launch_description(): control_node = Node( package="controller_manager", executable="ros2_control_node", - parameters=[robot_description, controller_config_path], + parameters=[controller_config_path], namespace=namespace, remappings=[ ( @@ -157,11 +158,13 @@ def generate_launch_description(): condition=UnlessCondition(use_sim), ) + namespace_ext = PythonExpression(["'", namespace, "' + '/' if '", namespace, "' else ''"]) + robot_state_pub_node = Node( package="robot_state_publisher", executable="robot_state_publisher", output="both", - parameters=[robot_description], + parameters=[robot_description, {"frame_prefix": namespace_ext}], namespace=namespace, condition=IfCondition(publish_robot_state), ) diff --git a/panther_description/urdf/panther_macro.urdf.xacro b/panther_description/urdf/panther_macro.urdf.xacro index 41ea2a5a5..03b74e21c 100644 --- a/panther_description/urdf/panther_macro.urdf.xacro +++ b/panther_description/urdf/panther_macro.urdf.xacro @@ -63,7 +63,7 @@ wheel_separation_x="${wheel_separation_x}" prefix="rr" /> - + diff --git a/panther_gazebo/README.md b/panther_gazebo/README.md index 7859d7bb1..ff92be4a3 100644 --- a/panther_gazebo/README.md +++ b/panther_gazebo/README.md @@ -4,20 +4,24 @@ A package containing the launch files and dependencies needed to run the simulat ## Usage -The recommended method for launching the simulation is by utilizing the [simulation.launch.py](https://github.com/husarion/panther_ros/panther_gazebo/launch/simulation.launch.py) file. Below, you will find launch arguments that enable simulation configuration. +The recommended method for launching the simulation is by utilizing the [simulation.launch.py](https://github.com/husarion/panther_ros/panther_gazebo/launch/simulation.launch.py) file. Below, you will find launch arguments that enable simulation configuration. You can also launch more robots using `spawn.launch.py` ​​after the system has been started. ### Launch Arguments +- `add_world_transform` [*bool*, default: **False**]: Adds a world frame that connects the tf trees of individual robots (useful when running multiple robots). - `battery_config_path` [*string*, default: **panther_gazebo/config/battery_plugin_config.yaml**]: Path to the Ignition `LinearBatteryPlugin` configuration file. This configuration is intended for use in simulations only. For more information on how to configure this plugin, please refer to the [Linear Battery Plugin](#linear-battery-plugin) section. - `controller_config_path` [*string*, default: **panther_controller/config/_controller.yaml**]: Path to the controller configuration file. If you want to use a custom configuration, you can specify the path to your custom controller configuration file here. - `gz_bridge_config_path` [*string*, default: **panther_gazebo/config/gz_bridge.yaml**]: Path to the `parameter_bridge` configuration file. For detailed information on configuring the `parameter_bridge`, please refer to this [example](https://github.com/gazebosim/ros_gz/tree/ros2/ros_gz_bridge#example-5-configuring-the-bridge-via-yaml). - `gz_log_level` [*[0-4]*, default: **1**]: Adjust the level of console output. - `headless_mode` [*bool*, default: **False**]: Run the simulation in headless mode. Useful when a GUI is not needed or to reduce the amount of calculations. -- `pos_x` [*float*, default: **5.0**]: spawn position **[m]** of the robot in the world in **X** direction. -- `pos_y` [*float*, default: **-5.0**]: spawn position **[m]** of the robot in the world in **Y** direction. -- `pos_z` [*float*, default: **0.2**]: spawn position **[m]** of the robot in the world in **Z** direction. -- `rot_yaw` [*float*, default: **0.0**]: spawn yaw angle **[rad]** of the robot in the world. +- `x` [*float*, default: **5.0**]: spawn position **[m]** of the robot in the world in **X** direction. +- `y` [*float*, default: **-5.0**]: spawn position **[m]** of the robot in the world in **Y** direction. +- `z` [*float*, default: **0.2**]: spawn position **[m]** of the robot in the world in **Z** direction. +- `roll` [*float*, default: **0.0**]: spawn roll angle **[rad]** of the robot in the world. +- `pitch` [*float*, default: **0.0**]: spawn pitch angle **[rad]** of the robot in the world. +- `yaw` [*float*, default: **0.0**]: spawn yaw angle **[rad]** of the robot in the world. - `publish_robot_state` [*bool*, default: **true**]: Whether to launch the robot_state_publisher node. When set to `false`, users should publish their own robot description. +- `robots` [*yaml style*, default: **""**]: The list of the robots spawned in the simulation e.g. robots:='robot1={x: 0.0, y: -1.0}; robot2={x: 1.0, y: -1.0}'" - `wheel_config_path` [*string*, default: **panther_description/config/.yaml**]: Path to the wheel configuration file. If you want to use a custom configuration, you can specify the path to your custom wheel configuration file here. Please refer to the `wheel_type` parameter description for more information. - `wheel_type` [*string*, default: **WH01**]: Specify the type of wheel. If you select a value from the provided options (`WH01`, `WH02`, `WH04`), you can disregard the `wheel_config_path` and `controller_config_path` parameters. If you have custom wheels, set this parameter to `CUSTOM` and provide the necessary configurations. - `world` [*string*, default: **-r /worlds/husarion_world.sdf**]: path to Gazebo world file used for simulation. diff --git a/panther_gazebo/launch/simulation.launch.py b/panther_gazebo/launch/simulation.launch.py index c12251015..db5770d4a 100644 --- a/panther_gazebo/launch/simulation.launch.py +++ b/panther_gazebo/launch/simulation.launch.py @@ -23,7 +23,7 @@ PathJoinSubstitution, PythonExpression, ) -from launch_ros.actions import Node, SetParameter +from launch_ros.actions import SetParameter from launch_ros.substitutions import FindPackageShare @@ -101,33 +101,37 @@ def generate_launch_description(): "gz_bridge.yaml", ] ), - description="Path to the parameter_bridge configuration file", + description="Path to the parameter_bridge configuration file.", ) - pose_x = LaunchConfiguration("pose_x") - declare_pose_x_arg = DeclareLaunchArgument( - "pose_x", - default_value=["5.0"], - description="Initial robot position in the global 'x' axis.", + x = LaunchConfiguration("x") + declare_x_arg = DeclareLaunchArgument( + "x", default_value="5.0", description="Initial robot position in the global 'x' axis." ) - pose_y = LaunchConfiguration("pose_y") - declare_pose_y_arg = DeclareLaunchArgument( - "pose_y", - default_value=["-5.0"], - description="Initial robot position in the global 'y' axis.", + y = LaunchConfiguration("y") + declare_y_arg = DeclareLaunchArgument( + "y", default_value="-5.0", description="Initial robot position in the global 'y' axis." ) - pose_z = LaunchConfiguration("pose_z") - declare_pose_z_arg = DeclareLaunchArgument( - "pose_z", - default_value=["0.2"], - description="Initial robot position in the global 'z' axis.", + z = LaunchConfiguration("z") + declare_z_arg = DeclareLaunchArgument( + "z", default_value="0.2", description="Initial robot position in the global 'z' axis." ) - rot_yaw = LaunchConfiguration("rot_yaw") - declare_rot_yaw_arg = DeclareLaunchArgument( - "rot_yaw", default_value=["0.0"], description="Initial robot orientation." + roll = LaunchConfiguration("roll") + declare_roll_arg = DeclareLaunchArgument( + "roll", default_value="0.0", description="Initial robot 'roll' orientation." + ) + + pitch = LaunchConfiguration("pitch") + declare_pitch_arg = DeclareLaunchArgument( + "pitch", default_value="0.0", description="Initial robot 'pitch' orientation." + ) + + yaw = LaunchConfiguration("yaw") + declare_yaw_arg = DeclareLaunchArgument( + "yaw", default_value="0.0", description="Initial robot 'yaw' orientation." ) publish_robot_state = LaunchConfiguration("publish_robot_state") @@ -144,7 +148,27 @@ def generate_launch_description(): declare_namespace_arg = DeclareLaunchArgument( "namespace", default_value=EnvironmentVariable("ROBOT_NAMESPACE", default_value=""), - description="Add namespace to all launched nodes", + description="Add namespace to all launched nodes.", + ) + + robots = LaunchConfiguration("robots") + declare_robots_arg = DeclareLaunchArgument( + "robots", + default_value=[], + description=( + "The list of the robots spawned in the simulation e. g. robots:='robot1={x: 0.0, y:" + " -1.0}; robot2={x: 1.0, y: -1.0}'" + ), + ) + + add_world_transform = LaunchConfiguration("add_world_transform") + declare_add_world_transform_arg = DeclareLaunchArgument( + "add_world_transform", + default_value="False", + description=( + "Adds a world frame that connects the tf trees of individual robots (useful when running" + " multiple robots)." + ), ) gz_sim = IncludeLaunchDescription( @@ -159,45 +183,13 @@ def generate_launch_description(): ), ) - gz_spawn_entity = Node( - package="ros_gz_sim", - executable="create", - arguments=[ - "-name", - "panther", - "-allow_renaming", - "true", - "-topic", - "robot_description", - "-x", - pose_x, - "-y", - pose_y, - "-z", - pose_z, - "-Y", - rot_yaw, - ], - output="screen", - namespace=namespace, - ) - - gz_bridge = Node( - package="ros_gz_bridge", - executable="parameter_bridge", - name="gz_bridge", - parameters=[{"config_file": gz_bridge_config_path}], - namespace=namespace, - output="screen", - ) - - bringup_launch = IncludeLaunchDescription( + spawn_robots_launch = IncludeLaunchDescription( PythonLaunchDescriptionSource( PathJoinSubstitution( [ - FindPackageShare("panther_bringup"), + FindPackageShare("panther_gazebo"), "launch", - "bringup.launch.py", + "spawn.launch.py", ] ) ), @@ -206,19 +198,28 @@ def generate_launch_description(): "wheel_config_path": wheel_config_path, "controller_config_path": controller_config_path, "battery_config_path": battery_config_path, + "gz_bridge_config_path": gz_bridge_config_path, + "x": x, + "y": y, + "z": z, + "roll": roll, + "pitch": pitch, + "yaw": yaw, "publish_robot_state": publish_robot_state, - "use_sim": "True", - "simulation_engine": "ignition-gazebo", "namespace": namespace, + "robots": robots, + "add_world_transform": add_world_transform, }.items(), ) return LaunchDescription( [ - declare_pose_x_arg, - declare_pose_y_arg, - declare_pose_z_arg, - declare_rot_yaw_arg, + declare_x_arg, + declare_y_arg, + declare_z_arg, + declare_roll_arg, + declare_pitch_arg, + declare_yaw_arg, declare_wheel_type_arg, declare_wheel_config_path_arg, declare_controller_config_path_arg, @@ -226,11 +227,11 @@ def generate_launch_description(): declare_gz_bridge_config_path_arg, declare_publish_robot_state_arg, declare_namespace_arg, + declare_robots_arg, + declare_add_world_transform_arg, # Sets use_sim_time for all nodes started below (doesn't work for nodes started from ignition gazebo) SetParameter(name="use_sim_time", value=True), gz_sim, - gz_bridge, - gz_spawn_entity, - bringup_launch, + spawn_robots_launch, ] ) diff --git a/panther_gazebo/launch/spawn.launch.py b/panther_gazebo/launch/spawn.launch.py new file mode 100644 index 000000000..1686895ce --- /dev/null +++ b/panther_gazebo/launch/spawn.launch.py @@ -0,0 +1,298 @@ +#!/usr/bin/env python3 + +# Copyright 2024 Husarion sp. z o.o. +# +# 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 launch import LaunchDescription +from launch.actions import ( + DeclareLaunchArgument, + IncludeLaunchDescription, + LogInfo, + OpaqueFunction, + TimerAction, +) +from launch.conditions import IfCondition +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch.substitutions import ( + EnvironmentVariable, + LaunchConfiguration, + PathJoinSubstitution, + PythonExpression, +) +from launch_ros.actions import Node, SetParameter +from launch_ros.substitutions import FindPackageShare +from nav2_common.launch import ParseMultiRobotPose + + +def launch_setup(context): + wheel_type = LaunchConfiguration("wheel_type").perform(context) + wheel_config_path = LaunchConfiguration("wheel_config_path").perform(context) + controller_config_path = LaunchConfiguration("controller_config_path").perform(context) + battery_config_path = LaunchConfiguration("battery_config_path").perform(context) + gz_bridge_config_path = LaunchConfiguration("gz_bridge_config_path").perform(context) + x = LaunchConfiguration("x").perform(context) + y = LaunchConfiguration("y").perform(context) + z = LaunchConfiguration("z").perform(context) + roll = LaunchConfiguration("roll").perform(context) + pitch = LaunchConfiguration("pitch").perform(context) + yaw = LaunchConfiguration("yaw").perform(context) + publish_robot_state = LaunchConfiguration("publish_robot_state").perform(context) + namespace = LaunchConfiguration("namespace").perform(context) + add_world_transform = LaunchConfiguration("add_world_transform").perform(context) + + robots_list = ParseMultiRobotPose("robots").value() + if len(robots_list) == 0: + robots_list = { + namespace: {"x": x, "y": y, "z": z, "roll": roll, "pitch": pitch, "yaw": yaw} + } + + spawn_group = [] + for idx, robot_name in enumerate(robots_list): + init_pose = robots_list[robot_name] + x, y, z, roll, pitch, yaw = [str(value) for value in init_pose.values()] + + spawn_log = LogInfo(msg=[f"Launching namespace={robot_name} with init_pose={init_pose}"]) + + spawn_robot = Node( + package="ros_gz_sim", + executable="create", + arguments=[ + "-name", + robot_name, + "-topic", + "robot_description", + "-x", + x, + "-y", + y, + "-z", + z, + "-Y", + yaw, + ], + namespace=robot_name, + output="screen", + ) + + gz_bridge = Node( + package="ros_gz_bridge", + executable="parameter_bridge", + name="gz_bridge", + parameters=[{"config_file": gz_bridge_config_path}], + namespace=robot_name, + output="screen", + ) + + bringup_launch = IncludeLaunchDescription( + PythonLaunchDescriptionSource( + PathJoinSubstitution( + [ + FindPackageShare("panther_bringup"), + "launch", + "bringup.launch.py", + ] + ) + ), + launch_arguments={ + "wheel_type": wheel_type, + "wheel_config_path": wheel_config_path, + "controller_config_path": controller_config_path, + "battery_config_path": battery_config_path, + "publish_robot_state": publish_robot_state, + "use_sim": "True", + "simulation_engine": "ignition-gazebo", + "namespace": robot_name, + }.items(), + ) + + ns_prefix = robot_name + "/" if robot_name else robot_name + + world_transform = Node( + package="tf2_ros", + executable="static_transform_publisher", + name="static_tf_publisher", + namespace=robot_name, + output="screen", + arguments=[x, y, z, roll, pitch, yaw, "world", ns_prefix + "odom"], + condition=IfCondition(add_world_transform), + ) + + # bringup.launch.py has a timerAction in it. If the timerAction in simulation.launch.py ​​is smaller than bringup.launch.py, the namespace will be overwritten, resulting creating nodes with the same namespace. + group = TimerAction( + period=10.0 * idx, + actions=[ + spawn_log, + spawn_robot, + gz_bridge, + bringup_launch, + world_transform, + ], + ) + spawn_group.append(group) + + return spawn_group + + +def generate_launch_description(): + wheel_type = LaunchConfiguration("wheel_type") + declare_wheel_type_arg = DeclareLaunchArgument( + "wheel_type", + default_value="WH01", + description=( + "Specify the type of wheel. If you select a value from the provided options ('WH01'," + " 'WH02', 'WH04'), you can disregard the 'wheel_config_path' and" + " 'controller_config_path' parameters. If you have custom wheels, set this parameter" + " to 'CUSTOM' and provide the necessary configurations." + ), + choices=["WH01", "WH02", "WH04", "CUSTOM"], + ) + + declare_wheel_config_path_arg = DeclareLaunchArgument( + "wheel_config_path", + default_value=PathJoinSubstitution( + [ + FindPackageShare("panther_description"), + "config", + PythonExpression(["'", wheel_type, ".yaml'"]), + ] + ), + description=( + "Path to wheel configuration file. By default, it is located in " + "'panther_description/config/.yaml'. You can also specify the path " + "to your custom wheel configuration file here. " + ), + ) + + declare_controller_config_path_arg = DeclareLaunchArgument( + "controller_config_path", + default_value=PathJoinSubstitution( + [ + FindPackageShare("panther_controller"), + "config", + PythonExpression(["'", wheel_type, "_controller.yaml'"]), + ] + ), + description=( + "Path to controller configuration file. By default, it is located in" + " 'panther_controller/config/_controller.yaml'. You can also specify" + " the path to your custom controller configuration file here. " + ), + ) + + declare_battery_config_path_arg = DeclareLaunchArgument( + "battery_config_path", + default_value=PathJoinSubstitution( + [ + FindPackageShare("panther_gazebo"), + "config", + "battery_plugin_config.yaml", + ] + ), + description=( + "Path to the Ignition LinearBatteryPlugin configuration file. " + "This configuration is intended for use in simulations only." + ), + ) + + declare_gz_bridge_config_path_arg = DeclareLaunchArgument( + "gz_bridge_config_path", + default_value=PathJoinSubstitution( + [ + FindPackageShare("panther_gazebo"), + "config", + "gz_bridge.yaml", + ] + ), + description="Path to the parameter_bridge configuration file.", + ) + + declare_x_arg = DeclareLaunchArgument( + "x", default_value="5.0", description="Initial robot position in the global 'x' axis." + ) + + declare_y_arg = DeclareLaunchArgument( + "y", default_value="-5.0", description="Initial robot position in the global 'y' axis." + ) + + declare_z_arg = DeclareLaunchArgument( + "z", default_value="0.2", description="Initial robot position in the global 'z' axis." + ) + + declare_roll_arg = DeclareLaunchArgument( + "roll", default_value="0.0", description="Initial robot 'roll' orientation." + ) + + declare_pitch_arg = DeclareLaunchArgument( + "pitch", default_value="0.0", description="Initial robot 'pitch' orientation." + ) + + declare_yaw_arg = DeclareLaunchArgument( + "yaw", default_value="0.0", description="Initial robot 'yaw' orientation." + ) + + declare_publish_robot_state_arg = DeclareLaunchArgument( + "publish_robot_state", + default_value="True", + description=( + "Whether to launch the robot_state_publisher node." + "When set to False, users should publish their own robot description." + ), + ) + + declare_namespace_arg = DeclareLaunchArgument( + "namespace", + default_value=EnvironmentVariable("ROBOT_NAMESPACE", default_value=""), + description="Add namespace to all launched nodes.", + ) + + declare_robots_arg = DeclareLaunchArgument( + "robots", + default_value=[], + description=( + "The list of the robots spawned in the simulation e. g. robots:='robot1={x: 0.0, y:" + " -1.0}; robot2={x: 1.0, y: -1.0}'." + ), + ) + + declare_add_world_transform_arg = DeclareLaunchArgument( + "add_world_transform", + default_value="False", + description=( + "Adds a world frame that connects the tf trees of individual robots (useful when running" + " multiple robots)." + ), + ) + + return LaunchDescription( + [ + declare_x_arg, + declare_y_arg, + declare_z_arg, + declare_roll_arg, + declare_pitch_arg, + declare_yaw_arg, + declare_wheel_type_arg, + declare_wheel_config_path_arg, + declare_controller_config_path_arg, + declare_battery_config_path_arg, + declare_gz_bridge_config_path_arg, + declare_publish_robot_state_arg, + declare_namespace_arg, + declare_robots_arg, + declare_add_world_transform_arg, + # Sets use_sim_time for all nodes started below (doesn't work for nodes started from ignition gazebo) + SetParameter(name="use_sim_time", value=True), + OpaqueFunction(function=launch_setup), + ] + ) diff --git a/panther_gazebo/package.xml b/panther_gazebo/package.xml index 95f39b6b1..ccd230bc0 100644 --- a/panther_gazebo/package.xml +++ b/panther_gazebo/package.xml @@ -21,6 +21,7 @@ ign_ros2_control launch launch_ros + nav2_common panther_bringup robot_state_publisher ros_gz_bridge diff --git a/panther_lights/launch/lights.launch.py b/panther_lights/launch/lights.launch.py index 4edeafb82..7a9477043 100644 --- a/panther_lights/launch/lights.launch.py +++ b/panther_lights/launch/lights.launch.py @@ -32,7 +32,7 @@ def generate_launch_description(): declare_namespace_arg = DeclareLaunchArgument( "namespace", default_value=EnvironmentVariable("ROBOT_NAMESPACE", default_value=""), - description="Add namespace to all launched nodes", + description="Add namespace to all launched nodes.", ) user_led_animations_file = LaunchConfiguration("user_led_animations_file") diff --git a/panther_manager/launch/manager_bt.launch.py b/panther_manager/launch/manager_bt.launch.py index d4d2e2696..e40386d7f 100644 --- a/panther_manager/launch/manager_bt.launch.py +++ b/panther_manager/launch/manager_bt.launch.py @@ -36,7 +36,7 @@ def launch_setup(context): declare_namespace_arg = DeclareLaunchArgument( "namespace", default_value=EnvironmentVariable("ROBOT_NAMESPACE", default_value=""), - description="Add namespace to all launched nodes", + description="Add namespace to all launched nodes.", ) panther_version = float(LaunchConfiguration("panther_version").perform(context))