ARGoS 3
A parallel, multi-engine simulator for swarm robotics
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
17namespace 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()) {
30 ptrShape = CDynamics3DShapeManager::RequestBox(cHalfExtents);
31 break;
33 ptrShape = CDynamics3DShapeManager::RequestCylinder(cHalfExtents);
34 break;
36 ptrShape = CDynamics3DShapeManager::RequestSphere(cHalfExtents.getZ());
37 break;
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 */
116 CPrototypeLinkEntity& cBaseLink = c_entity.GetLinkEquippedEntity().GetReferenceLink();
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 }
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 }
498 Sensor.Value = Model.GetMultiBody().getJointVel(JointIndex);
499 }
500 }
501
502 /****************************************/
503 /****************************************/
504
506
507 /****************************************/
508 /****************************************/
509
510}
511
#define REGISTER_STANDARD_DYNAMICS3D_OPERATIONS_ON_ENTITY(SPACE_ENTITY, DYN3D_ENTITY)
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
#define THROW_ARGOSEXCEPTION(message)
This macro throws an ARGoS exception with the passed message.
The namespace containing all the ARGoS related code.
Definition ci_actuator.h:12
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.
virtual void UpdateEntityStatus()
Updates the status of the associated entity.
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.
CMagnetEquippedEntity & GetMagnetEquippedEntity()
bool HasMagnetEquippedEntity() const
CPrototypeLinkEquippedEntity & GetLinkEquippedEntity()
const CVector3 & GetJointAxis() const
const CVector3 & GetChildLinkJointPosition() const
CPrototypeLinkEntity & GetParentLink()
std::vector< CPrototypeJointEntity * > TVector
const CVector3 & GetParentLinkJointPosition() const
CPrototypeLinkEntity & GetChildLink()
const CQuaternion & GetChildLinkJointOrientation() const
const CQuaternion & GetParentLinkJointOrientation() const
SInstance::TVector & GetInstances()
btScalar GetDefaultFriction() const
std::vector< std::shared_ptr< CAbstractBody > > m_vecBodies
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)