Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ SET(CMAKE_AUTOUIC ON)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(Qt5 REQUIRED COMPONENTS Widgets)
find_package(simulation_interfaces 1 REQUIRED)
# Both the 1.x and 2.x message definitions are supported (see src/resource_compat.h).
# The minimum version is 1.1.0, which introduced the world services.
find_package(simulation_interfaces REQUIRED)
find_package(rclcpp_action REQUIRED)
find_package(tf2 REQUIRED)
find_package(pluginlib REQUIRED)
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ It utilizes https://github.com/ros-simulation/simulation_interfaces to change th

# Prerequisites

`simulation_interfaces` 1.1.0 or newer is required; both the 1.x and the 2.x message definitions are supported.

```shell
sudo apt install ros-$ROS_DISTRO-simulation-interfaces libqt5-dev
```
Expand Down
87 changes: 87 additions & 0 deletions src/resource_compat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* Copyright 2025, Robotec.ai 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.
*/

#pragma once

#include <type_traits>

//! Compatibility helpers for the resource fields of simulation_interfaces.
//!
//! simulation_interfaces 2.0 replaced the flat `uri` and `resource_string` fields of
//! SpawnEntity::Request, LoadWorld::Request and Spawnable with a single nested
//! simulation_interfaces/msg/Resource member, named `entity_resource` or `world_resource`
//! depending on the message. The accessors below resolve the field at compile time, so the
//! panel builds against both the 1.x and the 2.x message definitions.

namespace ResourceCompat
{
template <typename T, typename = void>
struct HasEntityResource : std::false_type
{
};

template <typename T>
struct HasEntityResource<T, std::void_t<decltype(std::declval<T&>().entity_resource)>> : std::true_type
{
};

template <typename T, typename = void>
struct HasWorldResource : std::false_type
{
};

template <typename T>
struct HasWorldResource<T, std::void_t<decltype(std::declval<T&>().world_resource)>> : std::true_type
{
};
} // namespace ResourceCompat

//! Returns the `uri` field of a message, whether it is nested in a Resource member or not.
//! Constness of the message is preserved in the returned reference.
template <typename T>
auto& ResourceUri(T& message)
{
if constexpr (ResourceCompat::HasEntityResource<T>::value)
{
return message.entity_resource.uri;
}
else if constexpr (ResourceCompat::HasWorldResource<T>::value)
{
return message.world_resource.uri;
}
else
{
return message.uri;
}
}

//! Returns the `resource_string` field of a message, whether it is nested in a Resource member or not.
//! Constness of the message is preserved in the returned reference.
template <typename T>
auto& ResourceString(T& message)
{
if constexpr (ResourceCompat::HasEntityResource<T>::value)
{
return message.entity_resource.resource_string;
}
else if constexpr (ResourceCompat::HasWorldResource<T>::value)
{
return message.world_resource.resource_string;
}
else
{
return message.resource_string;
}
}
11 changes: 6 additions & 5 deletions src/simulation_widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <simulation_interfaces/action/simulate_steps.hpp>
#include <tf2/LinearMath/Quaternion.h>
#include "quaternion_utils.h"
#include "resource_compat.h"
#include "service.h"
#include "string_to_keys.h"
#include "ui_sim_widget.h"
Expand Down Expand Up @@ -252,11 +253,11 @@ namespace q_simulation_interfaces
auto selectedWorld = ui_->availableWorldsCombo->currentText();
if (useUriForWorlds_)
{
request.uri = selectedWorld.toStdString();
ResourceUri(request) = selectedWorld.toStdString();
}
else
{
request.resource_string = selectedWorld.toStdString();
ResourceString(request) = selectedWorld.toStdString();
}

auto cb = [this](auto response)
Expand Down Expand Up @@ -729,7 +730,7 @@ namespace q_simulation_interfaces

simulation_interfaces::srv::SpawnEntity::Request request;
request.name = ui_->lineEditName->text().toStdString();
request.uri = ui_->ComboSpawables->currentText().toStdString();
ResourceUri(request) = ui_->ComboSpawables->currentText().toStdString();
request.entity_namespace = ui_->lineEditNamespace->text().toStdString();
request.allow_renaming = ui_->checkBoxAllowRename->isChecked();
request.initial_pose.header.frame_id = ui_->spawnFrameLineEdit->text().toStdString();
Expand Down Expand Up @@ -780,11 +781,11 @@ namespace q_simulation_interfaces

auto spawnables = response->spawnables;
std::sort(spawnables.begin(), spawnables.end(),
[](const auto& a, const auto& b) { return a.uri < b.uri; });
[](const auto& a, const auto& b) { return ResourceUri(a) < ResourceUri(b); });

for (const auto& spawnable : spawnables)
{
ui_->ComboSpawables->addItem(QString::fromStdString(spawnable.uri));
ui_->ComboSpawables->addItem(QString::fromStdString(ResourceUri(spawnable)));
}

if (ui_->ComboSpawables->findText(selectedSpawnable) != -1)
Expand Down