YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
ControlBoard_nws_yarp.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-FileCopyrightText: 2006-2010 RobotCub Consortium
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
8
10#include "RPCMessagesParser.h"
12
13#include <yarp/os/LogStream.h>
15
16#include <numeric>
17#include <cmath>
18
19using namespace yarp::os;
20using namespace yarp::dev;
21using namespace yarp::sig;
23
24const double DEFAULT_PERIOD = 0.02;
25
30
31void ControlBoard_nws_yarp::closePorts()
32{
33 inputRPCPort.interrupt();
34 inputRPCPort.removeCallbackLock();
35 inputRPCPort.close();
36
37 inputStreamingPort.interrupt();
38 inputStreamingPort.close();
39
40 outputPositionStatePort.interrupt();
41 outputPositionStatePort.close();
42
43 extendedOutputStatePort.interrupt();
44 extendedOutputStatePort.close();
45}
46
48{
49 // Ensure that the device is not running
50 if (isRunning()) {
51 stop();
52 }
53
54 closeDevice();
55 closePorts();
56
57 return true;
58}
59
61{
62 if (!parseParams(config)) { return false; }
63
64 // open rpc port
65 std::string server_rpc_portname = m_name + "/nws/rpc";
66 if (!m_rpcPort.open(server_rpc_portname))
67 {
68 yCError(CONTROLBOARD, "Failed to open port %s", server_rpc_portname.c_str());
69 return false;
70 }
71 m_rpcPort.setReader(*this);
72
73 std::string rootName = m_name;
74
75 // Open ports, then attach the readers or callbacks
76 if (!inputRPCPort.open((rootName + "/rpc:i"))) {
77 yCError(CONTROLBOARD) << "Error opening port " << rootName + "/rpc:i";
78 closePorts();
79 return false;
80 }
81 inputRPCPort.setReader(RPC_parser);
82 inputRPC_buffer.attach(inputRPCPort);
83 RPC_parser.attach(inputRPC_buffer);
84
85 if (!inputStreamingPort.open(rootName + "/command:i")) {
86 yCError(CONTROLBOARD) << "Error opening port " << rootName + "/rpc:i";
87 closePorts();
88 return false;
89 }
90 inputStreamingPort.setStrict();
91 inputStreamingPort.useCallback(streaming_parser);
92
93 if (!outputPositionStatePort.open(rootName + "/state:o")) {
94 yCError(CONTROLBOARD) << "Error opening port " << rootName + "/state:o";
95 closePorts();
96 return false;
97 }
98
99 // Extended output state port
100 if (!extendedOutputStatePort.open(rootName + "/stateExt:o")) {
101 yCError(CONTROLBOARD) << "Error opening port " << rootName + "/state:o";
102 closePorts();
103 return false;
104 }
105 extendedOutputState_buffer.attach(extendedOutputStatePort);
106
107 // In case attach is not deferred and the controlboard already owns a valid device
108 // we can start the thread. Otherwise this will happen when attachAll is called
109 if (subdevice_ready) {
111 if (!start()) {
112 yCError(CONTROLBOARD) << "Error starting thread";
113 return false;
114 }
115 }
116
117 return true;
118}
119
120bool ControlBoard_nws_yarp::setDevice(yarp::dev::DeviceDriver* driver, bool owned)
121{
122 // Save the pointer and subDeviceOwned
124
125 subdevice_ptr->view(iJointFault);
126 if (!iJointFault) {
127 yCWarning(CONTROLBOARD, "Part <%s>: iJointFault interface was not found in subdevice.", partName.c_str());
128 }
129
130 subdevice_ptr->view(iPidControl);
131 if (!iPidControl) {
132 yCWarning(CONTROLBOARD, "Part <%s>: IPidControl interface was not found in subdevice.", partName.c_str());
133 }
134
135 subdevice_ptr->view(iPositionControl);
136 if (!iPositionControl) {
137 yCWarning(CONTROLBOARD, "Part <%s>: IPositionControl interface was not found in subdevice.", partName.c_str());
138 }
139
140 subdevice_ptr->view(iPositionDirect);
141 if (!iPositionDirect) {
142 yCWarning(CONTROLBOARD, "Part <%s>: IPositionDirect interface was not found in subdevice.", partName.c_str());
143 }
144
145 subdevice_ptr->view(iVelocityControl);
146 if (!iVelocityControl) {
147 yCWarning(CONTROLBOARD, "Part <%s>: IVelocityControl interface was not found in subdevice.", partName.c_str());
148 }
149
150 subdevice_ptr->view(iEncodersTimed);
151 if (!iEncodersTimed) {
152 yCWarning(CONTROLBOARD, "Part <%s>: IEncodersTimed interface was not found in subdevice.", partName.c_str());
153 }
154
155 subdevice_ptr->view(iMotor);
156 if (!iMotor) {
157 yCWarning(CONTROLBOARD, "Part <%s>: IMotor interface was not found in subdevice.", partName.c_str());
158 }
159
160 subdevice_ptr->view(iMotorEncoders);
161 if (!iMotorEncoders) {
162 yCWarning(CONTROLBOARD, "Part <%s>: IMotorEncoders interface was not found in subdevice.", partName.c_str());
163 }
164
165 subdevice_ptr->view(iAmplifierControl);
166 if (!iAmplifierControl) {
167 yCWarning(CONTROLBOARD, "Part <%s>: IAmplifierControl interface was not found in subdevice.", partName.c_str());
168 }
169
170 subdevice_ptr->view(iControlLimits);
171 if (!iControlLimits) {
172 yCWarning(CONTROLBOARD, "Part <%s>: IControlLimits interface was not found in subdevice.", partName.c_str());
173 }
174
175 subdevice_ptr->view(iControlCalibration);
176 if (!iControlCalibration) {
177 yCWarning(CONTROLBOARD, "Part <%s>: IControlCalibration interface was not found in subdevice.", partName.c_str());
178 }
179
180 subdevice_ptr->view(iTorqueControl);
181 if (!iTorqueControl) {
182 yCWarning(CONTROLBOARD, "Part <%s>: ITorqueControl interface was not found in subdevice.", partName.c_str());
183 }
184
185 subdevice_ptr->view(iImpedanceControl);
186 if (!iImpedanceControl) {
187 yCWarning(CONTROLBOARD, "Part <%s>: IImpedanceControl interface was not found in subdevice.", partName.c_str());
188 }
189
190 subdevice_ptr->view(iControlMode);
191 if (!iControlMode) {
192 yCWarning(CONTROLBOARD, "Part <%s>: IControlMode interface was not found in subdevice.", partName.c_str());
193 }
194
195 subdevice_ptr->view(iAxisInfo);
196 if (!iAxisInfo) {
197 yCWarning(CONTROLBOARD, "Part <%s>: IAxisInfo interface was not found in subdevice.", partName.c_str());
198 }
199
200 subdevice_ptr->view(iPreciselyTimed);
201 if (!iPreciselyTimed) {
202 yCWarning(CONTROLBOARD, "Part <%s>: IPreciselyTimed interface was not found in subdevice.", partName.c_str());
203 }
204
205 subdevice_ptr->view(iInteractionMode);
206 if (!iInteractionMode) {
207 yCWarning(CONTROLBOARD, "Part <%s>: IInteractionMode interface was not found in subdevice.", partName.c_str());
208 }
209
210 subdevice_ptr->view(iRemoteVariables);
211 if (!iRemoteVariables) {
212 yCWarning(CONTROLBOARD, "Part <%s>: IRemoteVariables interface was not found in subdevice.", partName.c_str());
213 }
214
215 subdevice_ptr->view(iPWMControl);
216 if (!iPWMControl) {
217 yCWarning(CONTROLBOARD, "Part <%s>: IPWMControl interface was not found in subdevice.", partName.c_str());
218 }
219
220 subdevice_ptr->view(iCurrentControl);
221 if (!iCurrentControl) {
222 yCWarning(CONTROLBOARD, "Part <%s>: ICurrentControl interface was not found in subdevice.", partName.c_str());
223 }
224
225 subdevice_ptr->view(iJointBrake);
226 if (!iJointBrake) {
227 yCWarning(CONTROLBOARD, "Part <%s>: iJointBrake interface was not found in subdevice.", partName.c_str());
228 }
229
230 subdevice_ptr->view(iVelocityDirect);
231 if (!iVelocityDirect) {
232 yCWarning(CONTROLBOARD, "Part <%s>: iVelocityDirect interface was not found in subdevice.", partName.c_str());
233 }
234
235 // Get the number of controlled joints
236 int tmp_axes = 0;
237 if (iAxisInfo)
238 {
239 if (!iAxisInfo->getAxes(&tmp_axes)) {
240 yCError(CONTROLBOARD) << "Part <%s>: iAxisInfo->getAxes() failed for subdevice " << partName.c_str();
241 return false;
242 }
243 }
244 else if (iEncodersTimed)
245 {
246 if (!iEncodersTimed->getAxes(&tmp_axes)) {
247 yCError(CONTROLBOARD) << "Part <%s>: iEncodersTimed->getAxes() failed for subdevice " << partName.c_str();
248 return false;
249 }
250 }
251 else if (iPositionControl)
252 {
253 if (!iPositionControl->getAxes(&tmp_axes)) {
254 yCError(CONTROLBOARD) << "Part <%s>: iPositionControl->getAxes() failed for subdevice " << partName.c_str();
255 return false;
256 }
257 }
258 else if (iVelocityControl)
259 {
260 if (!iVelocityControl->getAxes(&tmp_axes)) {
261 yCError(CONTROLBOARD) << "Part <%s>: iVelocityControl->getAxes() failed for subdevice " << partName.c_str();
262 return false;
263 }
264 }
265
266 if (tmp_axes <= 0) {
267 yCError(CONTROLBOARD, "Part <%s>: attached device has an invalid number of joints (%d)", partName.c_str(), tmp_axes);
268 return false;
269 }
270 subdevice_joints = static_cast<size_t>(tmp_axes);
271 times.resize(subdevice_joints);
272
273 // Initialization
274 streaming_parser.init(subdevice_ptr);
275 streaming_parser.initialize();
276
277 RPC_parser.init(subdevice_ptr);
278 RPC_parser.initialize();
279
280 return true;
281}
282
283void ControlBoard_nws_yarp::closeDevice()
284{
285 // Reset callbacks
286 streaming_parser.reset();
287 RPC_parser.reset();
288
289 subdevice_joints = 0;
290 subdevice_ready = false;
291
292 times.clear();
293
294 // Clear all interfaces
295 iPidControl = nullptr;
296 iPositionControl = nullptr;
297 iPositionDirect = nullptr;
298 iVelocityControl = nullptr;
299 iEncodersTimed = nullptr;
300 iMotor = nullptr;
301 iMotorEncoders = nullptr;
302 iAmplifierControl = nullptr;
303 iControlLimits = nullptr;
304 iControlCalibration = nullptr;
305 iTorqueControl = nullptr;
306 iImpedanceControl = nullptr;
307 iControlMode = nullptr;
308 iAxisInfo = nullptr;
309 iPreciselyTimed = nullptr;
310 iInteractionMode = nullptr;
311 iRemoteVariables = nullptr;
312 iPWMControl = nullptr;
313 iCurrentControl = nullptr;
314 iJointFault = nullptr;
315 iVelocityDirect = nullptr;
316}
317
319{
320 // Check if we already instantiated a subdevice previously
321 if (subdevice_ready) {
322 return false;
323 }
324
325 if (!setDevice(poly, false)) {
326 return false;
327 }
328
330 if (!start()) {
331 yCError(CONTROLBOARD) << "Error starting thread";
332 return false;
333 }
334
335 m_RPC = std::make_unique<ControlBoardRPCd>(iJointBrake, iVelocityDirect);
336
337 return true;
338}
339
341{
342 // Ensure that the device is not running
343 if (isRunning()) {
344 stop();
345 }
346
347 closeDevice();
348
349 return true;
350}
351
353{
354 // check we are not overflowing with input messages
355 constexpr int reads_for_warning = 20;
356 if (inputStreamingPort.getPendingReads() >= reads_for_warning) {
357 yCIWarning(CONTROLBOARD, id()) << "Number of streaming input messages to be read is " << inputStreamingPort.getPendingReads() << " and can overflow";
358 }
359 // handle stateExt first
360 jointData& data = extendedOutputState_buffer.get();
361
362 data.jointPosition.resize(subdevice_joints);
363 data.jointVelocity.resize(subdevice_joints);
364 data.jointAcceleration.resize(subdevice_joints);
365 data.motorPosition.resize(subdevice_joints);
366 data.motorVelocity.resize(subdevice_joints);
367 data.motorAcceleration.resize(subdevice_joints);
368 data.torque.resize(subdevice_joints);
369 data.pwmDutycycle.resize(subdevice_joints);
370 data.temperature.resize(subdevice_joints);
371 data.current.resize(subdevice_joints);
372 data.controlMode.resize(subdevice_joints);
373 data.interactionMode.resize(subdevice_joints);
374
375 // resize the temporary vector
376 tmpVariableForFloatSignals.resize(subdevice_joints);
377
378 // Get data from HW
379 if (iEncodersTimed) {
380 data.jointPosition_isValid = iEncodersTimed->getEncodersTimed(data.jointPosition.data(), times.data());
381 data.jointVelocity_isValid = iEncodersTimed->getEncoderSpeeds(data.jointVelocity.data());
383 } else {
384 data.jointPosition_isValid = false;
385 data.jointVelocity_isValid = false;
386 data.jointAcceleration_isValid = false;
387 }
388
389 if (iMotorEncoders) {
390 data.motorPosition_isValid = iMotorEncoders->getMotorEncoders(data.motorPosition.data());
391 data.motorVelocity_isValid = iMotorEncoders->getMotorEncoderSpeeds(data.motorVelocity.data());
393 } else {
394 data.motorPosition_isValid = false;
395 data.motorVelocity_isValid = false;
396 data.motorAcceleration_isValid = false;
397 }
398
399 if (iMotor) {
400 // the temperature is a double in the interface, but a float in the jointData struct.
401 data.temperature_isValid = iMotor->getTemperatures(tmpVariableForFloatSignals.data());
402
403 // The temperature values are stored as double in the interface but need to be converted to float in the jointData struct.
404 // We manually copy them, and while this conversion may lead to a minor loss of precision, it is negligible for temperature values,
405 // which typically do not require double precision. std::copy ensures a safe and efficient conversion.
406 std::copy(tmpVariableForFloatSignals.begin(), tmpVariableForFloatSignals.end(), data.temperature.begin());
407 } else {
408 data.temperature_isValid = false;
409 }
410
411 if (iTorqueControl) {
412 data.torque_isValid = iTorqueControl->getTorques(data.torque.data());
413 } else {
414 data.torque_isValid = false;
415 }
416
417 if (iPWMControl) {
418 // the pwmDutycycle is a double in the interface, but a float in the jointData struct.
419 data.pwmDutycycle_isValid = iPWMControl->getDutyCycles(tmpVariableForFloatSignals.data());
420
421 // The pwmDutycycle values are stored as double in the interface but need to be converted to float in the jointData struct.
422 // We manually copy them, and while this conversion may lead to a minor loss of precision, it is negligible for pwmDutycycle values,
423 // which typically do not require double precision. std::copy ensures a safe and efficient conversion.
424 std::copy(tmpVariableForFloatSignals.begin(), tmpVariableForFloatSignals.end(), data.pwmDutycycle.begin());
425 } else {
426 data.pwmDutycycle_isValid = false;
427 }
428
429 if (iCurrentControl) {
430 data.current_isValid = iCurrentControl->getCurrents(data.current.data());
431 } else if (iAmplifierControl) {
432 data.current_isValid = iAmplifierControl->getCurrents(data.current.data());
433 } else {
434 data.current_isValid = false;
435 }
436
437 if (iControlMode) {
438 data.controlMode_isValid = iControlMode->getControlModes(data.controlMode.data());
439 } else {
440 data.controlMode_isValid = false;
441 }
442
443 if (iInteractionMode) {
444 data.interactionMode_isValid = iInteractionMode->getInteractionModes(reinterpret_cast<yarp::dev::InteractionModeEnum*>(data.interactionMode.data()));
445 } else {
446 data.interactionMode_isValid = false;
447 }
448
449 // Check if the encoders timestamps are consistent.
450 for (double tt : times)
451 {
452 if (std::abs(times[0] - tt) > 1.0)
453 {
454 yCIErrorThrottle(CONTROLBOARD, id(), 1.0) << "Encoder timestamps are not consistent! Data will not be published.";
455 return;
456 }
457 }
458
459 // Update the port envelope time by averaging all timestamps
460 time.update(std::accumulate(times.begin(), times.end(), 0.0) / subdevice_joints);
462
463 extendedOutputStatePort.enableBackgroundWrite(true);
464 extendedOutputStatePort.setEnvelope(averageTime);
465 extendedOutputState_buffer.write();
466
467 // handle state:o
468 yarp::sig::Vector& v = outputPositionStatePort.prepare();
469 v.resize(subdevice_joints);
470 std::copy(data.jointPosition.begin(), data.jointPosition.end(), v.begin());
471
472 outputPositionStatePort.setEnvelope(averageTime);
473 outputPositionStatePort.write();
474}
475
477{
478 if (!connection.isValid()) {
479 return false;
480 }
481 if (!m_RPC) {
482 return false;
483 }
484
485 std::lock_guard<std::mutex> lock(m_mutex);
486 bool b = m_RPC->read(connection);
487 if (b) {
488 return true;
489 }
490 yCDebug(CONTROLBOARD) << "read() Command failed";
491 return false;
492}
const yarp::os::LogComponent & CONTROLBOARD()
const double DEFAULT_PERIOD
bool parseParams(const yarp::os::Searchable &config) override
Parse the DeviceDriver parameters.
void run() override
Loop function.
bool read(yarp::os::ConnectionReader &connection) override
Read this object from a network connection.
bool open(yarp::os::Searchable &prop) override
Open the DeviceDriver.
bool close() override
Close the DeviceDriver.
bool attach(yarp::dev::PolyDriver *poly) override
Attach to another object.
bool detach() override
Detach the object (you must have first called attach).
void init(yarp::dev::DeviceDriver *x)
Initialization.
virtual bool initialize()
Initialize the internal data.
void init(yarp::dev::DeviceDriver *x)
Initialization.
Interface implemented by all device drivers.
void attach(yarp::os::TypedReader< yarp::os::Bottle > &source)
Attach this object to a source of messages.
virtual bool getCurrents(double *vals)=0
virtual bool getAxes(int *ax)=0
Get the number of controlled axes.
virtual bool getControlModes(int *modes)=0
Get the current control mode (multiple joints).
virtual bool getCurrents(double *currs)=0
Get the instantaneous current measurement for all motors.
virtual bool getEncodersTimed(double *encs, double *time)=0
Read the instantaneous acceleration of all axes.
virtual bool getEncoderAccelerations(double *accs)=0
Read the instantaneous acceleration of all axes.
virtual bool getAxes(int *ax)=0
Get the number of controlled axes.
virtual bool getEncoderSpeeds(double *spds)=0
Read the instantaneous speed of all axes.
virtual bool getInteractionModes(int n_joints, int *joints, yarp::dev::InteractionModeEnum *modes)=0
Get the current interaction mode of the robot for a set of joints, values can be stiff or compliant.
virtual bool getMotorEncoderSpeeds(double *spds)=0
Read the instantaneous speed of all motor encoders.
virtual bool getMotorEncoderAccelerations(double *accs)=0
Read the instantaneous acceleration of all motor encoders.
virtual bool getMotorEncoders(double *encs)=0
Read the position of all motor encoders.
virtual bool getTemperatures(double *vals)=0
Get temperature of all the motors.
virtual bool getDutyCycles(double *vals)=0
Gets the current dutycycle of the output of the amplifier (i.e.
virtual bool getAxes(int *ax)=0
Get the number of controlled axes.
virtual bool getTorques(double *t)=0
Get the value of the torque for all joints (this is the feedback if you have torque sensors).
virtual bool getAxes(int *axes)=0
Get the number of controlled axes.
A container for a device driver.
Definition PolyDriver.h:23
yarp::sig::VectorOf< float > pwmDutycycle
Definition jointData.h:41
yarp::sig::VectorOf< double > motorVelocity
Definition jointData.h:35
yarp::sig::VectorOf< double > jointAcceleration
Definition jointData.h:31
yarp::sig::VectorOf< int > controlMode
Definition jointData.h:45
yarp::sig::VectorOf< int > interactionMode
Definition jointData.h:47
yarp::sig::VectorOf< double > current
Definition jointData.h:43
yarp::sig::VectorOf< double > motorAcceleration
Definition jointData.h:37
yarp::sig::VectorOf< double > motorPosition
Definition jointData.h:33
yarp::sig::VectorOf< double > torque
Definition jointData.h:39
yarp::sig::VectorOf< float > temperature
Definition jointData.h:49
yarp::sig::VectorOf< double > jointPosition
Definition jointData.h:27
yarp::sig::VectorOf< double > jointVelocity
Definition jointData.h:29
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
void setReader(PortReader &reader) override
Set an external reader for port data.
A mini-server for performing network communication in the background.
void close() override
Stop port activity.
bool setEnvelope(PortWriter &envelope) override
Set an envelope (e.g., a timestamp) to the next message which will be sent.
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
int getPendingReads() override
Get the number of objects ready to be read.
void interrupt() override
Interrupt any current reads or writes attached to the port.
void useCallback(TypedReaderCallback< T > &callback) override
Set an object whose onRead method will be called when data is available.
void setStrict(bool strict=true) override
Call this to strictly keep all messages, or allow old ones to be quietly dropped.
void write(bool forceStrict=false)
Write the current object being returned by BufferedPort::prepare.
T & prepare()
Access the object which will be transmitted by the next call to yarp::os::BufferedPort::write.
An interface for reading from a network connection.
virtual bool isValid() const =0
An abstraction for a periodic thread.
bool setPeriod(double period)
Set the (new) period of the thread.
bool isRunning() const
Returns true when the thread is started, false otherwise.
bool start()
Call this to start the thread.
void stop()
Call this to stop the thread, this call blocks until the thread is terminated (and releaseThread() ca...
void attach(Port &port)
Attach this buffer to a particular port.
T & get()
A synonym of PortWriterBuffer::prepare.
void write(bool forceStrict=false)
Try to write the last buffer returned by PortWriterBuffer::get.
void attach(Port &port)
Set the Port to which objects will be written.
void enableBackgroundWrite(bool backgroundFlag)
control whether writing from this port is done in the background.
Definition Port.cpp:492
void setReader(PortReader &reader) override
Set an external reader for port data.
Definition Port.cpp:470
bool removeCallbackLock() override
Remove a lock on callbacks added with setCallbackLock()
Definition Port.cpp:644
void interrupt() override
Interrupt any current reads or writes attached to the port.
Definition Port.cpp:347
bool setEnvelope(PortWriter &envelope) override
Set an envelope (e.g., a timestamp) to the next message which will be sent.
Definition Port.cpp:506
void close() override
Stop port activity.
Definition Port.cpp:330
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
Definition Port.cpp:79
A base class for nested structures that can be searched.
Definition Searchable.h:31
An abstraction for a time stamp and/or sequence number.
Definition Stamp.h:21
void update()
Set the timestamp to the current time, and increment the sequence number (wrapping to 0 if the sequen...
Definition Stamp.cpp:124
void resize(size_t size) override
Resize the vector.
Definition Vector.h:211
iterator begin() noexcept
Returns an iterator to the beginning of the VectorOf.
Definition Vector.h:463
T * data()
Return a pointer to the first element of the vector.
Definition Vector.h:196
iterator end() noexcept
Returns an iterator to the end of the VectorOf.
Definition Vector.h:470
#define yCError(component,...)
#define yCWarning(component,...)
#define yCIErrorThrottle(component, id, period,...)
#define yCDebug(component,...)
#define yCIWarning(component, id,...)
For streams capable of holding different kinds of content, check what they actually have.
An interface to the operating system, including Port based communication.
The main, catch-all namespace for YARP.
Definition dirs.h:16