Pendulum example (demo_MBS_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/ChVisualSystemIrrlicht.h"
// Use the namespaces of Chrono
using namespace chrono;
using namespace chrono::irrlicht;
// 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->GetBodies()) {
// Remember to reset 'user forces accumulators':
body->EmptyAccumulators();
// initialize speed of air (steady, if outside fan stream):
ChVector3d abs_wind(0, 0, 0);
// calculate the position of body COG in fan coordinates:
ChVector3d mrelpos = fan_csys.TransformPointParentToLocal(body->GetPos());
ChVector3d 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.TransformPointLocalToParent(ChVector3d(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..)
ChVector3d abs_force = (abs_wind - body->GetPosDt()) * adensity;
// apply this force at the body COG
body->AccumulateForce(abs_force, body->GetPos(), false);
}
}
int main(int argc, char* argv[]) {
std::cout << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << std::endl;
// Create a ChronoENGINE physical system
// 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(ChVector3d(0, 0, z_step));
mrigidBody0->SetFixed(true); // the truss does not move!
sys.Add(mrigidBody0);
auto mrigidBody1 = chrono_types::make_shared<ChBodyEasyBox>(1, 6, 1, // x,y,z size
1, // density
true, // visualization?
false); // collision?
mrigidBody1->SetPos(ChVector3d(0, -3, z_step));
sys.Add(mrigidBody1);
auto mrigidBody2 = chrono_types::make_shared<ChBodyEasyBox>(1, 6, 1, // x,y,z size
1, // density
true, // visualization?
false); // collision?
mrigidBody2->SetPos(ChVector3d(0, -9, z_step));
sys.Add(mrigidBody2);
auto mrigidBody3 = chrono_types::make_shared<ChBodyEasyBox>(6, 1, 1, // x,y,z size
1, // density
true, // visualization?
false); // collision?
mrigidBody3->SetPos(ChVector3d(3, -12, z_step));
sys.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, ChFrame<>(ChVector3d(0, 0, z_step)));
my_link_01->LimitX().SetActive(true);
my_link_01->LimitX().SetMax(1.0);
my_link_01->LimitX().SetMin(-1.0);
sys.AddLink(my_link_01);
// .. a spherical joint
auto my_link_12 = chrono_types::make_shared<ChLinkLockSpherical>();
my_link_12->Initialize(mrigidBody2, mrigidBody1, ChFrame<>(ChVector3d(0, -6, z_step)));
sys.AddLink(my_link_12);
// .. a spherical joint
auto my_link_23 = chrono_types::make_shared<ChLinkLockSpherical>();
my_link_23->Initialize(mrigidBody3, mrigidBody2, ChFrame<>(ChVector3d(0, -12, z_step)));
sys.AddLink(my_link_23);
}
// Create the Irrlicht visualization system
auto vis = chrono_types::make_shared<ChVisualSystemIrrlicht>();
vis->AttachSystem(&sys);
vis->SetWindowSize(800, 600);
vis->SetWindowTitle("A simple pendulum example");
vis->Initialize();
vis->AddLogo();
vis->AddSkyBox();
vis->AddCamera(ChVector3d(0, 14, -20));
vis->AddTypicalLights();
// 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;
irr::scene::IAnimatedMesh* fanMesh = vis->GetSceneManager()->getMesh(GetChronoDataFile("models/fan2.obj").c_str());
irr::scene::IAnimatedMeshSceneNode* fanNode = vis->GetSceneManager()->addAnimatedMeshSceneNode(fanMesh);
fanNode->setScale(irr::core::vector3df((irr::f32)fan_radius, (irr::f32)fan_radius, (irr::f32)fan_radius));
// Simulation loop
double timestep = 0.01;
ChRealtimeStepTimer realtime_timer;
while (vis->Run()) {
vis->BeginScene();
vis->Render();
tools::drawGrid(vis.get(), 2, 2, 20, 20, ChCoordsys<>(ChVector3d(0, -20, 0), QuatFromAngleX(CH_PI_2)),
ChColor(0.3f, 0.5f, 0.5f), 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.SetFromAngleY(sys.GetChTime() * -0.5);
ChQuaternion<> my_fan_spin;
my_fan_spin.SetFromAngleZ(sys.GetChTime() * 4);
ChCoordsys<> my_fan_coord(ChVector3d(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).GetCoordsys();
tools::alignIrrlichtNode(fanNode, my_fan_coordsys);
vis->EndScene();
// 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(&sys, my_fan_coord, fan_radius, 5.2, 0.5);
sys.DoStepDynamics(timestep);
realtime_timer.Spin(timestep);
}
return 0;
}
std::string GetChronoDataFile(const std::string &filename)
Get the full path to the specified filename, given relative to the Chrono data directory (thread safe...
Definition: ChGlobal.cpp:37
ChQuaterniond QuatFromAngleX(double angle)
Convert from a rotation about X axis to a quaternion.
Definition: ChRotation.cpp:188
void Add(std::shared_ptr< ChPhysicsItem > item)
Attach an arbitrary ChPhysicsItem (e.g.
Definition: ChSystem.cpp:196
ChVector3< Real > TransformPointLocalToParent(const ChVector3< Real > &v) const
Transform a point from the local coordinate system to the parent coordinate system.
Definition: ChCoordsys.h:195
Representation of a transform with translation and rotation.
Definition: ChCoordsys.h:28
const std::vector< std::shared_ptr< ChBody > > & GetBodies() const
Get the list of bodies.
Definition: ChSystem.h:345
virtual void AddLink(std::shared_ptr< ChLinkBase > link)
Attach a link to the underlying assembly.
Definition: ChSystem.cpp:144
Representation of a 3D transform.
Definition: ChFrame.h:41
Namespace with classes for the Irrlicht module.
Definition: ChApiIrr.h:47
Class for a timer which attempts to enforce soft real-time.
Definition: ChRealtimeStep.h:25
Real Length() const
Compute the euclidean norm of the vector, that is its length or magnitude.
Definition: ChVector3.h:847
void Spin(double step)
Call this function INSIDE the simulation loop, just ONCE per loop (preferably as the last call in the...
Definition: ChRealtimeStep.h:34
void SetFromAngleY(Real angleY)
Set the quaternion from an angle of rotation about Y axis.
Definition: ChQuaternion.h:320
void SetFromAngleZ(Real angleZ)
Set the quaternion from an angle of rotation about Z axis.
Definition: ChQuaternion.h:323
Definition of a visual color.
Definition: ChColor.h:30
void drawGrid(ChVisualSystemIrrlicht *vis, double ustep, double vstep, int nu, int nv, ChCoordsys<> pos, chrono::ChColor col, bool use_Zbuffer)
Draw grids in 3D space with given orientation, color, and spacing.
Definition: ChIrrTools.cpp:873
int DoStepDynamics(double step_size)
Advance the dynamics simulation by a single time step of given length.
Definition: ChSystem.cpp:1632
ChVector3< Real > TransformPointParentToLocal(const ChVector3< Real > &v) const
Transforms a point from the parent coordinate system to local coordinate system.
Definition: ChCoordsys.h:198
ChVector3< double > ChVector3d
Alias for double-precision vectors.
Definition: ChVector3.h:283
Class defining quaternion objects, that is four-dimensional numbers.
Definition: ChQuaternion.h:34
Main namespace for the Chrono package.
Definition: ChCamera.cpp:17
double GetChTime() const
Get the simulation time of this system.
Definition: ChSystem.h:154
Class for a physical system in which contact is modeled using a non-smooth (complementarity-based) me...
Definition: ChSystemNSC.h:29