1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2014 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: Hammad Mazhar
13 // =============================================================================
14 //
15 // Demo code about advanced contact feature: cohesion (using complementarity
16 // contact method)
17 //
18 // =============================================================================
19
20 #ifdef __EMSCRIPTEN__
21 #include <emscripten.h>
22 #endif
23
24 #include "chrono/physics/ChBodyEasy.h"
25 #include "chrono/physics/ChLinkMotorRotationSpeed.h"
26 #include "chrono/physics/ChSystemNSC.h"
27 #include "chrono_opengl/ChOpenGLWindow.h"
28
29 // Use the namespace of Chrono
30
31 using namespace chrono;
32 using namespace chrono::collision;
33
34 // Static values valid through the entire program (bad
35 // programming practice, but enough for quick tests)
36
37 float GLOBAL_friction = 0.3f;
38 float GLOBAL_cohesion = 0;
39 float GLOBAL_compliance = 0;
40 float GLOBAL_dampingf = 0.1f;
41
42 // Define a MyEventReceiver class which will be used to manage input
43 // from the GUI graphical user interface
44
create_some_falling_items(ChSystemNSC & mphysicalSystem)45 void create_some_falling_items(ChSystemNSC& mphysicalSystem) {
46 // From now on, all created collision models will have a large outward envelope (needed
47 // to allow some compliance with the plastic deformation of cohesive bounds
48 ChCollisionModel::SetDefaultSuggestedEnvelope(0.3);
49
50 // contact material shared by all falling objects
51 auto mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
52 mat->SetFriction(0.3f);
53
54 // Create falling bodies
55 for (int bi = 0; bi < 400; bi++) {
56 auto mrigidBody = chrono_types::make_shared<ChBodyEasySphere>(0.81, // radius
57 1000, // density
58 true, // visualization?
59 true, // collision?
60 mat); // contact material
61 mrigidBody->SetPos(ChVector<>(-5 + ChRandom() * 10, 4 + bi * 0.05, -5 + ChRandom() * 10));
62 mphysicalSystem.Add(mrigidBody);
63 }
64
65 // Create the five walls of the rectangular container, using fixed rigid bodies of 'box' type:
66
67 auto floor_mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
68
69 auto floorBody = chrono_types::make_shared<ChBodyEasyBox>(20, 1, 20, // x,y,z size
70 1000, // density
71 true, // visualization?
72 true, // collision?
73 floor_mat); // contact material
74 floorBody->SetPos(ChVector<>(0, -5, 0));
75 floorBody->SetBodyFixed(true);
76 mphysicalSystem.Add(floorBody);
77
78 auto wallBody1 = chrono_types::make_shared<ChBodyEasyBox>(1, 10, 20.99, // x,y,z size
79 1000, // density
80 true, // visualization?
81 true, // collision?
82 floor_mat); // contact material
83 wallBody1->SetPos(ChVector<>(-10, 0, 0));
84 wallBody1->SetBodyFixed(true);
85 mphysicalSystem.Add(wallBody1);
86
87 auto wallBody2 = chrono_types::make_shared<ChBodyEasyBox>(1, 10, 20.99, // x,y,z size
88 1000, // density
89 true, // visualization?
90 true, // collision?
91 floor_mat); // contact material
92 wallBody2->SetPos(ChVector<>(10, 0, 0));
93 wallBody2->SetBodyFixed(true);
94 mphysicalSystem.Add(wallBody2);
95
96 auto wallBody3 = chrono_types::make_shared<ChBodyEasyBox>(20.99, 10, 1, // x,y,z size
97 1000, // density
98 true, // visualization?
99 true, // collision?
100 floor_mat); // contact material
101 wallBody3->SetPos(ChVector<>(0, 0, -10));
102 wallBody3->SetBodyFixed(true);
103 mphysicalSystem.Add(wallBody3);
104
105 auto wallBody4 = chrono_types::make_shared<ChBodyEasyBox>(20.99, 10, 1, // x,y,z size
106 1000, // density
107 true, // visualization?
108 true, // collision?
109 floor_mat); // contact material
110 wallBody4->SetPos(ChVector<>(0, 0, 10));
111 wallBody4->SetBodyFixed(true);
112 mphysicalSystem.Add(wallBody4);
113
114 // Add the rotating mixer
115 auto mixer_mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
116 mixer_mat->SetFriction(0.4f);
117
118 auto rotatingBody = chrono_types::make_shared<ChBodyEasyBox>(10, 5, 1, // x,y,z size
119 4000, // density
120 true, // visualization?
121 true, // collision?
122 mixer_mat); // contact material
123 rotatingBody->SetPos(ChVector<>(0, -1.6, 0));
124 mphysicalSystem.Add(rotatingBody);
125
126 // .. a motor between mixer and truss
127 auto motor = chrono_types::make_shared<ChLinkMotorRotationSpeed>();
128 motor->Initialize(rotatingBody, floorBody, ChFrame<>(ChVector<>(0, 0, 0), Q_from_AngAxis(CH_C_PI_2, VECT_X)));
129 motor->SetSpeedFunction(chrono_types::make_shared<ChFunction_Const>(CH_C_PI / 2.0));
130 mphysicalSystem.AddLink(motor);
131 }
132
main(int argc,char * argv[])133 int main(int argc, char* argv[]) {
134 GetLog() << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";
135
136 // Create a Chrono physical system
137 ChSystemNSC mphysicalSystem;
138
139 // Create all the rigid bodies.
140
141 create_some_falling_items(mphysicalSystem);
142
143 // Modify some setting of the physical system for the simulation, if you want
144
145 mphysicalSystem.SetSolverType(ChSolver::Type::PSOR);
146 mphysicalSystem.SetSolverMaxIterations(20);
147
148 // Cohesion in a contact depends on the cohesion in the surface property of
149 // the touching bodies, but the user can override this value when each contact is created,
150 // by instancing a callback as in the following example:
151
152 class MyContactCallback : public ChContactContainer::AddContactCallback {
153 public:
154 virtual void OnAddContact(const collision::ChCollisionInfo& contactinfo,
155 ChMaterialComposite* const material) override {
156 // Downcast to appropriate composite material type
157 auto mat = static_cast<ChMaterialCompositeNSC* const>(material);
158
159 // Set friction according to user setting:
160 mat->static_friction = GLOBAL_friction;
161
162 // Set compliance (normal and tangential at once)
163 mat->compliance = GLOBAL_compliance;
164 mat->complianceT = GLOBAL_compliance;
165 mat->dampingf = GLOBAL_dampingf;
166
167 // Set cohesion according to user setting:
168 // Note that we must scale the cohesion force value by time step, because
169 // the material 'cohesion' value has the dimension of an impulse.
170 float my_cohesion_force = GLOBAL_cohesion;
171 mat->cohesion = (float)msystem->GetStep() * my_cohesion_force; //<- all contacts will have this cohesion!
172
173 if (contactinfo.distance > 0.12)
174 mat->cohesion = 0;
175
176 // Note that here you might decide to modify the cohesion
177 // depending on object sizes, type, time, position, etc. etc.
178 // For example, after some time disable cohesion at all, just
179 // add here:
180 // if (msystem->GetChTime() > 10) mat->cohesion = 0;
181 };
182 ChSystemNSC* msystem;
183 };
184
185 auto mycontact_callback = chrono_types::make_shared<MyContactCallback>(); // create the callback object
186 mycontact_callback->msystem = &mphysicalSystem; // will be used by callback
187
188 // Use the above callback to process each contact as it is created.
189 mphysicalSystem.GetContactContainer()->RegisterAddContactCallback(mycontact_callback);
190
191 //
192 // THE SOFT-REAL-TIME CYCLE
193 //
194
195 opengl::ChOpenGLWindow& gl_window = opengl::ChOpenGLWindow::getInstance();
196 gl_window.Initialize(1280, 720, "Demo_Cohesion_GL", &mphysicalSystem);
197 gl_window.SetCamera(ChVector<>(0, 0, -10), ChVector<>(0, 0, 0), ChVector<>(0, 1, 0));
198 gl_window.Pause();
199
200 std::function<void()> step_iter = [&]() {
201 if (gl_window.DoStepDynamics(0.01)) {
202 // Add code here that will only run after a step is taken
203 }
204 gl_window.Render();
205 };
206
207 #ifdef __EMSCRIPTEN__
208 emscripten_set_main_loop_arg(&opengl::ChOpenGLWindow::WrapRenderStep, (void*)&step_iter, 50, true);
209 #else
210 while (gl_window.Active()) {
211 step_iter();
212 }
213 #endif
214
215 return 0;
216 }
217