Gear constraint example (demo_IRR_gears.cpp)

Create a transmission made of pulleys, spur gears, bevel gears.

Custom simplified constraints are available, to avoid the simulation of contacts between gear teeth.

This tutorial shows how to:

  • use ChLinkGear constraints to represent simplified gear interaction in 3D space
  • the ChLinkPulley constraint is used to model simplified pulleys in 3D space.
  • manage rotations of references using ChCoordsys and ChFrame classes.
  • create a motor between two parts.
// =============================================================================
// Copyright (c) 2014
// 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
// =============================================================================
// Authors: Alessandro Tasora
// =============================================================================
// Demonstration of the gear constraint (ChLinkGear) as a method to impose a
// transmission ratio between two shafts as they were connected by gears,
// without the need of performing collision detection between gear teeth
// geometries (which would be inefficient)
// =============================================================================
#include "chrono/core/ChRealtimeStep.h"
#include "chrono/physics/ChLinkMotorRotationSpeed.h"
#include "chrono/physics/ChSystemNSC.h"
#include "chrono/physics/ChBodyEasy.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;
int main(int argc, char* argv[]) {
GetLog() << "Copyright (c) 2017\nChrono version: " << CHRONO_VERSION << "\n\n";
// Create a Chrono physical system
ChSystemNSC mphysicalSystem;
// Create the Irrlicht visualization (open the Irrlicht device,
// bind a simple user interface, etc. etc.)
ChIrrApp application(&mphysicalSystem, L"Gears and pulleys", core::dimension2d<u32>(800, 600), false);
// Easy shortcuts to add camera, lights, logo and sky in Irrlicht scene:
ChIrrWizard::add_typical_Camera(application.GetDevice(), core::vector3df(12, 15, -20));
// Contact material shared among all bodies
auto mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
// Create all the rigid bodies.
double radA = 2;
double radB = 4;
// ...the truss
auto mbody_truss = chrono_types::make_shared<ChBodyEasyBox>(20, 10, 2, 1000, true, false, mat);
mbody_truss->SetPos(ChVector<>(0, 0, 3));
// ...a texture asset that will be shared among the four wheels
auto cylinder_texture = chrono_types::make_shared<ChTexture>(GetChronoDataFile("textures/pinkwhite.png"));
// ...the rotating bar support for the two epicycloidal wheels
auto mbody_train = chrono_types::make_shared<ChBodyEasyBox>(8, 1.5, 1.0, 1000, true, false, mat);
mbody_train->SetPos(ChVector<>(3, 0, 0));
// ...which must rotate respect to truss along Z axis, in 0,0,0,
auto link_revoluteTT = chrono_types::make_shared<ChLinkLockRevolute>();
link_revoluteTT->Initialize(mbody_truss, mbody_train,
// ...the first gear
auto mbody_gearA = chrono_types::make_shared<ChBodyEasyCylinder>(radA, 0.5, 1000, true, false, mat);
mbody_gearA->SetPos(ChVector<>(0, 0, -1));
mbody_gearA->SetRot(Q_from_AngAxis(CH_C_PI / 2, VECT_X));
// for aesthetic reasons, also add a thin cylinder only as a visualization:
auto mshaft_shape = chrono_types::make_shared<ChCylinderShape>();
mshaft_shape->GetCylinderGeometry().p1 = ChVector<>(0,-3,0);
mshaft_shape->GetCylinderGeometry().p2 = ChVector<>(0, 10,0);
mshaft_shape->GetCylinderGeometry().rad = radA*0.4;
// ...impose rotation speed between the first gear and the fixed truss
auto link_motor = chrono_types::make_shared<ChLinkMotorRotationSpeed>();
link_motor->Initialize(mbody_gearA, mbody_truss, ChFrame<>(ChVector<>(0, 0, 0), QUNIT));
// ...the second gear
double interaxis12 = radA + radB;
auto mbody_gearB = chrono_types::make_shared<ChBodyEasyCylinder>(radB, 0.4, 1000, true, false, mat);
mbody_gearB->SetPos(ChVector<>(interaxis12, 0, -1));
mbody_gearB->SetRot(Q_from_AngAxis(CH_C_PI / 2, VECT_X));
// ... the second gear is fixed to the rotating bar
auto link_revolute = chrono_types::make_shared<ChLinkLockRevolute>();
link_revolute->Initialize(mbody_gearB, mbody_train,
ChCoordsys<>(ChVector<>(interaxis12, 0, 0), QUNIT));
// ...the gear constraint between the two wheels A and B.
// As transmission ratio (=speed of wheel B / speed of wheel A) to enter in Set_tau(), we
// could use whatever positive value we want: the ChLinkGear will compute the two radii of the
// wheels for its 'hidden' computations, given the distance between the two axes. However, since
// we already build two '3D cylinders' bodies -just for visualization reasons!- with radA and radB,
// we must enter Set_tau(radA/radB).
// Also, note that the initial position of the constraint has no importance (simply use CSYSNORM),
// but we must set where the two axes are placed in the local coordinates of the two wheels, so
// we use Set_local_shaft1() and pass some local ChFrame. Note that, since the Z axis of that frame
// will be considered the axis of the wheel, we must rotate the frame 90� with Q_from_AngAxis(), because
// we created the wheel with ChBodyEasyCylinder() which created a cylinder with Y as axis.
auto link_gearAB = chrono_types::make_shared<ChLinkGear>();
link_gearAB->Initialize(mbody_gearA, mbody_gearB, CSYSNORM);
link_gearAB->Set_local_shaft1(ChFrame<>(VNULL, chrono::Q_from_AngAxis(-CH_C_PI / 2, VECT_X)));
link_gearAB->Set_local_shaft2(ChFrame<>(VNULL, chrono::Q_from_AngAxis(-CH_C_PI / 2, VECT_X)));
link_gearAB->Set_tau(radA / radB);
// ...the gear constraint between the second wheel B and a large wheel C with inner teeth, that
// does not necessarily need to be created as a new body because it is the 'fixed' part of the
// epicycloidal reducer, so, as wheel C, we will simply use the ground object 'mbody_truss'.
double radC = 2 * radB + radA;
auto link_gearBC = chrono_types::make_shared<ChLinkGear>();
link_gearBC->Initialize(mbody_gearB, mbody_truss, CSYSNORM);
link_gearBC->Set_local_shaft1(ChFrame<>(VNULL, chrono::Q_from_AngAxis(-CH_C_PI / 2, VECT_X)));
link_gearBC->Set_local_shaft2(ChFrame<>(ChVector<>(0, 0, -4), QUNIT));
link_gearBC->Set_tau(radB / radC);
link_gearBC->Set_epicyclic(true); // <-- this means: use a wheel with internal teeth!
// ...the bevel gear at the side,
double radD = 5;
auto mbody_gearD = chrono_types::make_shared<ChBodyEasyCylinder>(radD, 0.8, 1000, true, false, mat);
mbody_gearD->SetPos(ChVector<>(-10, 0, -9));
mbody_gearD->SetRot(Q_from_AngAxis(CH_C_PI / 2, VECT_Z));
// ... it is fixed to the truss using a revolute joint with horizontal axis (must rotate
// default ChLink creation coordys 90� on the Y vertical, since the revolute axis is the Z axis).
auto link_revoluteD = chrono_types::make_shared<ChLinkLockRevolute>();
link_revoluteD->Initialize(mbody_gearD, mbody_truss,
ChCoordsys<>(ChVector<>(-10, 0, -9), Q_from_AngAxis(CH_C_PI / 2, VECT_Y)));
// ... Let's make a 1:1 gear between wheel A and wheel D as a bevel gear: Chrono does not require
// special info for this case -the position of the two shafts and the transmission ratio are enough-
auto link_gearAD = chrono_types::make_shared<ChLinkGear>();
link_gearAD->Initialize(mbody_gearA, mbody_gearD, CSYSNORM);
link_gearAD->Set_local_shaft1(ChFrame<>(ChVector<>(0, -7, 0), chrono::Q_from_AngAxis(-CH_C_PI / 2, VECT_X)));
link_gearAD->Set_local_shaft2(ChFrame<>(ChVector<>(0, -7, 0), chrono::Q_from_AngAxis(-CH_C_PI / 2, VECT_X)));
// ...the pulley at the side,
double radE = 2;
auto mbody_pulleyE = chrono_types::make_shared<ChBodyEasyCylinder>(radE, 0.8, 1000, true, false, mat);
mbody_pulleyE->SetPos(ChVector<>(-10, -11, -9));
mbody_pulleyE->SetRot(Q_from_AngAxis(CH_C_PI / 2, VECT_Z));
// ... it is fixed to the truss using a revolute joint with horizontal axis (must rotate
// default ChLink creation coordys 90� on the Y vertical, since the revolute axis is the Z axis).
auto link_revoluteE = chrono_types::make_shared<ChLinkLockRevolute>();
link_revoluteE->Initialize(mbody_pulleyE, mbody_truss,
ChCoordsys<>(ChVector<>(-10, -11, -9), Q_from_AngAxis(CH_C_PI / 2, VECT_Y)));
// ... Let's make a synchro belt constraint between pulley D and pulley E. The user must be
// sure that the two shafts are parallel in absolute space. Also, interaxial distance should not change.
auto link_pulleyDE = chrono_types::make_shared<ChLinkPulley>();
link_pulleyDE->Initialize(mbody_gearD, mbody_pulleyE, CSYSNORM);
link_pulleyDE->Set_local_shaft1(ChFrame<>(VNULL, chrono::Q_from_AngAxis(-CH_C_PI / 2, VECT_X)));
link_pulleyDE->Set_local_shaft2(ChFrame<>(VNULL, chrono::Q_from_AngAxis(-CH_C_PI / 2, VECT_X)));
link_pulleyDE->Set_checkphase(true); // synchro belts don't tolerate slipping: this avoids it as numerical errors accumulate.
// Use this function for adding a ChIrrNodeAsset to all items
// Otherwise use application.AssetBind(myitem); on a per-item basis.
// Use this function for 'converting' assets into Irrlicht meshes
// Prepare the physical system for the simulation
while (application.GetDevice()->run()) {
application.BeginScene(true, true, SColor(255, 140, 161, 192));
// .. draw also some circle lines representing gears - just for aesthetical reasons
ChIrrTools::drawCircle(application.GetVideoDriver(), link_gearBC->Get_r2(),
(link_gearBC->Get_local_shaft2() >> *link_gearBC->GetBody2()).GetCoord(),
video::SColor(255, 255, 0, 0), 50, true);
ChIrrTools::drawCircle(application.GetVideoDriver(), link_gearAD->Get_r1(),
(link_gearAD->Get_local_shaft1() >> *link_gearAD->GetBody1()).GetCoord(),
video::SColor(255, 255, 0, 0), 30, true);
ChIrrTools::drawCircle(application.GetVideoDriver(), link_gearAD->Get_r2(),
(link_gearAD->Get_local_shaft2() >> *link_gearAD->GetBody2()).GetCoord(),
video::SColor(255, 255, 0, 0), 30, true);
ChIrrTools::drawCircle(application.GetVideoDriver(), 0.1,
ChCoordsys<>(link_gearAB->GetMarker2()->GetAbsCoord().pos, QUNIT));
ChIrrTools::drawCircle(application.GetVideoDriver(), 0.1,
ChCoordsys<>(link_gearAD->GetMarker2()->GetAbsCoord().pos, QUNIT));
ChIrrTools::drawCircle(application.GetVideoDriver(), 0.1,
ChCoordsys<>(link_gearBC->GetMarker2()->GetAbsCoord().pos, QUNIT));
// ..draw also some segments for a simplified representation of pulley
ChIrrTools::drawSegment(application.GetVideoDriver(), link_pulleyDE->Get_belt_up1(),
link_pulleyDE->Get_belt_up2(), video::SColor(255, 0, 255, 0), true);
ChIrrTools::drawSegment(application.GetVideoDriver(), link_pulleyDE->Get_belt_low1(),
link_pulleyDE->Get_belt_low2(), video::SColor(255, 0, 255, 0), true);
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:146
static void add_typical_Camera(irr::IrrlichtDevice *device, irr::core::vector3df mpos=irr::core::vector3df(0, 0, -8), irr::core::vector3df mtarg=irr::core::vector3df(0, 0, 0))
A very basic and simple function which is just a shortcut to avoid lot of typing when someone wants t...
Definition: ChIrrWizard.cpp:53
Definition: ChCoordsys.h:38
ChLog & GetLog()
Global function to get the current ChLog object.
Definition: ChLog.cpp:39
virtual void AddLink(std::shared_ptr< ChLinkBase > link)
Attach a link to the underlying assembly.
Definition: ChSystem.h:268
void SetTimestep(double val)
Set/Get the time step for time integration.
Definition: ChIrrAppInterface.cpp:558
static void add_typical_Logo(irr::IrrlichtDevice *device, const std::string &mlogofilename=GetChronoDataFile("logo_chronoengine_alpha.png"))
A very basic and simple function which is just a shortcut to avoid lot of typing when someone wants t...
Definition: ChIrrWizard.cpp:20
static void add_typical_Sky(irr::IrrlichtDevice *device, const std::string &mtexturedir=GetChronoDataFile("skybox/"))
A very basic and simple function which is just a shortcut to avoid lot of typing when someone wants t...
Definition: ChIrrWizard.cpp:40
static void add_typical_Lights(irr::IrrlichtDevice *device, irr::core::vector3df pos1=irr::core::vector3df(30.f, 100.f, 30.f), irr::core::vector3df pos2=irr::core::vector3df(30.f, 80.f, -30.f), double rad1=290, double rad2=190, irr::video::SColorf col1=irr::video::SColorf(0.7f, 0.7f, 0.7f, 1.0f), irr::video::SColorf col2=irr::video::SColorf(0.7f, 0.8f, 0.8f, 1.0f))
A very basic and simple function which is just a shortcut to avoid lot of typing when someone wants t...
Definition: ChIrrWizard.cpp:25
static void drawCircle(irr::video::IVideoDriver *driver, double radius, ChCoordsys<> mpos=CSYSNORM, irr::video::SColor mcol=irr::video::SColor(255, 0, 0, 0), int mresolution=36, bool use_Zbuffer=false)
Easy-to-use function to draw a circle line in 3D space, with given color.
Definition: ChIrrTools.cpp:625
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
ChQuaternion< double > Q_from_AngAxis(double angle, const ChVector< double > &axis)
Get the quaternion from an angle of rotation and an axis, defined in abs coords.
Definition: ChQuaternion.cpp:100
const ChApi ChQuaternion< double > QUNIT
Constant unit quaternion: {1, 0, 0, 0} , corresponds to no rotation (diagonal rotation matrix)
virtual void EndScene()
Call this to end the scene draw at the end of each animation frame.
Definition: ChIrrAppInterface.cpp:634
Namespace with classes for the Irrlicht module.
Definition: ChApiIrr.h:48
static void drawSegment(irr::video::IVideoDriver *driver, ChVector<> mstart, ChVector<> mend, irr::video::SColor mcol=irr::video::SColor(255, 0, 0, 0), bool use_Zbuffer=false)
Easy-to-use function to draw segment lines in 3D space, with given color.
Definition: ChIrrTools.cpp:594
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:644
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:617
Main namespace for the Chrono package.
Definition: ChAsset.cpp:18
void SetTimestepperType(ChTimestepper::Type type)
Set the method for time integration (time stepper type).
Definition: ChSystem.cpp:348
virtual void DrawAll()
Call this function inside a loop such as.
Definition: ChIrrAppInterface.cpp:757
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:94