Creating A Powertrain In Chrono (demo_CH_powertrain.cpp)

Tutorial covers basic approaches to build systems that embed powertrains made with 1-degree-of-freedom items (rotating shafts):

  • connect 1D shafts with transmission ratios
  • connect 1D shafts with 1D clutches, brakes, etc.
  • connect a 1D shaft to a 3D body.
  • No GUI: only text output.

Example 1: create a simple powertrain with ChShaft objects

This models a very basic powertrain with two shafts A and B, connected by a reducer [ t ] with transmission ratio t. The shafts are free to rotate. Shaft A has an applied torque Ta, so A and B will constantly accelerate. Each shaft must have some inertia and each one is marked as || in the following scheme:

A B
Ta ||---[ t ]---||

First, create a ChShaft, a 1-degree-of-freedom '1D' mechanical object that can only rotate. It has one inertia value and maybe one applied torque. The ChShaft objects do not have any meaning in 3D, they are just 'building blocks'.

Next, create another shaft. Note that this falls back on the use of shared pointers for ChShaft objects. Also note that the elements must be added to the ChSystem object that manages this simulation.

Finally, create a ChShaftsGear that represents a simplified model of a reducer with transmission ratio t between two ChShaft objects.

Note that a full blown 3D powertrain could be created using a collection of rigid bodies of ChBody type that would be connected via ChLinkLockRevolute and ChLinkGear 3D constraints. However, this would introduce additional complexity to the model which is not always warranted. The 1D items of ChShaft type keep the model much simpler.

Example 2: a clutch between two shafts

This models a very basic powertrain with two shafts A and B connected by a clutch [ c ]. Each shaft (see flywheels || in schematic below) starts with a nonzero speed and is free to rotate independently until the clutch is activated. At that point, they will decelerate until they have the same speed.

A B
Ta ||---[ c ]---||

First, create a ChShaft that starts with nonzero angular velocity:

Next, create another ChShaft with opposite initial angular velocity:

Now, create a ChShaftsClutch that represents a simplified model of a clutch between two ChShaft objects (something that limits the max transmitted torque, up to slippage).

Below, the simulation is started with the clutch disengaged:

Example 3: an epicycloidal reducer

An epicycloidal reducer is modeled below using the ChShaftsPlanetary constraint.

The ChShaftsPlanetary sets up a kinematic constraint between three shafts. One of them will be fixed and represents the truss of the reducer - in epicycloidaal reducer, this is the role of the large gear with inner teeth. The two remaining shafts are the input and output shafts. In other cases, such as the differential planetary gear of cars, all three shafts are free. A brake is applied on the output shaft - it is enough that one of these last two shafts is fixed.

In the following schematic, the brake is [ b ], the planetary (the reducer) is [ p ], the shafts are A,B,C,D, the applied torque is Ta, inertias of free shafts are shown as flywheels || , and fixed shafts are marked with * .

A B D
Ta ||---[ p ]---||---[ b ]---*
[ ]---*
C

First, create shaft A with an applied torque:

Next, create shaft B:

Create shaft C, which will be fixed (used as truss of epicycloidal reducer):

Create a ChShaftsPlanetary that represents a simplified model of a planetary gear between three ChShaft objects (e.g., a car differential). An epicycloidal reducer is a special type of planetary gear.

The ratios of the planetary can be set using a simplified formula for the so called Willis case. Imagine we hold fixed the carrier (shaft B in epic. reducers), and leave the truss C free (the outer gear with inner teeth in our reducer); which is the transmission ratio \( t_0 \) that we get. It is simply \( t_0=-Z_a/Z_c \), with \( Z_i \) = num of teeth of gears. Use the following to set all the three ratios:

Now, let's make a shaft D that is fixed and thus used for the right side of a clutch (so the clutch will act as a brake).

Next, make the brake. It is, in fact, a clutch between shafts B and D, where D is fixed as a truss so that the clutch will operate as a brake.

Example 4: constraint between a ChBody and a ChShaft

Suppose we want to create a 3D model, for instance a slider-crank, built with multiple ChBody objects. Moreover, we want to create a powertrain, for instance a motor, a clutch, etc., for the rotation of the crank. Connecting 1D items of ChShaft class with the 3D items of ChBody class calls for the use of a ChShaftsBody constraint, shown as [ bs ] in the schematic in which the 3D body is shown as <>. This example also considers a 'torsional spring damper' C, shown as [ t ], that connects shafts A and C (C is shown as * because fixed).

B A C
Ta <>---[ bs ]---||---[ t ]---*

First, create 'A', a 1D shaft:

Next, create 'C', a 1D shaft, fixed:

Create 'B', a 3D rigid body:

Define the torsional spring-damper between shafts A and C:

Define the shaft 'A' connected to the rotation of the 3D body 'B'. Finally, specify the direction (in body coordinates) along which the shaft will affect the body:

Example 5: torque converter and thermal engine

This example highlights the use of a torque converter. The torque converter is represented by a ChShaftsTorqueConverter object that connects three 1D items of ChShaft class:

  • the input shaft A, i.e., the impeller connected to the engine
  • the output shaft B, i.e., the turbine connected to the gears and wheels
  • the stator C, which does not rotate and transmits reaction to the truss In the following schematic, the torque converter is represented as [ tc ], the thermal engine is marked with [ e ], and the breaking torque is Tb (C shown as * since fixed).

First, create 'A', a 1D shaft:

Next, create 'B', a 1D shaft:

Create 'C', a 1D shaft, fixed:

Create 'D', a 1D shaft, fixed:

Define the torque converter and connect the shafts: A (input), B (output), C(truss stator)

Define the thermal engine acting on shaft A, the input to the torque converter. Note that the thermal engine also requires shaft D, which is used to transmit the reaction torque back to a truss (the motor block).

Option A: use a ChShaftsMotor in MOT_MODE_TORQUE mode. It works, but most often this is more useful when in MOT_MODE_SPEED.

Option B: use a ChShaftsTorque - it simply applies a torque to my_shaftA (say, the crankshaft), and the negative torque to my_shaftD (say, the motor block). It is a quick approach. Note that the torque should be changed at each timestep if a torque curve is to be emulated.

Option C: a more versatile approach where one can define a torque curve and a throttle value via the ChShaftsThermalEngine.

The complete listing:

// =============================================================================
// 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 power train using the '1D' items of ChShaft class
// (rotating parts that have only one degree of freedom and one inertia value).
// This is an easier alternative to creating full 3D ChBody objects that rotate
// on revolute joints, etc.
//
// =============================================================================
#include "chrono/physics/ChSystemNSC.h"
#include "chrono/physics/ChShaftsGear.h"
#include "chrono/physics/ChShaftsClutch.h"
#include "chrono/physics/ChShaftsPlanetary.h"
#include "chrono/physics/ChShaftsBody.h"
#include "chrono/physics/ChShaftsTorsionSpring.h"
#include "chrono/physics/ChShaftsTorqueConverter.h"
#include "chrono/physics/ChShaftsMotor.h"
#include "chrono/physics/ChShaftsTorque.h"
#include "chrono/physics/ChShaftsThermalEngine.h"
#include "chrono/physics/ChShaftsFreewheel.h"
#include "chrono/physics/ChShaftsMotorAngle.h"
#include "chrono_thirdparty/filesystem/path.h"
using namespace chrono;
std::string out_dir = GetChronoOutputPath() + "DEMO_POWERTRAIN";
int main(int argc, char* argv[]) {
GetLog() << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";
// Create output directory
if (!filesystem::create_directory(filesystem::path(out_dir))) {
std::cout << "Error creating directory " << out_dir << std::endl;
return 1;
}
if (false) {
//
// EXAMPLE 1:
//
GetLog() << " Example: create a simple power train with ChShaft objects: \n";
// We will model a very basic powertrain with two shafts A and B,
// connected by a reducer [ t ] with transmission ratio 't'. Shafts are
// free to rotate, shaft A has an applied torque Ta, so A and B will
// constantly accelerate. Each shaft must have some inertia, it's like a
// flywheel, marked as || in the following scheme:
//
// A B
// Ta ||---[ t ]---||
//
// The physical system: it contains all physical objects.
// Create a 1-degree-of-freedom '1D' mechanical object, that
// is a ChShaft (an item that can oly rotate, with one inertia value
// and maybe one applied torque). The ChShaft objects do not have
// any meaning in 3d: they are just 'building blocks' for making
// power trains as in imput-output black box schemes.
auto my_shaftA = chrono_types::make_shared<ChShaft>();
my_shaftA->SetInertia(10);
my_shaftA->SetAppliedTorque(6);
sys.AddShaft(my_shaftA);
// Create another shaft. Note that we use shared pointers for ChShaft
// objects, as we did for ChBody objects. Also, note that we must add them
// to the ChSystemNSC.
auto my_shaftB = chrono_types::make_shared<ChShaft>();
my_shaftB->SetInertia(100);
my_shaftB->SetShaftFixed(false);
sys.AddShaft(my_shaftB);
// Create a ChShaftsGear, that represents a simplified model
// of a reducer, with transmission ratio t, between two ChShaft objects.
// (Note that you could also build a 3D powertrain by creating full rigid bodies
// of ChBody type and join them using ChLinkLockRevolute, ChLinkGear 3D constraints,
// but this would introduce many unnecessary degrees of freedom/constraints
// whereas the 1D items of ChShaft type, in this example, make things much simplier).
auto my_shaft_gearAB = chrono_types::make_shared<ChShaftsGear>();
my_shaft_gearAB->Initialize(my_shaftA, my_shaftB);
my_shaft_gearAB->SetTransmissionRatio(-0.1); // ex., a couple of spur gears with 20 and 200 teeth
sys.Add(my_shaft_gearAB);
GetLog() << "\n\n\nHere's the system hierarchy: \n\n ";
// Perform a very simple simulation loop..
double chronoTime = 0;
while (chronoTime < 2.5) {
chronoTime += 0.01;
// PERFORM SIMULATION UP TO chronoTime
sys.DoFrameDynamics(chronoTime);
// Print something on the console..
GetLog() << "Time: " << chronoTime << "\n"
<< " shaft A rot: " << my_shaftA->GetPos() << " speed: " << my_shaftA->GetPos_dt()
<< " accel: " << my_shaftA->GetPos_dtdt() << "\n"
<< " shaft B rot: " << my_shaftB->GetPos() << " speed: " << my_shaftB->GetPos_dt()
<< " accel: " << my_shaftB->GetPos_dtdt() << "\n"
<< " AB gear, torque on A side: " << my_shaft_gearAB->GetTorqueReactionOn1()
<< " AB gear, torque on B side: " << my_shaft_gearAB->GetTorqueReactionOn2() << "\n";
}
}
if (false) {
//
// EXAMPLE 2:
//
GetLog() << " Example: a clutch between two shafts \n";
// We will model a very basic powertrain with two shafts A and B,
// connected by a clutch [ c ]. Shafts (see flywheels || in scheme)
// starts with nonzero speed, and are free to rotate independently
// until the clutch is activated: since activation, they will decelerate
// until they have the same speed.
//
// A B
// Ta ||---[ c ]---||
//
// The physical system: it contains all physical objects.
// Create a ChShaft that starts with nonzero angular velocity
auto my_shaftA = chrono_types::make_shared<ChShaft>();
my_shaftA->SetInertia(0.5);
my_shaftA->SetPos_dt(30);
sys.AddShaft(my_shaftA);
// Create another ChShaft, with opposite initial angular velocity
auto my_shaftB = chrono_types::make_shared<ChShaft>();
my_shaftB->SetInertia(0.6);
my_shaftB->SetPos_dt(-10);
sys.AddShaft(my_shaftB);
// Create a ChShaftsClutch, that represents a simplified model
// of a clutch between two ChShaft objects (something that limits
// the max transmitted torque, up to slippage).
auto my_shaft_clutchAB = chrono_types::make_shared<ChShaftsClutch>();
my_shaft_clutchAB->Initialize(my_shaftA, my_shaftB);
my_shaft_clutchAB->SetTorqueLimit(60);
sys.Add(my_shaft_clutchAB);
// Let's begin the simulation with the clutch disengaged:
my_shaft_clutchAB->SetModulation(0);
GetLog() << "\n\n\nHere's the system hierarchy: \n\n ";
// Perform a very simple simulation loop..
double chronoTime = 0;
while (chronoTime < 1.5) {
chronoTime += 0.01;
// PERFORM SIMULATION UP TO chronoTime
sys.DoFrameDynamics(chronoTime);
// Activate the clutch only after 0.8 seconds of simulation:
if (chronoTime > 0.8) {
my_shaft_clutchAB->SetModulation(1);
}
// Print something on the console..
GetLog() << "Time: " << chronoTime << "\n"
<< " shaft A rot: " << my_shaftA->GetPos() << " speed: " << my_shaftA->GetPos_dt()
<< " accel: " << my_shaftA->GetPos_dtdt() << "\n"
<< " shaft B rot: " << my_shaftB->GetPos() << " speed: " << my_shaftB->GetPos_dt()
<< " accel: " << my_shaftB->GetPos_dtdt() << "\n"
<< " AB clutch, torque on A side: " << my_shaft_clutchAB->GetTorqueReactionOn1()
<< " AB clutch, torque on B side: " << my_shaft_clutchAB->GetTorqueReactionOn2() << "\n";
}
}
if (false) {
//
// EXAMPLE 3:
//
GetLog() << " Example: an epicycloidal reducer \n";
// We will model an epicycloidal reducer using the ChShaftsPlanetary
// constraint.
// The ChShaftsPlanetary makes a kinematic constraint between three
// shafts: so one of them will be 'fixed' and will represent the truss
// of the reducer -in s reducer, this is the role of the
// large gear with inner teeth- and the two remaining shafts are the
// input and output shafts (in other cases, such as the differential
// planetary gear of the cars, all three shafts are free).
// Also, a brake is applied for the output shaft: the ChShaftsClutch
// will be used to this end, it's enough that one of the two shafts is fixed.
// In the following scheme, the brake is [ b ], the planetary (the
// reducer) is [ p ], the shafts are A,B,C,D applied torque is Ta, inertias
// of free shafts are shown as flywheels || , and fixed shafts are marked with * .
//
// A B D
// Ta ||---[ p ]---||---[ b ]---*
// [ ]---*
// C
// The physical system: it contains all physical objects.
// Create shaft A, with applied torque
auto my_shaftA = chrono_types::make_shared<ChShaft>();
my_shaftA->SetInertia(0.5);
my_shaftA->SetAppliedTorque(10);
sys.AddShaft(my_shaftA);
// Create shaft B
auto my_shaftB = chrono_types::make_shared<ChShaft>();
my_shaftB->SetInertia(0.5);
sys.AddShaft(my_shaftB);
// Create shaft C, that will be fixed (to be used as truss of epicycloidal reducer)
auto my_shaftC = chrono_types::make_shared<ChShaft>();
my_shaftC->SetShaftFixed(true);
sys.AddShaft(my_shaftC);
// Create a ChShaftsPlanetary, that represents a simplified model
// of a planetary gear between THREE ChShaft objects (ex.: a car differential)
// An epicycloidal reducer is a special type of planetary gear.
auto my_shaft_planetaryBAC = chrono_types::make_shared<ChShaftsPlanetary>();
my_shaft_planetaryBAC->Initialize(my_shaftB, my_shaftA, my_shaftC); // output, carrier, fixed
// We can set the ratios of the planetary using a simplified formula, for the
// so called 'Willis' case. Imagine we hold fixed the carrier (shaft B in epic. reducers),
// and leave free the truss C (the outer gear with inner teeth in our reducer); which is
// the transmission ratio t0 that we get? It is simply t0=-Za/Zc, with Z = num of teeth of gears.
// So just use the following to set all the three ratios automatically:
double t0 =
-50.0 / 100.0; // suppose, in the reducer, that pinion A has 50 teeth and truss has 100 inner teeth.
my_shaft_planetaryBAC->SetTransmissionRatioOrdinary(t0);
sys.Add(my_shaft_planetaryBAC);
// Now, let's make a shaft D, that is fixed, and used for the right side
// of a clutch (so the clutch will act as a brake).
auto my_shaftD = chrono_types::make_shared<ChShaft>();
my_shaftD->SetShaftFixed(true);
sys.Add(my_shaftD);
// Make the brake. It is, in fact a clutch between shafts B and D, where
// D is fixed as a truss, so the clutch will operate as a brake.
auto my_shaft_clutchBD = chrono_types::make_shared<ChShaftsClutch>();
my_shaft_clutchBD->Initialize(my_shaftB, my_shaftD);
my_shaft_clutchBD->SetTorqueLimit(60);
sys.Add(my_shaft_clutchBD);
GetLog() << "\n\n\nHere's the system hierarchy: \n\n ";
// Perform a very simple simulation loop..
double chronoTime = 0;
while (chronoTime < 1.5) {
chronoTime += 0.01;
// PERFORM SIMULATION UP TO chronoTime
sys.DoFrameDynamics(chronoTime);
// Print something on the console..
GetLog() << "Time: " << chronoTime << "\n"
<< " shaft A rot: " << my_shaftA->GetPos() << " speed: " << my_shaftA->GetPos_dt()
<< " accel: " << my_shaftA->GetPos_dtdt() << "\n"
<< " shaft B rot: " << my_shaftB->GetPos() << " speed: " << my_shaftB->GetPos_dt()
<< " accel: " << my_shaftB->GetPos_dtdt() << "\n"
<< " epicycloidal react torques on shafts - on A: "
<< my_shaft_planetaryBAC->GetTorqueReactionOn2()
<< " , on B: " << my_shaft_planetaryBAC->GetTorqueReactionOn1()
<< " , on C: " << my_shaft_planetaryBAC->GetTorqueReactionOn3() << "\n";
}
}
if (false) {
//
// EXAMPLE 4:
//
GetLog() << " Example: constraint between a ChBody and a ChShaft \n";
// Suppose you want to create a 3D model, for instance a slider-crank,
// built with multiple ChBody objects; moreover you want to create a
// powertrain, for instance a motor, a clutch, etc, for the rotation of
// the crank. How to connect the '1D items' of ChShaft class to the 3D
// items of ChBody class? The solution is to use the ChShaftsBody constraint,
// shown as [ bs ] in the following scheme, where the 3D body is shown as <>.
// In this example we also add a 'torsional spring damper' C, shown as [ t ]
// that connects shafts A and C (C is shown as * because fixed).
//
// B A C
// Ta <>---[ bs ]---||---[ t ]---*
//
// The physical system: it contains all physical objects.
// Create 'A', a 1D shaft
auto my_shaftA = chrono_types::make_shared<ChShaft>();
my_shaftA->SetInertia(9);
sys.AddShaft(my_shaftA);
// Create 'C', a 1D shaft, fixed
auto my_shaftC = chrono_types::make_shared<ChShaft>();
my_shaftC->SetShaftFixed(true);
sys.AddShaft(my_shaftC);
// Create 'B', a 3D rigid body
auto my_bodyB = chrono_types::make_shared<ChBody>();
my_bodyB->Accumulate_torque(ChVector<>(0, 0, 3), true); // set some constant torque to body
sys.Add(my_bodyB);
// Make the torsional spring-damper between shafts A and C.
auto my_shaft_torsionAC = chrono_types::make_shared<ChShaftsTorsionSpring>();
my_shaft_torsionAC->Initialize(my_shaftA, my_shaftC);
my_shaft_torsionAC->SetTorsionalStiffness(40);
my_shaft_torsionAC->SetTorsionalDamping(0);
sys.Add(my_shaft_torsionAC);
// Make the shaft 'A' connected to the rotation of the 3D body 'B'.
// We must specify the direction (in body coordinates) along which the
// shaft will affect the body.
auto my_shaftbody_connection = chrono_types::make_shared<ChShaftsBody>();
ChVector<> mshaftdir(VECT_Z);
my_shaftbody_connection->Initialize(my_shaftA, my_bodyB, mshaftdir);
sys.Add(my_shaftbody_connection);
GetLog() << "\n\n\nHere's the system hierarchy: \n\n ";
// Perform a very simple simulation loop..
double chronoTime = 0;
while (chronoTime < 0.5) {
chronoTime += 0.01;
// PERFORM SIMULATION UP TO chronoTime
sys.DoFrameDynamics(chronoTime);
// Print something on the console..
GetLog() << "Time: " << chronoTime << "\n"
<< " shaft A rot: " << my_shaftA->GetPos() << " speed: " << my_shaftA->GetPos_dt()
<< " accel: " << my_shaftA->GetPos_dtdt() << "\n"
<< " Body B angular speed on z: " << my_bodyB->GetWvel_loc().z()
<< " accel on z: " << my_bodyB->GetWacc_loc().z() << "\n"
<< " AC spring, torque on A side: " << my_shaft_torsionAC->GetTorqueReactionOn1()
<< " torque on C side: " << my_shaft_torsionAC->GetTorqueReactionOn2() << "\n"
<< " shafts/body reaction, on shaft A: " << my_shaftbody_connection->GetTorqueReactionOnShaft()
<< " , on body (x y z): " << my_shaftbody_connection->GetTorqueReactionOnBody().x() << " "
<< my_shaftbody_connection->GetTorqueReactionOnBody().y() << " "
<< my_shaftbody_connection->GetTorqueReactionOnBody().z() << " "
<< "\n";
}
}
if (true) {
//
// EXAMPLE 5:
//
GetLog() << " Example 5: torque converter and thermal engine \n";
// In this example we use a torque converter.
// The torque converter is represented by a ChShaftsTorqueConverter
// object, that connects three '1D items' of ChShaft class:
// - the input shaft A, ie. the impeller connected to the engine
// - the output shaft B, i.e. the turbine connected to the gears and wheels
// - the stator C, that does not rotate and transmits reaction to the truss.
// In the following scheme, the torque converter is represented as [ tc ],
// and we also add a thermal engine, shown with [ e ], and a breaking torque Tb
// (C is shown as * because fixed).
//
// D A B
// *---[ e ]---||---[ tc ]---|| Tb
// [ ]---*
// C
//
// The physical system: it contains all physical objects.
// Create 'A', a 1D shaft
auto my_shaftA = chrono_types::make_shared<ChShaft>();
my_shaftA->SetInertia(1.5);
sys.AddShaft(my_shaftA);
// Create 'B', a 1D shaft
auto my_shaftB = chrono_types::make_shared<ChShaft>();
my_shaftB->SetInertia(3.2);
my_shaftB->SetAppliedTorque(-5); // apply const braking torque
sys.AddShaft(my_shaftB);
// Create 'C', a 1D shaft, fixed
auto my_shaftC = chrono_types::make_shared<ChShaft>();
my_shaftC->SetShaftFixed(true);
sys.AddShaft(my_shaftC);
// Create 'D', a 1D shaft, fixed
auto my_shaftD = chrono_types::make_shared<ChShaft>();
my_shaftD->SetShaftFixed(true);
sys.AddShaft(my_shaftD);
// Make the torque converter and connect the shafts:
// A (input),B (output), C(truss stator)
auto my_torqueconverter = chrono_types::make_shared<ChShaftsTorqueConverter>();
my_torqueconverter->Initialize(my_shaftA, my_shaftB, my_shaftC);
sys.Add(my_torqueconverter);
auto mK = chrono_types::make_shared<ChFunction_Recorder>();
mK->AddPoint(0.0, 15);
mK->AddPoint(0.25, 15);
mK->AddPoint(0.50, 15);
mK->AddPoint(0.75, 16);
mK->AddPoint(0.90, 18);
mK->AddPoint(1.00, 35);
my_torqueconverter->SetCurveCapacityFactor(mK);
auto mT = chrono_types::make_shared<ChFunction_Recorder>();
mT->AddPoint(0.0, 2.00);
mT->AddPoint(0.25, 1.80);
mT->AddPoint(0.50, 1.50);
mT->AddPoint(0.75, 1.15);
mT->AddPoint(1.00, 1.00);
my_torqueconverter->SetCurveTorqueRatio(mT);
// Make the thermal engine, acting on shaft A, the input to
// the torque converter. Note that the thermal engine also
// requires another shaft D, that is used to transmit the
// reaction torque back to a truss (the motor block).
// Option A: use a ChShaftsMotor, in the MOT_MODE_TORQUE mode.
// It works, but most often this is more useful when in MOT_MODE_SPEED.
/*
auto my_motor = chrono_types::make_shared<ChShaftsMotor>();
my_motor->Initialize(my_shaftA, my_shaftD);
my_motor->SetMotorMode(ChShaftsMotor::MOT_MODE_TORQUE);
my_motor->SetMotorTorque(30);
sys.Add(my_motor);
*/
// Option B: use a ChShaftsTorque, it just applies a torque
// to my_shaftA (say, the crankshaft) and the negative torque
// to my_shaftD (say, the motor block).
// It is a quick approach. But you should take care of changing
// the torque at each timestep if you want to simulate a torque curve...
/*
auto my_motor = chrono_types::make_shared<ChShaftsTorque>();
my_motor->Initialize(my_shaftA, my_shaftD);
my_motor->SetTorque(30);
sys.Add(my_motor);
*/
// Option C: a more powerful approach where you can
// define a torque curve and a throttle value, using the
// ChShaftsThermalEngine.
auto my_motor = chrono_types::make_shared<ChShaftsThermalEngine>();
my_motor->Initialize(my_shaftA, my_shaftD);
sys.Add(my_motor);
auto mTw = chrono_types::make_shared<ChFunction_Recorder>();
mTw->AddPoint(-5, 30); // [rad/s], [Nm]
mTw->AddPoint(0, 30);
mTw->AddPoint(200, 60);
mTw->AddPoint(400, 40);
mTw->AddPoint(450, 0);
mTw->AddPoint(500, -60); // torque curve must be defined beyond max speed too - engine might be 'pulled'
my_motor->SetTorqueCurve(mTw);
GetLog() << "\n\n\nHere's the system hierarchy: \n\n ";
// Perform a very simple simulation loop..
double chronoTime = 0;
while (chronoTime < 4.5) {
chronoTime += 0.01;
// PERFORM SIMULATION UP TO chronoTime
sys.DoFrameDynamics(chronoTime);
// Print something on the console..
GetLog() << "Time: " << chronoTime << "\n"
<< " shaft A rot: " << my_shaftA->GetPos() << " speed: " << my_shaftA->GetPos_dt()
<< " accel: " << my_shaftA->GetPos_dtdt() << "\n"
<< " shaft B rot: " << my_shaftB->GetPos() << " speed: " << my_shaftB->GetPos_dt()
<< " accel: " << my_shaftB->GetPos_dtdt() << "\n"
<< " T.Convert.:"
<< " R=" << my_torqueconverter->GetSpeedRatio()
<< " Tin=" << my_torqueconverter->GetTorqueReactionOnInput()
<< " Tout=" << my_torqueconverter->GetTorqueReactionOnOutput()
<< " Tstator=" << my_torqueconverter->GetTorqueReactionOnStator() << "\n"
<< " T.Motor: "
<< " T(w)=" << my_motor->GetTorqueReactionOn1() << "[Nm]"
<< " w=" << my_motor->GetRelativeRotation_dt() << "[rad/s]"
<< "\n";
}
}
if (true) {
//
// EXAMPLE 6:
//
GetLog() << " Example 6: a ratcheting freewheel, as a one-directional clutch \n";
// In this example we use a ratcheting freewheel, that acts as a one-directional
// clutch (where the locking in reverse direction happens only at discrete
// steps, depending on the n.of ratcheting teeths).
// The example consists of:
// - the fixed shaft A
// - the shaft B, that rotates back and forth
// - the shaft C, that rotates only unidirectionally
// - the fixed shaft D
// In the following scheme
// - the freewheel is represented as [ fw ],
// - we also add a motor, shown with [ m ], to generate sinusoidal rotation of B for testing
// - we also add a clutch, shown with [ cl ], just to keep the shaft C "stopped" when not
// pushed by the unidirectional freewheel, otherwise would proceed in one direction forever.
// (A,D are shown as * because fixed).
//
// A B C D
// *---[ m ]---||---[ fw ]---||---[ cl ]---*
//
// The physical system: it contains all physical objects.
// Create 'A', a 1D shaft, fixed
auto my_shaftA = chrono_types::make_shared<ChShaft>();
my_shaftA->SetShaftFixed(true);
sys.AddShaft(my_shaftA);
// Create 'B', a 1D shaft
auto my_shaftB = chrono_types::make_shared<ChShaft>();
my_shaftB->SetInertia(1.5);
sys.AddShaft(my_shaftB);
// Create 'C', a 1D shaft
auto my_shaftC = chrono_types::make_shared<ChShaft>();
my_shaftC->SetInertia(3.2);
sys.AddShaft(my_shaftC);
// Create D', a 1D shaft, fixed
auto my_shaftD = chrono_types::make_shared<ChShaft>();
my_shaftD->SetShaftFixed(true);
sys.AddShaft(my_shaftD);
// Make the motor imposing a test sinusoidal rotation
auto my_motor = chrono_types::make_shared<ChShaftsMotorAngle>();
my_motor->Initialize(my_shaftA, my_shaftB);
sys.Add(my_motor);
auto my_sinefunction = chrono_types::make_shared<ChFunction_Sine>(0, 1.2, 0.001+0.5*CH_C_2PI / 20); // phase freq ampl
my_motor->SetAngleFunction(my_sinefunction);
// Make the freewheel:
auto my_freewheel = chrono_types::make_shared<ChShaftsFreewheel>();
my_freewheel->Initialize(my_shaftB, my_shaftC);
my_freewheel->SetRatchetingModeTeeth(25);
//my_freewheel->SetJammingMode(); // this is like having infinite teeth, i.e. no backlash
//my_freewheel->SetFreeBackward(); // this is to reverse the unidirectional behavior
sys.Add(my_freewheel);
// Make the clutch that keeps the shaft C in place:
auto my_clutch = chrono_types::make_shared<ChShaftsClutch>();
my_clutch->Initialize(my_shaftC, my_shaftD);
my_clutch->SetTorqueLimit(100);
sys.Add(my_clutch);
GetLog() << "\n\n\nHere's the system hierarchy: \n\n ";
ChStreamOutAsciiFile file_results(out_dir + "/test_clutch.txt");
// Perform a very simple simulation loop..
double chronoTime = 0;
double step = 0.01;
while (chronoTime < 5.5) {
chronoTime += step;
// PERFORM SIMULATION UP TO chronoTime
sys.DoStepDynamics(step);
// Print something on the console..
GetLog() << "Time: " << chronoTime << "\n"
<< " shaft B rot: " << my_shaftB->GetPos() << " speed: " << my_shaftB->GetPos_dt()
<< " accel: " << my_shaftB->GetPos_dtdt() << "\n"
<< " shaft C rot: " << my_shaftC->GetPos() << " speed: " << my_shaftC->GetPos_dt()
<< " accel: " << my_shaftC->GetPos_dtdt() << "\n"
<< " Torque: Tmotor=" << my_motor->GetTorqueReactionOn1()
<< " Tfreewheel=" << my_freewheel->GetTorqueReactionOn1()
<< " Tclutch=" << my_clutch->GetTorqueReactionOn1()
<< " ratchet vane=" << my_freewheel->GetCurrentTeethVane()
<< "\n";
file_results << chronoTime << ", "
<< my_shaftB->GetPos() << ", "
<< my_shaftC->GetPos() << ", "
<< my_shaftC->GetPos_dt() << ", "
<< my_clutch->GetTorqueReactionOn1() << ", "
<< my_freewheel->GetCurrentTeethVane() << "\n";
}
}
return 0;
}
void Add(std::shared_ptr< ChPhysicsItem > item)
Attach an arbitrary ChPhysicsItem (e.g.
Definition: ChSystem.cpp:210
ChLog & GetLog()
Global function to get the current ChLog object.
Definition: ChLog.cpp:39
bool DoFrameDynamics(double end_time)
Performs integration until the m_endtime is exactly reached, but current time step may be automatical...
Definition: ChSystem.cpp:2035
Definition of general purpose 3d vector variables, such as points in 3D.
Definition: ChVector.h:35
const std::string & GetChronoOutputPath()
Obtain the path to the output directory for Chrono demos.
Definition: ChGlobal.cpp:110
void ShowHierarchy(ChStreamOutAscii &m_file, int level=0) const
Write the hierarchy of contained bodies, markers, etc.
Definition: ChSystem.h:404
int DoStepDynamics(double step_size)
Advances the dynamical simulation for a single step, of length step_size.
Definition: ChSystem.cpp:1601
Main namespace for the Chrono package.
Definition: ChCamera.cpp:17
virtual void AddShaft(std::shared_ptr< ChShaft > shaft)
Attach a shaft to the underlying assembly.
Definition: ChSystem.cpp:153
Specialized class for ASCII output on system's file.
Definition: ChStream.h:667
Class for a physical system in which contact is modeled using a non-smooth (complementarity-based) me...
Definition: ChSystemNSC.h:29