main.cpp
Go to the documentation of this file.
1/**
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @author Fabian Reister ( fabian dot reister at kit dot edu )
17 * @date 2026
18 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
19 * GNU General Public License
20 */
21
22#include <cstdlib>
23#include <filesystem>
24#include <iostream>
25#include <optional>
26#include <string>
27
28#include <boost/program_options.hpp>
29
30#include <SimoxUtility/json/json.hpp>
31
33
38
39#include "Scene.h"
40#include "io.h"
41#include "reparametrization.h"
42
43namespace po = boost::program_options;
44
45using namespace armarx::navigation;
46
47int
48main(int argc, char** argv)
49try
50{
51 po::options_description desc("Allowed options");
52
53 // clang-format off
54 desc.add_options()
55 ("help,h", "produce help message")
56 ("scene", po::value<std::string>()->required(), "Scene description (JSON).")
57 ("out", po::value<std::string>()->default_value("result.json"), "Output file (JSON).")
58 ;
59 // clang-format on
60
61 po::variables_map vm;
62 po::store(po::parse_command_line(argc, argv, desc), vm);
63
64 if (vm.count("help") != 0u)
65 {
66 std::cout << desc << "\n";
67 return EXIT_SUCCESS;
68 }
69
70 po::notify(vm);
71
72 const std::filesystem::path sceneFilename = vm["scene"].as<std::string>();
73 const std::filesystem::path outFilename = vm["out"].as<std::string>();
74
75 ARMARX_INFO << "Reading scene from `" << sceneFilename.string() << "`.";
76 const analysis::Config config = analysis::readConfig(sceneFilename);
77
78 const algorithms::Costmap costmap = analysis::buildCostmap(config);
79
80 // SPFAImpl is the actual pipeline used by the navigation stack (grid search, resampling,
81 // smoothing, orientation optimization, obstacle-aware velocities). Unlike the SPFA wrapper
82 // it needs no core::Scene, so it can be driven from a synthetic costmap.
83 global_planning::SPFAImpl planner(config.plannerParams, config.generalConfig, costmap);
84
85 ARMARX_INFO << "Planning ...";
86 // Not const: the reparametrization below replaces the trajectory's velocities.
87 std::optional<global_planning::GlobalPlannerResult> result =
88 planner.plan(config.start, config.goal);
89
90 if (result.has_value())
91 {
92 ARMARX_IMPORTANT << "Planning succeeded: " << result->trajectory.points().size()
93 << " points, " << result->trajectory.length() << " mm.";
94 }
95 else
96 {
97 ARMARX_WARNING << "Planning failed. Writing costmap only.";
98 }
99
100 // TOPPRA's time-parametrized reference, kept so the plots can compare it against what the
101 // simulated controller executed. Null for the other modes.
102 nlohmann::json reference = nullptr;
103
104 // Re-assign the velocities along the path before simulating. This is what the three modes
105 // compare: the planner's raw obstacle-aware velocities, the robot's ramping, or TOPPRA.
106 // Wall-clock cost of the parametrization. The planner's own stage timings stop at plan(),
107 // so without this the seconds TOPP-RA spends are invisible next to its 15 ms of planning.
108 double parametrizationSeconds = 0.0;
109
110 if (result.has_value() and
112 {
113 ARMARX_IMPORTANT << "Parametrization: " << analysis::toString(config.parametrization);
114
115 analysis::ReparametrizationResult reparametrized =
116 analysis::reparametrize(result->trajectory, config);
117
118 result->trajectory = std::move(reparametrized.trajectory);
119 reference = std::move(reparametrized.reference);
120 parametrizationSeconds = reparametrized.seconds;
121 }
122
123 // Whatever assigned the velocities -- the planner, applyRamping or TOPPRA -- none of them
124 // is aware of the device command ramp, so check the result against it before simulating.
126 if (result.has_value())
127 {
128 rampCheck = analysis::checkAgainstCommandRamp(result->trajectory,
131 }
132
133 // Simulate the low-level controller following the planned trajectory. The planned velocity
134 // profile says nothing about the accelerations the base is asked for; the simulation does.
135 std::optional<simulation::TrajectoryFollowingSimulation::Result> simulated;
136 if (result.has_value() and config.simulate)
137 {
138 ARMARX_INFO << "Simulating trajectory following ...";
140 simulated = sim.run(result->trajectory, config.start);
141 }
142
143 // Verify against the planner's own limit, not a reimplementation of it.
145 outFilename, config, costmap, result, planner.velocityLimit(), simulated, reference,
146 rampCheck, parametrizationSeconds);
147 ARMARX_IMPORTANT << "Wrote `" << outFilename.string() << "`.";
148
149 return EXIT_SUCCESS;
150}
151catch (const std::exception& e)
152{
153 // Without this the process aborts and the reason is buried under the runtime's
154 // `terminate called after throwing an instance of ...`, which reaches the caller as a
155 // bare exit code.
156 ARMARX_ERROR << e.what();
157
158 return EXIT_FAILURE;
159}
std::optional< GlobalPlannerResult > plan(const core::Pose &start, const core::Pose &goal)
Definition SPFA.cpp:253
algorithms::ObstacleAwareVelocityLimit velocityLimit() const
The obstacle-aware velocity limit this planner applies, for the current costmap.
Definition SPFA.cpp:239
Point-mass simulation of the platform following a global trajectory.
Result run(const core::GlobalTrajectory &trajectory, const core::Pose &start) const
Follow trajectory starting from start, which need not be on the trajectory.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:179
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:188
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:194
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:191
CommandRampCheck checkAgainstCommandRamp(const core::GlobalTrajectory &trajectory, const simulation::CommandRateLimit &rateLimit, const float boundaryVelocity)
Compare the profile's v * dv/ds against rateLimit.
ReparametrizationResult reparametrize(const core::GlobalTrajectory &trajectory, const Config &config)
Re-assign the velocities along trajectory according to config.parametrization.
std::string toString(const core::TrajectoryParametrization mode)
void writeResult(const std::filesystem::path &filename, const Config &config, const algorithms::Costmap &costmap, const std::optional< global_planning::GlobalPlannerResult > &result, const algorithms::ObstacleAwareVelocityLimit &limit, const std::optional< simulation::TrajectoryFollowingSimulation::Result > &simulated, const nlohmann::json &reference, const CommandRampCheck &rampCheck, const double parametrizationSeconds)
Write scene, costmap and planning result as JSON for the python plotting tool.
Definition io.cpp:274
Config readConfig(const std::filesystem::path &filename)
Read the scene description. Throws on malformed input.
Definition Scene.cpp:76
algorithms::Costmap buildCostmap(const Config &config)
Build a costmap holding, per cell, the distance to the closest obstacle reduced by the robot radius (...
Definition Scene.cpp:290
This file is part of ArmarX.
How far a velocity profile asks for more than the device command ramp can deliver.
Everything the application needs, as read from the scene description file.
Definition Scene.h:63
core::GeneralConfig generalConfig
Definition Scene.h:77
global_planning::SPFAParams plannerParams
Definition Scene.h:75
bool simulate
Simulate the low-level controller following the planned trajectory.
Definition Scene.h:80
core::TrajectoryParametrization parametrization
How the velocities along the planned path are (re-)assigned before simulating.
Definition Scene.h:93
simulation::TrajectoryFollowingSimulation::Parameters simulationParams
Definition Scene.h:82
double seconds
Wall-clock time the parametrization took [s].
nlohmann::json reference
The time-parametrized reference, as {duration, waypoints: [...]}.
CommandRateLimit rateLimit
The device-side command ramp between the controller and the platform.