YARP
Yet Another Robot Platform
ControlBoard_nws_ros.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 <yarp/os/LogStream.h>
11
13
15
17
18#include <numeric>
19#include <math.h>
20
21using namespace yarp::os;
22using namespace yarp::dev;
23using namespace yarp::sig;
24
27{
28}
29
30
31void ControlBoard_nws_ros::closePorts()
32{
33 publisherPort.interrupt();
34 publisherPort.close();
35
36 delete node;
37 node = nullptr;
38}
39
41{
42 // Ensure that the device is not running
43 if (isRunning()) {
44 stop();
45 }
46
47 closeDevice();
48 closePorts();
49
50 return true;
51}
52
53
55{
56 Property prop;
57 prop.fromString(config.toString());
58
59 // Check parameter, so if both are present we use the correct one
60 if (prop.check("period")) {
61 if (!prop.find("period").isFloat64()) {
62 yCError(CONTROLBOARD) << "'period' parameter is not a double value";
63 return false;
64 }
65 period = prop.find("period").asFloat64();
66 if (period <= 0) {
67 yCError(CONTROLBOARD) << "'period' parameter is not valid, read value is" << period;
68 return false;
69 }
70 } else {
71 yCDebug(CONTROLBOARD) << "'period' parameter missing, using default thread period = 0.02s";
72 period = default_period;
73 }
74
75 // Check if we need to create subdevice or if they are
76 // passed later on through attachAll()
77 if (prop.check("subdevice")) {
78 prop.setMonitor(config.getMonitor());
79 if (!openAndAttachSubDevice(prop)) {
80 yCError(CONTROLBOARD, "Error while opening subdevice");
81 return false;
82 }
83 subdevice_ready = true;
84 }
85
86 // check for node_name parameter
87 if (!config.check("node_name")) {
88 yCError(CONTROLBOARD) << nodeName << " cannot find node_name parameter";
89 return false;
90 }
91 nodeName = config.find("node_name").asString();
92 if(nodeName[0] != '/'){
93 yCError(CONTROLBOARD) << "node_name must begin with an initial /";
94 return false;
95 }
96
97 // check for topic_name parameter
98 if (!config.check("topic_name")) {
99 yCError(CONTROLBOARD) << nodeName << " cannot find topic_name parameter";
100 return false;
101 }
102 topicName = config.find("topic_name").asString();
103 if(topicName[0] != '/'){
104 yCError(CONTROLBOARD) << "topic_name must begin with an initial /";
105 return false;
106 }
107 yCInfo(CONTROLBOARD) << "topic_name is " << topicName;
108 // call ROS node/topic initialization
109 node = new yarp::os::Node(nodeName);
110 if (!publisherPort.topic(topicName)) {
111 yCError(CONTROLBOARD) << " opening " << topicName << " Topic, check your configuration";
112 return false;
113 }
114
115 // In case attach is not deferred and the controlboard already owns a valid device
116 // we can start the thread. Otherwise this will happen when attachAll is called
117 if (subdevice_ready) {
118 setPeriod(period);
119 if (!start()) {
120 yCError(CONTROLBOARD) << "Error starting thread";
121 return false;
122 }
123 }
124
125 return true;
126}
127
128
129
130// For the simulator, if a subdevice parameter is given to the wrapper, it will
131// open it and attach to immediately.
132bool ControlBoard_nws_ros::openAndAttachSubDevice(Property& prop)
133{
134 Property p;
135 auto* subDeviceOwned = new PolyDriver;
136 p.fromString(prop.toString());
137
138 std::string subdevice = prop.find("subdevice").asString();
139 p.setMonitor(prop.getMonitor(), subdevice.c_str()); // pass on any monitoring
140 p.unput("device");
141 p.put("device", subdevice); // subdevice was already checked before
142
143 // if errors occurred during open, quit here.
144 yCDebug(CONTROLBOARD, "opening subdevice");
145 subDeviceOwned->open(p);
146
147 if (!subDeviceOwned->isValid()) {
148 yCError(CONTROLBOARD, "opening subdevice... FAILED");
149 return false;
150 }
151
152 return setDevice(subDeviceOwned, true);
153}
154
155
156bool ControlBoard_nws_ros::setDevice(yarp::dev::DeviceDriver* driver, bool owned)
157{
158 yCAssert(CONTROLBOARD, driver);
159
160 // Save the pointer and subDeviceOwned
161 subdevice_ptr = driver;
162 subdevice_owned = owned;
163
164 subdevice_ptr->view(iPositionControl);
165 if (!iPositionControl) {
166 yCError(CONTROLBOARD, "<%s - %s>: IPositionControl interface was not found in subdevice. Quitting", nodeName.c_str(), topicName.c_str());
167 return false;
168 }
169
170 subdevice_ptr->view(iEncodersTimed);
171 if (!iEncodersTimed) {
172 yCError(CONTROLBOARD, "<%s - %s>: IEncodersTimed interface was not found in subdevice. Quitting", nodeName.c_str(), topicName.c_str());
173 return false;
174 }
175
176 subdevice_ptr->view(iTorqueControl);
177 if (!iTorqueControl) {
178 yCWarning(CONTROLBOARD, "<%s - %s>: ITorqueControl interface was not found in subdevice.", nodeName.c_str(), topicName.c_str());
179 }
180
181 subdevice_ptr->view(iAxisInfo);
182 if (!iAxisInfo) {
183 yCError(CONTROLBOARD, "<%s - %s>: IAxisInfo interface was not found in subdevice. Quitting", nodeName.c_str(), topicName.c_str());
184 return false;
185 }
186
187 // Get the number of controlled joints
188 int tmp_axes;
189 if (!iPositionControl->getAxes(&tmp_axes)) {
190 yCError(CONTROLBOARD, "<%s - %s>: Failed to get axes number for subdevice ", nodeName.c_str(), topicName.c_str());
191 return false;
192 }
193 if (tmp_axes <= 0) {
194 yCError(CONTROLBOARD, "<%s - %s>: attached device has an invalid number of joints (%d)", nodeName.c_str(), topicName.c_str(), tmp_axes);
195 return false;
196 }
197 subdevice_joints = static_cast<size_t>(tmp_axes);
198 times.resize(subdevice_joints);
199 ros_struct.name.resize(subdevice_joints);
200 ros_struct.position.resize(subdevice_joints);
201 ros_struct.velocity.resize(subdevice_joints);
202 ros_struct.effort.resize(subdevice_joints);
203
204 if (!updateAxisName()) {
205 return false;
206 }
207
208 return true;
209}
210
211
212void ControlBoard_nws_ros::closeDevice()
213{
214 // If the subdevice is owned, close and delete the device
215 if (subdevice_owned) {
216 yCAssert(CONTROLBOARD, subdevice_ptr);
217 subdevice_ptr->close();
218 delete subdevice_ptr;
219 }
220 subdevice_ptr = nullptr;
221 subdevice_owned = false;
222 subdevice_joints = 0;
223 subdevice_ready = false;
224
225 times.clear();
226
227 // Clear all interfaces
228 iPositionControl = nullptr;
229 iEncodersTimed = nullptr;
230 iTorqueControl = nullptr;
231 iAxisInfo = nullptr;
232}
233
235{
236 // Check if we already instantiated a subdevice previously
237 if (subdevice_ready) {
238 return false;
239 }
240
241 if (!setDevice(poly, false)) {
242 return false;
243 }
244
245 setPeriod(period);
246 if (!start()) {
247 yCError(CONTROLBOARD) << "Error starting thread";
248 return false;
249 }
250
251 return true;
252}
253
255{
256 //check if we already instantiated a subdevice previously
257 if (subdevice_owned) {
258 return false;
259 }
260
261 // Ensure that the device is not running
262 if (isRunning()) {
263 stop();
264 }
265
266 closeDevice();
267
268 return true;
269}
270
271
272bool ControlBoard_nws_ros::updateAxisName()
273{
274 // IMPORTANT!! This function has to be called BEFORE the thread starts,
275 // the name has to be correct right from the first message!!
276
277 yCAssert(CONTROLBOARD, iAxisInfo);
278
279 std::vector<std::string> tmpVect;
280 for (size_t i = 0; i < subdevice_joints; i++) {
281 std::string tmp;
282 bool ret = iAxisInfo->getAxisName(i, tmp);
283 if (!ret) {
284 yCError(CONTROLBOARD, "Joint name for axis %zu not found!", i);
285 return false;
286 }
287 tmpVect.emplace_back(tmp);
288 }
289
290 yCAssert(CONTROLBOARD, tmpVect.size() == subdevice_joints);
291
292 jointNames = tmpVect;
293
294 return true;
295}
296
297
299{
300 yCAssert(CONTROLBOARD, iEncodersTimed);
301 yCAssert(CONTROLBOARD, iAxisInfo);
302
303 bool positionsOk = iEncodersTimed->getEncodersTimed(ros_struct.position.data(), times.data());
304 YARP_UNUSED(positionsOk);
305
306 bool speedsOk = iEncodersTimed->getEncoderSpeeds(ros_struct.velocity.data());
307 YARP_UNUSED(speedsOk);
308
309 if (iTorqueControl) {
310 bool torqueOk = iTorqueControl->getTorques(ros_struct.effort.data());
311 YARP_UNUSED(torqueOk);
312 }
313
314 // Check if the encoders timestamps are consistent.
315 double tt = *times.data();
316 for (auto it = times.begin(); it != times.end(); it++)
317 {
318 if (fabs(tt - *it) > 1.0)
319 {
320 yCError(CONTROLBOARD, "Encoder Timestamps are not consistent! Data will not be published.");
321 return;
322 }
323 }
324
325 // Update the port envelope time by averaging all timestamps
326 time.update(std::accumulate(times.begin(), times.end(), 0.0) / subdevice_joints);
327 yarp::os::Stamp averageTime = time;
328
329 // Data from HW have been gathered few lines before
330 JointTypeEnum jType;
331 for (size_t i = 0; i < subdevice_joints; i++) {
332 iAxisInfo->getJointType(i, jType);
333 if (jType == VOCAB_JOINTTYPE_REVOLUTE) {
334 ros_struct.position[i] = convertDegreesToRadians(ros_struct.position[i]);
335 ros_struct.velocity[i] = convertDegreesToRadians(ros_struct.velocity[i]);
336 }
337 }
338
339 ros_struct.name = jointNames;
340
341 ros_struct.header.seq = counter++;
342 ros_struct.header.stamp = averageTime.getTime();
343
344 publisherPort.write(ros_struct);
345}
const yarp::os::LogComponent & CONTROLBOARD()
constexpr double default_period
Definition: FakeOdometry.h:14
bool ret
bool attach(yarp::dev::PolyDriver *poly) override
Attach to another object.
void run() override
Loop function.
bool close() override
Close the DeviceDriver.
bool open(yarp::os::Searchable &prop) override
Open the DeviceDriver.
bool detach() override
Detach the object (you must have first called attach).
Interface implemented by all device drivers.
Definition: DeviceDriver.h:30
bool view(T *&x)
Get an interface to the device driver.
Definition: DeviceDriver.h:88
bool close() override
Close the DeviceDriver.
Definition: DeviceDriver.h:59
virtual bool getAxisName(int axis, std::string &name)=0
virtual bool getJointType(int axis, yarp::dev::JointTypeEnum &type)
Definition: IAxisInfo.h:55
virtual bool getEncodersTimed(double *encs, double *time)=0
Read the instantaneous acceleration of all axes.
virtual bool getEncoderSpeeds(double *spds)=0
Read the instantaneous speed of all axes.
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).
A container for a device driver.
Definition: PolyDriver.h:23
The Node class.
Definition: Node.h:23
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...
A class for storing options and configuration information.
Definition: Property.h:33
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Property.cpp:1051
std::string toString() const override
Return a standard text representation of the content of the object.
Definition: Property.cpp:1069
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
Definition: Property.cpp:1063
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition: Property.cpp:1015
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition: Property.cpp:1041
void unput(const std::string &key)
Remove the association from the given key to a value, if present.
Definition: Property.cpp:1046
void close() override
Stop port activity.
Definition: Publisher.h:84
bool topic(const std::string &name)
Set topic to publish to.
Definition: Publisher.h:63
void interrupt() override
Interrupt any current reads or writes attached to the port.
Definition: Publisher.h:90
void write(bool forceStrict=false)
Write the current object being returned by Publisher::prepare.
Definition: Publisher.h:148
A base class for nested structures that can be searched.
Definition: Searchable.h:63
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
virtual std::string toString() const =0
Return a standard text representation of the content of the object.
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
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
double getTime() const
Get the time stamp.
Definition: Stamp.cpp:34
virtual yarp::conf::float64_t asFloat64() const
Get 64-bit floating point value.
Definition: Value.cpp:222
virtual bool isFloat64() const
Checks if value is a 64-bit floating point number.
Definition: Value.cpp:150
virtual std::string asString() const
Get string value.
Definition: Value.cpp:234
std::vector< std::string > name
Definition: JointState.h:56
std::vector< yarp::conf::float64_t > position
Definition: JointState.h:57
std::vector< yarp::conf::float64_t > velocity
Definition: JointState.h:58
std::vector< yarp::conf::float64_t > effort
Definition: JointState.h:59
yarp::rosmsg::std_msgs::Header header
Definition: JointState.h:55
yarp::rosmsg::TickTime stamp
Definition: Header.h:45
void resize(size_t size) override
Resize the vector.
Definition: Vector.h:220
iterator begin() noexcept
Returns an iterator to the beginning of the VectorOf.
Definition: Vector.h:453
T * data()
Return a pointer to the first element of the vector.
Definition: Vector.h:205
iterator end() noexcept
Returns an iterator to the end of the VectorOf.
Definition: Vector.h:460
#define yCInfo(component,...)
Definition: LogComponent.h:171
#define yCError(component,...)
Definition: LogComponent.h:213
#define yCAssert(component, x)
Definition: LogComponent.h:240
#define yCWarning(component,...)
Definition: LogComponent.h:192
#define yCDebug(component,...)
Definition: LogComponent.h:128
For streams capable of holding different kinds of content, check what they actually have.
@ VOCAB_JOINTTYPE_REVOLUTE
Definition: IAxisInfo.h:24
An interface to the operating system, including Port based communication.
The main, catch-all namespace for YARP.
Definition: dirs.h:16
#define YARP_UNUSED(var)
Definition: api.h:162
double convertDegreesToRadians(double degrees)
convert degrees to radiants for ROS messages
Definition: yarpRosHelper.h:27