Toppra.h
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#pragma once
23
24#include <filesystem>
25#include <memory>
26#include <string>
27
28#include <Eigen/Core>
29
32
34{
35
36 /**
37 * @brief Time-optimal reparametrization under per-motor torque and command-ramp limits.
38 *
39 * Delegates to `armarx_navigation.reparametrization` through an embedded Python
40 * interpreter. The robot model and the wheel Jacobian are loaded once, when this object is
41 * constructed; each `apply()` then exchanges two arrays with it and nothing else.
42 *
43 * The header is deliberately not guarded by the build-time availability macro, so the class
44 * exists whether or not the python side was found. When it was not, the constructor
45 * succeeds and `apply()` throws with the reason recorded at configure time -- that keeps
46 * the factory free of preprocessor branches.
47 *
48 * @note Called once per global path segment, not per control cycle. The solve takes on the
49 * order of a second and holds the GIL; do not move it onto a control path.
50 */
52 {
53 public:
54 /// Column layout of `lastSamples()`. Mirrors `SampleColumn` in the python package,
55 /// which is the single source of truth for the array boundary.
68
69 /// Which drive the platform has. Selects how the geometry below is read, and is not
70 /// inferable from the geometry itself -- a mecanum robot simply leaves the omni-wheel
71 /// fields at zero, which would otherwise reach the solver as a degenerate Jacobian.
72 enum class DriveType
73 {
76 };
77
78 /// ARMAR-7's three-wheel drive, in the units `VirtualRobot::OmniWheelPlatformKinematics`
79 /// uses: mm for the radii, rad for the angles.
81 {
82 float bodyRadius{0.F};
83 float wheelRadius{0.F};
84 float delta{0.F};
85 float relativeAngle{0.F};
86 float gearRatio{1.F};
87 Eigen::Vector3i invertWheel{Eigen::Vector3i::Zero()};
88 };
89
90 /// ARMAR-6's and ARMAR-DE's four-wheel drive, following
91 /// `VirtualRobot::MecanumPlatformKinematics`. All lengths in mm.
93 {
94 /// Half the lateral wheel spacing (`l1`).
95 float gauge{0.F};
96
97 /// Half the longitudinal wheel spacing (`l2`).
98 float wheelbase{0.F};
99
100 float wheelRadius{0.F};
101 };
102
103 /// Everything the python side needs that does not change between paths.
105 {
106 /// Robot model the inverse dynamics is built from.
107 std::string robotFile;
108 std::string nodeSet;
109 std::string configuration;
110
111 /// Selects which of the two geometries below is used.
115
116 /// Drive train.
117 float motorMaxTorque{0.F};
118 float gearRatio{1.F};
120 float torqueFraction{1.F};
121
122 /// Motor/gearbox speed rating referred to the wheel [rad/s], always in rad/s
123 /// regardless of the drive's own unit convention. Bounds each wheel individually,
124 /// which the Cartesian cap does not imply: wheel rate depends on the direction of
125 /// travel, so a mecanum diagonal needs up to sqrt(2) times a straight run's.
126 float maxWheelVelocity{std::numeric_limits<float>::infinity()};
127
128 /// Device command ramp. Infinite leaves the profile bounded by torque alone.
129 float maxAcceleration{std::numeric_limits<float>::infinity()};
130 float maxDeceleration{std::numeric_limits<float>::infinity()};
131 float maxAngularAcceleration{std::numeric_limits<float>::infinity()};
132
133 /// Waypoints the result should have. 0 keeps the input count.
134 int numSamples{500};
135 };
136
137 Toppra(const core::GeneralConfig& config, const DriveParams& drive);
138 ~Toppra() override;
139
140 void apply(core::GlobalTrajectory& trajectory, float startVelocity) const override;
141
142 /// Whether the python side was found at configure time. False means `apply()` throws.
143 static bool available();
144
145 /// Why it is unavailable, as recorded at configure time. Empty when available.
146 static std::string unavailableReason();
147
148 /**
149 * @brief The time-parametrized profile from the most recent `apply()`, `(M, 8)`.
150 *
151 * Introspection only -- for plots and offline analysis, never for control. `apply()`
152 * hands back a `GlobalTrajectory`, which stores a speed per *position*, so the time
153 * axis TOPP-RA computed is lost the moment the result is converted. This keeps it.
154 *
155 * Empty until `apply()` has run; overwritten by each call. Columns are `SampleColumn`.
156 */
157 const Eigen::MatrixXd& lastSamples() const;
158
159 /// Duration [s] of the profile behind `lastSamples()`. Zero until `apply()` has run.
160 double lastDuration() const;
161
162 private:
163 class Impl;
164 std::unique_ptr<Impl> impl_;
165 };
166
167 /**
168 * @brief Read `Toppra::DriveParams` from a `PlatformDynamics<Robot>.json`.
169 *
170 * The same files the analysis application and the python benchmark read, so all three agree
171 * on a platform by construction rather than by three hand-maintained copies.
172 *
173 * @note The ramp limits come from that file's `commandRateLimit` block, which mirrors the
174 * robot's `HardwareConfig/.../Platform.xml`. The two are not linked, so a change to the
175 * hardware config has to be reflected here by hand.
176 *
177 * @throws std::runtime_error if the file is missing, unreadable or lacks a required key.
178 */
179 Toppra::DriveParams LoadDriveParams(const std::filesystem::path& configFile);
180
181 /// Resolve `config/platform/PlatformDynamics<robot>.json` inside the `armarx_navigation`
182 /// package. `robot` is the platform name as the rest of the codebase spells it -- `Armar7`,
183 /// `Armar6`, `ArmarDE` -- matching the analysis application's `--robot`.
184 std::filesystem::path DriveParamsPath(const std::string& robot = "Armar7");
185
186} // namespace armarx::navigation::algorithms
double lastDuration() const
Duration [s] of the profile behind lastSamples(). Zero until apply() has run.
Definition Toppra.cpp:357
SampleColumn
Column layout of lastSamples().
Definition Toppra.h:57
static bool available()
Whether the python side was found at configure time. False means apply() throws.
Definition Toppra.cpp:217
DriveType
Which drive the platform has.
Definition Toppra.h:73
static std::string unavailableReason()
Why it is unavailable, as recorded at configure time. Empty when available.
Definition Toppra.cpp:227
Toppra(const core::GeneralConfig &config, const DriveParams &drive)
Definition Toppra.cpp:362
const Eigen::MatrixXd & lastSamples() const
The time-parametrized profile from the most recent apply(), (M, 8).
Definition Toppra.cpp:351
void apply(core::GlobalTrajectory &trajectory, float startVelocity) const override
Re-assign the velocities of trajectory in place.
Definition Toppra.cpp:401
Assigns the velocities along an already planned path.
This file is part of ArmarX.
Toppra::DriveParams LoadDriveParams(const std::filesystem::path &configFile)
Read Toppra::DriveParams from a PlatformDynamics<Robot>.json.
Definition Toppra.cpp:127
std::filesystem::path DriveParamsPath(const std::string &robot)
Resolve config/platform/PlatformDynamics<robot>.json inside the armarx_navigation package.
Definition Toppra.cpp:119
Everything the python side needs that does not change between paths.
Definition Toppra.h:105
int numSamples
Waypoints the result should have. 0 keeps the input count.
Definition Toppra.h:134
float maxWheelVelocity
Motor/gearbox speed rating referred to the wheel [rad/s], always in rad/s regardless of the drive's o...
Definition Toppra.h:126
float maxAcceleration
Device command ramp. Infinite leaves the profile bounded by torque alone.
Definition Toppra.h:129
DriveType driveType
Selects which of the two geometries below is used.
Definition Toppra.h:112
std::string robotFile
Robot model the inverse dynamics is built from.
Definition Toppra.h:107
ARMAR-6's and ARMAR-DE's four-wheel drive, following VirtualRobot::MecanumPlatformKinematics.
Definition Toppra.h:93
float gauge
Half the lateral wheel spacing (l1).
Definition Toppra.h:95
float wheelbase
Half the longitudinal wheel spacing (l2).
Definition Toppra.h:98
ARMAR-7's three-wheel drive, in the units VirtualRobot::OmniWheelPlatformKinematics uses: mm for the ...
Definition Toppra.h:81