KeypointsImpedanceController.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * ArmarX is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * ArmarX is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * @package ...
17  * @author Jianfeng Gao ( jianfeng dot gao at kit dot edu )
18  * @date 2021
19  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20  * GNU General Public License
21  */
22 
24 
25 #include <VirtualRobot/MathTools.h>
26 #include <VirtualRobot/RobotNodeSet.h>
27 
30 
35 
37 #include <armarx/control/common/control_law/aron/KeypointControllerConfig.aron.generated.h>
39 
41 {
42  NJointControllerRegistration<NJointKeypointsImpedanceController>
44  "NJointKeypointsImpedanceController");
45 
47  const RobotUnitPtr& robotUnit,
48  const NJointControllerConfigPtr& config,
50  {
51  ConfigPtrT cfg = ConfigPtrT::dynamicCast(config);
52 
55  {
56  auto configData = ::armarx::fromAronDict<AronDTO, BO>(cfg->config);
57 
58  kinematicChainName = configData.nodeSetName;
60  validateConfigData(configData);
61 
64  bufferUserToRt.reinitAllBuffers(configData);
65  }
66 
68  VirtualRobot::RobotNodeSetPtr rtRns = rtGetRobot()->getRobotNodeSet(kinematicChainName);
69 
70  nonRtRobot = robotUnit->cloneRobot();
71  VirtualRobot::RobotNodeSetPtr nonRtRns = nonRtRobot->getRobotNodeSet(kinematicChainName);
72  robotUnit->updateVirtualRobot(nonRtRobot);
73 
76 
77  controller.initialize(nonRtRns);
78 
79  jointNames.clear();
80  for (size_t i = 0; i < rtRns->getSize(); ++i)
81  {
82  std::string jointName = rtRns->getNode(i)->getName();
83  jointNames.push_back(jointName);
84  ControlTargetBase* ct = useControlTarget(jointName, ControlModes::Torque1DoF);
86  const SensorValueBase* sv = useSensorValue(jointName);
88  auto casted_ct = ct->asA<ControlTarget1DoFActuatorTorque>();
89  ARMARX_CHECK_EXPRESSION(casted_ct);
90  targets.push_back(casted_ct);
91 
92  const SensorValue1DoFActuatorTorque* torqueSensor =
93  sv->asA<SensorValue1DoFActuatorTorque>();
94  const SensorValue1DoFActuatorVelocity* velocitySensor =
95  sv->asA<SensorValue1DoFActuatorVelocity>();
96  const SensorValue1DoFActuatorPosition* positionSensor =
97  sv->asA<SensorValue1DoFActuatorPosition>();
98  if (!torqueSensor)
99  {
100  ARMARX_WARNING << "No Torque sensor available for " << jointName;
101  }
102  if (!velocitySensor)
103  {
104  ARMARX_WARNING << "No velocity sensor available for " << jointName;
105  }
106  if (!positionSensor)
107  {
108  ARMARX_WARNING << "No position sensor available for " << jointName;
109  }
110 
111  sensorDevices.torqueSensors.push_back(torqueSensor);
112  sensorDevices.velocitySensors.push_back(velocitySensor);
113  sensorDevices.positionSensors.push_back(positionSensor);
114  };
115 
116  controlTargets.targets.resize(rtRns->getSize(), 0.);
117  }
118 
119  std::string
121  {
122  return "NJointKeypointsImpedanceController";
123  }
124 
125  //std::string NJointKeypointsImpedanceController::getKinematicChainName(const Ice::Current &)
126  //{
127  // return kinematicChainName;
128  //}
129 
130  void
132  {
133  runTask("NJointTaskspaceAdmittanceAdditionalTask",
134  [&]
135  {
136  CycleUtil c(1);
137  getObjectScheduler()->waitForObjectStateMinimum(eManagedIceObjectStarted);
139  << "Create a new thread alone NJointKeypointsImpedanceController";
140  while (getState() == eManagedIceObjectStarted)
141  {
142  if (isControllerActive())
143  {
144  additionalTask();
145  }
146  c.waitForCycleDuration();
147  }
148  });
149  }
150 
151  void
153  {
154  robotUnit->updateVirtualRobot(nonRtRobot);
155 
157  bufferRtToAdditionalTask.getUpToDateReadBuffer());
158  }
159 
160  void
162  const IceUtil::Time& timeSinceLastIteration)
163  {
164  double deltaT = timeSinceLastIteration.toSecondsDouble();
165  auto& userConfig = bufferUserToRt.getUpToDateReadBuffer();
166 
167  if (rtFirstRun.load())
168  {
169  rtFirstRun.store(false);
170  rtReady.store(true);
171  controller.firstRun();
172  }
173 
174  auto& s = bufferRtToAdditionalTask.getWriteBuffer();
175  size_t nDoF = sensorDevices.positionSensors.size();
176  for (size_t i = 0; i < nDoF; ++i)
177  {
178  s.jointPosition[i] = sensorDevices.positionSensors[i]->position;
179  s.jointVelocity[i] = sensorDevices.velocitySensors[i]->velocity;
180  s.jointTorque[i] = sensorDevices.torqueSensors[i]->torque;
181  }
182  s.deltaT = deltaT;
183  bufferRtToAdditionalTask.commitWrite();
184 
185  controller.run(userConfig, controlTargets);
186 
187  for (unsigned int i = 0; i < controlTargets.targets.size(); i++)
188  {
189  targets.at(i)->torque = controlTargets.targets.at(i);
190  if (!targets.at(i)->isValid())
191  {
192  targets.at(i)->torque = 0;
193  }
194  }
195  }
196 
197  void
199  const Ice::Current& iceCurrent)
200  {
201  auto configData = ::armarx::fromAronDict<AronDTO, BO>(dto);
202 
203  validateConfigData(configData);
204 
207 
208  bufferUserToRt.getWriteBuffer() = configData;
210  }
211 
213  NJointKeypointsImpedanceController::getConfig(const Ice::Current& iceCurrent)
214  {
216  return armarx::toAronDict<AronDTO, BO>(configData);
217  }
218 
219  void
221  {
222  const auto nDoF = jointNames.size();
223 
224  const auto checkSize = [nDoF](const auto& v)
225  { ARMARX_CHECK_EQUAL((unsigned)v.rows(), nDoF); };
226  const auto checkNonNegative = [](const auto& v) { ARMARX_CHECK((v.array() >= 0).all()); };
227 
228  if (!configData.desiredNullspaceJointAngles.has_value() and !isControllerActive())
229  {
230  ARMARX_INFO << "No user defined nullspace target, reset to zero with " << VAROUT(nDoF);
231  configData.desiredNullspaceJointAngles = Eigen::VectorXf::Zero(nDoF);
232  reInitPreActivate.store(true);
233  }
234  checkSize(configData.desiredNullspaceJointAngles.value());
235  checkSize(configData.kdNullspace);
236  checkSize(configData.kpNullspace);
237 
238  checkNonNegative(configData.kdNullspace);
239  checkNonNegative(configData.kpNullspace);
240  checkNonNegative(configData.kdImpedance);
241  checkNonNegative(configData.kpImpedance);
242 
243  ARMARX_CHECK_GREATER_EQUAL(configData.numPoints, 0);
244  ARMARX_CHECK_GREATER_EQUAL(configData.qvelFilter, 0);
245  ARMARX_CHECK_GREATER_EQUAL(configData.numPoints, 0);
246  ARMARX_CHECK_GREATER_EQUAL(configData.keypointPositionFilter, 0);
247  ARMARX_CHECK_GREATER_EQUAL(configData.keypointVelocityFilter, 0);
248 
249  ARMARX_CHECK_EQUAL(configData.keypointKp.size(), configData.numPoints * 3);
250  ARMARX_CHECK_EQUAL(configData.keypointKd.size(), configData.numPoints * 3);
251  ARMARX_CHECK_EQUAL(configData.fixedTranslation.size(), configData.numPoints * 3);
252  }
253 
254  void
257  const DebugObserverInterfacePrx& debugObs)
258  {
259  StringVariantBaseMap datafields;
260 
261  auto nonRtData = controller.bufferNonRtToOnPublish.getUpToDateReadBuffer();
262  auto rtData = controller.bufferRtToOnPublish.getUpToDateReadBuffer();
264 
265  common::debugEigenVec(datafields, "kpImpedance", configData.kpImpedance);
266  common::debugEigenVec(datafields, "kdImpedance", configData.kdImpedance);
267 
268  common::debugEigenVec(datafields, "forceImpedance", rtData.forceImpedance);
269  common::debugEigenVec(datafields, "desiredJointTorques", rtData.desiredJointTorques);
270  common::debugEigenVec(datafields, "f_Impedance", rtData.forceImpedance);
271  common::debugEigenVec(datafields, "tau_d_joint", rtData.desiredJointTorques);
272 
273  common::debugEigenPose(datafields, "current_pose", nonRtData.currentPose);
274  common::debugEigenPose(datafields, "desired_pose", nonRtData.desiredPose);
275  common::debugEigenVec(datafields, "v_d", nonRtData.desiredVel);
276  common::debugEigenVec(datafields, "a_d", nonRtData.desiredAcc);
277  common::debugEigenVec(datafields, "f_density", nonRtData.desiredDensityForce);
278  common::debugEigenVec(datafields, "pointTrackingForce", nonRtData.pointTrackingForce);
280  datafields, "desiredKeypointPosition", nonRtData.desiredKeypointPosition);
282  datafields, "currentKeypointPosition", nonRtData.currentKeypointPosition);
284  datafields, "currentKeypointVelocity", nonRtData.currentKeypointVelocity);
286  datafields, "filteredKeypointPosition", nonRtData.filteredKeypointPosition);
287 
288  debugObs->setDebugChannel("NJointKeypointsImpedanceController", datafields);
289  }
290 
291  void
293  {
294  VirtualRobot::RobotNodeSetPtr rns = rtGetRobot()->getRobotNodeSet(kinematicChainName);
295  Eigen::Matrix4f currentPose = rns->getTCP()->getPoseInRootFrame();
296  ARMARX_IMPORTANT << "rt preactivate controller with target pose\n\n" << currentPose;
297  controller.preactivateInit(rns, bufferUserToRt.getUpToDateReadBuffer());
298 
299  if (reInitPreActivate.load())
300  {
302  c.desiredNullspaceJointAngles.value() = rns->getJointValuesEigen();
303 
306 
307  reInitPreActivate.store(false);
308  }
309 
310  const auto nDoF = rns->getSize();
311 
312  {
313  law::RobotStatus rtToNonRtStatus;
314  rtToNonRtStatus.jointPosition.resize(nDoF, 0.);
315  rtToNonRtStatus.jointVelocity.resize(nDoF, 0.);
316  rtToNonRtStatus.jointTorque.resize(nDoF, 0.);
317  for (size_t i = 0; i < nDoF; ++i)
318  {
319  rtToNonRtStatus.jointPosition[i] = sensorDevices.positionSensors[i]->position;
320  rtToNonRtStatus.jointVelocity[i] = sensorDevices.velocitySensors[i]->velocity;
321  rtToNonRtStatus.jointTorque[i] = sensorDevices.torqueSensors[i]->torque;
322  }
323  bufferRtToAdditionalTask.reinitAllBuffers(rtToNonRtStatus);
324  }
325  }
326 
327  void
329  {
330  controller.isInitialized.store(false);
331  }
332 } // namespace armarx::control::njoint_controller::task_space
armarx::ControlTargetBase::asA
const T * asA() const
Definition: ControlTargetBase.h:76
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::SensorDevices::velocitySensors
std::vector< const SensorValue1DoFActuatorVelocity * > velocitySensors
Definition: KeypointsImpedanceController.h:87
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::bufferRtToAdditionalTask
TripleBuffer< law::RobotStatus > bufferRtToAdditionalTask
Definition: KeypointsImpedanceController.h:105
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::bufferAdditionalTaskToUser
TripleBuffer< BO > bufferAdditionalTaskToUser
Definition: KeypointsImpedanceController.h:103
armarx::control::common::debugEigenPose
void debugEigenPose(StringVariantBaseMap &datafields, const std::string &name, Eigen::Matrix4f pose)
Definition: utils.cpp:113
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::robotUnit
RobotUnitPtr robotUnit
Definition: KeypointsImpedanceController.h:115
armarx::control::common::control_law::ControlTarget::targets
std::vector< float > targets
Definition: common.h:54
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::BO
law::KeypointsImpedanceController::Config BO
Definition: KeypointsImpedanceController.h:56
armarx::TripleBuffer::getWriteBuffer
T & getWriteBuffer()
Definition: TripleBuffer.h:92
armarx::NJointControllerBase::useSynchronizedRtRobot
const VirtualRobot::RobotPtr & useSynchronizedRtRobot(bool updateCollisionModel=false)
Requests a VirtualRobot for use in rtRun *.
Definition: NJointController.cpp:293
armarx::StringVariantBaseMap
std::map< std::string, VariantBasePtr > StringVariantBaseMap
Definition: ManagedIceObject.h:110
ARMARX_IMPORTANT
#define ARMARX_IMPORTANT
Definition: Logging.h:190
armarx::SensorValueBase::asA
const T * asA() const
Definition: SensorValueBase.h:82
armarx::SensorValueBase
The SensorValueBase class.
Definition: SensorValueBase.h:40
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::kinematicChainName
std::string kinematicChainName
variables
Definition: KeypointsImpedanceController.h:97
armarx::ControlTargetBase
Brief description of class JointControlTargetBase.
Definition: ControlTargetBase.h:47
RobotUnit.h
armarx::TripleBuffer::commitWrite
void commitWrite()
Definition: TripleBuffer.h:163
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::bufferUserToRt
TripleBuffer< BO > bufferUserToRt
Definition: KeypointsImpedanceController.h:104
armarx::control::common::control_law::RobotStatus::jointTorque
std::vector< float > jointTorque
Definition: common.h:37
GfxTL::Matrix4f
MatrixXX< 4, 4, float > Matrix4f
Definition: MatrixXX.h:650
armarx::NJointControllerBase::useControlTarget
ControlTargetBase * useControlTarget(const std::string &deviceName, const std::string &controlMode)
Declares to calculate the ControlTarget for the given ControlDevice in the given ControlMode when rtR...
Definition: NJointController.cpp:410
armarx::control::njoint_controller::task_space
Definition: AdmittanceController.cpp:43
armarx::CycleUtil
This util class helps with keeping a cycle time during a control cycle.
Definition: CycleUtil.h:40
armarx::ManagedIceObject::getState
int getState() const
Retrieve current state of the ManagedIceObject.
Definition: ManagedIceObject.cpp:769
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::sensorDevices
SensorDevices sensorDevices
Definition: KeypointsImpedanceController.h:91
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::nonRtRobot
VirtualRobot::RobotPtr nonRtRobot
Definition: KeypointsImpedanceController.h:111
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:46
armarx::NJointControllerBase::ConfigPtrT
NJointControllerConfigPtr ConfigPtrT
Definition: NJointControllerBase.h:587
armarx::control::common::control_law::RobotStatus::jointVelocity
std::vector< float > jointVelocity
Definition: common.h:36
aron_conversions.h
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::onInitNJointController
void onInitNJointController() override
NJointControllerBase interface.
Definition: KeypointsImpedanceController.cpp:131
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::rtFirstRun
std::atomic_bool rtFirstRun
Definition: KeypointsImpedanceController.h:107
IceInternal::Handle
Definition: forward_declarations.h:8
armarx::NJointControllerBase::rtGetRobot
const VirtualRobot::RobotPtr & rtGetRobot()
TODO make protected and use attorneys.
Definition: NJointControllerBase.h:846
armarx::detail::ControlThreadOutputBufferEntry
Definition: ControlThreadOutputBuffer.h:182
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::targets
std::vector< ControlTarget1DoFActuatorTorque * > targets
Definition: KeypointsImpedanceController.h:93
controller
Definition: AddOperation.h:39
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::controlTargets
common::control_law::ControlTarget controlTargets
Definition: KeypointsImpedanceController.h:113
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::rtPostDeactivateController
void rtPostDeactivateController() override
This function is called after the controller is deactivated.
Definition: KeypointsImpedanceController.cpp:328
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::validateConfigData
void validateConfigData(BO &config)
Definition: KeypointsImpedanceController.cpp:220
armarx::NJointControllerBase::isControllerActive
bool isControllerActive(const Ice::Current &=Ice::emptyCurrent) const final override
Definition: NJointControllerBase.h:778
armarx::control::common::control_law::RobotStatus
Definition: common.h:32
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::jointNames
std::vector< std::string > jointNames
Definition: KeypointsImpedanceController.h:98
armarx::NJointControllerBase::runTask
void runTask(const std::string &taskName, Task &&task)
Executes a given task in a separate thread from the Application ThreadPool.
Definition: NJointControllerBase.h:754
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::additionalTask
virtual void additionalTask()
Definition: KeypointsImpedanceController.cpp:152
ArmarXObjectScheduler.h
ControlTarget1DoFActuator.h
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::NJointKeypointsImpedanceController
NJointKeypointsImpedanceController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &)
Definition: KeypointsImpedanceController.cpp:46
ARMARX_CHECK_GREATER_EQUAL
#define ARMARX_CHECK_GREATER_EQUAL(lhs, rhs)
This macro evaluates whether lhs is greater or equal (>=) rhs and if it turns out to be false it will...
Definition: ExpressionException.h:123
armarx::armem::Time
armarx::core::time::DateTime Time
Definition: forward_declarations.h:13
armarx::control::common::control_law::RobotStatus::jointPosition
std::vector< float > jointPosition
Definition: common.h:35
armarx::control::common::debugEigenVec
void debugEigenVec(StringVariantBaseMap &datafields, const std::string &name, Eigen::VectorXf vec)
Definition: utils.cpp:125
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::SensorDevices::torqueSensors
std::vector< const SensorValue1DoFActuatorTorque * > torqueSensors
Definition: KeypointsImpedanceController.h:86
utils.h
CycleUtil.h
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::reInitPreActivate
std::atomic_bool reInitPreActivate
Definition: KeypointsImpedanceController.h:109
NJointController.h
armarx::aron::data::DictPtr
std::shared_ptr< Dict > DictPtr
Definition: Dict.h:41
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::bufferUserToAdditionalTask
TripleBuffer< BO > bufferUserToAdditionalTask
set buffers
Definition: KeypointsImpedanceController.h:102
armarx::ctrlutil::v
double v(double t, double v0, double a0, double j)
Definition: CtrlUtil.h:39
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::rtPreActivateController
void rtPreActivateController() override
This function is called before the controller is activated.
Definition: KeypointsImpedanceController.cpp:292
ARMARX_CHECK_EXPRESSION
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
Definition: ExpressionException.h:73
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
VAROUT
#define VAROUT(x)
Definition: StringHelpers.h:198
IceUtil::Handle< class RobotUnit >
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::getClassName
std::string getClassName(const Ice::Current &) const override
Definition: KeypointsImpedanceController.cpp:120
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::updateConfig
void updateConfig(const ::armarx::aron::data::dto::DictPtr &dto, const Ice::Current &iceCurrent=Ice::emptyCurrent) override
NJointController interface.
Definition: KeypointsImpedanceController.cpp:198
IceInternal::ProxyHandle<::IceProxy::armarx::DebugDrawerInterface >
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::onPublish
void onPublish(const SensorAndControl &, const DebugDrawerInterfacePrx &, const DebugObserverInterfacePrx &) override
Definition: KeypointsImpedanceController.cpp:255
armarx::control::njoint_controller::task_space::registrationControllerNJointKeypointsImpedanceController
NJointControllerRegistration< NJointKeypointsImpedanceController > registrationControllerNJointKeypointsImpedanceController("NJointKeypointsImpedanceController")
armarx::TripleBuffer::getUpToDateReadBuffer
const T & getUpToDateReadBuffer() const
Definition: TripleBuffer.h:116
ARMARX_CHECK_EQUAL
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
Definition: ExpressionException.h:130
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::getConfig
::armarx::aron::data::dto::DictPtr getConfig(const Ice::Current &iceCurrent=Ice::emptyCurrent) override
Definition: KeypointsImpedanceController.cpp:213
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::rtRun
void rtRun(const IceUtil::Time &sensorValuesTimestamp, const IceUtil::Time &timeSinceLastIteration) override
TODO make protected and use attorneys.
Definition: KeypointsImpedanceController.cpp:161
armarx::TripleBuffer::reinitAllBuffers
std::enable_if< std::is_copy_constructible< U >::value >::type reinitAllBuffers(const T &init)
Definition: TripleBuffer.h:171
KeypointsImpedanceController.h
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::SensorDevices::positionSensors
std::vector< const SensorValue1DoFActuatorPosition * > positionSensors
Definition: KeypointsImpedanceController.h:88
armarx::ManagedIceObject::getObjectScheduler
ArmarXObjectSchedulerPtr getObjectScheduler() const
Definition: ManagedIceObject.cpp:776
armarx::control::njoint_controller::task_space::NJointKeypointsImpedanceController::rtReady
std::atomic_bool rtReady
Definition: KeypointsImpedanceController.h:108
SensorValue1DoFActuator.h
armarx::NJointControllerBase::useSensorValue
const SensorValueBase * useSensorValue(const std::string &sensorDeviceName) const
Get a const ptr to the given SensorDevice's SensorValue.
Definition: NJointController.cpp:383
VirtualRobot::RobotPtr
std::shared_ptr< class Robot > RobotPtr
Definition: Bus.h:19