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: Alessandro Tasora
13 // =============================================================================
14 //
15 // Demonstration of the conveyor belt primitive.
16 //
17 // =============================================================================
18
19 #include "chrono/physics/ChSystemNSC.h"
20 #include "chrono/physics/ChBodyEasy.h"
21 #include "chrono/physics/ChConveyor.h"
22
23 #include "chrono_irrlicht/ChIrrApp.h"
24
25 // Use the namespaces of Chrono
26 using namespace chrono;
27 using namespace chrono::collision;
28 using namespace chrono::irrlicht;
29
30 // Use the main namespaces of Irrlicht
31 using namespace irr;
32 using namespace irr::core;
33 using namespace irr::scene;
34 using namespace irr::video;
35 using namespace irr::io;
36 using namespace irr::gui;
37
38 // Static values valid through the entire program (bad
39 // programming practice, but enough for quick tests)
40
41 double STATIC_flow = 100;
42 double STATIC_speed = 2;
43 std::vector<std::shared_ptr<ChBody> > particlelist;
44
45 // Define a MyEventReceiver class which will be used to manage input
46 // from the GUI graphical user interface
47
48 class MyEventReceiver : public IEventReceiver {
49 public:
MyEventReceiver(ChIrrAppInterface * myapp)50 MyEventReceiver(ChIrrAppInterface* myapp) {
51 // store pointer application
52 application = myapp;
53
54 // ..add a GUI slider to control particles flow
55 scrollbar_flow = application->GetIGUIEnvironment()->addScrollBar(true, rect<s32>(510, 85, 650, 100), 0, 101);
56 scrollbar_flow->setMax(300);
57 scrollbar_flow->setPos(150);
58 text_flow = application->GetIGUIEnvironment()->addStaticText(L"Flow [particles/s]",
59 rect<s32>(650, 85, 750, 100), false);
60
61 // ..add GUI slider to control the speed
62 scrollbar_speed = application->GetIGUIEnvironment()->addScrollBar(true, rect<s32>(510, 125, 650, 140), 0, 102);
63 scrollbar_speed->setMax(100);
64 scrollbar_speed->setPos(100);
65 text_speed = application->GetIGUIEnvironment()->addStaticText(L"Conveyor speed [m/s]:",
66 rect<s32>(650, 125, 750, 140), false);
67 }
68
OnEvent(const SEvent & event)69 bool OnEvent(const SEvent& event) {
70 // check if user moved the sliders with mouse..
71 if (event.EventType == EET_GUI_EVENT) {
72 s32 id = event.GUIEvent.Caller->getID();
73
74 switch (event.GUIEvent.EventType) {
75 case EGET_SCROLL_BAR_CHANGED:
76 if (id == 101) // id of 'flow' slider..
77 {
78 s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
79 STATIC_flow = (double)pos;
80 }
81 if (id == 102) // id of 'speed' slider..
82 {
83 s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
84 STATIC_speed = (((double)pos) / 100) * 2;
85 }
86 break;
87 default:
88 break;
89 }
90 }
91
92 return false;
93 }
94
95 private:
96 ChIrrAppInterface* application;
97
98 IGUIScrollBar* scrollbar_flow;
99 IGUIStaticText* text_flow;
100 IGUIScrollBar* scrollbar_speed;
101 IGUIStaticText* text_speed;
102 };
103
104 // Function that creates debris that fall on the conveyor belt, to be called at each dt.
105 // In this example, all debris particles share the same contact material.
create_debris(ChIrrApp & application,double dt,double particles_second)106 void create_debris(ChIrrApp& application, double dt, double particles_second) {
107 double xnozzlesize = 0.2;
108 double znozzlesize = 0.56;
109 double ynozzle = 0.2;
110
111 double box_fraction = 0.3; // 30% cubes
112 double cyl_fraction = 0.4; // 40% cylinders
113
114 double sphrad = 0.013;
115
116 double exact_particles_dt = dt * particles_second;
117 double particles_dt = floor(exact_particles_dt);
118 double remaind = exact_particles_dt - particles_dt;
119 if (remaind > ChRandom())
120 particles_dt += 1;
121
122 auto sphere_mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
123 sphere_mat->SetFriction(0.2f);
124 sphere_mat->SetRestitution(0.8f);
125
126 auto box_mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
127 box_mat->SetFriction(0.4f);
128
129 auto cyl_mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
130 cyl_mat->SetFriction(0.2f);
131
132 for (int i = 0; i < particles_dt; i++) {
133 double rand_fract = ChRandom();
134
135 if (rand_fract < box_fraction) {
136 auto mrigidBody = chrono_types::make_shared<ChBodyEasySphere>(sphrad, // size
137 1000, // density
138 true, // visualization?
139 true, // collision?
140 sphere_mat); // contact material
141 mrigidBody->SetPos(ChVector<>(-0.5 * xnozzlesize + ChRandom() * xnozzlesize, ynozzle + i * 0.005,
142 -0.5 * znozzlesize + ChRandom() * znozzlesize));
143 mrigidBody->AddAsset(chrono_types::make_shared<ChTexture>(GetChronoDataFile("textures/bluewhite.png")));
144
145 application.GetSystem()->Add(mrigidBody);
146
147 // This will make particle's visualization assets visible in Irrlicht:
148 application.AssetBind(mrigidBody);
149 application.AssetUpdate(mrigidBody);
150
151 particlelist.push_back(mrigidBody);
152 }
153
154 if ((rand_fract > box_fraction) && (rand_fract < box_fraction + cyl_fraction)) {
155 double xscale = 1.3 * (1 - 0.4 * ChRandom()); // for oddly-shaped boxes..
156 double yscale = 1.3 * (1 - 0.4 * ChRandom());
157 double zscale = 1.3 * (1 - 0.4 * ChRandom());
158
159 auto mrigidBody =
160 chrono_types::make_shared<ChBodyEasyBox>(sphrad * 2 * xscale, sphrad * 2 * yscale, sphrad * 2 * zscale,
161 1000, // density
162 true, // visualization?
163 true, // collision?
164 box_mat); // contact material
165 mrigidBody->SetPos(ChVector<>(-0.5 * xnozzlesize + ChRandom() * xnozzlesize, ynozzle + i * 0.005,
166 -0.5 * znozzlesize + ChRandom() * znozzlesize));
167 mrigidBody->AddAsset(chrono_types::make_shared<ChTexture>(GetChronoDataFile("textures/cubetexture_bluewhite.png")));
168
169 application.GetSystem()->Add(mrigidBody);
170
171 // This will make particle's visualization assets visible in Irrlicht:
172 application.AssetBind(mrigidBody);
173 application.AssetUpdate(mrigidBody);
174
175 particlelist.push_back(mrigidBody);
176 }
177
178 if (rand_fract > box_fraction + cyl_fraction) {
179 auto mrigidBody = chrono_types::make_shared<ChBodyEasyCylinder>(sphrad, sphrad * 2, // rad, height
180 1000, // density
181 true, // visualization?
182 true, // collision?
183 cyl_mat); // contact material
184 mrigidBody->SetPos(ChVector<>(-0.5 * xnozzlesize + ChRandom() * xnozzlesize, ynozzle + i * 0.005,
185 -0.5 * znozzlesize + ChRandom() * znozzlesize));
186 mrigidBody->AddAsset(chrono_types::make_shared<ChTexture>(GetChronoDataFile("textures/pinkwhite.png")));
187
188 application.GetSystem()->Add(mrigidBody);
189
190 // This will make particle's visualization assets visible in Irrlicht:
191 application.AssetBind(mrigidBody);
192 application.AssetUpdate(mrigidBody);
193
194 particlelist.push_back(mrigidBody);
195 }
196 }
197 }
198
199 // Function that deletes old debris (to avoid infinite creation that fills memory)
200
purge_debris(ChIrrAppInterface & application,int nmaxparticles=100)201 void purge_debris(ChIrrAppInterface& application, int nmaxparticles = 100) {
202 while (particlelist.size() > nmaxparticles) {
203 application.GetSystem()->Remove(particlelist[0]); // remove from physical simulation
204 particlelist.erase(particlelist.begin()); // remove also from our particle list (will also automatically delete
205 // object thank to shared pointer)
206 }
207 }
208
main(int argc,char * argv[])209 int main(int argc, char* argv[]) {
210 GetLog() << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";
211
212 // Create a ChronoENGINE physical system
213 ChSystemNSC mphysicalSystem;
214
215 // Create the Irrlicht visualization (open the Irrlicht device,
216 // bind a simple user interface, etc. etc.)
217 ChIrrApp application(&mphysicalSystem, L"Conveyor belt", core::dimension2d<u32>(800, 600));
218 application.AddTypicalLogo();
219 application.AddTypicalSky();
220 application.AddTypicalLights();
221 application.AddTypicalCamera(core::vector3df(1.5f, 0.4f, -1.0f), core::vector3df(0.5f, 0.0f, 0.0f));
222
223 // This is for GUI tweaking of system parameters..
224 MyEventReceiver receiver(&application);
225 // note how to add the custom event receiver to the default interface:
226 application.SetUserEventReceiver(&receiver);
227
228 // Set small collision envelopes for objects that will be created from now on..
229 ChCollisionModel::SetDefaultSuggestedEnvelope(0.002);
230 ChCollisionModel::SetDefaultSuggestedMargin(0.002);
231
232 // Create two conveyor fences
233 auto fence_mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
234 fence_mat->SetFriction(0.1f);
235
236 auto mfence1 = chrono_types::make_shared<ChBodyEasyBox>(2, 0.11, 0.04, 1000, true, true, fence_mat);
237 mphysicalSystem.Add(mfence1);
238 mfence1->SetPos(ChVector<>(0, 0, -0.325));
239 mfence1->SetBodyFixed(true);
240
241 auto mfence2 = chrono_types::make_shared<ChBodyEasyBox>(2, 0.11, 0.04, 1000, true, true, fence_mat);
242 mphysicalSystem.Add(mfence2);
243 mfence2->SetPos(ChVector<>(0, 0, 0.325));
244 mfence2->SetBodyFixed(true);
245
246 // Create the conveyor belt (this is a pure Chrono::Engine object,
247 // because an Irrlicht 'SceneNode' wrapper is not yet available, so it is invisible - no 3D preview)
248 auto conveyor_mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
249 conveyor_mat->SetFriction(0.35f);
250
251 auto mconveyor = chrono_types::make_shared<ChConveyor>(2, 0.05, 0.6);
252 mconveyor->SetBodyFixed(true);
253 mconveyor->SetMaterialSurface(conveyor_mat);
254 mconveyor->SetConveyorSpeed(STATIC_speed);
255 mconveyor->SetPos(ChVector<>(0, 0, 0));
256
257 mphysicalSystem.Add(mconveyor);
258
259 // Use this function for adding a ChIrrNodeAsset to all items.
260 // Otherwise use application.AssetBind(myitem); on a per-item basis.
261 application.AssetBindAll();
262
263 // Use this function for 'converting' assets into Irrlicht meshes
264 application.AssetUpdateAll();
265
266 //
267 // THE SOFT-REAL-TIME CYCLE
268 //
269
270 application.SetTimestep(0.005);
271
272 while (application.GetDevice()->run()) {
273 application.BeginScene(true, true, SColor(255, 140, 161, 192));
274
275 application.DrawAll();
276
277 application.DoStep();
278
279 if (!application.GetPaused()) {
280 // Continuosly create debris that fall on the conveyor belt
281 create_debris(application, application.GetTimestep(), STATIC_flow);
282
283 // Limit the max number of debris particles on the scene, deleting the oldest ones, for performance
284 purge_debris(application, 300);
285
286 // Maybe the user played with the slider and changed STATIC_speed...
287 mconveyor->SetConveyorSpeed(STATIC_speed);
288 }
289
290 application.EndScene();
291 }
292
293 return 0;
294 }
295