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
2 changes: 1 addition & 1 deletion motion_planners/ompl/src/ompl_motion_planner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ long OMPLMotionPlanner::assignTrajectory(tesseract::command_language::CompositeI
bool found{ false };
Eigen::Index row{ 0 };
auto& ci = output.getInstructions();
for (auto it = ci.begin() + static_cast<long>(start_index); it != ci.end(); ++it)
for (auto it = ci.begin() + start_index; it != ci.end(); ++it)
{
if (it->isMoveInstruction())
{
Expand Down
1 change: 1 addition & 0 deletions task_composer/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ add_library(
src/task_composer_plugin_factory.cpp
src/task_composer_server.cpp
src/task_composer_task.cpp
src/yaml_extensions.cpp
src/yaml_utils.cpp)
add_library(tesseract::task_composer ALIAS task_composer)
if(NOT WIN32 AND NOT APPLE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class TESSERACT_TASK_COMPOSER_NODES_EXPORT RemapTask : public TaskComposerTask
explicit RemapTask(std::string name, const YAML::Node& config, const TaskComposerPluginFactory& plugin_factory);
~RemapTask() override = default;

static tesseract::common::PropertyTree schema();

private:
bool copy_{ false };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ class TaskComposerGraph : public TaskComposerNode
TaskComposerGraph(TaskComposerGraph&&) = delete;
TaskComposerGraph& operator=(TaskComposerGraph&&) = delete;

/** @brief Return the PropertyTree schema for a TaskComposerGraph. */
static tesseract::common::PropertyTree schema();

/**
* @brief Get the root node of the graph
* @return The root node uuid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ class TaskComposerNode

int run(TaskComposerContext& context, OptionalTaskComposerExecutor executor = std::nullopt) const;

/** @brief Return the PropertyTree schema for this node type. */
static tesseract::common::PropertyTree schema();

/** @brief Set the name of the node */
void setName(const std::string& name);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ class TaskComposerNodeFactory
const YAML::Node& config,
const TaskComposerPluginFactory& plugin_factory) const = 0;

/** @brief Return the PropertyTree schema describing the config this factory accepts */
virtual tesseract::common::PropertyTree schema() const;

static std::string getSection();
};

Expand All @@ -85,6 +88,9 @@ class TaskComposerExecutorFactory

virtual std::unique_ptr<TaskComposerExecutor> create(const std::string& name, const YAML::Node& config) const = 0;

/** @brief Return the PropertyTree schema describing the config this factory accepts */
virtual tesseract::common::PropertyTree schema() const;

static std::string getSection();
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#define TESSERACT_TASK_COMPOSER_TASK_COMPOSER_PLUGIN_FACTORY_UTILS_H

#include <tesseract/task_composer/task_composer_plugin_factory.h>
#include <tesseract/common/property_tree.h>

namespace tesseract::task_composer
{
Expand All @@ -38,6 +39,8 @@ class TaskComposerTaskFactory : public TaskComposerNodeFactory
{
return std::make_unique<TaskType>(name, config, plugin_factory);
}

tesseract::common::PropertyTree schema() const override { return TaskType::schema(); }
};

template <typename ExecutorType>
Expand All @@ -48,7 +51,10 @@ class TaskComposerExecutorFactoryImpl : public TaskComposerExecutorFactory
{
return std::make_unique<ExecutorType>(name, config);
}

tesseract::common::PropertyTree schema() const override { return ExecutorType::schema(); }
};

} // namespace tesseract::task_composer

#endif // TESSERACT_TASK_COMPOSER_TASK_COMPOSER_PLUGIN_FACTORY_UTILS_H
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ class TaskComposerTask : public TaskComposerNode
TaskComposerTask(TaskComposerTask&&) = delete;
TaskComposerTask& operator=(TaskComposerTask&&) = delete;

/** @brief Return the PropertyTree schema for this task type. */
static tesseract::common::PropertyTree schema();

/**
* @brief If true this node should call context.abort(uuid_) after run method returns
* @param enable True if task should call context.abort(uuid_) after run method returns
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class TestTask : public TaskComposerTask
bool operator==(const TestTask& rhs) const;
bool operator!=(const TestTask& rhs) const;

static tesseract::common::PropertyTree schema();

private:
static TaskComposerNodePorts ports();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
TESSERACT_COMMON_IGNORE_WARNINGS_POP

#include <tesseract/common/yaml_extensions.h>
#include <tesseract/common/fwd.h>
#include <tesseract/task_composer/task_composer_keys.h>

namespace YAML
Expand Down Expand Up @@ -69,6 +70,8 @@ struct convert<tesseract::task_composer::TaskComposerKeys>

return true;
}

static tesseract::common::PropertyTree schema();
};

} // namespace YAML
Expand Down
34 changes: 34 additions & 0 deletions task_composer/core/include/tesseract/task_composer/yaml_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

#include <memory>

#include <tesseract/common/fwd.h>

namespace YAML
{
class Node;
Expand Down Expand Up @@ -65,6 +67,38 @@ void loadSubTaskConfig(TaskComposerNode& node, const YAML::Node& config);
*/
void validateSubTask(const std::string& parent_name, const std::string& key, const YAML::Node& node);

/** @brief Registry key for the graph edge schema. */
inline constexpr const char* GRAPH_EDGE_SCHEMA_KEY = "tesseract::task_composer::GraphEdge";

/** @brief Registry key for the sub-task schema. */
inline constexpr const char* SUB_TASK_SCHEMA_KEY = "tesseract::task_composer::SubTask";

/** @brief Registry key for the sub-task config schema. */
inline constexpr const char* SUB_TASK_CONFIG_SCHEMA_KEY = "tesseract::task_composer::SubTaskConfig";

/**
* @brief Return the schema for a sub-task entry.
*
* A sub-task is a oneOf: either a plugin info structure (class + config)
* or a named task reference (task + config with conditional/abort_terminal/override).
*/
tesseract::common::PropertyTree subTaskSchema();

/**
* @brief Return the schema for a sub-task config (the 'task' branch config).
*
* Contains optional fields: conditional (bool), abort_terminal (int),
* and override (container with inputs/outputs maps).
*/
tesseract::common::PropertyTree subTaskConfigSchema();

/**
* @brief Return the schema for a graph edge entry.
*
* Contains a required source (string) and required destinations (list of strings).
*/
tesseract::common::PropertyTree graphEdgeSchema();

} // namespace tesseract::task_composer

#endif // TESSERACT_TASK_COMPOSER_CORE_YAML_UTILS_H
12 changes: 12 additions & 0 deletions task_composer/core/src/nodes/remap_task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ TESSERACT_COMMON_IGNORE_WARNINGS_POP
#include <tesseract/task_composer/task_composer_context.h>
#include <tesseract/task_composer/task_composer_data_storage.h>
#include <tesseract/task_composer/task_composer_node_info.h>
#include <tesseract/common/property_tree.h>

namespace tesseract::task_composer
{
Expand Down Expand Up @@ -104,4 +105,15 @@ TaskComposerNodeInfo RemapTask::runImpl(TaskComposerContext& context, OptionalTa
}
return info;
}

tesseract::common::PropertyTree RemapTask::schema()
{
using namespace tesseract::common;
return PropertyTreeBuilder()
.attribute(property_attribute::TYPE, property_type::CONTAINER)
.compose(TaskComposerTask::schema())
.boolean("copy")
.done()
.build();
}
} // namespace tesseract::task_composer
125 changes: 125 additions & 0 deletions task_composer/core/src/task_composer_graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ TESSERACT_COMMON_IGNORE_WARNINGS_POP
#include <tesseract/task_composer/task_composer_plugin_factory.h>
#include <tesseract/task_composer/yaml_extensions.h>
#include <tesseract/task_composer/yaml_utils.h>
#include <tesseract/common/property_tree.h>

namespace tesseract::task_composer
{
Expand Down Expand Up @@ -520,4 +521,128 @@ std::string TaskComposerGraph::dump(std::ostream& os,
return {};
}

namespace
{
/**
* @brief Validator that checks terminals, edge sources, and edge destinations all reference keys in the nodes map.
*/
void validateGraphNodeReferences(const tesseract::common::PropertyTree& node,
const std::string& path,
std::vector<std::string>& errors)
{
// Collect node keys from the nodes map
const auto* nodes_node = node.find("nodes");
if (nodes_node == nullptr || nodes_node->getValue().IsNull())
return; // nodes missing — other validators handle that

std::set<std::string> node_keys;
if (nodes_node->getValue().IsMap())
{
for (auto it = nodes_node->getValue().begin(); it != nodes_node->getValue().end(); ++it)
node_keys.insert(it->first.as<std::string>());
}

if (node_keys.empty())
return;

// Validate terminals
const auto* terminals_node = node.find("terminals");
if (terminals_node != nullptr && terminals_node->getValue().IsSequence())
{
for (std::size_t i = 0; i < terminals_node->getValue().size(); ++i)
{
auto name = terminals_node->getValue()[i].as<std::string>();
if (node_keys.find(name) == node_keys.end())
{
std::string error = path;
error += ".terminals[";
error += std::to_string(i);
error += "]: '";
error += name;
error += "' not found in nodes";
errors.push_back(std::move(error));
}
}
}

// Validate edge sources and destinations
const auto* edges_node = node.find("edges");
if (edges_node != nullptr && edges_node->getValue().IsSequence())
{
for (std::size_t i = 0; i < edges_node->getValue().size(); ++i)
{
const auto& edge = edges_node->getValue()[i];
if (edge["source"])
{
auto source = edge["source"].as<std::string>();
if (node_keys.find(source) == node_keys.end())
{
std::string error = path;
error += ".edges[";
error += std::to_string(i);
error += "].source: '";
error += source;
error += "' not found in nodes";
errors.push_back(std::move(error));
}
}
if (edge["destinations"])
{
const auto& dests = edge["destinations"];
if (dests.IsSequence())
{
for (std::size_t j = 0; j < dests.size(); ++j)
{
auto dest = dests[j].as<std::string>();
if (node_keys.find(dest) == node_keys.end())
{
std::string error = path;
error += ".edges[";
error += std::to_string(i);
error += "].destinations[";
error += std::to_string(j);
error += "]: '";
error += dest;
error += "' not found in nodes";
errors.push_back(std::move(error));
}
}
}
else if (dests.IsScalar())
{
auto dest = dests.as<std::string>();
if (node_keys.find(dest) == node_keys.end())
{
std::string error = path;
error += ".edges[";
error += std::to_string(i);
error += "].destinations: '";
error += dest;
error += "' not found in nodes";
errors.push_back(std::move(error));
}
}
}
}
}
}
} // namespace

tesseract::common::PropertyTree TaskComposerGraph::schema()
{
using namespace tesseract::common;
// clang-format off
return PropertyTreeBuilder()
.attribute(property_attribute::TYPE, property_type::CONTAINER)
.compose(TaskComposerNode::schema())
.validator(validateGraphNodeReferences)
.customType("nodes", property_type::createMap(SUB_TASK_SCHEMA_KEY))
.required().acceptsDerivedTypes().validator(validateCustomType).done()
.customType("edges", property_type::createList(GRAPH_EDGE_SCHEMA_KEY)).required()
.validator(validateCustomType).done()
.customType("terminals", property_type::createList(property_type::STRING)).required().done()
.build();
// clang-format on
}

} // namespace tesseract::task_composer
15 changes: 15 additions & 0 deletions task_composer/core/src/task_composer_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ TESSERACT_COMMON_IGNORE_WARNINGS_POP
#include <tesseract/task_composer/task_composer_node_info.h>
#include <tesseract/task_composer/task_composer_data_storage.h>
#include <tesseract/task_composer/yaml_extensions.h>
#include <tesseract/common/property_tree.h>

namespace tesseract::task_composer
{
Expand Down Expand Up @@ -95,6 +96,20 @@ TaskComposerNode::TaskComposerNode(std::string name,
validatePorts();
}

tesseract::common::PropertyTree TaskComposerNode::schema()
{
using namespace tesseract::common;
// clang-format off
return PropertyTreeBuilder()
.attribute(property_attribute::TYPE, property_type::CONTAINER)
.string("namespace").done()
.boolean("conditional").done()
.customType("inputs", "tesseract::task_composer::TaskComposerKeys").validator(validateCustomType).done()
.customType("outputs", "tesseract::task_composer::TaskComposerKeys").validator(validateCustomType).done()
.build();
// clang-format on
}

int TaskComposerNode::run(TaskComposerContext& context, OptionalTaskComposerExecutor executor) const
{
auto start_time = std::chrono::system_clock::now();
Expand Down
11 changes: 11 additions & 0 deletions task_composer/core/src/task_composer_plugin_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ TESSERACT_COMMON_IGNORE_WARNINGS_POP
#include <tesseract/common/resource_locator.h>
#include <tesseract/common/yaml_utils.h>
#include <tesseract/common/yaml_extensions.h>
#include <tesseract/common/property_tree.h>
#include <tesseract/task_composer/task_composer_plugin_factory.h>
#include <tesseract/task_composer/task_composer_node.h>
#include <tesseract/task_composer/task_composer_executor.h>
Expand All @@ -47,8 +48,18 @@ namespace tesseract::task_composer
{
std::string TaskComposerExecutorFactory::getSection() { return "TaskExec"; }

tesseract::common::PropertyTree TaskComposerExecutorFactory::schema() const
{
return tesseract::common::PropertyTreeBuilder().build();
}

std::string TaskComposerNodeFactory::getSection() { return "TaskNode"; }

tesseract::common::PropertyTree TaskComposerNodeFactory::schema() const
{
return tesseract::common::PropertyTreeBuilder().build();
}

struct TaskComposerPluginFactory::Implementation
{
mutable std::map<std::string, TaskComposerExecutorFactory::Ptr> executor_factories;
Expand Down
Loading
Loading