30#include <SimoxUtility/json/json.hpp>
42 toJson(
const Eigen::Vector2f& v)
44 return nlohmann::json::array({v.x(), v.y()});
49 toJson(
const Eigen::VectorXf& v)
51 nlohmann::json a = nlohmann::json::array();
52 for (Eigen::Index i = 0; i < v.size(); i++)
61 toJsonFlags(
const Eigen::ArrayXi& v)
63 nlohmann::json a = nlohmann::json::array();
64 for (Eigen::Index i = 0; i < v.size(); i++)
66 a.push_back(v[i] != 0);
74 return std::atan2(pose.linear()(1, 0), pose.linear()(0, 0));
80 return nlohmann::json{{
"x", pose.translation().x()},
81 {
"y", pose.translation().y()},
82 {
"yaw", yawOf(pose)}};
86 toJson(
const Scene& scene)
88 nlohmann::json jObstacles = nlohmann::json::array();
91 jObstacles.push_back(nlohmann::json{
93 {
"min", toJson(obstacle.
min)},
94 {
"max", toJson(obstacle.
max)},
95 {
"yaw", obstacle.
yaw}});
98 return nlohmann::json{
100 nlohmann::json{{
"min", toJson(scene.
bounds.
min)},
103 {
"obstacles", jObstacles}};
111 nlohmann::json jGrid = nlohmann::json::array();
112 for (
int ix = 0; ix < grid.rows(); ix++)
114 std::vector<float> row(
static_cast<std::size_t
>(grid.cols()));
115 for (
int iy = 0; iy < grid.cols(); iy++)
117 row[
static_cast<std::size_t
>(iy)] = grid(ix, iy);
120 jGrid.push_back(row);
123 return nlohmann::json{
129 {
"rows", grid.rows()},
130 {
"cols", grid.cols()},
135 constexpr float violationTolerance = 1e-3F;
143 constexpr float violationToleranceAbsolute = 5.F;
149 nlohmann::json jPoints = nlohmann::json::array();
151 std::size_t violations = 0;
152 float maxViolation = 0.F;
156 const core::Position& position = point.waypoint.pose.translation();
157 const float permissible = limit.
at(Eigen::Vector2f{position.head<2>()});
158 const float excess = point.velocity - permissible;
160 if (excess > std::max(violationTolerance * permissible,
161 violationToleranceAbsolute))
164 maxViolation = std::max(maxViolation, excess);
167 jPoints.push_back(nlohmann::json{{
"x", position.x()},
169 {
"yaw", yawOf(point.waypoint.pose)},
170 {
"velocity", point.velocity},
171 {
"velocity_limit", permissible}});
174 return nlohmann::json{
179 {
"velocity_limit_violations", violations},
180 {
"max_velocity_limit_violation", maxViolation}};
187 nlohmann::json jSamples = nlohmann::json::array();
189 for (
const auto& sample : simulated.
samples)
191 const core::Position& position = sample.global_T_robot.translation();
194 nlohmann::json{{
"t", sample.time},
197 {
"yaw", yawOf(sample.global_T_robot)},
198 {
"speed", sample.speed},
199 {
"vx", sample.velocityGlobal.x()},
200 {
"vy", sample.velocityGlobal.y()},
201 {
"commanded_speed", sample.commandedVelocityGlobal.norm()},
202 {
"angular_velocity", sample.commandedAngular},
203 {
"required_linear_acceleration",
204 sample.requiredLinearAcceleration},
205 {
"linear_acceleration", sample.linearAcceleration},
206 {
"required_angular_acceleration",
207 sample.requiredAngularAcceleration},
208 {
"angular_acceleration", sample.angularAcceleration},
209 {
"acceleration_saturated", sample.accelerationSaturated},
210 {
"required_wheel_accelerations", toJson(sample.requiredWheelAccelerations)},
211 {
"wheel_velocities", toJson(sample.wheelVelocities)},
212 {
"wheel_saturated", toJsonFlags(sample.wheelSaturated)},
213 {
"required_motor_torques", toJson(sample.requiredMotorTorques)},
214 {
"applied_motor_torques", toJson(sample.appliedMotorTorques)},
215 {
"motor_saturated", toJsonFlags(sample.motorSaturated)},
216 {
"wheel_speed_saturated", toJsonFlags(sample.wheelSpeedSaturated)},
217 {
"drop_point_velocity", sample.dropPointVelocity},
218 {
"tracking_error", sample.trackingError},
219 {
"distance_to_goal", sample.distanceToGoal},
220 {
"orientation_error", sample.orientationError}});
223 const std::string modelName = [&]() -> std::string
225 switch (dynamics.
model)
228 return "omni_wheel_torque";
230 return "mecanum_torque";
232 return "omni_wheel_velocity";
240 return nlohmann::json{
241 {
"samples", jSamples},
267 {
"model", modelName},
280 const std::optional<global_planning::GlobalPlannerResult>& result,
282 const std::optional<simulation::TrajectoryFollowingSimulation::Result>& simulated,
283 const nlohmann::json& reference,
285 const double parametrizationSeconds)
288 {
"success", result.has_value()},
289 {
"scene", toJson(config.
scene)},
290 {
"start", toJson(config.
start)},
291 {
"goal", toJson(config.
goal)},
292 {
"costmap", toJson(costmap)},
302 {
"enable_final_velocity_clamp",
306 if (result.has_value())
308 j[
"trajectory"] = toJson(result->trajectory, limit);
309 j[
"timings"] = result->timings;
313 j[
"parametrization_seconds"] = parametrizationSeconds;
325 const float inputSpeedRpm =
326 std::min(drive.motorNominalSpeedRpm, drive.gearboxMaxInputSpeedRpm);
328 const float maxWheelVelocity =
330 ? drive.maxWheelVelocity
331 : inputSpeedRpm / 60.F / drive.gearRatio * 2.F *
static_cast<float>(
M_PI);
333 j[
"parametrization_limits"] = nlohmann::json{
336 {
"max_acceleration", ramp.maxAcceleration},
337 {
"max_deceleration", ramp.maxDeceleration},
341 {
"acceleration_radius", std::min(ramp.maxAcceleration, ramp.maxDeceleration)},
342 {
"acceleration_polygon_sides", 32},
345 {
"acceleration_frame",
"body"},
346 {
"max_wheel_velocity", maxWheelVelocity},
350 nlohmann::json jGridPath = nlohmann::json::array();
354 nlohmann::json{{
"x", position.x()}, {
"y", position.y()}});
356 j[
"grid_path"] = jGridPath;
357 j[
"position_smoothing_applied"] = result->positionSmoothingApplied;
360 if (simulated.has_value())
366 nlohmann::json jSpans = nlohmann::json::array();
367 for (
const auto& [from, to] : rampCheck.
spans)
369 jSpans.push_back(nlohmann::json::array({from, to}));
372 j[
"velocity_profile_exceeds_command_ramp"] =
373 nlohmann::json{{
"violations", rampCheck.
violations},
377 {
"terminal_stopping_distance",
379 {
"terminal_velocity_exceeds_boundary",
384 if (not reference.is_null())
386 j[
"reparametrization_reference"] = reference;
389 std::ofstream ofs{filename};
392 ofs << j.dump(2) << std::endl;
const Grid & getGrid() const
const SceneBounds & getLocalSceneBounds() const noexcept
const Parameters & params() const noexcept
The maximum permissible linear velocity as a function of the distance to the closest obstacle.
float at(const Eigen::Vector2f &position) const
The limit at a position in the costmap's global frame.
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
This file is part of ArmarX.
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.
@ MecanumTorque
As OmniWheelTorque, but for a four-wheel mecanum drive.
@ OmniWheelVelocity
Bound each wheel's angular acceleration separately, so one saturating wheel also distorts the directi...
@ Cartesian
Bound the magnitude of the twist change. Direction of the change is preserved.
@ OmniWheelTorque
Bound each motor's torque and speed, using the robot's real inertia.
bool isfinite(const std::vector< T, Ts... > &v)
float cellSize
How big each cell is in the uniform grid.
bool obstacleDistanceCosts
float obstacleMaxDistance
For ARMAR-7 the following was tested:
float obstacleCostExponent
float obstacleDistanceWeight
A box obstacle in the ground plane, optionally rotated about its own centre.
float yaw
Rotation about the box centre [rad].
How far a velocity profile asks for more than the device command ramp can deliver.
bool terminalVelocityExceedsBoundary
Whether the profile ends above boundaryVelocity, i.e. faster than by design.
float worstDemand
Largest demanded tangential acceleration [mm/s^2], and where along the path it is.
float worstLimit
The bound that was exceeded there [mm/s^2].
std::vector< std::pair< float, float > > spans
Arc-length spans in which the demand exceeds the ramp, for the plot.
std::size_t violations
Waypoints demanding more than the ramp can deliver.
float terminalStoppingDistance
Distance the ramp needs to stop from the profile's final velocity [mm].
Everything the application needs, as read from the scene description file.
core::GeneralConfig generalConfig
global_planning::SPFAParams plannerParams
core::TrajectoryParametrization parametrization
How the velocities along the planned path are (re-)assigned before simulating.
float parametrizationTorqueFraction
Fraction of the motor torque the reparametrization may use.
simulation::TrajectoryFollowingSimulation::Parameters simulationParams
The synthetic scene: what the world looks like, independent of the planner.
algorithms::SceneBounds bounds
float cellSize
Edge length of a costmap cell [mm].
std::vector< Box > obstacles
core::TwistLimits maxVel
max velocity
algorithms::spfa::ShortestPathFasterAlgorithm::Parameters algo
bool enableFinalVelocityClamp
Re-apply the obstacle-aware velocity limit after orientation optimization.
bool enablePositionSmoothing
Diagnostic switches for the post-processing stages.
float maxWheelDeceleration
float maxWheelAcceleration
float motorMaxTorque
Torque bound per motor [N m]. Default is the 7.0 A MaxCurrent cap x 62.4 mNm/A.
float gearRatio
Motor revolutions per wheel revolution. 65536 counts/wheel-rev / 4096 counts/motor-rev.
PlatformDynamics dynamics
What the simulated mass can actually deliver.
CommandRateLimit rateLimit
The device-side command ramp between the controller and the platform.
float finalDistanceToGoal
Distance to the last trajectory point when the run ended [mm].
float maxTrackingError
Largest cross-track error over the run [mm].
Eigen::Matrix3d massMatrix
Full mass matrix at the Home configuration, [x, y, yaw].
float maxRequiredMotorTorque
Largest motor torque demanded over the run [N m]. OmniWheelTorque only.
float maxRequiredAngularAcceleration
Largest requiredAngularAcceleration over the run [rad/s^2].
std::size_t motorTorqueSaturatedCycles
Cycles in which a motor torque bound was binding. OmniWheelTorque only.
std::size_t wheelSpeedSaturatedCycles
Cycles in which a wheel speed bound was binding. OmniWheelTorque only.
float platformMass
Platform mass and yaw inertia from the robot model. OmniWheelTorque only.
float maxRequiredLinearAcceleration
Largest requiredLinearAcceleration over the run [mm/s^2].
float maxGoalOvershoot
Furthest the robot ever got past the last trajectory point [mm].
std::size_t saturatedCycles
Number of control cycles in which any limit was binding.
std::vector< Sample > samples
bool settledShortOfGoal
Set when the run ended because the robot stopped moving short of the goal.