// Use convex decomposition for collision detection with the Trelleborg tire SoilbinWheel(ChSystemNSC* system, ChVector<> mposition, double mass, ChVector<>& inertia) { ChCollisionModel::SetDefaultSuggestedEnvelope(0.005); ChCollisionModel::SetDefaultSuggestedMargin(0.004); // Create the wheel body wheel = std::make_shared<ChBody>(); wheel->SetPos(mposition); wheel->SetMass(mass); wheel->SetInertiaXX(inertia); wheel->GetMaterialSurfaceNSC()->SetFriction(0.4f); wheel->SetCollide(true); // Visualization mesh auto tireMesh = std::make_shared<ChTriangleMeshConnected>(); tireMesh->LoadWavefrontMesh(GetChronoDataFile("tractor_wheel.obj"), true, true); auto tireMesh_asset = std::make_shared<ChTriangleMeshShape>(); tireMesh_asset->SetMesh(tireMesh); wheel->AddAsset(tireMesh_asset); // Contact mesh wheel->GetCollisionModel()->ClearModel(); // Describe the (invisible) colliding shape by adding the 'carcass' decomposed shape and the // 'knobs'. Since these decompositions are only for 1/15th of the wheel, use for() to pattern them. for (double mangle = 0; mangle < 360.; mangle += (360. / 15.)) { ChQuaternion<> myrot; ChStreamInAsciiFile myknobs(GetChronoDataFile("tractor_wheel_knobs.chulls").c_str()); ChStreamInAsciiFile myslice(GetChronoDataFile("tractor_wheel_slice.chulls").c_str()); myrot.Q_from_AngAxis(mangle * (CH_C_PI / 180.), VECT_X); ChMatrix33<> mm(myrot); wheel->GetCollisionModel()->AddConvexHullsFromFile(myknobs, ChVector<>(0, 0, 0), mm); wheel->GetCollisionModel()->AddConvexHullsFromFile(myslice, ChVector<>(0, 0, 0), mm); } wheel->GetCollisionModel()->BuildModel(); // Add wheel body to system system->AddBody(wheel); }
int main(int argc, char* argv[]) { // In CHRONO engine, The DLL_CreateGlobals() - DLL_DeleteGlobals(); pair is needed if // global functions are needed. DLL_CreateGlobals(); // Create a Chrono::Engine physical system ChSystem mphysicalSystem; // Create the Irrlicht visualization (open the Irrlicht device, // bind a simple user interface, etc. etc.) ChIrrApp application(&mphysicalSystem, L"Assets for Irrlicht visualization",core::dimension2d<u32>(800,600),false, true); // Easy shortcuts to add camera, lights, logo and sky in Irrlicht scene: application.AddTypicalLogo(); application.AddTypicalSky(); application.AddTypicalLights(); application.AddTypicalCamera(core::vector3df(0,4,-6)); // // EXAMPLE 1: // // Create a ChBody, and attach some 'assets' // that define 3D shapes. These shapes can be shown // by Irrlicht or POV postprocessing, etc... // Note: these assets are independent from collision shapes! // Create a rigid body as usual, and add it // to the physical system: ChSharedPtr<ChBody> mfloor(new ChBody); mfloor->SetBodyFixed(true); // Define a collision shape mfloor->GetCollisionModel()->ClearModel(); mfloor->GetCollisionModel()->AddBox(10,0.5,10, &ChVector<>(0,-1,0)); mfloor->GetCollisionModel()->BuildModel(); mfloor->SetCollide(true); // Add body to system application.GetSystem()->Add(mfloor); // ==Asset== attach a 'box' shape. // Note that assets are managed via shared pointer, so they // can also be shared). Do not forget AddAsset() at the end! ChSharedPtr<ChBoxShape> mboxfloor(new ChBoxShape); mboxfloor->GetBoxGeometry().Pos = ChVector<>(0,-1,0); mboxfloor->GetBoxGeometry().Size = ChVector<>(10,0.5,10); mfloor->AddAsset(mboxfloor); // ==Asset== attach color asset. ChSharedPtr<ChVisualization> mfloorcolor(new ChVisualization); mfloorcolor->SetColor(ChColor(0.3,0.3,0.6)); mfloor->AddAsset(mfloorcolor); /* // ==Asset== IRRLICHT! Add a ChIrrNodeAsset so that Irrlicht will be able // to 'show' all the assets that we added to the body! // OTHERWISE: use the application.AssetBind() function as at the end.. ChSharedPtr<ChIrrNodeAsset> mirr_asset_floor(new ChIrrNodeAsset); mirr_asset_floor->Bind(mfloor, application); mfloor->AddAsset(mirr_asset_floor); */ // // EXAMPLE 2: // // Textures, colors, asset levels with transformations. // This section shows how to add more advanced types of assets // and how to group assets in ChAssetLevel containers. // Create the rigid body as usual (this won't move, // it is only for visualization tests) ChSharedPtr<ChBody> mbody(new ChBody); mbody->SetBodyFixed(true); application.GetSystem()->Add(mbody); // ==Asset== Attach a 'sphere' shape ChSharedPtr<ChSphereShape> msphere(new ChSphereShape); msphere->GetSphereGeometry().rad = 0.5; msphere->GetSphereGeometry().center = ChVector<>(-1,0,0); mbody->AddAsset(msphere); // ==Asset== Attach also a 'box' shape ChSharedPtr<ChBoxShape> mbox(new ChBoxShape); mbox->GetBoxGeometry().Pos = ChVector<>(1,1,0); mbox->GetBoxGeometry().Size = ChVector<>(0.3,0.5,0.1); mbody->AddAsset(mbox); // ==Asset== Attach also a 'cylinder' shape ChSharedPtr<ChCylinderShape> mcyl(new ChCylinderShape); mcyl->GetCylinderGeometry().p1 = ChVector<>(2,-0.2,0); mcyl->GetCylinderGeometry().p2 = ChVector<>(2.2,0.5,0); mcyl->GetCylinderGeometry().rad = 0.3; mbody->AddAsset(mcyl); // ==Asset== Attach color. To set colors for all assets // in the same level, just add this: ChSharedPtr<ChVisualization> mvisual(new ChVisualization); mvisual->SetColor(ChColor(0.9,0.4,0.2)); mbody->AddAsset(mvisual); // ==Asset== Attach a level that contains other assets. // Note: a ChAssetLevel can define a rotation/translation respect to paren level, // Note: a ChAssetLevel can contain colors or textures: if any, they affect only objects in the level. ChSharedPtr<ChAssetLevel> mlevelA(new ChAssetLevel); // ==Asset== Attach, in this level, a 'Wavefront mesh' asset, // referencing a .obj file: ChSharedPtr<ChObjShapeFile> mobjmesh(new ChObjShapeFile); mobjmesh->SetFilename("../data/forklift_body.obj"); mlevelA->AddAsset(mobjmesh); // ==Asset== Attach also a texture, that will affect only the // assets in mlevelA: ChSharedPtr<ChTexture> mtexture(new ChTexture); mtexture->SetTextureFilename("../data/bluwhite.png"); mlevelA->AddAsset(mtexture); // Change the position of mlevelA, thus moving also its sub-assets: mlevelA->GetFrame().SetPos(ChVector<>(0,0,2)); mbody->AddAsset(mlevelA); // ==Asset== Attach sub level, then add to it an array of sub-levels, // each rotated, and each containing a displaced box, thus making a // spiral of cubes ChSharedPtr<ChAssetLevel> mlevelB(new ChAssetLevel); for (int j = 0; j<20; j++) { // ==Asset== the sub sub level.. ChSharedPtr<ChAssetLevel> mlevelC(new ChAssetLevel); // ==Asset== the contained box.. ChSharedPtr<ChBoxShape> msmallbox(new ChBoxShape); msmallbox->GetBoxGeometry().Pos = ChVector<>(0.4,0,0); msmallbox->GetBoxGeometry().Size = ChVector<>(0.1,0.1,0.01); mlevelC->AddAsset(msmallbox); ChQuaternion<> mrot; mrot.Q_from_AngAxis(j*21*CH_C_DEG_TO_RAD, ChVector<>(0,1,0)); mlevelC->GetFrame().SetRot(mrot); mlevelC->GetFrame().SetPos(ChVector<>(0,j*0.02,0)); mlevelB->AddAsset(mlevelC); } mbody->AddAsset(mlevelB); // ==Asset== Attach a video camera. This will be used by Irrlicht, // or POVray postprocessing, etc. Note that a camera can also be // put in a moving object. ChSharedPtr<ChCamera> mcamera(new ChCamera); mcamera->SetAngle(50); mcamera->SetPosition(ChVector<>(-3,4,-5)); mcamera->SetAimPoint(ChVector<>(0,1,0)); mbody->AddAsset(mcamera); /* // ==Asset== IRRLICHT! Add a ChIrrNodeAsset so that Irrlicht will be able // to 'show' all the assets that we added to the body! // OTHERWISE: use the application.AssetBind() function as at the end.. ChSharedPtr<ChIrrNodeAsset> mirr_asset(new ChIrrNodeAsset); mirr_asset->Bind(mbody, application); mbody->AddAsset(mirr_asset); */ // // EXAMPLE 3: // // Create a ChParticleClones cluster, and attach 'assets' // that define a single "sample" 3D shape. This will be shown // N times in Irrlicht. // Create the ChParticleClones, populate it with some random particles, // and add it to physical system: ChSharedPtr<ChParticlesClones> mparticles(new ChParticlesClones); // Note: coll. shape, if needed, must be specified before creating particles mparticles->GetCollisionModel()->ClearModel(); mparticles->GetCollisionModel()->AddSphere(0.05); mparticles->GetCollisionModel()->BuildModel(); mparticles->SetCollide(true); // Create the random particles for (int np=0; np<100; ++np) mparticles->AddParticle(ChCoordsys<>(ChVector<>(ChRandom()-2,1.5,ChRandom()+2))); // Do not forget to add the particle cluster to the system: application.GetSystem()->Add(mparticles); // ==Asset== Attach a 'sphere' shape asset.. it will be used as a sample // shape to display all particles when rendering in 3D! ChSharedPtr<ChSphereShape> mspherepart(new ChSphereShape); mspherepart->GetSphereGeometry().rad = 0.05; mparticles->AddAsset(mspherepart); /* // ==Asset== IRRLICHT! Add a ChIrrNodeAsset so that Irrlicht will be able // to 'show' all the assets that we added to the body! // OTHERWISE: use the application.AssetBind() function as at the end! ChSharedPtr<ChIrrNodeAsset> mirr_assetpart(new ChIrrNodeAsset); mirr_assetpart->Bind(mparticles, application); mparticles->AddAsset(mirr_assetpart); */ //////////////////////// // ==IMPORTANT!== Use this function for adding a ChIrrNodeAsset to all items // in the system. These ChIrrNodeAsset assets are 'proxies' to the Irrlicht meshes. // If you need a finer control on which item really needs a visualization proxy in // Irrlicht, just use application.AssetBind(myitem); on a per-item basis. application.AssetBindAll(); // ==IMPORTANT!== Use this function for 'converting' into Irrlicht meshes the assets // that you added to the bodies into 3D shapes, they can be visualized by Irrlicht! application.AssetUpdateAll(); // // THE SOFT-REAL-TIME CYCLE // application.SetStepManage(true); application.SetTimestep(0.01); application.SetTryRealtime(true); while(application.GetDevice()->run()) { application.BeginScene(); application.DrawAll(); application.DoStep(); application.EndScene(); } // Remember this at the end of the program, if you started // with DLL_CreateGlobals(); DLL_DeleteGlobals(); return 0; }
// functions TestMech(ChSystemNSC* system, std::shared_ptr<ChBody> wheelBody, double binWidth = 1.0, double binLength = 2.0, double weightMass = 100.0, double springK = 25000, double springD = 100) { ChCollisionModel::SetDefaultSuggestedEnvelope(0.003); ChCollisionModel::SetDefaultSuggestedMargin(0.002); ChQuaternion<> rot; rot.Q_from_AngAxis(ChRandom() * CH_C_2PI, VECT_Y); // ******* // Create a soil bin with planes. bin width = x-dir, bin length = z-dir // Note: soil bin depth will always be ~ 1m // ******* double binHeight = 1.0; double wallWidth = std::min<double>(binWidth, binLength) / 10.0; // wall width = 1/10 of min of bin dims // create the floor auto cubeMap = std::make_shared<ChTexture>(); cubeMap->SetTextureFilename(GetChronoDataFile("concrete.jpg")); floor = std::make_shared<ChBodyEasyBox>(binWidth + wallWidth / 2.0, wallWidth, binLength + wallWidth / 2.0, 1.0, true, true); floor->SetPos(ChVector<>(0, -0.5 - wallWidth / 2.0, 0)); floor->SetBodyFixed(true); floor->GetMaterialSurfaceNSC()->SetFriction(0.5); floor->AddAsset(cubeMap); system->AddBody(floor); // add some transparent walls to the soilBin, w.r.t. width, length of bin wall1 = std::make_shared<ChBodyEasyBox>(wallWidth, binHeight, binLength, 1.0, true, true); wall1->SetPos(ChVector<>(-binWidth / 2.0 - wallWidth / 2.0, 0, 0)); wall1->SetBodyFixed(true); system->AddBody(wall1); wall2 = std::make_shared<ChBodyEasyBox>(wallWidth, binHeight, binLength, 1.0, true, false); wall2->SetPos(ChVector<>(binWidth / 2.0 + wallWidth / 2.0, 0, 0)); wall2->SetBodyFixed(true); system->AddBody(wall2); wall3 = std::make_shared<ChBodyEasyBox>(binWidth + wallWidth / 2.0, binHeight, wallWidth, 1.0, true, false); wall3->SetPos(ChVector<>(0, 0, -binLength / 2.0 - wallWidth / 2.0)); wall3->SetBodyFixed(true); system->AddBody(wall3); // wall 4 wall4 = std::make_shared<ChBodyEasyBox>(binWidth + wallWidth / 2.0, binHeight, wallWidth, 1.0, true, true); wall4->SetPos(ChVector<>(0, 0, binLength / 2.0 + wallWidth / 2.0)); wall4->SetBodyFixed(true); system->AddBody(wall4); // ****** // make a truss, connect it to the wheel via revolute joint // single rotational DOF will be driven with a user-input for torque // ***** auto bluMap = std::make_shared<ChTexture>(); bluMap->SetTextureFilename(GetChronoDataFile("blu.png")); ChVector<> trussCM = wheelBody->GetPos(); truss = std::make_shared<ChBodyEasyBox>(0.2, 0.2, 0.4, 300.0, false, true); truss->SetPos(trussCM); truss->SetMass(5.0); truss->AddAsset(bluMap); system->AddBody(truss); // create the revolute joint between the wheel and spindle spindle = std::make_shared<ChLinkLockRevolute>(); spindle->Initialize(truss, wheelBody, ChCoordsys<>(trussCM, chrono::Q_from_AngAxis(CH_C_PI / 2, VECT_Y))); system->AddLink(spindle); // create a torque between the truss and wheel torqueDriver = std::make_shared<ChLinkEngine>(); torqueDriver->Initialize(truss, wheelBody, ChCoordsys<>(trussCM, chrono::Q_from_AngAxis(CH_C_PI / 2, VECT_Y))); torqueDriver->Set_eng_mode(ChLinkEngine::ENG_MODE_TORQUE); system->AddLink(torqueDriver); // ****** // create a body that will be used as a vehicle weight ChVector<> weightCM = ChVector<>(trussCM); weightCM.y() += 1.0; // note: this will determine the spring free length suspweight = std::make_shared<ChBodyEasyBox>(0.2, 0.4, 0.2, 5000.0, false, true); suspweight->SetPos(weightCM); suspweight->SetMass(weightMass); suspweight->AddAsset(bluMap); system->AddBody(suspweight); // create the translational joint between the truss and weight load auto translational = std::make_shared<ChLinkLockPrismatic>(); translational->Initialize(truss, suspweight, ChCoordsys<>(trussCM, chrono::Q_from_AngAxis(CH_C_PI / 2, VECT_X))); system->AddLink(translational); // create a spring between spindle truss and weight spring = std::make_shared<ChLinkSpring>(); spring->Initialize(truss, suspweight, false, trussCM, suspweight->GetPos()); spring->Set_SpringK(springK); spring->Set_SpringR(springD); system->AddLink(spring); // create a prismatic constraint between the weight and the ground auto weightLink = std::make_shared<ChLinkLockOldham>(); weightLink->Initialize(suspweight, floor, ChCoordsys<>(weightCM, chrono::Q_from_AngAxis(CH_C_PI / 2.0, VECT_Y))); system->AddLink(weightLink); }