dynamics3d_prototype_model.cpp
Go to the documentation of this file.
1 
9 #include <argos3/plugins/robots/prototype/simulator/prototype_entity.h>
10 #include <argos3/plugins/robots/prototype/simulator/prototype_joint_equipped_entity.h>
11 #include <argos3/plugins/robots/prototype/simulator/prototype_link_equipped_entity.h>
12 #include <argos3/plugins/simulator/entities/magnet_equipped_entity.h>
13 #include <argos3/plugins/simulator/physics_engines/dynamics3d/dynamics3d_multi_body_object_model.h>
14 #include <argos3/plugins/simulator/physics_engines/dynamics3d/dynamics3d_shape_manager.h>
15 #include <argos3/plugins/simulator/physics_engines/dynamics3d/dynamics3d_engine.h>
16 
17 namespace argos {
18 
19  /****************************************/
20  /****************************************/
21 
22  std::shared_ptr<btCollisionShape> CDynamics3DPrototypeModel::RequestShape(const CPrototypeLinkEntity& c_link_entity) {
23  btVector3 cHalfExtents(c_link_entity.GetExtents().GetX() * 0.5f,
24  c_link_entity.GetExtents().GetZ() * 0.5f,
25  c_link_entity.GetExtents().GetY() * 0.5f);
26  std::vector<btVector3> vecConvexHullPoints;
27  std::shared_ptr<btCollisionShape> ptrShape;
28  switch(c_link_entity.GetGeometry()) {
29  case CPrototypeLinkEntity::EGeometry::BOX:
30  ptrShape = CDynamics3DShapeManager::RequestBox(cHalfExtents);
31  break;
32  case CPrototypeLinkEntity::EGeometry::CYLINDER:
33  ptrShape = CDynamics3DShapeManager::RequestCylinder(cHalfExtents);
34  break;
35  case CPrototypeLinkEntity::EGeometry::SPHERE:
36  ptrShape = CDynamics3DShapeManager::RequestSphere(cHalfExtents.getZ());
37  break;
38  case CPrototypeLinkEntity::EGeometry::CONVEX_HULL:
39  vecConvexHullPoints.reserve(c_link_entity.GetConvexHullPoints().size());
40  for(const CVector3& c_point : c_link_entity.GetConvexHullPoints()) {
41  vecConvexHullPoints.emplace_back(c_point.GetX(),
42  c_point.GetZ(),
43  -c_point.GetY());
44  }
45  ptrShape = CDynamics3DShapeManager::RequestConvexHull(vecConvexHullPoints);
46  break;
47  default:
48  THROW_ARGOSEXCEPTION("Collision shape geometry not implemented");
49  break;
50  }
51  return ptrShape;
52  }
53 
54  /****************************************/
55  /****************************************/
56 
57  CDynamics3DMultiBodyObjectModel::CAbstractBody::SData
58  CDynamics3DPrototypeModel::CreateBodyData(const CPrototypeLinkEntity& c_link_entity) {
59  /* Get friction */
60  btScalar fFriction = GetEngine().GetDefaultFriction();
61  /* Calculate inertia */
62  btScalar fMass = c_link_entity.GetMass();
63  btVector3 cInertia;
64  RequestShape(c_link_entity)->calculateLocalInertia(fMass, cInertia);
65  /* Calculate start transform */
66  const CVector3& cPosition = c_link_entity.GetAnchor().Position;
67  const CQuaternion& cOrientation = c_link_entity.GetAnchor().Orientation;
68  btTransform cStartTransform(btQuaternion(cOrientation.GetX(),
69  cOrientation.GetZ(),
70  -cOrientation.GetY(),
71  cOrientation.GetW()),
72  btVector3(cPosition.GetX(),
73  cPosition.GetZ(),
74  -cPosition.GetY()));
75  /* Calculate center of mass offset */
76  btTransform cCenterOfMassOffset(btQuaternion(0.0f, 0.0f, 0.0f, 1.0f),
77  btVector3(0.0f, -c_link_entity.GetExtents().GetZ() * 0.5f, 0.0f));
78  std::vector<CAbstractBody::SData::SDipole> vecDipoles;
79  /* check if this link is magnetic */
80  if(m_cEntity.HasMagnetEquippedEntity()) {
83  for(CMagnetEquippedEntity::SInstance& s_instance : vecInstances) {
84  /* check if the dipole/magnet belongs to this link by comparing the anchors */
85  if(s_instance.Anchor.Index == c_link_entity.GetAnchor().Index) {
86  btTransform cOffset(btQuaternion(0.0f, 0.0f, 0.0f, 1.0f),
87  btVector3(s_instance.Offset.GetX(),
88  s_instance.Offset.GetZ(),
89  -s_instance.Offset.GetY()));
90  cOffset *= cCenterOfMassOffset;
91  std::function<btVector3()> fnGetField = [&s_instance] () {
92  const CVector3& cField = s_instance.Magnet.GetField();
93  return btVector3(cField.GetX(), cField.GetZ(), -cField.GetY());
94  };
95  vecDipoles.emplace_back(fnGetField, cOffset);
96  }
97  }
98  }
99  /* Return link data */
100  return CAbstractBody::SData(cStartTransform, cCenterOfMassOffset, cInertia, fMass, fFriction, vecDipoles);
101 
102  }
103 
104  /****************************************/
105  /****************************************/
106 
108  CPrototypeEntity& c_entity) :
110  c_entity,
111  c_entity.GetLinkEquippedEntity().GetLinks().size() - 1,
112  !c_entity.GetEmbodiedEntity().IsMovable()),
113  m_cEntity(c_entity),
114  m_cJointEquippedEntity(c_entity.GetJointEquippedEntity()) {
115  /* Use the reference link as the base of the robot */
117  /* Get the collision shape */
118  std::shared_ptr<btCollisionShape> ptrBaseLinkShape = RequestShape(cBaseLink);
119  /* Set up the base link body */
120  std::shared_ptr<CBase> ptrBase =
121  std::make_shared<CBase>(*this, &cBaseLink.GetAnchor(), ptrBaseLinkShape, CreateBodyData(cBaseLink));
122  /* Add to collection */
123  m_vecBodies.push_back(ptrBase);
124  /* Counter for enumerating the links inside the btMultiBody */
125  UInt32 unLinkIndex = 0;
126  /* Copy all joints pointers into a temporary vector */
127  CPrototypeJointEntity::TVector vecJointsToAdd =
128  m_cJointEquippedEntity.GetJoints();
129  /* While there are joints to be added */
130  while(! vecJointsToAdd.empty()) {
131  size_t unRemainingJoints = vecJointsToAdd.size();
132  for(auto it_joint = std::begin(vecJointsToAdd);
133  it_joint != std::end(vecJointsToAdd);
134  ++it_joint) {
135  /* Get a reference to the joint */
136  CPrototypeJointEntity& cJoint = (**it_joint);
137  /* Get a reference to the parent link entity */
138  const CPrototypeLinkEntity& cParentLink = cJoint.GetParentLink();
139  /* Check if the parent link has been added */
140  auto itParentLinkBody =
141  std::find_if(std::begin(m_vecBodies),
142  std::end(m_vecBodies),
143  [&cParentLink] (const std::shared_ptr<CAbstractBody>& ptr_body) {
144  return (cParentLink.GetAnchor().Index == ptr_body->GetAnchor().Index);
145  });
146  /* If the parent link hasn't been added yet, try the next joint */
147  if(itParentLinkBody == std::end(m_vecBodies)) {
148  continue;
149  }
150  /* Parent body must be a CLink, therefore no need to use dynamic_pointer_cast */
151  std::shared_ptr<CLink> ptrParentLinkBody =
152  std::static_pointer_cast<CLink>(*itParentLinkBody);
153  /* Get a reference to the child link */
154  CPrototypeLinkEntity& cChildLink = cJoint.GetChildLink();
155  /* Get the collision shape */
156  std::shared_ptr<btCollisionShape> ptrChildLinkShape =
157  RequestShape(cChildLink);
158  /* Set up the child link body */
159  std::shared_ptr<CLink> ptrChildLinkBody =
160  std::make_shared<CLink>(*this,
161  unLinkIndex++,
162  &cChildLink.GetAnchor(),
163  ptrChildLinkShape,
164  CreateBodyData(cChildLink));
165  /* Add to collection */
166  m_vecBodies.push_back(ptrChildLinkBody);
167  /* Calculate joint parameters for parent link */
168  const CVector3& cParentOffsetPosition = cJoint.GetParentLinkJointPosition();
169  const CQuaternion& cParentOffsetOrientation = cJoint.GetParentLinkJointOrientation();
170  btTransform cParentOffsetTransform =
171  btTransform(btQuaternion(cParentOffsetOrientation.GetX(),
172  cParentOffsetOrientation.GetZ(),
173  -cParentOffsetOrientation.GetY(),
174  cParentOffsetOrientation.GetW()),
175  btVector3(cParentOffsetPosition.GetX(),
176  cParentOffsetPosition.GetZ(),
177  -cParentOffsetPosition.GetY()));
178  cParentOffsetTransform = ptrParentLinkBody->GetData().CenterOfMassOffset * cParentOffsetTransform;
179  /* Calculate joint parameters for child link */
180  const CVector3& cChildOffsetPosition = cJoint.GetChildLinkJointPosition();
181  const CQuaternion& cChildOffsetOrientation = cJoint.GetChildLinkJointOrientation();
182  btTransform cChildOffsetTransform =
183  btTransform(btQuaternion(cChildOffsetOrientation.GetX(),
184  cChildOffsetOrientation.GetZ(),
185  -cChildOffsetOrientation.GetY(),
186  cChildOffsetOrientation.GetW()),
187  btVector3(cChildOffsetPosition.GetX(),
188  cChildOffsetPosition.GetZ(),
189  -cChildOffsetPosition.GetY()));
190  cChildOffsetTransform = ptrChildLinkBody->GetData().CenterOfMassOffset * cChildOffsetTransform;
191  /* Calculate the joint axis */
192  btVector3 cJointAxis(cJoint.GetJointAxis().GetX(),
193  cJoint.GetJointAxis().GetZ(),
194  -cJoint.GetJointAxis().GetY());
195  /* Calculate the parent to child joint rotation */
196  /*
197  // From testing, these both the of following solutions seem correct although one may be wrong
198  btQuaternion cParentToChildRotation = cParentOffsetTransform.inverse().getRotation() *
199  cChildOffsetTransform.getRotation();
200  */
201  btQuaternion cParentToChildRotation = cChildOffsetTransform.getRotation() *
202  cParentOffsetTransform.inverse().getRotation();
203  /* Store joint configuration for reset */
204  m_vecJoints.emplace_back(cJoint.GetType(),
205  ptrParentLinkBody,
206  ptrChildLinkBody,
207  cParentOffsetTransform.getOrigin(),
208  -cChildOffsetTransform.getOrigin(),
209  cParentToChildRotation,
210  cJointAxis,
211  cJoint.GetDisableCollision());
212  /* Sensor and actuator configuration for revolute and prismatic joints */
215  /* If the joint actuator isn't disabled */
216  CPrototypeJointEntity::SActuator& sActuator = cJoint.GetActuator();
218  m_vecActuators.emplace_back(*this, sActuator, ptrChildLinkBody->GetIndex());
219  }
220  /* And if the joint sensor isn't disabled */
221  CPrototypeJointEntity::SSensor& sSensor = cJoint.GetSensor();
223  m_vecSensors.emplace_back(*this, sSensor, ptrChildLinkBody->GetIndex());
224  }
225  }
226  /* Joint limits */
227  if(cJoint.HasLimit()) {
229  const CRange<CRadians>& cLimit = cJoint.GetLimit().Revolute;
230  m_vecLimits.emplace_back(*this,
231  cLimit.GetMin().GetValue(),
232  cLimit.GetMax().GetValue(),
233  ptrChildLinkBody->GetIndex());
234  }
235  else if(cJoint.GetType() == CPrototypeJointEntity::EType::PRISMATIC) {
236  const CRange<Real>& cLimit = cJoint.GetLimit().Prismatic;
237  m_vecLimits.emplace_back(*this,
238  cLimit.GetMin(),
239  cLimit.GetMax(),
240  ptrChildLinkBody->GetIndex());
241  }
242  }
243  /* Now that the joint and link has been added we remove it from the vector
244  and restart the loop */
245  vecJointsToAdd.erase(it_joint);
246  break;
247  }
248  if(unRemainingJoints == vecJointsToAdd.size()) {
249  CPrototypeJointEntity* pcJoint = vecJointsToAdd.front();
250  THROW_ARGOSEXCEPTION("Can not add link \"" <<
251  pcJoint->GetChildLink().GetId() <<
252  "\" to the model before its parent link \"" <<
253  pcJoint->GetParentLink().GetId() <<
254  "\" has been added.");
255  }
256  }
257  for(CPrototypeLinkEntity* pc_link : m_cEntity.GetLinkEquippedEntity().GetLinks()) {
258  if(std::find_if(std::begin(m_vecBodies),
259  std::end(m_vecBodies),
260  [pc_link] (std::shared_ptr<CAbstractBody>& ptr_body) {
261  return (pc_link->GetAnchor().Index == ptr_body->GetAnchor().Index);
262  }) == std::end(m_vecBodies)) {
263  THROW_ARGOSEXCEPTION("Link \"" << pc_link->GetId() <<
264  "\" is not connected to the model.");
265 
266  }
267  }
268  /* Finalize model with a reset */
269  Reset();
270  }
271 
272  /****************************************/
273  /****************************************/
274 
275  void CDynamics3DPrototypeModel::AddToWorld(btMultiBodyDynamicsWorld& c_world) {
276  /* Call CDynamics3DMultiBodyObjectModel::AddToWorld to add all bodies to the world */
278  /* Add the actuators (btMultiBodyJointMotors) constraints to the world */
279  for(SActuator& s_actuator : m_vecActuators) {
280  c_world.addMultiBodyConstraint(&s_actuator.Motor);
281  }
282  /* Add the joint limits to the world */
283  for(SLimit& s_limit : m_vecLimits) {
284  c_world.addMultiBodyConstraint(&s_limit.Constraint);
285  }
286  }
287 
288  /****************************************/
289  /****************************************/
290 
291  void CDynamics3DPrototypeModel::RemoveFromWorld(btMultiBodyDynamicsWorld& c_world) {
292  /* Remove the joint limits to the world */
293  for(SLimit& s_limit : m_vecLimits) {
294  c_world.removeMultiBodyConstraint(&s_limit.Constraint);
295  }
296  /* Remove the actuators (btMultiBodyJointMotors) constraints to the world */
297  for(SActuator& s_actuator : m_vecActuators) {
298  c_world.removeMultiBodyConstraint(&s_actuator.Motor);
299  }
300  /* Call CDynamics3DMultiBodyObjectModel::RemoveFromWorld to remove all bodies to the world */
302  }
303 
304  /****************************************/
305  /****************************************/
306 
308  /* Reset the base class (recreates the btMultiBody and calls reset on the bodies) */
310  /* Add setup the links and joints */
311  for(SJoint& s_joint : m_vecJoints) {
312  switch(s_joint.Type) {
314  m_cMultiBody.setupFixed(s_joint.Child->GetIndex(),
315  s_joint.Child->GetData().Mass,
316  s_joint.Child->GetData().Inertia,
317  s_joint.Parent->GetIndex(),
318  s_joint.ParentToChildRotation,
319  s_joint.ParentOffset,
320  s_joint.ChildOffset);
321  break;
323  m_cMultiBody.setupSpherical(s_joint.Child->GetIndex(),
324  s_joint.Child->GetData().Mass,
325  s_joint.Child->GetData().Inertia,
326  s_joint.Parent->GetIndex(),
327  s_joint.ParentToChildRotation,
328  s_joint.ParentOffset,
329  s_joint.ChildOffset,
330  s_joint.DisableCollision);
331  break;
333  m_cMultiBody.setupRevolute(s_joint.Child->GetIndex(),
334  s_joint.Child->GetData().Mass,
335  s_joint.Child->GetData().Inertia,
336  s_joint.Parent->GetIndex(),
337  s_joint.ParentToChildRotation,
338  s_joint.Axis,
339  s_joint.ParentOffset,
340  s_joint.ChildOffset,
341  s_joint.DisableCollision);
342  break;
344  m_cMultiBody.setupPrismatic(s_joint.Child->GetIndex(),
345  s_joint.Child->GetData().Mass,
346  s_joint.Child->GetData().Inertia,
347  s_joint.Parent->GetIndex(),
348  s_joint.ParentToChildRotation,
349  s_joint.Axis,
350  s_joint.ParentOffset,
351  s_joint.ChildOffset,
352  s_joint.DisableCollision);
353  break;
354  default:
355  break;
356  }
357  }
358  /* Reset the actuators */
359  for(SActuator& s_actuator : m_vecActuators) {
360  s_actuator.Reset();
361  }
362  /* Reset the joint limits */
363  for(SLimit& s_limit : m_vecLimits) {
364  s_limit.Reset();
365  }
366  /* Allocate memory and prepare the btMultiBody */
367  m_cMultiBody.finalizeMultiDof();
368  /* Synchronize with the entity in the space */
370  }
371 
372  /****************************************/
373  /****************************************/
374 
376  /* Write back sensor data to the joints */
377  for(SSensor& s_sensor : m_vecSensors) {
378  s_sensor.Update();
379  }
380  /* Update anchors using the base class method */
382  }
383 
384  /****************************************/
385  /****************************************/
386 
388  /* Read in actuator data from the joints */
389  for(SActuator& s_actuator : m_vecActuators) {
390  s_actuator.Update();
391  }
392  }
393 
394  /****************************************/
395  /****************************************/
396 
397  CDynamics3DPrototypeModel::SJoint::SJoint(CPrototypeJointEntity::EType e_type,
398  std::shared_ptr<CLink>& ptr_parent,
399  std::shared_ptr<CLink>& ptr_child,
400  const btVector3& c_parent_offset,
401  const btVector3& c_child_offset,
402  const btQuaternion& c_parent_to_child_rotation,
403  const btVector3& c_axis,
404  bool b_disable_collision) :
405  Type(e_type),
406  Parent(ptr_parent),
407  Child(ptr_child),
408  ParentOffset(c_parent_offset),
409  ChildOffset(c_child_offset),
410  ParentToChildRotation(c_parent_to_child_rotation),
411  Axis(c_axis),
412  DisableCollision(b_disable_collision) {}
413 
414  /****************************************/
415  /****************************************/
416 
417  CDynamics3DPrototypeModel::SLimit::SLimit(CDynamics3DPrototypeModel& c_model,
418  Real f_lower_limit,
419  Real f_upper_limit,
420  SInt32 n_joint_index) :
421  Model(c_model),
422  LowerLimit(f_lower_limit),
423  UpperLimit(f_upper_limit),
424  JointIndex(n_joint_index),
425  Constraint(&c_model.GetMultiBody(),
426  n_joint_index,
427  f_lower_limit,
428  f_upper_limit) {}
429 
430  /****************************************/
431  /****************************************/
432 
433  void CDynamics3DPrototypeModel::SLimit::Reset() {
434  Constraint.~btMultiBodyJointLimitConstraint();
435  new (&Constraint) btMultiBodyJointLimitConstraint(&Model.GetMultiBody(),
436  JointIndex,
437  LowerLimit,
438  UpperLimit);
439  }
440 
441  /****************************************/
442  /****************************************/
443 
444  CDynamics3DPrototypeModel::SActuator::SActuator(CDynamics3DPrototypeModel& c_model,
445  CPrototypeJointEntity::SActuator& s_actuator,
446  SInt32 n_joint_index) :
447  Model(c_model),
448  Actuator(s_actuator),
449  JointIndex(n_joint_index),
450  Motor(&c_model.GetMultiBody(),
451  n_joint_index,
452  0,
453  s_actuator.Target,
454  s_actuator.MaxImpulse) {}
455 
456  /****************************************/
457  /****************************************/
458 
459  void CDynamics3DPrototypeModel::SActuator::Reset() {
460  Motor.~btMultiBodyJointMotor();
461  new (&Motor) btMultiBodyJointMotor(&Model.GetMultiBody(),
462  JointIndex,
463  0,
464  Actuator.Target,
465  Actuator.MaxImpulse);
466  }
467 
468  /****************************************/
469  /****************************************/
470 
471  void CDynamics3DPrototypeModel::SActuator::Update() {
473  Motor.setPositionTarget(Actuator.Target);
474  }
475  else if(Actuator.Mode == CPrototypeJointEntity::SActuator::EMode::VELOCITY) {
476  Motor.setVelocityTarget(Actuator.Target);
477  }
478  }
479 
480  /****************************************/
481  /****************************************/
482 
483  CDynamics3DPrototypeModel::SSensor::SSensor(CDynamics3DPrototypeModel& c_model,
484  CPrototypeJointEntity::SSensor& s_sensor,
485  SInt32 n_joint_index) :
486  Model(c_model),
487  Sensor(s_sensor),
488  JointIndex(n_joint_index) {}
489 
490  /****************************************/
491  /****************************************/
492 
493  void CDynamics3DPrototypeModel::SSensor::Update() {
495  Sensor.Value = Model.GetMultiBody().getJointPos(JointIndex);
496  }
497  else if(Sensor.Mode == CPrototypeJointEntity::SSensor::EMode::VELOCITY) {
498  Sensor.Value = Model.GetMultiBody().getJointVel(JointIndex);
499  }
500  }
501 
502  /****************************************/
503  /****************************************/
504 
506 
507  /****************************************/
508  /****************************************/
509 
510 }
511 
#define THROW_ARGOSEXCEPTION(message)
This macro throws an ARGoS exception with the passed message.
signed int SInt32
32-bit signed integer.
Definition: datatypes.h:93
unsigned int UInt32
32-bit unsigned integer.
Definition: datatypes.h:97
float Real
Collects all ARGoS code.
Definition: datatypes.h:39
The namespace containing all the ARGoS related code.
Definition: ci_actuator.h:12
REGISTER_STANDARD_DYNAMICS3D_OPERATIONS_ON_ENTITY(CEPuckEntity, CDynamics3DEPuckModel)
const std::string & GetId() const
Returns the id of this entity.
Definition: entity.h:157
UInt32 Index
The index of the anchor assigned by the embodied entity.
Definition: physics_model.h:45
Real GetW() const
Definition: quaternion.h:49
Real GetX() const
Definition: quaternion.h:53
Real GetZ() const
Definition: quaternion.h:61
Real GetY() const
Definition: quaternion.h:57
T GetMax() const
Definition: range.h:48
T GetMin() const
Definition: range.h:32
A 3D vector class.
Definition: vector3.h:31
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
virtual void RemoveFromWorld(btMultiBodyDynamicsWorld &c_world)
virtual void AddToWorld(btMultiBodyDynamicsWorld &c_world)
virtual void UpdateEntityStatus()
Updates the status of the associated entity.
CDynamics3DPrototypeModel(CDynamics3DEngine &c_engine, CPrototypeEntity &c_entity)
virtual void UpdateFromEntityStatus()
Updates the state of this model from the status of the associated entity.
bool HasMagnetEquippedEntity() const
CMagnetEquippedEntity & GetMagnetEquippedEntity()
CPrototypeLinkEquippedEntity & GetLinkEquippedEntity()
CPrototypeLinkEntity & GetChildLink()
const CVector3 & GetChildLinkJointPosition() const
const CVector3 & GetParentLinkJointPosition() const
const CVector3 & GetJointAxis() const
std::vector< CPrototypeJointEntity * > TVector
CPrototypeLinkEntity & GetParentLink()
const CQuaternion & GetParentLinkJointOrientation() const
const CQuaternion & GetChildLinkJointOrientation() const
CPrototypeJointEntity::TVector & GetJoints()
CPrototypeLinkEntity::TVector & GetLinks()
SInstance::TVector & GetInstances()
btScalar GetDefaultFriction() const
std::vector< std::shared_ptr< CAbstractBody > > m_vecBodies
virtual void UpdateEntityStatus()
Updates the status of the associated entity.
CDynamics3DEngine & GetEngine()
virtual void RemoveFromWorld(btMultiBodyDynamicsWorld &c_world)
virtual void AddToWorld(btMultiBodyDynamicsWorld &c_world)
static std::shared_ptr< btCollisionShape > RequestBox(const btVector3 &c_half_extents)
static std::shared_ptr< btCollisionShape > RequestSphere(btScalar f_radius)
static std::shared_ptr< btCollisionShape > RequestConvexHull(const std::vector< btVector3 > &vec_points)
static std::shared_ptr< btCollisionShape > RequestCylinder(const btVector3 &c_half_extents)