RobotUnitModuleControlThreadDataBuffer.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::RobotUnit
17 * @author Raphael Grimm ( raphael dot grimm at kit dot edu )
18 * @date 2018
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
24
25#include <VirtualRobot/Robot.h>
26
28
31
33{
34 /**
35 * \brief This class allows minimal access to private members of \ref Devices in a sane fashion for \ref ControlThreadDataBuffer.
36 * \warning !! DO NOT ADD ANYTHING IF YOU DO NOT KNOW WAHT YOU ARE DOING! IF YOU DO SOMETHING WRONG YOU WILL CAUSE UNDEFINED BEHAVIOUR !!
37 */
39 {
41
42 static std::vector<JointController*>
43 GetStopMovementJointControllers(ControlThreadDataBuffer* p)
44 {
45 return p->_module<Devices>().getStopMovementJointControllers();
46 }
47 };
48
49 /**
50 * \brief This class allows minimal access to private members of \ref ControllerManagement in a sane fashion for \ref ControlThreadDataBuffer.
51 * \warning !! DO NOT ADD ANYTHING IF YOU DO NOT KNOW WAHT YOU ARE DOING! IF YOU DO SOMETHING WRONG YOU WILL CAUSE UNDEFINED BEHAVIOUR !!
52 */
54 {
56
57 static void
58 UpdateNJointControllerRequestedState(ControlThreadDataBuffer* p,
59 const std::set<NJointControllerBasePtr>& request)
60 {
61 p->_module<ControllerManagement>().updateNJointControllerRequestedState(request);
62 }
63 };
64} // namespace armarx::RobotUnitModule
65
67{
68 JointAndNJointControllers
70 {
71 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
72 throwIfDevicesNotReady(__FUNCTION__);
73 std::lock_guard<std::recursive_mutex> guard{controllersActivatedMutex};
74 return controllersActivated.getReadBuffer();
75 }
76
77 std::vector<JointController*>
79 {
80 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
81 throwIfDevicesNotReady(__FUNCTION__);
82 std::lock_guard<std::recursive_mutex> guard{controllersActivatedMutex};
83 return controllersActivated.getReadBuffer().jointControllers;
84 }
85
86 std::vector<NJointControllerBase*>
88 {
89 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
90 throwIfDevicesNotReady(__FUNCTION__);
91 std::lock_guard<std::recursive_mutex> guard{controllersActivatedMutex};
92 return controllersActivated.getReadBuffer().nJointControllers;
93 }
94
95 bool
97 {
98 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
99 throwIfDevicesNotReady(__FUNCTION__);
100 std::lock_guard<std::recursive_mutex> guard{controllersActivatedMutex};
101 return controllersActivated.updateReadBuffer();
102 }
103
106 {
107 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
108 throwIfDevicesNotReady(__FUNCTION__);
109 std::lock_guard<std::recursive_mutex> guard{controllersRequestedMutex};
110 return controllersRequested.getWriteBuffer();
111 }
112
113 std::vector<JointController*>
115 {
116 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
117 throwIfDevicesNotReady(__FUNCTION__);
118 std::lock_guard<std::recursive_mutex> guard{controllersRequestedMutex};
119 return controllersRequested.getWriteBuffer().jointControllers;
120 }
121
122 std::vector<NJointControllerBase*>
124 {
125 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
126 throwIfDevicesNotReady(__FUNCTION__);
127 std::lock_guard<std::recursive_mutex> guard{controllersRequestedMutex};
128 return controllersRequested.getWriteBuffer().nJointControllers;
129 }
130
131 bool
133 {
134 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
135 throwIfDevicesNotReady(__FUNCTION__);
136 return controlThreadOutputBuffer.updateReadBuffer();
137 }
138
139 const SensorAndControl&
141 {
142 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
143 throwIfDevicesNotReady(__FUNCTION__);
144 return controlThreadOutputBuffer.getReadBuffer();
145 }
146
147 void
148 ControlThreadDataBuffer::writeRequestedControllers(JointAndNJointControllers&& setOfControllers)
149 {
150 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
151 throwIfDevicesNotReady(__FUNCTION__);
152 //check NJoint
153 const auto& nJointCtrls = setOfControllers.nJointControllers;
154 std::set<NJointControllerBasePtr> nJointSet{nJointCtrls.begin(), nJointCtrls.end()};
155 nJointSet.erase(nullptr);
156 //# NJoint
157 const std::size_t nNJointCtrls =
158 std::count_if(nJointCtrls.begin(),
159 nJointCtrls.end(),
160 [](const NJointControllerBasePtr& p) { return p; });
161
162 ARMARX_CHECK_EXPRESSION(nNJointCtrls == nJointSet.size());
163 ARMARX_CHECK_EXPRESSION(nJointCtrls.size() ==
164 _module<Devices>().getNumberOfControlDevices());
165 //first nNJointCtrls not null
166 ARMARX_CHECK_EXPRESSION(std::all_of(nJointCtrls.begin(),
167 nJointCtrls.begin() + nNJointCtrls,
168 [](NJointControllerBase* p) { return p; }));
169 //last getNumberOfControlDevices()-nNJointCtrls null
170 ARMARX_CHECK_EXPRESSION(std::all_of(nJointCtrls.begin() + nNJointCtrls,
171 nJointCtrls.end(),
172 [](NJointControllerBase* p) { return !p; }));
173 //conflict free and sorted
174 ARMARX_CHECK_EXPRESSION(std::is_sorted(
175 nJointCtrls.begin(), nJointCtrls.end(), std::greater<NJointControllerBase*>{}));
177 nJointCtrls.begin(), nJointCtrls.begin() + nNJointCtrls));
178
179 //check JointCtrl
180 const auto& jointCtrls = setOfControllers.jointControllers;
181 ARMARX_CHECK_EXPRESSION(jointCtrls.size() ==
182 _module<Devices>().getNumberOfControlDevices());
183 ARMARX_CHECK_EXPRESSION(std::all_of(
184 jointCtrls.begin(), jointCtrls.end(), [](JointController* p) { return p; }));
185
186 //check groups
187 {
188 ARMARX_DEBUG << "check groups";
189 std::size_t grpIdx = 0;
190 for (const auto& group : _module<Devices>().getControlModeGroups().groups)
191 {
192 ARMARX_CHECK_EXPRESSION(!group.empty());
193 const auto hwMode =
194 setOfControllers.jointControllers
195 .at(_module<Devices>().getControlDeviceIndex(*group.begin()))
196 ->getHardwareControlMode();
197 ARMARX_DEBUG << "---- group " << grpIdx << " mode '" << hwMode << "'";
198 for (const auto& other : group)
199 {
200 const auto& dev = _module<Devices>().getControlDeviceIndex(other);
202 const auto otherHwMode =
203 setOfControllers.jointControllers.at(dev)->getHardwareControlMode();
204 ARMARX_DEBUG << "-------- '" << other << "'' mode '" << otherHwMode << "'";
205 ARMARX_CHECK_EXPRESSION(otherHwMode == hwMode);
206 }
207 ++grpIdx;
208 }
209 }
210 //setup assignement
211 {
212 ARMARX_DEBUG << "setup assignement index";
213 setOfControllers.resetAssignement();
214 for (std::size_t nJointCtrlIndex = 0;
215 nJointCtrlIndex < setOfControllers.nJointControllers.size();
216 ++nJointCtrlIndex)
217 {
218 const NJointControllerBase* nJoint =
219 setOfControllers.nJointControllers.at(nJointCtrlIndex);
220 if (!nJoint)
221 {
222 break;
223 }
224 ARMARX_DEBUG << "---- " << nJoint->getInstanceName();
225 for (std::size_t jointIndex : nJoint->getControlDeviceUsedIndices())
226 {
227 ARMARX_DEBUG << "-------- Index " << jointIndex << ": "
228 << setOfControllers.jointToNJointControllerAssignement.at(
229 jointIndex)
230 << "-> " << nJointCtrlIndex;
231 ARMARX_CHECK_EXPRESSION(setOfControllers.jointToNJointControllerAssignement.at(
232 jointIndex) == IndexSentinel());
233 setOfControllers.jointToNJointControllerAssignement.at(jointIndex) =
234 nJointCtrlIndex;
235 }
236 }
237 }
238
239 {
240 ARMARX_DEBUG << "call checkSetOfControllersToActivate";
241 checkSetOfControllersToActivate(setOfControllers);
242 }
243 //set requested state
244 ControllerManagementAttorneyForControlThreadDataBuffer::
245 UpdateNJointControllerRequestedState(this, nJointSet);
246
247 ARMARX_CHECK_EQUAL(_module<Devices>().getNumberOfControlDevices(),
248 setOfControllers.jointControllers.size());
249 ARMARX_CHECK_EQUAL(_module<Devices>().getNumberOfControlDevices(),
250 setOfControllers.nJointControllers.size());
251 ARMARX_CHECK_EQUAL(_module<Devices>().getNumberOfControlDevices(),
252 setOfControllers.jointToNJointControllerAssignement.size());
253 {
254 std::lock_guard<std::recursive_mutex> guard{controllersRequestedMutex};
255 controllersRequested.getWriteBuffer() = std::move(setOfControllers);
256 controllersRequested.commitWrite();
257 }
259 << "writeRequestedControllers(JointAndNJointControllers&& setOfControllers)...done!";
260 }
261
262 void
264 std::set<NJointControllerBasePtr, std::greater<NJointControllerBasePtr>> ctrls)
265 {
266 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
267 std::lock_guard<std::recursive_mutex> guardRequested{controllersRequestedMutex};
268 throwIfDevicesNotReady(__FUNCTION__);
269 //erase nullptr
270 ctrls.erase(nullptr);
271 ARMARX_CHECK_EXPRESSION(ctrls.size() <= _module<Devices>().getNumberOfControlDevices());
272
273 const std::set<NJointControllerBasePtr, std::greater<NJointControllerBasePtr>>
274 setOfRequestedCtrls{controllersRequested.getWriteBuffer().nJointControllers.begin(),
275 controllersRequested.getWriteBuffer().nJointControllers.end()};
276 if (setOfRequestedCtrls == ctrls)
277 {
278 //redirty the flag to swap in the same set again
279 controllersRequested.commitWrite();
280 return;
281 }
282 JointAndNJointControllers request{_module<Devices>().getNumberOfControlDevices()};
283 std::size_t idx = 0;
284 for (const NJointControllerBasePtr& nJointCtrl : ctrls)
285 {
286 request.nJointControllers.at(idx++) = nJointCtrl.get();
287 //add Joint for this ctrl
288 for (const auto& cd2cm : nJointCtrl->getControlDeviceUsedControlModeMap())
289 {
290 std::size_t jointCtrlIndex =
291 _module<Devices>().getControlDevices().index(cd2cm.first);
292 if (request.jointControllers.at(jointCtrlIndex))
293 {
294 std::stringstream ss;
295 ss << "RobotUnit:setActivateControllersRequest controllers to activate are in "
296 "conflict!\ncontrollers:";
297 for (const auto& ctrl : ctrls)
298 {
299 ss << "\n" << ctrl->getInstanceName();
300 }
301 ARMARX_ERROR << ss.str();
302 throw InvalidArgumentException{ss.str()};
303 }
304 request.jointControllers.at(jointCtrlIndex) =
306 .getControlDevices()
307 .at(jointCtrlIndex)
308 ->getJointController(cd2cm.second);
309 }
310 }
311
312 std::size_t jointControllersCount = request.jointControllers.size();
313 for (std::size_t i = 0; i < jointControllersCount; ++i)
314 {
315 JointController*& jointCtrl = request.jointControllers.at(i);
316 if (!jointCtrl)
317 {
318 JointController* jointCtrlOld =
319 controllersRequested.getWriteBuffer().jointControllers.at(i);
320 if (jointCtrlOld ==
321 _module<Devices>().getControlDevices().at(i)->getJointStopMovementController())
322 {
323 //don't replace this controller with emergency stop
324 jointCtrl = jointCtrlOld;
325 }
326 else
327 {
328 //no one controls this device -> emergency stop
329 jointCtrl = _module<Devices>()
330 .getControlDevices()
331 .at(i)
332 ->getJointEmergencyStopController();
333 }
334 }
335 }
336 ARMARX_DEBUG << "wrote requested controllers";
337 ARMARX_INFO << "requested controllers:\n" << ARMARX_STREAM_PRINTER
338 {
339 for (std::size_t i = 0; i < request.nJointControllers.size(); ++i)
340 {
341 const auto& ctrl = request.nJointControllers.at(i);
342 if (ctrl)
343 {
344 out << i << "\t'" << ctrl->getInstanceName() << "' \t of class '"
345 << ctrl->getClassName() << "'\n";
346 }
347 }
348 };
349 writeRequestedControllers(std::move(request));
350 }
351
352 void
354 const VirtualRobot::RobotPtr& robot,
355 const std::vector<VirtualRobot::RobotNodePtr>& nodes) const
356 {
357 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
358 _module<Devices>().updateVirtualRobotFromSensorValues(
359 robot, nodes, controlThreadOutputBuffer.getReadBuffer().sensors);
360 }
361
362 void
364 {
365 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
366 _module<Devices>().updateVirtualRobotFromSensorValues(
367 robot, controlThreadOutputBuffer.getReadBuffer().sensors);
368 }
369
370 void
371 ControlThreadDataBuffer::_postFinishDeviceInitialization()
372 {
373 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
374 ARMARX_DEBUG << "initializing buffers:";
375 {
376 ARMARX_DEBUG << "----initializing controller buffers for "
377 << _module<Devices>().getNumberOfControlDevices() << " control devices";
378
379 JointAndNJointControllers ctrlinitReq(_module<Devices>().getNumberOfControlDevices());
380 ARMARX_CHECK_EQUAL(_module<Devices>().getNumberOfControlDevices(),
381 ctrlinitReq.jointControllers.size());
382 ARMARX_CHECK_EQUAL(_module<Devices>().getNumberOfControlDevices(),
383 ctrlinitReq.nJointControllers.size());
384 ARMARX_CHECK_EQUAL(_module<Devices>().getNumberOfControlDevices(),
385 ctrlinitReq.jointToNJointControllerAssignement.size());
386 controllersActivated.reinitAllBuffers(ctrlinitReq);
387
388 ctrlinitReq.jointControllers =
389 DevicesAttorneyForControlThreadDataBuffer::GetStopMovementJointControllers(this);
390 ARMARX_CHECK_EQUAL(_module<Devices>().getNumberOfControlDevices(),
391 ctrlinitReq.jointControllers.size());
392 ARMARX_CHECK_EQUAL(_module<Devices>().getNumberOfControlDevices(),
393 ctrlinitReq.nJointControllers.size());
394 ARMARX_CHECK_EQUAL(_module<Devices>().getNumberOfControlDevices(),
395 ctrlinitReq.jointToNJointControllerAssignement.size());
396 controllersRequested.reinitAllBuffers(ctrlinitReq);
397 controllersRequested
398 .commitWrite(); //to make sure the diry bit is activated (to trigger rt switch)
399 }
400 }
401} // namespace armarx::RobotUnitModule
#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
The JointController class represents one joint in one control mode.
A high level controller writing its results into ControlTargets.
static std::optional< std::vector< char > > AreNotInConflict(ItT first, ItT last)
virtual void checkSetOfControllersToActivate(const JointAndNJointControllers &) const
This hook is called prior to writing the set of requested controllers.
std::vector< NJointControllerBase * > getActivatedNJointControllers() const
Returns the set of activated NJointControllers.
bool sensorAndControlBufferChanged() const
Updates the sensor and control buffer and returns whether the buffer was updated.
bool activatedControllersChanged() const
Returns whether the set of activated Joint- and NJointControllers changed.
void setActivateControllersRequest(std::set< NJointControllerBasePtr, std::greater< NJointControllerBasePtr > > ctrls)
Sets the set of requested NJointControllers to.
JointAndNJointControllers getActivatedControllers() const
TODO private + attorney for publish.
const SensorAndControl & getSensorAndControlBuffer() const
TODO private + attorney for publish.
std::vector< JointController * > copyRequestedJointControllers() const
Returns the set of requsted JointControllers.
JointAndNJointControllers copyRequestedControllers() const
Returns the set of requsted Joint- and NJointControllers.
std::vector< NJointControllerBase * > copyRequestedNJointControllers() const
Returns the set of requsted NJointControllers.
void updateVirtualRobot(const VirtualRobot::RobotPtr &robot) const
Updates the given VirtualRobot with the current joint values.
std::vector< JointController * > getActivatedJointControllers() const
Returns the set of activated JointControllers.
This class allows minimal access to private members of ControllerManagement in a sane fashion for Con...
This class allows minimal access to private members of Devices in a sane fashion for ControlThreadDat...
This Module manages sensor and control devices for a RobotUnit and only allows save and sane access.
T & _module()
Returns this as ref to the given type.
void throwIfInControlThread(const std::string &fnc) const
Throws if the current thread is the ControlThread.
static constexpr std::size_t IndexSentinel()
Returns a sentinel value for an index (std::numeric_limits<std::size_t>::max())
void throwIfDevicesNotReady(const std::string &fnc) const
Throws if the Devices are not ready.
#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
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
detail::ControlThreadOutputBufferEntry SensorAndControl
Structure used by the RobotUnit to swap lists of Joint and NJoint controllers.
std::vector< JointController * > jointControllers