NJointTrajectoryController.cpp
Go to the documentation of this file.
2
3#include <VirtualRobot/Nodes/RobotNode.h>
4#include <VirtualRobot/Robot.h>
5#include <VirtualRobot/TimeOptimalTrajectory/TimeOptimalTrajectory.h>
6
8#include <ArmarXCore/interface/observers/ObserverInterface.h>
9
13
14namespace armarx
15{
18
20 const NJointControllerConfigPtr& config,
21 const VirtualRobot::RobotPtr& robot)
22 {
23 cfg = NJointTrajectoryControllerConfigPtr::dynamicCast(config);
24 ARMARX_CHECK_EXPRESSION(cfg) << "Needed type: NJointTrajectoryControllerConfigPtr";
25
26 for (std::string jointName : cfg->jointNames)
27 {
28 ControlTargetBase* ct = useControlTarget(jointName, ControlModes::Velocity1DoF);
29 const SensorValueBase* sv = useSensorValue(jointName);
30 targets.push_back(ct->asA<ControlTarget1DoFActuatorVelocity>());
31 sensors.push_back(sv->asA<SensorValue1DoFActuatorPosition>());
32 }
33 if (cfg->jointNames.size() == 0)
34 {
35 ARMARX_ERROR << "cfg->jointNames.size() == 0";
36 }
37 for (auto& jointName : cfg->jointNames)
38 {
39 LimitlessState ls;
40 ls.enabled = false;
41 VirtualRobot::RobotNodePtr rn = robot->getRobotNode(jointName);
42 if (rn)
43 {
44 ls.enabled = rn->isLimitless();
45 ls.limitLo = rn->getJointLimitLo();
46 ls.limitHi = rn->getJointLimitHi();
47 }
48 ARMARX_DEBUG << "limitless status - " << jointName << ": " << rn->isLimitless();
49 limitlessStates.push_back(ls);
50 }
51 }
52
56
57 std::string
59 {
60 return "NJointTrajectoryController";
61 }
62
63 void
68
69 void
75
76 void
77 NJointTrajectoryController::rtRun(const IceUtil::Time& sensorValuesTimestamp,
78 const IceUtil::Time& timeSinceLastIteration)
79 {
80 if (rtGetControlStruct().trajectoryCtrl)
81 {
83 ARMARX_CHECK_EQUAL(sensors.size(), targets.size());
84 const auto& dimNames = contr.getTraj()->getDimensionNames();
85 for (size_t i = 0; i < sensors.size(); i++)
86 // for(auto& s : sensors)
87 {
88 ARMARX_CHECK_EQUAL(dimNames.at(i), cfg->jointNames.at(i));
89 currentPos(i) = sensors.at(i)->position;
90 }
91
92 auto& newVelocities =
93 contr.update(timeSinceLastIteration.toSecondsDouble() * direction, currentPos);
94 // StringVariantBaseMap positions;
95 // ARMARX_RT_LOGF_INFO("Current error %.3f", contr.getCurrentError()(1)).deactivateSpam(0.1);
96
97 // for (int i = 0; i < contr.getCurrentError().rows(); ++i)
98 // {
99 // positions[dimNames.at(i) + "-targetPosition"] = new Variant(contr.getPositions()(i));
100 // positions[dimNames.at(i) + "-currentPosition"] = new Variant(currentPos(i));
101 // }
102 // dbgObs->setDebugChannel("positions", positions);
103 currentTimestamp = contr.getCurrentTimestamp();
104 finished =
105 (currentTimestamp >= contr.getTraj()->rbegin()->getTimestamp() &&
106 direction == 1.0) ||
107 (currentTimestamp <= contr.getTraj()->begin()->getTimestamp() && direction == -1.0);
108
109 for (size_t i = 0; i < targets.size(); ++i)
110 {
111 {
112 targets.at(i)->velocity =
113 (cfg->isPreview || finished) ? 0.0f : newVelocities(i);
114 }
115 }
116
117 if (finished && looping)
118 {
119 direction *= -1.0;
120 }
121 }
122 }
123
124 void
125 NJointTrajectoryController::setTrajectory(const TrajectoryBasePtr& t, const Ice::Current&)
126 {
127 TIMING_START(TrajectoryOptimization);
129 TrajectoryPtr trajectory = TrajectoryPtr::dynamicCast(t);
131 size_t trajectoryDimensions = trajectory->dim();
132 ARMARX_CHECK_EQUAL(trajectoryDimensions, targets.size());
133 trajectory->setLimitless(limitlessStates);
134 // trajectory->gaussianFilter(0.3);
135 if (cfg->considerConstraints)
136 {
137 std::list<Eigen::VectorXd> pathPoints;
138 double timeStep = cfg->preSamplingStepMs / 1000.0;
139 Eigen::VectorXd maxVelocities =
140 Eigen::VectorXd::Constant(trajectoryDimensions, cfg->maxVelocity);
141 Eigen::VectorXd maxAccelerations =
142 Eigen::VectorXd::Constant(trajectoryDimensions, cfg->maxAcceleration);
144 for (const Trajectory::TrajData& element : *trajectory)
145 {
146 Eigen::VectorXd waypoint(trajectoryDimensions);
147 for (size_t i = 0; i < trajectoryDimensions; ++i)
148 {
149 waypoint(i) = element.getPosition(i);
150 }
151 pathPoints.emplace_back(waypoint);
152 }
153
154 VirtualRobot::Path p(pathPoints, cfg->maxDeviation);
155 VirtualRobot::TimeOptimalTrajectory timeOptimalTraj(
156 p, maxVelocities, maxAccelerations, timeStep);
157
158 TrajectoryPtr newTraj = new Trajectory();
159
160 Ice::DoubleSeq newTimestamps;
161 double duration = timeOptimalTraj.getDuration();
162 for (double t = 0.0; t < duration; t += timeStep)
163 {
164 newTimestamps.push_back(t);
165 }
166 newTimestamps.push_back(duration);
167
168 for (size_t d = 0; d < trajectoryDimensions; d++)
169 {
170 // Ice::DoubleSeq position;
171 // for (double t = 0.0; t < duration; t += timeStep)
172 // {
173 // position.push_back(timeOptimalTraj.getPosition(t)[d]);
174 // }
175 // position.push_back(timeOptimalTraj.getPosition(duration)[d]);
176 // newTraj->addDimension(position, newTimestamps, trajectory->getDimensionName(d));
177
178 Ice::DoubleSeq derivs;
179 for (double t = 0.0; t < duration; t += timeStep)
180 {
181 derivs.clear();
182 derivs.push_back(timeOptimalTraj.getPosition(t)[d]);
183 derivs.push_back(timeOptimalTraj.getVelocity(t)[d]);
184 newTraj->addDerivationsToDimension(d, t, derivs);
185 }
186 derivs.clear();
187 derivs.push_back(timeOptimalTraj.getPosition(duration)[d]);
188 derivs.push_back(timeOptimalTraj.getVelocity(duration)[d]);
189 newTraj->addDerivationsToDimension(d, duration, derivs);
190 }
191 newTraj->setDimensionNames(trajectory->getDimensionNames());
192 newTraj->setLimitless(limitlessStates);
194 TIMING_END(TrajectoryOptimization);
195 ARMARX_INFO << "Trajectory duration: " << newTraj->getTimeLength();
196 ARMARX_INFO << VAROUT(newTraj->output());
197 trajectory = newTraj;
198 }
199
200 trajEndTime = *trajectory->getTimestamps().rbegin() - *trajectory->getTimestamps().begin();
201 currentPos.resize(trajectory->getDimensionNames().size());
202
203 startTimestamp = *trajectory->getTimestamps().begin();
204 endTimestamp = *trajectory->getTimestamps().rbegin();
205 if (plotter)
206 {
207 StringFloatSeqDict posData;
208 StringFloatSeqDict velData;
209 for (size_t d = 0; d < trajectory->dim(); ++d)
210 {
211 auto positions = trajectory->getDimensionData(d, 0);
212 posData[trajectory->getDimensionName(d)] =
213 Ice::FloatSeq(positions.begin(), positions.end());
214 auto velocities = trajectory->getDimensionData(d, 1);
215 velData[trajectory->getDimensionName(d)] =
216 Ice::FloatSeq(velocities.begin(), velocities.end());
217 }
218 auto timestampsDouble = trajectory->getTimestamps();
219 Ice::FloatSeq timestamps(timestampsDouble.begin(), timestampsDouble.end());
220 plotter->addPlotWithTimestampVector("Positions", timestamps, posData);
221 plotter->addPlotWithTimestampVector("Velocities", timestamps, velData);
222 }
223 else
224 {
225 ARMARX_WARNING << "Plotter proxy is NULL";
226 }
227
228
230 ARMARX_INFO << VAROUT(cfg->PID_p) << VAROUT(cfg->PID_i) << VAROUT(cfg->PID_d);
231
232 trajectoryCtrl.reset(
233 new TrajectoryController(trajectory, cfg->PID_p, cfg->PID_i, cfg->PID_d, false));
234 getWriterControlStruct().trajectoryCtrl = trajectoryCtrl;
236 }
237
238 bool
240 {
241 return finished;
242 }
243
244 double
246 {
247 return currentTimestamp;
248 }
249
250 float
252 {
253 return math::MathUtils::ILerp(startTimestamp, endTimestamp, currentTimestamp);
254 }
255
256 double
258 {
260 if (trajectoryCtrl)
261 {
262 return trajectoryCtrl->getCurrentTimestamp();
263 }
264 else
265 {
266 return 0.0;
267 }
268 }
269
270 void
272 {
273 this->looping = looping;
274 }
275
276 double
278 {
279 return trajEndTime;
280 }
281
284 {
286 if (trajectoryCtrl)
287 {
288 return TrajectoryPtr::dynamicCast(trajectoryCtrl->getTraj()->clone());
289 }
290 else
291 {
292 return new Trajectory();
293 }
294 }
295
296 void
298 {
299 startTime = IceUtil::Time();
300 }
301
302 void
304 {
305 for (auto& target : targets)
306 {
307 target->velocity = 0.0f;
308 }
309 }
310
311} // namespace armarx
#define VAROUT(x)
Brief description of class JointControlTargetBase.
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.
const SensorValueBase * useSensorValue(const std::string &sensorDeviceName) const
Get a const ptr to the given SensorDevice's SensorValue.
ControlTargetBase * useControlTarget(const std::string &deviceName, const std::string &controlMode)
Declares to calculate the ControlTarget for the given ControlDevice in the given ControlMode when rtR...
NJointTrajectoryController(RobotUnit *prov, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &)
bool isFinished(const Ice::Current &) override
double getCurrentTimestamp(const Ice::Current &) override
void rtPostDeactivateController() override
This function is called after the controller is deactivated.
void rtRun(const IceUtil::Time &sensorValuesTimestamp, const IceUtil::Time &timeSinceLastIteration) override
TODO make protected and use attorneys.
float getCurrentProgressFraction(const Ice::Current &) override
void setTrajectory(const TrajectoryBasePtr &t, const Ice::Current &) override
std::string getClassName(const Ice::Current &) const override
void rtPreActivateController() override
This function is called before the controller is activated.
The RobotUnit class manages a robot and its controllers.
Definition RobotUnit.h:192
The SensorValueBase class.
const T * asA() const
Subcontroller which handles all program interaction with the modle, communicates with other controlle...
static void UnfoldLimitlessJointPositions(TrajectoryPtr traj)
const TrajectoryPtr & getTraj() const
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
static float ILerp(float a, float b, float f)
Definition MathUtils.h:197
#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_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_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 TIMING_START(name)
Helper macro to do timing tests.
Definition TimeUtil.h:289
#define TIMING_END(name)
Prints duration.
Definition TimeUtil.h:306
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceInternal::Handle< Trajectory > TrajectoryPtr
Definition Trajectory.h:52
NJointControllerRegistration< NJointTrajectoryController > registrationControllerNJointTrajectoryController("NJointTrajectoryController")