NJointController.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::NJointController
17 * @author Raphael Grimm ( 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
23#include <atomic>
24
27
28#include "../RobotUnit.h"
31
32namespace armarx
33{
39} // namespace armarx
40
42{
43
44 /**
45 * \brief This class allows minimal access to private members of \ref armarx::RobotUnitModule::Devices in a sane fashion for \ref armarx::NJointControllerBase.
46 * \warning !! DO NOT ADD ANYTHING IF YOU DO NOT KNOW WAHT YOU ARE DOING! IF YOU DO SOMETHING WRONG YOU WILL CAUSE UNDEFINED BEHAVIOUR !!
47 */
49 {
50 friend class ::armarx::NJointControllerBase;
51
52 static JointController*
53 GetJointController(Devices& d,
54 const std::string& deviceName,
55 const std::string& controlMode)
56 {
57 if (d.controlDevices.has(deviceName))
58 {
59 auto& dev = d.controlDevices.at(deviceName);
60 if (dev->hasJointController(controlMode))
61 {
62 ARMARX_CHECK_NOT_NULL(dev->getJointController(controlMode));
63 ARMARX_CHECK_NOT_NULL(dev->getJointController(controlMode)->getControlTarget());
64 return dev->getJointController(controlMode);
65 }
66 }
67 return nullptr;
68 }
69 };
70} // namespace armarx::RobotUnitModule
71
73
74namespace armarx
75{
76 const NJointControllerBasePtr NJointControllerBase::NullPtr{nullptr};
77
78 NJointControllerDescription
80 {
82 NJointControllerDescription d;
83 d.className = getClassName();
85 d.controller = NJointControllerInterfacePrx::uncheckedCast(getProxy(-1));
86 d.controlModeAssignment = controlDeviceControlModeMap;
87 d.instanceName = getInstanceName();
88 d.deletable = deletable;
89 d.internal = internal;
90 return d;
91 }
92
93 std::optional<std::vector<char>>
94 NJointControllerBase::isNotInConflictWith(const std::vector<char>& used) const
95 {
97 ARMARX_CHECK_EXPRESSION(used.size() == controlDeviceUsedBitmap.size());
98 auto result = used;
99 for (std::size_t i = 0; i < controlDeviceUsedBitmap.size(); ++i)
100 {
101 if (controlDeviceUsedBitmap.at(i))
102 {
103 if (used.at(i))
104 {
105 return std::nullopt;
106 }
107 result.at(i) = true;
108 }
109 }
110 return result;
111 }
112
113 NJointControllerStatus
115 {
117 NJointControllerStatus s;
118 s.active = isActive;
119 s.instanceName = getInstanceName();
120 s.requested = isRequested;
121 s.error = deactivatedBecauseOfError;
122 s.timestampUSec = std::chrono::duration_cast<std::chrono::microseconds>(
123 std::chrono::high_resolution_clock::now().time_since_epoch())
124 .count();
125 return s;
126 }
127
128 NJointControllerDescriptionWithStatus
130 {
131 NJointControllerDescriptionWithStatus ds;
132 ds.description = getControllerDescription();
133 ds.status = getControllerStatus();
134 return ds;
135 }
136
137 // RobotUnitInterfacePrx NJointControllerBase::getRobotUnit(const Ice::Current&) const
138 // {
139 // return RobotUnitInterfacePrx::uncheckedCast(robotUnit.getProxy(-1));
140 // }
141
142 void
144 {
145 robotUnit.activateNJointController(this);
146 }
147
148 void
150 {
151 robotUnit.deactivateNJointController(this);
152 }
153
154 void
156 {
157 robotUnit.deleteNJointController(this);
158 }
159
160 void
162 {
163 robotUnit.deactivateAndDeleteNJointController(this);
164 }
165
166 void
167 NJointControllerBase::publish(const SensorAndControl& sac,
168 const DebugDrawerInterfacePrx& draw,
169 const DebugObserverInterfacePrx& observer)
170 {
172 const bool active = isActive;
173 if (publishActive.exchange(active) != active)
174 {
175 if (active)
176 {
177 ARMARX_DEBUG << "activating publishing for " << getInstanceName();
178 try
179 {
180 onPublishActivation(draw, observer);
181 }
182 catch (std::exception& e)
183 {
184 ARMARX_WARNING << "onPublishActivation of '" << getInstanceName()
185 << "' threw an exception!\nWhat:\n"
186 << e.what();
187 }
188 catch (...)
189 {
190 ARMARX_WARNING << "onPublishActivation of '" << getInstanceName()
191 << "' threw an exception!";
192 }
193 }
194 else
195 {
196 ARMARX_DEBUG << "deactivating publishing for " << getInstanceName();
197 try
198 {
199 onPublishDeactivation(draw, observer);
200 }
201 catch (std::exception& e)
202 {
203 ARMARX_WARNING << "onPublishDeactivation of '" << getInstanceName()
204 << "' threw an exception!\nWhat:\n"
205 << e.what();
206 }
207 catch (...)
208 {
209 ARMARX_WARNING << "onPublishDeactivation of '" << getInstanceName()
210 << "' threw an exception!";
211 }
212 }
213 }
214 if (active)
215 {
216 try
217 {
218 onPublish(sac, draw, observer);
219 }
220 catch (std::exception& e)
221 {
222 ARMARX_WARNING << "onPublish of '" << getInstanceName()
223 << "' threw an exception!\nWhat:\n"
224 << e.what();
225 }
226 catch (...)
227 {
228 ARMARX_WARNING << "onPublish of '" << getInstanceName() << "' threw an exception!";
229 }
230 }
231 }
232
233 void
234 NJointControllerBase::deactivatePublish(const DebugDrawerInterfacePrx& draw,
235 const DebugObserverInterfacePrx& observer)
236 {
238 if (publishActive.exchange(false))
239 {
240 ARMARX_DEBUG << "forced deactivation of publishing for " << getInstanceName();
241 onPublishDeactivation(draw, observer);
242 }
243 }
244
245 void
246 NJointControllerBase::rtActivateController()
247 {
248 if (!isActive)
249 {
250 deactivatedBecauseOfError = false;
252 isActive = true;
253 errorState.store(false);
254 }
255 }
256
257 void
258 NJointControllerBase::rtDeactivateController()
259 {
260 if (isActive)
261 {
262 isActive = false;
264 }
265 }
266
267 void
268 NJointControllerBase::rtDeactivateControllerBecauseOfError()
269 {
270 deactivatedBecauseOfError = true;
271 rtDeactivateController();
272 }
273
275 armarx::NJointControllerBase::peekSensorDevice(const std::string& deviceName) const
276 {
278 << "The function '" << BOOST_CURRENT_FUNCTION
279 << "' must only be called during the construction of an NJointController.";
281 }
282
284 NJointControllerBase::peekControlDevice(const std::string& deviceName) const
285 {
287 << "The function '" << BOOST_CURRENT_FUNCTION
288 << "' must only be called during the construction of an NJointController.";
290 }
291
294 {
296 << "The function '" << BOOST_CURRENT_FUNCTION
297 << "' must only be called during the construction of an NJointController.";
298 ARMARX_CHECK_IS_NULL(rtRobot) << "useSynchronizedRtRobot was already called";
299 rtRobot = RobotUnitModule::RobotData::Instance().cloneRobot(updateCollisionModel);
300 rtRobotNodes = rtRobot->getRobotNodes();
301 return rtRobot;
302 }
303
304 void
310
311 void
317
318 void
324
325 void
327 {
330 // make sure the destructor of the handles does not throw an exception and triggers a termination of the process
331 ARMARX_DEBUG << "Deleting thread handles";
332 std::unique_lock lock(threadHandlesMutex);
333 for (auto& pair : threadHandles)
334 {
335 try
336 {
337
338 auto& name = pair.first;
339 auto& handle = pair.second;
340 if (!handle || !handle->isValid())
341 {
342 ARMARX_VERBOSE << "Thread Handle is NULL or invalid - skipping";
343 continue;
344 }
345 if (handle->isDetached())
346 {
347 continue;
348 }
349 std::future_status status;
350 do
351 {
352 status = handle->getFuture().wait_for(std::chrono::seconds(3));
353 if (status == std::future_status::timeout)
354 {
355 ARMARX_INFO << "Still waiting for " << name << " thread handle!";
356 }
357 else if (status == std::future_status::ready ||
358 status == std::future_status::deferred)
359 {
360 ARMARX_VERBOSE << "Joining " << name << " task";
361 handle->join();
362 handle.reset();
363 }
364 } while (status != std::future_status::ready);
365 }
366 catch (...)
367 {
369 }
370 }
371
372 threadHandles.clear();
373 }
374
381
382 const SensorValueBase*
383 NJointControllerBase::useSensorValue(const std::string& deviceName) const
384 {
387 << "The function '" << BOOST_CURRENT_FUNCTION
388 << "' must only be called during the construction of an NJointController.";
389 auto dev = peekSensorDevice(deviceName);
390 if (!dev)
391 {
392 ARMARX_DEBUG << "No sensor device for " << deviceName;
393 return nullptr;
394 }
395 return dev->getSensorValue();
396 }
397
399 robotUnit(RobotUnitModule::ModuleBase::Instance<::armarx::RobotUnit>()),
400 controlDeviceUsedBitmap(robotUnit.getNumberOfControlDevices(), 0)
401 {
402 controlDeviceUsedIndices.reserve(robotUnit.getNumberOfControlDevices());
403 }
404
408
410 NJointControllerBase::useControlTarget(const std::string& deviceName,
411 const std::string& controlMode)
412 {
415 << "The function '" << BOOST_CURRENT_FUNCTION
416 << "' must only be called during the construction of an NJointController.";
417 ARMARX_CHECK_EQUAL(controlDeviceControlModeMap.count(deviceName), 0)
418 << BOOST_CURRENT_FUNCTION
419 << ": Must not request two ControlTargets for the same device. (got = "
420 << controlDeviceControlModeMap.at(deviceName) << ", requested " + controlMode + ") "
421 << "(You can only have a ControlDevice in one ControlMode. "
422 << "To check all available ControlModes for this device, get the ControlDevice via "
423 "peekControlDevice(" +
424 deviceName + ") and querry it)";
425
426 //there is a device and a target was requested:
427 JointController* const jointCtrl =
428 RobotUnitModule::DevicesAttorneyForNJointController::GetJointController(
429 RobotUnitModule::Devices::Instance(), deviceName, controlMode);
430 if (!jointCtrl)
431 {
432 return nullptr;
433 }
434
435 //update meta data structured
436 const std::size_t devIndex = robotUnit.getControlDeviceIndex(deviceName);
437 controlDeviceUsedJointController[deviceName] = jointCtrl;
438
439 controlDeviceControlModeMap[deviceName] = controlMode;
440
441 ARMARX_CHECK_EQUAL(0, controlDeviceUsedBitmap.at(devIndex));
442 controlDeviceUsedBitmap.at(devIndex) = 1;
443 //we want this vector to be sorted
444 controlDeviceUsedIndices.insert(std::upper_bound(controlDeviceUsedIndices.begin(),
445 controlDeviceUsedIndices.end(),
446 devIndex),
447 devIndex);
448
449 return jointCtrl->getControlTarget();
450 }
451} // namespace armarx
static ApplicationPtr getInstance()
Retrieve shared pointer to the application object.
Brief description of class JointControlTargetBase.
The JointController class represents one joint in one control mode.
virtual ControlTargetBase * getControlTarget()=0
bool has(const KeyT &k) const
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
const SensorValueBase * useSensorValue(const std::string &sensorDeviceName) const
Get a const ptr to the given SensorDevice's SensorValue.
virtual void rtPostDeactivateController()
This function is called after the controller is deactivated.
virtual void rtPreActivateController()
This function is called before the controller is activated.
std::string getClassName(const Ice::Current &=Ice::emptyCurrent) const override=0
void deactivateController(const Ice::Current &=Ice::emptyCurrent) override
NJointControllerStatus getControllerStatus(const Ice::Current &=Ice::emptyCurrent) const final override
const VirtualRobot::RobotPtr & useSynchronizedRtRobot(bool updateCollisionModel=false)
Requests a VirtualRobot for use in rtRun *.
std::string getInstanceName(const Ice::Current &=Ice::emptyCurrent) const final override
std::optional< std::vector< char > > isNotInConflictWith(const NJointControllerBasePtr &other) const
void deleteController(const Ice::Current &=Ice::emptyCurrent) final override
virtual void onPublishActivation(const DebugDrawerInterfacePrx &, const DebugObserverInterfacePrx &)
ConstControlDevicePtr peekControlDevice(const std::string &deviceName) const
Get a const ptr to the given ControlDevice.
void activateController(const Ice::Current &=Ice::emptyCurrent) override
virtual void onPublishDeactivation(const DebugDrawerInterfacePrx &, const DebugObserverInterfacePrx &)
virtual void onPublish(const SensorAndControl &, const DebugDrawerInterfacePrx &, const DebugObserverInterfacePrx &)
ConstSensorDevicePtr peekSensorDevice(const std::string &deviceName) const
Get a const ptr to the given SensorDevice.
NJointControllerDescription getControllerDescription(const Ice::Current &=Ice::emptyCurrent) const final override
NJointControllerDescriptionWithStatus getControllerDescriptionWithStatus(const Ice::Current &=Ice::emptyCurrent) const final override
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...
std::map< std::string, std::shared_ptr< ThreadPool::Handle > > threadHandles
static const NJointControllerBasePtr NullPtr
void deactivateAndDeleteController(const Ice::Current &=Ice::emptyCurrent) final override
ThreadPoolPtr getThreadPool() const
This class allows minimal access to private members of Devices in a sane fashion for NJointController...
This Module manages sensor and control devices for a RobotUnit and only allows save and sane access.
static Devices & Instance()
Returns the singleton instance of this class.
ConstSensorDevicePtr getSensorDevice(const std::string &deviceName) const
TODO move to attorney for NJointControllerBase.
ConstControlDevicePtr getControlDevice(const std::string &deviceName) const
Returns the ControlDevice.
T * _modulePtr()
Returns this as ptr to the given type.
VirtualRobot::RobotPtr cloneRobot(bool updateCollisionModel=false) const
Returns a clone of the robot's model.
static RobotData & Instance()
Returns the singleton instance of this class.
The RobotUnit class manages a robot and its controllers.
Definition RobotUnit.h:192
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_CHECK_IS_NULL(ptr)
This macro evaluates whether ptr is null and if it turns out to be false it will throw an ExpressionE...
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#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_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
This file offers overloads of toIce() and fromIce() functions for STL container types.
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugObserverInterface > DebugObserverInterfacePrx
RobotUnit * getRobotUnit(RobotUnitModule::ControllerManagement *cmngr)
void handleExceptions()
std::shared_ptr< ThreadPool > ThreadPoolPtr
Definition Application.h:76
std::shared_ptr< const class ControlDevice > ConstControlDevicePtr
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugDrawerInterface > DebugDrawerInterfacePrx
detail::ControlThreadOutputBufferEntry SensorAndControl
std::shared_ptr< const class SensorDevice > ConstSensorDevicePtr
#define ARMARX_TRACE
Definition trace.h:77