From 9eaccb272e5903f2b7432700351448adbbabd6d2 Mon Sep 17 00:00:00 2001 From: E-Krantz Date: Mon, 19 May 2025 12:22:31 +0200 Subject: [PATCH 01/10] Added launch files for multi-spacecraft launch in kth_space_lab world --- .../launch/kth_multi_spacecraft.launch.py | 41 +++++++++++++++++ .../launch/kth_single_spacecraft.launch.py | 46 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 discower_launch/launch/kth_multi_spacecraft.launch.py create mode 100644 discower_launch/launch/kth_single_spacecraft.launch.py diff --git a/discower_launch/launch/kth_multi_spacecraft.launch.py b/discower_launch/launch/kth_multi_spacecraft.launch.py new file mode 100644 index 0000000..4b9c72b --- /dev/null +++ b/discower_launch/launch/kth_multi_spacecraft.launch.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +from launch import LaunchDescription +from launch.actions import IncludeLaunchDescription +from launch.launch_description_sources import PythonLaunchDescriptionSource +from ament_index_python.packages import get_package_share_directory +import os + +def generate_launch_description(): + launch_dir = get_package_share_directory('discower_launch') + + return LaunchDescription([ + IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(launch_dir, 'kth_single_spacecraft.launch.py')), + launch_arguments={ + 'id': '0', + 'pose': '1,0,0.2', + 'name': 'snap', + 'delay': '0' + }.items() + ), + + IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(launch_dir, 'kth_single_spacecraft.launch.py')), + launch_arguments={ + 'id': '1', + 'pose': '2,0,0.2', + 'name': 'crackle', + 'delay': '5' + }.items() + ), + + IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(launch_dir, 'kth_single_spacecraft.launch.py')), + launch_arguments={ + 'id': '2', + 'pose': '3,0,0.2', + 'name': 'pop', + 'delay': '5' + }.items() + ), + ]) diff --git a/discower_launch/launch/kth_single_spacecraft.launch.py b/discower_launch/launch/kth_single_spacecraft.launch.py new file mode 100644 index 0000000..3ee9b4c --- /dev/null +++ b/discower_launch/launch/kth_single_spacecraft.launch.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument, OpaqueFunction +from launch.substitutions import LaunchConfiguration +from launch.actions import ExecuteProcess +import os + +def launch_px4(context, *args, **kwargs): + px4_dir = os.getenv("PX4_SPACE_SYSTEMS_DIR") + if not px4_dir: + raise RuntimeError("PX4_SPACE_SYSTEMS_DIR is not set.") + + id_ = LaunchConfiguration("id").perform(context) + pose = LaunchConfiguration("pose").perform(context) + name = LaunchConfiguration("name").perform(context) + delay = LaunchConfiguration("delay").perform(context) + + return [ + ExecuteProcess( + cmd=[ + "bash", "-c", + f"sleep {delay} && {px4_dir}/build/px4_sitl_default/bin/px4 -i {id_}" + ], + cwd=px4_dir, + env={ + **os.environ, + "PX4_SIM_AUTOSTART": "71002", + "PX4_SIM_MODEL": "gz_spacecraft_2d", + "PX4_SIM_SPEED_FACTOR": "1", + "PX4_GZ_MODEL_POSE": pose, + "PX4_UXRCE_DDS_NS": name, + "PX4_GZ_WORLD": "kth_space_lab" + }, + output="screen" + ) + ] + +def generate_launch_description(): + return LaunchDescription([ + DeclareLaunchArgument("id", default_value="0"), + DeclareLaunchArgument("pose", default_value="0,0,0"), + DeclareLaunchArgument("name", default_value="snap"), + DeclareLaunchArgument("delay", default_value="0"), + + OpaqueFunction(function=launch_px4) + ]) From 9b2f5f71749705a62a3f28bb88096c70a62604fe Mon Sep 17 00:00:00 2001 From: E-Krantz Date: Mon, 19 May 2025 12:26:59 +0200 Subject: [PATCH 02/10] Changed default pose for single spacecraft --- discower_launch/launch/kth_single_spacecraft.launch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discower_launch/launch/kth_single_spacecraft.launch.py b/discower_launch/launch/kth_single_spacecraft.launch.py index 3ee9b4c..68fefb7 100644 --- a/discower_launch/launch/kth_single_spacecraft.launch.py +++ b/discower_launch/launch/kth_single_spacecraft.launch.py @@ -38,7 +38,7 @@ def launch_px4(context, *args, **kwargs): def generate_launch_description(): return LaunchDescription([ DeclareLaunchArgument("id", default_value="0"), - DeclareLaunchArgument("pose", default_value="0,0,0"), + DeclareLaunchArgument("pose", default_value="2,0,0"), DeclareLaunchArgument("name", default_value="snap"), DeclareLaunchArgument("delay", default_value="0"), From b601311eaac31bf050bdc3989460e1c53a11f2f7 Mon Sep 17 00:00:00 2001 From: E-Krantz Date: Tue, 27 May 2025 17:18:50 +0200 Subject: [PATCH 03/10] Added ros_gz_bridge for odom topic --- .../launch/kth_single_spacecraft.launch.py | 15 +++++++++++++-- package.xml | 1 + setup.py | 1 - 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/discower_launch/launch/kth_single_spacecraft.launch.py b/discower_launch/launch/kth_single_spacecraft.launch.py index 68fefb7..8b6fa81 100644 --- a/discower_launch/launch/kth_single_spacecraft.launch.py +++ b/discower_launch/launch/kth_single_spacecraft.launch.py @@ -1,8 +1,7 @@ #!/usr/bin/env python3 from launch import LaunchDescription -from launch.actions import DeclareLaunchArgument, OpaqueFunction +from launch.actions import ExecuteProcess, DeclareLaunchArgument, OpaqueFunction from launch.substitutions import LaunchConfiguration -from launch.actions import ExecuteProcess import os def launch_px4(context, *args, **kwargs): @@ -15,6 +14,8 @@ def launch_px4(context, *args, **kwargs): name = LaunchConfiguration("name").perform(context) delay = LaunchConfiguration("delay").perform(context) + model_name = f"spacecraft_2d_{id_}" + return [ ExecuteProcess( cmd=[ @@ -32,6 +33,16 @@ def launch_px4(context, *args, **kwargs): "PX4_GZ_WORLD": "kth_space_lab" }, output="screen" + ), + + # Odometry bridge with remap + ExecuteProcess( + cmd=[ + "ros2", "run", "ros_gz_bridge", "parameter_bridge", + f"/model/{model_name}/odometry@nav_msgs/msg/Odometry@gz.msgs.Odometry", + "--ros-args", "-r", f"/model/{model_name}/odometry:=/{name}/odom" + ], + output="screen" ) ] diff --git a/package.xml b/package.xml index 006eceb..36bb5ea 100644 --- a/package.xml +++ b/package.xml @@ -10,6 +10,7 @@ px4_msgs ros2launch + ros_gz_bridge ament_copyright ament_flake8 diff --git a/setup.py b/setup.py index 6699d8c..1afad07 100644 --- a/setup.py +++ b/setup.py @@ -19,6 +19,5 @@ maintainer_email='jorisv@kth.se', description='simple SITL launch files for single- and multi-agent simulation of the ATMOS platform', license='BSD 3-Clause', - tests_require=['pytest'], entry_points={}, ) From c92a014b3ed9bf888db1bb5b7b6e4ffcde74c02e Mon Sep 17 00:00:00 2001 From: E-Krantz Date: Wed, 4 Jun 2025 17:20:22 +0200 Subject: [PATCH 04/10] Add support for kth_space_lab world and gazebo-ros bridge in launch files --- README.md | 27 ++++-- .../launch/kth_multi_spacecraft.launch.py | 41 --------- .../launch/kth_single_spacecraft.launch.py | 57 ------------ discower_launch/launch/px4.launch.py | 86 +++++++++++-------- .../launch/sitl_multi_agent_kth.launch.py | 58 +++++++++++++ .../launch/sitl_single_agent_kth.launch.py | 25 ++++++ 6 files changed, 153 insertions(+), 141 deletions(-) delete mode 100644 discower_launch/launch/kth_multi_spacecraft.launch.py delete mode 100644 discower_launch/launch/kth_single_spacecraft.launch.py create mode 100644 discower_launch/launch/sitl_multi_agent_kth.launch.py create mode 100644 discower_launch/launch/sitl_single_agent_kth.launch.py diff --git a/README.md b/README.md index d65bfc9..cc7b3e5 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,15 @@ # discower_launch: SITL launch files for Single and Multi-agent experiments -This repository contains launch files indicating how a single and multiple ATMOS space platform SITL simulation can be started. +This repository contains launch files indicating how a single and multiple ATMOS space platform SITL simulation can be started. The dependencies for launching the SITL simulation are - [PX4-Space-Systems](https://github.com/DISCOWER/PX4-Space-Systems) - [px4_msgs](https://github.com/DISCOWER/px4_msgs) As this repository contains simple examples to merely run the SITL, you might need to follow additional instructions in the `PX4-Space-Systems` repository to fully get started. In short, you additionally need to - build the workspace: `colcon build --symlink-install` -- start the microros service: `ros2 run micro_ros_agent micro_ros_agent udp4 --port 8888` -after which you can display the robot's topics with `ros2 topic list`. Then, you can arm/disarm the robot with [QGroundControl](https://github.com/DISCOWER/qgroundcontrol). +- start the microros service: `micro-xrce-dds-agent udp4 -p 8888` + +After that, you can display the robot's topics with `ros2 topic list`. Then, you can arm/disarm the robot with [QGroundControl](https://github.com/DISCOWER/qgroundcontrol). Further details can be found on the [ATMOS website](https://atmos.discower.io/pages/Simulation/) @@ -17,26 +18,36 @@ Further details can be found on the [ATMOS website](https://atmos.discower.io/pa First make sure that your environment variable for `PX4_SPACE_SYSTEMS_DIR` is set. This can be checked with: ```bash echo $PX4_SPACE_SYSTEMS_DIR -``` -If this is not set, you can set it at the end of your .bashrc (or .zshrc) file with: +```` + +If this is not set, you can set it at the end of your `.bashrc` (or `.zshrc`) file with: + ```bash export PX4_SPACE_SYSTEMS_DIR=/path/to/your/PX4-Space-Systems ``` Then, test the multi-agent setup by running the following command: + ```bash ros2 launch discower_launch sitl_multi_agent.launch.py ``` -## Adding extra ATMOS platforms +> Alternatively, if you want to simulate in the `kth_space_lab` world and use the Gazebo-ROS bridge, you can run: + +```bash +ros2 launch discower_launch sitl_multi_agent_kth.launch.py +``` + +## Adding extra ATMOS platforms + +In the launch file, for each vehicle, you can set the namespaces and pose for each vehicle. To add an extra vehicle, add another instance of the `px4.launch.py` with a different `id` and with five extra seconds of delay. Make sure to also change the `pose` variable to avoid agents being deployed in the same position. An example can be found below: -In the launch file, for each vehicle, you can set the namespaces and pose for each vehicle. To add an extra vehicle, add another instance of the `px4.launch.py` with different `id` and with five extra seconds of delay. Make sure to also change the pose variable to avoid agents being deployd in the same position. An example can be found below: ```python lf_3 = IncludeLaunchDescription( PythonLaunchDescriptionSource( [get_package_share_directory('discower_launch'), '/px4.launch.py']), - launch_arguments={'id': '3', 'pose': '-1.0, 1.75, 0', 'name': 'snap', 'delay': '10'}.items() + launch_arguments={'id': '3', 'pose': '-1.0, 1.75, 0', 'name': 'snap', 'delay': '10', 'world': 'kth_space_lab'}.items() ) ld.add_action(lf_3) diff --git a/discower_launch/launch/kth_multi_spacecraft.launch.py b/discower_launch/launch/kth_multi_spacecraft.launch.py deleted file mode 100644 index 4b9c72b..0000000 --- a/discower_launch/launch/kth_multi_spacecraft.launch.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python3 -from launch import LaunchDescription -from launch.actions import IncludeLaunchDescription -from launch.launch_description_sources import PythonLaunchDescriptionSource -from ament_index_python.packages import get_package_share_directory -import os - -def generate_launch_description(): - launch_dir = get_package_share_directory('discower_launch') - - return LaunchDescription([ - IncludeLaunchDescription( - PythonLaunchDescriptionSource(os.path.join(launch_dir, 'kth_single_spacecraft.launch.py')), - launch_arguments={ - 'id': '0', - 'pose': '1,0,0.2', - 'name': 'snap', - 'delay': '0' - }.items() - ), - - IncludeLaunchDescription( - PythonLaunchDescriptionSource(os.path.join(launch_dir, 'kth_single_spacecraft.launch.py')), - launch_arguments={ - 'id': '1', - 'pose': '2,0,0.2', - 'name': 'crackle', - 'delay': '5' - }.items() - ), - - IncludeLaunchDescription( - PythonLaunchDescriptionSource(os.path.join(launch_dir, 'kth_single_spacecraft.launch.py')), - launch_arguments={ - 'id': '2', - 'pose': '3,0,0.2', - 'name': 'pop', - 'delay': '5' - }.items() - ), - ]) diff --git a/discower_launch/launch/kth_single_spacecraft.launch.py b/discower_launch/launch/kth_single_spacecraft.launch.py deleted file mode 100644 index 8b6fa81..0000000 --- a/discower_launch/launch/kth_single_spacecraft.launch.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 -from launch import LaunchDescription -from launch.actions import ExecuteProcess, DeclareLaunchArgument, OpaqueFunction -from launch.substitutions import LaunchConfiguration -import os - -def launch_px4(context, *args, **kwargs): - px4_dir = os.getenv("PX4_SPACE_SYSTEMS_DIR") - if not px4_dir: - raise RuntimeError("PX4_SPACE_SYSTEMS_DIR is not set.") - - id_ = LaunchConfiguration("id").perform(context) - pose = LaunchConfiguration("pose").perform(context) - name = LaunchConfiguration("name").perform(context) - delay = LaunchConfiguration("delay").perform(context) - - model_name = f"spacecraft_2d_{id_}" - - return [ - ExecuteProcess( - cmd=[ - "bash", "-c", - f"sleep {delay} && {px4_dir}/build/px4_sitl_default/bin/px4 -i {id_}" - ], - cwd=px4_dir, - env={ - **os.environ, - "PX4_SIM_AUTOSTART": "71002", - "PX4_SIM_MODEL": "gz_spacecraft_2d", - "PX4_SIM_SPEED_FACTOR": "1", - "PX4_GZ_MODEL_POSE": pose, - "PX4_UXRCE_DDS_NS": name, - "PX4_GZ_WORLD": "kth_space_lab" - }, - output="screen" - ), - - # Odometry bridge with remap - ExecuteProcess( - cmd=[ - "ros2", "run", "ros_gz_bridge", "parameter_bridge", - f"/model/{model_name}/odometry@nav_msgs/msg/Odometry@gz.msgs.Odometry", - "--ros-args", "-r", f"/model/{model_name}/odometry:=/{name}/odom" - ], - output="screen" - ) - ] - -def generate_launch_description(): - return LaunchDescription([ - DeclareLaunchArgument("id", default_value="0"), - DeclareLaunchArgument("pose", default_value="2,0,0"), - DeclareLaunchArgument("name", default_value="snap"), - DeclareLaunchArgument("delay", default_value="0"), - - OpaqueFunction(function=launch_px4) - ]) diff --git a/discower_launch/launch/px4.launch.py b/discower_launch/launch/px4.launch.py index 18e0ecf..1fd6ce9 100644 --- a/discower_launch/launch/px4.launch.py +++ b/discower_launch/launch/px4.launch.py @@ -1,44 +1,60 @@ #!/usr/bin/env python3 from launch import LaunchDescription -from launch.actions import ExecuteProcess, DeclareLaunchArgument +from launch.actions import DeclareLaunchArgument, OpaqueFunction, ExecuteProcess from launch.substitutions import LaunchConfiguration import os -def generate_launch_description(): - """Launch Gazebo with a freeflyer running PX4 communicating over ROS 2.""" - +def launch_px4_with_bridge(context, *args, **kwargs): px4_dir = os.getenv("PX4_SPACE_SYSTEMS_DIR") if not px4_dir: raise RuntimeError("PX4_SPACE_SYSTEMS_DIR is not set. Did you add it to your .bashrc file?") - return LaunchDescription( - [ - # We have the first robot always start with id 0 - DeclareLaunchArgument("id", default_value="0"), - DeclareLaunchArgument("pose", default_value="0,0,0"), - DeclareLaunchArgument("name", default_value="snap"), - DeclareLaunchArgument("delay", default_value="0"), - DeclareLaunchArgument("headless", default_value="1"), - ExecuteProcess( - cmd=[ - "xterm", # or "gnome-terminal", "konsole", "xterm" - "-hold", # Keep terminal open for debugging - "-e", - "bash", - "-c", - "sleep $PX4_DELAY && " +px4_dir+"/build/px4_sitl_default/bin/px4 -i $PX4_INSTANCE", - ], - cwd=px4_dir, - env={**os.environ, - "PX4_SIM_AUTOSTART": "4001", - "PX4_SIM_SPEED_FACTOR": "1", - "PX4_GZ_MODEL_POSE": LaunchConfiguration("pose"), - "PX4_INSTANCE": LaunchConfiguration("id"), - "PX4_DELAY": LaunchConfiguration("delay"), - "PX4_SIM_MODEL": "gz_spacecraft_2d", - "PX4_UXRCE_DDS_NS": LaunchConfiguration("name")}, - # "HEADLESS": LaunchConfiguration("headless")}, - output="screen", - ), - ] - ) + id_ = LaunchConfiguration("id").perform(context) + pose = LaunchConfiguration("pose").perform(context) + name = LaunchConfiguration("name").perform(context) + delay = LaunchConfiguration("delay").perform(context) + world = LaunchConfiguration("world").perform(context) + + model_name = f"spacecraft_2d_{id_}" + + return [ + ExecuteProcess( + cmd=[ + "bash", "-c", + f"sleep {delay} && {px4_dir}/build/px4_sitl_default/bin/px4 -i {id_}" + ], + cwd=px4_dir, + env={ + **os.environ, + "PX4_SIM_AUTOSTART": "71002", + "PX4_SIM_SPEED_FACTOR": "1", + "PX4_GZ_MODEL_POSE": pose, + "PX4_INSTANCE": id_, + "PX4_DELAY": delay, + "PX4_SIM_MODEL": "gz_spacecraft_2d", + "PX4_UXRCE_DDS_NS": name, + "PX4_GZ_WORLD": world + }, + output="screen" + ), + + ExecuteProcess( + cmd=[ + "ros2", "run", "ros_gz_bridge", "parameter_bridge", + f"/model/{model_name}/odometry@nav_msgs/msg/Odometry@gz.msgs.Odometry", + "--ros-args", "-r", f"/model/{model_name}/odometry:=/{name}/odom" + ], + output="screen" + ) + ] + +def generate_launch_description(): + return LaunchDescription([ + DeclareLaunchArgument("id", default_value="0"), + DeclareLaunchArgument("pose", default_value="0,0,0"), + DeclareLaunchArgument("name", default_value="snap"), + DeclareLaunchArgument("delay", default_value="0"), + DeclareLaunchArgument("world", default_value=""), + + OpaqueFunction(function=launch_px4_with_bridge) + ]) \ No newline at end of file diff --git a/discower_launch/launch/sitl_multi_agent_kth.launch.py b/discower_launch/launch/sitl_multi_agent_kth.launch.py new file mode 100644 index 0000000..a9a0690 --- /dev/null +++ b/discower_launch/launch/sitl_multi_agent_kth.launch.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +__author__ = "Elias Krantz" +__contact__ = "eliaskra@kth.se" + +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import IncludeLaunchDescription +from launch.launch_description_sources import PythonLaunchDescriptionSource + +def generate_launch_description(): + """Launch multiple spacecrafts in the kth_space_lab world with PX4 and ROS 2.""" + ld = LaunchDescription() + + # Path to the shared px4 launcher + px4_launch_path = [get_package_share_directory('discower_launch'), '/px4.launch.py'] + + # First agent + spacecraft_0 = IncludeLaunchDescription( + PythonLaunchDescriptionSource(px4_launch_path), + launch_arguments={ + 'id': '0', + 'pose': '1,0,0.2', + 'name': 'snap', + 'delay': '0', + 'world': 'kth_space_lab' + }.items() + ) + + # Second agent + spacecraft_1 = IncludeLaunchDescription( + PythonLaunchDescriptionSource(px4_launch_path), + launch_arguments={ + 'id': '1', + 'pose': '2,0,0.2', + 'name': 'crackle', + 'delay': '5', + 'world': 'kth_space_lab' + }.items() + ) + + # Third agent + spacecraft_2 = IncludeLaunchDescription( + PythonLaunchDescriptionSource(px4_launch_path), + launch_arguments={ + 'id': '2', + 'pose': '3,0,0.2', + 'name': 'pop', + 'delay': '5', + 'world': 'kth_space_lab' + }.items() + ) + + # Add all to launch description + ld.add_action(spacecraft_0) + ld.add_action(spacecraft_1) + ld.add_action(spacecraft_2) + + return ld \ No newline at end of file diff --git a/discower_launch/launch/sitl_single_agent_kth.launch.py b/discower_launch/launch/sitl_single_agent_kth.launch.py new file mode 100644 index 0000000..17e9bcf --- /dev/null +++ b/discower_launch/launch/sitl_single_agent_kth.launch.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +__author__ = "Elias Krantz" +__contact__ = "eliaskra@kth.se" + +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import IncludeLaunchDescription +from launch.launch_description_sources import PythonLaunchDescriptionSource + +def generate_launch_description(): + """Launch Gazebo with a spacecraft in the kth_space_lab world and ROS bridge.""" + px4_launch_path = [get_package_share_directory('discower_launch'), '/px4.launch.py'] + + return LaunchDescription([ + IncludeLaunchDescription( + PythonLaunchDescriptionSource(px4_launch_path), + launch_arguments={ + 'id': '0', + 'pose': '2,0,0', + 'name': 'snap', + 'delay': '0', + 'world': 'kth_space_lab' + }.items() + ) + ]) \ No newline at end of file From c0e0f8310f075675087638c4e16d6b8717c34842 Mon Sep 17 00:00:00 2001 From: E-Krantz Date: Wed, 4 Jun 2025 17:29:37 +0200 Subject: [PATCH 05/10] Cleanup before merge --- README.md | 2 +- discower_launch/launch/sitl_multi_agent_kth.launch.py | 3 --- discower_launch/launch/sitl_single_agent_kth.launch.py | 3 --- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/README.md b/README.md index cc7b3e5..c345bb2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # discower_launch: SITL launch files for Single and Multi-agent experiments -This repository contains launch files indicating how a single and multiple ATMOS space platform SITL simulation can be started. +This repository contains launch files indicating how a single and multiple ATMOS space platform SITL simulation can be started. The dependencies for launching the SITL simulation are - [PX4-Space-Systems](https://github.com/DISCOWER/PX4-Space-Systems) - [px4_msgs](https://github.com/DISCOWER/px4_msgs) diff --git a/discower_launch/launch/sitl_multi_agent_kth.launch.py b/discower_launch/launch/sitl_multi_agent_kth.launch.py index a9a0690..054fb91 100644 --- a/discower_launch/launch/sitl_multi_agent_kth.launch.py +++ b/discower_launch/launch/sitl_multi_agent_kth.launch.py @@ -1,7 +1,4 @@ #!/usr/bin/env python -__author__ = "Elias Krantz" -__contact__ = "eliaskra@kth.se" - from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch.actions import IncludeLaunchDescription diff --git a/discower_launch/launch/sitl_single_agent_kth.launch.py b/discower_launch/launch/sitl_single_agent_kth.launch.py index 17e9bcf..5c96f41 100644 --- a/discower_launch/launch/sitl_single_agent_kth.launch.py +++ b/discower_launch/launch/sitl_single_agent_kth.launch.py @@ -1,7 +1,4 @@ #!/usr/bin/env python -__author__ = "Elias Krantz" -__contact__ = "eliaskra@kth.se" - from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch.actions import IncludeLaunchDescription From f20c9f5c4156b10dead693c9d7c17a11e91b641b Mon Sep 17 00:00:00 2001 From: E-Krantz Date: Tue, 24 Jun 2025 13:16:57 +0200 Subject: [PATCH 06/10] Renamed kth_space_lab to kthspacelab --- README.md | 4 ++-- discower_launch/launch/px4.launch.py | 5 +++-- discower_launch/launch/sitl_multi_agent_kth.launch.py | 8 ++++---- discower_launch/launch/sitl_single_agent_kth.launch.py | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c345bb2..929aab5 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Then, test the multi-agent setup by running the following command: ros2 launch discower_launch sitl_multi_agent.launch.py ``` -> Alternatively, if you want to simulate in the `kth_space_lab` world and use the Gazebo-ROS bridge, you can run: +> Alternatively, if you want to simulate in the `kthspacelab` world and use the Gazebo-ROS bridge, you can run: ```bash ros2 launch discower_launch sitl_multi_agent_kth.launch.py @@ -47,7 +47,7 @@ lf_3 = IncludeLaunchDescription( PythonLaunchDescriptionSource( [get_package_share_directory('discower_launch'), '/px4.launch.py']), - launch_arguments={'id': '3', 'pose': '-1.0, 1.75, 0', 'name': 'snap', 'delay': '10', 'world': 'kth_space_lab'}.items() + launch_arguments={'id': '3', 'pose': '-1.0, 1.75, 0', 'name': 'snap', 'delay': '10', 'world': 'kthspacelab'}.items() ) ld.add_action(lf_3) diff --git a/discower_launch/launch/px4.launch.py b/discower_launch/launch/px4.launch.py index 1fd6ce9..ce6ac14 100644 --- a/discower_launch/launch/px4.launch.py +++ b/discower_launch/launch/px4.launch.py @@ -13,9 +13,10 @@ def launch_px4_with_bridge(context, *args, **kwargs): pose = LaunchConfiguration("pose").perform(context) name = LaunchConfiguration("name").perform(context) delay = LaunchConfiguration("delay").perform(context) + model = LaunchConfiguration("model").perform(context) if "model" in context.launch_configurations else "spacecraft_2d" world = LaunchConfiguration("world").perform(context) - model_name = f"spacecraft_2d_{id_}" + model_name = f"{model}_{id_}" return [ ExecuteProcess( @@ -31,7 +32,7 @@ def launch_px4_with_bridge(context, *args, **kwargs): "PX4_GZ_MODEL_POSE": pose, "PX4_INSTANCE": id_, "PX4_DELAY": delay, - "PX4_SIM_MODEL": "gz_spacecraft_2d", + "PX4_SIM_MODEL": f"gz_{model}", "PX4_UXRCE_DDS_NS": name, "PX4_GZ_WORLD": world }, diff --git a/discower_launch/launch/sitl_multi_agent_kth.launch.py b/discower_launch/launch/sitl_multi_agent_kth.launch.py index 054fb91..aa072a5 100644 --- a/discower_launch/launch/sitl_multi_agent_kth.launch.py +++ b/discower_launch/launch/sitl_multi_agent_kth.launch.py @@ -5,7 +5,7 @@ from launch.launch_description_sources import PythonLaunchDescriptionSource def generate_launch_description(): - """Launch multiple spacecrafts in the kth_space_lab world with PX4 and ROS 2.""" + """Launch multiple spacecrafts in the kthspacelab world with PX4 and ROS 2.""" ld = LaunchDescription() # Path to the shared px4 launcher @@ -19,7 +19,7 @@ def generate_launch_description(): 'pose': '1,0,0.2', 'name': 'snap', 'delay': '0', - 'world': 'kth_space_lab' + 'world': 'kthspacelab' }.items() ) @@ -31,7 +31,7 @@ def generate_launch_description(): 'pose': '2,0,0.2', 'name': 'crackle', 'delay': '5', - 'world': 'kth_space_lab' + 'world': 'kthspacelab' }.items() ) @@ -43,7 +43,7 @@ def generate_launch_description(): 'pose': '3,0,0.2', 'name': 'pop', 'delay': '5', - 'world': 'kth_space_lab' + 'world': 'kthspacelab' }.items() ) diff --git a/discower_launch/launch/sitl_single_agent_kth.launch.py b/discower_launch/launch/sitl_single_agent_kth.launch.py index 5c96f41..c284715 100644 --- a/discower_launch/launch/sitl_single_agent_kth.launch.py +++ b/discower_launch/launch/sitl_single_agent_kth.launch.py @@ -5,7 +5,7 @@ from launch.launch_description_sources import PythonLaunchDescriptionSource def generate_launch_description(): - """Launch Gazebo with a spacecraft in the kth_space_lab world and ROS bridge.""" + """Launch Gazebo with a spacecraft in the kthspacelab world and ROS bridge.""" px4_launch_path = [get_package_share_directory('discower_launch'), '/px4.launch.py'] return LaunchDescription([ @@ -16,7 +16,7 @@ def generate_launch_description(): 'pose': '2,0,0', 'name': 'snap', 'delay': '0', - 'world': 'kth_space_lab' + 'world': 'kthspacelab' }.items() ) ]) \ No newline at end of file From c1880b936627a1b761c91769343d8a3e928d1804 Mon Sep 17 00:00:00 2001 From: E-Krantz Date: Tue, 24 Jun 2025 16:24:05 +0200 Subject: [PATCH 07/10] Made Gazebo-ROS bridge optional --- README.md | 27 ++++++++++++++-- discower_launch/launch/px4.launch.py | 32 ++++++++++++------- .../launch/sitl_multi_agent_kth.launch.py | 9 ++++-- .../launch/sitl_single_agent_kth.launch.py | 3 +- 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 929aab5..47fcac8 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,14 @@ # discower_launch: SITL launch files for Single and Multi-agent experiments This repository contains launch files indicating how a single and multiple ATMOS space platform SITL simulation can be started. -The dependencies for launching the SITL simulation are + +## Dependencies + - [PX4-Space-Systems](https://github.com/DISCOWER/PX4-Space-Systems) - [px4_msgs](https://github.com/DISCOWER/px4_msgs) As this repository contains simple examples to merely run the SITL, you might need to follow additional instructions in the `PX4-Space-Systems` repository to fully get started. In short, you additionally need to + - build the workspace: `colcon build --symlink-install` - start the microros service: `micro-xrce-dds-agent udp4 -p 8888` @@ -13,12 +16,32 @@ After that, you can display the robot's topics with `ros2 topic list`. Then, you Further details can be found on the [ATMOS website](https://atmos.discower.io/pages/Simulation/) +## Launch files overview + +This package provides four main launch files: + +- `sitl_single_agent.launch.py`: Launches a single agent on the default PX4 world. +- `sitl_multi_agent.launch.py`: Launches multiple agents on the default PX4 world. +- `sitl_single_agent_kth.launch.py`: Launches a single agent in the KTH Space Lab world **with** Gazebo-ROS odometry bridging enabled. +- `sitl_multi_agent_kth.launch.py`: Launches multiple agents in the KTH Space Lab world **with** Gazebo-ROS odometry bridging enabled. + +> **Note:** Gazebo-ROS odometry bridging requires the additional ROS package +> `ros-[ros2-distro]-ros-gzharmonic-bridge`. +> You can install it via, e.g. for Humble: +> +> ```bash +> sudo apt install ros-humble-ros-gzharmonic-bridge +> ``` + +The bridged odometry simulates the motion capture system used in the real KTH Space Lab and publishes ground-truth data from Gazebo to ROS. + ## Testing a Multi-Agent setup First make sure that your environment variable for `PX4_SPACE_SYSTEMS_DIR` is set. This can be checked with: + ```bash echo $PX4_SPACE_SYSTEMS_DIR -```` +``` If this is not set, you can set it at the end of your `.bashrc` (or `.zshrc`) file with: diff --git a/discower_launch/launch/px4.launch.py b/discower_launch/launch/px4.launch.py index ce6ac14..bac84e8 100644 --- a/discower_launch/launch/px4.launch.py +++ b/discower_launch/launch/px4.launch.py @@ -4,7 +4,7 @@ from launch.substitutions import LaunchConfiguration import os -def launch_px4_with_bridge(context, *args, **kwargs): +def launch_px4(context, *args, **kwargs): px4_dir = os.getenv("PX4_SPACE_SYSTEMS_DIR") if not px4_dir: raise RuntimeError("PX4_SPACE_SYSTEMS_DIR is not set. Did you add it to your .bashrc file?") @@ -18,7 +18,9 @@ def launch_px4_with_bridge(context, *args, **kwargs): model_name = f"{model}_{id_}" - return [ + use_odom_bridge = LaunchConfiguration("use_odom_bridge").perform(context).lower() == "true" + + processes = [ ExecuteProcess( cmd=[ "bash", "-c", @@ -37,18 +39,23 @@ def launch_px4_with_bridge(context, *args, **kwargs): "PX4_GZ_WORLD": world }, output="screen" - ), - - ExecuteProcess( - cmd=[ - "ros2", "run", "ros_gz_bridge", "parameter_bridge", - f"/model/{model_name}/odometry@nav_msgs/msg/Odometry@gz.msgs.Odometry", - "--ros-args", "-r", f"/model/{model_name}/odometry:=/{name}/odom" - ], - output="screen" ) ] + if use_odom_bridge: + processes.append( + ExecuteProcess( + cmd=[ + "ros2", "run", "ros_gz_bridge", "parameter_bridge", + f"/model/{model_name}/odometry@nav_msgs/msg/Odometry[gz.msgs.Odometry", + "--ros-args", "-r", f"/model/{model_name}/odometry:=/{name}/odom" + ], + output="screen" + ) + ) + + return processes + def generate_launch_description(): return LaunchDescription([ DeclareLaunchArgument("id", default_value="0"), @@ -56,6 +63,7 @@ def generate_launch_description(): DeclareLaunchArgument("name", default_value="snap"), DeclareLaunchArgument("delay", default_value="0"), DeclareLaunchArgument("world", default_value=""), + DeclareLaunchArgument("use_odom_bridge", default_value="false"), - OpaqueFunction(function=launch_px4_with_bridge) + OpaqueFunction(function=launch_px4) ]) \ No newline at end of file diff --git a/discower_launch/launch/sitl_multi_agent_kth.launch.py b/discower_launch/launch/sitl_multi_agent_kth.launch.py index aa072a5..04a4271 100644 --- a/discower_launch/launch/sitl_multi_agent_kth.launch.py +++ b/discower_launch/launch/sitl_multi_agent_kth.launch.py @@ -19,7 +19,8 @@ def generate_launch_description(): 'pose': '1,0,0.2', 'name': 'snap', 'delay': '0', - 'world': 'kthspacelab' + 'world': 'kthspacelab', + 'use_odom_bridge': 'true', }.items() ) @@ -31,7 +32,8 @@ def generate_launch_description(): 'pose': '2,0,0.2', 'name': 'crackle', 'delay': '5', - 'world': 'kthspacelab' + 'world': 'kthspacelab', + 'use_odom_bridge': 'true', }.items() ) @@ -43,7 +45,8 @@ def generate_launch_description(): 'pose': '3,0,0.2', 'name': 'pop', 'delay': '5', - 'world': 'kthspacelab' + 'world': 'kthspacelab', + 'use_odom_bridge': 'true', }.items() ) diff --git a/discower_launch/launch/sitl_single_agent_kth.launch.py b/discower_launch/launch/sitl_single_agent_kth.launch.py index c284715..e3473fb 100644 --- a/discower_launch/launch/sitl_single_agent_kth.launch.py +++ b/discower_launch/launch/sitl_single_agent_kth.launch.py @@ -16,7 +16,8 @@ def generate_launch_description(): 'pose': '2,0,0', 'name': 'snap', 'delay': '0', - 'world': 'kthspacelab' + 'world': 'kthspacelab', + 'use_odom_bridge': 'true', }.items() ) ]) \ No newline at end of file From 9d671c67d35491ce13a51a79174657ea3bcffd9b Mon Sep 17 00:00:00 2001 From: E-Krantz Date: Tue, 24 Jun 2025 16:35:37 +0200 Subject: [PATCH 08/10] Replace deprecated tests_require with extras_require for pytest --- setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.py b/setup.py index 1afad07..4754c6d 100644 --- a/setup.py +++ b/setup.py @@ -19,5 +19,8 @@ maintainer_email='jorisv@kth.se', description='simple SITL launch files for single- and multi-agent simulation of the ATMOS platform', license='BSD 3-Clause', + extras_require={ + 'test': ['pytest'] + }, entry_points={}, ) From dcfbff7b9ad3b54b26c6f40815ab306bfb9509ce Mon Sep 17 00:00:00 2001 From: E-Krantz Date: Tue, 24 Jun 2025 16:50:30 +0200 Subject: [PATCH 09/10] Removed exec_depend for ros_gz_bridge --- package.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/package.xml b/package.xml index 36bb5ea..006eceb 100644 --- a/package.xml +++ b/package.xml @@ -10,7 +10,6 @@ px4_msgs ros2launch - ros_gz_bridge ament_copyright ament_flake8 From d2a3a46edae58217de3aa637d0ac1725e2b2536c Mon Sep 17 00:00:00 2001 From: E-Krantz Date: Wed, 25 Jun 2025 09:45:33 +0200 Subject: [PATCH 10/10] Update to README for ROS2-Jazzy bridge --- README.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 47fcac8..c71fb67 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # discower_launch: SITL launch files for Single and Multi-agent experiments -This repository contains launch files indicating how a single and multiple ATMOS space platform SITL simulation can be started. +This repository contains launch files for running Single and Multi-agent ATMOS platform SITL simulations. ## Dependencies @@ -25,13 +25,19 @@ This package provides four main launch files: - `sitl_single_agent_kth.launch.py`: Launches a single agent in the KTH Space Lab world **with** Gazebo-ROS odometry bridging enabled. - `sitl_multi_agent_kth.launch.py`: Launches multiple agents in the KTH Space Lab world **with** Gazebo-ROS odometry bridging enabled. -> **Note:** Gazebo-ROS odometry bridging requires the additional ROS package -> `ros-[ros2-distro]-ros-gzharmonic-bridge`. -> You can install it via, e.g. for Humble: +> **Note:** Gazebo-ROS odometry bridging requires an additional ROS package depending on your ROS2 distribution: > -> ```bash -> sudo apt install ros-humble-ros-gzharmonic-bridge -> ``` +> - **ROS2 Humble:** +> +> ```bash +> sudo apt install ros-humble-ros-gzharmonic-bridge +> ``` +> +> - **ROS2 Jazzy:** +> +> ```bash +> sudo apt install ros-jazzy-ros-gz-bridge +> ``` The bridged odometry simulates the motion capture system used in the real KTH Space Lab and publishes ground-truth data from Gazebo to ROS.