Problems with Bullet Vehicle

Hello,

I’ve been experimenting with the Bullet Vehicle demo from the Panda tutorials. However, a lot of the settings are a mystery to me, such as chassis connection point and wheel direction. Is there a way to calculate these values? In the below code the vehicle only moves very slowly almost on the spot, so I’m assuming one of the driven wheels is going in the wrong direction or something is amiss. Does anybody have experience of this?

#include "pandaFramework.h"
#include "windowFramework.h"
#include "nodePath.h"
#include "clockObject.h"
 
#include "asyncTask.h"
#include "genericAsyncTask.h"
 
#include "bulletWorld.h"
#include "bulletVehicle.h"
#include "bulletBoxShape.h"
#include "bulletPlaneShape.h"
#include "bulletWheel.h"

 
BulletWorld *get_physics_world() {
    // physics_world is supposed to be an global variable,
    // but declaring global variables is not cool
    // for good programmers lol, instead, should use static keyword.
    static BulletWorld *physics_world = new BulletWorld();
    return physics_world;
}
 
AsyncTask::DoneStatus update_scene(GenericAsyncTask* task, void* data) {
    // Get dt (from Python example) and apply to do_physics(float, int, int);
    ClockObject *co = ClockObject::get_global_clock();
    get_physics_world()->do_physics(co->get_dt(), 10, 1.0 / 180.0);
 
    return AsyncTask::DS_cont;
}
 
int main(int argc, char *argv[]) {
    // All variables.
    PandaFramework framework;
    PT(WindowFramework) window;
    NodePath camera;
    PT(AsyncTaskManager) task_mgr;
 
    // Init everything :D
    framework.open_framework(argc, argv);
    framework.set_window_title("Bullet Vehicle");
 
    window = framework.open_window();
    window->enable_keyboard();
    window->setup_trackball();
 
    camera = window->get_camera_group();
    task_mgr = AsyncTaskManager::get_global_ptr();
 
    // Make physics simulation.
    // Static world stuff.
    get_physics_world()->set_gravity(0, 0, -9.81f);

	// Chassis body
	BulletBoxShape* shape = new BulletBoxShape(LVecBase3(0.7, 1.5, 0.5));
	ConstPointerTo<TransformState> ts = TransformState::make_pos(LVecBase3(0, 0, 0.5));

	PT(BulletRigidBodyNode) chassis_rigid_node = new BulletRigidBodyNode("Vehicle");
	chassis_rigid_node->add_shape(shape,ts);
	NodePath np_chassis = window->get_render().attach_new_node(chassis_rigid_node);
	np_chassis.set_pos(0, 0, 1);
	chassis_rigid_node->set_mass(800.0);
	chassis_rigid_node->set_deactivation_enabled(false);
 
	get_physics_world()->attach_rigid_body(chassis_rigid_node);
 
	//Chassis

	PT(BulletDebugNode) visNode = new BulletDebugNode("ChassisVisual");
	NodePath visNP = np_chassis.attach_new_node(visNode);
 
	// Vehicle
	BulletVehicle* vehicle = new BulletVehicle(get_physics_world(), chassis_rigid_node);
	vehicle->set_coordinate_system(BulletUpAxis::Z_up);
	get_physics_world()->attach_vehicle(vehicle);

	//wheels
	NodePath wheel1NP;
	wheel1NP.reparent_to(window->get_render());
 
	BulletWheel wheel1 = vehicle->create_wheel();
 
	wheel1.set_node(wheel1NP.node());
	wheel1.set_chassis_connection_point_cs(LPoint3(0.8, 1.1, 0.3));
	wheel1.set_front_wheel(true);
 
	wheel1.set_wheel_direction_cs(LVector3(0, 0, -1));
	wheel1.set_wheel_axle_cs(LVector3(1, 0, 0));
	wheel1.set_wheel_radius(0.25);
	wheel1.set_max_suspension_travel_cm(40.0);
 
	wheel1.set_suspension_stiffness(40.0);
	wheel1.set_wheels_damping_relaxation(2.3);
	wheel1.set_wheels_damping_compression(4.4);
	wheel1.set_friction_slip(100.0);
	wheel1.set_roll_influence(0.1);
	
	//wheel2
	BulletWheel wheel2 = vehicle->create_wheel();
	NodePath wheel2NP;
	wheel2NP.reparent_to(window->get_render());
 
	wheel2.set_node(wheel2NP.node());
	wheel2.set_chassis_connection_point_cs(LPoint3(-0.8, 1.1, 0.3));
	wheel2.set_front_wheel(true);
 
	wheel2.set_wheel_direction_cs(LVector3(0, 0, -1));
	wheel2.set_wheel_axle_cs(LVector3(-1, 0, 0));
	wheel2.set_wheel_radius(0.25);
	wheel2.set_max_suspension_travel_cm(40.0);
 
	wheel2.set_suspension_stiffness(40.0);
	wheel2.set_wheels_damping_relaxation(2.3);
	wheel2.set_wheels_damping_compression(4.4);
	wheel2.set_friction_slip(100.0);
	wheel2.set_roll_influence(0.1);

	////wheel3
	BulletWheel wheel3 = vehicle->create_wheel();
	NodePath wheel3NP;
	wheel3NP.reparent_to(window->get_render());
 
	wheel3.set_node(wheel3NP.node());
	wheel3.set_chassis_connection_point_cs(LPoint3(0.8, -1.1, 0.3));
	wheel3.set_front_wheel(false);
 
	wheel3.set_wheel_direction_cs(LVector3(0, 0, -1));
	wheel3.set_wheel_axle_cs(LVector3(1, 0, 0));
	wheel3.set_wheel_radius(0.25);
	wheel3.set_max_suspension_travel_cm(40.0);
 
	wheel3.set_suspension_stiffness(40.0);
	wheel3.set_wheels_damping_relaxation(2.3);
	wheel3.set_wheels_damping_compression(4.4);
	wheel3.set_friction_slip(100.0);
	wheel3.set_roll_influence(0.1);

	////wheel4
	BulletWheel wheel4 = vehicle->create_wheel();
	NodePath wheel4NP;
	wheel4NP.reparent_to(window->get_render());
 
	wheel4.set_node(wheel4NP.node());
	wheel4.set_chassis_connection_point_cs(LPoint3(-0.8, -1.1, 0.3));
	wheel4.set_front_wheel(false);
 
	wheel4.set_wheel_direction_cs(LVector3(0, 0, -1));
	wheel4.set_wheel_axle_cs(LVector3(-1, 0, 0));
	wheel4.set_wheel_radius(0.25);
	wheel4.set_max_suspension_travel_cm(40.0);
 
	wheel4.set_suspension_stiffness(40.0);
	wheel4.set_wheels_damping_relaxation(2.3);
	wheel4.set_wheels_damping_compression(4.4);
	wheel4.set_friction_slip(100.0);
	wheel4.set_roll_influence(0.1);

	// Steering info
	PN_stdfloat steering = 0.0;
	PN_stdfloat engineForce = 1000.0;

	// Apply steering to front wheels
	vehicle->set_steering_value(steering, 0);
	vehicle->set_steering_value(steering, 1);
 
	// Apply engine and brake to rear wheels
	vehicle->apply_engine_force(engineForce, 0);
	vehicle->apply_engine_force(engineForce, 1);

	//ground
	PT(BulletPlaneShape) floor_shape = new BulletPlaneShape(LVecBase3f(0, 0, 1), 1);
    PT(BulletRigidBodyNode) floor_rigid_node = new BulletRigidBodyNode("Ground");

	floor_shape->set_margin(100);
 
    floor_rigid_node->add_shape(floor_shape);
 
    NodePath np_ground = window->get_render().attach_new_node(floor_rigid_node);
    np_ground.set_pos(0, 0, -2);
    get_physics_world()->attach_rigid_body(floor_rigid_node);

	visNode->add_child(floor_rigid_node);
	visNode->show_bounding_boxes(false);
	visNode->show_constraints(true);
	visNode->show_normals(true);
	visNode->show_wireframe(true);

	get_physics_world()->set_debug_node(visNode);
	visNP.show();
	np_ground.show();
	//wheelNP.show();

	PT(GenericAsyncTask) task;
    task = new GenericAsyncTask("Scene update", &update_scene, (void*) NULL);
    task_mgr->add(task);
 
    framework.main_loop();
 
    return (0);
}

Thanks,
Zobbo

Hi zobbo! Looking at your configuration, there are several values that differs from my setup.

As instance I use higher mass, lower friction slip, higher roll influence, higher engine force (but it is related to the mass, so it should be expected).

As for the other values, it looks like we use similar values (and here).

Actually, configuring Bullet Vehicles is a delicate process, since a lot of factors influence car’s behavior: wheels’ connection points, chassis’ shape, … I started from a working example, then I modified one parameter at a time. Moreover, looking at Bullet’s source code should explain some settings.