Land Domain API Reference¶
Terramechanics, suspension, and tracked/wheeled vehicle APIs.
Header: jaguar/domain/land.h
SoilProperties¶
Bekker-Wong soil parameters for terramechanics.
struct SoilProperties {
Real k_c{0.0}; // Cohesive modulus (kN/m^(n+1))
Real k_phi{0.0}; // Frictional modulus (kN/m^(n+2))
Real n{1.0}; // Deformation exponent
Real c{0.0}; // Cohesion (kPa)
Real phi{0.0}; // Internal friction angle (rad)
Real K{0.0}; // Shear deformation modulus (m)
// Preset soil types
static SoilProperties DrySand();
static SoilProperties WetSand();
static SoilProperties Clay();
static SoilProperties Snow();
static SoilProperties Asphalt();
static SoilProperties Mud();
static SoilProperties Gravel();
};
Preset Values¶
| Soil Type | k_c | k_phi | n | c (kPa) | φ (deg) |
|---|---|---|---|---|---|
| Dry Sand | 0.99 | 1528 | 1.10 | 1.04 | 28 |
| Wet Sand | 5.27 | 1515 | 0.73 | 1.72 | 29 |
| Clay | 13.19 | 692 | 0.50 | 4.14 | 13 |
| Snow | 4.37 | 196 | 1.60 | 1.03 | 19.7 |
| Asphalt | 10⁶ | 10⁶ | 0.0 | 1000 | 45 |
Example¶
// Use preset
auto soil = domain::land::SoilProperties::DrySand();
// Or customize
domain::land::SoilProperties custom_soil;
custom_soil.k_c = 5.0;
custom_soil.k_phi = 1000.0;
custom_soil.n = 0.9;
custom_soil.c = 2.0;
custom_soil.phi = 30.0 * DEG_TO_RAD;
TerramechanicsModel¶
Bekker-Wong pressure-sinkage and shear-displacement model.
class TerramechanicsModel : public physics::ITerramechanicsModel {
public:
// Configuration
void set_contact_area(Real width, Real length); // m
void set_vehicle_weight(Real weight_n); // N
void set_soil(const SoilProperties& soil);
// IForceGenerator
void compute_forces(const physics::EntityState& state,
const environment::Environment& env,
Real dt,
physics::EntityForces& forces) override;
// ITerramechanicsModel queries
Real get_sinkage() const override; // m
Real get_motion_resistance() const override; // N
Real get_traction() const override; // N
Real get_slip_ratio() const override; // 0-1
// Additional queries
Real get_ground_pressure() const; // Pa
Real get_bearing_capacity() const; // Pa
bool is_mobility_limited() const; // True if sinking
};
Example¶
domain::land::TerramechanicsModel terra;
// Configure for tank tracks
terra.set_contact_area(0.63, 4.6); // Track: 63cm x 4.6m
terra.set_vehicle_weight(62000.0 * constants::G0); // 62 tonnes
// Set soil (can change dynamically based on terrain)
auto soil = domain::land::SoilProperties::DrySand();
terra.set_soil(soil);
// In simulation loop
physics::EntityForces forces;
terra.compute_forces(state, env, dt, forces);
// Check mobility
Real sinkage = terra.get_sinkage();
if (sinkage > 0.3) {
std::cout << "Warning: Vehicle stuck! Sinkage: " << sinkage << " m\n";
}
std::cout << "Motion resistance: " << terra.get_motion_resistance() << " N\n";
std::cout << "Available traction: " << terra.get_traction() << " N\n";
SuspensionUnit¶
Individual suspension unit (road wheel, spring, damper).
struct SuspensionUnit {
Real spring_k{50000.0}; // Spring stiffness (N/m)
Real damper_c{5000.0}; // Damping coefficient (N·s/m)
Real preload{0.0}; // Preload force (N)
Real travel_max{0.3}; // Maximum travel (m)
Real travel_min{0.0}; // Minimum travel (m)
Real current_position{0.0}; // Current compression (m)
Real current_velocity{0.0}; // Compression rate (m/s)
// Calculate spring-damper force
Real calculate_force() const;
// Update state
void update(Real ground_height, Real wheel_height, Real dt);
// Check limits
bool is_bottomed_out() const;
bool is_topped_out() const;
};
Example¶
domain::land::SuspensionUnit wheel;
wheel.spring_k = 300000.0; // 300 kN/m (heavy vehicle)
wheel.damper_c = 30000.0; // 30 kN·s/m
wheel.travel_max = 0.40; // 40 cm travel
wheel.preload = 10000.0; // 10 kN preload
// Update based on terrain
Real terrain_height = env.terrain.elevation;
Real wheel_height = vehicle_height - wheel_offset;
wheel.update(terrain_height, wheel_height, dt);
// Get force
Real suspension_force = wheel.calculate_force();
SuspensionModel¶
Complete vehicle suspension system.
class SuspensionModel {
public:
// Add suspension units
void add_unit(const Vec3& position, const SuspensionUnit& unit);
void clear_units();
// Update all units
void update(const physics::EntityState& state,
const environment::Environment& env,
Real dt);
// Get total forces and torques
Vec3 get_total_force() const;
Vec3 get_total_torque() const;
// Query individual units
SizeT unit_count() const;
const SuspensionUnit& get_unit(SizeT index) const;
Real get_average_compression() const;
};
Example¶
domain::land::SuspensionModel suspension;
// Configure suspension unit template
domain::land::SuspensionUnit wheel;
wheel.spring_k = 300000.0;
wheel.damper_c = 30000.0;
wheel.travel_max = 0.40;
// Add 7 road wheels per side (tank)
Real wheel_spacing = 0.8; // meters
for (int i = 0; i < 7; ++i) {
Real x = -3.0 + i * wheel_spacing;
// Left side
suspension.add_unit(Vec3{x, 1.5, -0.8}, wheel);
// Right side
suspension.add_unit(Vec3{x, -1.5, -0.8}, wheel);
}
// In simulation loop
suspension.update(state, env, dt);
physics::EntityForces forces;
forces.add_force(suspension.get_total_force());
forces.add_torque(suspension.get_total_torque());
TrackedVehicleModel¶
Track system dynamics.
class TrackedVehicleModel {
public:
struct TrackState {
Real tension{10000.0}; // Track tension (N)
Real velocity{0.0}; // Track linear velocity (m/s)
Real slip{0.0}; // Track slip ratio
};
// Configuration
void set_sprocket_radius(Real radius); // m
void set_sprocket_max_torque(Real torque); // N·m
void set_track_width(Real width); // m
void set_track_length(Real length); // m
void set_idler_radius(Real radius); // m
// Update tracks
void update(Real left_torque, Real right_torque,
Real load, const SoilProperties& soil, Real dt);
// Queries
const TrackState& get_left_track() const;
const TrackState& get_right_track() const;
Real get_propulsive_force() const;
Real get_steering_moment() const;
// Steering (differential)
void set_steering(Real steer); // -1 to +1 (left to right)
};
Example¶
domain::land::TrackedVehicleModel tracks;
// Configure
tracks.set_sprocket_radius(0.33);
tracks.set_sprocket_max_torque(100000.0); // 100 kN·m
tracks.set_track_width(0.63);
tracks.set_track_length(4.6);
// In simulation loop
Real engine_torque = throttle * max_engine_torque;
// Apply steering (differential)
tracks.set_steering(steering_input);
// Update
auto soil = domain::land::SoilProperties::DrySand();
tracks.update(engine_torque, engine_torque, vehicle_weight, soil, dt);
// Get forces
Real propulsion = tracks.get_propulsive_force();
Real steering_moment = tracks.get_steering_moment();
physics::EntityForces forces;
Vec3 thrust_body{propulsion, 0.0, 0.0};
forces.add_force(state.orientation.rotate(thrust_body));
forces.add_torque(Vec3{0.0, 0.0, steering_moment});
WheeledVehicleModel¶
Wheeled vehicle drivetrain and tire model.
class WheeledVehicleModel {
public:
struct WheelState {
Real angular_velocity{0.0}; // rad/s
Real slip_ratio{0.0};
Real slip_angle{0.0}; // rad
Real normal_load{0.0}; // N
Vec3 force{0, 0, 0}; // Tire force
};
// Configuration
void set_wheel_radius(Real radius); // m
void set_wheel_inertia(Real inertia); // kg·m²
// Add wheels (position relative to CG)
void add_wheel(const Vec3& position, bool is_driven, bool is_steered);
// Control
void set_drive_torque(Real torque); // N·m (to driven wheels)
void set_brake_torque(Real torque); // N·m
void set_steering_angle(Real angle); // rad
// Update
void update(const physics::EntityState& state,
const SoilProperties& soil, Real dt);
// Queries
Vec3 get_total_force() const;
Vec3 get_total_torque() const;
const WheelState& get_wheel(SizeT index) const;
SizeT wheel_count() const;
};
Example¶
domain::land::WheeledVehicleModel wheels;
// Configure wheels
wheels.set_wheel_radius(0.4);
wheels.set_wheel_inertia(5.0);
// 4x4 vehicle
wheels.add_wheel(Vec3{2.0, 1.0, -0.4}, true, true); // FL: driven, steered
wheels.add_wheel(Vec3{2.0, -1.0, -0.4}, true, true); // FR: driven, steered
wheels.add_wheel(Vec3{-2.0, 1.0, -0.4}, true, false); // RL: driven
wheels.add_wheel(Vec3{-2.0, -1.0, -0.4}, true, false); // RR: driven
// Control
wheels.set_drive_torque(throttle * max_torque);
wheels.set_brake_torque(brake * max_brake);
wheels.set_steering_angle(steer * max_steer_rad);
// Update
auto soil = domain::land::SoilProperties::Asphalt();
wheels.update(state, soil, dt);
// Apply forces
physics::EntityForces forces;
forces.add_force(wheels.get_total_force());
forces.add_torque(wheels.get_total_torque());
Terrain Integration¶
// Get terrain properties at vehicle location
auto env = engine.get_environment(vehicle_id);
// Terrain data available
Real elevation = env.terrain.elevation;
Vec3 normal = env.terrain.normal;
Real slope = env.terrain.slope_angle;
// Get soil type based on terrain material
SoilProperties soil;
switch (env.terrain.material.type) {
case MaterialType::Sand:
soil = SoilProperties::DrySand();
break;
case MaterialType::Clay:
soil = SoilProperties::Clay();
break;
case MaterialType::Road:
soil = SoilProperties::Asphalt();
break;
default:
soil = SoilProperties::DrySand();
}
terra.set_soil(soil);
See Also¶
- Physics API - Force generator interfaces
- Environment API - Terrain system
- Land Domain Concepts - Domain overview
- Land Domain Tutorial - Step-by-step guide
- Terrain Tutorial - Working with terrain