diff --git a/README.md b/README.md
index 6e6159b4..a5e46bd9 100644
--- a/README.md
+++ b/README.md
@@ -85,7 +85,6 @@ Launch arguments are largely common to both simulation and physical robot. Howev
| 🤖 | 🖥️ | Argument | Description
***Type:*** `Default` |
| --- | --- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
-| ❌ | ✅ | `add_wheel_joints` | Flag enabling joint_state_publisher to publish information about the wheel position. Should be false when there is a controller that sends this information.
***bool:*** `False` |
| ❌ | ✅ | `add_world_transform` | Adds a world frame that connects the tf trees of individual robots (useful when running multiple robots).
***bool:*** `False` |
| ✅ | ✅ | `animations_config_path` | Path to a YAML file with a description of led configuration. This file includes definition of robot panels, virtual segments and default animations.
***string:*** [`{robot_model}_animations.yaml`](./husarion_ugv_lights/config) |
| ❌ | ✅ | `battery_config_path` | Path to the Ignition LinearBatteryPlugin configuration file. This configuration is intended for use in simulations only.
***string:*** `None` |
@@ -108,6 +107,8 @@ Launch arguments are largely common to both simulation and physical robot. Howev
| ✅ | ✅ | `safety_bt_project_path` | Path to BehaviorTree project file, responsible for safety and shutdown management.
***string:*** [`SafetyBT.btproj`](./husarion_ugv_manager/behavior_trees/SafetyBT.btproj) |
| ✅ | ✅ | `shutdown_hosts_config_path` | Path to file with list of hosts to request shutdown.
***string:*** [`shutdown_hosts.yaml`](./husarion_ugv_manager/config/shutdown_hosts.yaml) |
| ✅ | ✅ | `use_ekf` | Enable or disable EKF.
***bool:*** `True` |
+| ❌ | ✅ | `use_joint_state_publisher` | Flag enabling joint_state_publisher to publish information about the wheel position. Should be false when there is a controller that sends this information.
***bool:*** `False` |
+| ❌ | ✅ | `use_joint_state_publisher_gui` | Flag enabling joint_state_publisher_gui to publish information about the wheel position. Should be false when there is a controller that sends this information.
***bool:*** `False` |
| ❌ | ✅ | `use_rviz` | Run RViz simultaneously.
***bool:*** `True` |
| ✅ | ✅ | `use_sim` | Whether simulation is used.
***bool:*** `False` |
| ✅ | ✅ | `user_led_animations_path` | Path to a YAML file with a description of the user-defined animations.
***string:*** `''` |
diff --git a/husarion_ugv_description/CONFIGURATION.md b/husarion_ugv_description/CONFIGURATION.md
new file mode 100644
index 00000000..c1c7e8b0
--- /dev/null
+++ b/husarion_ugv_description/CONFIGURATION.md
@@ -0,0 +1,69 @@
+# husarion_ugv_description
+
+## URDF - Robot Model Configuration
+
+### Configure Components
+
+Create `components.yaml` file with the desired components. Here's a sample configuration:
+
+```yaml
+components:
+ - type: MAN02
+ parent_link: cover_link
+ xyz: 0.2 -0.2 0.0
+ rpy: 0.0 0.0 0.0
+ device_namespace: ur5
+```
+
+In this example:
+ - `type`: MAN02: Specifies the component type.
+ - `parent_link`: cover_link: Defines the parent link to attach the component.
+ - `xyz`: 0.2 -0.2 0.0: Sets the position of the component.
+ - `rpy`: 0.0 0.0 0.0: Sets the rotation of the component.
+ - `device_namespace`: ur5: Sets the device namespace.
+
+### Visualize Robot Model Configuration
+
+To use the `ros2 launch` command to launch the `visualize_fake_robot.launch.py` file with a specified robot model and components configuration path, follow these steps:
+
+1. Open a terminal.
+2. Source build workspace.
+3. Execute the following command:
+
+```bash
+ros2 launch husarion_ugv_description visualize_fake_robot.launch.py robot_model:=lynx use_joint_state_publisher:=true components_config_path:=$(pwd)/components.yaml
+```
+
+If you want to move the wheels or move the manipulator you can run the launch file with `joint_state_publisher_gui`:
+
+```bash
+ros2 launch husarion_ugv_description visualize_fake_robot.launch.py robot_model:=lynx use_joint_state_publisher_gui:=true components_config_path:=$(pwd)/components.yaml
+```
+
+### Overwrite Robot Model Configuration
+
+To change the configuration let's add another manipulator to `components.yaml`:
+
+```yaml
+components:
+ - type: MAN02
+ parent_link: cover_link
+ xyz: 0.2 -0.2 0.0
+ rpy: 0.0 0.0 0.0
+ device_namespace: left_ur5
+ - type: MAN02
+ parent_link: cover_link
+ xyz: 0.2 0.2 0.0
+ rpy: 0.0 0.0 0.0
+ device_namespace: right_ur5
+```
+
+To use the `ros2 launch` command to launch the `overwrite_robot_description.launch.py` file with the appropriate arguments to overwrite the robot model, follow these steps:
+
+1. Open a terminal.
+2. Source workspace.
+3. Execute the following command:
+
+```bash
+ros2 launch husarion_ugv_description overwrite_robot_description.launch.py robot_model:=lynx components_config_path:=$(pwd)/components.yaml
+```
diff --git a/husarion_ugv_description/launch/load_urdf.launch.py b/husarion_ugv_description/launch/load_urdf.launch.py
index 9347553f..c4acc0c4 100644
--- a/husarion_ugv_description/launch/load_urdf.launch.py
+++ b/husarion_ugv_description/launch/load_urdf.launch.py
@@ -19,7 +19,6 @@
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
-from launch.conditions import IfCondition
from launch.substitutions import (
Command,
EnvironmentVariable,
@@ -33,15 +32,6 @@
def generate_launch_description():
- add_wheel_joints = LaunchConfiguration("add_wheel_joints")
- declared_add_wheel_joints_arg = DeclareLaunchArgument(
- "add_wheel_joints",
- default_value="True",
- description="Flag enabling joint_state_publisher to publish information about the wheel "
- "position. Should be false when there is a controller that sends this information.",
- choices=["True", "true", "False", "false"],
- )
-
battery_config_path = LaunchConfiguration("battery_config_path")
declare_battery_config_path_arg = DeclareLaunchArgument(
"battery_config_path",
@@ -183,16 +173,7 @@ def generate_launch_description():
emulate_tty=True,
)
- joint_state_publisher_node = Node(
- package="joint_state_publisher",
- executable="joint_state_publisher",
- namespace=namespace,
- emulate_tty=True,
- condition=IfCondition(add_wheel_joints),
- )
-
actions = [
- declared_add_wheel_joints_arg,
declare_battery_config_path_arg,
declare_components_config_path_arg,
declare_robot_model_arg, # robot_model is used by wheel_type
@@ -203,7 +184,6 @@ def generate_launch_description():
declare_wheel_config_path_arg,
SetParameter(name="use_sim_time", value=use_sim),
robot_state_pub_node,
- joint_state_publisher_node, # do not publish, when use_sim is true
]
return LaunchDescription(actions)
diff --git a/husarion_ugv_description/launch/visualize_fake_robot.launch.py b/husarion_ugv_description/launch/visualize_fake_robot.launch.py
new file mode 100644
index 00000000..236eb897
--- /dev/null
+++ b/husarion_ugv_description/launch/visualize_fake_robot.launch.py
@@ -0,0 +1,153 @@
+#!/usr/bin/env python3
+
+# Copyright 2020 ros2_control Development Team
+# 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.
+
+import os
+
+from launch import LaunchDescription
+from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
+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
+from launch_ros.substitutions import FindPackageShare
+
+
+def generate_launch_description():
+ components_config_path = LaunchConfiguration("components_config_path")
+ declare_components_config_path_arg = DeclareLaunchArgument(
+ "components_config_path",
+ default_value=PathJoinSubstitution(
+ [FindPackageShare("husarion_ugv_description"), "config", "components.yaml"]
+ ),
+ description=(
+ "Additional components configuration file. Components described in this file "
+ "are dynamically included in Panther's urdf."
+ "Panther options are described here "
+ "https://husarion.com/manuals/panther/panther-options/"
+ ),
+ )
+
+ namespace = LaunchConfiguration("namespace")
+ declare_namespace_arg = DeclareLaunchArgument(
+ "namespace",
+ default_value=EnvironmentVariable("ROBOT_NAMESPACE", default_value=""),
+ description="Add namespace to all launched nodes.",
+ )
+
+ robot_model = LaunchConfiguration("robot_model")
+ robot_model_dict = {"LNX": "lynx", "PTH": "panther"}
+ robot_model_env = os.environ.get("ROBOT_MODEL", default="PTH")
+ declare_robot_model_arg = DeclareLaunchArgument(
+ "robot_model",
+ default_value=robot_model_dict[robot_model_env],
+ description="Specify robot model.",
+ choices=["lynx", "panther"],
+ )
+
+ rviz_config = LaunchConfiguration("rviz_config")
+ declare_rviz_config_arg = DeclareLaunchArgument(
+ "rviz_config",
+ default_value=PathJoinSubstitution(
+ [FindPackageShare("husarion_ugv_description"), "rviz", "robot_model.rviz"]
+ ),
+ description="RViz configuration file.",
+ )
+
+ use_joint_state_publisher = LaunchConfiguration("use_joint_state_publisher")
+ declare_use_joint_state_publisher_arg = DeclareLaunchArgument(
+ "use_joint_state_publisher",
+ default_value="False",
+ description="Flag enabling joint_state_publisher to publish information about joints positions. Should be false when there is a controller that sends this information.",
+ choices=["True", "true", "False", "false"],
+ )
+
+ use_joint_state_publisher_gui = LaunchConfiguration("use_joint_state_publisher_gui")
+ declare_use_joint_state_publisher_gui_arg = DeclareLaunchArgument(
+ "use_joint_state_publisher_gui",
+ default_value="False",
+ description="Flag enabling joint_state_publisher_gui to publish information about joints positions. Should be false when there is a controller that sends this information.",
+ choices=["True", "true", "False", "false"],
+ )
+
+ wheel_type = LaunchConfiguration("wheel_type")
+ default_wheel_type = {"lynx": "WH05", "panther": "WH01"}
+ declare_wheel_type_arg = DeclareLaunchArgument(
+ "wheel_type",
+ default_value=PythonExpression([f"{default_wheel_type}['", robot_model, "']"]),
+ description=(
+ "Specify the wheel type. If the selected wheel type is not 'custom', "
+ "the 'wheel_config_path' and 'controller_config_path' arguments will be "
+ "automatically adjusted and can be omitted."
+ ),
+ choices=["WH01", "WH02", "WH04", "WH05", "custom"],
+ )
+
+ load_urdf = IncludeLaunchDescription(
+ PythonLaunchDescriptionSource(
+ [FindPackageShare("husarion_ugv_description"), "/launch/load_urdf.launch.py"]
+ ),
+ launch_arguments={
+ "components_config_path": components_config_path,
+ "namespace": namespace,
+ "robot_model": robot_model,
+ "wheel_type": wheel_type,
+ }.items(),
+ )
+
+ rviz = IncludeLaunchDescription(
+ PythonLaunchDescriptionSource(
+ [FindPackageShare("husarion_ugv_description"), "/launch/rviz.launch.py"]
+ ),
+ launch_arguments={"namespace": namespace, "rviz_config": rviz_config}.items(),
+ )
+
+ joint_state_publisher_node = Node(
+ package="joint_state_publisher",
+ executable="joint_state_publisher",
+ namespace=namespace,
+ emulate_tty=True,
+ condition=IfCondition(use_joint_state_publisher),
+ )
+
+ joint_state_publisher_gui_node = Node(
+ package="joint_state_publisher_gui",
+ executable="joint_state_publisher_gui",
+ namespace=namespace,
+ emulate_tty=True,
+ condition=IfCondition(use_joint_state_publisher_gui),
+ )
+
+ actions = [
+ declare_components_config_path_arg,
+ declare_namespace_arg,
+ declare_robot_model_arg,
+ declare_rviz_config_arg,
+ declare_use_joint_state_publisher_arg,
+ declare_use_joint_state_publisher_gui_arg,
+ declare_wheel_type_arg,
+ load_urdf,
+ rviz,
+ joint_state_publisher_node,
+ joint_state_publisher_gui_node,
+ ]
+
+ return LaunchDescription(actions)
diff --git a/husarion_ugv_description/package.xml b/husarion_ugv_description/package.xml
index 5712cdfd..481d035d 100644
--- a/husarion_ugv_description/package.xml
+++ b/husarion_ugv_description/package.xml
@@ -20,6 +20,7 @@
ament_cmake
joint_state_publisher
+ joint_state_publisher_gui
launch
launch_ros
nav2_common
diff --git a/husarion_ugv_description/rviz/robot_model.rviz b/husarion_ugv_description/rviz/robot_model.rviz
new file mode 100644
index 00000000..73166d19
--- /dev/null
+++ b/husarion_ugv_description/rviz/robot_model.rviz
@@ -0,0 +1,233 @@
+Panels:
+ - Class: rviz_common/Displays
+ Help Height: 85
+ Name: Displays
+ Property Tree Widget:
+ Expanded:
+ - /Status1
+ Splitter Ratio: 0.5
+ Tree Height: 692
+ - Class: rviz_common/Selection
+ Name: Selection
+ - Class: rviz_common/Tool Properties
+ Expanded:
+ - /2D Goal Pose1
+ - /Publish Point1
+ Name: Tool Properties
+ Splitter Ratio: 0.5886790156364441
+ - Class: rviz_common/Views
+ Expanded:
+ - /Current View1
+ Name: Views
+ Splitter Ratio: 0.5
+ - Class: rviz_common/Time
+ Experimental: false
+ Name: Time
+ SyncMode: 0
+ SyncSource: ""
+Visualization Manager:
+ Class: ""
+ Displays:
+ - Class: rviz_common/Group
+ Displays:
+ - Alpha: 0.5
+ Cell Size: 1
+ Class: rviz_default_plugins/Grid
+ Color: 160; 160; 164
+ Enabled: true
+ Line Style:
+ Line Width: 0.029999999329447746
+ Value: Lines
+ Name: Grid
+ Normal Cell Count: 0
+ Offset:
+ X: 0
+ Y: 0
+ Z: 0
+ Plane: XY
+ Plane Cell Count: 10
+ Reference Frame:
+ Value: true
+ Enabled: true
+ Name: Map
+ - Class: rviz_common/Group
+ Displays:
+ - Alpha: 1
+ Class: rviz_default_plugins/RobotModel
+ Collision Enabled: false
+ Description File: ""
+ Description Source: Topic
+ Description Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: robot_description
+ Enabled: true
+ Links:
+ All Links Enabled: true
+ Expand Joint Details: false
+ Expand Link Details: false
+ Expand Tree: false
+ Link Tree Style: Links in Alphabetic Order
+ base_link:
+ Alpha: 1
+ Show Axes: false
+ Show Trail: false
+ body_link:
+ Alpha: 1
+ Show Axes: false
+ Show Trail: false
+ Value: true
+ cover_link:
+ Alpha: 1
+ Show Axes: false
+ Show Trail: false
+ fl_wheel_link:
+ Alpha: 1
+ Show Axes: false
+ Show Trail: false
+ Value: true
+ fr_wheel_link:
+ Alpha: 1
+ Show Axes: false
+ Show Trail: false
+ Value: true
+ front_bumper_link:
+ Alpha: 1
+ Show Axes: false
+ Show Trail: false
+ imu_link:
+ Alpha: 1
+ Show Axes: false
+ Show Trail: false
+ lights_channel_1_link:
+ Alpha: 1
+ Show Axes: false
+ Show Trail: false
+ lights_channel_2_link:
+ Alpha: 1
+ Show Axes: false
+ Show Trail: false
+ rear_bumper_link:
+ Alpha: 1
+ Show Axes: false
+ Show Trail: false
+ rl_wheel_link:
+ Alpha: 1
+ Show Axes: false
+ Show Trail: false
+ Value: true
+ rr_wheel_link:
+ Alpha: 1
+ Show Axes: false
+ Show Trail: false
+ Value: true
+ Mass Properties:
+ Inertia: false
+ Mass: false
+ Name: RobotModel
+ TF Prefix: ""
+ Update Interval: 0
+ Value: true
+ Visual Enabled: true
+ - Class: rviz_default_plugins/TF
+ Enabled: false
+ Frame Timeout: 15
+ Frames:
+ All Enabled: true
+ Marker Scale: 1
+ Name: TF
+ Show Arrows: true
+ Show Axes: true
+ Show Names: false
+ Tree:
+ {}
+ Update Interval: 0
+ Value: false
+ Enabled: true
+ Name: Robot
+ Enabled: true
+ Global Options:
+ Background Color: 48; 48; 48
+ Fixed Frame: base_link
+ Frame Rate: 30
+ Name: root
+ Tools:
+ - Class: rviz_default_plugins/Interact
+ Hide Inactive Objects: true
+ - Class: rviz_default_plugins/MoveCamera
+ - Class: rviz_default_plugins/Select
+ - Class: rviz_default_plugins/FocusCamera
+ - Class: rviz_default_plugins/Measure
+ Line color: 128; 128; 0
+ - Class: rviz_default_plugins/SetInitialPose
+ Covariance x: 0.25
+ Covariance y: 0.25
+ Covariance yaw: 0.06853891909122467
+ Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: initialpose
+ - Class: rviz_default_plugins/SetGoal
+ Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: goal_pose
+ - Class: rviz_default_plugins/PublishPoint
+ Single click: true
+ Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: clicked_point
+ Transformation:
+ Current:
+ Class: rviz_default_plugins/TF
+ Value: true
+ Views:
+ Current:
+ Class: rviz_default_plugins/Orbit
+ Distance: 2.1199140548706055
+ Enable Stereo Rendering:
+ Stereo Eye Separation: 0.05999999865889549
+ Stereo Focal Distance: 1
+ Swap Stereo Eyes: false
+ Value: false
+ Focal Point:
+ X: 0.13748444616794586
+ Y: 0.210101917386055
+ Z: 0.22006787359714508
+ Focal Shape Fixed Size: false
+ Focal Shape Size: 0.05000000074505806
+ Invert Z Axis: false
+ Name: Current View
+ Near Clip Distance: 0.009999999776482582
+ Pitch: 0.49539831280708313
+ Target Frame:
+ Value: Orbit (rviz)
+ Yaw: 0.8653994202613831
+ Saved: ~
+Window Geometry:
+ Displays:
+ collapsed: false
+ Height: 1009
+ Hide Left Dock: false
+ Hide Right Dock: true
+ QMainWindow State: 000000ff00000000fd00000004000000000000015a0000034afc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006b00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c00610079007301000000440000034a000000eb00fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f0000035afc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003d0000035a000000b900fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073a0000003efc0100000002fb0000000800540069006d006501000000000000073a000002d200fffffffb0000000800540069006d00650100000000000004500000000000000000000005d90000034a00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
+ Selection:
+ collapsed: false
+ Time:
+ collapsed: false
+ Tool Properties:
+ collapsed: false
+ Views:
+ collapsed: true
+ Width: 1850
+ X: 70
+ Y: 34
diff --git a/husarion_ugv_gazebo/launch/simulate_robot.launch.py b/husarion_ugv_gazebo/launch/simulate_robot.launch.py
index 9fd37809..f21e0148 100644
--- a/husarion_ugv_gazebo/launch/simulate_robot.launch.py
+++ b/husarion_ugv_gazebo/launch/simulate_robot.launch.py
@@ -106,7 +106,6 @@ def generate_launch_description():
)
),
launch_arguments={
- "add_wheel_joints": "False",
"namespace": namespace,
"robot_model": robot_model,
}.items(),
diff --git a/husarion_ugv_gazebo/launch/spawn_robot.launch.py b/husarion_ugv_gazebo/launch/spawn_robot.launch.py
index 77527036..2c0480d3 100644
--- a/husarion_ugv_gazebo/launch/spawn_robot.launch.py
+++ b/husarion_ugv_gazebo/launch/spawn_robot.launch.py
@@ -88,7 +88,6 @@ def generate_launch_description():
)
),
launch_arguments={
- "add_wheel_joints": LaunchConfiguration("add_wheel_joints", default="True"),
"namespace": namespace,
"robot_model": robot_model,
"use_sim": "True",