NJointCartesianVelocityController.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2017, 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 ArmarX
19 * @author Mirko Waechter( mirko.waechter at kit dot edu)
20 * @date 2017
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24
26
27#include <VirtualRobot/IK/DifferentialIK.h>
28#include <VirtualRobot/Nodes/RobotNode.h>
29#include <VirtualRobot/Robot.h>
30#include <VirtualRobot/RobotNodeSet.h>
31
35
36#define DEFAULT_TCP_STRING "default TCP"
37
38namespace armarx
39{
40
41 NJointControllerRegistration<NJointCartesianVelocityController>
43 "NJointCartesianVelocityController");
44
45 std::string
47 {
48 return "NJointCartesianVelocityController";
49 }
50
52 RobotUnit* robotUnit,
53 const NJointCartesianVelocityControllerConfigPtr& config,
55 {
57 ARMARX_CHECK_EXPRESSION(!config->nodeSetName.empty());
58 VirtualRobot::RobotNodeSetPtr rns = rtGetRobot()->getRobotNodeSet(config->nodeSetName);
59 ARMARX_CHECK_EXPRESSION(rns) << config->nodeSetName;
60 for (size_t i = 0; i < rns->getSize(); ++i)
61 {
62 std::string jointName = rns->getNode(i)->getName();
63 ControlTargetBase* ct = useControlTarget(jointName, ControlModes::Velocity1DoF);
64 const SensorValueBase* sv = useSensorValue(jointName);
65 targets.push_back(ct->asA<ControlTarget1DoFActuatorVelocity>());
66
67 const SensorValue1DoFActuatorTorque* torqueSensor =
68 sv->asA<SensorValue1DoFActuatorTorque>();
69 const SensorValue1DoFGravityTorque* gravityTorqueSensor =
70 sv->asA<SensorValue1DoFGravityTorque>();
71 if (!torqueSensor)
72 {
73 ARMARX_WARNING << "No Torque sensor available for " << jointName;
74 }
75 if (!gravityTorqueSensor)
76 {
77 ARMARX_WARNING << "No Gravity Torque sensor available for " << jointName;
78 }
79 torqueSensors.push_back(torqueSensor);
80 gravityTorqueSensors.push_back(gravityTorqueSensor);
81 };
82
83 VirtualRobot::RobotNodePtr tcp =
84 (config->tcpName.empty() || config->tcpName == DEFAULT_TCP_STRING)
85 ? rns->getTCP()
86 : rtGetRobot()->getRobotNode(config->tcpName);
87 ARMARX_CHECK_EXPRESSION(tcp) << config->tcpName;
88 tcpController.reset(new CartesianVelocityController(rns, tcp));
89
90 nodeSetName = config->nodeSetName;
91
92 torquePIDs.resize(tcpController->rns->getSize(), SimplePID());
93
95 initData.nullspaceJointVelocities.resize(tcpController->rns->getSize(), 0);
96 initData.torqueKp.resize(tcpController->rns->getSize(), 0);
97 initData.torqueKd.resize(tcpController->rns->getSize(), 0);
98 initData.mode = ModeFromIce(config->mode);
99 reinitTripleBuffer(initData);
100 }
101
102 void
106
107 void
108 NJointCartesianVelocityController::rtRun(const IceUtil::Time& sensorValuesTimestamp,
109 const IceUtil::Time& timeSinceLastIteration)
110 {
111 auto mode = rtGetControlStruct().mode;
112
113 Eigen::VectorXf x;
114 if (mode == VirtualRobot::IKSolver::All)
115 {
116 x.resize(6);
120 }
121 else if (mode == VirtualRobot::IKSolver::Position)
122 {
123 x.resize(3);
125 }
126 else if (mode == VirtualRobot::IKSolver::Orientation)
127 {
128 x.resize(3);
131 }
132 else
133 {
134 // No mode has been set
135 return;
136 }
137
138 Eigen::VectorXf jnv = Eigen::VectorXf::Zero(tcpController->rns->getSize());
139 float jointLimitAvoidanceKp = rtGetControlStruct().avoidJointLimitsKp;
140 if (jointLimitAvoidanceKp > 0)
141 {
142 jnv += jointLimitAvoidanceKp * tcpController->calculateJointLimitAvoidance();
143 }
144 for (size_t i = 0; i < tcpController->rns->getSize(); i++)
145 {
147 if (torqueSensors.at(i) && gravityTorqueSensors.at(i) &&
148 rtGetControlStruct().torqueKp.at(i) != 0)
149 {
150 torquePIDs.at(i).Kp = rtGetControlStruct().torqueKp.at(i);
151 torquePIDs.at(i).Kd = rtGetControlStruct().torqueKd.at(i);
152 jnv(i) += torquePIDs.at(i).update(timeSinceLastIteration.toSecondsDouble(),
153 torqueSensors.at(i)->torque -
154 gravityTorqueSensors.at(i)->gravityTorque);
155 //jnv(i) += rtGetControlStruct().torqueKp.at(i) * (torqueSensors.at(i)->torque - gravityTorqueSensors.at(i)->gravityTorque);
156 }
157 else
158 {
159 torquePIDs.at(i).lastError = 0;
160 }
161 }
162
163 Eigen::VectorXf jointTargetVelocities = tcpController->calculate(x, jnv, mode);
164 for (size_t i = 0; i < targets.size(); ++i)
165 {
166 targets.at(i)->velocity = jointTargetVelocities(i);
167 }
168 }
169
170 ::armarx::WidgetDescription::WidgetSeq
172 {
173 using namespace armarx::WidgetDescription;
174 ::armarx::WidgetDescription::WidgetSeq widgets;
175 auto addSlider = [&](const std::string& label, float limit)
176 {
177 widgets.emplace_back(new Label(false, label));
178 {
179 FloatSliderPtr c_x = new FloatSlider;
180 c_x->name = label;
181 c_x->min = -limit;
182 c_x->defaultValue = 0.0f;
183 c_x->max = limit;
184 widgets.emplace_back(c_x);
185 }
186 };
187
188 addSlider("x", 100);
189 addSlider("y", 100);
190 addSlider("z", 100);
191 addSlider("roll", 0.5);
192 addSlider("pitch", 0.5);
193 addSlider("yaw", 0.5);
194 addSlider("avoidJointLimitsKp", 1);
195 return widgets;
196 }
197
198 WidgetDescription::HBoxLayoutPtr
200 float max,
201 float defaultValue) const
202 {
203 using namespace armarx::WidgetDescription;
204 HBoxLayoutPtr layout = new HBoxLayout;
205 auto addSlider = [&](const std::string& label)
206 {
207 layout->children.emplace_back(new Label(false, label));
208 FloatSliderPtr floatSlider = new FloatSlider;
209 floatSlider->name = label;
210 floatSlider->min = min;
211 floatSlider->defaultValue = defaultValue;
212 floatSlider->max = max;
213 layout->children.emplace_back(floatSlider);
214 };
215
216 for (const VirtualRobot::RobotNodePtr& rn : tcpController->rns->getAllRobotNodes())
217 {
218 addSlider(rn->getName());
219 }
220
221 return layout;
222 }
223
226 const VirtualRobot::RobotPtr& robot,
227 const std::map<std::string, ConstControlDevicePtr>& controlDevices,
228 const std::map<std::string, ConstSensorDevicePtr>&)
229 {
230 using namespace armarx::WidgetDescription;
231 HBoxLayoutPtr layout = new HBoxLayout;
232
233 LabelPtr label = new Label;
234 label->text = "nodeset name";
235 layout->children.emplace_back(label);
236 StringComboBoxPtr box = new StringComboBox;
237 box->defaultIndex = 0;
238
239 box->options = robot->getRobotNodeSetNames();
240 box->name = "nodeSetName";
241 layout->children.emplace_back(box);
242
243 LabelPtr labelTCP = new Label;
244 labelTCP->text = "tcp name";
245 layout->children.emplace_back(labelTCP);
246 StringComboBoxPtr boxTCP = new StringComboBox;
247 boxTCP->defaultIndex = 0;
248
249 boxTCP->options = robot->getRobotNodeNames();
250 boxTCP->options.insert(boxTCP->options.begin(), DEFAULT_TCP_STRING);
251 boxTCP->name = "tcpName";
252 layout->children.emplace_back(boxTCP);
253
254 LabelPtr labelMode = new Label;
255 labelMode->text = "mode";
256 layout->children.emplace_back(labelMode);
257 StringComboBoxPtr boxMode = new StringComboBox;
258 boxMode->defaultIndex = 0;
259
260 boxMode->options = {"Position", "Orientation", "Both"};
261 boxMode->name = "mode";
262 layout->children.emplace_back(boxMode);
263
264
265 // auto sliders = createSliders();
266 // layout->children.insert(layout->children.end(),
267 // sliders.begin(),
268 // sliders.end());
269 layout->children.emplace_back(new HSpacer);
270 return layout;
271 }
272
273 NJointCartesianVelocityControllerConfigPtr
275 const StringVariantBaseMap& values)
276 {
277 return new NJointCartesianVelocityControllerConfig(
278 values.at("nodeSetName")->getString(),
279 values.at("tcpName")->getString(),
280 IceModeFromString(values.at("mode")->getString()));
281 }
282
283 VirtualRobot::IKSolver::CartesianSelection
285 {
286 //ARMARX_IMPORTANT_S << "the mode is " << mode;
287 if (mode == "Position")
288 {
289 return VirtualRobot::IKSolver::CartesianSelection::Position;
290 }
291 if (mode == "Orientation")
292 {
293 return VirtualRobot::IKSolver::CartesianSelection::Orientation;
294 }
295 if (mode == "Both")
296 {
297 return VirtualRobot::IKSolver::CartesianSelection::All;
298 }
299 ARMARX_ERROR_S << "invalid mode " << mode;
300 return (VirtualRobot::IKSolver::CartesianSelection)0;
301 }
302
303 NJointCartesianVelocityControllerMode::CartesianSelection
305 {
306 if (mode == "Position")
307 {
308 return NJointCartesianVelocityControllerMode::CartesianSelection::ePosition;
309 }
310 if (mode == "Orientation")
311 {
312 return NJointCartesianVelocityControllerMode::CartesianSelection::eOrientation;
313 }
314 if (mode == "Both")
315 {
316 return NJointCartesianVelocityControllerMode::CartesianSelection::eAll;
317 }
318 ARMARX_ERROR_S << "invalid mode " << mode;
319 return (NJointCartesianVelocityControllerMode::CartesianSelection)0;
320 }
321
322 VirtualRobot::IKSolver::CartesianSelection
324 const NJointCartesianVelocityControllerMode::CartesianSelection mode)
325 {
326 if (mode == NJointCartesianVelocityControllerMode::CartesianSelection::ePosition)
327 {
328 return VirtualRobot::IKSolver::CartesianSelection::Position;
329 }
330 if (mode == NJointCartesianVelocityControllerMode::CartesianSelection::eOrientation)
331 {
332 return VirtualRobot::IKSolver::CartesianSelection::Orientation;
333 }
334 if (mode == NJointCartesianVelocityControllerMode::CartesianSelection::eAll)
335 {
336 return VirtualRobot::IKSolver::CartesianSelection::All;
337 }
338 ARMARX_ERROR_S << "invalid mode " << mode;
339 return (VirtualRobot::IKSolver::CartesianSelection)0;
340 }
341
342 void
344 float xVel,
345 float yVel,
346 float zVel,
347 float rollVel,
348 float pitchVel,
349 float yawVel,
350 VirtualRobot::IKSolver::CartesianSelection mode)
351 {
357 getWriterControlStruct().pitchVel = pitchVel;
361 }
362
363 void
370
371 std::string
373 {
374 return nodeSetName;
375 }
376
377 void
381
384 {
385 using namespace armarx::WidgetDescription;
386 HBoxLayoutPtr layout = new HBoxLayout;
387 auto sliders = createSliders();
388 layout->children.insert(layout->children.end(), sliders.begin(), sliders.end());
389
390 return {{"ControllerTarget", layout},
391 {"TorqueKp", createJointSlidersLayout(-1, 1, 0)},
392 {"TorqueKd", createJointSlidersLayout(-1, 1, 0)},
393 {"NullspaceJointVelocities", createJointSlidersLayout(-1, 1, 0)}};
394 }
395
396 void
398 const StringVariantBaseMap& valueMap,
399 const Ice::Current&)
400 {
401 if (name == "ControllerTarget")
402 {
404 getWriterControlStruct().xVel = valueMap.at("x")->getFloat();
405 getWriterControlStruct().yVel = valueMap.at("y")->getFloat();
406 getWriterControlStruct().zVel = valueMap.at("z")->getFloat();
407 getWriterControlStruct().rollVel = valueMap.at("roll")->getFloat();
408 getWriterControlStruct().pitchVel = valueMap.at("pitch")->getFloat();
409 getWriterControlStruct().yawVel = valueMap.at("yaw")->getFloat();
411 valueMap.at("avoidJointLimitsKp")->getFloat();
413 }
414 else if (name == "TorqueKp")
415 {
417 for (size_t i = 0; i < tcpController->rns->getSize(); i++)
418 {
420 valueMap.at(tcpController->rns->getNode(i)->getName())->getFloat();
421 }
423 }
424 else if (name == "TorqueKd")
425 {
427 for (size_t i = 0; i < tcpController->rns->getSize(); i++)
428 {
430 valueMap.at(tcpController->rns->getNode(i)->getName())->getFloat();
431 }
433 }
434 else if (name == "NullspaceJointVelocities")
435 {
437 for (size_t i = 0; i < tcpController->rns->getSize(); i++)
438 {
440 valueMap.at(tcpController->rns->getNode(i)->getName())->getFloat();
441 }
443 }
444 else
445 {
446 ARMARX_WARNING << "Unknown function name called: " << name;
447 }
448 }
449
450 float
451 SimplePID::update(float dt, float error)
452 {
453 float derivative = (error - lastError) / dt;
454 float retVal = Kp * error + Kd * derivative;
455 lastError = error;
456 return retVal;
457 }
458
459} // namespace armarx
460
461void
463 float x,
464 float y,
465 float z,
466 float roll,
467 float pitch,
468 float yaw,
469 float avoidJointLimitsKp,
470 NJointCartesianVelocityControllerMode::CartesianSelection mode,
471 const Ice::Current&)
472{
480 getWriterControlStruct().avoidJointLimitsKp = avoidJointLimitsKp;
483}
484
485void
486armarx::NJointCartesianVelocityController::setTorqueKp(const StringFloatDictionary& torqueKp,
487 const Ice::Current&)
488{
490 for (size_t i = 0; i < tcpController->rns->getSize(); i++)
491 {
492 getWriterControlStruct().torqueKp.at(i) =
493 torqueKp.at(tcpController->rns->getNode(i)->getName());
494 }
496}
497
498void
500 const StringFloatDictionary& nullspaceJointVelocities,
501 const Ice::Current&)
502{
504 for (size_t i = 0; i < tcpController->rns->getSize(); i++)
505 {
506 getWriterControlStruct().nullspaceJointVelocities.at(i) =
507 nullspaceJointVelocities.at(tcpController->rns->getNode(i)->getName());
508 }
510}
int Label(int n[], int size, int *curLabel, MiscLib::Vector< std::pair< int, size_t > > *labels)
Definition Bitmap.cpp:801
constexpr T dt
Brief description of class JointControlTargetBase.
void setTorqueKp(const StringFloatDictionary &torqueKp, const Ice::Current &) override
static NJointCartesianVelocityControllerMode::CartesianSelection IceModeFromString(const std::string mode)
static WidgetDescription::WidgetPtr GenerateConfigDescription(const VirtualRobot::RobotPtr &, const std::map< std::string, ConstControlDevicePtr > &, const std::map< std::string, ConstSensorDevicePtr > &)
void setNullspaceJointVelocities(const StringFloatDictionary &nullspaceJointVelocities, const Ice::Current &) override
WidgetDescription::StringWidgetDictionary getFunctionDescriptions(const Ice::Current &) const override
NJointCartesianVelocityController(RobotUnit *prov, const NJointCartesianVelocityControllerConfigPtr &config, const VirtualRobot::RobotPtr &)
WidgetDescription::HBoxLayoutPtr createJointSlidersLayout(float min, float max, float defaultValue) const
static NJointCartesianVelocityControllerConfigPtr GenerateConfigFromVariants(const StringVariantBaseMap &values)
static VirtualRobot::IKSolver::CartesianSelection ModeFromString(const std::string mode)
void setControllerTarget(float x, float y, float z, float roll, float pitch, float yaw, float avoidJointLimitsKp, NJointCartesianVelocityControllerMode::CartesianSelection mode, const Ice::Current &) override
::armarx::WidgetDescription::WidgetSeq createSliders()
static VirtualRobot::IKSolver::CartesianSelection ModeFromIce(const NJointCartesianVelocityControllerMode::CartesianSelection mode)
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.
void setVelocities(float xVel, float yVel, float zVel, float rollVel, float pitchVel, float yawVel, VirtualRobot::IKSolver::CartesianSelection mode)
std::string getClassName(const Ice::Current &) const override
void callDescribedFunction(const std::string &name, const StringVariantBaseMap &valueMap, const Ice::Current &) override
void rtPreActivateController() override
This function is called before the controller is activated.
const SensorValueBase * useSensorValue(const std::string &sensorDeviceName) const
Get a const ptr to the given SensorDevice's SensorValue.
const VirtualRobot::RobotPtr & useSynchronizedRtRobot(bool updateCollisionModel=false)
Requests a VirtualRobot for use in rtRun *.
const VirtualRobot::RobotPtr & rtGetRobot()
TODO make protected and use attorneys.
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...
The RobotUnit class manages a robot and its controllers.
Definition RobotUnit.h:192
The SensorValueBase class.
const T * asA() const
float update(float dt, float error)
#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_ERROR_S
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:216
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
::IceInternal::Handle<::armarx::WidgetDescription::Widget > WidgetPtr
::std::map<::std::string, ::armarx::WidgetDescription::WidgetPtr > StringWidgetDictionary
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::map< std::string, VariantBasePtr > StringVariantBaseMap
std::vector< T > max(const std::vector< T > &v1, const std::vector< T > &v2)
std::vector< T > min(const std::vector< T > &v1, const std::vector< T > &v2)
NJointControllerRegistration< NJointCartesianVelocityController > registrationControllerNJointCartesianVelocityController("NJointCartesianVelocityController")