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