Pendulum example (demo_IRR_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)
// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Authors: Alessandro Tasora
// =============================================================================
//
// Demo code about
// - creating a pendulum
// - apply custom forces using accumulators
// - creating constraints with limits
// - 3D viewing with the Irrlicht library
//
// =============================================================================
#include "chrono/physics/ChSystemNSC.h"
#include "chrono/physics/ChBodyEasy.h"
#include "chrono/core/ChTimer.h"
#include "chrono/core/ChRealtimeStep.h"
#include "chrono_irrlicht/ChIrrApp.h"
// Use the namespaces of Chrono
using namespace chrono;
using namespace chrono::irrlicht;
// Use the main namespaces of Irrlicht
using namespace irr;
using namespace irr::core;
using namespace irr::scene;
using namespace irr::video;
using namespace irr::io;
using namespace irr::gui;
// This 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).
void apply_fan_force(ChSystemNSC* 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 (auto body : msystem->Get_bodylist()) {
// Remember to reset 'user forces accumulators':
body->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.TransformParentToLocal(body->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.TransformLocalToParent(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 - body->GetPos_dt()) * adensity;
// apply this force at the body COG
body->Accumulate_force(abs_force, body->GetPos(), false);
}
}
int main(int argc, char* argv[]) {
GetLog() << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";
// Create a ChronoENGINE physical system
ChSystemNSC my_system;
// Create the Irrlicht visualization (open the Irrlicht device,
// bind a simple user interface, etc. etc.)
ChIrrApp application(&my_system, L"A simple pendulum example", core::dimension2d<u32>(800, 600));
application.AddTypicalLogo();
application.AddTypicalSky();
application.AddTypicalLights();
application.AddTypicalCamera(core::vector3df(0, 14, -20));
//
// Create all the rigid bodies!!!!
//
// ..create the five pendulums
for (int k = 0; k < 5; k++) {
double z_step = (double)k * 2.;
// .. the truss
auto mrigidBody0 = chrono_types::make_shared<ChBodyEasyBox>(5, 1, 0.5, // x,y,z size
100, // density
true, // visualization?
false); // collision?
mrigidBody0->SetPos(ChVector<>(0, 0, z_step));
mrigidBody0->SetBodyFixed(true); // the truss does not move!
my_system.Add(mrigidBody0);
auto mrigidBody1 = chrono_types::make_shared<ChBodyEasyBox>(1, 6, 1, // x,y,z size
1, // density
true, // visualization?
false); // collision?
mrigidBody1->SetPos(ChVector<>(0, -3, z_step));
my_system.Add(mrigidBody1);
auto mrigidBody2 = chrono_types::make_shared<ChBodyEasyBox>(1, 6, 1, // x,y,z size
1, // density
true, // visualization?
false); // collision?
mrigidBody2->SetPos(ChVector<>(0, -9, z_step));
my_system.Add(mrigidBody2);
auto mrigidBody3 = chrono_types::make_shared<ChBodyEasyBox>(6, 1, 1, // x,y,z size
1, // density
true, // visualization?
false); // collision?
mrigidBody3->SetPos(ChVector<>(3, -12, z_step));
my_system.Add(mrigidBody3);
//
// 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.
auto my_link_01 = chrono_types::make_shared<ChLinkLockPointLine>();
my_link_01->Initialize(mrigidBody1, mrigidBody0, ChCoordsys<>(ChVector<>(0, 0, z_step)));
my_link_01->GetLimit_X().SetActive(true);
my_link_01->GetLimit_X().SetMax(1.0);
my_link_01->GetLimit_X().SetMin(-1.0);
my_system.AddLink(my_link_01);
// .. a spherical joint
auto my_link_12 = chrono_types::make_shared<ChLinkLockSpherical>();
my_link_12->Initialize(mrigidBody2, mrigidBody1, ChCoordsys<>(ChVector<>(0, -6, z_step)));
my_system.AddLink(my_link_12);
// .. a spherical joint
auto my_link_23 = chrono_types::make_shared<ChLinkLockSpherical>();
my_link_23->Initialize(mrigidBody3, mrigidBody2, ChCoordsys<>(ChVector<>(0, -12, 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)
double fan_radius = 5.3;
IAnimatedMesh* fanMesh = application.GetSceneManager()->getMesh(GetChronoDataFile("models/fan2.obj").c_str());
IAnimatedMeshSceneNode* fanNode = application.GetSceneManager()->addAnimatedMeshSceneNode(fanMesh);
fanNode->setScale(irr::core::vector3df((irr::f32)fan_radius, (irr::f32)fan_radius, (irr::f32)fan_radius));
// Use this function for adding a ChIrrNodeAsset to all items
// Otherwise use application.AssetBind(myitem); on a per-item basis.
application.AssetBindAll();
// Use this function for 'converting' assets into Irrlicht meshes
application.AssetUpdateAll();
application.SetTimestep(0.01);
application.SetTryRealtime(true);
//application.GetSystem()->SetSolverType(ChSolver::Type::BARZILAIBORWEIN); // if you need a more precise CCP solver..
while (application.GetDevice()->run()) {
// Irrlicht must prepare frame to draw
application.BeginScene(true, true, SColor(255, 140, 161, 192));
// Irrlicht application draws all 3D objects and all GUI items
application.DrawAll();
// Draw also a grid on the horizontal XZ plane
tools::drawGrid(application.GetVideoDriver(), 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));
ChCoordsys<> my_fan_coordsys = (my_fan_framespin >> my_fan_framerotation).GetCoord();
tools::alignIrrlichtNodeToChronoCsys(fanNode, my_fan_coordsys);
// 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, 5.2, 0.5);
// HERE CHRONO INTEGRATION IS PERFORMED: THE
// TIME OF THE SIMULATION ADVANCES FOR A SINGLE
// STEP:
application.DoStep();
application.EndScene();
}
return 0;
}
std::string GetChronoDataFile(const std::string &filename)
Obtain the complete path to the specified filename, given relative to the Chrono data directory (thre...
Definition: ChGlobal.cpp:95
void Add(std::shared_ptr< ChPhysicsItem > item)
Attach an arbitrary ChPhysicsItem (e.g.
Definition: ChSystem.cpp:170
COORDSYS:
Definition: ChCoordsys.h:38
ChLog & GetLog()
Global function to get the current ChLog object.
Definition: ChLog.cpp:39
void SetTimestep(double val)
Set/Get the time step for time integration.
Definition: ChIrrAppInterface.cpp:552
virtual void AddLink(std::shared_ptr< ChLinkBase > link)
Attach a link to the underlying assembly.
Definition: ChSystem.cpp:155
ChFrame: a class for coordinate systems in 3D space.
Definition: ChFrame.h:42
Class to add some GUI to Irrlicht+ChronoEngine applications.
Definition: ChIrrApp.h:29
virtual void EndScene()
Call this to end the scene draw at the end of each animation frame.
Definition: ChIrrAppInterface.cpp:627
void Q_from_AngY(Real angleY)
Set the quaternion from an angle of rotation about Y axis.
Definition: ChQuaternion.h:333
const std::vector< std::shared_ptr< ChBody > > & Get_bodylist() const
Get the list of bodies.
Definition: ChSystem.h:318
Definition of general purpose 3d vector variables, such as points in 3D.
Definition: ChVector.h:35
virtual void DoStep()
Call this function inside a loop such as.
Definition: ChIrrAppInterface.cpp:637
void Q_from_AngZ(Real angleZ)
Set the quaternion from an angle of rotation about Z axis.
Definition: ChQuaternion.h:336
ChVector< Real > TransformParentToLocal(const ChVector< Real > &parent) const
This function transforms a point from the parent coordinate system to a local coordinate system,...
Definition: ChCoordsys.h:249
Class defining quaternion objects, that is four-dimensional numbers, also known as Euler parameters.
Definition: ChQuaternion.h:45
virtual void BeginScene(bool backBuffer=true, bool zBuffer=true, irr::video::SColor color=irr::video::SColor(255, 0, 0, 0))
Call this to clean the canvas at the beginning of each animation frame.
Definition: ChIrrAppInterface.cpp:610
Main namespace for the Chrono package.
Definition: ChAsset.cpp:18
double GetChTime() const
Get the simulation time of this system.
Definition: ChSystem.h:230
virtual void DrawAll()
Call this function inside a loop such as.
Definition: ChIrrAppInterface.cpp:750
Class for a physical system in which contact is modeled using a non-smooth (complementarity-based) me...
Definition: ChSystemNSC.h:29
void SetTryRealtime(bool val)
If enabled, the function DoStep() will enforce soft real-time, by spinning in place until simulation ...
Definition: ChIrrAppInterface.h:98
void drawGrid(irr::video::IVideoDriver *driver, double ustep, double vstep, int nu, int nv, ChCoordsys<> mpos, irr::video::SColor mcol, bool use_Zbuffer)
Easy-to-use function to draw grids in 3D space, with given orientation, color and spacing.
Definition: ChIrrTools.cpp:693
ChVector< Real > TransformLocalToParent(const ChVector< Real > &local) const
This function transforms a point from the local coordinate system to the parent coordinate system.
Definition: ChCoordsys.h:241
Real Length() const
Compute the euclidean norm of the vector, that is its length or magnitude.
Definition: ChVector.h:817