Skip to content

Add a Vehicle#

This page gives the procedure to add a vehicle to the game and to ACRES Core. The procedure follows the steps that added the Polaris.

Before You Start#

The game has two vehicles: the Maxxum and the Polaris. They use one pawn class, AAcresVehiclePawn. The Polaris is the pattern for a new vehicle, because the project added it to a game that had only the Maxxum.

What a Vehicle Needs#

A vehicle has ten parts. The table gives each part with its Polaris example.

Part Function Polaris Example
Engine-free model The dynamics and the control interface in C++ without Unreal types Acres/Source/Acres/AcresUtvModel.h and .cpp
Parameters file Each parameter with its value and its source Acres/Content/Simulation/polaris.json
Pawn branch Connects the model to the Chaos body, the ground traces and the farm AcresPolaris.cpp and the bUtv branches of AcresVehicle.cpp
Equipment rig The skeletal mesh and its controls Acres/Raw/farm-equipment/polaris/, Acres/Content/Simulation/rigs/polaris.json
Sensor rig overlay The sensors of the vehicle with their mounting poses Acres/Content/Simulation/sensors_polaris.json
Agents entry The vehicle kind for -Vehicle=, -Vehicles= and -Agents= AcresAgents.cpp
Bridge messages Commands and reports on the vehicle bridge and in ROS 2 AcresRlBridge.cpp, ROS/acres_sim, ROS/acres_description
Core support The same model on a rigid chassis without Unreal Core/Source/AcresCorePolaris.h and .cpp
Tests Model checks and replay of recorded logs Tools/PolarisModel/, Core/Tests/
Documentation Model page, tutorial and reference entries Polaris Ranger Dynamics

Do the parts in this sequence. The engine-free model and its tests come first, because all other parts depend on them.

Write the Engine-Free Model#

An engine-free model is a C++ file that uses no Unreal types. The game, ACRES Core and the test tools compile the same file. The Polaris model uses the wheel, soil and energy functions of the Maxxum model again. It adds only the parts that are different.

Model Part Maxxum Function That the Polaris Uses Polaris Function
Wheel contact on soil and hard ground PrepareWheel PrepareUtvWheel
Wheel speeds and driveline AxleCarrierTorqueNm, RisingRoot, SettleWheels SolveUtvDriveline
Energy ledger FEnergyFlows, AccountChassis Same structure
Engine, CVT, gearbox, brakes StepUtvPowertrain
Steering StepUtvSteering
Drive-by-wire actuators and ULC StepDbw
Parameters SetUtvParameter, FinalizeUtvParameters
Reset ResetUtv
  1. Make Acres/Source/Acres/Acres<Name>Model.h and .cpp in the namespace AcresSim.

  2. Define a parameter structure, a state structure and a command structure.

  3. Use the shared functions of AcresVehicleModel.h for the tyres, the soil and the energy ledger.

  4. Write a function that sets one parameter from a key and a value, such as SetUtvParameter.

    The game, ACRES Core and the tools then read the parameters file through the same function.

  5. Write a function that derives the dependent values, such as FinalizeUtvParameters.

  6. Write the step functions. Keep the sequence of one physics step explicit.

    The Polaris sequence is StepDbw, StepUtvSteering, StepUtvPowertrain, PrepareUtvWheel for each wheel and SolveUtvDriveline.

  7. Write the header comments in the format of Write Documentation. The reference pages come from these comments.

Obey these rules.

  • Use SI units, and put the unit in each name, for example MassKg.
  • Cite the publication or the data source of each sub-model in a comment.
  • Give helper functions in an anonymous namespace a prefix. The unity build of Unreal joins the model files.
  • Do not allocate memory in a step function.
  • If the real vehicle has a control interface, model that interface with its message names and units.

Write the Parameters File#

The parameters file is Acres/Content/Simulation/<name>.json. In polaris.json, each parameter is an object with its source.

"wheelbase_m": {"value": 2.8702, "basis": "oem", "source": "owner_manual; product_page", "sd": 0.01}
Key Content
value The number, the boolean or the array that the model reads.
basis The type of the source: oem, dataspeed, fitted, installed, derived or estimate.
source The document or the log of the value.
sd, range, note The uncertainty and a remark.

The model reads only value. The loader reads each value with its dotted path as the key, for example geometry.wheelbase_m. An array element has an index, for example engine.torque_curve_rpm[3]. The game writes ACRES_POLARIS_UNUSED_KEY to the log for each key that the model does not know.

  1. Write the file with one block for each sub-model.

  2. Give each value its basis and its source. Do not put a number without a source in the file.

  3. Add an option for a different file and an option for single keys, such as -PolarisConfig= and -PolarisSet=.

  4. Fit the parameters that no document gives to recorded logs. Refer to Calibrate against Real Logs.

Add the Tests of the Model#

Write the tests before the pawn branch. The tools compile the model with a standard compiler in some seconds.

  1. Make a folder Tools/<Name>Model with a test program and a build.sh.

    Tools/PolarisModel is the pattern: polaris_tests.cpp contains the checks, and UtvBench.h is a small test bench with a flat reader for the parameters file.

  2. Test each sub-model: limits, signs, conservation of energy and the results at different time steps.

  3. If you have logs of the real vehicle, add extracts and a replay program.

    Tools/PolarisModel/Data contains the extracts. polaris_replay.cpp replays their commands through the model, and polaris_dbw.py fits the parameters.

  4. Build and run the tests.

    Tools/PolarisModel/build.sh
    

    Expected Result

    The script builds the programs and runs the checks. The last line for the Polaris is:

    44 passed, 0 failed
    
  5. Add the command to Tests and Regression Checklist.

WARNING

Do not connect a test tool to the real vehicle. Use only recorded logs. A command on the real drive-by-wire can move the vehicle.

Add the Pawn Branch#

AAcresVehiclePawn does the work that is the same for all vehicles. This work includes the ground traces of the wheels, the soil below each wheel and the forces on the Chaos body. It also includes the farm marks, the sensors and the logs. A vehicle adds a flag and the functions that are different. The Polaris flag is bUtv, and its functions are in AcresPolaris.cpp.

Function Thread Content
LoadPolarisConfiguration Game Reads the parameters file and the options. Copies the wheel parameters to the shared Parameters.
ResetPolaris Physics Resets the model state for a start speed.
StepPolarisControls Physics Takes the commands from the queue and steps the control interface, the steering and the powertrain.
PublishPolaris Physics Fills the telemetry and the reports of the control interface.
FlushDbwReports Game Sends the reports to the vehicle bridge and writes dbw.csv.
CreatePolarisVisuals Game Adds the colliders and loads the equipment rig.
UpdatePolarisRig Game Sets the rig controls from the telemetry.
ReadPolarisKeys, StepPolarisKeys Game, physics The keyboard as the driver of the vehicle.
  1. Add a flag for the vehicle to AAcresVehiclePawn and set it in LoadConfiguration from the agent.

  2. Add a new source file for the functions of the vehicle. Do not make AcresVehicle.cpp larger.

  3. Load the parameters. Copy the wheel layout, the mass and the inertia to the values that the shared code reads.

    The Polaris keeps the ground of the session. LoadPolarisConfiguration copies the soil block of tractor.json into its wheel parameters.

  4. Branch in AsyncPhysicsTickActor: step the controls, prepare each wheel and solve the driveline with the functions of the new model.

  5. Set the collision shapes, the spawn box in SpawnHalfExtentCm and the camera positions.

  6. Publish the telemetry of the vehicle and add its columns to the session log.

  7. Add the keyboard controls and the HUD items: the card, the key help and the vehicle label in VehicleLabel.

The physics step runs on the physics thread, and the keyboard and the rig run on the game thread. Send commands to the physics thread through a queue with an apply time, as PostDbw does. Read the state under StateMutex.

Add the Equipment Rig#

The equipment rig comes from a Blender file through the same tools as an implement. Add an Implement gives the commands.

  1. Put the Blender file, the FBX file and the vehicle data in Acres/Raw/farm-equipment/<name>/.

    The Polaris folder also contains vehicle-parameters.json, sensor-evidence.json and recorded-calibration.json.

  2. Put the origin of the rig at the middle of the rear axle on the ground. Use the FLU frame in metres.

  3. Add the asset to the export tool and the import tool in Tools/ACRE/Vehicles.

    The four Polaris finishes share one mesh. The rig map lists them as material variants, and LoadRig takes the variant name.

  4. Run the export, the import and the option -RigSelfTest.

  5. Load the rig in the visuals function. Compare the wheel centres of the rig with those of the physics.

    Expected Result

    The log contains the layout line. This is the line of the Maxxum:

    ACRES_RIG_LAYOUT wheel_centre_max_error_cm=0.000 radius_max_error_m=0.0000 wheelbase_m=2.6416 track_m=1.900 rig_mass_kg=5820 physics_mass_kg=5820.0
    
  6. Set the rig controls from the telemetry in each frame: steering, wheel roll, suspension travel and pedals.

Add the Sensor Rig Overlay#

The file sensors.json gives the default sensors. A vehicle with its own sensors has an overlay file that replaces some values. sensors_polaris.json contains the mounting poses and the models of the Polaris sensors in the frame base_footprint.

  1. Write Acres/Content/Simulation/sensors_<name>.json with only the keys that are different from sensors.json.

  2. Load the overlay for the vehicle in BeginPlay, and add an option for a different file, such as -PolarisSensorConfig=.

  3. Give the overlay a profile name. The recordings store it as the sensor profile.

Add a Sensor describes the sensor code.

Add the Agents Entry#

AcresAgents.cpp reads the vehicles of a session. Each agent has a vehicle kind.

  1. Add the name of the vehicle and its aliases to the function that normalises the vehicle kind in AcresAgents.cpp.

  2. Add the name to the three error messages that list the vehicle kinds.

  3. Add the keys of the vehicle to the table in AcresAgents.h, such as finish for the Polaris.

  4. Add the vehicle to the menu choice flag:vehicle and to the command line of the session in AcresSession.cpp.

    Expected Result

    The game starts with -VehicleDemo -Vehicle=<name>. A session with -Vehicles=maxxum,<name> has two agents, and F2 changes the vehicle.

Add the Bridge Messages#

A client controls a vehicle through the vehicle bridge. Each observation contains the keys agent and vehicle. The Polaris uses the message names, the fields and the units of the Dataspeed drive-by-wire. The ROS 2 bridge thus converts each message one to one.

  1. Add the vehicle name to the observation in AcresRlBridge.cpp.

  2. Add the command messages of the vehicle. Refuse them with a warning on a different vehicle.

  3. Add the report messages at the rate of the real vehicle.

  4. Add the vehicle to the sensor stream greeting in BeginPlay.

  5. Add the topics to the ROS 2 bridge in ROS/acres_sim, and a URDF to ROS/acres_description.

  6. Use the timeouts of the real interface. A subsystem of the Polaris stops 0.1 s after its last command.

Add a ROS 2 Interface gives the procedure for the ROS 2 packages. The Vehicle Bridge reference lists the messages.

Add ACRES Core Support#

ACRES Core runs the same model without Unreal. Core/CMakeLists.txt compiles the model files of the game and the files in Core/Source. FAcresPolaris does in plain C++ what the pawn does with Chaos. It computes the wheel traces against the terrain, the forces, the farm stamps and the step of the rigid chassis.

  1. Add the model source file to ACRES_MODEL_SOURCES in Core/CMakeLists.txt.

  2. Write Core/Source/AcresCore<Name>.h and .cpp with a class that has Init, Reset and Step.

  3. Load the parameters file with the same key function as the game, as LoadPolarisParameters does.

  4. Use the same sequence in Step as the pawn uses in the physics step.

  5. Add the vehicle to the batch class in AcresCoreBatch.h and to the Python module in Core/Python/acres_core_module.cpp.

  6. Add tests in Core/Tests, then build and run.

    Core/build.sh
    
  7. Compare ACRES Core with the game for the same commands. Core/Scripts/compare_unreal.py does this comparison for the Polaris.

Note

ACRES Core supports only the Polaris. The Maxxum and its implements run only in the game.

Update the Documentation#

  1. Add a model page in Documentation/Models with the full mathematics of the vehicle.

  2. Add a tutorial in Documentation/Tutorials for the keyboard and the control interface.

  3. Add the options, the bridge messages, the topics and the file formats to the reference pages.

  4. Add the vehicle to the Glossary and to the Changelog.

  5. Do the checks of Write Documentation.

Checklist#

Check Command or Condition
Model tests pass Tools/<Name>Model/build.sh has the exit code 0.
Portability The same script with UE_CLANG= passes.
Rig -RigSelfTest reports PASS for the rig. The layout line reports a wheel centre error near zero.
Session -VehicleDemo -Vehicle=<name> starts and the vehicle drives.
Two vehicles -Vehicles=maxxum,<name> starts and each agent has its own output folder.
Bridge A client receives observations and reports, and the vehicle obeys its commands.
Core Core/build.sh passes, and the comparison with the game agrees.
Documentation The site builds in strict mode.