Vehicle Dynamics
The Vehicle Dynamics extension provides tools for creating vehicle simulations that include tire, engine, clutch, transmission and suspension models.
Prerequisite
To use the full feature set of samples, tools and utilities for the vehicle dynamics simulation, the vehicle extension must be enabled in the Window > Extensions window. Search for the omni.physx.vehicle extension and enable it.
Quickstart tutorials
This section will present two step-by-step guides on how to create a PhysX based vehicle in Omniverse USD Composer. These guides offer a way to quickly get something to play with before diving into details. To read detailed documentation on the topic, read the next section.
Vehicle Dynamics Introduction
The Vehicle Extension provides some sample scenes that can be loaded quickly to see how the vehicle drives and works in Omniverse USD Composer.
Open the Physics Demo Scenes: Window > Simulation > Demo Scenes
In the Physics Demo Scenes Tab, click on the Vehicle Demos list to show the list of available samples.
As an introduction, select the Vehicle sounds sample and click Load scene.
If you have a gamepad connected to your PC, and would like to drive the vehicle with it, click on the settings icon in the top left corner of the Viewport window. Then, uncheck the Gamepad Camera Control setting. This allows the gamepad to control the vehicle, instead of the camera. If you would prefer to control the vehicle with the keyboard arrow keys, this step can be skipped.
If the omni.physx.camera
extension is enabled, a special camera that follows the vehicle can be added. Select the Vehicle primitive in the Stage window. Right click on the Vehicle, cursor over the Add menu, then the Cameras menu and select the Follow Look menu item.
A camera will appear in the Viewport. To view the scene through that camera, click on the camera icon in the top left corner of the Viewport window, click on the Cameras button and select the VehicleLookFollowCamera0. For additional information on the camera extension and how to tune all of the camera settings, please refer to the PhysX Cameras documentation.
This demo plays engine and tire sounds interactively as you control the vehicle. To hear it, make sure your PC audio is not muted and is set to a reasonable volume. Press the Play button on the left side of Omniverse USD Composer to start the simulation.
If you are using a gamepad, use the right trigger to accelerate, the left trigger to brake and the left analog joystick to steer the vehicle left and right. If you are using a keyboard, use the up arrow key to accelerate, the down arrow key to brake and the left and right arrow keys to steer the vehicle. Press the Stop button to end the simulation.
Creating a Vehicle Using the Vehicle Wizard
Introduction
The physical simulation of a vehicle requires many components and settings that must be created and tuned. To make the process a bit easier, Omniverse USD Composer provides a Vehicle Wizard that asks for some initial parameters as inputs and creates a whole vehicle setup as a result. If the first vehicle created has to be changed, it can be deleted and the Vehicle Wizard settings can be adjusted to try again.
Alternatively, Omniverse USD Composer provides a couple of Vehicle Demos in the Physics Demo Scenes that can be used as a starting point for a vehicle simulation. The Setup demos in particular show vehicles where all the pieces are put together (through a script). One of those demos uses a Basic Drive setup another uses a Standard Drive setup, for example. The differences between these two types are discussed in the Vehicle Wizard Basic Page documentation, below.
Vehicle Wizard Description
The Vehicle Wizard can be opened through the Create > Physics > Vehicle menu command.
The Vehicle Wizard contains three pages. The first asks for the basic dimensions and configuration of the vehicle, the second sets the dimensions of the tires and other wheel and suspension related settings. The last page provides a check list of optional Next Steps to complete the setup of the vehicle and its physics.
The vehicle created by the wizard will be oriented according to Create’s coordinate frame. If Z-up is selected, the X or Y axes can be the forward direction. If Y-up is selected, the X or Z axes can be forward. The Vehicle Wizard will create a PhysicsScene primitive with the PhysxVehicleContextAPI applied which will reflect the chosen configuration. However, if there already exists a physics scene primitive with PhysxVehicleContextAPI applied in the stage, its vertical axis and longitudinal axis information will be used to orient the new vehicle.
Basic Page
The Vehicle Prim panel allows to specify the path of the prim that should be used as the vehicle prim. The vehicle prim is the root of a vehicle hierarchy containing all parts that move with the vehicle. This option can be considered, if there is a vehicle render asset available and if the goal is to directly apply vehicle related properties to the prims of that asset to turn it into a vehicle simulation asset. It has to be noted that the specified vehicle prim needs to be a UsdGeomXform. Also, see Authoring the Vehicle’s Rendered Mesh for some recommendations on stage setup and how to arrange the prims of the asset. If no vehicle prim is defined, the wizard will create a prim (and child prims for wheels etc.). The buttons Selected and Clear are helpers to allow to pick the path of the currently selected prim or to clear the path respectively.
In the Chassis Box panel, enter the Length, Width and Height in the same units that are being used in Omniverse USD Composer to model the world. These dimensions will be used to compute the mass distribution, or moments of inertia, of the vehicle. Furthermore, the dimensions will influence where the wheels will be placed (unless the wheel geometry is scanned or the wheel attachment prims are specified explicitly). If no vehicle prim has been defined, the dimensions will also be used to create a collision box that should contain most of the vehicle mesh geometry. The collision box that is created by the wizard can be deleted and replaced with a more form fitting representation later, if desired. However, these inputs are still required to compute the vehicle’s basic mass properties.
Enter the weight of the vehicle in the Mass edit box if you want to deviate from the automatically computed value. Use the same weight units as defined in the stage.
The forward (longitudinal) direction of the vehicle can be selected from the Longitudinal Axis drop down list. If the prim with PhysxVehicleContextAPI applied exists on the stage, the Longitudinal Axis drop down will be disabled and the longitudinal axis specified in PhysxVehicleContextAPI will be displayed. If a longitudinal direction was not previously selected, the available options will be presented.
An option to automatically fill in most of these settings is available by selecting a set of prims from the stage that represent the chassis and then pressing the Scan button. Make sure to define the Longitudinal Axis as desired prior to running the scan. The Vehicle Wizard will fit an axis aligned bounding box to the selected prims and fill in the dimensions settings. The mass will get adjusted too unless the field was previously overridden. The bounding box will also be used to define the vehicle position (if no vehicle prim is specified) and for computing the vehicle’s center of mass. Prims have a purpose that describes what they are used for, such as render, guide, default and proxy. Only render and default prims are scanned. Also, only geometric meshes and shapes can be used to fit a bounding box. Note that selecting the vehicle prim and scanning the chassis box are separated because the vehicle prim does not have to be close to the chassis box and not all render meshes or geometry under the vehicle prim are good candidates to be included in the bounding box computation for the chassis box.
The Drive panel asks for one of three methods to propel the vehicle: Standard, Basic or None.
The Number of Axles edit box sets the number of tire pairs on the vehicle. The tire settings are tuned on the next page.
Press the Next button to access these settings. Alternatively, the Create button can be pressed to use the Axle Page’s default settings to create the vehicle. Press Reset at any time to reset the wizard settings to their default values (this will also clear fields overridden by the user and return to computing those values automatically).
Property |
Description |
---|---|
Path |
The path to the prim that should be used as the vehicle prim (leave empty to have the wizard create the prim) |
Selected Button |
Use the path of the currently selected prim for the Path property |
Clear Button |
Clear the content of the Path property |
Length |
The longitudinal dimension of the vehicle chassis in world units |
Width |
The lateral dimension of the vehicle chassis in world units |
Height |
The vertical dimension of the vehicle chassis in world units |
Mass |
The weight of the entire vehicle, in units as defined in the stage |
Longitudinal Axis |
The longitudinal (forward) direction of the vehicle |
Scan Button |
Computes an axis aligned bounding box around the selected prims and fills in the dimensions and mass settings automatically. |
Type |
Selects which propulsion model is used to generate tire torques (Standard, Basic, None) |
Horsepower |
For the Standard and Basic drive type, specifies how much power the engine can generate at its peak |
RPM |
For the Standard drive type, specifies the maximum revolutions per minute the engine can reach |
Number of Gears |
For the Standard drive type, specifies the number of gears the transmission has. |
Tank Mode |
For the Standard drive type, specifies whether special wheel constraints should be added such that the wheels on each side emulate a tank track. This will also add special controller attributes to set the thrust on each track. |
Number of Axles |
Specifies the number of pairs of tires the vehicle has. |
Create Shareable Components |
Vehicle components like wheel, tire, suspension, engine etc. will each get their own prim |
Use Ackermann Steering Correction |
The wheels on the first axle can have Ackermann correction applied. The inner wheel will turn more than the outer wheel when following the path around a curve. This avoids wheels having to slip sideways to stay on the path. |
Reset Button |
Reset the wizard settings to their default values |
Create Button |
Create a vehicle simulation using the current settings |
Next Button |
Go to the Axles page |
Standard Drive
The Standard drive type utilizes an engine and transmission to transfer torque to the driven tires. When using this Drive Type, enter the maximum engine Horsepower, the maximum engine RPM and the Number of Gears in the transmission.
The vehicle engine will be configured to follow an horsepower versus engine RPM curve that is defined by the following reference points:
RPM |
Horsepower (HP) |
---|---|
0 |
80% of max HP |
33% of max RPM |
100% of max HP |
max RPM |
80% of max HP |
This power curve outputs peak horsepower when the engine reaches a third of its maximum RPM and drops off to 80% at engine idle and max RPM. This curve is not very realistic, but it generates more power at idle for better acceleration from rest.
The Number of Gears specifies how many gears are in the transmission. The top gear is always 1:1 and the 1st gear ratio is set to the same value as the number of gears, 5:1 in a transmission with 5 gears, for example. The remaining gears evenly reduce the gear ratios between the 1st gear and the top gear. The final gear ratio is set to 4:1.
Gears scale the torque generated by the engine before it is applied to the tires. However, the higher the gear ratio, the sooner the transmission must shift up to the next gear before the engine reaches its maximum RPM. Heavier vehicles require higher gear ratios to generate more tire torque to accelerate but require additional gears and more time shifting to compensate.
The vehicle’s top speed will be determined by the RPM and to some degree by the Horsepower setting, while the vehicle’s acceleration profile will be controlled by the Number of Gears and Horsepower setting. If increasing the Horsepower does not increase the vehicle acceleration, then it is likely that the driven tires are spinning or burning out. To further increase the vehicle acceleration, the tire longitudinal stiffness or friction will need to be increased.
Basic Drive
The Basic drive type works by simply setting a maximum torque that is applied to the driven tires. No engine or transmission is created. The torque is scaled by the amount of throttle applied. The input device is also used to control the steer angle of the tires that steer. This Drive Type is useful for simulating electric vehicles. The maximum torque is computed from the Horsepower setting (and the RPM value which is kept locked when this drive type is selected: Horsepower * 7120 / RPM).
No Drive (None)
When the None drive type is selected, no tire torques are passed to the tires by the vehicle. The tire torques and steer angles are set manually, instead. This allows customized user control of each tire independently. This can be useful for robotics applications, for example, where tires may be rotated in opposite directions to spin the robot in place.
Axles Page
The Axles panel is used to specify which tires can steer in the Standard and Basic drive types and how much those tires steer. Tire torques are passed to all the tires that have the Driven check box selected. These settings are disabled for the, None drive type. Check the front axle for front wheel drive, check the rear axle for rear wheel drive, or check both axles for all wheel drive. If Tank Mode was enabled, it will not be possible to set the steer values.
The Weight Distribution edit box specifies the percentage of the vehicle weight that rests on each axle. Best results are observed when the weight is evenly distributed, with slight adjustments. The percentages should all sum to 100%, but if they do not, each percentage will be normalized.
The Suspension Damping is used to control the bounce of the vehicle after it is disturbed, like going over a bump. A normal value of 0.3 is the default. This setting causes the vehicle to bounce once before settling. Higher values damp out oscillations faster. A setting of 0.7 causes the vehicle to settle without a single oscillation. For a bouncy ride, try settings between 0.1 and 0.3.
Scan Selected Prims buttons labeled Left and Right are provided to fit an axis aligned bounding box to the selected prims. The bounding box will be used to measure and automatically fill in the Radius, Width and Mass settings for each of the tires scanned. The center of the bounding box will also be used to position the wheel (unless a wheel attachment prim was specified explicitly). Just like the chassis box on the Basic Page, only render and default purpose prims are scanned and only geometric meshes and shapes can be used to fit a bounding box. Make sure to define the Longitudinal Axis on the Basic Page as desired prior to running the scan. Once a tire is scanned, its dimensions will appear below the Default wheel settings in the Wheels panel.
Select Wheel Attachment buttons labeled Left and Right are provided to get the path of the currently selected prim and use it as the wheel attachment prim. The wheel attachment prim is the prim that will take on the position and orientation of the wheel as it spins, steers and moves up and down along the suspension while simulating. The wizard will use the position of the specified wheel attachment prim to define the reference position of the suspension. It has to be noted that the specified wheel attachment prim needs to be a UsdGeomXformable. If no wheel attachment prim is defined, the wizard will create a prim. Once a wheel attachment prim is selected, a corresponding entry will appear below the Default wheel settings in the Wheels panel.
Inside the Wheels panel on the Axles page, select the tire Tire Type to use. The racing Slicks are stickiest on smooth surfaces. Summer tires provide a good grip on smooth, dry surfaces while All Season tires have the least grip on smooth, dry surfaces. The Enable Collisions check box is provided to generate collision objects for the tires themselves (note: will be disabled if any wheel attachment prim was specified). This is useful for open wheeled vehicles, for example, but requires filtering and distinction between geometry to collide against and geometry to drive on. Also note that if the chassis collision box encloses the tires, performance can be improved by disabling the tire collisions.
The Default tire Radius and Width, entered in the same units used to specify the chassis dimensions, are used to set the size of the tire used in the tire physics and tire collision detection. The Mass includes the wheel and tire. Any wheels that were scanned in the Axles panel will be presented below the Default settings (the same goes for selected wheel attachment prims). Any wheels that are not scanned will use the defaults. If a wheel attachment prim was selected, the corresponding entry will show the path of the prim in the Path field.
Press, the Back button to re-adjust the Basic page settings. Changing the number of axles will clear all scanned wheels and selected wheel attachment prims. The Create and Reset button behave the same as on the Basic Page.
Property |
Description |
---|---|
Steer Angle |
The maximum angle the tire can rotate to one side, in degrees. |
Driven |
When checked, the tires on this axle receive a drive torque in the Standard or Basic drive types. |
Weight Distribution |
Specifies the percentage of the vehicle weight supported by this axle. The percentages should sum to 100% but will be normalized if they do not. |
Suspension Damping |
The “damping ratio” of the shock absorbers, from 0 to 1. A value of 0.3 is normal, a smaller number yields more bounce, larger is more rigid. |
Left Button (Scan) |
Computes an axis aligned bounding box around the selected prims and fills in the Radius, Width and Mass settings for the left wheel on the specified axle. |
Right Button (Scan) |
Same as Left Button but applying to the right wheel on the specified axle. |
Left Button (Select) |
The path to the prim that should be used as the wheel attachment prim (leave empty to have the wizard create the prim) |
Right Button (Select) |
Same as Left Button but applying to the right wheel on the specified axle. |
Tire Type |
The type of tire to use on the vehicle, which principally sets the tire friction. |
Enable Collisions |
When checked, collision objects for the tires will be created. |
Query Type |
The type of scene query to use for detecting collision of the wheel with the ground surface. Raycast is more efficient but less precise than Sweep. Since Raycast is using one ray per wheel only, collision with a bump etc. might not get detected immediately or not at all. |
Default Radius |
The vertical size of the tire from its center to an edge in world units |
Default Width |
The lateral size of the tire from edge to edge in world units |
Default Mass |
The mass of the wheel and tire, in units as defined in the stage |
# Left |
The Radius, Width and Mass, in world/stage units, of scanned wheels on the left side of the specified axle. Unscanned wheels will use the Default settings. Path will show the path of the prim to use as the wheel attachment prim (leave empty to have the wizard create the prim). |
# Right |
Same as # Left but applying to the right wheel on the specified axle. |
Reset Button |
Reset the wizard settings to their default values |
Create Button |
Create a vehicle simulation using the current settings |
Back Button |
Return to the Basic page |
Next Button |
Go to the Next Steps page |
Next Steps Page
Once the Vehicle Wizard has set up the prims to run a vehicle simulation, there is still more work to do. A ground surface to drive on is needed and the physics settings of the vehicle can be tuned. The Next Steps page will be updated and provides additional detail.
Property |
Description |
---|---|
Reset Button |
Reset the wizard settings to their default values |
Create Button |
Create a vehicle simulation using the current settings |
Back Button |
Return to the Axles page |
Vehicle Wizard Collision Groups
The Vehicle Wizard does not create a drivable surface, but it does create collision groups to prevent the wheels of the car from colliding with the chassis, for example. One of the collision groups created is called GroundSurfaceCollisionGroup, which is set up to prevent collisions with objects in the VehicleWheelCollisionGroup. This prevents the wheels from colliding with the ground surface (instead, tire collisions with the surface are detected using ray casts or sweeps). If Enable Collisions was ticked, be sure the driving surface is a member of the GroundSurfaceCollisionGroup.
To add a simple, drivable surface for testing, select Create > Physics > Ground Plane. If Enable Collisions was ticked, the surface must be added to the GroundSurfaceCollisionGroup. Select the GroundSurfaceCollisionGroup prim on the stage. In the Property panel, find the Collision Group section and add the created collision plane under Includes. When using custom drivable surfaces, ensure they are all members of the GroundSurfaceCollisionGroup.
Animating the Vehicle’s Rendered Mesh
If the Vehicle Wizard operates on a render mesh hierarchy directly (by defining the vehicle prim and the wheel attachment prims), the render meshes will animate automatically along with the simulation. If the wizard was configured to create a separate simulation prim hierarchy instead or if one of the samples is used as a starting point, it is up to the user to link the render meshes to this simulation representation. Select the Chassis root primitive, created as described in the Authoring the Vehicle’s Rendered Mesh section, above, and child it to the /WizardVehicle/Vehicle primitive, if the vehicle was created with the Vehicle Wizard, or the /Vehicle primitive if a Vehicle Sample was loaded. The Chassis transform may need to be moved so the rendered vehicle lines up with the physics box as much as possible. The rendered vehicle mesh should now move around with the vehicle.
The Vehicle Wizard creates a box to visualize the chassis when no other mesh is connected to the vehicle. It can be removed by selecting the /WizardVehicle/Vehicle/ChassisRender primitive on the stage and deleting it or hiding it, by clicking on the eye icon, next to it.
Aligning the Tires with the Vehicle
If the Vehicle Wizard tire scan or wheel attachment selection feature was not used to measure the position and radius of each tire, the physics representation of the tires will not align properly with the rendered, mesh representation. Move the physics representation of the tires by selecting each of them in the Viewport window and then dragging them into position.
For improved accuracy, the X, Y and Z position of each wheel in the rendered mesh hierarchy can be copied into the physics Position transforms. The Vehicle Wizard primitives that need updating are named, “/WizardVehicle1/Vehicle/LeftWheel1References”, “/WizardVehicle1/Vehicle/RightWheel1References”, “/WizardVehicle1/Vehicle/LeftWheel2References”, “/WizardVehicle1/Vehicle/RightWheel2References” etc. The Vehicle Sample wheels are named “FrontLeftWheel”, “FrontRightWheel”, “RearLeftWheel” and “RearRightWheel”.
Adjusting the Tire Radii
Some vehicles have different tire radii for the front and rear tires. If the Vehicle Wizard tire scan feature was not used, only a single tire radius is used for all of the tires. The tire radii that are different must be manually adjusted. Find the wheel components created by the wizard and adjust their tire radii. The wheel components are called “/WizardVehicle1/LeftWheel1”, “/WizardVehicle1/RightWheel1”, “/WizardVehicle1/LeftWheel2” and “/WizardVehicle1/RightWheel2” (or the “/WizardVehicle1/Vehicle/__Wheel_References” prims in case the wizard was told to not create shareable components). Each have a radius edit box that can be adjusted.
The vehicle wheels might also have a render and potentially a collision representation (depending on how the Vehicle Wizard was configured) whose radii should be modified, too. Click the “/WizardVehicle1/Vehicle/LeftWheel1References/Render” primitive (or the appropriate primitive for the tire that must be changed), select the Property panel and scroll to the bottom to find the radius.
Likewise, to update the collision tire radius, find the “/WizardVehicle1/Vehicle/LeftWheel1References/Collision” primitive (or the appropriate primitive for the tire that must be changed), select the Property panel and scroll to the bottom to find the radius.
Animating the Wheels
If it is satisfactory to allow the physics to animate the wheels and tires, all of the rotating wheel and tire parts of the rendered mesh can simply be linked to the “/Vehicle/LeftWheel1References”, “/Vehicle/RightWheel1References”, “/Vehicle/LeftWheel2References”, “/Vehicle/RightWheel2References” etc. primitives. If the wheel attachment prims were specified in the Vehicle Wizard, this will be the case already.
However, if it is preferred to have non-rotating wheel parts that steer and compress, but not rotate with the tires, then a more sophisticated approach is required and the more complicated hierarchy described in Authoring the Vehicle’s Rendered Mesh and animated in Copying Transforms is required.
Copying Transforms
The position and orientation of the physics representation of the wheels must be broken apart into three components and copied into the rendered mesh representation after each simulation step, or update.
This can be accomplished using a Python script, for example. The exact math to do this is different for every vehicle and suspension configuration, but the two very common configurations are provided as an example in the following script for a double wishbone and a swing arm configuration. The front tires use a double wishbone and simply move up and down to compress the tire. The rear tires use a swing arm configuration. The angle of the swingarm is calculated from the compression of the tires and the swing arm radius. This code is used to load a USD file, register for an update callback, and then animate the suspension.
1 import math
2
3 import omni.kit.app
4 import omni.usd
5 import omni.physx
6 from omni.physx.bindings._physx import (
7 SimulationEvent,
8
9 VEHICLE_WHEEL_STATE_LOCAL_POSE_POSITION,
10 VEHICLE_WHEEL_STATE_LOCAL_POSE_QUATERNION
11 )
12
13 from pxr import Usd, UsdGeom, Sdf, Gf
14
15
16 # Put the name of your USD file here.
17 myStageName = "C:/Users/username/Desktop/PodWorkVehicle.usd"
18
19 myVehiclePrimName = "/World/WizardVehicle1/Vehicle"
20
21 myFrontLeftName = "/LeftWheel1References"
22 myFrontRightName = "/RightWheel1References"
23 myRearLeftName = "/LeftWheel2References"
24 myRearRightName = "/RightWheel2References"
25
26 frontLeftTirePath = myVehiclePrimName + myFrontLeftName
27 frontRightTirePath = myVehiclePrimName + myFrontRightName
28 rearLeftTirePath = myVehiclePrimName + myRearLeftName
29 rearRightTirePath = myVehiclePrimName + myRearRightName
30
31 myFrontLeftSuspensionName = "/FrontLeftSuspension"
32 myFrontRightSuspensionName = "/FrontRightSuspension"
33 myRearLeftSuspensionName = "/RearLeftSuspension"
34 myRearRightSuspensionName = "/RearRightSuspension"
35
36 frontLeftSuspensionPath = myVehiclePrimName + myFrontLeftSuspensionName
37 frontRightSuspensionPath = myVehiclePrimName + myFrontRightSuspensionName
38 rearLeftSuspensionPath = myVehiclePrimName + myRearLeftSuspensionName
39 rearRightSuspensionPath = myVehiclePrimName + myRearRightSuspensionName
40
41 myFrontLeftWheelName = "/FrontLeftWheel"
42 myFrontRightWheelName = "/FrontRightWheel"
43 myRearLeftWheelName = "/RearLeftWheel"
44 myRearRightWheelName = "/RearRightWheel"
45
46 frontLeftWheelPath = frontLeftSuspensionPath + myFrontLeftWheelName
47 frontRightWheelPath = frontRightSuspensionPath + myFrontRightWheelName
48 rearLeftWheelPath = rearLeftSuspensionPath + myRearLeftWheelName
49 rearRightWheelPath = rearRightSuspensionPath + myRearRightWheelName
50
51
52 class AnimatedVehicleClass:
53
54 def load_animation(self):
55 # Get all of the necessary prims
56 self._vehiclePrim = self._stage.GetPrimAtPath(myVehiclePrimName)
57
58 self._frontLeftTire = self._stage.GetPrimAtPath(frontLeftTirePath)
59 self._frontLeftSuspension = self._stage.GetPrimAtPath(frontLeftSuspensionPath)
60 self._frontLeftWheel = self._stage.GetPrimAtPath(frontLeftWheelPath)
61
62 self._frontLeftSuspension.CreateAttribute("xformOpOrder", Sdf.ValueTypeNames.String, False).Set(["xformOp:translate", "xformOp:orient", "xformOp:scale"])
63 self._frontLeftWheel.CreateAttribute("xformOpOrder", Sdf.ValueTypeNames.String, False).Set(["xformOp:translate", "xformOp:orient", "xformOp:scale"])
64 self._frontLeftSuspension.CreateAttribute("xformOp:orient", Sdf.ValueTypeNames.Quatf, False)
65 self._frontLeftWheel.CreateAttribute("xformOp:orient", Sdf.ValueTypeNames.Quatf, False)
66
67 self._frontRightTire = self._stage.GetPrimAtPath(frontRightTirePath)
68 self._frontRightSuspension = self._stage.GetPrimAtPath(frontRightSuspensionPath)
69 self._frontRightWheel = self._stage.GetPrimAtPath(frontRightWheelPath)
70
71 self._frontRightSuspension.CreateAttribute("xformOpOrder", Sdf.ValueTypeNames.String, False).Set(["xformOp:translate", "xformOp:orient", "xformOp:scale"])
72 self._frontRightWheel.CreateAttribute("xformOpOrder", Sdf.ValueTypeNames.String, False).Set(["xformOp:translate", "xformOp:orient", "xformOp:scale"])
73 self._frontRightSuspension.CreateAttribute("xformOp:orient", Sdf.ValueTypeNames.Quatf, False)
74 self._frontRightWheel.CreateAttribute("xformOp:orient", Sdf.ValueTypeNames.Quatf, False)
75
76 self._rearLeftTire = self._stage.GetPrimAtPath(rearLeftTirePath)
77 self._rearLeftSuspension = self._stage.GetPrimAtPath(rearLeftSuspensionPath)
78 self._rearLeftWheel = self._stage.GetPrimAtPath(rearLeftWheelPath)
79
80 self._rearLeftSuspension.CreateAttribute("xformOpOrder", Sdf.ValueTypeNames.String, False).Set(["xformOp:translate", "xformOp:orient", "xformOp:scale"])
81 self._rearLeftWheel.CreateAttribute("xformOpOrder", Sdf.ValueTypeNames.String, False).Set(["xformOp:translate", "xformOp:orient", "xformOp:scale"])
82 self._rearLeftSuspension.CreateAttribute("xformOp:orient", Sdf.ValueTypeNames.Quatf, False)
83 self._rearLeftWheel.CreateAttribute("xformOp:orient", Sdf.ValueTypeNames.Quatf, False)
84
85 self._rearRightTire = self._stage.GetPrimAtPath(rearRightTirePath)
86 self._rearRightSuspension = self._stage.GetPrimAtPath(rearRightSuspensionPath)
87 self._rearRightWheel = self._stage.GetPrimAtPath(rearRightWheelPath)
88
89 self._rearRightSuspension.CreateAttribute("xformOpOrder", Sdf.ValueTypeNames.String, False).Set(["xformOp:translate", "xformOp:orient", "xformOp:scale"])
90 self._rearRightWheel.CreateAttribute("xformOpOrder", Sdf.ValueTypeNames.String, False).Set(["xformOp:translate", "xformOp:orient", "xformOp:scale"])
91 self._rearRightSuspension.CreateAttribute("xformOp:orient", Sdf.ValueTypeNames.Quatf, False)
92 self._rearRightWheel.CreateAttribute("xformOp:orient", Sdf.ValueTypeNames.Quatf, False)
93
94 rearRightWheelPosition = self._rearRightTire.GetAttribute("xformOp:translate").Get()
95 self._rearWheelRestHeight = rearRightWheelPosition[2]
96 self._swingArmRadius = rearRightWheelPosition.GetLength()
97
98 def load_stage(self, success, errorMsg):
99 if success == True:
100 self._stage = self._usd_context.get_stage()
101 self._physxInterface = omni.physx.get_physx_interface()
102
103 self.load_animation()
104
105 # Subscribe to events
106 self._physxSimEventSubscription = self._physxInterface.get_simulation_event_stream_v2().create_subscription_to_pop(
107 self._on_simulation_event
108 )
109 self._stageEventSubscription = self._usd_context.get_stage_event_stream().create_subscription_to_pop(self.on_stage_event)
110 self._updateEventSubscription = omni.kit.app.get_app().get_update_event_stream().create_subscription_to_pop(self.update)
111
112 def __init__(self):
113 self._simStarted = False
114
115 print("Loading Stage " + myStageName)
116
117 self._usd_context = omni.usd.get_context()
118
119 self._physxInterface = None
120
121 # Load the level
122 self._usd_context.open_stage(myStageName, self.load_stage)
123
124 def _on_simulation_event(self, event):
125 if event.type == int(SimulationEvent.RESUMED):
126 self._simStarted = True
127 elif event.type == int(SimulationEvent.STOPPED):
128 self._simStarted = False
129
130 def on_stage_event(self, event):
131 if (event.type == int(omni.usd.StageEventType.CLOSING)):
132 self.shutdown()
133
134 def shutdown(self):
135 self._physxSimEventSubscription = None
136 self._updateEventSubscription = None
137 self._stageEventSubscription = None
138
139 def animate(self):
140
141 # Front Left
142 wheelState = self._physxInterface.get_wheel_state(frontLeftTirePath)
143 position = wheelState[VEHICLE_WHEEL_STATE_LOCAL_POSE_POSITION]
144 rotation = wheelState[VEHICLE_WHEEL_STATE_LOCAL_POSE_QUATERNION]
145 frontLeftPosition = Gf.Vec3f(position[0], position[1], position[2])
146
147 self._frontLeftSuspension.GetAttribute("xformOp:translate").Set(frontLeftPosition)
148
149 frontLeftSuspensionRotation = Gf.Quatf(rotation[3], 0.0, 0.0, rotation[2])
150 frontLeftSuspensionRotation.Normalize()
151 self._frontLeftSuspension.GetAttribute("xformOp:orient").Set(frontLeftSuspensionRotation)
152
153 frontLeftWheelRotation = Gf.Quatf(rotation[3], 0.0, rotation[1], 0.0)
154 frontLeftWheelRotation.Normalize()
155 self._frontLeftWheel.GetAttribute("xformOp:orient").Set(frontLeftWheelRotation)
156
157 # Front Right
158 wheelState = self._physxInterface.get_wheel_state(frontRightTirePath)
159 position = wheelState[VEHICLE_WHEEL_STATE_LOCAL_POSE_POSITION]
160 rotation = wheelState[VEHICLE_WHEEL_STATE_LOCAL_POSE_QUATERNION]
161 frontRightPosition = Gf.Vec3f(position[0], position[1], position[2])
162
163 self._frontRightSuspension.GetAttribute("xformOp:translate").Set(frontRightPosition)
164
165 frontRightSuspensionRotation = Gf.Quatf(rotation[3], 0.0, 0.0, rotation[2])
166 frontRightSuspensionRotation.Normalize()
167 self._frontRightSuspension.GetAttribute("xformOp:orient").Set(frontRightSuspensionRotation)
168
169 frontRightWheelRotation = Gf.Quatf(rotation[3], 0.0, rotation[1], 0.0)
170 frontRightWheelRotation.Normalize()
171 self._frontRightWheel.GetAttribute("xformOp:orient").Set(frontRightWheelRotation)
172
173 # Rear Left
174 wheelState = self._physxInterface.get_wheel_state(rearLeftTirePath)
175 position = wheelState[VEHICLE_WHEEL_STATE_LOCAL_POSE_POSITION]
176 rotation = wheelState[VEHICLE_WHEEL_STATE_LOCAL_POSE_QUATERNION]
177
178 angle = (position[2] - self._rearWheelRestHeight) / self._swingArmRadius
179 rearLeftSuspensionRotation = Gf.Quatf(math.cos(0.5 * angle), 0.0, math.sin(0.5 * angle), 0.0)
180 self._rearLeftSuspension.GetAttribute("xformOp:orient").Set(rearLeftSuspensionRotation)
181
182 rearLeftWheelRotation = Gf.Quatf(rotation[3], 0.0, rotation[1], 0.0)
183 rearLeftWheelRotation.Normalize()
184 self._rearLeftWheel.GetAttribute("xformOp:orient").Set(rearLeftWheelRotation)
185
186 # Rear Right
187 wheelState = self._physxInterface.get_wheel_state(rearRightTirePath)
188 position = wheelState[VEHICLE_WHEEL_STATE_LOCAL_POSE_POSITION]
189 rotation = wheelState[VEHICLE_WHEEL_STATE_LOCAL_POSE_QUATERNION]
190
191 angle = (position[2] - self._rearWheelRestHeight) / self._swingArmRadius
192 rearRightSuspensionRotation = Gf.Quatf(math.cos(0.5 * angle), 0.0, math.sin(0.5 * angle), 0.0)
193 self._rearRightSuspension.GetAttribute("xformOp:orient").Set(rearRightSuspensionRotation)
194
195 rearRightWheelRotation = Gf.Quatf(rotation[3], 0.0, rotation[1], 0.0)
196 rearRightWheelRotation.Normalize()
197 self._rearRightWheel.GetAttribute("xformOp:orient").Set(rearRightWheelRotation)
198
199 def update(self, event):
200 if (self._simStarted):
201 self.animate()
202
203 animatedVehicle = AnimatedVehicleClass()
Driving the Vehicle
After the Vehicle Wizard has created the vehicle, try driving it around a bit to see how it behaves. The vehicle can be controlled using the keyboard or a connected gamepad.
Every vehicle has some additional properties to control it. On the stage, find and select the vehicle to adjust. In the Property panel, scroll down to the Vehicle Controller Settings section. To select which vehicle to control using the input system, check or un-check the Input Enabled check box. To enable the mouse, check the Mouse Enabled check box. If it is undesirable to automatically go into reverse when the brake is held while at rest, un-check the Auto Reverse Enabled checkbox. When using a gamepad, Steering Sensitivity can be used to apply smaller steer values than the gamepad input indicates. Steering Filter Time allows the steer target to be approached over a certain span of time instead of being applied instantly.
Note that the default input handling for driving a vehicle is mainly meant to quickly test the driving behavior of a vehicle. User applications often want to control the mapping from device input to steer, brake, accelerate commands themselves as the desired control behavior is often very specific. The vehicle command attributes are described in the corresponding USD API schemas PhysxVehicleControllerAPI, PhysxVehicleTankControllerAPI and PhysxVehicleWheelControllerAPI.