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{
92 {
"type",
"box"}, {
"min", toJson(obstacle.
min)}, {
"max", toJson(obstacle.
max)}});
95 return nlohmann::json{
97 nlohmann::json{{
"min", toJson(scene.
bounds.
min)},
100 {
"obstacles", jObstacles}};
108 nlohmann::json jGrid = nlohmann::json::array();
109 for (
int ix = 0; ix < grid.rows(); ix++)
111 std::vector<float> row(
static_cast<std::size_t
>(grid.cols()));
112 for (
int iy = 0; iy < grid.cols(); iy++)
114 row[
static_cast<std::size_t
>(iy)] = grid(ix, iy);
117 jGrid.push_back(row);
120 return nlohmann::json{
126 {
"rows", grid.rows()},
127 {
"cols", grid.cols()},
132 constexpr float violationTolerance = 1e-3F;
140 constexpr float violationToleranceAbsolute = 5.F;
146 nlohmann::json jPoints = nlohmann::json::array();
148 std::size_t violations = 0;
149 float maxViolation = 0.F;
153 const core::Position& position = point.waypoint.pose.translation();
154 const float permissible = limit.
at(Eigen::Vector2f{position.head<2>()});
155 const float excess = point.velocity - permissible;
157 if (excess > std::max(violationTolerance * permissible,
158 violationToleranceAbsolute))
161 maxViolation = std::max(maxViolation, excess);
164 jPoints.push_back(nlohmann::json{{
"x", position.x()},
166 {
"yaw", yawOf(point.waypoint.pose)},
167 {
"velocity", point.velocity},
168 {
"velocity_limit", permissible}});
171 return nlohmann::json{
176 {
"velocity_limit_violations", violations},
177 {
"max_velocity_limit_violation", maxViolation}};
184 nlohmann::json jSamples = nlohmann::json::array();
186 for (
const auto& sample : simulated.
samples)
188 const core::Position& position = sample.global_T_robot.translation();
191 nlohmann::json{{
"t", sample.time},
194 {
"yaw", yawOf(sample.global_T_robot)},
195 {
"speed", sample.speed},
196 {
"vx", sample.velocityGlobal.x()},
197 {
"vy", sample.velocityGlobal.y()},
198 {
"commanded_speed", sample.commandedVelocityGlobal.norm()},
199 {
"angular_velocity", sample.commandedAngular},
200 {
"required_linear_acceleration",
201 sample.requiredLinearAcceleration},
202 {
"linear_acceleration", sample.linearAcceleration},
203 {
"required_angular_acceleration",
204 sample.requiredAngularAcceleration},
205 {
"angular_acceleration", sample.angularAcceleration},
206 {
"acceleration_saturated", sample.accelerationSaturated},
207 {
"required_wheel_accelerations", toJson(sample.requiredWheelAccelerations)},
208 {
"wheel_velocities", toJson(sample.wheelVelocities)},
209 {
"wheel_saturated", toJsonFlags(sample.wheelSaturated)},
210 {
"required_motor_torques", toJson(sample.requiredMotorTorques)},
211 {
"applied_motor_torques", toJson(sample.appliedMotorTorques)},
212 {
"motor_saturated", toJsonFlags(sample.motorSaturated)},
213 {
"wheel_speed_saturated", toJsonFlags(sample.wheelSpeedSaturated)},
214 {
"drop_point_velocity", sample.dropPointVelocity},
215 {
"tracking_error", sample.trackingError},
216 {
"distance_to_goal", sample.distanceToGoal},
217 {
"orientation_error", sample.orientationError}});
220 const std::string modelName = [&]() -> std::string
222 switch (dynamics.
model)
225 return "omni_wheel_torque";
227 return "mecanum_torque";
229 return "omni_wheel_velocity";
237 return nlohmann::json{
238 {
"samples", jSamples},
264 {
"model", modelName},
277 const std::optional<global_planning::GlobalPlannerResult>& result,
279 const std::optional<simulation::TrajectoryFollowingSimulation::Result>& simulated,
280 const nlohmann::json& reference,
282 const double parametrizationSeconds)
285 {
"success", result.has_value()},
286 {
"scene", toJson(config.
scene)},
287 {
"start", toJson(config.
start)},
288 {
"goal", toJson(config.
goal)},
289 {
"costmap", toJson(costmap)},
299 {
"enable_final_velocity_clamp",
303 if (result.has_value())
305 j[
"trajectory"] = toJson(result->trajectory, limit);
306 j[
"timings"] = result->timings;
310 j[
"parametrization_seconds"] = parametrizationSeconds;
322 const float inputSpeedRpm =
323 std::min(drive.motorNominalSpeedRpm, drive.gearboxMaxInputSpeedRpm);
325 j[
"parametrization_limits"] = nlohmann::json{
328 {
"max_acceleration", ramp.maxAcceleration},
329 {
"max_deceleration", ramp.maxDeceleration},
333 {
"acceleration_radius", std::min(ramp.maxAcceleration, ramp.maxDeceleration)},
334 {
"acceleration_polygon_sides", 32},
337 {
"acceleration_frame",
"body"},
338 {
"max_wheel_velocity",
339 inputSpeedRpm / 60.F / drive.gearRatio * 2.F *
static_cast<float>(
M_PI)},
343 nlohmann::json jGridPath = nlohmann::json::array();
347 nlohmann::json{{
"x", position.x()}, {
"y", position.y()}});
349 j[
"grid_path"] = jGridPath;
350 j[
"position_smoothing_applied"] = result->positionSmoothingApplied;
353 if (simulated.has_value())
359 nlohmann::json jSpans = nlohmann::json::array();
360 for (
const auto& [from, to] : rampCheck.
spans)
362 jSpans.push_back(nlohmann::json::array({from, to}));
365 j[
"velocity_profile_exceeds_command_ramp"] =
366 nlohmann::json{{
"violations", rampCheck.
violations},
370 {
"terminal_stopping_distance",
372 {
"terminal_velocity_exceeds_boundary",
377 if (not reference.is_null())
379 j[
"reparametrization_reference"] = reference;
382 std::ofstream ofs{filename};
385 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.
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
An axis-aligned box obstacle in the ground plane.
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.