iMSTK
Interactive Medical Simulation Toolkit
imstkRigidObjectController.cpp
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #include "imstkRigidObjectController.h"
8 #include "imstkDeviceClient.h"
9 #include "imstkLogger.h"
10 #include "imstkRbdConstraint.h"
11 #include "imstkRigidObject2.h"
12 
13 #include <Eigen/Eigenvalues>
14 
15 namespace imstk
16 {
17 void
18 RigidObjectController::setControlledObject(std::shared_ptr<SceneObject> obj)
19 {
20  SceneObjectController::setControlledObject(obj);
21  m_rigidObject = std::dynamic_pointer_cast<RigidObject2>(obj);
22  CHECK(m_rigidObject != nullptr) <<
23  "RigidObjectController controlled object must be type RigidObject2";
24 }
25 
26 void
28 {
29  if (!updateTrackingData(dt))
30  {
31  LOG(WARNING) << "warning: could not update tracking info.";
32  return;
33  }
34 
35  if (m_rigidObject == nullptr)
36  {
37  return;
38  }
39 
40  // Implementation partially from otaduy lin's paper eq14
41  // "A Modular Haptic Rendering Algorithm for Stable and Transparent 6 - DOF Manipulation"
42  if (m_deviceClient->getTrackingEnabled() && m_useSpring)
43  {
44  const Vec3d& currPos = m_rigidObject->getRigidBody()->getPosition();
45  const Quatd& currOrientation = m_rigidObject->getRigidBody()->getOrientation();
46  const Vec3d& currVelocity = m_rigidObject->getRigidBody()->getVelocity();
47  const Vec3d& currAngularVelocity = m_rigidObject->getRigidBody()->getAngularVelocity();
48  Vec3d& currForce = *m_rigidObject->getRigidBody()->m_force;
49  Vec3d& currTorque = *m_rigidObject->getRigidBody()->m_torque;
50 
51  const Vec3d& devicePos = getPosition();
52  const Quatd& deviceOrientation = getOrientation();
53  const Vec3d& deviceOffset = Vec3d(0.0, 0.0, 0.0);
54 
55  // If using critical damping automatically compute kd
57  {
58  const double mass = m_rigidObject->getRigidBody()->getMass();
59  const double linearKs = m_linearKs.maxCoeff();
60  m_linearKd = 2.0 * std::sqrt(mass * linearKs);
61 
62  const Mat3d inertia = m_rigidObject->getRigidBody()->getIntertiaTensor();
63  // Currently kd is not a 3d vector though it could be.
64  // So here we make an approximation. Either:
65  // - Use one colums eigenvalue (maxCoeff)
66  // - cbrt(eigenvalue0*eigenvalue1*eigenvalue2). (det)
67  // Both may behave weird on anistropic inertia tensors
68  //const double inertiaScale = inertia.eigenvalues().real().maxCoeff();
69  const double inertiaScale = std::cbrt(inertia.determinant());
70  const double angularKs = m_angularKs.maxCoeff();
71  m_angularKd = 2.0 * std::sqrt(inertiaScale * angularKs);
72  }
73 
74  // If kd > 2 * sqrt(mass * ks); The system is overdamped (may be intentional)
75  // If kd < 2 * sqrt(mass * ks); The system is underdamped (never intended)
76 
77  // Uses non-relative force
78  {
79  // Compute force
80  m_fS = m_linearKs.cwiseProduct(devicePos - currPos - deviceOffset);
81  m_fD = m_linearKd * (-currVelocity - currAngularVelocity.cross(deviceOffset));
82  Vec3d force = m_fS + m_fD;
83 
84  // Computer torque
85  const Quatd dq = deviceOrientation * currOrientation.inverse();
86  const Rotd angleAxes = Rotd(dq);
87  m_tS = deviceOffset.cross(force) + m_angularKs.cwiseProduct(angleAxes.axis() * angleAxes.angle());
88  m_tD = m_angularKd * -currAngularVelocity;
89  Vec3d torque = m_tS + m_tD;
90 
91  currForce += force;
92  currTorque += torque;
93  }
94 
95  // Uses relative velocity
96  //{
97  // const Vec3d& deviceVelocity = getVelocity();
98  // const Vec3d& deviceAngularVelocity = getAngularVelocity();
99 
100  // // Compute force
101  // m_fS = m_linearKs.cwiseProduct(devicePos - currPos - deviceOffset);
102  // m_fD = m_linearKd * (deviceVelocity - currVelocity - currAngularVelocity.cross(deviceOffset));
103  // Vec3d force = m_fS + m_fD;
104 
105  // // Compute torque
106  // const Quatd dq = deviceOrientation * currOrientation.inverse();
107  // const Rotd angleAxes = Rotd(dq);
108  // m_tS = deviceOffset.cross(force) + m_angularKs.cwiseProduct(angleAxes.axis() * angleAxes.angle());
109  // m_tD = m_angularKd * (deviceAngularVelocity - currAngularVelocity);
110  // Vec3d torque = m_tS + m_tD;
111 
112  // currForce += force;
113  // currTorque += torque;
114  //}
115  }
116  else
117  {
118  // Zero out external force/torque
119  *m_rigidObject->getRigidBody()->m_force = Vec3d(0.0, 0.0, 0.0);
120  *m_rigidObject->getRigidBody()->m_torque = Vec3d(0.0, 0.0, 0.0);
121  // Directly set position/rotation
122  (*m_rigidObject->getRigidBody()->m_pos) = getPosition();
123  (*m_rigidObject->getRigidBody()->m_orientation) = getOrientation();
124  }
125 
126  applyForces();
127  this->postEvent(Event(RigidObjectController::modified()));
128 }
129 
130 void
132 {
133  if (!m_deviceClient->getButton(0))
134  {
135  // Apply force back to device
136  if (m_rigidObject != nullptr && m_useSpring)
137  {
138  const Vec3d force = -getDeviceForce();
139  if (m_forceSmoothening)
140  {
141  m_forces.push_back(force);
142  m_forceSum += force;
143  if (static_cast<int>(m_forces.size()) > m_smoothingKernelSize)
144  {
145  m_forceSum -= m_forces.front();
146  m_forces.pop_front();
147  }
148  const Vec3d avgForce = m_forceSum / m_forces.size();
149 
150  // Render only the spring force (not the other forces the body has)
151  m_deviceClient->setForce(avgForce);
152  }
153  else
154  {
155  // Render only the spring force (not the other forces the body has)
156  m_deviceClient->setForce(force);
157  }
158  }
159  }
160  else
161  {
162  m_deviceClient->setForce(Vec3d(0.0, 0.0, 0.0));
163  }
164 }
165 } // namespace imstk
double m_angularKd
Damping coefficient, rotational.
bool m_useCriticalDamping
If on, kd is automatically computed.
bool m_useSpring
If off, pos & orientation directly set.
double m_linearKd
Damping coefficient, linear.
Base class for events which contain a type, priority, and data priority defaults to 0 and uses a grea...
virtual bool updateTrackingData(const double dt)
Update tracking data.
Compound Geometry.
const Quatd & getOrientation() const
Set/Get the orientation of the tracker.
const Vec3d & getPosition() const
Set/Get the position of the tracker.
void postEvent(const T &e)
Emits the event Direct observers will be immediately called, in sync Queued observers will receive th...
void applyForces() override
Apply forces to the haptic device.
Vec3d m_angularKs
Spring coefficient, rotational.
void update(const double &dt) override
Update controlled scene object using latest tracking information.
Vec3d getDeviceForce() const
Return the device applied force (scaled)
Vec3d m_linearKs
Spring coefficient, linear.