KinematicSubUnit.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 RobotAPI::ArmarXObjects::KinematicSubUnit
17 * @author Raphael ( raphael dot grimm at kit dot edu )
18 * @date 2017
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22#include "KinematicSubUnit.h"
23
24#include <VirtualRobot/RobotNodeSet.h>
25
27
29#include <RobotAPI/interface/units/KinematicUnitInterface.h>
31
33{
34}
35
36void
38 std::string relRobFile,
40 std::map<std::string, ActuatorData>&& newDevs,
41 std::vector<std::set<std::string>> controlDeviceHardwareControlModeGrps,
42 std::set<std::string> controlDeviceHardwareControlModeGrpsMerged,
43 RobotUnit* newRobotUnit)
44{
45 std::lock_guard<std::mutex> guard{dataMutex};
46 ARMARX_CHECK_EXPRESSION(getState() == eManagedIceObjectCreated);
47
50 robot = rob;
51 robot->setUpdateCollisionModel(false);
52 robot->setUpdateVisualization(false);
53 robot->setThreadsafe(false);
54
55 ARMARX_CHECK_EXPRESSION(!robotUnit);
56 ARMARX_CHECK_EXPRESSION(newRobotUnit);
57 robotUnit = newRobotUnit;
58
60 ARMARX_CHECK_EXPRESSION(!relRobFile.empty());
61 relativeRobotFile = relRobFile;
62
63 devs = std::move(newDevs);
64 controlDeviceHardwareControlModeGroups = controlDeviceHardwareControlModeGrps;
65 controlDeviceHardwareControlModeGroupsMerged = controlDeviceHardwareControlModeGrpsMerged;
66
67 auto nodes = robot->getRobotNodes();
68 for (auto& node : nodes)
69 {
70 if (node->isJoint() && !devs.count(node->getName()))
71 {
72 sensorLessJoints.push_back(node);
73 }
74 }
75}
76
77void
80{
81 if (!getProxy())
82 {
83 //this unit is not initialized yet
84 ARMARX_IMPORTANT << deactivateSpam(1) << "not initialized yet";
85 return;
86 }
87 if (!listenerPrx)
88 {
89 ARMARX_IMPORTANT << deactivateSpam(1) << "listener is not set";
90 return;
91 }
92 std::lock_guard<std::mutex> guard{dataMutex};
93 bool ctrlModesAValueChanged = false;
94 bool angAValueChanged = false;
95 bool velAValueChanged = false;
96 bool accAValueChanged = false;
97 bool torAValueChanged = false;
98 bool motorCurrentAValueChanged = false;
99 bool motorTemperaturesAValueChanged = false;
100 bool statusesAvalueChanged = false;
101
102 long timestamp = sc.sensorValuesTimestamp.toMicroSeconds();
103 std::set<NJointControllerBase*> nJointCtrls{c.nJointControllers.begin(),
104 c.nJointControllers.end()};
105 std::vector<std::string> actuatorsWithoutSensor;
106 actuatorsWithoutSensor.reserve(devs.size());
107 for (const auto& name2actuatorData : devs)
108 {
109 const ActuatorData& actuatorData = name2actuatorData.second;
110 const auto& name = actuatorData.name;
111 //mode
112 {
113 ControlMode c = eUnknown;
114 if (actuatorData.ctrlPos && nJointCtrls.count(actuatorData.ctrlPos.get()))
115 {
116 c = ePositionControl;
117 }
118 if (actuatorData.ctrlVel && nJointCtrls.count(actuatorData.ctrlVel.get()))
119 {
120 ARMARX_CHECK_EXPRESSION(eUnknown == c);
121 c = eVelocityControl;
122 }
123 if (actuatorData.ctrlTor && nJointCtrls.count(actuatorData.ctrlTor.get()))
124 {
125 ARMARX_CHECK_EXPRESSION(eUnknown == c);
126 c = eTorqueControl;
127 }
128 ctrlModesAValueChanged =
129 ctrlModesAValueChanged || !ctrlModes.count(name) || (ctrlModes.at(name) != c);
130 ctrlModes[name] = c;
131 }
132 if (actuatorData.sensorDeviceIndex < sc.sensors.size())
133 {
134 const SensorValueBase* s = sc.sensors.at(actuatorData.sensorDeviceIndex).get();
135 UpdateNameValueMap<float,
136 SensorValue1DoFActuatorPosition,
137 &SensorValue1DoFActuatorPosition::position>(
138 ang, name, s, angAValueChanged);
139 UpdateNameValueMap<float,
140 SensorValue1DoFActuatorVelocity,
141 &SensorValue1DoFActuatorVelocity::velocity>(
142 vel, name, s, velAValueChanged);
143 UpdateNameValueMap<float,
144 SensorValue1DoFActuatorAcceleration,
145 &SensorValue1DoFActuatorAcceleration::acceleration>(
146 acc, name, s, accAValueChanged);
147 UpdateNameValueMap<float,
148 SensorValue1DoFActuatorTorque,
149 &SensorValue1DoFActuatorTorque::torque>(
150 tor, name, s, torAValueChanged);
151 UpdateNameValueMap<float,
152 SensorValue1DoFActuatorCurrent,
153 &SensorValue1DoFActuatorCurrent::motorCurrent>(
154 motorCurrents, name, s, motorCurrentAValueChanged);
155 UpdateNameValueMap<float,
156 SensorValue1DoFActuatorMotorTemperature,
157 &SensorValue1DoFActuatorMotorTemperature::motorTemperature>(
158 motorTemperatures, name, s, motorTemperaturesAValueChanged);
159 UpdateNameValueMap<JointStatus,
162 statuses, name, s, statusesAvalueChanged);
163 }
164 else
165 {
166 actuatorsWithoutSensor.emplace_back(name);
167 }
168 }
169 if (!actuatorsWithoutSensor.empty())
170 {
171 ARMARX_WARNING << deactivateSpam(5) << "these actuators have no sensor!:\n"
172 << actuatorsWithoutSensor;
173 }
174
175 // update the joint values of linked joints
176 robot->setJointValues(ang);
177 auto nodes = robot->getRobotNodes();
178 for (auto& node : nodes)
179 {
180 node->updatePose(false);
181 }
182 for (auto& node : sensorLessJoints)
183 {
184 ang[node->getName()] = node->getJointValue();
185 }
186
187
188 ARMARX_DEBUG << deactivateSpam(30) << "reporting updated data:\n"
189 << ctrlModes.size()
190 << " \tcontrol modes (updated = " << ctrlModesAValueChanged << ")\n"
191 << ang.size() << " \tjoint angles (updated = " << angAValueChanged << ")\n"
192 << vel.size() << " \tjoint velocities (updated = " << velAValueChanged << ")\n"
193 << acc.size() << " \tjoint accelerations (updated = " << accAValueChanged << ")\n"
194 << tor.size() << " \tjoint torques (updated = " << torAValueChanged << ")\n"
195 << motorCurrents.size()
196 << " \tmotor currents (updated = " << motorCurrentAValueChanged << ")\n"
197 << motorTemperatures.size()
198 << " \tmotor temperatures (updated = " << motorTemperaturesAValueChanged << ")\n";
199 auto prx = listenerPrx->ice_batchOneway();
200 prx->reportJointAngles(ang, timestamp, angAValueChanged);
201 prx->reportJointVelocities(vel, timestamp, velAValueChanged);
202 prx->reportJointTorques(tor, timestamp, torAValueChanged);
203 if (reportSkipper.checkFrequency("Meta")) // only report the following data with low frequency
204 {
205 prx->reportJointAccelerations(acc, timestamp, accAValueChanged);
206 if (!motorCurrents.empty())
207 {
208 prx->reportJointCurrents(motorCurrents, timestamp, motorCurrentAValueChanged);
209 }
210 if (!motorTemperatures.empty())
211 {
212 prx->reportJointMotorTemperatures(
213 motorTemperatures, timestamp, motorTemperaturesAValueChanged);
214 }
215 if (!statuses.empty())
216 {
217 prx->reportJointStatuses(statuses, timestamp, statusesAvalueChanged);
218 }
219 prx->reportControlModeChanged(ctrlModes, timestamp, ctrlModesAValueChanged);
220 }
221 prx->ice_flushBatchRequests();
222}
223
224void
225armarx::KinematicSubUnit::requestJoints(const Ice::StringSeq&, const Ice::Current&)
226{
227 ARMARX_INFO << "NYI: requestJoints";
228}
229
230void
231armarx::KinematicSubUnit::releaseJoints(const Ice::StringSeq&, const Ice::Current&)
232{
233 ARMARX_INFO << "NYI: releaseJoints";
234}
235
236void
237armarx::KinematicSubUnit::setJointAngles(const armarx::NameValueMap& angles, const Ice::Current&)
238{
239 std::lock_guard<std::mutex> guard{dataMutex};
240 for (const auto& n2v : angles)
241 {
242 if (devs.count(n2v.first))
243 {
244 if (devs.at(n2v.first).ctrlPos)
245 {
246 devs.at(n2v.first).ctrlPos->set(n2v.second);
247 }
248 }
249 }
250}
251
252void
253armarx::KinematicSubUnit::setJointVelocities(const armarx::NameValueMap& velocities,
254 const Ice::Current&)
255{
256 std::lock_guard<std::mutex> guard{dataMutex};
257 for (const auto& n2v : velocities)
258 {
259 if (devs.count(n2v.first))
260 {
261 if (devs.at(n2v.first).ctrlVel)
262 {
263 devs.at(n2v.first).ctrlVel->set(n2v.second);
264 }
265 }
266 }
267}
268
269void
270armarx::KinematicSubUnit::setJointTorques(const armarx::NameValueMap& torques, const Ice::Current&)
271{
272 std::lock_guard<std::mutex> guard{dataMutex};
273 for (const auto& n2v : torques)
274 {
275 if (devs.count(n2v.first))
276 {
277 if (devs.at(n2v.first).ctrlTor)
278 {
279 devs.at(n2v.first).ctrlTor->set(n2v.second);
280 }
281 }
282 }
283}
284
285void
286armarx::KinematicSubUnit::switchControlMode(const armarx::NameControlModeMap& ncm,
287 const Ice::Current&)
288{
289 std::map<std::string, NJointControllerBasePtr> toActivate;
290 {
291 std::lock_guard<std::mutex> guard{dataMutex};
292 for (const auto& n2c : ncm)
293 {
294 const std::string& name = n2c.first;
295 ControlMode mode = n2c.second;
296 if (!devs.count(name))
297 {
298 ARMARX_WARNING << "requested mode '"
300 << "' for nonexistent device '" << name
301 << "'. (ignoring this device)";
302 continue;
303 }
304 NJointKinematicUnitPassThroughControllerPtr ctrl =
305 NJointKinematicUnitPassThroughControllerPtr::dynamicCast(
306 devs.at(name).getController(mode));
307 if (!ctrl)
308 {
309 ARMARX_WARNING << "requested unsupported mode '"
310 << KinematicUnitHelper::ControlModeToString(mode) << "' for device '"
311 << name << "'. (ignoring this device)";
312 continue;
313 }
314 if (ctrl->isControllerActive())
315 {
316 continue;
317 }
318 ctrl->reset(); // reset immediately instead of preActivate() to avoid race condition
319 toActivate[name] = std::move(ctrl);
320 }
321 const auto printToActivate = ARMARX_STREAM_PRINTER
322 {
323 for (const auto& elem : toActivate)
324 {
325 out << " '" << elem.first << "' -> '" << elem.second->getInstanceName() << "'\n";
326 }
327 };
328 ARMARX_DEBUG << "switching control modes requests these NJointControllers (without "
329 "consideration of ControlDeviceHardwareControlModeGroups):\n"
330 << printToActivate;
331 for (const auto& n2NJointCtrl : toActivate)
332 {
333 const auto& name = n2NJointCtrl.first;
334 ARMARX_DEBUG << "checking group of '" << name << "'";
335 const NJointControllerBasePtr& nJointCtrl = n2NJointCtrl.second;
336 if (!controlDeviceHardwareControlModeGroupsMerged.count(name))
337 {
338 continue;
339 }
340 //is in a group! (find the correct group)
341 const std::set<std::string>* group = nullptr;
342 for (const auto& grp : controlDeviceHardwareControlModeGroups)
343 {
344 if (grp.count(name))
345 {
346 group = &grp;
347 break;
348 }
349 }
351 const auto jointCtrl = nJointCtrl->getControlDevicesUsedJointController().at(name);
352 const auto hwMode = jointCtrl->getHardwareControlMode();
353 //check against all other elems of the group
354 for (const auto& other : *group)
355 {
356 if (name == other)
357 {
358 continue;
359 }
360 if (!devs.count(other))
361 {
362 continue;
363 }
364 //this device may have a controller switch
365 if (toActivate.count(other))
366 {
367 const auto otherJointCtrl =
368 toActivate.at(other)->getControlDevicesUsedJointController().at(other);
369 const auto otherHwMode = otherJointCtrl->getHardwareControlMode();
370 if (otherHwMode != hwMode)
371 {
372 std::stringstream strstr;
373 strstr << "The hardware control mode for two control devices with "
374 "requested control mode changein the same group does not match!\n"
375 << "Device 1: '" << name << "' mode "
376 << "'" << jointCtrl->getControlMode() << "' hw mode '" << hwMode
377 << "'\n"
378 << "Device 2: '" << other << "' mode "
379 << "'" << otherJointCtrl->getControlMode() << "' hw mode '"
380 << otherHwMode << "'\n";
381 ARMARX_ERROR << strstr.str();
382 throw InvalidArgumentException{strstr.str()};
383 }
384 }
385 else
386 {
387 //get the current active
388 const auto otherNJointCtrl = devs.at(other).getActiveController();
389 const auto otherJointCtrl =
390 otherNJointCtrl
391 ? otherNJointCtrl->getControlDevicesUsedJointController().at(other)
392 : nullptr;
393 const auto otherHwMode =
394 otherJointCtrl ? otherJointCtrl->getHardwareControlMode() : "";
395 if (hwMode != otherHwMode)
396 {
397 toActivate[other] = std::move(devs.at(other).getController(ncm.at(name)));
398 ARMARX_CHECK_EXPRESSION(toActivate.at(other));
399 ARMARX_CHECK_EXPRESSION(toActivate.at(other)
400 ->getControlDevicesUsedJointController()
401 .at(other)
402 ->getHardwareControlMode() == hwMode);
403 ARMARX_VERBOSE << "activating '" << nJointCtrl->getInstanceName()
404 << "' caused activation of '"
405 << toActivate.at(name)->getInstanceName() << "'";
406 }
407 }
408 }
409 ARMARX_DEBUG << "checking group of '" << name << "'...done!";
410 }
411 ARMARX_DEBUG << "switching control modes requests these NJointControllers (with "
412 "consideration of ControlDeviceHardwareControlModeGroups):\n"
413 << printToActivate;
414 //now check if groups are satisfied
415 ARMARX_CHECK_EXPRESSION(robotUnit);
416 }
417 if (!toActivate.empty())
418 {
419 robotUnit->activateNJointControllers(getMapValues(toActivate));
420 }
421}
422
423void
424armarx::KinematicSubUnit::setJointAccelerations(const armarx::NameValueMap&, const Ice::Current&)
425{
426 ARMARX_INFO << "NYI: setJointAccelerations";
427}
428
429void
430armarx::KinematicSubUnit::setJointDecelerations(const armarx::NameValueMap&, const Ice::Current&)
431{
432 ARMARX_INFO << "NYI: setJointDecelerations";
433}
434
435armarx::NameControlModeMap
437{
438 std::lock_guard<std::mutex> guard{dataMutex};
439 return ctrlModes;
440}
441
442armarx::NameValueMap
444{
445 std::lock_guard<std::mutex> guard{dataMutex};
446 return ang;
447}
448
449armarx::NameValueMap
451{
452 std::lock_guard<std::mutex> guard{dataMutex};
453 return vel;
454}
455
456Ice::StringSeq
457armarx::KinematicSubUnit::getJoints(const Ice::Current& c) const
458{
459 std::lock_guard<std::mutex> guard{dataMutex};
460 return getMapKeys(ang);
461}
462
463armarx::DebugInfo
465{
466 std::lock_guard<std::mutex> guard{dataMutex};
467
468 armarx::DebugInfo debugInfo{.jointModes = ctrlModes,
469 .jointAngles = ang,
470 .jointVelocities = vel,
471 .jointAccelerations = acc,
472 .jointTorques = tor,
473 .jointCurrents = motorCurrents,
474 .jointMotorTemperatures = motorTemperatures,
475 .jointStatus = statuses};
476
477 return debugInfo;
478}
479
482{
483 switch (c)
484 {
485 case ePositionVelocityControl:
486 return ctrlPos;
487 case ePositionControl:
488 return ctrlPos;
489 case eVelocityControl:
490 return ctrlVel;
491 case eTorqueControl:
492 return ctrlTor;
493 default:
494 return nullptr;
495 }
496}
497
500{
501 if (ctrlPos->isControllerActive())
502 {
503 return ctrlPos;
504 }
505 if (ctrlVel->isControllerActive())
506 {
507 return ctrlVel;
508 }
509 if (ctrlTor->isControllerActive())
510 {
511 return ctrlTor;
512 }
513 return nullptr;
514}
#define float
Definition 16_Level.h:22
std::string timestamp()
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
#define ARMARX_STREAM_PRINTER
use this macro to write output code that is executed when printed and thus not executed if the debug ...
Definition Logging.h:310
constexpr T c
void switchControlMode(const NameControlModeMap &ncm, const Ice::Current &) override
void setJointAngles(const NameValueMap &angles, const Ice::Current &) override
void releaseJoints(const Ice::StringSeq &, const Ice::Current &) override
void setupData(std::string relRobFile, VirtualRobot::RobotPtr rob, std::map< std::string, ActuatorData > &&newDevs, std::vector< std::set< std::string > > controlDeviceHardwareControlModeGrps, std::set< std::string > controlDeviceHardwareControlModeGrpsMerged, RobotUnit *newRobotUnit)
void requestJoints(const Ice::StringSeq &, const Ice::Current &) override
void update(const SensorAndControl &sc, const JointAndNJointControllers &c) override
void setJointDecelerations(const NameValueMap &, const Ice::Current &) override
NameControlModeMap getControlModes(const Ice::Current &) override
DebugInfo getDebugInfo(const Ice::Current &c=Ice::emptyCurrent) const override
void setJointVelocities(const NameValueMap &velocities, const Ice::Current &) override
void setJointAccelerations(const NameValueMap &, const Ice::Current &) override
void setJointTorques(const NameValueMap &torques, const Ice::Current &) override
Ice::StringSeq getJoints(const Ice::Current &c) const override
NameValueMap getJointAngles(const Ice::Current &) const override
NameValueMap getJointVelocities(const Ice::Current &) const override
static std::string ControlModeToString(ControlMode controlMode)
VirtualRobot::RobotPtr robot
std::string relativeRobotFile
KinematicUnitListenerPrx listenerPrx
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
int getState() const
Retrieve current state of the ManagedIceObject.
The RobotUnit class manages a robot and its controllers.
Definition RobotUnit.h:192
DETAIL_SensorValueBase_DEFAULT_METHOD_IMPLEMENTATION armarx::JointStatus status
The SensorValueBase class.
#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_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#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::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
void getMapKeys(const MapType &map, OutputIteratorType it)
Definition algorithm.h:173
void getMapValues(const MapType &map, OutputIteratorType it)
Definition algorithm.h:194
SynchronousNJointControllerPtr NJointControllerPtr
detail::ControlThreadOutputBufferEntry SensorAndControl
Structure used by the RobotUnit to swap lists of Joint and NJoint controllers.
NJointControllerPtr getActiveController() const
NJointKinematicUnitPassThroughControllerPtr ctrlPos
NJointControllerPtr getController(ControlMode c) const
NJointKinematicUnitPassThroughControllerPtr ctrlTor
NJointKinematicUnitPassThroughControllerPtr ctrlVel
std::vector< PropagateConst< SensorValueBase * > > sensors