CollisionFreeJointControl.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 RobotSkillTemplates::MotionControlGroup
17 * @author Mirko Waechter ( mirko dot waechter at kit dot edu )
18 * @date 2018
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
24
27
28#include <RobotAPI/interface/components/TrajectoryPlayerInterface.h>
29//#include <ArmarXCore/observers/variant/DatafieldRef.h>
30
31#include <VirtualRobot/CollisionDetection/CDManager.h>
32#include <VirtualRobot/RobotNodeSet.h>
33#include <VirtualRobot/TimeOptimalTrajectory/TimeOptimalTrajectory.h>
34
36
39
41#include <MotionPlanning/CSpace/CSpacePath.h>
42#include <MotionPlanning/CSpace/CSpaceSampled.h>
43#include <MotionPlanning/Planner/BiRrt.h>
44#include <MotionPlanning/PostProcessing/ShortcutProcessor.h>
45
46using namespace armarx;
47using namespace MotionControlGroup;
48
49// DO NOT EDIT NEXT LINE
50CollisionFreeJointControl::SubClassRegistry
51 CollisionFreeJointControl::Registry(CollisionFreeJointControl::GetName(),
53
54void
56{
57 // put your user code for the enter-point here
58 // execution time should be short (<100ms)
59}
60
61void
63{
64 // put your user code for the execution-phase here
65 // runs in seperate thread, thus can do complex operations
66 // should check constantly whether isRunningTaskStopped() returns true
67 TIMING_START(FullCalc);
68
70 getContext<MotionControlGroupStatechartContext>();
71 std::set<std::string> jointNameSet;
72 if (!in.isSingleGoalConfigSet() && !in.isGoalConfigSet())
73 {
74 ARMARX_WARNING << "Either GoalConfig or SingleGoalConfig input parameter must be set!";
75 emitFailure();
76 return;
77 }
78 ARMARX_INFO << VAROUT(in.isGoalConfigSet()) << VAROUT(in.isSingleGoalConfigSet());
79 if (in.isSingleGoalConfigSet())
80 {
81 ARMARX_INFO << VAROUT(in.getSingleGoalConfig());
82 }
83 std::vector<StringValueMapPtr> goalConfig;
84 if (in.isGoalConfigSet())
85 {
86 goalConfig = in.getGoalConfig();
87 }
88 else
89 {
90 auto mapPtr = StringValueMap::FromStdMap(in.getSingleGoalConfig());
92 goalConfig.push_back(mapPtr);
93 }
94 // check for joint conflict
95 ARMARX_INFO << VAROUT(goalConfig.size());
96 for (auto goalConfigMapPtr : goalConfig)
97 {
98 ARMARX_CHECK_EXPRESSION(goalConfigMapPtr);
99 auto goalConfigMap = goalConfigMapPtr->toStdMap<float>();
100 for (auto pair : goalConfigMap)
101 {
102 if (jointNameSet.count(pair.first) != 0)
103 {
104 ARMARX_ERROR << "joint " << pair.first << " is used twice!";
105 emitFailure();
106 return;
107 }
108 jointNameSet.insert(pair.first);
109 }
110 }
111
112 float timeStep = in.getTimestep();
113 std::vector<TrajectoryPtr> solutions;
114 TIMING_START(robotCloning);
115
116 auto robot = context->getRobotPool()->getRobot(in.getSafetyMargin());
117 TIMING_END(robotCloning);
118 // TIMING_START(robotInflation);
119 // for (auto& node : robot->getRobotNodes())
120 // {
121 // if (node->getCollisionModel())
122 // {
123 // node->getCollisionModel()->inflateModel(30);
124 // }
125 // }
126 // // robot->inflateCollisionModel(30);
127 // TIMING_END(robotInflation);
128 if (!in.isCollisionSetNamesSet() && !in.isCollisionSetPairsSet())
129 {
130 throw LocalException()
131 << "You need to either specify CollisionSetNames or CollisionSetPairs!";
132 }
133
134 VirtualRobot::CDManagerPtr cdm(new VirtualRobot::CDManager(robot->getCollisionChecker()));
135
136
137 auto rnsList = in.isCollisionSetNamesSet() ? in.getCollisionSetNames() : Ice::StringSeq();
138 for (size_t i = 0; i < rnsList.size(); ++i)
139 {
140 auto rns1 = robot->getRobotNodeSet(rnsList.at(i));
142 cdm->addCollisionModel(rns1);
143 // for (size_t j = i + 1; j < rnsList.size(); ++j)
144 // {
145 // auto rns1 = robot->getRobotNodeSet(rnsList.at(i));
146 // auto rns2 = robot->getRobotNodeSet(rnsList.at(j));
147 // ARMARX_CHECK_NOT_NULL(rns1);
148 // ARMARX_CHECK_NOT_NULL(rns2);
149 // ARMARX_INFO << "Adding: " << rns1->getName() << " and " << rns2->getName();
150 // cdm->addCollisionModelPair(rns1, rns2);
151 // }
152 }
153
154 auto rnsPairList = in.getCollisionSetPairs();
155 for (auto& subList : rnsPairList)
156 {
157 ARMARX_CHECK_EQUAL(subList->getSize(), 2);
158 auto getRns = [&](const std::string& name)
159 {
160 VirtualRobot::RobotNodeSetPtr rns;
161 if (robot->hasRobotNodeSet(name))
162 {
163 rns = robot->getRobotNodeSet(name);
164 }
165 else
166 {
167 if (robot->hasRobotNode(name))
168 {
169 auto node = robot->getRobotNode(name);
170 rns = VirtualRobot::RobotNodeSet::createRobotNodeSet(
171 robot, node->getName(), {node});
172 }
173 }
174 ARMARX_CHECK_EXPRESSION(rns) << name;
175 return rns;
176 };
177
178 auto rns1 = getRns(subList->getVariant(0)->getString());
179 auto rns2 = getRns(subList->getVariant(1)->getString());
180
181 cdm->addCollisionModelPair(rns1, rns2);
182 }
183
184 for (auto goalConfigMapPtr : goalConfig)
185 {
186 if (isRunningTaskStopped())
187 {
188 break;
189 }
190 auto goalConfigMap = goalConfigMapPtr->toStdMap<float>();
191 Ice::StringSeq jointNames = getMapKeys(goalConfigMap);
192
193
194 auto rns = VirtualRobot::RobotNodeSet::createRobotNodeSet(
195 robot, "tempset", jointNames, robot->getRootNode()->getName());
196 // auto rns = robot->getRobotNodeSet(in.getKinematicChain());
197 // auto jointNames = rns->getNodeNames();
198 Saba::CSpaceSampledPtr cspace(new Saba::CSpaceSampled(robot, cdm, rns, 1000000));
199
200 Saba::BiRrt rrt(cspace, Saba::Rrt::eExtend);
201 rrt.setPlanningTimeout(in.getTimeoutMs());
203
204 Eigen::VectorXf goalConfig(rns->getSize());
205 for (std::size_t i = 0; i < rns->getSize(); ++i)
206 {
207 goalConfig(i) = goalConfigMap.at(rns->getNode(i)->getName());
208 }
209 rrt.setStart(rns->getJointValuesEigen());
210 rrt.setGoal(goalConfig);
211 TIMING_START(Planning);
212 auto planningOk = rrt.plan();
213 TIMING_END(Planning);
214 Saba::CSpacePathPtr solutionOptimized;
215 if (planningOk)
216 {
217 ARMARX_INFO << " Planning succeeded ";
218 auto solution = rrt.getSolution();
219 TIMING_START(ShortCutting);
220
221 // Saba::ElasticBandProcessorPtr postProcessing(new Saba::ElasticBandProcessor(solution, cspace, false));
222 Saba::ShortcutProcessorPtr postProcessing(
223 new Saba::ShortcutProcessor(solution, cspace, false));
224 solutionOptimized = postProcessing->shortenSolutionRandom(
225 in.getOptimizationSteps(), in.getOptimizationMaxStepSize());
226 TIMING_END(ShortCutting);
227 }
228 else
229 {
230 ARMARX_INFO << " Planning failed";
231 emitPlanningFailed();
232 return;
233 }
234
235
236 auto waypoints = solutionOptimized->getPoints();
237 ARMARX_INFO << "Waypoint Count: " << waypoints.size();
238 TrajectoryPtr waypointTraj = new Trajectory();
239 LimitlessStateSeq limitlessStates;
240 for (std::size_t i = 0; i < rns->getSize(); ++i)
241 {
242 auto node = rns->getNode(i);
243 limitlessStates.push_back(LimitlessState{
244 node->isLimitless(), node->getJointLimitLow(), node->getJointLimitHigh()});
245 }
246 waypointTraj->setDimensionNames(jointNames);
247 waypointTraj->setLimitless(limitlessStates);
248 int t = 0;
249 for (auto waypoint : waypoints)
250 {
251 for (std::size_t i = 0; i < rns->getSize(); ++i)
252 {
253 waypointTraj->setPositionEntry(t, i, waypoint(i));
254 }
255 t++;
256 }
258
259 Eigen::VectorXd maxVelocities =
260 Eigen::VectorXd::Constant(rns->getSize(), (double)in.getMaxVelocity());
261 Eigen::VectorXd maxAcceleration =
262 Eigen::VectorXd::Constant(rns->getSize(), (double)in.getMaxAcceleration());
263 if (in.isJointScaleSet())
264 {
265 auto scalingMap = in.getJointScale();
266 for (size_t i = 0; i < rns->getSize(); ++i)
267 {
268 if (scalingMap.at(rns->getNode(i)->getName()) > 0)
269 {
270 auto scale = scalingMap.at(rns->getNode(i)->getName());
271 maxVelocities(i) *= scale;
272 maxAcceleration(i) *= scale;
273 }
274 }
275 }
276 auto newTraj =
277 waypointTraj->calculateTimeOptimalTrajectory(maxVelocities,
278 maxAcceleration,
279 in.getMaxDeviation(),
280 IceUtil::Time::secondsDouble(timeStep));
282 solutions.push_back(newTraj);
283 }
284 TrajectoryPtr combinedTraj(new Trajectory());
285 Ice::StringSeq jointNames;
286 int fullTrajDim = 0;
287 for (auto& sol : solutions)
288 {
289 size_t dims = sol->dim();
290 Ice::DoubleSeq timestamps = sol->getTimestamps();
291
292 for (size_t d = 0; d < dims; ++d)
293 {
294 combinedTraj->addPositionsToDimension(
295 fullTrajDim, sol->getDimensionData(d), timestamps);
296 jointNames.push_back(sol->getDimensionName(d));
297 fullTrajDim++;
298 }
299 }
300 combinedTraj->setDimensionNames(jointNames);
301 double duration = combinedTraj->getTimeLength();
302 auto rns = VirtualRobot::RobotNodeSet::createRobotNodeSet(
303 robot, "tempset", jointNames, robot->getRootNode()->getName());
304 LimitlessStateSeq limitlessStates;
305 for (std::size_t i = 0; i < rns->getSize(); ++i)
306 {
307 auto node = rns->getNode(i);
308 limitlessStates.push_back(LimitlessState{
309 node->isLimitless(), node->getJointLimitLow(), node->getJointLimitHigh()});
310 }
311 combinedTraj->setLimitless(limitlessStates);
312
313 TIMING_END(FullCalc);
314 ARMARX_INFO << "traj: " << combinedTraj->output();
315
316 NameValueMap targetVelocities;
317
318 if (in.getUseTrajectoryPlayerComponent())
319 {
320 TrajectoryPlayerInterfacePrx trajPlayer =
321 context->getProxy<TrajectoryPlayerInterfacePrx>(in.getTrajectoryPlayerName());
322 trajPlayer->resetTrajectoryPlayer(false);
323 trajPlayer->considerConstraints(false);
324 trajPlayer->setLoopPlayback(false);
325 trajPlayer->loadJointTraj(combinedTraj);
326 trajPlayer->startTrajectoryPlayer();
327 auto endTime = trajPlayer->getEndTime();
328 double currentTime = 0;
329 do
330 {
331 ARMARX_INFO << deactivateSpam(1) << "CurrentTime: " << currentTime
332 << " endTime: " << endTime;
333 usleep(10000);
334 currentTime = trajPlayer->getCurrentTime();
335 } while (currentTime < endTime && !isRunningTaskStopped());
336 if (!isRunningTaskStopped() && currentTime >= endTime)
337 {
338 if (in.getWaitTimeAfterExecution() > 0)
339 {
340 ARMARX_INFO << "Waiting for " << in.getWaitTimeAfterExecution();
341 TimeUtil::MSSleep(in.getWaitTimeAfterExecution());
342 }
343 trajPlayer->pauseTrajectoryPlayer();
344 emitSuccess();
345 }
346 else if (isRunningTaskStopped())
347 {
348 trajPlayer->pauseTrajectoryPlayer();
349 }
350 }
351 else
352 {
353 TrajectoryController ctrl(combinedTraj, in.getKp());
354
355 CycleUtil cycle(timeStep * 1000);
356 NameControlModeMap modes;
357
358 for (auto& jointName : jointNames)
359 {
360 modes[jointName] = eVelocityControl;
361 }
362 context->getKinematicUnit()->switchControlMode(modes);
363 // uncomment this if you need a continous run function. Make sure to use sleep or use blocking wait to reduce cpu load.
364 while (!isRunningTaskStopped()) // stop run function if returning true
365 {
366 // do your calculations
368
369 Eigen::VectorXf velocityTargets = ctrl.update(timeStep, rns->getJointValuesEigen());
370 int i = 0;
371 for (auto& jointName : jointNames)
372 {
373 targetVelocities[jointName] = velocityTargets(i);
374 i++;
375 }
376 context->getKinematicUnit()->setJointVelocities(targetVelocities);
377 // context->getDebugDrawerTopicProxy()->setSphereVisu("trajectory", "timestep" + std::to_string(), new )
378 ARMARX_INFO << deactivateSpam(2) << "timestep: " << ctrl.getCurrentTimestamp()
379 << " Duration: " << duration;
380 if (ctrl.getCurrentTimestamp() >= duration)
381 {
382 ARMARX_INFO << "Reached Goal!";
383 emitSuccess();
384 break;
385 }
386 cycle.waitForCycleDuration();
387 }
388 for (auto& jointName : jointNames)
389 {
390 targetVelocities[jointName] = 0;
391 }
392 context->getKinematicUnit()->setJointVelocities(targetVelocities);
393 }
395
396 for (auto goalConfigMapPtr : goalConfig)
397 {
398 auto goalConfigMap = goalConfigMapPtr->toStdMap<float>();
399 NameValueMap errors;
400 for (auto& pair : goalConfigMap)
401 {
402 errors[pair.first] = robot->getRobotNode(pair.first)->getJointValue();
403 }
404 ARMARX_INFO << VAROUT(errors) << VAROUT(goalConfigMap);
405 }
406}
407
408void
410{
411 // put your user code for the breaking point here
412 // execution time should be short (<100ms)
413 if (in.getUseTrajectoryPlayerComponent())
414 {
416 getContext<MotionControlGroupStatechartContext>();
417 TrajectoryPlayerInterfacePrx trajPlayer =
418 context->getProxy<TrajectoryPlayerInterfacePrx>(in.getTrajectoryPlayerName());
419 trajPlayer->stopTrajectoryPlayer();
420 }
421}
422
423void
425{
426 // put your user code for the exit point here
427 // execution time should be short (<100ms)
428}
429
430// DO NOT EDIT NEXT FUNCTION
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
#define VAROUT(x)
This util class helps with keeping a cycle time during a control cycle.
Definition CycleUtil.h:41
IceUtil::Time waitForCycleDuration()
This function will wait (virtual or system time) until the cycle time is reached.
Definition CycleUtil.cpp:53
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
CollisionFreeJointControl(const XMLStateConstructorParams &stateData)
static XMLStateFactoryBasePtr CreateInstance(XMLStateConstructorParams stateData)
custom implementation of the StatechartContext for a statechart
const RobotPoolPtr & getRobotPool() const
Robot Pool containing collision robots.
static bool synchronizeLocalClone(VirtualRobot::RobotPtr robot, RobotStateComponentInterfacePrx robotStatePrx)
static StringValueMapPtr FromStdMap(const std::map< std::string, Type > &map)
FromStdMap creates a StringValueMap from a std::map<std::string, Type>.
static void MSSleep(int durationMS)
lock the calling thread for a given duration (like usleep(...) but using Timeserver time)
Definition TimeUtil.cpp:100
Subcontroller which handles all program interaction with the modle, communicates with other controlle...
static void UnfoldLimitlessJointPositions(TrajectoryPtr traj)
static void FoldLimitlessJointPositions(TrajectoryPtr traj)
const Eigen::VectorXf & update(double deltaT, const Eigen::VectorXf &currentPosition)
The Trajectory class represents n-dimensional sampled trajectories.
Definition Trajectory.h:77
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#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...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define TIMING_START(name)
Helper macro to do timing tests.
Definition TimeUtil.h:289
#define TIMING_END(name)
Prints duration.
Definition TimeUtil.h:306
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceInternal::Handle< Trajectory > TrajectoryPtr
Definition Trajectory.h:52
void getMapKeys(const MapType &map, OutputIteratorType it)
Definition algorithm.h:173
IceInternal::Handle< XMLStateFactoryBase > XMLStateFactoryBasePtr
Definition XMLState.h:64