ChronoEngine:Demo pendulum

From ChronoWiki

(Redirected from Demo pendulum)
Jump to: navigation, search

This demo is about creating a set of composite pendulums that swing under the effect of a field of forces. The attachment of the pendulum is a sliding joint with upper-lower limits.

We do not report here the initial part of the source (includes, namespaces, etc. - see the first simplier demos).

First of all, we create a 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). We exploit the 'force accumulator' feature.

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);
	}
}

Now here is the main program:

int main(int argc, char* argv[])
{

	// In CHRONO engine, The DLL_CreateGlobals() - DLL_DeleteGlobals(); pair is needed if
	// global functions are needed.
	DLL_CreateGlobals();


	// Create a ChronoENGINE physical system
	ChSystem my_system;


	// Create the Irrlicht visualization (open the Irrlicht device,
	// bind a simple user interface, etc. etc.)
	ChIrrAppInterface application(&my_system, L"A simple pendulum example",core::dimension2d<u32>(800,600),false);

	// Easy shortcuts to add logo, camera, lights and sky in Irrlicht scene:
	ChIrrWizard::add_typical_Logo(application.GetDevice());
	ChIrrWizard::add_typical_Sky(application.GetDevice());
	ChIrrWizard::add_typical_Lights(application.GetDevice());
	ChIrrWizard::add_typical_Camera(application.GetDevice(), core::vector3df(0,14,-20));

Using a 'for' fycle, 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, application.GetSceneManager(),
												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, application.GetSceneManager(),
												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, application.GetSceneManager(),
												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, application.GetSceneManager(),
												1.0,
												ChVector<>(6,-9,z_step),
												ChQuaternion<>(1,0,0,0),
												ChVector<>(1,6,1) );
		mrigidBody3->GetBody()->SetCollide(false);

Note: here we create 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
		//    (exercise, try also: ChSharedPtr<ChLinkLockHook>  my_link_12(new ChLinkLockHook);
		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);

	}

Before starting the real-time simulation loop, 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 = application.GetSceneManager()->getMesh("../data/fan2.obj");
	IAnimatedMeshSceneNode* fanNode = application.GetSceneManager()->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;


	my_system.SetLcpSolverType(ChSystem::LCP_ITERATIVE_PMINRES);


	while(application.GetDevice()->run())
	{
		// Irrlicht must prepare frame to draw
		application.GetVideoDriver()->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
		ChIrrTools::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();
		ChIrrTools::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, 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) );


		application.GetVideoDriver()->endScene();

	}



	// Remember this at the end of the program, if you started
	// with DLL_CreateGlobals();
	DLL_DeleteGlobals();

	return 0;
}
Personal tools