ARGoS 3
A parallel, multi-engine simulator for swarm robotics
dynamics3d_engine.cpp
Go to the documentation of this file.
1
7#include "dynamics3d_engine.h"
8
9#include <argos3/core/simulator/simulator.h>
10#include <argos3/core/simulator/space/space.h>
11#include <argos3/core/simulator/entity/embodied_entity.h>
12#include <argos3/plugins/simulator/physics_engines/dynamics3d/dynamics3d_model.h>
13#include <argos3/plugins/simulator/physics_engines/dynamics3d/dynamics3d_plugin.h>
14
15#include <algorithm>
16
17namespace argos {
18
19 /****************************************/
20 /****************************************/
21
23 m_pcRNG(nullptr),
24 m_cRandomSeedRange(0,1000),
25 m_fDefaultFriction(1.0f),
26 m_cBroadphase(),
27 m_cConfiguration(),
28 m_cDispatcher(&m_cConfiguration),
29 m_cSolver(),
30 m_cWorld(&m_cDispatcher,
31 &m_cBroadphase,
32 &m_cSolver,
33 &m_cConfiguration) {}
34
35 /****************************************/
36 /****************************************/
37
39 /* Initialize parent */
41 /* Create the random number generator */
42 m_pcRNG = CRandom::CreateRNG("argos");
43 /* Set random seed */
44 m_cSolver.setRandSeed(m_pcRNG->Uniform(m_cRandomSeedRange));
45 /* Disable gravity by default */
46 m_cWorld.setGravity(btVector3(0.0,0.0,0.0));
47 /* Load the plugins */
48 TConfigurationNodeIterator tPluginIterator;
49 for(tPluginIterator = tPluginIterator.begin(&t_tree);
50 tPluginIterator != tPluginIterator.end();
51 ++tPluginIterator) {
52 CDynamics3DPlugin* pcPlugin = CFactory<CDynamics3DPlugin>::New(tPluginIterator->Value());
53 pcPlugin->SetEngine(*this);
54 pcPlugin->Init(*tPluginIterator);
55 AddPhysicsPlugin(tPluginIterator->Value(), *pcPlugin);
56 }
57 GetNodeAttributeOrDefault(t_tree, "debug_file", m_strDebugFilename, m_strDebugFilename);
58 GetNodeAttributeOrDefault(t_tree, "default_friction", m_fDefaultFriction, m_fDefaultFriction);
59 }
60
61 /****************************************/
62 /****************************************/
63
65 /* Call reset to set up the simulation */
66 Reset();
67 }
68
69 /****************************************/
70 /****************************************/
71
73 /* Remove and reset all physics models */
74 for(auto itModel = std::begin(m_tPhysicsModels);
75 itModel != std::end(m_tPhysicsModels);
76 ++itModel) {
77 /* Remove model from plugins */
78 for(auto itPlugin = std::begin(m_tPhysicsPlugins);
79 itPlugin != std::end(m_tPhysicsPlugins);
80 ++itPlugin) {
81 itPlugin->second->UnregisterModel(*itModel->second);
82 }
83 /* Remove model from world */
84 itModel->second->RemoveFromWorld(m_cWorld);
85 /* Reset the model */
86 itModel->second->Reset();
87 }
88 /* Run the destructors on bullet's components */
89 m_cWorld.~btMultiBodyDynamicsWorld();
90 m_cSolver.~btMultiBodyConstraintSolver();
91 m_cDispatcher.~btCollisionDispatcher();
92 m_cConfiguration.~btDefaultCollisionConfiguration();
93 m_cBroadphase.~btDbvtBroadphase();
94 /* Rerun the constructors for the bullet's components */
95 new (&m_cBroadphase) btDbvtBroadphase;
96 new (&m_cConfiguration) btDefaultCollisionConfiguration;
97 new (&m_cDispatcher) btCollisionDispatcher(&m_cConfiguration);
98 new (&m_cSolver) btMultiBodyConstraintSolver;
99 new (&m_cWorld) btMultiBodyDynamicsWorld(&m_cDispatcher,
100 &m_cBroadphase,
101 &m_cSolver,
102 &m_cConfiguration);
103 /* Provide the same random seed to the solver */
104 m_cSolver.setRandSeed(m_pcRNG->Uniform(m_cRandomSeedRange));
105 /* Reset the plugins */
106 for(auto itPlugin = std::begin(m_tPhysicsPlugins);
107 itPlugin != std::end(m_tPhysicsPlugins);
108 ++itPlugin) {
109 itPlugin->second->Reset();
110 }
111 /* Set up the call back for the plugins */
112 m_cWorld.setInternalTickCallback([] (btDynamicsWorld* pc_world, btScalar f_time_step) {
113 auto* pc_engine = static_cast<CDynamics3DEngine*>(pc_world->getWorldUserInfo());
114 pc_world->clearForces();
115 for(std::pair<const std::string, CDynamics3DPlugin*>& c_plugin :
116 pc_engine->GetPhysicsPlugins()) {
117 c_plugin.second->Update();
118 }
119 }, static_cast<void*>(this), true);
120 /* Add the models back into the engine */
121 for(auto itModel = std::begin(m_tPhysicsModels);
122 itModel != std::end(m_tPhysicsModels);
123 ++itModel) {
124 /* Add model to plugins */
125 for(auto itPlugin = std::begin(m_tPhysicsPlugins);
126 itPlugin != std::end(m_tPhysicsPlugins);
127 ++itPlugin) {
128 itPlugin->second->RegisterModel(*itModel->second);
129 }
130 /* Add model to world */
131 itModel->second->AddToWorld(m_cWorld);
132 }
133 /* Initialize any multi-body constraints */
134 for (SInt32 i = 0; i < m_cWorld.getNumMultiBodyConstraints(); i++) {
135 m_cWorld.getMultiBodyConstraint(i)->finalizeMultiDof();
136 }
137 }
138
139 /****************************************/
140 /****************************************/
141
143 /* Destroy all physics models */
144 for(auto itModel = std::begin(m_tPhysicsModels);
145 itModel != std::end(m_tPhysicsModels);
146 ++itModel) {
147 /* Remove model from the plugins first */
148 for(auto itPlugin = std::begin(m_tPhysicsPlugins);
149 itPlugin != std::end(m_tPhysicsPlugins);
150 ++itPlugin) {
151 itPlugin->second->UnregisterModel(*itModel->second);
152 }
153 /* Destroy the model */
154 itModel->second->RemoveFromWorld(m_cWorld);
155 delete itModel->second;
156 }
157 /* Destroy all plug-ins */
158 for(auto itPlugin = std::begin(m_tPhysicsPlugins);
159 itPlugin != std::end(m_tPhysicsPlugins);
160 ++itPlugin) {
161 itPlugin->second->Destroy();
162 delete itPlugin->second;
163 }
164 /* Empty the maps */
165 m_tPhysicsPlugins.clear();
166 m_tPhysicsModels.clear();
167 }
168
169 /****************************************/
170 /****************************************/
171
173 /* Update the physics state from the entities */
174 for(auto it = m_tPhysicsModels.begin();
175 it != std::end(m_tPhysicsModels); ++it) {
176 it->second->UpdateFromEntityStatus();
177 }
178 /* Step the simuation forwards */
179 m_cWorld.stepSimulation(GetSimulationClockTick(),
182 /* Update the simulated space */
183 for(auto it = std::begin(m_tPhysicsModels);
184 it != std::end(m_tPhysicsModels);
185 ++it) {
186 it->second->UpdateEntityStatus();
187 }
188 /* Dump the state of the world to a bullet file (if requested) */
189 if(!m_strDebugFilename.empty()) {
190 btDefaultSerializer cSerializer;
191 m_cWorld.serialize(&cSerializer);
192 std::ofstream cDebugOutput(m_strDebugFilename);
193 if(cDebugOutput.is_open()) {
194 cDebugOutput.write(reinterpret_cast<const char*>(cSerializer.getBufferPointer()),
195 cSerializer.getCurrentBufferSize());
196 }
197 }
198 }
199
200 /****************************************/
201 /****************************************/
202
204 const CRay3& c_ray) const {
205 /* Convert the start and end ray vectors to the bullet coordinate system */
206 btVector3 cRayStart(c_ray.GetStart().GetX(), c_ray.GetStart().GetZ(), -c_ray.GetStart().GetY());
207 btVector3 cRayEnd(c_ray.GetEnd().GetX(), c_ray.GetEnd().GetZ(), -c_ray.GetEnd().GetY());
208 btCollisionWorld::ClosestRayResultCallback cResult(cRayStart, cRayEnd);
209 /* The default flag/algorithm 'kF_UseSubSimplexConvexCastRaytest' is too approximate for
210 our purposes */
211 cResult.m_flags |= btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest;
212 /* Run the ray test */
213 m_cWorld.rayTest(cRayStart, cRayEnd, cResult);
214 /* Examine the results */
215 if (cResult.hasHit() && cResult.m_collisionObject->getUserPointer() != nullptr) {
216 Real f_t = (cResult.m_hitPointWorld - cRayStart).length() / c_ray.GetLength();
217 auto* pcModel =
218 static_cast<CDynamics3DModel*>(cResult.m_collisionObject->getUserPointer());
219 t_data.push_back(SEmbodiedEntityIntersectionItem(&(pcModel->GetEmbodiedEntity()), f_t));
220 }
221 }
222
223 /****************************************/
224 /****************************************/
225
227 return m_tPhysicsModels.size();
228 }
229
230 /****************************************/
231 /****************************************/
232
239
240 /****************************************/
241 /****************************************/
242
249
250 /****************************************/
251 /****************************************/
252
253 void CDynamics3DEngine::AddPhysicsModel(const std::string& str_id,
254 CDynamics3DModel& c_model) {
255 /* Add model to world */
256 c_model.AddToWorld(m_cWorld);
257 /* Notify the plugins of the added model */
258 for(auto itPlugin = std::begin(m_tPhysicsPlugins);
259 itPlugin != std::end(m_tPhysicsPlugins);
260 ++itPlugin) {
261 itPlugin->second->RegisterModel(c_model);
262 }
263 /* Add a pointer to the model to the map of models */
264 m_tPhysicsModels[str_id] = &c_model;
265 }
266
267 /****************************************/
268 /****************************************/
269
270 void CDynamics3DEngine::RemovePhysicsModel(const std::string& str_id) {
271 auto itModel = m_tPhysicsModels.find(str_id);
272 if(itModel != std::end(m_tPhysicsModels)) {
273 /* Notify the plugins of model removal */
274 for(auto itPlugin = std::begin(m_tPhysicsPlugins);
275 itPlugin != std::end(m_tPhysicsPlugins);
276 ++itPlugin) {
277 itPlugin->second->UnregisterModel(*(itModel->second));
278 }
279 /* Remove the model from world */
280 itModel->second->RemoveFromWorld(m_cWorld);
281 /* Destroy the model */
282 delete itModel->second;
283 /* Remove the model from the map */
284 m_tPhysicsModels.erase(itModel);
285 }
286 else {
287 THROW_ARGOSEXCEPTION("The model \"" << str_id <<
288 "\" was not found in the dynamics 3D engine \"" <<
289 GetId() << "\"");
290 }
291 }
292
293 /****************************************/
294 /****************************************/
295
296 void CDynamics3DEngine::AddPhysicsPlugin(const std::string& str_id,
297 CDynamics3DPlugin& c_plugin) {
298 m_tPhysicsPlugins[str_id] = &c_plugin;
299 }
300
301 /****************************************/
302 /****************************************/
303
304 void CDynamics3DEngine::RemovePhysicsPlugin(const std::string& str_id) {
305 auto it = m_tPhysicsPlugins.find(str_id);
306 if(it != std::end(m_tPhysicsPlugins)) {
307 delete it->second;
308 m_tPhysicsPlugins.erase(it);
309 }
310 else {
311 THROW_ARGOSEXCEPTION("The plugin \"" << str_id <<
312 "\" was not found in the dynamics 3D engine \"" <<
313 GetId() << "\"");
314 }
315 }
316
317 /****************************************/
318 /****************************************/
319
321 "dynamics3d",
322 "Michael Allwright [allsey87@gmail.com]",
323 "1.0",
324 "A 3D dynamics physics engine",
325 "This physics engine is a 3D dynamics engine based on the Bullet Physics SDK\n"
326 "(https://github.com/bulletphysics/bullet3).\n\n"
327
328 "REQUIRED XML CONFIGURATION\n\n"
329 " <physics_engines>\n"
330 " ...\n"
331 " <dynamics3d id=\"dyn3d\" />\n"
332 " ...\n"
333 " </physics_engines>\n\n"
334
335 "The 'id' attribute is necessary and must be unique among the physics engines.\n\n"
336
337 "Multiple physics engines of this type cannot be used, and defining '<boundaries>'\n"
338 "as a child tag under the '<dynamics3d>' tree will result in an initialization error.\n\n"
339
340 "OPTIONAL XML CONFIGURATION\n\n"
341
342 "It is possible to change the default friction used in the simulation from\n"
343 "its initial value of 1.0 using the default_friction attribute as shown\n"
344 "below. For debugging purposes, it is also possible to provide a filename\n"
345 "via the debug_file attribute which will cause the Bullet world to be\n"
346 "serialized and written out to a file at the end of each step. This file can\n"
347 "then be opened using the Bullet example browser and can provide useful\n"
348 "insights into the stability of a simulation.\n\n"
349
350 " <physics_engines>\n"
351 " ...\n"
352 " <dynamics3d id=\"dyn3d\"\n"
353 " default_friction=\"1.0\"\n"
354 " debug_file=\"dynamics3d.bullet\"/>\n"
355 " ...\n"
356 " </physics_engines>\n\n"
357
358 "The physics engine supports a number of plugins that add features to the\n"
359 "simulation. In the example below, a floor plane has been added which has a\n"
360 "height of 1 cm and the dimensions of the floor as specified by the arena\n"
361 "node. It is possible to change the coefficient of friction of the floor\n"
362 "using the friction attribute. This will override the default friction used\n"
363 "by the physics engine. By default, there will be no gravity in the\n"
364 "simulation. This can be changed by adding a gravity node with a single\n"
365 "attribute 'g' which is the downwards acceleration caused by gravity.\n"
366 "Finally, there is a magnetism plugin. This plugin applies forces and\n"
367 "torques to bodies in the simulation that contains magnetic dipoles. The\n"
368 "'max_distance' attribute is an optional optimization that sets the maximum\n"
369 "distance at which two magnetic dipoles will interact with each other. In\n"
370 "the example below, this distance has been set to 4 cm.\n\n"
371
372 " <physics_engines>\n"
373 " ...\n"
374 " <dynamics3d id=\"dyn3d\" default_friction=\"2.0\">\n"
375 " <floor height=\"0.01\" friction=\"0.05\"/>\n"
376 " <gravity g=\"10\" />\n"
377 " <magnetism max_distance=\"0.04\" />\n"
378 " </dynamics3d>\n"
379 " ...\n"
380 " </physics_engines>\n\n",
381
382 "Usable (multiple engines not supported)"
383 );
384
385 /****************************************/
386 /****************************************/
387
388}
signed int SInt32
32-bit signed integer.
Definition datatypes.h:93
float Real
Collects all ARGoS code.
Definition datatypes.h:39
#define THROW_ARGOSEXCEPTION(message)
This macro throws an ARGoS exception with the passed message.
#define REGISTER_PHYSICS_ENGINE(CLASSNAME, LABEL, AUTHOR, VERSION, BRIEF_DESCRIPTION, LONG_DESCRIPTION, STATUS)
The namespace containing all the ARGoS related code.
Definition ci_actuator.h:12
ticpp::Iterator< ticpp::Element > TConfigurationNodeIterator
The iterator for the ARGoS configuration XML node.
RETURN_VALUE CallEntityOperation(PLUGIN &t_plugin, CEntity &c_entity)
Calls the operation corresponding to the given context and operand Skips the function call if the ope...
Definition entity.h:418
void GetNodeAttributeOrDefault(TConfigurationNode &t_node, const std::string &str_attribute, T &t_buffer, const T &t_default)
Returns the value of a node's attribute, or the passed default value.
ticpp::Element TConfigurationNode
The ARGoS configuration XML node.
std::vector< SEmbodiedEntityIntersectionItem > TEmbodiedEntityIntersectionData
The basic entity type.
Definition entity.h:90
Type to use as return value for operation outcome.
Definition entity.h:352
static Real GetSimulationClockTick()
Returns the simulation clock tick.
virtual void Init(TConfigurationNode &t_tree)
Initializes the resource.
const std::string & GetId() const
Returns the id of this physics engine.
Real GetPhysicsClockTick() const
Returns the length of the physics engine tick.
UInt32 GetIterations() const
Returns the number of iterations per simulation clock tick.
Real GetLength() const
Definition ray3.h:96
CVector3 & GetStart()
Definition ray3.h:37
CVector3 & GetEnd()
Definition ray3.h:45
static CRNG * CreateRNG(const std::string &str_category)
Creates a new RNG inside the given category.
Definition rng.cpp:347
CRadians Uniform(const CRange< CRadians > &c_range)
Returns a random value from a uniform distribution.
Definition rng.cpp:87
Real GetX() const
Returns the x coordinate of this vector.
Definition vector3.h:105
Real GetY() const
Returns the y coordinate of this vector.
Definition vector3.h:121
Real GetZ() const
Returns the z coordinate of this vector.
Definition vector3.h:137
static TYPE * New(const std::string &str_label)
Creates a new object of type TYPE
virtual size_t GetNumPhysicsModels()
void AddPhysicsModel(const std::string &str_id, CDynamics3DModel &c_model)
void RemovePhysicsModel(const std::string &str_id)
virtual bool AddEntity(CEntity &c_entity)
Adds an entity to the physics engine.
virtual void CheckIntersectionWithRay(TEmbodiedEntityIntersectionData &t_data, const CRay3 &c_ray) const
Check which objects in this engine intersect the given ray.
virtual bool RemoveEntity(CEntity &c_entity)
Removes an entity from the physics engine.
virtual void Reset()
Resets the resource.
virtual void Destroy()
Undoes whatever was done by Init().
void AddPhysicsPlugin(const std::string &str_id, CDynamics3DPlugin &c_plugin)
void RemovePhysicsPlugin(const std::string &str_id)
virtual void PostSpaceInit()
Executes extra initialization activities after the space has been initialized.
virtual void Init(TConfigurationNode &t_tree)
Initializes the resource.
virtual void AddToWorld(btMultiBodyDynamicsWorld &c_world)=0
virtual void SetEngine(CDynamics3DEngine &c_engine)
virtual void Init(TConfigurationNode &t_tree)