Tutorial: demo_pendulum.cpp
Create some swinging pendulums, anchored to sliding joints. They move when the fan pushes some air toward them.
This tutorial shows how to:
- create a pendulum
- apply custom forces using 'force accumulators' (the simplified aereodinamic drag, in this case)
- create constraints with upper-lower limits (the horizontal sliding joints between pendula and truss)
#include "physics/CHapidll.h" #include "physics/CHsystem.h" #include "irrlicht_interface/CHbodySceneNode.h" #include "irrlicht_interface/CHbodySceneNodeTools.h" #include "irrlicht_interface/CHdisplayTools.h" #include "irrlicht_interface/CHirrWizard.h" #include "core/CHtimer.h" #include "core/CHrealtimeStep.h" #include <irrlicht.h> // Use the namespace of Chrono using namespace chrono; // Use the main namespaces of Irrlicht using namespace irr; using namespace core; using namespace scene; using namespace video; using namespace io; using namespace gui;The following function will be used to apply forces caused by a rotating fan, to all objects in front of it (a simple example just to demonstrate how to apply custom forces: the aereodynamical drag is a very simplified model).
void apply_fan_force ( ChSystem* msystem, // contains all bodies ChCoordsys<>& fan_csys, // pos and rotation of fan double aradius, // radius of fan double aspeed, // speed of fan double adensity) // density (heuristic) { for (unsigned int i=0; i<msystem->Get_bodylist()->size(); i++) { ChBody* abody = (*msystem->Get_bodylist())[i]; // Remember to reset 'user forces accumulators': abody->Empty_forces_accumulators(); // initialize speed of air (steady, if outside fan stream): ChVector<> abs_wind(0,0,0); // calculate the position of body COG in fan coordinates: ChVector<> mrelpos = fan_csys.TrasformParentToLocal(abody->GetPos()); ChVector<> mrelpos_ondisc = mrelpos; mrelpos_ondisc.z=0; if (mrelpos.z >0) // if not behind fan.. if (mrelpos_ondisc.Length() < aradius) { //OK! we are inside wind stream cylinder.. // wind is directed as normal to the fan disc abs_wind = fan_csys.TrasformLocalToParent(ChVector<>(0,0,1)); // wind inside fan stream is constant speed abs_wind *= -aspeed; } // force proportional to relative speed body-wind // and fluid density (NOTE! pretty simplified physics..) ChVector<> abs_force = ( abs_wind - abody->GetPos_dt() ) * adensity; // apply this force at the body COG abody->Accumulate_force(abs_force, abody->GetPos(), false); } }The following is the main function, where - as usual - the Irrlicht device is created, the Chrono::Engine globals are initialized, and the real-time simulation loop is performed. See the previous tutorials for more explainations.
int main(int argc, char* argv[]) { // In CHRONO engine, The DLL_CreateGlobals() - DLL_DeleteGlobals(); pair is needed if // global functions are needed. ChGlobals* GLOBAL_Vars = DLL_CreateGlobals(); // Create the IRRLICHT context (device, etc.) IrrlichtDevice* device = createDevice(video::EDT_DIRECT3D9, core::dimension2d<s32>(640, 480)); if (device == 0) { GetLog() << "Cannot use DirectX - switch to OpenGL \n"; device = createDevice(video::EDT_OPENGL, core::dimension2d<s32>(640, 480)); if (!device) return 1; } device->setWindowCaption(L"Example of integration of Chrono::Engine and Irrlicht"); IVideoDriver* driver = device->getVideoDriver(); ISceneManager* msceneManager = device->getSceneManager(); IGUIEnvironment* guienv = device->getGUIEnvironment(); timer = device->getTimer(); // timer declared in CHbodySceneNode.h // Easy shortcuts to add logo, camera, lights and sky in Irrlicht scene: ChIrrWizard::add_typical_Logo(device); ChIrrWizard::add_typical_Sky(device); ChIrrWizard::add_typical_Lights(device); ChIrrWizard::add_typical_Camera(device, core::vector3df(0,14,-20)); // create text with info IGUIStaticText* textFPS = guienv->addStaticText(L"FPS", rect<s32>(10,80,120,220), true); // // HERE YOU CREATE THE MECHANICAL SYSTEM OF CHRONO... // // Create a ChronoENGINE physical system! ChSystem my_system; // // Create all the rigid bodies!!!! // // ..create the five pendulums (bodies are Irrlicht nodes of // the special class ChBodySceneNode, which encapsulate ChBody items ): for (int k=0;k<5; k++) { double z_step =(double)k*2.; // .. the truss ChBodySceneNode* mrigidBody0 = (ChBodySceneNode*)addChBodySceneNode_easyBox( &my_system, msceneManager, 1.0, ChVector<>(0,0,z_step), ChQuaternion<>(1,0,0,0), ChVector<>(5,1,0.5) ); mrigidBody0->GetBody()->SetBodyFixed(true); // the truss does not move! mrigidBody0->GetBody()->SetCollide(false); ChBodySceneNode* mrigidBody1 = (ChBodySceneNode*)addChBodySceneNode_easyBox( &my_system, msceneManager, 1.0, ChVector<>(0,-3,z_step), ChQuaternion<>(1,0,0,0), ChVector<>(1,6,1) ); mrigidBody1->GetBody()->SetCollide(false); ChBodySceneNode* mrigidBody2 = (ChBodySceneNode*)addChBodySceneNode_easyBox( &my_system, msceneManager, 1.0, ChVector<>(3,-6,z_step), ChQuaternion<>(1,0,0,0), ChVector<>(6,1,1) ); mrigidBody2->GetBody()->SetCollide(false); ChBodySceneNode* mrigidBody3 = (ChBodySceneNode*)addChBodySceneNode_easyBox( &my_system, msceneManager, 1.0, ChVector<>(6,-9,z_step), ChQuaternion<>(1,0,0,0), ChVector<>(1,6,1) ); mrigidBody3->GetBody()->SetCollide(false); // // Create the links between bodies!!!! // // .. a joint of type 'point on a line', with upper and lower limits on // the X sliding direction, for the pendulum-ground constraint. ChSharedPtr<ChLinkLockPointLine> my_link_01(new ChLinkLockPointLine); my_link_01->Initialize(mrigidBody1->GetBody(), mrigidBody0->GetBody(), ChCoordsys<>(ChVector<>(0,0,z_step))); my_link_01->GetLimit_X()->Set_active(true); my_link_01->GetLimit_X()->Set_max( 1.0); my_link_01->GetLimit_X()->Set_min(-1.0); my_system.AddLink(my_link_01); // .. a spherical joint ChSharedPtr<ChLinkLockSpherical> my_link_12(new ChLinkLockSpherical); my_link_12->Initialize(mrigidBody2->GetBody(), mrigidBody1->GetBody(), ChCoordsys<>(ChVector<>(0,-6,z_step))); my_system.AddLink(my_link_12); // .. a spherical joint ChSharedPtr<ChLinkLockSpherical> my_link_23(new ChLinkLockSpherical); my_link_23->Initialize(mrigidBody3->GetBody(), mrigidBody2->GetBody(), ChCoordsys<>(ChVector<>(6,-6,z_step))); my_system.AddLink(my_link_23); } // // THE SOFT-REAL-TIME CYCLE // // create a 'fan ventilator' object, using Irrlicht mesh // loading and handling (this object is here for aesthetical reasons, // it is NOT handled by Chrono::Engine). double fan_radius = 5.3; IAnimatedMesh* fanMesh = msceneManager->getMesh("../data/fan2.obj"); IAnimatedMeshSceneNode* fanNode = msceneManager->addAnimatedMeshSceneNode (fanMesh); fanNode->setScale(irr::core::vector3df((irr::f32)fan_radius,(irr::f32)fan_radius,(irr::f32)fan_radius)); // This will help choosing an integration step which matches the // real-time step of the simulation.. ChRealtimeStepTimer m_realtime_timer; while(device->run()) { // Irrlicht must prepare frame to draw driver->beginScene(true, true, SColor(255,140,161,192)); // Irrlicht draws all 3D objects and all GUI items msceneManager->drawAll(); guienv->drawAll(); // draw a grid on the horizontal XZ plane ChIrrTools::drawGrid(driver, 2, 2, 20,20, ChCoordsys<>(ChVector<>(0,-20,0), Q_from_AngX(CH_C_PI_2) ), video::SColor(255, 80,100,100), true); // Update the position of the spinning fan (an Irrlicht // node, which is here just for aesthetical reasons!) ChQuaternion<> my_fan_rotation; my_fan_rotation.Q_from_AngY(my_system.GetChTime()*-0.5); ChQuaternion<> my_fan_spin; my_fan_spin.Q_from_AngZ(my_system.GetChTime()*4); ChCoordsys<> my_fan_coord( ChVector<>(12, -6, 0), my_fan_rotation); ChFrame<> my_fan_framerotation(my_fan_coord); ChFrame<> my_fan_framespin(ChCoordsys<>(VNULL, my_fan_spin)); ChIrrTools::alignIrrlichtNodeToChronoCsys(fanNode, (my_fan_framespin >> my_fan_framerotation).GetCoord()); // Apply forces caused by fan & wind if Chrono rigid bodies are // in front of the fan, using a simple tutorial function (see above): apply_fan_force(&my_system, my_fan_coord, fan_radius, 2.2, 0.5); // HERE CHRONO INTEGRATION IS PERFORMED: THE // TIME OF THE SIMULATION ADVANCES FOR A SINGLE // STEP: (2x as fast as real-time - looks better:) my_system.DoStepDynamics( 2* m_realtime_timer.SuggestSimulationStep(0.01) ); driver->endScene(); } // This Irrlicht statement will safely delete all.. device->drop(); // Remember this at the end of the program, if you started // with DLL_CreateGlobals(); DLL_DeleteGlobals(); return 0; }that's all.