KinematicUnitSimulation.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package ArmarXCore::units
19 * @author Christian Boege (boege at kit dot edu)
20 * @date 2011
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24
25
27
28#include <algorithm>
29
30#include <VirtualRobot/Nodes/RobotNode.h>
31#include <VirtualRobot/RobotNodeSet.h>
32#include <VirtualRobot/VirtualRobot.h>
33#include <VirtualRobot/VirtualRobotException.h>
34#include <VirtualRobot/XML/RobotIO.h>
35
39
40#include <RobotAPI/interface/units/KinematicUnitInterface.h>
41
42using namespace armarx;
43
45 std::string prefix) :
47{
49 "IntervalMs", 10, "The time in milliseconds between two calls to the simulation method.");
51 "Noise", 0.0f, "Gaussian noise is added to the velocity. Value in Degree");
52 defineOptionalProperty<bool>("UsePDControllerForJointControl",
53 true,
54 "If true a PD controller is also used in Position Mode instead of "
55 "setting the joint angles instantly");
56 defineOptionalProperty<float>("Kp", 3, "proportional gain of the PID position controller.");
57 defineOptionalProperty<float>("Ki", 0.001f, "integral gain of the PID position controller.");
58 defineOptionalProperty<float>("Kd", 0.0, "derivative gain of the PID position controller.");
59}
60
61void
63{
65 ARMARX_INFO << "Init Simulation";
66 usePDControllerForPosMode = getProperty<bool>("UsePDControllerForJointControl").getValue();
67 for (std::vector<VirtualRobot::RobotNodePtr>::iterator it = robotNodes.begin();
68 it != robotNodes.end();
69 it++)
70 {
71 std::string jointName = (*it)->getName();
72 jointInfos[jointName].limitLo = (*it)->getJointLimitLo();
73 jointInfos[jointName].limitHi = (*it)->getJointLimitHi();
74
75 if ((*it)->isRotationalJoint())
76 {
77 if (jointInfos[jointName].limitHi - jointInfos[jointName].limitLo >= float(M_PI * 2))
78 {
79 jointInfos[jointName].reset();
80 }
81 }
82
83 ARMARX_VERBOSE << jointName << " with limits: lo: " << jointInfos[jointName].limitLo
84 << " hi: " << jointInfos[jointName].limitHi;
85 }
87 {
88 // duplicate the loop because of locking
89 std::unique_lock lock(jointStatesMutex);
90
91 // initialize JoinStates
92 for (std::vector<VirtualRobot::RobotNodePtr>::iterator it = robotNodes.begin();
93 it != robotNodes.end();
94 it++)
95 {
96 std::string jointName = (*it)->getName();
98 jointStates[jointName].init();
101 getProperty<float>("Ki").getValue(),
102 getProperty<float>("Kd").getValue()));
103 }
104 }
106 noise = getProperty<float>("Noise").getValue() / 180.f * M_PI;
107 if (noise > 0)
108 {
109 // Aborts due to assertion when noise <= 0.
110 distribution = std::normal_distribution<double>(0, noise);
111 }
112 intervalMs = getProperty<int>("IntervalMs").getValue();
113 ARMARX_VERBOSE << "Starting kinematic unit simulation with " << intervalMs << " ms interval";
118 false,
119 "KinematicUnitSimulation");
120}
121
122void
128
129void
134
135void
137{
138 // the time it took until this method was called again
139 double timeDeltaInSeconds =
140 (TimeUtil::GetTime() - lastExecutionTime).toMilliSecondsDouble() / 1000.0;
142
143 // name value maps for reporting
144 std::lock_guard guard{sensorDataMutex};
145 sensorAngles.clear();
146 sensorVelocities.clear();
147
148 bool aPosValueChanged = false;
149 bool aVelValueChanged = false;
150 auto signedMin = [](float newValue, float minAbsValue)
151 { return std::copysign(std::min<float>(fabs(newValue), fabs(minAbsValue)), newValue); };
152
153 {
154
155 std::unique_lock lock(jointStatesMutex);
156
157 for (KinematicUnitSimulationJointStates::iterator it = jointStates.begin();
158 it != jointStates.end();
159 it++)
160 {
161
162 float newAngle = 0.0f;
163 float newVelocity = 0.0f;
164 KinematicUnitSimulationJointInfo& jointInfo = jointInfos[it->first];
165 // calculate joint positions if joint is in velocity control mode
166 if (it->second.controlMode == eVelocityControl)
167 {
168 double change = (it->second.velocity * timeDeltaInSeconds);
169 newVelocity = it->second.velocity;
170 if (noise > 0)
171 {
172 double randomNoiseValue = distribution(generator);
173 change *= 1 + randomNoiseValue;
174 }
175 newAngle = it->second.angle + change;
176 // check if velocities have changed
177 if (std::fabs(previousJointStates[it->first].velocity - newVelocity) > 0.00000001f)
178 {
179 aVelValueChanged = true;
180 }
181 }
182 else if (it->second.controlMode == ePositionControl)
183 {
185 {
186 newAngle = it->second.angle;
187 }
188 else
189 {
191 if (pid)
192 {
193 float velValue =
194 (it->second.velocity != 0.0f
195 ? signedMin(pid->getControlValue(), it->second.velocity)
196 : pid->getControlValue()); //restrain to max velocity
197 if (noise > 0)
198 {
199 velValue *= 1 + distribution(generator);
200 }
201
202 pid->update(it->second.angle);
203 newAngle = it->second.angle + velValue * timeDeltaInSeconds;
204 if (fabs(previousJointStates[it->first].velocityActual - velValue) >
205 0.00000001)
206 {
207 aVelValueChanged = true;
208 }
209 it->second.velocityActual = newVelocity = velValue;
210 }
211 }
212 }
213
214 // constrain the angle
215 if (!jointInfo.continuousJoint())
216 {
217 float maxAngle = (jointInfo.hasLimits()) ? jointInfo.limitHi : M_PI;
218 float minAngle = (jointInfo.hasLimits()) ? jointInfo.limitLo : -M_PI;
219
220 newAngle = std::max<float>(newAngle, minAngle);
221 newAngle = std::min<float>(newAngle, maxAngle);
222 }
223
224 // Check if joint existed before
225 KinematicUnitSimulationJointStates::iterator itPrev =
226 previousJointStates.find(it->first);
227
228 if (itPrev == previousJointStates.end())
229 {
230 aPosValueChanged = aVelValueChanged = true;
231 }
232
233 // check if the angle has changed
234 if (fabs(previousJointStates[it->first].angle - newAngle) > 0.00000001)
235 {
236 aPosValueChanged = true;
237 // set the new joint angle locally for the next simulation iteration
238 it->second.angle = newAngle;
239 }
240
241
242 if (jointInfo.continuousJoint())
243 {
244 if (newAngle < 0)
245 {
246 newAngle = fmod(newAngle - M_PI, 2 * M_PI) + M_PI;
247 }
248 else
249 {
250 newAngle = fmod(newAngle + M_PI, 2 * M_PI) - M_PI;
251 }
252 }
253
254 sensorAngles[it->first] = newAngle;
255 sensorVelocities[it->first] = newVelocity;
256 }
257
259 }
260 auto timestamp = TimeUtil::GetTime().toMicroSeconds();
261 listenerPrx->reportJointAngles(sensorAngles, timestamp, aPosValueChanged);
262 listenerPrx->reportJointVelocities(sensorVelocities, timestamp, aVelValueChanged);
263}
264
265void
266KinematicUnitSimulation::switchControlMode(const NameControlModeMap& targetJointModes,
267 const Ice::Current& c)
268{
269 bool aValueChanged = false;
270 NameControlModeMap changedControlModes;
271 {
272 std::unique_lock lock(jointStatesMutex);
273
274 for (NameControlModeMap::const_iterator it = targetJointModes.begin();
275 it != targetJointModes.end();
276 it++)
277 {
278 // target values
279 std::string targetJointName = it->first;
280 ControlMode targetControlMode = it->second;
281
282 KinematicUnitSimulationJointStates::iterator iterJoints =
283 jointStates.find(targetJointName);
284
285 // check whether there is a joint with this name and set joint angle
286 if (iterJoints != jointStates.end())
287 {
288 if (iterJoints->second.controlMode != targetControlMode)
289 {
290 aValueChanged = true;
291 }
292
293 iterJoints->second.controlMode = targetControlMode;
294 changedControlModes.insert(*it);
295 }
296 else
297 {
298 ARMARX_WARNING << "Could not find joint with name " << targetJointName;
299 }
300 }
301 }
302 // only report control modes which have been changed
303 listenerPrx->reportControlModeChanged(
304 changedControlModes, aValueChanged, TimeUtil::GetTime().toMicroSeconds());
305}
306
307void
308KinematicUnitSimulation::setJointAngles(const NameValueMap& targetJointAngles,
309 const Ice::Current& c)
310{
311
312 std::unique_lock lock(jointStatesMutex);
313 // name value maps for reporting
314 NameValueMap actualJointAngles;
315 bool aValueChanged = false;
316
317 for (NameValueMap::const_iterator it = targetJointAngles.begin(); it != targetJointAngles.end();
318 it++)
319 {
320 // target values
321 std::string targetJointName = it->first;
322 float targetJointAngle = it->second;
323
324 // check whether there is a joint with this name and set joint angle
325 KinematicUnitSimulationJointStates::iterator iterJoints = jointStates.find(targetJointName);
326
327 if (iterJoints != jointStates.end())
328 {
329 if (fabs(iterJoints->second.angle - targetJointAngle) > 0)
330 {
331 aValueChanged = true;
332 }
333 KinematicUnitSimulationJointInfo& jointInfo = jointInfos[targetJointName];
334 if (jointInfo.hasLimits() && !jointInfo.continuousJoint())
335 {
336 targetJointAngle = std::max<float>(targetJointAngle, jointInfo.limitLo);
337 targetJointAngle = std::min<float>(targetJointAngle, jointInfo.limitHi);
338 }
339
341 {
342 iterJoints->second.angle = targetJointAngle;
343 actualJointAngles[targetJointName] = iterJoints->second.angle;
344 }
345 else
346 {
348 if (pid)
349 {
350 pid->reset();
351 if (jointInfo.continuousJoint())
352 {
353 float delta = targetJointAngle - iterJoints->second.angle;
354 float signedSmallestDelta = atan2(sin(delta), cos(delta));
355 targetJointAngle = iterJoints->second.angle + signedSmallestDelta;
356 }
357
358 pid->setTarget(targetJointAngle);
359 }
360 }
361 }
362 else
363 {
364 ARMARX_WARNING << deactivateSpam(1) << "Joint '" << targetJointName << "' not found!";
365 }
366 }
367
368 if (aValueChanged)
369 {
370 listenerPrx->reportJointAngles(
371 actualJointAngles, aValueChanged, TimeUtil::GetTime().toMicroSeconds());
372 }
373}
374
375void
376KinematicUnitSimulation::setJointVelocities(const NameValueMap& targetJointVelocities,
377 const Ice::Current&)
378{
379 std::unique_lock lock(jointStatesMutex);
380 NameValueMap actualJointVelocities;
381 bool aValueChanged = false;
382
383 for (NameValueMap::const_iterator it = targetJointVelocities.begin();
384 it != targetJointVelocities.end();
385 it++)
386 {
387 // target values
388 std::string targetJointName = it->first;
389 float targetJointVelocity = it->second;
390
391 KinematicUnitSimulationJointStates::iterator iterJoints = jointStates.find(targetJointName);
392
393 // check whether there is a joint with this name and set joint angle
394 if (iterJoints != jointStates.end())
395 {
396 if (fabs(iterJoints->second.velocity - targetJointVelocity) > 0)
397 {
398 aValueChanged = true;
399 }
400
401 iterJoints->second.velocity = targetJointVelocity;
402 actualJointVelocities[targetJointName] = iterJoints->second.velocity;
403 }
404 }
405
406 if (aValueChanged)
407 {
408 listenerPrx->reportJointVelocities(
409 actualJointVelocities, aValueChanged, TimeUtil::GetTime().toMicroSeconds());
410 }
411}
412
413void
414KinematicUnitSimulation::setJointTorques(const NameValueMap& targetJointTorques,
415 const Ice::Current&)
416{
417 std::unique_lock lock(jointStatesMutex);
418 NameValueMap actualJointTorques;
419 bool aValueChanged = false;
420
421 for (NameValueMap::const_iterator it = targetJointTorques.begin();
422 it != targetJointTorques.end();
423 it++)
424 {
425 // target values
426 std::string targetJointName = it->first;
427 float targetJointTorque = it->second;
428
429 KinematicUnitSimulationJointStates::iterator iterJoints = jointStates.find(targetJointName);
430
431 // check whether there is a joint with this name and set joint angle
432 if (iterJoints != jointStates.end())
433 {
434 if (fabs(iterJoints->second.torque - targetJointTorque) > 0)
435 {
436 aValueChanged = true;
437 }
438
439 iterJoints->second.torque = targetJointTorque;
440 actualJointTorques[targetJointName] = iterJoints->second.torque;
441 }
442 }
443
444 if (aValueChanged)
445 {
446 listenerPrx->reportJointTorques(
447 actualJointTorques, aValueChanged, TimeUtil::GetTime().toMicroSeconds());
448 }
449}
450
451NameControlModeMap
453{
454 NameControlModeMap result;
455
456 for (KinematicUnitSimulationJointStates::iterator it = jointStates.begin();
457 it != jointStates.end();
458 it++)
459 {
460 result[it->first] = it->second.controlMode;
461 }
462
463 return result;
464}
465
466void
467KinematicUnitSimulation::setJointAccelerations(const NameValueMap& targetJointAccelerations,
468 const Ice::Current&)
469{
470 (void)targetJointAccelerations;
471}
472
473void
474KinematicUnitSimulation::setJointDecelerations(const NameValueMap& targetJointDecelerations,
475 const Ice::Current&)
476{
477 (void)targetJointDecelerations;
478}
479
480void
482{
483
484 std::unique_lock lock(jointStatesMutex);
485
486 for (KinematicUnitSimulationJointStates::iterator it = jointStates.begin();
487 it != jointStates.end();
488 it++)
489 {
490 it->second.velocity = 0;
491 }
492
494}
495
502
503NameValueMap
505{
506 std::lock_guard<std::mutex> guard{sensorDataMutex};
507 return sensorAngles;
508}
509
510NameValueMap
512{
513 std::lock_guard<std::mutex> guard{sensorDataMutex};
514 return sensorVelocities;
515}
516
517Ice::StringSeq
518KinematicUnitSimulation::getJoints(const Ice::Current& c) const
519{
520 std::lock_guard<std::mutex> guard{sensorDataMutex};
521 return getMapKeys(sensorAngles);
522}
523
524DebugInfo
525KinematicUnitSimulation::getDebugInfo(const Ice::Current& c) const
526{
527 std::lock_guard g{jointStatesMutex};
528
529 DebugInfo debugInfo;
530 for (const auto& [jointName, info] : jointStates)
531 {
532 debugInfo.jointAngles[jointName] = info.angle;
533 debugInfo.jointVelocities[jointName] = info.velocity;
534
535 debugInfo.jointMotorTemperatures[jointName] = info.temperature;
536
537 debugInfo.jointTorques[jointName] = info.torque;
538 debugInfo.jointModes[jointName] = info.controlMode;
539 };
540
541 return debugInfo;
542}
543
544bool
545mapEntryEqualsString(std::pair<std::string, KinematicUnitSimulationJointState> iter,
546 std::string compareString)
547{
548 return (iter.first == compareString);
549}
550
551void
552KinematicUnitSimulation::requestJoints(const Ice::StringSeq& joints, const Ice::Current& c)
553{
554 // if one of the joints belongs to this unit, lock access to this unit for other components except for the requesting one
555 KinematicUnitSimulationJointStates::const_iterator it = std::find_first_of(
556 jointStates.begin(), jointStates.end(), joints.begin(), joints.end(), mapEntryEqualsString);
557
558 if (jointStates.end() != it)
559 {
561 }
562}
563
564void
565KinematicUnitSimulation::releaseJoints(const Ice::StringSeq& joints, const Ice::Current& c)
566{
567 // if one of the joints belongs to this unit, unlock access
568 KinematicUnitSimulationJointStates::const_iterator it = std::find_first_of(
569 jointStates.begin(), jointStates.end(), joints.begin(), joints.end(), mapEntryEqualsString);
570
571 if (jointStates.end() != it)
572 {
574 }
575}
std::string timestamp()
float signedMin(float newValue, float minAbsValue)
bool mapEntryEqualsString(std::pair< std::string, KinematicUnitSimulationJointState > iter, std::string compareString)
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
#define M_PI
Definition MathTools.h:17
constexpr T c
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
KinematicUnitPropertyDefinitions(std::string prefix)
void releaseJoints(const Ice::StringSeq &joints, const Ice::Current &c=Ice::emptyCurrent) override
PeriodicTask< KinematicUnitSimulation >::pointer_type simulationTask
void requestJoints(const Ice::StringSeq &joints, const Ice::Current &c=Ice::emptyCurrent) override
std::normal_distribution< double > distribution
armarx::NameValueMap getJointVelocities(const Ice::Current &c) const override
armarx::NameValueMap getJointAngles(const Ice::Current &c) const override
void setJointAngles(const NameValueMap &targetJointAngles, const Ice::Current &c=Ice::emptyCurrent) override
void switchControlMode(const NameControlModeMap &targetJointModes, const Ice::Current &c=Ice::emptyCurrent) override
void setJointTorques(const NameValueMap &targetJointTorques, const Ice::Current &c=Ice::emptyCurrent) override
DebugInfo getDebugInfo(const Ice::Current &c=Ice::emptyCurrent) const override
std::map< std::string, PIDControllerPtr > positionControlPIDController
void stop(const Ice::Current &c=Ice::emptyCurrent) override
void setJointAccelerations(const NameValueMap &targetJointAccelerations, const Ice::Current &c=Ice::emptyCurrent) override
void setJointDecelerations(const NameValueMap &targetJointDecelerations, const Ice::Current &c=Ice::emptyCurrent) override
PropertyDefinitionsPtr createPropertyDefinitions() override
NameControlModeMap getControlModes(const Ice::Current &c=Ice::emptyCurrent) override
KinematicUnitSimulationJointStates jointStates
KinematicUnitSimulationJointInfos jointInfos
Ice::StringSeq getJoints(const Ice::Current &c) const override
KinematicUnitSimulationJointStates previousJointStates
void setJointVelocities(const NameValueMap &targetJointVelocities, const Ice::Current &c=Ice::emptyCurrent) override
std::vector< VirtualRobot::RobotNodePtr > robotNodes
KinematicUnitListenerPrx listenerPrx
The periodic task executes one thread method repeatedly using the time period specified in the constr...
std::string prefix
Prefix of the properties such as namespace, domain, component name, etc.
PropertyDefinition< PropertyType > & defineOptionalProperty(const std::string &name, PropertyType defaultValue, const std::string &description="", PropertyDefinitionBase::PropertyConstness constness=PropertyDefinitionBase::eConstant)
void release(const Ice::Current &c=Ice::emptyCurrent) override
Release exclusive access to current unit.
void stop(const Ice::Current &c=Ice::emptyCurrent) override
Set execution state to eStopped.
void request(const Ice::Current &c=Ice::emptyCurrent) override
Request exclusive access to current unit.
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition TimeUtil.cpp:42
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::shared_ptr< PIDController > PIDControllerPtr
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
void getMapKeys(const MapType &map, OutputIteratorType it)
Definition algorithm.h:173
#define ARMARX_TRACE
Definition trace.h:77