KinematicUnitDynamicSimulation.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2013-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 ArmarXSimulation::ArmarXObjects::KinematicUnitDynamicSimulation
19 * @author Nikolaus ( vahrenkamp at kit dot edu )
20 * @date 2013
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24
26
27#include <algorithm>
28
29#include <VirtualRobot/Nodes/RobotNode.h>
30#include <VirtualRobot/RobotNodeSet.h>
31#include <VirtualRobot/VirtualRobot.h>
32#include <VirtualRobot/VirtualRobotException.h>
33#include <VirtualRobot/XML/RobotIO.h>
34
36
37using namespace armarx;
38
39void
41{
42 ARMARX_VERBOSE << "Init with RNS " << robotNodeSetName << std::endl;
43
44 for (auto& robotNode : robotNodes)
45 {
46 std::string jointName = robotNode->getName();
47 ARMARX_VERBOSE << "* " << jointName << flush;
48 nodeNames.insert(jointName);
49 }
50
51 if (robot)
52 {
53 robotTopicName = "Simulator_Robot_";
54 robotName =
55 hasProperty("RobotName") ? getProperty<std::string>("RobotName") : robot->getName();
57 ARMARX_INFO << "Simulator Robot topic: " << robotTopicName << std::endl;
59 }
60 else
61 {
62 ARMARX_WARNING << "No robot loaded..." << std::endl;
63 }
64
65 mapVelToPosVel = getProperty<bool>("MapVelocityToPositionVelocity").getValue();
66
67 simulatorPrxName = getProperty<std::string>("SimulatorName").getValue();
69}
70
71void
73{
74 // subscribe topic in order to receive the simulator reports
75 ARMARX_INFO << "Using simulator proxy: " << simulatorPrxName << flush;
77
78 // periodic task setup
79 cycleTime = 1000.f / getProperty<float>("ControlFrequency").getValue();
80
81 if (execTask)
82 {
83 execTask->stop();
84 }
85
87 this,
90 false,
91 "KinematicUnitDynamicSimulation");
92 execTask->start();
93 execTask->setDelayWarningTolerance(100);
94}
95
96void
98{
99 if (execTask)
100 {
101 execTask->stop();
102 }
103}
104
105void
106KinematicUnitDynamicSimulation::reportState(SimulatedRobotState const& state, const Ice::Current&)
107{
108 NameValueMap angleValues;
109 NameValueMap velocitiyValues;
110 NameValueMap torqueValues;
111
112 {
113 // Calculate results with lock, publish later without lock
114 std::scoped_lock scoped_lock(accessMutex);
115
116 // Joint angles
117 if (state.jointAngles.size() > 0)
118 {
119 // check which joints are covered
120 for (const auto& actualJointAngle : state.jointAngles)
121 {
122 if (nodeNames.find(actualJointAngle.first) != nodeNames.end())
123 {
124 angleValues[actualJointAngle.first] = actualJointAngle.second;
125 }
126
127 currentJointValues[actualJointAngle.first] = actualJointAngle.second;
128 }
129 }
130
131 // Joint velocities
132 // check which jonts are covered
133 for (const auto& actualVelocity : state.jointVelocities)
134 {
135 if (nodeNames.find(actualVelocity.first) != nodeNames.end())
136 {
137 velocitiyValues[actualVelocity.first] = actualVelocity.second;
138 }
139 }
140
141 // Joint torques
142 // check which jonts are covered
143 for (const auto& actualJointTorque : state.jointTorques)
144 {
145 if (nodeNames.find(actualJointTorque.first) != nodeNames.end())
146 {
147 torqueValues[actualJointTorque.first] = actualJointTorque.second;
148 }
149 }
150 }
151
152 // FIXME: Use Ice batching to optimize
153 if (angleValues.size() > 0)
154 {
155 listenerPrx->reportJointAngles(angleValues, state.timestampInMicroSeconds, true);
156 }
157 if (velocitiyValues.size() > 0)
158 {
159 listenerPrx->reportJointVelocities(velocitiyValues, state.timestampInMicroSeconds, true);
160 }
161 if (torqueValues.size() > 0)
162 {
163 listenerPrx->reportJointTorques(torqueValues, state.timestampInMicroSeconds, true);
164 }
165}
166
167NameControlModeMap
169{
170 NameControlModeMap result;
171
172 for (const auto& nodeName : nodeNames)
173 {
174 auto c = currentControlModes.find(nodeName);
175
176 // if not specified, we assume position control
177 if (c == currentControlModes.end())
178 {
179 result[nodeName] = ePositionControl;
180 }
181 else
182 {
183 result[nodeName] = c->second;
184 }
185 }
186
187 return result;
188}
189
190void
191KinematicUnitDynamicSimulation::switchControlMode(const NameControlModeMap& targetJointModes,
192 const Ice::Current& c)
193{
194 std::scoped_lock scoped_lock(accessMutex);
195
196 //currentControlModes = targetJointModes;
197 NameControlModeMap::const_iterator itAng = targetJointModes.begin();
198
199 while (itAng != targetJointModes.end())
200 {
201 currentControlModes[itAng->first] = itAng->second;
202 itAng++;
203 }
204
205 listenerPrx->reportControlModeChanged(
206 targetJointModes, IceUtil::Time::now().toMicroSeconds(), true);
207}
208
209void
210KinematicUnitDynamicSimulation::setJointAngles(const NameValueMap& targetJointAngles,
211 const Ice::Current& c)
212{
213 std::scoped_lock scoped_lock(accessMutex);
214
215
216 // store current joint angles
217 NameValueMap::const_iterator itAng = targetJointAngles.begin();
218
219 while (itAng != targetJointAngles.end())
220 {
221 currentJointTargets[itAng->first] = itAng->second;
222 itAng++;
223 }
224}
225
226void
227KinematicUnitDynamicSimulation::setJointVelocities(const NameValueMap& targetJointVelocities,
228 const Ice::Current& c)
229{
230 std::scoped_lock scoped_lock(accessMutex);
231 NameValueMap::const_iterator itVel = targetJointVelocities.begin();
232
233 while (itVel != targetJointVelocities.end())
234 {
235 currentJointVelTargets[itVel->first] = itVel->second;
236 itVel++;
237 }
238}
239
240void
241KinematicUnitDynamicSimulation::setJointTorques(const NameValueMap& targetJointTorques,
242 const Ice::Current& c)
243{
244 std::scoped_lock scoped_lock(accessMutex);
245
246 // store current joint torques
247 NameValueMap::const_iterator itAng = targetJointTorques.begin();
248
249 while (itAng != targetJointTorques.end())
250 {
251 currentJointTorqueTargets[itAng->first] = itAng->second;
252 itAng++;
253 }
254}
255
256void
257KinematicUnitDynamicSimulation::setJointAccelerations(const NameValueMap& targetJointAccelerations,
258 const Ice::Current& c)
259{
260}
261
262void
263KinematicUnitDynamicSimulation::setJointDecelerations(const NameValueMap& targetJointDecelerations,
264 const Ice::Current& c)
265{
266}
267
268void
269KinematicUnitDynamicSimulation::requestJoints(const Ice::StringSeq& joints, const Ice::Current& c)
270{
271 std::scoped_lock scoped_lock(accessMutex);
272
273 // if one of the joints belongs to this unit, lock access to this unit for other components except for the requesting one
274 for (const auto& joint : joints)
275 {
276 if (nodeNames.find(joint) != nodeNames.end())
277 {
279 return;
280 }
281 }
282}
283
284void
285KinematicUnitDynamicSimulation::releaseJoints(const Ice::StringSeq& joints, const Ice::Current& c)
286{
287 std::scoped_lock scoped_lock(accessMutex);
288
289 // if one of the joints belongs to this unit, unlock access
290 for (const auto& joint : joints)
291 {
292 if (nodeNames.find(joint) != nodeNames.end())
293 {
295 return;
296 }
297 }
298}
299
300void
302{
303 if (!simulatorPrx)
304 {
305 return;
306 }
307
308 float loopTime = (float)execTask->getInterval() / 1000.0f; // in s
309 float factorLoopTime = 1.1f;
310
311 {
312 std::scoped_lock lock(accessMutex);
313
314 NameValueMap applyPosMap;
315 NameValueMap applyVelMap;
316 NameValueMap applyPosVelMap_pos;
317 NameValueMap applyPosVelMap_vel;
318 NameValueMap applyTorMap;
319 NameControlModeMap::const_iterator itMode = currentControlModes.begin();
320
321 while (itMode != currentControlModes.end())
322 {
323 switch (itMode->second)
324 {
325 case ePositionControl:
326 if (currentJointTargets.find(itMode->first) != currentJointTargets.end())
327 {
328 applyPosMap[itMode->first] =
329 currentJointTargets.find(itMode->first)->second;
330 }
331
332 break;
333
334 case eVelocityControl:
335 {
336 auto it = currentJointVelTargets.find(itMode->first);
337 if (it != currentJointVelTargets.end())
338 {
339 if (mapVelToPosVel)
340 {
341 // compute pos
342 if (currentJointValues.find(itMode->first) != currentJointValues.end())
343 {
344 float posTarget = currentJointValues[itMode->first] +
345 it->second * loopTime * factorLoopTime;
346 applyPosVelMap_pos[itMode->first] = posTarget;
347 applyPosVelMap_vel[itMode->first] = it->second;
348 }
349 }
350 else
351 {
352 // just use velocity
353 applyVelMap[itMode->first] =
354 currentJointVelTargets.find(itMode->first)->second;
355 }
356 }
357 }
358
359 break;
360
361 case eTorqueControl:
362 if (currentJointTorqueTargets.find(itMode->first) !=
364 {
365 applyTorMap[itMode->first] =
366 currentJointTorqueTargets.find(itMode->first)->second;
367 }
368
369 break;
370
371 case ePositionVelocityControl:
372 if (currentJointVelTargets.find(itMode->first) !=
374 currentJointTargets.find(itMode->first) != currentJointTargets.end())
375 {
376 applyPosVelMap_pos[itMode->first] =
377 currentJointTargets.find(itMode->first)->second;
378 applyPosVelMap_vel[itMode->first] =
379 currentJointVelTargets.find(itMode->first)->second;
380 }
381
382 break;
383
384 case eUnknown:
385 case eDisabled:
386 default:
387 // do nothing
388 ;
389 }
390
391 itMode++;
392 }
393 auto batchPrx = simulatorPrx->ice_batchOneway();
394 if (applyPosMap.size() > 0)
395 {
396 batchPrx->actuateRobotJointsPos(robotName, applyPosMap);
397 }
398
399 if (applyVelMap.size() > 0)
400 {
401 batchPrx->actuateRobotJointsVel(robotName, applyVelMap);
402 }
403
404 if (applyTorMap.size() > 0)
405 {
406 batchPrx->actuateRobotJointsTorque(robotName, applyTorMap);
407 }
408
409 if (applyPosVelMap_pos.size() > 0)
410 {
411 batchPrx->actuateRobotJoints(robotName, applyPosVelMap_pos, applyPosVelMap_vel);
412 }
413 batchPrx->ice_flushBatchRequests();
414
415 // command only once
416 if (!mapVelToPosVel) // dont clear this in pos-velo mode because it is needed to calculate next position target
417 {
419 }
420 currentJointTargets.clear();
422 }
423}
424
425armarx::DebugInfo
427{
428 const ::armarx::SimulatedRobotState robotState = simulatorPrx->getRobotState(robotName);
429
430 ::armarx::NameStatusMap jointStatus;
431 for (const auto& [jointName, _] : currentControlModes)
432 {
433 jointStatus[jointName] = {
434 .operation = eOnline,
435 .error = eOk,
436 .enabled = true,
437 .emergencyStop = false // TODO: implement
438 };
439 }
440
441 return {.jointModes = currentControlModes,
442 .jointAngles = robotState.jointAngles,
443 .jointVelocities = robotState.jointVelocities,
444 .jointAccelerations = {}, // not available
445 .jointTorques = robotState.jointTorques,
446 .jointCurrents = {}, // not available
447 .jointMotorTemperatures = {}, // not available
448 .jointStatus = jointStatus};
449}
#define float
Definition 16_Level.h:22
constexpr T c
Property< PropertyType > getProperty(const std::string &name)
void releaseJoints(const Ice::StringSeq &joints, const Ice::Current &c=Ice::emptyCurrent) override
void requestJoints(const Ice::StringSeq &joints, const Ice::Current &c=Ice::emptyCurrent) 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
PeriodicTask< KinematicUnitDynamicSimulation >::pointer_type execTask
void setJointAccelerations(const NameValueMap &targetJointAccelerations, const Ice::Current &c=Ice::emptyCurrent) override
void setJointDecelerations(const NameValueMap &targetJointDecelerations, const Ice::Current &c=Ice::emptyCurrent) override
DebugInfo getDebugInfo(const Ice::Current &c=Ice::emptyCurrent) const override
void reportState(SimulatedRobotState const &state, const Ice::Current &) override
NameControlModeMap getControlModes(const Ice::Current &c=Ice::emptyCurrent) override
void setJointVelocities(const NameValueMap &targetJointVelocities, const Ice::Current &c=Ice::emptyCurrent) override
VirtualRobot::RobotPtr robot
std::vector< VirtualRobot::RobotNodePtr > robotNodes
std::string robotNodeSetName
KinematicUnitListenerPrx listenerPrx
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
void usingTopic(const std::string &name, bool orderedPublishing=false)
Registers a proxy for subscription after initialization.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
The periodic task executes one thread method repeatedly using the time period specified in the constr...
bool hasProperty(const std::string &name)
void release(const Ice::Current &c=Ice::emptyCurrent) override
Release exclusive access to current unit.
void request(const Ice::Current &c=Ice::emptyCurrent) override
Request exclusive access to current unit.
#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.
const LogSender::manipulator flush
Definition LogSender.h:251