PlayPlatformTrajectory.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::PlatformGroup
17 * @author Stefan Reither ( stef dot reither at web dot de )
18 * @date 2017
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
24
27
29
31
32using namespace armarx;
33using namespace PlatformGroup;
34
35#define STATE_POSITION 0
36#define STATE_VELOCITY 1
37
38#define MAX_TRANSLATION_ACCEL 0.5 // m/s²
39#define MAX_ROTATION_ACCEL 0.75 // rad/s²
40
41#define FACTOR_BETWEEN_TRANS_AND_ROT 500.0
42
43// DO NOT EDIT NEXT LINE
44PlayPlatformTrajectory::SubClassRegistry
45 PlayPlatformTrajectory::Registry(PlayPlatformTrajectory::GetName(),
47
50{
51 ARMARX_INFO << t->output();
52 double length = t->getLength(0);
53 ARMARX_INFO << VAROUT(length);
54 double timelength = t->getTimeLength();
55 ARMARX_INFO << VAROUT(timelength);
56 auto timestamps = t->getTimestamps();
57 ARMARX_INFO << VAROUT(timestamps);
58 Ice::DoubleSeq newTimestamps;
59 newTimestamps.push_back(0);
60 for (size_t var = 0; var < timestamps.size() - 1; ++var)
61 {
62 double tBefore = timestamps.at(var);
63 double tAfter = (timestamps.at(var + 1));
64 ARMARX_INFO << VAROUT(tBefore) << VAROUT(tAfter);
65 double partLength = t->getLength(0, tBefore, tAfter);
66 double lengthPortion = partLength / length;
67 ARMARX_INFO << VAROUT(partLength) << VAROUT(lengthPortion);
68 newTimestamps.push_back(*newTimestamps.rbegin() + timelength * lengthPortion);
69 }
70 ARMARX_INFO << VAROUT(newTimestamps);
71 TrajectoryPtr newTraj = new Trajectory();
72 for (size_t d = 0; d < t->dim(); ++d)
73 {
74 newTraj->addDimension(t->getDimensionData(d), newTimestamps, t->getDimensionName(d));
75 }
76 ARMARX_INFO << newTraj->output();
77
78 return newTraj;
79}
80
82normalizeTimestamps(TrajectoryPtr t, float maxTransVel, float maxRotVel)
83{
84 double totalTime = 0.0;
85 auto timestamps = t->getTimestamps();
86 auto dimNames = t->getDimensionNames();
87
88 for (size_t var = 0; var < timestamps.size() - 1; ++var)
89 {
90 double xLength =
91 t->getLength(std::find(dimNames.begin(), dimNames.end(), "x") - dimNames.begin(),
92 0,
93 timestamps.at(var),
94 timestamps.at(var + 1)) /
95 1000; // conversion mm to m
96 ARMARX_INFO << VAROUT(xLength);
97 double yLength =
98 t->getLength(std::find(dimNames.begin(), dimNames.end(), "y") - dimNames.begin(),
99 0,
100 timestamps.at(var),
101 timestamps.at(var + 1)) /
102 1000; // conversion mm to m
103 ARMARX_INFO << VAROUT(yLength);
104 double alphaLength =
105 t->getLength(std::find(dimNames.begin(), dimNames.end(), "alpha") - dimNames.begin(),
106 0,
107 timestamps.at(var),
108 timestamps.at(var + 1));
109 ARMARX_INFO << VAROUT(alphaLength);
110
111 double xyLength = std::sqrt(fabs(xLength * xLength + yLength * yLength));
112 ARMARX_INFO << VAROUT(xyLength);
113
114 double sAcc = 0.5 * maxTransVel * maxTransVel / MAX_TRANSLATION_ACCEL;
115
116 double xyTime = 0.0;
117
118 if (xyLength <= 2 * sAcc)
119 {
120 xyTime = 2 * std::sqrt(xyLength / MAX_TRANSLATION_ACCEL);
121 }
122 else
123 {
124 xyTime = 2 * maxTransVel / MAX_TRANSLATION_ACCEL + (xyLength - 2 * sAcc) / maxTransVel;
125 }
126
127 ARMARX_INFO << VAROUT(xyTime);
128 double rotTime =
129 2 * maxRotVel / MAX_ROTATION_ACCEL +
130 (alphaLength - 0.5 * maxRotVel * maxRotVel / MAX_ROTATION_ACCEL) / maxRotVel;
131 ARMARX_INFO << VAROUT(rotTime);
132
133 double dtime = (xyTime > rotTime) ? xyTime : rotTime;
134 totalTime += dtime;
135 }
136
137 t = t->normalize(0.0, totalTime);
138 ARMARX_INFO << t->output();
139
140 return t;
141}
142
145{
146 Ice::DoubleSeq factors = {1.0, 1.0, factor};
147 ARMARX_INFO << VAROUT(factors);
148 t->scaleValue(factors);
149 return t;
150}
151
152void
154{
155 TrajectoryPtr platformTraj = in.getTrajectory();
156 auto dimNames = platformTraj->getDimensionNames();
157 if (dimNames.at(0) != "x" || dimNames.at(1) != "y" || dimNames.at(2) != "alpha")
158 {
159 ARMARX_WARNING << "Trajectory misses at least one of the following needed dimensions: 'x', "
160 "'y' and 'alpha'.";
161 emitFailure();
162 }
163}
164
165void
167{
168 PlatformContext* c = getContext<PlatformContext>();
169 PlatformUnitInterfacePrx platformUnit = c->platformUnitPrx;
170 TrajectoryPtr platformTraj = in.getTrajectory();
171 auto dimNames = platformTraj->getDimensionNames();
172 float maxTransVel = in.getMaxTranslationVelocity();
173 float maxRotVel = in.getMaxRotationVelocity();
174
175 if (in.getBalanceTrajectory())
176 {
177 // Scaling rotation dimension of the trajectory to fit to the translation trajectory
178
179 platformTraj = scaleRotationLengths(platformTraj, FACTOR_BETWEEN_TRANS_AND_ROT);
180
181 // Balancing timestamps of the trajetory
182
183 platformTraj = balanceTimestamps(platformTraj);
184
185 // Rescaling rotation dimension of the trajectory
186
187 platformTraj =
188 scaleRotationLengths(platformTraj, (float)(1 / FACTOR_BETWEEN_TRANS_AND_ROT));
189
190 // calculate approximation of duration of the movement given a maximal velocity and a maximal acceleration
191
192 platformTraj = normalizeTimestamps(platformTraj, maxTransVel, maxRotVel);
193 }
194
195 // Executing trajectory
196
197
198 MultiDimPIDController pidTrans(in.getPTranslation(),
199 in.getITranslation(),
200 in.getDTranslation(),
201 maxTransVel,
202 MAX_TRANSLATION_ACCEL * 1000);
203 PIDController pidRot(in.getPOrientation(),
204 in.getIOrientation(),
205 in.getDOrientation(),
206 maxRotVel,
208 DatafieldRefPtr posXRef =
209 new DatafieldRef(c->platformUnitObserverPrx, "platformPose", "positionX");
210 DatafieldRefPtr posYRef =
211 new DatafieldRef(c->platformUnitObserverPrx, "platformPose", "positionY");
212 DatafieldRefPtr oriRef =
213 new DatafieldRef(c->platformUnitObserverPrx, "platformPose", "rotation");
214
215 NameValueMap targetValues;
216 IceUtil::Time startTime = armarx::TimeUtil::GetTime();
217 double currentTime = 0.0;
218 bool finalPoseReached = false;
219 int cycleTime = in.getCycleTimeMS();
220 CycleUtil cycle(cycleTime);
221
222 c->debugDrawer->removeLayer("ActualRobotPath");
223
224 // Vector3Ptr positionOld;
225
226 IceUtil::Time cycleStart;
227 while (!isRunningTaskStopped()) // stop run function if returning true
228 {
229 cycleStart = armarx::TimeUtil::GetTime();
230
231 currentTime = (armarx::TimeUtil::GetTime() - startTime).toSecondsDouble();
232 if (currentTime > platformTraj->getTimeLength())
233 {
234 currentTime = platformTraj->getTimeLength();
235 finalPoseReached = true;
236 }
237
238 float posx = posXRef->getDataField()->getFloat();
239 float posy = posYRef->getDataField()->getFloat();
240 float ori = oriRef->getDataField()->getFloat();
241
242 // Vector3Ptr v = new Vector3 {posx, posy, 50.f};
243 // if (positionOld)
244 // {
245 // c->debugDrawer->setLineVisu("ActualRobotPath", boost::lexical_cast<std::string>(currentTime), positionOld, v, 2.0, DrawColor {0, 1, 0, 1});
246 // }
247 // positionOld = v;
248
249 std::vector<Ice::DoubleSeq> allStates = platformTraj->getAllStates(currentTime, 1);
250 for (size_t i = 0; i < platformTraj->dim(); ++i)
251 {
252 targetValues[dimNames.at(i)] = allStates[i][STATE_POSITION];
253 }
254
255 Eigen::Vector3f pos{posx, posy, 0.0f};
256 Eigen::Vector3f targetPos{targetValues["x"], targetValues["y"], 0.0f};
257
258 pidTrans.update(pos, targetPos);
259 pidRot.update(ori, targetValues["alpha"]);
260 float newRotVel = pidRot.getControlValue();
261 Eigen::Vector3f globalNewTransVel = {
262 pidTrans.getControlValue()[0], pidTrans.getControlValue()[1], 0};
263 Eigen::Matrix3f m;
264 m = Eigen::AngleAxisf(ori, Eigen::Vector3f::UnitZ());
265 Eigen::Vector3f localVel = m.inverse() * globalNewTransVel;
266
267
268 ARMARX_INFO << "New values: x: " << localVel[0] << " , y= " << localVel[1]
269 << " , alpha= " << newRotVel;
270
271 platformUnit->move(localVel[0], localVel[1], newRotVel);
272
273 if (finalPoseReached && fabs(pidTrans.previousError) < in.getPositionalAccuracy() &&
274 fabs(pidRot.previousError) < in.getOrientationalAccuracy())
275 {
276 disableRunFunction();
277 platformUnit->move(0, 0, 0);
278 ARMARX_INFO << "Success";
279 emitSuccess();
280 }
281 else
282 {
283 cycle.waitForCycleDuration();
284 }
285 }
286}
287
288void
290{
291 // Setting velocities to zero
292 PlatformContext* c = getContext<PlatformContext>();
293 PlatformUnitInterfacePrx platformUnit = c->platformUnitPrx;
294 platformUnit->move(0.0, 0.0, 0.0);
295}
296
297// DO NOT EDIT NEXT FUNCTION
TrajectoryPtr normalizeTimestamps(TrajectoryPtr t, float maxTransVel, float maxRotVel)
#define MAX_ROTATION_ACCEL
#define STATE_POSITION
TrajectoryPtr scaleRotationLengths(TrajectoryPtr t, float factor)
#define MAX_TRANSLATION_ACCEL
#define FACTOR_BETWEEN_TRANS_AND_ROT
TrajectoryPtr balanceTimestamps(TrajectoryPtr t)
#define VAROUT(x)
constexpr T c
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
The DatafieldRef class is similar to the ChannelRef, but points to a specific Datafield instead of to...
void update(const double deltaSec, const PIDVectorX &measuredValue, const PIDVectorX &targetValue)
double getControlValue() const
void update(double deltaSec, double measuredValue, double targetValue)
PlayPlatformTrajectory(const XMLStateConstructorParams &stateData)
static XMLStateFactoryBasePtr CreateInstance(XMLStateConstructorParams stateData)
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition TimeUtil.cpp:42
The Trajectory class represents n-dimensional sampled trajectories.
Definition Trajectory.h:77
#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
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceInternal::Handle< Trajectory > TrajectoryPtr
Definition Trajectory.h:52
MultiDimPIDControllerTemplate<> MultiDimPIDController
IceInternal::Handle< DatafieldRef > DatafieldRefPtr
Definition Observer.h:43
IceInternal::Handle< XMLStateFactoryBase > XMLStateFactoryBasePtr
Definition XMLState.h:64