ARGoS 3
A parallel, multi-engine simulator for swarm robotics
dynamics3d_magnetism_plugin.cpp
Go to the documentation of this file.
1
10
11#include <argos3/plugins/simulator/physics_engines/dynamics3d/dynamics3d_model.h>
12
13#include <algorithm>
14
15namespace argos {
16
17 /****************************************/
18 /****************************************/
19
21 GetNodeAttributeOrDefault(t_tree, "force_constant", m_fForceConstant, m_fForceConstant);
22 GetNodeAttributeOrDefault(t_tree, "max_distance", m_fMaxDistance, m_fMaxDistance);
23 }
24
25 /****************************************/
26 /****************************************/
27
29 for(std::shared_ptr<CDynamics3DModel::CAbstractBody>& ptr_body : c_model.GetBodies()) {
31 ptr_body->GetData().Dipoles) {
32 m_vecDipoles.emplace_back(ptr_body,
33 s_dipole.GetField,
34 s_dipole.Offset);
35 }
36 }
37 }
38
39 /****************************************/
40 /****************************************/
41
43 auto itRemove =
44 std::remove_if(std::begin(m_vecDipoles),
45 std::end(m_vecDipoles),
46 [&c_model] (const SMagneticDipole& c_magnetic_dipole) {
47 return(&(c_magnetic_dipole.Body->GetModel()) == &c_model);
48 });
49 m_vecDipoles.erase(itRemove, std::end(m_vecDipoles));
50 }
51
52 /****************************************/
53 /****************************************/
54
56 if(m_vecDipoles.size() < 2) {
57 /* Nothing to do */
58 return;
59 }
60 for(auto itDipole0 = std::begin(m_vecDipoles);
61 itDipole0 != (std::end(m_vecDipoles) - 1);
62 ++itDipole0) {
63 for(auto itDipole1 = std::next(itDipole0, 1);
64 itDipole1 != std::end(m_vecDipoles);
65 ++itDipole1) {
66 const btTransform& cTransformDipole0 = itDipole0->Offset * itDipole0->Body->GetTransform();
67 const btTransform& cTransformDipole1 = itDipole1->Offset * itDipole1->Body->GetTransform();
68 const btVector3& cPositionDipole0 = cTransformDipole0.getOrigin();
69 const btVector3& cPositionDipole1 = cTransformDipole1.getOrigin();
70 /* calculate the distance between the two magnetic bodies */
71 btScalar fDistance = cPositionDipole0.distance(cPositionDipole1);
72 /* optimization - don't calculate magnetism for dipoles more than m_fMaxDistance apart */
73 if(fDistance > m_fMaxDistance) {
74 continue;
75 }
76 /* perform Barnes-hut algorithm */
77 /* calculate the normalized seperation between the two dipoles, pointing from Dipole1 to Dipole0*/
78 const btVector3& cNormalizedSeparation =
79 btVector3(cPositionDipole0 - cPositionDipole1) / fDistance;
80 /* calculate the rotated field of dipole 0 */
81 const btVector3& cRotatedFieldDipole0 =
82 itDipole0->Body->GetTransform().getBasis() * itDipole0->GetField();
83 /* calculate the rotated field of dipole 1 */
84 const btVector3& cRotatedFieldDipole1 =
85 itDipole1->Body->GetTransform().getBasis() * itDipole1->GetField();
86 /* We now have cRotatedFieldDipole0 and cRotatedFieldDipole1 as the magnetic moments
87 (i.e., m0, m1), cNormalizedSeparation as the direction unit vector from Dipole 1
88 to Dipole 0 (i.e., n), fDistance is the scalar distance between the dipoles (i.e.,
89 d), and B0 is the magnetic flux density at Dipole 0.
90 B0 = u0/4pi * [3n(n.m1) - m1] / d^3
91 T0 = m0 * B0
92 = u0.4pi/d^3 * [3 (m1.n)(m0 * n) - m0 * m1]
93
94 F0 = grad(m0.B0)
95 = u0.4pi/d^4 * [-15n(m0.n)(m1.n) + 3n(m0.m1) + 3(m0(m1.n)+m1(m0.n))]
96 */
97 /* calculate the intermediate cross and dot products */
98 const btVector3& cCrossProduct01 = cRotatedFieldDipole0.cross(cRotatedFieldDipole1);
99 const btVector3& cCrossProduct0 = cRotatedFieldDipole0.cross(cNormalizedSeparation);
100 const btVector3& cCrossProduct1 = cRotatedFieldDipole1.cross(cNormalizedSeparation);
101 btScalar fDotProduct01 = cRotatedFieldDipole0.dot(cRotatedFieldDipole1);
102 btScalar fDotProduct0 = cRotatedFieldDipole0.dot(cNormalizedSeparation);
103 btScalar fDotProduct1 = cRotatedFieldDipole1.dot(cNormalizedSeparation);
104 /* calculate the magnetic force and torque */
105 const btVector3& cTorque0 =
106 ((3 * fDotProduct1 * cCrossProduct0) - cCrossProduct01) *
107 m_fForceConstant / btPow(fDistance, 3);
108 const btVector3& cTorque1 =
109 ((3 * fDotProduct0 * cCrossProduct1) + cCrossProduct01) *
110 m_fForceConstant / btPow(fDistance, 3);
111 const btVector3& cForce = (m_fForceConstant / btPow(fDistance, 4)) *
112 ((-15 * cNormalizedSeparation * fDotProduct1 * fDotProduct0) +
113 (3 * cNormalizedSeparation * fDotProduct01) +
114 (3 * (fDotProduct1 * cRotatedFieldDipole0 + fDotProduct0 * cRotatedFieldDipole1)));
115 /* apply torques and forces to the bodies */
116 itDipole0->Body->ApplyForce(cForce, (itDipole0->Offset).getOrigin());
117 itDipole0->Body->ApplyTorque(cTorque0);
118 itDipole1->Body->ApplyForce(-cForce, (itDipole1->Offset).getOrigin());
119 itDipole1->Body->ApplyTorque(cTorque1);
120 }
121 }
122 }
123
124 /****************************************/
125 /****************************************/
126
128 "magnetism",
129 "Michael Allwright [allsey87@gmail.com]",
130 "1.0",
131 "Applies forces and torques between magnetic dipoles in the simulation",
132 "For a description on how to use this plugin, please consult the documentation\n"
133 "for the dynamics3d physics engine plugin",
134 "Usable");
135
136 /****************************************/
137 /****************************************/
138
139}
#define REGISTER_DYNAMICS3D_PLUGIN(CLASSNAME, LABEL, AUTHOR, VERSION, BRIEF_DESCRIPTION, LONG_DESCRIPTION, STATUS)
The namespace containing all the ARGoS related code.
Definition ci_actuator.h:12
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.
virtual void RegisterModel(CDynamics3DModel &c_model)
virtual void UnregisterModel(CDynamics3DModel &c_model)
virtual void Init(TConfigurationNode &t_tree)
std::vector< std::shared_ptr< CAbstractBody > > & GetBodies()