28. agxDriveTrain

agxDriveTrain is a library of agxPowerLine components designed to model the various parts of a vehicle drive train. It deals exclusively with rotational motion, hence all components inherit either from RotationalUnit or from RotationalConnector.

To use components which are part of the PowerLine API one must first create a PowerLine instance to hold the components:

agxPowerLine::PowerLineRef powerLine = new agxPowerLine::PowerLine();
simulation->add(powerLine);

28.1. Shaft

The Shaft is the most basic drive train Unit. It is simply a rotating body that we can connect Connectors to.

agxDriveTrain::ShaftRef shaft1 = new agxDriveTrain::Shaft();
powerLine->add(shaft1);

28.2. Gear

The Gear is the most basic drive train Connector. It is used to transfer rotational motion between the Unit-based drive train components. A Gear is actually the interaction between two geared wheels, one from each connected Unit, and has therefore a gear ratio. The gear ratio define the number of gear teeth on the output shaft to the number on the input shaft. A gear ratio magnitude higher than 1 will cause the output gear to rotate slower than the input shaft, and a gear ratio magnitude lower than 1 will instead cause the output gear to rotate faster than the input shaft. Negative gear ratios make the output shaft rotate in the opposite direction of the input shaft.

\[\omega_{out} = \frac{\omega_{in}}{g}\]

where \(g\) is the gear ratio.

A pair of shafts are connected using code such as the following:

agxDriveTrain::ShaftRef shaft2 = new agxDriveTrain::Shaft();
agxDriveTrain::GearRef gear = new agxDriveTrain::Gear();

powerLine->add(shaft2);
powerLine->add(gear);

gear->setGearRatio(agx::Real(2.0));

shaft1->connect(gear);
gear->connect(shaft2);

With the system created so far, since shaft1 is the input of the gear and shaft2 is the output, whenever shaft1 is rotating, shaft2 will rotate at half the speed.

In addition to the basic Gear, there are other drive train components which have gear-like behavior.

28.2.1. GearBox

A gear box is a gear-like connector that has a collection of gear ratios that it can switch between. It is created from a vector of gear ratios and provides methods for changing the currently selected gear.

agx::RealVector gearRatios;
gearRatios.push_back(agx::Real(10));
gearRatios.push_back(agx::Real(7));
gearRatios.push_back(agx::Real(5));
gearRatios.push_back(agx::Real(3.5));
gearRatios.push_back(agx::Real(2));
gearRatios.push_back(agx::Real(1));
agxDriveTrain::GearBoxRef gearBox = new agxDriveTrain::GearBox(gearRatios);

gearBox->setGear(0);

The above example creates a gear box with six gears with decreasing gear ratios, i.e., increasing output shaft velocity, and set the current gear to the first one.

28.2.2. SlipGear

A gear with a configurable compliance. Increasing the compliance will cause the gear to slip more under load.

28.2.3. HolonomicGear

A regular Gear uses a nonholonomic constraint to maintain the velocity relationship, which means that small differences in angle may accumulate over time. The HolonomicGear uses a holonomic constraint instead, which ensures that the two connected shafts never slip.

28.2.4. MultiGear

A gear that allows for multiple connected shafts, each with its own gear ratio. Whenever one of the connected shafts rotate a hidden internal shaft will rotate with a velocity corresponding to the gear ratio configured for that connected shaft. All other connected shafts will then rotate along with the internal shaft with the velocity that corresponds to their respective gear ratio.

A MultiGear only support connections on the output side.

../_images/agxDriveTrain_MultiGear.png

28.2.5. TorqueConverter

The torque converter is a viscous coupling between two rotating axes. When there is a velocity ratio between the incoming shaft and the outgoing there will be a torque multiplication. The incoming shaft rotates a pump which accelerates a fluid. The fluid will accelerate a turbine which is connected to the outgoing shaft.

The torque converter is created simply as:

TorqueConverterRef tc = new TorqueConverter();

When the torque converter is created it is set up with default values, for what should be a generic torque converter. This means that after creating it, it can be connected to the drive train and used directly.

The torque converter contains a lock that can be enabled to lock it so it will have the same input and output velocities.

tc->enableLockUp(true);

This lock should be disabled when switching gear, suddenly increasing velocity or when braking.

28.2.5.1. Torque converter characteristics

The multiplication you get from a specific torque converter depends on the internal construction of the pump and the turbine. The torque converter has two important tables that define its behavior; the geometry factor table and the efficiency table.

The torque needed to rotate the pump is calulated using the geometry factor table, \(\xi(\nu)\), which depends on the velocity ratio between the turbine and the pump: \(\nu = \omega_{t} / \omega_{p}\). The pump torque is calculated as

\[M_{p} = \xi(\nu) \rho d_{p}^{5} \omega_{p}^{2},\]

where \(\rho\) is the fluid density and \(d_{p}\) the pump diameter, parameters that can also be modified to change the torque converter behavior. The geometry factor table can bet set with the following method:

TorqueConverter::setGeometryFactorTable(const agx::RealPairVector& velRatio_geometryFactor);

The efficiency table \(\psi(\nu)\) determines the amplification of the output torque on the turbine side. The torque is calculated as

\[M_{t} = \psi(\nu) M_{p}.\]

The efficiency table can be set using this method:

TorqueConverter::setEfficiencyTable(const agx::RealPairVector& velRatio_efficiency);

28.3. Engine

An engine is a Unit that is a source of power in a drive train. There are three types of engines: torque curve based, fixed velocity based and the combustion engine.

28.3.1. Torque curve engines

Torque curve engines uses a torque curve to determine the maximum available torque for the current RPM and a user controlled throttle to select a fraction of that available torque to actually apply. The Engine class is a torque curve engine. It is used as follows:

agxDriveTrain::EngineRef engine = new agxDriveTrain::Engine();
agxPowerLine::PowerTimeIntegralLookupTable* torqueCurve =
    engine->getPowerGenerator()->getPowerTimeIntegralLookupTable();
torqueCurve->insertValue(rpm0, torque0);
torqueCurve->insertValue(rpm1, torque1);
torqueCurve->insertValue(rpmN, torqueN);
engine->setThrottle(throttle);

Every time step the engine does a lookup into the torque table to find the maximum available torque for the current RPM. It then scales the maximum torque with the current throttle, a value between 0 and 1, to find the torque to apply this time step. The engine uses piecewise linear interpolation for lookups between the inserted values, and extrapolation of the first two or last two values for lookups outside of the torque curve domain.

An Engine has an idle RPM and the power generator has a corresponding minimum torque. When the engine is below the idle RPM, then the power generator will apply at least the minimum torque to reach the idle RPM.

Another torque curve engine is the PidControlledEngine. It inherits from Engine and by default behaves almost the same. The added functionality it provides is an ignition used to start and stop the engine and the ability to control the throttle automatically, for example to maintain a target RPM. Specific throttle controllers are created by inheriting from ThrottleCalculator. Provided with agxDriveTrain is RpmController, which is a PID controller that tries to maintain a target RPM.

engine = new agxDriveTrain::PidControlledEngine();
controller = new agxDriveTrain::RpmController(engine, targetRpm, pGain, dGain, iGain, iRange);
engine->setThrottleCalculator(controller);
engine->ignition(true);
// Don't forget to create the torque curve as well.

Idle RPM works differently for a PidControlledEngine compared to the base Engine. If a ThrottleCalculator has been set then that has full control over the throttle. If a ThrottleCalculator has not been set then the PidControlledEngine will use setGradient to force the engine RPM to reach the idle RPM.

28.3.2. Fixed velocity engine

The fixed velocity engine uses a velocity constraint to maintain the target velocity. This type of engine can be used when the expected velocity of the engine is known and any amount of torque is allowed to reach that velocity.

28.3.3. Combustion engine

The combustion engine calculates the torque directly from the current engine velocity and some known engine parameters, at each time step. This means that no torque curve needs to be set for this engine.

To create a combustion engine, the displacement volume of the engine must be known. This is the total volume the engine pistons sweeps as they move. It can be calculated from the bore, \(B\), and stroke, \(S\), length as follows

\[V_D = \frac{\pi B^2}{4} S N_{cyl},\]

where \(N_{cyl}\) is the number of engine cylinders. Note that the displacement volume must be in cubic meters, not liters.

The combustion engine is created and started as:

agxDriveTrain::CombustionEngineRef engine = new agxDriveTrain::CombustionEngine(displacementVol);
engine->setEnable(true);

Note that the combustion engine must be enabled to start it. To change the velocity of the engine the throttle can be set between 0 and 1, where 0 means idle and 1 full throttle. After being created the engine is at 0 throttle.

engine->setThrottle(throttle);

The engine has several other parameters that can be set and all of these are set to a default value when the engine is created. These parameters can be changed, but it is not necessary if one is not interested in the details of the engine control. All parameters that can be set for the combustion engine are listed and described below.

Parameter

Method

Description

Throttle

setThrottle

Percentage of open throttle. Value between 0 and 1.

Throttle Angle

setThrottleAngle

Set the angle of the throttle plate, instead of the percentage it is open

Idle Throttle Angle

setIdleThrottleAngle

The minimum angle the throttle plate can have when engine is running

Max. Throttle Angle

setMaxThrottleAngle

The maximum angle the throttle plate is allowed to open

Throttle Bore

setThrottleBore

Diameter of throttle plate

Inlet Volume

setInletVolume

The volume of the inlet manifold of the engine

Nr. Revolutions Per Cycle

setNrRevolutionsPerCycle

Should have value 1 for two-stroke engine and 2 for four-stroke

Volumetric Efficiency

setVolumetricEfficieny

How efficient the engine moves fuel and air in and out of the cylinders. Value between 0 and 1.

Discharge Coefficient

setDischargeCoefficient

The discharge coefficient of the flow past the throttle. Value between 0 and 1.

28.4. Electric motor

An electric motor is a Unit that, similar to an engine, is a source of power in a drive train. It simulates the conversion of electrical energy to mechanical energy.

When creating an electrical motor one must first know the resistance, inductance, torque constant and back electromotive force (EMF) constant of the motor. The torque constant, \(\alpha\), is related to the torque, \(\tau\), and current, \(I\), as follows

\[\tau = \alpha I.\]

The EMF constant, \(\beta\), is related to the back EMF, \(V\), and the angular velocity of the motor, \(\omega\), as follows

\[V = \beta \omega.\]

For an ideal motor \(\alpha = \beta\). However, if we have additional energy losses in the motor then \(\beta \leq \alpha\). This happens at high current since energy in the form of heat is dissipated in the armature of the motor, and we thus get less mechanical energy out than electrical energy in.

When the motor is created the input voltage to the motor is by default set to zero, and thus it must be set to some other value to start the motor.

agxDriveTrain::ElectricMotorRef motor = new agxDriveTrain::ElectricMotor( resistance, torqueConstant,
                                                                          emfConstant, inductance );
motor->setVoltage( voltage );

The voltage can be set at each time step to regulate the angular velocity of the motor.

28.5. Clutch

A clutch is a Connector with a configurable efficiency and torque transfer constant. The efficiency is a value between 0 and 1 where 0 means no torque transfer and 1 means a rigid coupling. The torque transfer constant define the shape of the torque transfer curve as the efficiency is changed between 0 and 1, where a larger constant leads to a faster increase in torque as the efficiency is increased.

28.6. Differential

A differential is a Connector that distributes toque evenly over multiple output shafts in such a way that the angular velocity of the input shaft is the average of the velocities of the output shafts. The differential can be locked, forcing all outputs to rotate at the same speed. There is also a limited slip torque version of the lock, which causes only a limited amount of torque to be transferred between outputs in order to maintain equal velocity of the output shafts.

28.7. Connecting a hinge constraint

To connect the powerline to a hinge constraint we use the RotationalActuator class found in the agxPowerLine namespace. An Actuator is a powerline component that transfers motion between a powerline unit and a regular AGX constraint. Assuming there exists a wheel body attached to a chassis body using a hinge named hinge, we can drive that wheel with the drive train using the following code.

agxPowerLine::RotationalActuatorRef axle = new agxPowerLine::RotationalActuator(hinge);
shaft1->connect(axle);

28.8. Connecting a wire winch to a drivetrain

A agxWire::WireWinchController is a class that can winch in/out wire using a brake and a motor. A WireWinchController is a linear constraint, meaning it operates using a linear force specified in Newton (N). A winch is usually a rotating object with a certain effective radius (depending on how much wire is spooled in). To model a torque driven winch one need to connect a rotational power source such as a motorized Hinge or a Engine.

As the winch is linear and a motor/hinge is rotational, we need to transform rotational work to linear work. This is done using a agxPowerLine::RotationalTranslationalHolonomicConnector. We also need to connect the connector to a winch and this is done using a agxPowerLine::WireWinchActuator.

We will then end up with a powerline system that looks like:

Hinge---> Shaft ---> RotationalTranslationalHolonomicConnector ---> WireWinchActuator ---> Winch

Below is a sample code snippet that will create this system:

// Assume we have a pointer to a winch object with a routed wire.

// First create a shaft that will transfer rotation between the motorized hinge and the connector below
auto shaft = new agxDriveTrain::Shaft();
auto winch_socket = new agxPowerLine::RotationalTranslationalHolonomicConnector();

// The effective rotation of the "winch" can be specified here
// This will affect the ratio between rotational motion of the hinge and the linear motion of the winch
// A larger radius leads to a higher speed and less force
winch_socket->setShaftRadius( radius );

// Connect the shaft with the winch_socket
shaft->connect( winch_socket );
// Set some small inertia of the shaft. This is the inertia of the rotating drum.
shaft->setInertia( 1e-4 );

// Add the shaft to the powerline
power_line->add( shaft );

// Now create a constraint that will be attached to the shaft rigidbody (1-dimensional)
// First we need to orient the Hinge so that it rotates in the direction of the shaft body
auto frame = new agx.Frame()
frame->setLocalRotate( agx::Quat( agx::Vec3::Z_AXIS(), shaft->getRotationalDimension()->getWorldDirection())  );

// Next we create the hinge
auto winch_hinge = new agx::Hinge( shaft->getRotationalDimension()->getOrReserveBody(), frame );

// We will initially enable the lock of the hinge and disable the motor.
// If we want to winch, we just disable the lock and enable the motor with a target speed.
winch_hinge->getMotor1D()->setEnable( false );
winch_hinge->getMotor1D()->setSpeed( 0 );

// Remember a Lock1D is NOT a brake. It will work as a spring if you violate the target position.
// So either you have to set the position of the lock to avoid a "springback" or, you can use the friction controller
winch_hinge->getLock1D()->setEnable( true );
simulation->add( winch_hinge );

// Finally we create an actuator that will transfer the linear motion from the winch socket to the winch.
auto winch_actuator = new agxPowerLine::WireWinchActuator( winch );
winch_socket->connect( winch_actuator );
power_line->add( winch_actuator );

For a more complete example of this, see the python script data/python/torque_driven_winch.agxPy.