Skip to content

Commit c5c97f2

Browse files
committed
Add demo illustrating the use of rigid and sCM terrain patches in the same environment
1 parent 59e3cb4 commit c5c97f2

File tree

6 files changed

+307
-0
lines changed

6 files changed

+307
-0
lines changed
40.1 KB
Binary file not shown.
5.05 KB
Binary file not shown.
40.1 KB
Binary file not shown.
5.05 KB
Binary file not shown.

src/demos/vehicle/terrain/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ if(CH_ENABLE_MODULE_IRRLICHT OR CH_ENABLE_MODULE_VSG)
1212
set(DEMOS ${DEMOS}
1313
demo_VEH_RigidTerrain_WheeledVehicle
1414
demo_VEH_RigidTerrain_MovingPatch
15+
demo_VEH_RigidSCMTerrain_MixedPatches
1516
demo_VEH_SCMTerrain_WheeledVehicle
1617
demo_VEH_SCMTerrain_RigidTire
1718
demo_VEH_SCMTerrain_TrackedVehicle
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
// =============================================================================
2+
// PROJECT CHRONO - http://projectchrono.org
3+
//
4+
// Copyright (c) 2025 projectchrono.org
5+
// All rights reserved.
6+
//
7+
// Use of this source code is governed by a BSD-style license that can be found
8+
// in the LICENSE file at the top level of the distribution and at
9+
// http://projectchrono.org/license-chrono.txt.
10+
//
11+
// =============================================================================
12+
// Authors: Harry Zhang, Radu Serban
13+
// =============================================================================
14+
//
15+
// Demonstration of using rigid terrain and SCM terrain patches in the same
16+
// environment.
17+
//
18+
// The vehicle reference frame has Z up, X towards the front of the vehicle, and
19+
// Y pointing to the left.
20+
//
21+
// =============================================================================
22+
23+
#include "chrono/utils/ChOpenMP.h"
24+
25+
#include "chrono_vehicle/ChVehicleModelData.h"
26+
#include "chrono_vehicle/driver/ChInteractiveDriver.h"
27+
#include "chrono_vehicle/terrain/RigidTerrain.h"
28+
#include "chrono_vehicle/terrain/SCMTerrain.h"
29+
30+
#include "chrono_models/vehicle/hmmwv/HMMWV.h"
31+
32+
#include "chrono/assets/ChVisualSystem.h"
33+
#ifdef CHRONO_IRRLICHT
34+
#include "chrono_vehicle/wheeled_vehicle/ChWheeledVehicleVisualSystemIrrlicht.h"
35+
using namespace chrono::irrlicht;
36+
#endif
37+
#ifdef CHRONO_VSG
38+
#include "chrono_vehicle/wheeled_vehicle/ChWheeledVehicleVisualSystemVSG.h"
39+
using namespace chrono::vsg3d;
40+
#endif
41+
42+
using namespace chrono;
43+
using namespace chrono::vehicle;
44+
using namespace chrono::vehicle::hmmwv;
45+
46+
// =============================================================================
47+
48+
// Patch types (RIGID or SCM)
49+
enum class PatchType { RIGID, SCM };
50+
PatchType patches[2] = {PatchType::SCM, PatchType::RIGID};
51+
52+
// Run-time visualization system (IRRLICHT or VSG)
53+
ChVisualSystem::Type vis_type = ChVisualSystem::Type::VSG;
54+
55+
// -----------------------------------------------------------------------------
56+
57+
// Frictional contact formulation.
58+
// Smooth contact (SMC) leads to stiffer problems, potentially requiring a smaller step size,
59+
// but the cost per time step of contact calculation is low.
60+
// Non-smooth contact (NSC) can use larger step sizes than SCM but has high cost per step.
61+
ChContactMethod contact_method = ChContactMethod::SMC;
62+
63+
// Integration step size.
64+
double step_size = 2e-3;
65+
66+
// Set number of OpenMP threads (settings for optimum performance are hardware-specific).
67+
// Here,
68+
// num_threads_eigen - affects SCM calculations
69+
// num_threads_collision - affects Bullet collision detection
70+
// See documentation for ChSystem::SetNumThreads for more details.
71+
int num_threads_chrono = std::min(8, ChOMP::GetNumProcs());
72+
int num_threads_collision = std::min(8, ChOMP::GetNumProcs());
73+
int num_threads_eigen = 1;
74+
75+
// High resolution height-map images (false: 64x64, true: 200x200).
76+
// A high resolution of the height-map images results in dense meshes for rigid terrain patches.
77+
// This can significantly impact performance of the rigid-rigid collision detection algorithm.
78+
bool high_res = false;
79+
80+
// Render frequency.
81+
double render_fps = 50;
82+
83+
// SCM terrain visualization options.
84+
bool render_wireframe = true; // render wireframe (flat otherwise)
85+
bool apply_texture = false; // add texture
86+
bool render_sinkage = true; // use false coloring for sinkage visualization
87+
88+
// =============================================================================
89+
90+
int main(int argc, char* argv[]) {
91+
std::cout << "Copyright (c) 2025 projectchrono.org\nChrono version: " << CHRONO_VERSION << std::endl;
92+
93+
// ------------------------
94+
// Create the HMMWV vehicle
95+
// ------------------------
96+
97+
HMMWV_Full hmmwv;
98+
hmmwv.SetContactMethod(contact_method);
99+
hmmwv.SetChassisFixed(false);
100+
hmmwv.SetInitPosition(ChCoordsys<>(ChVector3d(-5, 0, 0.5), QUNIT));
101+
hmmwv.SetEngineType(EngineModelType::SIMPLE);
102+
hmmwv.SetTransmissionType(TransmissionModelType::AUTOMATIC_SIMPLE_MAP);
103+
hmmwv.SetDriveType(DrivelineTypeWV::AWD);
104+
hmmwv.SetTireType(TireModelType::RIGID);
105+
hmmwv.SetTireStepSize(step_size);
106+
hmmwv.Initialize();
107+
108+
hmmwv.SetChassisVisualizationType(VisualizationType::NONE);
109+
hmmwv.SetSuspensionVisualizationType(VisualizationType::PRIMITIVES);
110+
hmmwv.SetSteeringVisualizationType(VisualizationType::PRIMITIVES);
111+
hmmwv.SetWheelVisualizationType(VisualizationType::MESH);
112+
hmmwv.SetTireVisualizationType(VisualizationType::MESH);
113+
114+
// Extract underlying Chrono system
115+
auto sys = hmmwv.GetSystem();
116+
117+
// Enable the Bullet collision system
118+
sys->SetCollisionSystemType(ChCollisionSystem::Type::BULLET);
119+
120+
// Set number of threads used for different Chrono algorithms
121+
sys->SetNumThreads(num_threads_chrono, num_threads_collision, num_threads_eigen);
122+
123+
// ----------------------
124+
// Create terrain patches
125+
// ----------------------
126+
127+
// Height-map image files
128+
auto hm_concave = high_res ? vehicle::GetDataFile("terrain/height_maps/concave200.bmp")
129+
: vehicle::GetDataFile("terrain/height_maps/concave64.bmp");
130+
auto hm_convex = high_res ? vehicle::GetDataFile("terrain/height_maps/convex200.bmp")
131+
: vehicle::GetDataFile("terrain/height_maps/convex64.bmp");
132+
133+
// Create rigid terrain contact material consistent with the current contact formulation
134+
ChContactMaterialData mat_data;
135+
mat_data.mu = 0.9f;
136+
mat_data.cr = 0.01f;
137+
mat_data.Y = 2e7f;
138+
auto mat = mat_data.CreateMaterial(contact_method);
139+
140+
// Create rigid terrain patches
141+
RigidTerrain rigid_terrain(sys);
142+
{
143+
// x: [-20 ... 0]
144+
auto patch = rigid_terrain.AddPatch(mat, ChCoordsys<>(ChVector3d(-10, 0, 0), QUNIT), 20, 10);
145+
patch->SetTexture(vehicle::GetDataFile("terrain/textures/concrete.jpg"), 10, 5);
146+
}
147+
if (patches[0] == PatchType::RIGID) {
148+
// x: [0 ... 10]
149+
auto patch0 = rigid_terrain.AddPatch(mat, ChCoordsys<>(ChVector3d(5, 0, -1), QUNIT), hm_concave, 10, 10, 0, 1);
150+
patch0->SetTexture(vehicle::GetDataFile("terrain/textures/concrete.jpg"), 5, 5);
151+
}
152+
if (patches[1] == PatchType::RIGID) {
153+
// x: [10 ... 20]
154+
auto patch1 = rigid_terrain.AddPatch(mat, ChCoordsys<>(ChVector3d(15, 0, 0), QUNIT), hm_convex, 10, 10, 0, 1);
155+
patch1->SetTexture(vehicle::GetDataFile("terrain/textures/concrete.jpg"), 5, 5);
156+
}
157+
{
158+
// x: [20 ... 40]
159+
auto patch = rigid_terrain.AddPatch(mat, ChCoordsys<>(ChVector3d(30, 0, 0), QUNIT), 20, 10);
160+
patch->SetTexture(vehicle::GetDataFile("terrain/textures/concrete.jpg"), 10, 5);
161+
}
162+
163+
rigid_terrain.Initialize();
164+
165+
// Create SCM terrain patches
166+
// Notes:
167+
// - make sure to define a bounding AABB for each SCM terrain patch;
168+
// this prevent the SCM grid from extending beyond those limits and interfering with the rigid terrain patches.
169+
// - define active domains for bodies interacting with the SCM terrain patches;
170+
// this minimizes the number of ray casts; for best performance, define an active domain for each tire.
171+
172+
ChAABB scm_patch_aabb(ChVector3d(-5, -5, -2), ChVector3d(5, 5, 2)); // AABB for an SCM patch
173+
ChVector3d hmmwv_tire_aabb_size(1.0, 0.6, 1.0); // dimensions of OOBB associated with a tire
174+
175+
if (patches[0] == PatchType::SCM) {
176+
// x: [0 ... 10]
177+
SCMTerrain scm0(sys);
178+
scm0.SetReferenceFrame(ChCoordsys<>(ChVector3d(5, 0, 0), QUNIT));
179+
scm0.SetBoundary(scm_patch_aabb);
180+
for (auto& axle : hmmwv.GetVehicle().GetAxles()) {
181+
scm0.AddActiveDomain(axle->m_wheels[0]->GetSpindle(), VNULL, hmmwv_tire_aabb_size);
182+
scm0.AddActiveDomain(axle->m_wheels[1]->GetSpindle(), VNULL, hmmwv_tire_aabb_size);
183+
}
184+
scm0.Initialize(hm_concave, 10, 10, -1, 0, 0.05);
185+
186+
scm0.GetMesh()->SetWireframe(render_wireframe);
187+
if (apply_texture)
188+
scm0.GetMesh()->SetTexture(vehicle::GetDataFile("terrain/textures/dirt.jpg"), 10, 10);
189+
if (render_sinkage)
190+
scm0.SetPlotType(vehicle::SCMTerrain::PLOT_SINKAGE, 0, 0.1);
191+
}
192+
if (patches[1] == PatchType::SCM) {
193+
// x: [10 ... 20]
194+
SCMTerrain scm1(sys);
195+
scm1.SetReferenceFrame(ChCoordsys<>(ChVector3d(15, 0, 0), QUNIT));
196+
scm1.SetBoundary(scm_patch_aabb);
197+
for (auto& axle : hmmwv.GetVehicle().GetAxles()) {
198+
scm1.AddActiveDomain(axle->m_wheels[0]->GetSpindle(), VNULL, hmmwv_tire_aabb_size);
199+
scm1.AddActiveDomain(axle->m_wheels[1]->GetSpindle(), VNULL, hmmwv_tire_aabb_size);
200+
}
201+
scm1.Initialize(hm_convex, 10, 10, 0, 1, 0.05);
202+
203+
scm1.GetMesh()->SetWireframe(render_wireframe);
204+
if (apply_texture)
205+
scm1.GetMesh()->SetTexture(vehicle::GetDataFile("terrain/textures/dirt.jpg"), 10, 10);
206+
if (render_sinkage)
207+
scm1.SetPlotType(vehicle::SCMTerrain::PLOT_SINKAGE, 0, 0.1);
208+
}
209+
210+
// ----------------------------
211+
// Create an interactive driver
212+
// ----------------------------
213+
214+
ChInteractiveDriver driver(hmmwv.GetVehicle());
215+
driver.SetSteeringDelta(1.0 / 50);
216+
driver.SetThrottleDelta(1.0 / 50);
217+
driver.SetBrakingDelta(3.0 / 50);
218+
driver.Initialize();
219+
220+
// -----------------------------
221+
// Create run-time visualization
222+
// -----------------------------
223+
224+
#ifndef CHRONO_IRRLICHT
225+
if (vis_type == ChVisualSystem::Type::IRRLICHT)
226+
vis_type = ChVisualSystem::Type::VSG;
227+
#endif
228+
#ifndef CHRONO_VSG
229+
if (vis_type == ChVisualSystem::Type::VSG)
230+
vis_type = ChVisualSystem::Type::IRRLICHT;
231+
#endif
232+
233+
std::shared_ptr<ChVehicleVisualSystem> vis;
234+
switch (vis_type) {
235+
case ChVisualSystem::Type::IRRLICHT: {
236+
#ifdef CHRONO_IRRLICHT
237+
// Create the vehicle Irrlicht interface
238+
auto vis_irr = chrono_types::make_shared<ChWheeledVehicleVisualSystemIrrlicht>();
239+
vis_irr->SetWindowTitle("Mixed Terrain Demo");
240+
vis_irr->SetChaseCamera(ChVector3d(0.0, 0.0, .75), 6.0, 0.75);
241+
vis_irr->Initialize();
242+
vis_irr->AddLightDirectional();
243+
vis_irr->AddSkyBox();
244+
vis_irr->AddLogo();
245+
vis_irr->AttachVehicle(&hmmwv.GetVehicle());
246+
vis_irr->AttachDriver(&driver);
247+
248+
vis = vis_irr;
249+
#endif
250+
break;
251+
}
252+
253+
default:
254+
case ChVisualSystem::Type::VSG: {
255+
#ifdef CHRONO_VSG
256+
// Create the vehicle VSG interface
257+
auto vis_vsg = chrono_types::make_shared<ChWheeledVehicleVisualSystemVSG>();
258+
vis_vsg->SetWindowTitle("Mixed Terrain Demo");
259+
vis_vsg->SetWindowSize(1280, 800);
260+
vis_vsg->SetChaseCamera(ChVector3d(0.0, 0.0, .75), 8.0, 0.75);
261+
vis_vsg->AttachVehicle(&hmmwv.GetVehicle());
262+
vis_vsg->AttachDriver(&driver);
263+
vis_vsg->AttachTerrain(&rigid_terrain);
264+
vis_vsg->SetLightDirection(1.5 * CH_PI_2, CH_PI_4);
265+
vis_vsg->EnableShadows();
266+
vis_vsg->EnableSkyBox();
267+
vis_vsg->Initialize();
268+
269+
vis = vis_vsg;
270+
#endif
271+
break;
272+
}
273+
}
274+
275+
// ---------------
276+
// Simulation loop
277+
// ---------------
278+
279+
int render_frame = 0;
280+
double time = 0;
281+
282+
while (vis->Run()) {
283+
if (time >= render_frame / render_fps) {
284+
vis->BeginScene();
285+
vis->Render();
286+
vis->EndScene();
287+
render_frame++;
288+
}
289+
290+
DriverInputs inputs = driver.GetInputs();
291+
292+
driver.Synchronize(time);
293+
rigid_terrain.Synchronize(time);
294+
hmmwv.Synchronize(time, inputs, rigid_terrain);
295+
vis->Synchronize(time, inputs);
296+
297+
driver.Advance(step_size);
298+
rigid_terrain.Advance(step_size);
299+
hmmwv.Advance(step_size);
300+
vis->Advance(step_size);
301+
302+
time += step_size;
303+
}
304+
305+
return 0;
306+
}

0 commit comments

Comments
 (0)