diff --git a/.cruft.json b/.cruft.json index 3e06d3e..6ff1684 100644 --- a/.cruft.json +++ b/.cruft.json @@ -1,6 +1,6 @@ { "template": "https://github.com/UrbanMachine/create-ros-app.git", - "commit": "6a85fd934e7c6297d5fd717c545fad443cc4dfcf", + "commit": "5d14b64b8a4c2ac85f57a19dd962216de9c7a28a", "checkout": null, "context": { "cookiecutter": { diff --git a/docker/Dockerfile b/docker/Dockerfile index 6273fd3..2168b24 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -45,6 +45,7 @@ RUN --mount=type=cache,target="${APT_CACHE}" \ # Build tools build-essential \ git \ + git-lfs \ # Complementary ROS2 Python tools python3-colcon-common-extensions \ python3-colcon-mixin \ diff --git a/launch-profiles/node_helpers_showcase/launcher.py b/launch-profiles/node_helpers_showcase/launcher.py index 4e80f01..a6ea41b 100644 --- a/launch-profiles/node_helpers_showcase/launcher.py +++ b/launch-profiles/node_helpers_showcase/launcher.py @@ -1,12 +1,69 @@ """Launch nodes for this launch profile.""" +from pathlib import Path + from launch import LaunchDescription from launch_ros.actions import Node +# Import the forklift URDF module so it register itself with the URDFConstants +from node_helpers import launching +from node_helpers.parameters import ParameterLoader +from pydantic import BaseModel + + +class MetaParameters(BaseModel): + """This is a great place to put parameters that affect the generation of the launch + file. Don't put node specific configuration in here, rather, put configuration for + what nodes you want to be created in the first place. + + Read more about this functionality under docs/parameters.rst + """ + + urdf_modules_to_load: list[launching.URDFModuleNodeFactory.Parameters] + """This is an example of dynamically loading an arbitrary number of URDFs. + + This is set in the `/robot/launch-profile/parameters.yaml` under `meta_parameters`. + """ + def generate_launch_description() -> LaunchDescription: - rviz_config = "/robot/launch-profile/rviz-config.rviz" + # Create a parameter loader to parse all yaml files in the launch-profile/parameters + # directory, and then apply overrides from the override file, if one exists. + param_loader: ParameterLoader[MetaParameters] = ParameterLoader( + parameters_directory=Path("/robot/launch-profile/parameters/"), + override_file=Path("/robot/launch-profile/parameters.override.yaml"), + meta_parameters_schema=MetaParameters, + ) + + rviz_config = launching.required_file("/robot/launch-profile/rviz-config.rviz") + + urdf_node_factories = ( + launching.URDFModuleNodeFactory(parameters=node_factory_params) + for node_factory_params in param_loader.meta_parameters.urdf_modules_to_load + ) + urdf_nodes = [] + for urdf_node_factory in urdf_node_factories: + urdf_nodes += urdf_node_factory.create_nodes() + launch_description = [ - Node(package="rviz2", executable="rviz2", arguments=["-d", [rviz_config]]), + *urdf_nodes, + Node( + package="node_helpers", + executable="run_ExampleNode", + name="ExampleNode", + parameters=[param_loader.ros_parameters_file], + namespace="example_node_namespace", + ), + Node( + package="rviz2", + executable="rviz2", + arguments=["-d", [str(rviz_config)]], + ), + Node( + namespace="urdf_arrangement", + package="node_helpers", + executable="interactive_transform_publisher", + parameters=[param_loader.ros_parameters_file], + ), ] return LaunchDescription(launch_description) diff --git a/launch-profiles/node_helpers_showcase/parameters/parameters.yaml b/launch-profiles/node_helpers_showcase/parameters/parameters.yaml new file mode 100644 index 0000000..c939132 --- /dev/null +++ b/launch-profiles/node_helpers_showcase/parameters/parameters.yaml @@ -0,0 +1,23 @@ +meta_parameters: + urdf_modules_to_load: + # URDF's are attached to base_link down below in the + - namespace: "example_node_namespace" + urdf_constant_name: "forklift" + + +example_node_namespace: + ExampleNode: + ros__parameters: + root_config: + publish_value: "hello" + publish_hz: 10.0 + +urdf_arrangement: + interactive_transform_publisher: + ros__parameters: + static_transforms_file: /robot/persistent/interactive_transforms.json + scale_factor: 1.0 + tf_publish_frequency: 1.0 + transforms: + # Mounts the forklift urdf to the base_link so it can be visualized in rviz + - "base_link:example_node_namespace.forklift_body" \ No newline at end of file diff --git a/launch-profiles/node_helpers_showcase/rviz-config.rviz b/launch-profiles/node_helpers_showcase/rviz-config.rviz index 5da66cd..7a6847a 100644 --- a/launch-profiles/node_helpers_showcase/rviz-config.rviz +++ b/launch-profiles/node_helpers_showcase/rviz-config.rviz @@ -4,10 +4,10 @@ Panels: Name: Displays Property Tree Widget: Expanded: - - /Global Options1 - - /Status1 + - /InteractiveMarkers1 + - /InteractiveTransforms1 Splitter Ratio: 0.5 - Tree Height: 1064 + Tree Height: 1108 - Class: rviz_common/Selection Name: Selection - Class: rviz_common/Tool Properties @@ -47,10 +47,69 @@ Visualization Manager: Plane Cell Count: 10 Reference Frame: Value: true + - 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: /example_node_namespace/urdf_0/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 + example_node_namespace.forklift_body: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + example_node_namespace.forks: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + example_node_namespace.forks_origin: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + Mass Properties: + Inertia: false + Mass: false + Name: ExampleURDF + TF Prefix: "" + Update Interval: 0 + Value: true + Visual Enabled: true + - Class: rviz_default_plugins/InteractiveMarkers + Enable Transparency: true + Enabled: true + Interactive Markers Namespace: "" + Name: InteractiveMarkers + Show Axes: false + Show Descriptions: true + Show Visual Aids: false + Value: true + - Class: rviz_default_plugins/InteractiveMarkers + Enable Transparency: true + Enabled: true + Interactive Markers Namespace: /urdf_arrangement + Name: InteractiveTransforms + Show Axes: false + Show Descriptions: true + Show Visual Aids: false + Value: true Enabled: true Global Options: Background Color: 48; 48; 48 - Fixed Frame: map + Fixed Frame: base_link Frame Rate: 30 Name: root Tools: @@ -93,33 +152,33 @@ Visualization Manager: Views: Current: Class: rviz_default_plugins/Orbit - Distance: 10 + Distance: 8.649819374084473 Enable Stereo Rendering: Stereo Eye Separation: 0.05999999865889549 Stereo Focal Distance: 1 Swap Stereo Eyes: false Value: false Focal Point: - X: 0 - Y: 0 - Z: 0 + X: -0.4261273145675659 + Y: -0.3684071898460388 + Z: 0.5727261900901794 Focal Shape Fixed Size: true Focal Shape Size: 0.05000000074505806 Invert Z Axis: false Name: Current View Near Clip Distance: 0.009999999776482582 - Pitch: 0.785398006439209 + Pitch: 0.5403984189033508 Target Frame: Value: Orbit (rviz) - Yaw: 0.785398006439209 + Yaw: 1.0753980875015259 Saved: ~ Window Geometry: Displays: collapsed: false - Height: 1355 + Height: 1331 Hide Left Dock: false Hide Right Dock: false - QMainWindow State: 000000ff00000000fd000000040000000000000156000004b1fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003b000004b1000000c700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000004b1fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003b000004b1000000a000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004f60000003efc0100000002fb0000000800540069006d00650100000000000004f60000025300fffffffb0000000800540069006d0065010000000000000450000000000000000000000285000004b100000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + QMainWindow State: 000000ff00000000fd0000000400000000000001c5000004ddfc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003b000004dd000000c700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f00000499fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003b00000499000000a000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000009f40000003efc0100000002fb0000000800540069006d00650000000000000009f40000025300fffffffb0000000800540069006d0065010000000000000450000000000000000000000829000004dd00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 Selection: collapsed: false Time: @@ -128,6 +187,6 @@ Window Geometry: collapsed: false Views: collapsed: false - Width: 1270 - X: 3842 - Y: 40 + Width: 2548 + X: 8 + Y: 64 diff --git a/pkgs/node_helpers/node_helpers/urdfs/loading.py b/pkgs/node_helpers/node_helpers/urdfs/loading.py index e75ac09..349b6bb 100644 --- a/pkgs/node_helpers/node_helpers/urdfs/loading.py +++ b/pkgs/node_helpers/node_helpers/urdfs/loading.py @@ -4,8 +4,6 @@ from ament_index_python import get_package_share_directory -from node_helpers.launching.files import required_file - NAMESPACE_FMT = "{namespace}.{name}" _JOINT_TAG = "joint" _LINK_TAG = "link" @@ -20,7 +18,10 @@ def load_urdf(package: str, relative_urdf_path: Path | str) -> str: relative_urdf_path = Path(relative_urdf_path) package_root = get_package_share_directory(package) - urdf_file = required_file(package_root, relative_urdf_path) + urdf_file = Path(package_root, relative_urdf_path) + + if not urdf_file.is_file(): + raise FileNotFoundError(f"URDF file '{urdf_file!s}' not found") return urdf_file.read_text()