ugv_nav4d
ConfigLoader.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <string>
4#include <yaml-cpp/yaml.h>
5#include <ugv_nav4d/Planner.hpp>
6#include <traversability_generator3d/TraversabilityGenerator3d.hpp>
7#include <sbpl_spline_primitives/SbplSplineMotionPrimitives.hpp>
8
9namespace ugv_nav4d {
10
12public:
13 static bool loadConfig(
14 const std::string& configPath,
15 sbpl_spline_primitives::SplinePrimitivesConfig& splineConfig,
16 ugv_nav4d::Mobility& mobilityConfig,
17 traversability_generator3d::TraversabilityConfig& travConfig,
18 ugv_nav4d::PlannerConfig& plannerConfig)
19 {
20 try {
21 YAML::Node config = YAML::LoadFile(configPath);
22
23 YAML::Node params = config;
24 if (config["ugv_nav4d_ros2"] && config["ugv_nav4d_ros2"]["ros__parameters"]) {
25 params = config["ugv_nav4d_ros2"]["ros__parameters"];
26 }
27
28 // Load spline config
29 if (params["splineConfig"]) {
30 auto sc = params["splineConfig"];
31 splineConfig.gridSize = sc["gridSize"].as<double>(0.5);
32 splineConfig.numAngles = sc["numAngles"].as<unsigned>(16);
33 splineConfig.numEndAngles = sc["numEndAngles"].as<unsigned>(8);
34 splineConfig.destinationCircleRadius = sc["destinationCircleRadius"].as<double>(6);
35 splineConfig.cellSkipFactor = sc["cellSkipFactor"].as<double>(0.1);
36 splineConfig.generatePointTurnMotions = sc["generatePointTurnMotions"].as<bool>(true);
37 splineConfig.generateLateralMotions = sc["generateLateralMotions"].as<bool>(true);
38 splineConfig.generateBackwardMotions = sc["generateBackwardMotions"].as<bool>(true);
39 splineConfig.generateForwardMotions = sc["generateForwardMotions"].as<bool>(true);
40 splineConfig.splineOrder = sc["splineOrder"].as<unsigned>(4);
41 } else {
42 double res = params["grid_resolution"] ? params["grid_resolution"].as<double>(0.5) : (params["gridSize"] ? params["gridSize"].as<double>(0.5) : 0.5);
43 splineConfig.gridSize = res;
44 splineConfig.numAngles = params["numAngles"] ? params["numAngles"].as<unsigned>(16) : 16;
45 splineConfig.numEndAngles = params["numEndAngles"] ? params["numEndAngles"].as<unsigned>(8) : 8;
46 splineConfig.destinationCircleRadius = params["destinationCircleRadius"] ? params["destinationCircleRadius"].as<double>(6) : 6;
47 splineConfig.cellSkipFactor = params["cellSkipFactor"] ? params["cellSkipFactor"].as<double>(0.1) : 0.1;
48 splineConfig.generatePointTurnMotions = params["generatePointTurnMotions"] ? params["generatePointTurnMotions"].as<bool>(true) : true;
49 splineConfig.generateLateralMotions = params["generateLateralMotions"] ? params["generateLateralMotions"].as<bool>(true) : true;
50 splineConfig.generateBackwardMotions = params["generateBackwardMotions"] ? params["generateBackwardMotions"].as<bool>(true) : true;
51 splineConfig.generateForwardMotions = params["generateForwardMotions"] ? params["generateForwardMotions"].as<bool>(true) : true;
52 splineConfig.splineOrder = params["splineOrder"] ? params["splineOrder"].as<unsigned>(4) : 4;
53 }
54
55 // Load mobility config
56 if (params["mobilityConfig"]) {
57 auto mc = params["mobilityConfig"];
58 mobilityConfig.translationSpeed = mc["translationSpeed"].as<double>(0.5);
59 mobilityConfig.rotationSpeed = mc["rotationSpeed"].as<double>(0.5);
60 mobilityConfig.minTurningRadius = mc["minTurningRadius"].as<double>(1);
61 mobilityConfig.searchRadius = mc["searchRadius"].as<double>(0.0);
62 mobilityConfig.searchProgressSteps = mc["searchProgressSteps"].as<double>(0.1);
63 mobilityConfig.multiplierForward = mc["multiplierForward"].as<double>(1);
64 mobilityConfig.multiplierForwardTurn = mc["multiplierForwardTurn"].as<double>(2);
65 mobilityConfig.multiplierBackward = mc["multiplierBackward"].as<double>(2);
66 mobilityConfig.multiplierBackwardTurn = mc["multiplierBackwardTurn"].as<double>(3);
67 mobilityConfig.multiplierLateral = mc["multiplierLateral"].as<double>(4);
68 mobilityConfig.multiplierLateralCurve = mc["multiplierLateralCurve"].as<double>(4);
69 mobilityConfig.multiplierPointTurn = mc["multiplierPointTurn"].as<double>(3);
70 mobilityConfig.maxMotionCurveLength = mc["maxMotionCurveLength"].as<double>(100);
71 mobilityConfig.spline_sampling_resolution = mc["spline_sampling_resolution"].as<double>(0.05);
72 mobilityConfig.remove_goal_offset = mc["remove_goal_offset"].as<bool>(false);
73 mobilityConfig.curvaturePenaltyWeight = mc["curvaturePenaltyWeight"] ? mc["curvaturePenaltyWeight"].as<double>(0.0) : 0.0;
74 mobilityConfig.angularCostWeight = mc["angularCostWeight"] ? mc["angularCostWeight"].as<double>(1.0) : 1.0;
75 } else {
76 mobilityConfig.translationSpeed = params["translationSpeed"] ? params["translationSpeed"].as<double>(0.5) : 0.5;
77 mobilityConfig.rotationSpeed = params["rotationSpeed"] ? params["rotationSpeed"].as<double>(0.5) : 0.5;
78 mobilityConfig.minTurningRadius = params["minTurningRadius"] ? params["minTurningRadius"].as<double>(1.0) : 1.0;
79 mobilityConfig.searchRadius = params["searchRadius"] ? params["searchRadius"].as<double>(0.0) : 0.0;
80 mobilityConfig.searchProgressSteps = params["searchProgressSteps"] ? params["searchProgressSteps"].as<double>(0.1) : 0.1;
81 mobilityConfig.multiplierForward = params["multiplierForward"] ? params["multiplierForward"].as<double>(1.0) : 1.0;
82 mobilityConfig.multiplierForwardTurn = params["multiplierForwardTurn"] ? params["multiplierForwardTurn"].as<double>(2.0) : 2.0;
83 mobilityConfig.multiplierBackward = params["multiplierBackward"] ? params["multiplierBackward"].as<double>(2.0) : 2.0;
84 mobilityConfig.multiplierBackwardTurn = params["multiplierBackwardTurn"] ? params["multiplierBackwardTurn"].as<double>(3.0) : 3.0;
85 mobilityConfig.multiplierLateral = params["multiplierLateral"] ? params["multiplierLateral"].as<double>(4.0) : 4.0;
86 mobilityConfig.multiplierLateralCurve = params["multiplierLateralCurve"] ? params["multiplierLateralCurve"].as<double>(4.0) : 4.0;
87 mobilityConfig.multiplierPointTurn = params["multiplierPointTurn"] ? params["multiplierPointTurn"].as<double>(3.0) : 3.0;
88 mobilityConfig.maxMotionCurveLength = params["maxMotionCurveLength"] ? params["maxMotionCurveLength"].as<double>(100.0) : 100.0;
89 mobilityConfig.spline_sampling_resolution = params["spline_sampling_resolution"] ? params["spline_sampling_resolution"].as<double>(0.05) : 0.05;
90 mobilityConfig.remove_goal_offset = params["remove_goal_offset"] ? params["remove_goal_offset"].as<bool>(false) : false;
91 mobilityConfig.curvaturePenaltyWeight = params["curvaturePenaltyWeight"] ? params["curvaturePenaltyWeight"].as<double>(0.0) : 0.0;
92 mobilityConfig.angularCostWeight = params["angularCostWeight"] ? params["angularCostWeight"].as<double>(1.0) : 1.0;
93 }
94
95 // Load traversability config
96 if (params["travConfig"]) {
97 auto tc = params["travConfig"];
98 travConfig.gridResolution = tc["gridResolution"].as<double>(0.3);
99 travConfig.maxSlope = tc["maxSlope"].as<double>(0.45);
100 travConfig.maxStepHeight = tc["maxStepHeight"].as<double>(0.25);
101 travConfig.robotSizeX = tc["robotSizeX"].as<double>(0.5);
102 travConfig.robotSizeY = tc["robotSizeY"].as<double>(0.5);
103 travConfig.footprintOffsetX = tc["footprintOffsetX"].as<double>(0.0);
104 travConfig.robotHeight = tc["robotHeight"].as<double>(0.5);
105 travConfig.slopeMetricScale = tc["slopeMetricScale"].as<double>(1.0);
106 travConfig.inclineLimittingMinSlope = tc["inclineLimittingMinSlope"].as<double>(0.22);
107 travConfig.inclineLimittingLimit = tc["inclineLimittingLimit"].as<double>(0.43);
108 travConfig.costFunctionDist = tc["costFunctionDist"].as<double>(0.0);
109 travConfig.distToGround = tc["distToGround"].as<double>(0.0);
110 travConfig.minTraversablePercentage = tc["minTraversablePercentage"].as<double>(0.5);
111 travConfig.allowForwardDownhill = tc["allowForwardDownhill"].as<bool>(true);
112 travConfig.enableInclineLimitting = tc["enableInclineLimitting"].as<bool>(false);
113 travConfig.articulatedSuspension = tc["articulatedSuspension"] ? tc["articulatedSuspension"].as<bool>(true) : true;
114 travConfig.obstacleInflationMultiplier = tc["obstacleInflationMultiplier"] ? tc["obstacleInflationMultiplier"].as<double>(1.0) : 1.0;
115 travConfig.partiallyTraversableMultiplier = tc["partiallyTraversableMultiplier"] ? tc["partiallyTraversableMultiplier"].as<double>(2.0) : 2.0;
116 travConfig.numYawSamples = tc["numYawSamples"] ? tc["numYawSamples"].as<int>(12) : 12;
117
118
119 std::string slopeMetricStr = tc["slopeMetric"].as<std::string>("NONE");
120 if (slopeMetricStr == "AVG_SLOPE") travConfig.slopeMetric = traversability_generator3d::SlopeMetric::AVG_SLOPE;
121 else if (slopeMetricStr == "MAX_SLOPE") travConfig.slopeMetric = traversability_generator3d::SlopeMetric::MAX_SLOPE;
122 else if (slopeMetricStr == "TRIANGLE_SLOPE") travConfig.slopeMetric = traversability_generator3d::SlopeMetric::TRIANGLE_SLOPE;
123 else travConfig.slopeMetric = traversability_generator3d::SlopeMetric::NONE;
124 } else {
125 travConfig.gridResolution = params["grid_resolution"] ? params["grid_resolution"].as<double>(0.3) : (params["gridResolution"] ? params["gridResolution"].as<double>(0.3) : 0.3);
126 travConfig.maxSlope = params["maxSlope"] ? params["maxSlope"].as<double>(0.45) : 0.45;
127 travConfig.maxStepHeight = params["maxStepHeight"] ? params["maxStepHeight"].as<double>(0.25) : 0.25;
128 travConfig.robotSizeX = params["robotSizeX"] ? params["robotSizeX"].as<double>(0.5) : 0.5;
129 travConfig.robotSizeY = params["robotSizeY"] ? params["robotSizeY"].as<double>(0.5) : 0.5;
130 travConfig.footprintOffsetX = params["footprintOffsetX"] ? params["footprintOffsetX"].as<double>(0.0) : 0.0;
131 travConfig.robotHeight = params["robotHeight"] ? params["robotHeight"].as<double>(0.5) : 0.5;
132 travConfig.slopeMetricScale = params["slopeMetricScale"] ? params["slopeMetricScale"].as<double>(1.0) : 1.0;
133 travConfig.inclineLimittingMinSlope = params["inclineLimittingMinSlope"] ? params["inclineLimittingMinSlope"].as<double>(0.22) : 0.22;
134 travConfig.inclineLimittingLimit = params["inclineLimittingLimit"] ? params["inclineLimittingLimit"].as<double>(0.43) : 0.43;
135 travConfig.costFunctionDist = params["costFunctionDist"] ? params["costFunctionDist"].as<double>(0.0) : 0.0;
136 travConfig.distToGround = params["distToGround"] ? params["distToGround"].as<double>(0.0) : 0.0;
137 travConfig.minTraversablePercentage = params["minTraversablePercentage"] ? params["minTraversablePercentage"].as<double>(0.5) : 0.5;
138 travConfig.allowForwardDownhill = params["allowForwardDownhill"] ? params["allowForwardDownhill"].as<bool>(true) : true;
139 travConfig.enableInclineLimitting = params["enableInclineLimitting"] ? params["enableInclineLimitting"].as<bool>(false) : false;
140 travConfig.articulatedSuspension = params["articulatedSuspension"] ? params["articulatedSuspension"].as<bool>(true) : true;
141 travConfig.obstacleInflationMultiplier = params["obstacleInflationMultiplier"] ? params["obstacleInflationMultiplier"].as<double>(1.0) : 1.0;
142 travConfig.partiallyTraversableMultiplier = params["partiallyTraversableMultiplier"] ? params["partiallyTraversableMultiplier"].as<double>(2.0) : 2.0;
143 travConfig.numYawSamples = params["numYawSamples"] ? params["numYawSamples"].as<int>(12) : 12;
144
145
146 std::string slopeMetricStr = "NONE";
147 if (params["slopeMetric"]) {
148 slopeMetricStr = params["slopeMetric"].as<std::string>("NONE");
149 if (slopeMetricStr.length() > 0 && slopeMetricStr[0] == ':') {
150 slopeMetricStr = slopeMetricStr.substr(1);
151 }
152 }
153 if (slopeMetricStr == "AVG_SLOPE") travConfig.slopeMetric = traversability_generator3d::SlopeMetric::AVG_SLOPE;
154 else if (slopeMetricStr == "MAX_SLOPE") travConfig.slopeMetric = traversability_generator3d::SlopeMetric::MAX_SLOPE;
155 else if (slopeMetricStr == "TRIANGLE_SLOPE") travConfig.slopeMetric = traversability_generator3d::SlopeMetric::TRIANGLE_SLOPE;
156 else travConfig.slopeMetric = traversability_generator3d::SlopeMetric::NONE;
157 }
158
159 // Load planner config
160 if (params["plannerConfig"]) {
161 auto pc = params["plannerConfig"];
162 plannerConfig.epsilonSteps = pc["epsilonSteps"].as<double>(2.0);
163 plannerConfig.initialEpsilon = pc["initialEpsilon"].as<double>(64.0);
164 plannerConfig.numThreads = pc["numThreads"].as<unsigned>(4);
165 plannerConfig.usePathStatistics = pc["usePathStatistics"].as<bool>(false);
166 plannerConfig.searchUntilFirstSolution = pc["searchUntilFirstSolution"].as<bool>(false);
167 plannerConfig.corridorWidth = pc["corridorWidth"].as<double>(-1.0);
168 plannerConfig.maxTime = pc["maxTime"] ? pc["maxTime"].as<double>(5.0) : 5.0;
169 plannerConfig.goalOrientationMargin = pc["goalOrientationMargin"] ? pc["goalOrientationMargin"].as<double>(0.0) : (pc["goal_orientation_margin"] ? pc["goal_orientation_margin"].as<double>(0.0) : 0.0);
170 plannerConfig.goalDistanceMargin = pc["goalDistanceMargin"] ? pc["goalDistanceMargin"].as<double>(0.0) : (pc["goal_distance_margin"] ? pc["goal_distance_margin"].as<double>(0.0) : 0.0);
171 plannerConfig.useReedsSheppFinalPath = pc["useReedsSheppFinalPath"] ? pc["useReedsSheppFinalPath"].as<bool>(false) : false;
172 plannerConfig.reedsSheppStepSize = pc["reedsSheppStepSize"] ? pc["reedsSheppStepSize"].as<double>(0.0) : 0.0;
173 plannerConfig.reedsSheppMaxShortcut = pc["reedsSheppMaxShortcut"] ? pc["reedsSheppMaxShortcut"].as<int>(0) : 0;
174 plannerConfig.useReedsSheppGoalShot = pc["useReedsSheppGoalShot"] ? pc["useReedsSheppGoalShot"].as<bool>(false) : false;
175 plannerConfig.reedsSheppGoalShotMaxDistance = pc["reedsSheppGoalShotMaxDistance"] ? pc["reedsSheppGoalShotMaxDistance"].as<double>(15.0) : 15.0;
176 plannerConfig.reedsSheppMaxCusps = pc["reedsSheppMaxCusps"] ? pc["reedsSheppMaxCusps"].as<int>(1) : 1;
177 } else {
178 plannerConfig.epsilonSteps = params["epsilonSteps"] ? params["epsilonSteps"].as<double>(2.0) : 2.0;
179 plannerConfig.initialEpsilon = params["initialEpsilon"] ? params["initialEpsilon"].as<double>(64.0) : 64.0;
180 plannerConfig.numThreads = params["numThreads"] ? params["numThreads"].as<unsigned>(4) : 4;
181 plannerConfig.usePathStatistics = params["usePathStatistics"] ? params["usePathStatistics"].as<bool>(false) : false;
182 plannerConfig.searchUntilFirstSolution = params["searchUntilFirstSolution"] ? params["searchUntilFirstSolution"].as<bool>(false) : false;
183 plannerConfig.corridorWidth = params["corridorWidth"] ? params["corridorWidth"].as<double>(-1.0) : -1.0;
184 plannerConfig.maxTime = params["maxTime"] ? params["maxTime"].as<double>(5.0) : 5.0;
185 plannerConfig.goalOrientationMargin = params["goalOrientationMargin"] ? params["goalOrientationMargin"].as<double>(0.0) : (params["goal_orientation_margin"] ? params["goal_orientation_margin"].as<double>(0.0) : 0.0);
186 plannerConfig.goalDistanceMargin = params["goalDistanceMargin"] ? params["goalDistanceMargin"].as<double>(0.0) : (params["goal_distance_margin"] ? params["goal_distance_margin"].as<double>(0.0) : 0.0);
187 plannerConfig.useReedsSheppFinalPath = params["useReedsSheppFinalPath"] ? params["useReedsSheppFinalPath"].as<bool>(false) : false;
188 plannerConfig.reedsSheppStepSize = params["reedsSheppStepSize"] ? params["reedsSheppStepSize"].as<double>(0.0) : 0.0;
189 plannerConfig.reedsSheppMaxShortcut = params["reedsSheppMaxShortcut"] ? params["reedsSheppMaxShortcut"].as<int>(0) : 0;
190 plannerConfig.useReedsSheppGoalShot = params["useReedsSheppGoalShot"] ? params["useReedsSheppGoalShot"].as<bool>(false) : false;
191 plannerConfig.reedsSheppGoalShotMaxDistance = params["reedsSheppGoalShotMaxDistance"] ? params["reedsSheppGoalShotMaxDistance"].as<double>(15.0) : 15.0;
192 plannerConfig.reedsSheppMaxCusps = params["reedsSheppMaxCusps"] ? params["reedsSheppMaxCusps"].as<int>(1) : 1;
193 }
194
195 // One thread knob: travgen's expansion uses the planner's thread count
196 // (travConfig.numThreads = 0 would mean "do not parallelize").
197 travConfig.numThreads = static_cast<int>(plannerConfig.numThreads);
198
199 // Validate values that crash or silently corrupt downstream:
200 // numAngles == 0 is an integer division by zero (SIGFPE) in
201 // DiscreteTheta; non-positive resolution/speeds poison costs.
202 if (splineConfig.numAngles < 1 || splineConfig.numEndAngles < 1)
203 {
204 LOG_ERROR_S << "Config error: numAngles/numEndAngles must be >= 1 (got "
205 << splineConfig.numAngles << "/" << splineConfig.numEndAngles << ").";
206 return false;
207 }
208 if (splineConfig.gridSize <= 0.0 || travConfig.gridResolution <= 0.0)
209 {
210 LOG_ERROR_S << "Config error: grid resolution must be > 0.";
211 return false;
212 }
213 if (mobilityConfig.translationSpeed <= 0.0 || mobilityConfig.rotationSpeed <= 0.0)
214 {
215 LOG_ERROR_S << "Config error: translationSpeed/rotationSpeed must be > 0 (got "
216 << mobilityConfig.translationSpeed << "/" << mobilityConfig.rotationSpeed << ").";
217 return false;
218 }
219
220 return true;
221 } catch (const std::exception& e) {
222 LOG_ERROR_S << "Failed to load config: " << e.what();
223 return false;
224 }
225 }
226};
227
228}
Definition ConfigLoader.hpp:11
static bool loadConfig(const std::string &configPath, sbpl_spline_primitives::SplinePrimitivesConfig &splineConfig, ugv_nav4d::Mobility &mobilityConfig, traversability_generator3d::TraversabilityConfig &travConfig, ugv_nav4d::PlannerConfig &plannerConfig)
Definition ConfigLoader.hpp:13
Definition ConfigLoader.hpp:9
Definition Mobility.hpp:12
double curvaturePenaltyWeight
Definition Mobility.hpp:43
unsigned int multiplierPointTurn
Definition Mobility.hpp:32
double minTurningRadius
Definition Mobility.hpp:19
unsigned int multiplierForwardTurn
Definition Mobility.hpp:30
unsigned int multiplierLateral
Definition Mobility.hpp:29
double spline_sampling_resolution
Definition Mobility.hpp:21
unsigned int multiplierBackwardTurn
Definition Mobility.hpp:31
double angularCostWeight
Definition Mobility.hpp:46
unsigned int multiplierBackward
Definition Mobility.hpp:28
double searchRadius
Definition Mobility.hpp:36
double translationSpeed
Definition Mobility.hpp:14
unsigned int multiplierForward
Definition Mobility.hpp:27
double rotationSpeed
Definition Mobility.hpp:16
double searchProgressSteps
Definition Mobility.hpp:38
double maxMotionCurveLength
Definition Mobility.hpp:40
bool remove_goal_offset
Definition Mobility.hpp:23
unsigned int multiplierLateralCurve
Definition Mobility.hpp:33
Definition PlannerConfig.hpp:8
double epsilonSteps
Definition PlannerConfig.hpp:20
double goalDistanceMargin
Definition PlannerConfig.hpp:35
double reedsSheppStepSize
Definition PlannerConfig.hpp:43
bool useReedsSheppGoalShot
Definition PlannerConfig.hpp:52
double corridorWidth
Definition PlannerConfig.hpp:25
double goalOrientationMargin
Definition PlannerConfig.hpp:31
double initialEpsilon
Definition PlannerConfig.hpp:17
int reedsSheppMaxShortcut
Definition PlannerConfig.hpp:46
double maxTime
Definition PlannerConfig.hpp:27
double reedsSheppGoalShotMaxDistance
Definition PlannerConfig.hpp:55
bool usePathStatistics
Definition PlannerConfig.hpp:11
bool useReedsSheppFinalPath
Definition PlannerConfig.hpp:40
unsigned numThreads
Definition PlannerConfig.hpp:22
int reedsSheppMaxCusps
Definition PlannerConfig.hpp:62
bool searchUntilFirstSolution
Definition PlannerConfig.hpp:14