HeadIKUnit.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-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
19 * @author
20 * @date
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24#include "HeadIKUnit.h"
25
26#include <memory>
27
28#include <SimoxUtility/algorithm/string/string_tools.h>
29#include <VirtualRobot/IK/GazeIK.h>
30#include <VirtualRobot/LinkedCoordinate.h>
31#include <VirtualRobot/RobotNodeSet.h>
32#include <VirtualRobot/XML/RobotIO.h>
33
36
37namespace armarx
38{
39
40 HeadIKUnit::HeadIKUnit() : requested(false), cycleTime(30), newTargetSet(false)
41 {
42 targetPosition = new FramedPosition();
43 }
44
45 void
47 {
48 std::unique_lock lock(accessMutex);
49
50 usingProxy(getProperty<std::string>("KinematicUnitName").getValue());
51 usingProxy(getProperty<std::string>("RobotStateComponentName").getValue());
52
53
54 cycleTime = getProperty<int>("CycleTime").getValue();
55 offeringTopic("DebugDrawerUpdates");
56 offeringTopic(getProperty<std::string>("HeadIKUnitTopicName").getValue());
57 }
58
59 void
61 {
62 std::unique_lock lock(accessMutex);
63
64 drawer = getTopic<DebugDrawerInterfacePrx>("DebugDrawerUpdates");
65
66 kinematicUnitPrx = getProxy<KinematicUnitInterfacePrx>(
67 getProperty<std::string>("KinematicUnitName").getValue());
68 robotStateComponentPrx = getProxy<RobotStateComponentInterfacePrx>(
69 getProperty<std::string>("RobotStateComponentName").getValue());
70
71
72 //remoteRobotPrx = robotStateComponentPrx->getSynchronizedRobot();
74 robotStateComponentPrx, VirtualRobot::RobotIO::RobotDescription::eStructure);
75 // localRobot = RemoteRobot::createLocalClone(robotStateComponentPrx);
76
77
78 headIKUnitListener = getTopic<armarx::HeadIKUnitListenerPrx>(
79 getProperty<std::string>("HeadIKUnitTopicName").getValue());
80
81 //std::string robotModelFile;
82 //ArmarXDataPath::getAbsolutePath("Armar3/robotmodel/ArmarIII.xml", robotModelFile);
83 //localRobot = VirtualRobot::RobotIO::loadRobot(robotModelFile.c_str(), VirtualRobot::RobotIO::eStructure);
84 //VirtualRobot::RobotPtr robotSnapshot(new RemoteRobot(remoteRobotPrx));
85 //localRobot->setConfig(robotSnapshot->getConfig());
86
87 requested = false;
88
89 if (execTask)
90 {
91 execTask->stop();
92 }
93
94 execTask = new PeriodicTask<HeadIKUnit>(
95 this, &HeadIKUnit::periodicExec, cycleTime, false, "HeadIKCalculator");
96 execTask->setDelayWarningTolerance(300);
97 execTask->start();
98 }
99
100 void
102 {
103 release();
104
105 //std::unique_lock lock(accessMutex);
106 if (drawer)
107 {
108 drawer->removeSphereDebugLayerVisu("HeadViewTarget");
109 drawer->removeSphereDebugLayerVisu("HeadViewTargetSolution");
110 }
111
112
113 if (execTask)
114 {
115 execTask->stop();
116 }
117 }
118
119 void
123
124 void
125 HeadIKUnit::setCycleTime(Ice::Int milliseconds, const Ice::Current& c)
126 {
127 std::unique_lock lock(accessMutex);
128
129 cycleTime = milliseconds;
130
131 if (execTask)
132 {
133 execTask->changeInterval(cycleTime);
134 }
135 }
136
137 void
138 HeadIKUnit::setHeadTarget(const std::string& robotNodeSetName,
139 const FramedPositionBasePtr& targetPosition,
140 const Ice::Current& c)
141 {
142 std::unique_lock lock(accessMutex);
143
144 this->robotNodeSetNames = armarx::Split(robotNodeSetName, ",");
145 for (auto& setName : robotNodeSetNames)
146 {
147 simox::alg::trim(setName);
148 }
149 this->targetPosition->x = targetPosition->x;
150 this->targetPosition->y = targetPosition->y;
151 this->targetPosition->z = targetPosition->z;
152 this->targetPosition->frame = targetPosition->frame;
153
154 FramedPositionPtr globalTarget =
155 FramedPositionPtr::dynamicCast(targetPosition)
156 ->toGlobal(robotStateComponentPrx->getSynchronizedRobot());
157
158 if (drawer && getProperty<bool>("VisualizeIKTarget").getValue())
159 {
160 drawer->setSphereDebugLayerVisu(
161 "HeadViewTarget", globalTarget, DrawColor{1, 0, 0, 0.7}, 15);
162 }
163
164 ARMARX_DEBUG << "new Head target set: " << *globalTarget << " for " << robotNodeSetName;
165
166 newTargetSet = true;
167 }
168
169 void
170 HeadIKUnit::init(const Ice::Current& c)
171 {
172 }
173
174 void
175 HeadIKUnit::start(const Ice::Current& c)
176 {
177 }
178
179 void
180 HeadIKUnit::stop(const Ice::Current& c)
181 {
182 }
183
184 UnitExecutionState
185 HeadIKUnit::getExecutionState(const Ice::Current& c)
186 {
187 switch (getState())
188 {
189 case eManagedIceObjectStarted:
190 return eUnitStarted;
191
192 case eManagedIceObjectInitialized:
193 case eManagedIceObjectStarting:
194 return eUnitInitialized;
195
196 case eManagedIceObjectExiting:
197 case eManagedIceObjectExited:
198 return eUnitStopped;
199
200 default:
201 return eUnitConstructed;
202 }
203 }
204
205 void
206 HeadIKUnit::request(const Ice::Current& c)
207 {
208 std::unique_lock lock(accessMutex);
209
210 requested = true;
211 ARMARX_IMPORTANT << "Requesting HeadIKUnit";
212
213 if (execTask)
214 {
215 execTask->stop();
216 }
217
218 execTask = new PeriodicTask<HeadIKUnit>(
219 this, &HeadIKUnit::periodicExec, cycleTime, false, "TCPVelocityCalculator");
220 execTask->start();
221 ARMARX_IMPORTANT << "Requested HeadIKUnit";
222 }
223
224 void
225 HeadIKUnit::release(const Ice::Current& c)
226 {
227 std::unique_lock lock(accessMutex);
228
229 ARMARX_INFO << "Releasing HeadIKUnit";
230 requested = false;
231
232 if (drawer)
233 {
234 drawer->removeSphereDebugLayerVisu("HeadViewTarget");
235 drawer->removeSphereDebugLayerVisu("HeadViewTargetSolution");
236 }
237
238 // why do we stop the kin unit?
239 /*try
240 {
241 if (kinematicUnitPrx)
242 kinematicUnitPrx->stop();
243 } catch (...)
244 {
245 ARMARX_IMPORTANT << "Released HeadIKUnit failed";
246 }*/
247
248 ARMARX_INFO << "Released HeadIKUnit";
249 }
250
251 void
252 HeadIKUnit::periodicExec()
253 {
254 bool doCalculation = false;
255
256 {
257 std::unique_lock lock(accessMutex, std::defer_lock);
258
259 if (lock.try_lock())
260 {
261 doCalculation = requested && newTargetSet;
262 newTargetSet = false;
263 }
264 else
265 {
266 return;
267 }
268 }
269
270
271 if (doCalculation)
272 {
273 std::unique_lock lock(accessMutex);
274
275 VirtualRobot::RobotNodeSetPtr kinematicChain;
276 bool foundSolution = false;
277 NameValueMap targetJointAngles;
278 NameControlModeMap controlModes;
279 std::set<std::string> possiblyInvolvedJointNames;
280 // // set all involved joints initially to zero
281 for (auto robotNodeSetName : robotNodeSetNames)
282 {
283 kinematicChain = localRobot->getRobotNodeSet(robotNodeSetName);
284 for (unsigned int i = 0; i < kinematicChain->getSize(); i++)
285 {
286 possiblyInvolvedJointNames.insert(kinematicChain->getNode(i)->getName());
287 // kinematicChain->getNode(i)->setJointValue(0.0f);
288 // targetJointAngles[kinematicChain->getNode(i)->getName()] = 0.0f;
289 // controlModes[kinematicChain->getNode(i)->getName()] = ePositionControl;
290 }
291 }
292 FramedPositionPtr globalPos;
293 float error = -1;
294 //VirtualRobot::RobotPtr robotSnapshot(new RemoteRobot(remoteRobotPrx));
295 //localRobot->setConfig(robotSnapshot->getConfig());
296 std::string selectedRobotNodeSetName;
297 for (auto robotNodeSetName : robotNodeSetNames)
298 {
299 RemoteRobot::synchronizeLocalClone(localRobot, robotStateComponentPrx);
300
301 kinematicChain = localRobot->getRobotNodeSet(robotNodeSetName);
302 auto tcpNode = kinematicChain->getTCP();
303 VirtualRobot::RobotNodePrismaticPtr virtualPrismaticJoint;
304
305 virtualPrismaticJoint =
306 std::dynamic_pointer_cast<VirtualRobot::RobotNodePrismatic>(tcpNode);
307 if (!virtualPrismaticJoint)
308 {
309 ARMARX_WARNING << deactivateSpam(10, robotNodeSetName)
310 << "Head IK Kinematic Chain TCP is not a prismatic joint! "
311 "skipping joint set";
312 continue;
313 }
314
315 // set other not-used joints to 0
316 for (auto& nodeName : possiblyInvolvedJointNames)
317 {
318 if (!kinematicChain->hasRobotNode(nodeName))
319 {
320 localRobot->getRobotNode(nodeName)->setJointValue(0.0f);
321 targetJointAngles[nodeName] = 0.0f;
322 controlModes[nodeName] = ePositionControl;
323 }
324 }
325
326 ARMARX_DEBUG << deactivateSpam(5) << VAROUT(virtualPrismaticJoint->getName()) << " "
327 << VAROUT(kinematicChain->getName());
328 VirtualRobot::GazeIK ikSolver(kinematicChain, virtualPrismaticJoint);
329 ikSolver.enableJointLimitAvoidance(true);
330 ikSolver.setup(10, 30, 20);
331 //ikSolver.setVerbose(true);
332
333 globalPos = targetPosition->toGlobal(localRobot);
334 ARMARX_DEBUG << "Calculating IK for target position " << globalPos->output();
335 auto start = IceUtil::Time::now();
336 bool solutionFound = ikSolver.solve(globalPos->toEigen());
337 auto duration = (IceUtil::Time::now() - start);
338
339 if (duration.toMilliSeconds() > 500)
340 {
341 ARMARX_INFO << "Calculating Gaze IK took " << duration.toMilliSeconds()
342 << " ms";
343 }
344 Eigen::Vector3f position =
345 globalPos->toEigen() -
346 kinematicChain->getTCP()->getGlobalPose().block(0, 3, 3, 1);
347 error = position.norm();
348 if (!solutionFound)
349 {
350
351 if (error < 150)
352 {
353 foundSolution = true;
354 selectedRobotNodeSetName = robotNodeSetName;
355 ARMARX_INFO << "IKSolver found no solution! applying best solution with "
356 << error << "mm error";
357 break;
358 }
359 }
360 else
361 {
362 foundSolution = true;
363 selectedRobotNodeSetName = robotNodeSetName;
364 break;
365 }
366 }
367 if (!foundSolution)
368 {
369 ARMARX_WARNING << "IKSolver found no solution! " << error << "mm error";
370 return;
371 }
372 ARMARX_DEBUG << "Solution found with " << selectedRobotNodeSetName
373 << " - remaining error: " << error << " mm";
374
375 if (drawer && localRobot->hasRobotNode("Cameras") &&
376 getProperty<bool>("VisualizeIKTarget").getValue())
377 {
378 Vector3Ptr startPos =
379 new Vector3(localRobot->getRobotNode("Cameras")->getGlobalPose());
380 drawer->setSphereDebugLayerVisu(
381 "HeadViewTargetSolution", startPos, DrawColor{0, 1, 1, 0.2}, 17);
382 }
383 auto tcpNode = kinematicChain->getTCP();
384 for (int i = 0; i < (signed int)kinematicChain->getSize(); i++)
385 {
386 if (kinematicChain->getNode(i) != tcpNode)
387 {
388 targetJointAngles[kinematicChain->getNode(i)->getName()] =
389 kinematicChain->getNode(i)->getJointValue();
390 controlModes[kinematicChain->getNode(i)->getName()] = ePositionControl;
391 }
392
393 ARMARX_DEBUG << kinematicChain->getNode(i)->getName() << ": "
394 << kinematicChain->getNode(i)->getJointValue();
395 }
396
397
398 if (headIKUnitListener)
399 {
400 headIKUnitListener->reportHeadTargetChanged(targetJointAngles, globalPos);
401 }
402
403 try
404 {
405 kinematicUnitPrx->switchControlMode(controlModes);
406 ARMARX_DEBUG << "setting new joint angles" << targetJointAngles;
407 kinematicUnitPrx->setJointAngles(targetJointAngles);
408 }
409 catch (...)
410 {
411 ARMARX_IMPORTANT << "setJointAngles failed";
412 }
413 }
414 }
415
421
422
423} // namespace armarx
#define VAROUT(x)
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)
The FramedPosition class.
Definition FramedPose.h:158
void onInitComponent() override
Pure virtual hook for the subclass.
void start(const Ice::Current &c=Ice::emptyCurrent) override
void release(const Ice::Current &c=Ice::emptyCurrent) override
UnitExecutionState getExecutionState(const Ice::Current &c=Ice::emptyCurrent) override
void onDisconnectComponent() override
Hook for subclass.
void init(const Ice::Current &c=Ice::emptyCurrent) override
void setCycleTime(Ice::Int milliseconds, const Ice::Current &c=Ice::emptyCurrent) override
void stop(const Ice::Current &c=Ice::emptyCurrent) override
void setHeadTarget(const std::string &robotNodeSetName, const FramedPositionBasePtr &targetPosition, const Ice::Current &c=Ice::emptyCurrent) override
void onConnectComponent() override
Pure virtual hook for the subclass.
void request(const Ice::Current &c=Ice::emptyCurrent) override
PropertyDefinitionsPtr createPropertyDefinitions() override
void onExitComponent() override
Hook for subclass.
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
Definition Logging.cpp:99
void offeringTopic(const std::string &name)
Registers a topic for retrival after initialization.
TopicProxyType getTopic(const std::string &name)
Returns a proxy of the specified topic.
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
int getState() const
Retrieve current state of the ManagedIceObject.
void setName(std::string name)
Override name of well-known object.
The periodic task executes one thread method repeatedly using the time period specified in the constr...
Property< PropertyType > getProperty(const std::string &name)
Property creation and retrieval.
static VirtualRobot::RobotPtr createLocalCloneFromFile(RobotStateComponentInterfacePrx robotStatePrx, VirtualRobot::RobotIO::RobotDescription loadMode=VirtualRobot::RobotIO::eFull)
This is a convenience function for createLocalClone, which automatically gets the filename from the R...
static bool synchronizeLocalClone(VirtualRobot::RobotPtr robot, RobotStateComponentInterfacePrx robotStatePrx)
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceInternal::Handle< Vector3 > Vector3Ptr
Definition Pose.h:165
std::vector< std::string > Split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
IceInternal::Handle< FramedPosition > FramedPositionPtr
Definition FramedPose.h:149
Eigen::Vector3d Vector3
Definition kbm.h:43