Skip to content

Commit cb912e6

Browse files
committed
extend perceptive demo node
1 parent ff736aa commit cb912e6

File tree

6 files changed

+105
-40
lines changed

6 files changed

+105
-40
lines changed

ocs2_anymal_loopshaping_mpc/config/rviz/demo_config.rviz

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Visualization Manager:
4141
Cell Size: 0.10000000149011612
4242
Class: rviz/Grid
4343
Color: 160; 160; 164
44-
Enabled: true
44+
Enabled: false
4545
Line Style:
4646
Line Width: 0.029999999329447746
4747
Value: Lines
@@ -54,7 +54,7 @@ Visualization Manager:
5454
Plane: XY
5555
Plane Cell Count: 100
5656
Reference Frame: world
57-
Value: true
57+
Value: false
5858
- Alpha: 1
5959
Class: rviz/RobotModel
6060
Collision Enabled: false
@@ -867,25 +867,25 @@ Visualization Manager:
867867
Views:
868868
Current:
869869
Class: rviz/ThirdPersonFollower
870-
Distance: 3.5496129989624023
870+
Distance: 5.270549297332764
871871
Enable Stereo Rendering:
872872
Stereo Eye Separation: 0.05999999865889549
873873
Stereo Focal Distance: 1
874874
Swap Stereo Eyes: false
875875
Value: false
876876
Field of View: 0.7853981852531433
877877
Focal Point:
878-
X: 0.8991929292678833
879-
Y: 0.35367560386657715
880-
Z: 5.960464477539063e-08
878+
X: 3.331205368041992
879+
Y: 1.1847355365753174
880+
Z: 0
881881
Focal Shape Fixed Size: true
882882
Focal Shape Size: 0.05000000074505806
883883
Invert Z Axis: false
884884
Name: Current View
885885
Near Clip Distance: 0.009999999776482582
886-
Pitch: 0.10979794710874557
886+
Pitch: 0.044797856360673904
887887
Target Frame: <Fixed Frame>
888-
Yaw: 1.8865485191345215
888+
Yaw: 1.556549310684204
889889
Saved:
890890
- Angle: 3.140000104904175
891891
Class: rviz/TopDownOrtho
727 Bytes
Loading
835 Bytes
Loading
1.02 KB
Loading

ocs2_anymal_loopshaping_mpc/launch/perceptive_mpc_demo.launch

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
<launch>
2-
<arg name="robot_name" default="camel" />
3-
<arg name="config_name" default="c_series" />
4-
<arg name="description_name" default="ocs2_anymal_description"/>
5-
<arg name="perception_parameter_file" default="$(find convex_plane_decomposition_ros)/config/parameters.yaml" />
2+
<arg name="robot_name" default="camel" />
3+
<arg name="config_name" default="c_series" />
4+
<arg name="description_name" default="ocs2_anymal_description"/>
5+
<arg name="perception_parameter_file" default="$(find convex_plane_decomposition_ros)/config/parameters.yaml" />
66

7-
<param name="config_name" value="$(arg config_name)"/>
7+
<param name="config_name" value="$(arg config_name)"/>
8+
9+
<param name="forward_velocity" value="0.5"/>
10+
<param name="terrain_name" value="step.png"/>
11+
<param name="terrain_scale" value="0.35"/>
12+
<param name="adaptReferenceToTerrain" value="true"/>
813

914
<!-- Load robot description -->
1015
<include file="$(find ocs2_anymal_models)/launch/load_urdf.launch">
11-
<arg name="robot_name" value="$(arg robot_name)"/>
12-
<arg name="description_name" value="$(arg description_name)"/>
16+
<arg name="robot_name" value="$(arg robot_name)"/>
17+
<arg name="description_name" value="$(arg description_name)"/>
1318
</include>
1419

1520
<!-- Launch rviz with specific configuration -->

ocs2_anymal_loopshaping_mpc/src/PerceptiveMpcDemo.cpp

Lines changed: 85 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -64,24 +64,28 @@ int main(int argc, char* argv[]) {
6464
const ocs2::vector_t initSystemState = anymalInterface->getInitialState().head(switched_model::STATE_DIM);
6565

6666
// ====== Scenario settings ========
67-
ocs2::scalar_t forwardVelocity{0.6};
68-
ocs2::scalar_t forwardDistance{8.0};
67+
ocs2::scalar_t forwardVelocity{0.0};
68+
nodeHandle.getParam("/forward_velocity", forwardVelocity);
69+
ocs2::scalar_t gaitDuration{0.8};
70+
ocs2::scalar_t forwardDistance{3.0};
6971

7072
ocs2::scalar_t initTime = 0.0;
71-
ocs2::scalar_t stanceTime = 1.5;
72-
ocs2::scalar_t finalTime = forwardDistance / forwardVelocity + stanceTime;
73+
ocs2::scalar_t stanceTime = 1.0;
74+
int numGaitCycles = std::ceil((forwardDistance / forwardVelocity) / gaitDuration);
75+
ocs2::scalar_t walkTime = numGaitCycles * gaitDuration;
76+
ocs2::scalar_t finalTime = walkTime + 2 * stanceTime;
7377
ocs2::scalar_t f_mpc = 100; // hz
7478

7579
// Load a map
7680
const std::string elevationLayer{"elevation"};
7781
const std::string frameId{"world"};
78-
std::string terrainFile = "gaps.png";
79-
double heightScale = 1.0;
82+
std::string terrainFile{""};
83+
nodeHandle.getParam("/terrain_name", terrainFile);
84+
double heightScale{1.0};
85+
nodeHandle.getParam("/terrain_scale", heightScale);
8086
auto gridMap = convex_plane_decomposition::loadGridmapFromImage(terrainFolder + "/" + terrainFile, elevationLayer, frameId,
8187
perceptionConfig.preprocessingParameters.resolution, heightScale);
82-
if (terrainFile == "gaps.png") {
83-
gridMap.get(elevationLayer).array() -= static_cast<float>(heightScale);
84-
}
88+
gridMap.get(elevationLayer).array() -= gridMap.atPosition(elevationLayer, {0., 0.});
8589

8690
// Gait
8791
using MN = switched_model::ModeNumber;
@@ -91,19 +95,26 @@ int main(int argc, char* argv[]) {
9195
stance.modeSequence = {MN::STANCE};
9296

9397
switched_model::Gait gait;
94-
gait.duration = 0.8;
95-
gait.eventPhases = {0.45, 0.5, 0.95};
96-
gait.modeSequence = {MN::LF_RH, MN::STANCE, MN::RF_LH, MN::STANCE};
98+
gait.duration = gaitDuration;
99+
gait.eventPhases = {0.5};
100+
gait.modeSequence = {MN::LF_RH, MN::RF_LH};
97101

98-
GaitSchedule::GaitSequence gaitSequence{stance, gait};
102+
GaitSchedule::GaitSequence gaitSequence{stance};
103+
for (int i = 0; i < numGaitCycles; ++i) {
104+
gaitSequence.push_back(gait);
105+
}
106+
gaitSequence.push_back(stance);
99107

100108
// Reference trajectory
109+
bool adaptReferenceToTerrain = true;
110+
nodeHandle.getParam("/adaptReferenceToTerrain", adaptReferenceToTerrain);
111+
101112
const double dtRef = 0.1;
102-
const BaseReferenceHorizon commandHorizon{dtRef, size_t((finalTime - stanceTime) / dtRef) + 1};
113+
const BaseReferenceHorizon commandHorizon{dtRef, size_t(walkTime / dtRef) + 1};
103114
BaseReferenceCommand command;
104115
command.baseHeight = getPositionInOrigin(getBasePose(initSystemState)).z();
105116
command.yawRate = 0.0;
106-
command.headingVelocity = 0.6;
117+
command.headingVelocity = forwardVelocity;
107118
command.lateralVelocity = 0.0;
108119

109120
// ====== Run the perception pipeline ========
@@ -128,11 +139,11 @@ int main(int argc, char* argv[]) {
128139
getOrientation(getBasePose(initSystemState))};
129140

130141
BaseReferenceTrajectory terrainAdaptedBaseReference;
131-
if (terrainFile == "gaps.png") {
132-
terrainAdaptedBaseReference = generateExtrapolatedBaseReference(commandHorizon, initialBaseState, command, TerrainPlane());
133-
} else {
142+
if (adaptReferenceToTerrain) {
134143
terrainAdaptedBaseReference = generateExtrapolatedBaseReference(commandHorizon, initialBaseState, command, planarTerrain.gridMap,
135144
nominalStanceWidthInHeading, nominalStanceWidthLateral);
145+
} else {
146+
terrainAdaptedBaseReference = generateExtrapolatedBaseReference(commandHorizon, initialBaseState, command, TerrainPlane());
136147
}
137148

138149
ocs2::TargetTrajectories targetTrajectories;
@@ -154,6 +165,12 @@ int main(int argc, char* argv[]) {
154165
targetTrajectories.stateTrajectory.push_back(std::move(costReference));
155166
targetTrajectories.inputTrajectory.push_back(vector_t::Zero(INPUT_DIM));
156167
}
168+
targetTrajectories.timeTrajectory.push_back(stanceTime + walkTime);
169+
targetTrajectories.timeTrajectory.push_back(finalTime);
170+
targetTrajectories.stateTrajectory.push_back(targetTrajectories.stateTrajectory.back());
171+
targetTrajectories.stateTrajectory.push_back(targetTrajectories.stateTrajectory.back());
172+
targetTrajectories.inputTrajectory.push_back(vector_t::Zero(INPUT_DIM));
173+
targetTrajectories.inputTrajectory.push_back(vector_t::Zero(INPUT_DIM));
157174

158175
// ====== Set the scenario to the correct interfaces ========
159176
auto referenceManager = anymalInterface->getQuadrupedInterface().getSwitchedModelModeScheduleManagerPtr();
@@ -171,20 +188,22 @@ int main(int argc, char* argv[]) {
171188
const auto mpcSettings = ocs2::mpc::loadSettings(taskFolder + configName + "/task.info");
172189

173190
std::unique_ptr<ocs2::MPC_BASE> mpcPtr;
191+
const auto sqpSettings = ocs2::multiple_shooting::loadSettings(taskFolder + configName + "/multiple_shooting.info");
174192
switch (anymalInterface->modelSettings().algorithm_) {
175193
case switched_model::Algorithm::DDP: {
176194
const auto ddpSettings = ocs2::ddp::loadSettings(taskFolder + configName + "/task.info");
177195
mpcPtr = getDdpMpc(*anymalInterface, mpcSettings, ddpSettings);
178196
break;
179197
}
180198
case switched_model::Algorithm::SQP: {
181-
const auto sqpSettings = ocs2::multiple_shooting::loadSettings(taskFolder + configName + "/multiple_shooting.info");
182199
mpcPtr = getSqpMpc(*anymalInterface, mpcSettings, sqpSettings);
183200
break;
184201
}
185202
}
186203
ocs2::MPC_MRT_Interface mpcInterface(*mpcPtr);
187204

205+
std::unique_ptr<ocs2::RolloutBase> rollout(anymalInterface->getRollout().clone());
206+
188207
// ====== Execute the scenario ========
189208
ocs2::SystemObservation observation;
190209
observation.time = initTime;
@@ -199,6 +218,7 @@ int main(int argc, char* argv[]) {
199218

200219
// run MPC till final time
201220
ocs2::PrimalSolution closedLoopSolution;
221+
std::vector<ocs2::PerformanceIndex> performances;
202222
while (observation.time < finalTime) {
203223
std::cout << "t: " << observation.time << "\n";
204224
try {
@@ -207,9 +227,13 @@ int main(int argc, char* argv[]) {
207227
mpcInterface.advanceMpc();
208228
mpcInterface.updatePolicy();
209229

210-
// Evaluate the optimized solution
230+
performances.push_back(mpcInterface.getPerformanceIndices());
231+
232+
// Evaluate the optimized solution - change to optimal controller
211233
ocs2::vector_t tmp;
212234
mpcInterface.evaluatePolicy(observation.time, observation.state, tmp, observation.input, observation.mode);
235+
observation.input = ocs2::LinearInterpolation::interpolate(observation.time, mpcInterface.getPolicy().timeTrajectory_,
236+
mpcInterface.getPolicy().inputTrajectory_);
213237

214238
closedLoopSolution.timeTrajectory_.push_back(observation.time);
215239
closedLoopSolution.stateTrajectory_.push_back(observation.state);
@@ -221,11 +245,17 @@ int main(int argc, char* argv[]) {
221245
closedLoopSolution.modeSchedule_.eventTimes.push_back(observation.time - 0.5 / f_mpc);
222246
}
223247

224-
// Forward stepping: use optimal state for the next observation:
225-
observation.time += 1.0 / f_mpc;
226-
size_t tmpMode;
227-
mpcInterface.evaluatePolicy(observation.time, ocs2::vector_t::Zero(switched_model_loopshaping::STATE_DIM), observation.state, tmp,
228-
tmpMode);
248+
// perform a rollout
249+
scalar_array_t timeTrajectory;
250+
size_array_t postEventIndicesStock;
251+
vector_array_t stateTrajectory, inputTrajectory;
252+
const scalar_t finalTime = observation.time + 1.0 / f_mpc;
253+
auto modeschedule = mpcInterface.getPolicy().modeSchedule_;
254+
rollout->run(observation.time, observation.state, finalTime, mpcInterface.getPolicy().controllerPtr_.get(), modeschedule,
255+
timeTrajectory, postEventIndicesStock, stateTrajectory, inputTrajectory);
256+
257+
observation.time = finalTime;
258+
observation.state = stateTrajectory.back();
229259
observation.input.setZero(switched_model_loopshaping::INPUT_DIM); // reset
230260
} catch (std::exception& e) {
231261
std::cout << "MPC failed\n";
@@ -236,6 +266,36 @@ int main(int argc, char* argv[]) {
236266
const auto closedLoopSystemSolution =
237267
ocs2::loopshapingToSystemPrimalSolution(closedLoopSolution, *anymalInterface->getLoopshapingDefinition());
238268

269+
// ====== Print result ==========
270+
const auto totalCost = std::accumulate(performances.cbegin(), performances.cend(), 0.0,
271+
[](double v, const ocs2::PerformanceIndex& p) { return v + p.cost; });
272+
const auto totalDynamics =
273+
std::accumulate(performances.cbegin(), performances.cend(), 0.0,
274+
[](double v, const ocs2::PerformanceIndex& p) { return v + std::sqrt(p.dynamicsViolationSSE); });
275+
const auto maxDynamics = std::sqrt(std::max_element(performances.cbegin(), performances.cend(),
276+
[](const ocs2::PerformanceIndex& lhs, const ocs2::PerformanceIndex& rhs) {
277+
return lhs.dynamicsViolationSSE < rhs.dynamicsViolationSSE;
278+
})
279+
->dynamicsViolationSSE);
280+
const auto totalEquality =
281+
std::accumulate(performances.cbegin(), performances.cend(), 0.0,
282+
[](double v, const ocs2::PerformanceIndex& p) { return v + std::sqrt(p.equalityConstraintsSSE); });
283+
const auto maxEquality = std::sqrt(std::max_element(performances.cbegin(), performances.cend(),
284+
[](const ocs2::PerformanceIndex& lhs, const ocs2::PerformanceIndex& rhs) {
285+
return lhs.equalityConstraintsSSE < rhs.equalityConstraintsSSE;
286+
})
287+
->equalityConstraintsSSE);
288+
289+
double achievedWalkTime = observation.time - stanceTime;
290+
std::cout << "Speed: " << forwardVelocity << "\n";
291+
std::cout << "Scale: " << heightScale << "\n";
292+
std::cout << "Completed: " << std::min(1.0, (achievedWalkTime / walkTime)) * 100.0 << "\n";
293+
std::cout << "average Cost: " << totalCost / performances.size() << "\n";
294+
std::cout << "average Dynamics constr: " << totalDynamics / performances.size() << "\n";
295+
std::cout << "max Dynamics constr: " << maxDynamics << "\n";
296+
std::cout << "average Equality constr: " << totalEquality / performances.size() << "\n";
297+
std::cout << "max Equality constr: " << maxEquality << "\n";
298+
239299
// ====== Visualize ==========
240300
QuadrupedVisualizer visualizer(anymalInterface->getKinematicModel(), anymalInterface->getJointNames(), anymalInterface->getBaseName(),
241301
nodeHandle);

0 commit comments

Comments
 (0)