YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
ControlBoard_nws_ros2.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2023 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
6#ifndef _USE_MATH_DEFINES
7#define _USE_MATH_DEFINES
8#endif
9
11
12#include <chrono>
13#include <functional>
14#include <memory>
15#include <string>
16#include <cmath>
17
19#include <yarp/os/LogStream.h>
20#include <Ros2Utils.h>
21#include <rcutils/logging_macros.h>
22
23using namespace std::chrono_literals;
24using namespace yarp::os;
25using namespace yarp::dev;
26using namespace yarp::sig;
27
28namespace {
29YARP_LOG_COMPONENT(CONTROLBOARD_ROS2, "yarp.ros2.controlBoard_nws_ros2", yarp::os::Log::TraceType);
30
31
33inline double convertDegreesToRadians(double degrees)
34{
35 return degrees / 180.0 * M_PI;
36}
37
38}
39
40
45
46void ControlBoard_nws_ros2::closePorts()
47{
48 // FIXME
49 yCWarning(CONTROLBOARD_ROS2, "FIXME: closePorts() is not implemented yet!");
50 YARP_UNUSED(this);
51}
52
54{
55 if(m_spinner){
56 if(m_spinner->isRunning()){
57 m_spinner->stop();
58 }
59 }
60 // Ensure that the device is not running
61 if (isRunning()) {
62 stop();
63 }
64
65 closeDevice();
66 closePorts();
67
68 return true;
69}
70
71
73{
74 parseParams(config);
76 m_jointStateTopicName = m_topic_name;
77 m_publisherJointStates = m_node->create_publisher<sensor_msgs::msg::JointState>(m_jointStateTopicName, 10);
78 m_jointControlModeTopicName = m_topic_name + "/controlModes";
79 m_publisherControlModes = m_node->create_publisher<std_msgs::msg::Int8MultiArray>(m_jointControlModeTopicName, 10);
80
81 return true;
82}
83
84
85bool ControlBoard_nws_ros2::initRos2Control(const std::string& name){
86
87 m_posTopicName = name+"/position";
88 m_posDirTopicName = name+"/position_direct";
89 m_velTopicName = name+"/velocity";
90 m_getModesSrvName = name+"/get_modes";
91 m_setModesSrvName = name+"/set_modes";
92 m_getVelocitySrvName = name+"/get_velocity";
93 m_getPositionSrvName = name+"/get_position";
94 m_getAvailableModesSrvName = name+"/get_available_modes";
95 m_getJointsNamesSrvName = name+"/get_joints_names";
96
97 // Creating topics ------------------------------------------------------------------------------------------------- //
98
99 if(m_iPositionControl){
100 m_posSubscription = m_node->create_subscription<yarp_control_msgs::msg::Position>(m_posTopicName, 10,
101 std::bind(&ControlBoard_nws_ros2::positionTopic_callback,
102 this, std::placeholders::_1));
103 if(!m_posSubscription){
104 yCError(CONTROLBOARD_ROS2) << "Could not initialize the Position msg subscription";
105 RCLCPP_ERROR(m_node->get_logger(),"Could not initialize the Position msg subscription");
106
107 return false;
108 }
109 }
110 if(m_iPositionDirect){
111 m_posDirectSubscription = m_node->create_subscription<yarp_control_msgs::msg::PositionDirect>(m_posDirTopicName, 10,
112 std::bind(&ControlBoard_nws_ros2::positionDirectTopic_callback,
113 this, std::placeholders::_1));
114 if(!m_posDirectSubscription){
115 yCError(CONTROLBOARD_ROS2) << "Could not initialize the Position direct msg subscription";
116 RCLCPP_ERROR(m_node->get_logger(),"Could not initialize the Position direct msg subscription");
117
118 return false;
119 }
120 }
121 if(m_iVelocityControl){
122 m_velSubscription = m_node->create_subscription<yarp_control_msgs::msg::Velocity>(m_velTopicName, 10,
123 std::bind(&ControlBoard_nws_ros2::velocityTopic_callback,
124 this, std::placeholders::_1));
125 if(!m_velSubscription){
126 yCError(CONTROLBOARD_ROS2) << "Could not initialize the Velocity msg subscription";
127 RCLCPP_ERROR(m_node->get_logger(),"Could not initialize the Velocity msg subscription");
128
129 return false;
130 }
131 }
132
133 // Creating services ----------------------------------------------------------------------------------------------- //
134
135 if(!m_iControlMode){
136 return true;
137 }
138
141 qos.depth=10;
142 rmw_time_t time;
143 time.sec=10000;
144 time.nsec = 0;
145 qos.deadline= time;
146 qos.lifespan=time;
147 qos.liveliness_lease_duration=time;
151 qos.avoid_ros_namespace_conventions = true;
152 m_getControlModesSrv = m_node->create_service<yarp_control_msgs::srv::GetControlModes>(m_getModesSrvName,
153 std::bind(&ControlBoard_nws_ros2::getControlModesCallback,
154 this,std::placeholders::_1,std::placeholders::_2,
155 std::placeholders::_3));
156 if(!m_getControlModesSrv){
157 yCError(CONTROLBOARD_ROS2) << "Could not initialize the GetControlModes service";
158 RCLCPP_ERROR(m_node->get_logger(),"Could not initialize the GetControlModes service");
159
160 return false;
161 }
162 m_getPositionSrv = m_node->create_service<yarp_control_msgs::srv::GetPosition>(m_getPositionSrvName,
163 std::bind(&ControlBoard_nws_ros2::getPositionCallback,
164 this,std::placeholders::_1,std::placeholders::_2,
165 std::placeholders::_3));
166 if(!m_getPositionSrv){
167 yCError(CONTROLBOARD_ROS2) << "Could not initialize the GetPosition service";
168 RCLCPP_ERROR(m_node->get_logger(),"Could not initialize the GetPosition service");
169
170 return false;
171 }
172 m_getVelocitySrv = m_node->create_service<yarp_control_msgs::srv::GetVelocity>(m_getVelocitySrvName,
173 std::bind(&ControlBoard_nws_ros2::getVelocityCallback,
174 this,std::placeholders::_1,std::placeholders::_2,
175 std::placeholders::_3));
176 if(!m_getVelocitySrv){
177 yCError(CONTROLBOARD_ROS2) << "Could not initialize the GetVelocity service";
178 RCLCPP_ERROR(m_node->get_logger(),"Could not initialize the GetVelocity service");
179
180 return false;
181 }
182 m_setControlModesSrv = m_node->create_service<yarp_control_msgs::srv::SetControlModes>(m_setModesSrvName,
183 std::bind(&ControlBoard_nws_ros2::setControlModesCallback,
184 this,std::placeholders::_1,std::placeholders::_2,
185 std::placeholders::_3));
186 if(!m_setControlModesSrv){
187 yCError(CONTROLBOARD_ROS2) << "Could not initialize the SetControlModes service";
188 RCLCPP_ERROR(m_node->get_logger(),"Could not initialize the SetControlModes service");
189
190 return false;
191 }
192 m_getAvailableModesSrv = m_node->create_service<yarp_control_msgs::srv::GetAvailableControlModes>(m_getAvailableModesSrvName,
193 std::bind(&ControlBoard_nws_ros2::getAvailableModesCallback,
194 this,std::placeholders::_1,std::placeholders::_2,
195 std::placeholders::_3));
196 if(!m_getAvailableModesSrv){
197 yCError(CONTROLBOARD_ROS2) << "Could not initialize the GetAvailableModes service";
198 RCLCPP_ERROR(m_node->get_logger(),"Could not initialize the GetAvailableModes service");
199
200 return false;
201 }
202 m_getJointsNamesSrv = m_node->create_service<yarp_control_msgs::srv::GetJointsNames>(m_getJointsNamesSrvName,
203 std::bind(&ControlBoard_nws_ros2::getJointsNamesCallback,
204 this,std::placeholders::_1,std::placeholders::_2,
205 std::placeholders::_3));
206 if(!m_getJointsNamesSrv){
207 yCError(CONTROLBOARD_ROS2) << "Could not initialize the GetJointsNames service";
208 RCLCPP_ERROR(m_node->get_logger(),"Could not initialize the GetJointsNames service");
209
210 return false;
211 }
212
213 m_spinner = new Ros2Spinner(m_node);
214 if (!m_spinner){
215 yCError(CONTROLBOARD_ROS2) << "Could not initialize the GetJointsNames service";
216 RCLCPP_ERROR(m_node->get_logger(),"Could not initialize the GetJointsNames service");
217
218 return false;
219 }
220
221 std::string tmpName;
222 for(size_t i=0; i<m_subdevice_joints; i++){
223 if(!m_iAxisInfo->getAxisName(i,tmpName)){
224 yCError(CONTROLBOARD_ROS2) << "Error retrieving axis" << i << "name. For this device to work, every joint needs a name";
225
226 return false;
227 }
228 m_quickJointRef[tmpName] = i;
229 }
230
231 return true;
232}
233
234
235bool ControlBoard_nws_ros2::setDevice(yarp::dev::DeviceDriver* driver)
236{
238
239 // Save the pointer and subDeviceOwned
240 m_subdevice_ptr = driver;
241
242 m_subdevice_ptr->view(m_iPositionControl);
243 if (!m_iPositionControl) {
244 yCError(CONTROLBOARD_ROS2, "<%s - %s>: IPositionControl interface was not found in attached device.", m_node_name.c_str(), m_topic_name.c_str());
245 }
246
247 m_subdevice_ptr->view(m_iPositionDirect);
248 if (!m_iPositionDirect) {
249 yCError(CONTROLBOARD_ROS2, "<%s - %s>: IPositionDirect interface was not found in attached device.", m_node_name.c_str(), m_posTopicName.c_str());
250 }
251
252 m_subdevice_ptr->view(m_iVelocityControl);
253 if (!m_iVelocityControl) {
254 yCError(CONTROLBOARD_ROS2, "<%s - %s>: IVelocityControl interface was not found in attached device.", m_node_name.c_str(), m_posTopicName.c_str());
255 }
256
257 m_subdevice_ptr->view(m_iControlMode);
258 if (!m_iControlMode) {
259 yCError(CONTROLBOARD_ROS2, "<%s - %s>: IControlMode interface was not found in attached device.", m_node_name.c_str(), m_posTopicName.c_str());
260 }
261
262 m_subdevice_ptr->view(m_iEncodersTimed);
263 if (!m_iEncodersTimed) {
264 yCError(CONTROLBOARD_ROS2, "<%s - %s>: IEncodersTimed interface was not found in attached device. Quitting", m_node_name.c_str(), m_topic_name.c_str());
265 return false;
266 }
267
268 m_subdevice_ptr->view(m_iTorqueControl);
269 if (!m_iTorqueControl) {
270 yCWarning(CONTROLBOARD_ROS2, "<%s - %s>: ITorqueControl interface was not found in attached device.", m_node_name.c_str(), m_topic_name.c_str());
271 }
272
273 m_subdevice_ptr->view(m_iAxisInfo);
274 if (!m_iAxisInfo) {
275 yCError(CONTROLBOARD_ROS2, "<%s - %s>: IAxisInfo interface was not found in attached device. Quitting", m_node_name.c_str(), m_topic_name.c_str());
276 return false;
277 }
278
279 // Get the number of controlled joints
280 int tmp_axes;
281 if (!m_iEncodersTimed->getAxes(&tmp_axes)) {
282 yCError(CONTROLBOARD_ROS2, "<%s - %s>: Failed to get axes number for attached device ", m_node_name.c_str(), m_topic_name.c_str());
283 return false;
284 }
285 if (tmp_axes <= 0) {
286 yCError(CONTROLBOARD_ROS2, "<%s - %s>: attached device has an invalid number of joints (%d)", m_node_name.c_str(), m_topic_name.c_str(), tmp_axes);
287 return false;
288 }
289 m_subdevice_joints = static_cast<size_t>(tmp_axes);
290 m_times.resize(m_subdevice_joints);
291 m_ros_struct.name.resize(m_subdevice_joints);
292 m_ros_struct.position.resize(m_subdevice_joints);
293 m_ros_struct.velocity.resize(m_subdevice_joints);
294 m_ros_struct.effort.resize(m_subdevice_joints);
295
296 if (!updateAxisName()) {
297 return false;
298 }
299
300 return true;
301}
302
303
304void ControlBoard_nws_ros2::closeDevice()
305{
306 m_subdevice_ptr = nullptr;
307 m_subdevice_joints = 0;
308
309 m_times.clear();
310
311 // Clear all interfaces
312 m_iPositionControl = nullptr;
313 m_iEncodersTimed = nullptr;
314 m_iTorqueControl = nullptr;
315 m_iAxisInfo = nullptr;
316}
317
319{
320 if (!setDevice(poly)) {
321 return false;
322 }
323
325 if (!start()) {
326 yCError(CONTROLBOARD_ROS2) << "Error starting thread";
327 return false;
328 }
329
330 if(!m_msgs_name.empty())
331 {
332 if (m_msgs_name[0] != '/') {
334 }
335 if(!initRos2Control(m_msgs_name)){
336 yCError(CONTROLBOARD_ROS2) << "Error initializing the ROS2 control related topics and services";
337 RCLCPP_ERROR(m_node->get_logger(),"Error initializing the ROS2 control related topics and services");
338 return false;
339 }
340 }
341
342 if(m_spinner){
343 if(!m_spinner->start()){
344 yCError(CONTROLBOARD_ROS2) << "Error starting the spinner";
345 }
346 }
347
348 return true;
349}
350
352{
353 // Ensure that the device is not running
354 if (isRunning()) {
355 stop();
356 }
357
358 closeDevice();
359
360 return true;
361}
362
363bool ControlBoard_nws_ros2::updateAxisName()
364{
365 // IMPORTANT!! This function has to be called BEFORE the thread starts,
366 // the name has to be correct right from the first message!!
367
368 yCAssert(CONTROLBOARD_ROS2, m_iAxisInfo);
369
370 std::vector<std::string> tmpVect;
371 for (size_t i = 0; i < m_subdevice_joints; i++) {
372 std::string tmp;
373 bool ret = m_iAxisInfo->getAxisName(i, tmp);
374 if (!ret) {
375 yCError(CONTROLBOARD_ROS2, "Joint name for axis %zu not found!", i);
376 return false;
377 }
378 tmpVect.emplace_back(tmp);
379 }
380
381 yCAssert(CONTROLBOARD_ROS2, tmpVect.size() == m_subdevice_joints);
382
383 m_jointNames = tmpVect;
384
385 return true;
386}
387
389{
390 yCAssert(CONTROLBOARD_ROS2, m_iEncodersTimed);
391 yCAssert(CONTROLBOARD_ROS2, m_iAxisInfo);
392
393 bool positionsOk = m_iEncodersTimed->getEncodersTimed(m_ros_struct.position.data(), m_times.data());
395
396 bool speedsOk = m_iEncodersTimed->getEncoderSpeeds(m_ros_struct.velocity.data());
398
399 if (m_iTorqueControl) {
400 bool torqueOk = m_iTorqueControl->getTorques(m_ros_struct.effort.data());
402 }
403
404 // Update the port envelope time by averaging all timestamps
405 m_time.update(std::accumulate(m_times.begin(), m_times.end(), 0.0) / m_subdevice_joints);
407
408 // Data from HW have been gathered few lines before
410 for (size_t i = 0; i < m_subdevice_joints; i++) {
411 m_iAxisInfo->getJointType(i, jType);
413 m_ros_struct.position[i] = convertDegreesToRadians(m_ros_struct.position[i]);
414 m_ros_struct.velocity[i] = convertDegreesToRadians(m_ros_struct.velocity[i]);
415 }
416 }
417
418 m_ros_struct.name = m_jointNames;
419 m_ros_struct.header.stamp.sec = int(averageTime.getTime()); // FIXME
420 m_ros_struct.header.stamp.nanosec = static_cast<int>(1000000000 * (averageTime.getTime() - int(averageTime.getTime()))); // FIXME
421
422// m_ros_struct.header.stamp = m_node->get_clock()->now(); //@@@@@@@@@@@ FIXME: averageTime.getTime();
423// m_ros_struct.header.frame_id = m_frame_id; // FIXME
424
425
426 // FIXME
427 ++m_counter;
428// m_ros_struct.header.seq = m_counter++;
429
430 m_publisherJointStates->publish(m_ros_struct);
431
432
433 //get and publish Control Modes
434 std::vector<int> modes_array(m_subdevice_joints);
435 m_iControlMode->getControlModes(modes_array.data());
436
437 auto modes = std_msgs::msg::Int8MultiArray();
438 modes.data.resize(m_subdevice_joints);
439 for (size_t i = 0; i < m_subdevice_joints; i++) {
440 modes.data[i]=modes_array[i];
441 }
442 m_publisherControlModes->publish(modes);
443}
#define M_PI
bool ret
double convertDegreesToRadians(double degrees)
bool parseParams(const yarp::os::Searchable &config) override
Parse the DeviceDriver parameters.
bool open(yarp::os::Searchable &prop) override
Open the DeviceDriver.
void run() override
Loop function.
bool attach(yarp::dev::PolyDriver *poly) override
Attach to another object.
bool detach() override
Detach the object (you must have first called attach).
bool close() override
Close the DeviceDriver.
static rclcpp::Node::SharedPtr createNode(std::string name)
Definition Ros2Utils.cpp:9
Interface implemented by all device drivers.
bool view(T *&x)
Get an interface to the device driver.
virtual bool getAxisName(int axis, std::string &name)=0
virtual bool getJointType(int axis, yarp::dev::JointTypeEnum &type)
Definition IAxisInfo.h:63
virtual bool getControlModes(int *modes)=0
Get the current control mode (multiple joints).
virtual bool getEncodersTimed(double *encs, double *time)=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 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
A mini-server for performing network communication in the background.
@ TraceType
Definition Log.h:92
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 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
bool stop()
Stop the thread.
Definition Thread.cpp:81
bool isRunning()
Returns true if the thread is running (Thread::start has been called successfully and the thread has ...
Definition Thread.cpp:105
bool start()
Start the new thread running.
Definition Thread.cpp:93
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 yCAssert(component, x)
#define yCWarning(component,...)
#define YARP_LOG_COMPONENT(name,...)
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