PlatformUnitDynamicSimulation.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
19 * @author Valerij Wittenbeck, Nikolaus Vahrenkamp
20 * @date 2014
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24
25
27
28#include <cmath>
29
30#include <Eigen/Geometry>
31
33
36
37using namespace armarx;
38
39void
41{
42 linearVelocityMax = getProperty<float>("LinearVelocityMax").getValue();
43 linearVelocityMin = getProperty<float>("LinearVelocityMin").getValue();
44 linearAccelerationMax = getProperty<float>("LinearAccelerationMax").getValue();
45 angularVelocityMax = getProperty<float>("AngularVelocityMax").getValue();
46 angularAccelerationMax = getProperty<float>("AngularAccelerationMax").getValue();
47 platformOrientationOffset = getProperty<float>("PlatformOrientationOffset").getValue();
48
49
50 robotName = getProperty<std::string>("RobotName").getValue();
51 platformName = getProperty<std::string>("PlatformName").getValue();
52
53 simulatorPrxName = getProperty<std::string>("SimulatorProxyName").getValue();
54
55 positionalAccuracy = 0.02f; //in m
56 orientationalAccuracy = 0.1f; //in rad
57
58 intervalMs = getProperty<int>("IntervalMs").getValue();
59 ARMARX_VERBOSE << "Starting platform unit dynamic simulation with " << intervalMs
60 << " ms interval";
62 this,
65 false,
66 "PlatformUnitSimulation");
67 simulationTask->setDelayWarningTolerance(100);
68
69 if (!robotName.empty())
70 {
71 std::string robotTopicName = "Simulator_Robot_";
72 robotTopicName += robotName;
73 ARMARX_INFO << "Simulator Robot topic: " << robotTopicName;
74 usingTopic(robotTopicName);
75 }
76 else
77 {
78 ARMARX_WARNING << "No robot loaded...";
79 }
80
82
83 currentRotation = 0.0f;
84 targetRotation = 0.0f;
85}
86
87void
89{
90 ARMARX_INFO << "Stopping platform unit";
91 std::unique_lock<std::mutex> lock(currentPoseMutex);
92 simulationTask->stop();
93 simulatorPrx = nullptr;
94}
95
96void
98{
99 platformControlMode = eUnknown;
100
101
102 ARMARX_INFO << "Using simulator proxy: " << simulatorPrxName << flush;
104
105 {
106 std::unique_lock<std::mutex> lock(currentPoseMutex);
108 }
111
112 simulationTask->start();
113}
114
115void
120
121Eigen::Vector3f
123 Eigen::Vector3f curV)
124{
125 ARMARX_DEBUG << "calc platform vel, dist:" << distance.transpose()
126 << ", curVel:" << curV.transpose() << ", linearVelocityMax:" << linearVelocityMax
127 << ", linearAccelerationMax:" << linearAccelerationMax << flush;
128
129 if (distance.norm() < positionalAccuracy)
130 {
131 ARMARX_DEBUG << "calc platform vel end: ZERO" << flush;
132 return Eigen::Vector3f::Zero();
133 }
134
135 Eigen::Vector3f v = distance;
136 //make sure there is a minimum velocity so the platform doesn't slow down too much
137 v = clampf(v.norm(), linearVelocityMin, linearVelocityMax) * v.normalized();
138
139 if (!std::isfinite(v(0)) || !std::isfinite(v(1)) || !std::isfinite(v(2)))
140 {
141
142 ARMARX_ERROR << "NAN in platform calculation, v=" << v << ", distance=" << distance
143 << ",distance.normalized()=" << distance.normalized() << flush;
144 return Eigen::Vector3f::Zero();
145 }
146
147 //throttle speed if the change of current to desired is too large (> max. accel)
148 Eigen::Vector3f a = (v - curV);
149
150 if ((v - curV).norm() > 1e-5)
151 {
152 a = std::min<float>(a.norm(), linearAccelerationMax) * a.normalized();
153
154 if (!std::isfinite(a(0)) || !std::isfinite(a(1)) || !std::isfinite(a(2)))
155 {
156
157 ARMARX_ERROR << "NAN in platform calculation, a=" << a << ", (v - curV)=" << (v - curV)
158 << ",(v - curV).normalized()=" << (v - curV).normalized() << flush;
159 return Eigen::Vector3f::Zero();
160 }
161 }
162
163 v = a + curV;
164 ARMARX_DEBUG << "calc platform vel end: " << v.transpose() << flush;
165 return v;
166}
167
168float
169PlatformUnitDynamicSimulation::calculateAngularVelocity(float source, float target, float curV)
170{
171 ARMARX_DEBUG << "calc platform ang vel, from:" << source << " to:" << target
172 << ", curVel:" << curV << flush;
173 const float M_2PI = 2 * M_PI;
174 float cw = fmod(source - target + M_2PI, M_2PI); //ensure that angle is in [0,2PI]
175 float ccw = fmod(target - source + M_2PI, M_2PI);
176 float minDist = (cw < ccw) ? -cw : ccw;
177
178 if (fabs(minDist) < orientationalAccuracy)
179 {
180 ARMARX_DEBUG << "calc platform ang vel end: ZERO" << flush;
181 return 0.f;
182 }
183
184 float v = (minDist < 0) ? -angularVelocityMax : angularVelocityMax;
185 float a = (v - curV);
187 v = a + curV;
188 ARMARX_DEBUG << "calc platform ang vel end:" << v << flush;
189 return v;
190}
191
192void
194{
195 moveRelative(0, 0, 0, 500, 500, current);
196}
197
198static Eigen::Vector2f
199transformToLocalVelocity(float currentRotation, float velX, float velY)
200{
201 // Revert the rotation by rotating by the negative angle
202 return Eigen::Rotation2Df(-currentRotation) * Eigen::Vector2f(velX, velY);
203}
204
205void
207{
208 Eigen::Vector3f relTargetPosition;
209 Eigen::Vector3f curLinVel;
210 float curAngVel = 0.f;
211 {
212 std::unique_lock<std::mutex> lock(currentPoseMutex);
213
214 if (!simulatorPrx)
215 {
216 return;
217 }
218
219 if (platformControlMode == ePositionControl)
220 {
221
222
223 ARMARX_DEBUG << "Platform sim step" << flush;
224
225 SimulatedRobotState state = simulatorPrx->getRobotState(robotName);
226
227 if (!state.hasRobot)
228 {
229 ARMARX_ERROR << deactivateSpam(5) << "No robot with name " << robotName;
230 return;
231 }
232
233 Vector3Ptr p = Vector3Ptr::dynamicCast(state.pose->position);
234 relTargetPosition << (targetPosition.x - p->x) / 1000.f,
235 (targetPosition.y - p->y) / 1000.f, 0;
236
237 Vector3BasePtr v = state.linearVelocity;
238 Vector3BasePtr o = state.angularVelocity;
239 currentVelocity.x = v->x;
240 currentVelocity.y = v->y;
242
243 // The currentVelocity is in the global frame, we need to report the velocity in the platform local frame
244 Eigen::Vector2f localVelocity =
245 transformToLocalVelocity(currentRotation, currentVelocity.x, currentVelocity.y);
246 listenerPrx->begin_reportPlatformVelocity(
247 localVelocity.x(), localVelocity.y(), currentRotationVelocity);
248
249 curLinVel =
250 Eigen::Vector3f(currentVelocity.x / 1000.f, currentVelocity.y / 1000.f, 0.f);
251 curAngVel = currentRotationVelocity;
252
253 const Eigen::Vector3f desiredLinVel =
254 calculateLinearVelocity(relTargetPosition, curLinVel);
255 const float desiredAngVel =
257
258 simulatorPrx->begin_setRobotLinearVelocity(
259 robotName, platformName, new Vector3(desiredLinVel));
260 simulatorPrx->begin_setRobotAngularVelocity(
261 robotName, platformName, new Vector3(Eigen::Vector3f(0.f, 0.f, desiredAngVel)));
262 ARMARX_DEBUG << "Platform sim step end" << flush;
263 }
264 }
265}
266
267void
268PlatformUnitDynamicSimulation::moveTo(Ice::Float targetPlatformPositionX,
269 Ice::Float targetPlatformPositionY,
270 Ice::Float targetPlatformRotation,
271 Ice::Float positionalAccuracy,
272 Ice::Float orientationalAccuracy,
273 const Ice::Current& c)
274{
275 std::unique_lock<std::mutex> lock(currentPoseMutex);
276 platformControlMode = ePositionControl;
277 ARMARX_DEBUG << "Platform move to" << flush;
278 targetPosition.x = targetPlatformPositionX;
279 targetPosition.y = targetPlatformPositionY;
280 targetRotation = targetPlatformRotation;
281 this->positionalAccuracy = positionalAccuracy * .001f;
282 this->orientationalAccuracy = orientationalAccuracy;
283 // listenerPrx->begin_reportNewTargetPose(targetPosition.x, targetPosition.y, targetRotation);
284 ARMARX_INFO << "New Target: " << targetPosition.x << " " << targetPosition.y << " "
285 << targetRotation << flush;
286}
287
288void
289PlatformUnitDynamicSimulation::move(float targetPlatformVelocityX,
290 float targetPlatformVelocityY,
291 float targetPlatformVelocityRotation,
292 const Ice::Current& c)
293{
294 std::unique_lock<std::mutex> lock(currentPoseMutex);
295 targetPlatformVelocityRotation *= 5;
296
297 Eigen::Vector3f translationVel;
298 platformControlMode = eVelocityControl;
299 translationVel << targetPlatformVelocityX, targetPlatformVelocityY, 0;
300 translationVel *= .003;
301 // ARMARX_INFO << deactivateSpam(1) << "New Platformvelocity: " << translationVel << "\nrot vel: " << targetPlatformVelocityRotation;
302
303 simulatorPrx->setRobotLinearVelocityRobotRootFrame(
304 robotName, platformName, new Vector3(translationVel));
305 simulatorPrx->setRobotAngularVelocityRobotRootFrame(
306 robotName,
308 new Vector3(Eigen::Vector3f(0.f, 0.f, targetPlatformVelocityRotation)));
309}
310
311void
313 float targetPlatformOffsetY,
314 float targetPlatformOffsetRotation,
315 float positionalAccuracy,
317 const Ice::Current& c)
318{
319 float targetPositionX, targetPositionY, targetRotation;
320 {
321 std::unique_lock<std::mutex> lock(currentPoseMutex);
322 platformControlMode = ePositionControl;
323 ARMARX_DEBUG << "Platform move relative" << flush;
324 targetPositionX = currentPosition.x + targetPlatformOffsetX;
325 targetPositionY = currentPosition.y + targetPlatformOffsetY;
326 targetRotation = currentRotation + targetPlatformOffsetRotation;
327 }
328 moveTo(targetPositionX,
329 targetPositionY,
333}
334
335void
337 float angularVelocity,
338 const Ice::Current& c)
339{
340 linearVelocityMax = linearVelocity;
341 angularVelocityMax = angularVelocity;
342}
343
344void
346{
347 ARMARX_DEBUG << "Update new platform pose" << flush;
348
349 if (!newPose)
350 {
351 return;
352 }
353
354 Vector3Ptr newPosition = Vector3Ptr::dynamicCast(newPose->position);
355
356 if (newPosition)
357 {
358 currentPosition = Vector3(newPosition->toEigen());
359 }
360
361 QuaternionPtr newOrientation = QuaternionPtr::dynamicCast(newPose->orientation);
362
363 if (newOrientation)
364 {
365 //axis is assumed to be z (fixed)
366 Eigen::Matrix3f rotMat = newOrientation->toEigen();
367 currentRotation = copysign(std::acos(rotMat(0, 0)), std::asin(rotMat(1, 0)));
368 //for some really odd reason, currentRotation can be nan when it should be 0
370
372 }
373}
374
375void
376PlatformUnitDynamicSimulation::updateCurrentVelocity(const Vector3BasePtr& translationVel,
377 const Vector3BasePtr& rotationVel)
378{
379 ARMARX_DEBUG << "Update new platform vel" << flush;
380
381 if (translationVel)
382 {
383 currentVelocity = *Vector3Ptr::dynamicCast(translationVel);
384 ARMARX_DEBUG << "currentVelocity: " << currentVelocity.x << "," << currentVelocity.y << ","
385 << currentVelocity.z;
386 }
387 if (rotationVel)
388 {
389 ARMARX_DEBUG << "currentRotationVelocity (only z is used): " << rotationVel->x << ","
390 << rotationVel->x << "," << rotationVel->z;
391 currentRotationVelocity = rotationVel->z;
392 }
393}
394
395void
396PlatformUnitDynamicSimulation::reportState(SimulatedRobotState const& state, const Ice::Current&)
397{
398 std::unique_lock<std::mutex> lock(currentPoseMutex);
399
400 // Pose
401 updateCurrentPose(state.pose);
402
403 ::armarx::TransformStamped transformStamped;
404
405 FrameHeader header;
406 header.parentFrame = GlobalFrame;
407 header.frame = "root";
408 header.agent = robotName;
409 header.timestampInMicroSeconds = state.timestampInMicroSeconds;
410
411 TransformStamped globalRobotPose;
412 globalRobotPose.header = header;
413 globalRobotPose.transform = armarx::fromIce(state.pose);
414
415 globalPosePrx->reportGlobalRobotPose(globalRobotPose);
416
417 // Velocity
418 updateCurrentVelocity(state.linearVelocity, state.angularVelocity);
419
420 if (platformControlMode != ePositionControl)
421 {
422 // The currentVelocity is in the global frame, we need to report the velocity in the platform local frame
423 Eigen::Vector2f localVelocity =
424 transformToLocalVelocity(currentRotation, currentVelocity.x, currentVelocity.y);
425 listenerPrx->reportPlatformVelocity(
426 localVelocity.x(), localVelocity.y(), currentRotationVelocity);
427 }
428}
429
432{
434
435 def->defineOptionalProperty<int>(
436 "IntervalMs", 100, "The time in milliseconds between two calls to the simulation method.");
437
438 //assures that the platform still gets some amount of velocity when near target
439 def->defineOptionalProperty<float>(
440 "LinearVelocityMin", 0.5, "Minimum Linear velocity of the platform (unit: m/sec).");
441 def->defineOptionalProperty<float>(
442 "LinearVelocityMax", 1.5, "Maximum Linear velocity of the platform (unit: m/sec).");
443 def->defineOptionalProperty<float>(
444 "LinearAccelerationMax", 0.9, "Maximum Linear Acceleration (unit: m/sec^2");
445 def->defineOptionalProperty<float>(
446 "AngularVelocityMax", 0.8, "Maximum Angular velocity of the platform (unit: rad/sec).");
447 def->defineOptionalProperty<float>(
448 "AngularAccelerationMax", 1.9, "Maximum Angular Acceleration (unit: rad/sec^2");
449 def->defineOptionalProperty<float>(
450 "PlatformOrientationOffset", 0, "Rotation offset of the platform (unit: rad).");
451 def->defineOptionalProperty<std::string>("RobotName", "Armar3", "Name of the Robot to use.");
452 def->defineOptionalProperty<std::string>(
453 "PlatformName", "Platform", "Name of the Platform node to use.");
454 def->defineOptionalProperty<std::string>(
455 "SimulatorProxyName", "Simulator", "Name of the simulator proxy to use.");
456
457 return def;
458}
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
#define M_PI
Definition MathTools.h:17
constexpr T c
Property< PropertyType > getProperty(const std::string &name)
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...
void setMaxVelocities(float linearVelocity, float angularVelocity, const Ice::Current &c=Ice::emptyCurrent) override
float clampf(float x, float min, float max)
void moveTo(Ice::Float targetPlatformPositionX, Ice::Float targetPlatformPositionY, Ice::Float targetPlatformRotation, Ice::Float positionalAccuracy, Ice::Float orientationalAccuracy, const Ice::Current &c=Ice::emptyCurrent) override
PeriodicTask< PlatformUnitDynamicSimulation >::pointer_type simulationTask
void stopPlatform(const Ice::Current &current) override
Eigen::Vector3f calculateLinearVelocity(Eigen::Vector3f distance, Eigen::Vector3f curV)
void reportState(SimulatedRobotState const &state, const Ice::Current &) override
void updateCurrentVelocity(const Vector3BasePtr &translationVel, const Vector3BasePtr &rotationVel)
PropertyDefinitionsPtr createPropertyDefinitions() override
float calculateAngularVelocity(float source, float target, float curV)
void move(float targetPlatformVelocityX, float targetPlatformVelocityY, float targetPlatformVelocityRotation, const Ice::Current &c=Ice::emptyCurrent) override
void moveRelative(float targetPlatformOffsetX, float targetPlatformOffsetY, float targetPlatformOffsetRotation, float positionalAccuracy, float orientationalAccuracy, const Ice::Current &c=Ice::emptyCurrent) override
PlatformUnitListenerPrx listenerPrx
PlatformUnitListener proxy for publishing state updates.
GlobalRobotPoseLocalizationListenerPrx globalPosePrx
PropertyDefinitionsPtr createPropertyDefinitions() override
The Vector3 class.
Definition Pose.h:113
#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_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
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
std::string const GlobalFrame
Variable of the global coordinate system.
Definition FramedPose.h:65
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceInternal::Handle< Vector3 > Vector3Ptr
Definition Pose.h:165
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
IceInternal::Handle< Quaternion > QuaternionPtr
Definition Pose.h:234
const LogSender::manipulator flush
Definition LogSender.h:251
void fromIce(const std::map< IceKeyT, IceValueT > &iceMap, boost::container::flat_map< CppKeyT, CppValueT > &cppMap)
bool isfinite(const std::vector< T, Ts... > &v)
Definition algorithm.h:366
double norm(const Point &a)
Definition point.hpp:102
double distance(const Point &a, const Point &b)
Definition point.hpp:95