YARP
Yet Another Robot Platform
AnalogWrapper.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
6#include "AnalogWrapper.h"
7#include <sstream>
8#include <iostream>
11#include <yarp/os/LogStream.h>
12
13using namespace yarp::sig;
14using namespace yarp::dev;
15using namespace yarp::os;
16
17
18YARP_LOG_COMPONENT(ANALOGWRAPPER, "yarp.devices.AnalogWrapper")
19
20
25 public yarp::os::PortReader
26{
27 yarp::dev::IAnalogSensor* is; // analog sensor to calibrate, when required
28 yarp::os::Port rpcPort; // rpc port related to the analog sensor
29
30public:
31 AnalogServerHandler(const char* n);
33
34 void setInterface(yarp::dev::IAnalogSensor *is);
35
36 bool _handleIAnalog(yarp::os::Bottle &cmd, yarp::os::Bottle &reply);
37
38 bool read(yarp::os::ConnectionReader& connection) override;
39};
40
41
48{
49public:
51 std::string port_name; // the complete name of the port
52 int offset; // an offset, the port is mapped starting from this taxel
53 int length; // length of the output vector of the port (-1 for max length)
57};
58
59
65AnalogServerHandler::AnalogServerHandler(const char* n) : is(nullptr)
66{
67 rpcPort.open(n);
68 rpcPort.setReader(*this);
69}
70
72{
73 rpcPort.close();
74 is = nullptr;
75}
76
78{
79 this->is = is;
80}
81
83{
84 if (is == nullptr) {
85 return false;
86 }
87
88 const size_t msgsize=cmd.size();
89 int ret=IAnalogSensor::AS_ERROR;
90
91 int code=cmd.get(1).asVocab32();
92 switch (code)
93 {
94 case VOCAB_CALIBRATE:
95 if (msgsize == 2) {
96 ret = is->calibrateSensor();
97 } else if (msgsize > 2) {
98 size_t offset = 2;
99 Vector v(msgsize - offset);
100 for (unsigned int i = 0; i < v.size(); i++) {
101 v[i] = cmd.get(i + offset).asFloat64();
102 }
103 ret = is->calibrateSensor(v);
104 }
105 break;
107 if (msgsize==3)
108 {
109 int ch=cmd.get(2).asInt32();
110 ret=is->calibrateChannel(ch);
111 }
112 else if (msgsize==4)
113 {
114 int ch=cmd.get(2).asInt32();
115 double v=cmd.get(3).asFloat64();
116 ret=is->calibrateChannel(ch, v);
117 }
118 break;
119 default:
120 return false;
121 }
122
123 reply.addInt32(ret);
124 return true;
125}
126
128{
131 bool ok=in.read(connection);
132 if (!ok) {
133 return false;
134 }
135
136 // parse in, prepare out
137 int code = in.get(0).asVocab32();
138 bool ret=false;
139 if (code==VOCAB_IANALOG)
140 {
141 ret=_handleIAnalog(in, out);
142 }
143
144 if (!ret)
145 {
146 out.clear();
148 }
149
150 yarp::os::ConnectionWriter *returnToSender = connection.getWriter();
151 if (returnToSender!=nullptr) {
152 out.write(*returnToSender);
153 }
154 return true;
155}
156
157
165 offset(0),
166 length(0)
167{}
168
170{
171 this->length = alt.length;
172 this->offset = alt.offset;
173 this->port_name = alt.port_name;
174}
175
177{
178 this->length = alt.length;
179 this->offset = alt.offset;
180 this->port_name = alt.port_name;
181 return *this;
182}
183
184 // closing anonimous namespace
185
186
192bool AnalogWrapper::createPort(const char* name, int rate)
193{
194 analogSensor_p=nullptr;
195 analogPorts.resize(1);
196 analogPorts[0].offset = 0;
197 analogPorts[0].length = -1; // max length
198 analogPorts[0].port_name = std::string(name);
199 setHandlers();
200 setPeriod(rate / 1000.0);
201 return true;
202}
203
204bool AnalogWrapper::createPorts(const std::vector<AnalogPortEntry>& _analogPorts, int rate)
205{
206 analogSensor_p=nullptr;
207 this->analogPorts=_analogPorts;
208 setHandlers();
209 setPeriod(rate / 1000.0);
210 return true;
211}
212
215{
216 // init ROS struct
217 frame_idVec.resize(1);
218 frame_idVec.at(0) = "";
219 rosTopicNamesVec.resize(1);
220 rosTopicNamesVec.at(0) = "";
221 rosMsgCounterVec.resize(1);
222 rosMsgCounterVec.at(0) = 0;
223}
224
226{
228 close();
229 _rate = DEFAULT_THREAD_PERIOD;
230 analogSensor_p = nullptr;
231}
232
233void AnalogWrapper::setHandlers()
234{
235 for(auto& analogPort : analogPorts)
236 {
237 std::string rpcPortName = analogPort.port_name;
238 rpcPortName += "/rpc:i";
239 auto* ash = new AnalogServerHandler(rpcPortName.c_str());
240 handlers.push_back(ash);
241 }
242}
243
244void AnalogWrapper::removeHandlers()
245{
246 for(auto& handler : handlers)
247 {
248 if (handler != nullptr)
249 {
250 delete handler;
251 handler = nullptr;
252 }
253 }
254 handlers.clear();
255}
256
257bool AnalogWrapper::openAndAttachSubDevice(Searchable &prop)
258{
259 Property p;
260 subDeviceOwned = new PolyDriver;
261 p.fromString(prop.toString());
262
263// p.setMonitor(prop.getMonitor(), "subdevice"); // pass on any monitoring
264 p.unput("device");
265 p.put("device", prop.find("subdevice").asString()); // subdevice was already checked before
266
267 // if errors occurred during open, quit here.
268 yCDebug(ANALOGWRAPPER, "opening AnalogWrapper subdevice...");
269 subDeviceOwned->open(p);
270
271 if (!subDeviceOwned->isValid())
272 {
273 yCError(ANALOGWRAPPER, "opening AnalogWrapper subdevice... FAILED\n");
274 return false;
275 }
276
277 subDeviceOwned->view(analogSensor_p);
278
279 if (analogSensor_p == nullptr)
280 {
281 yCError(ANALOGWRAPPER, "Opening IAnalogSensor interface of AnalogWrapper subdevice... FAILED\n");
282 return false;
283 }
284
285 int chNum = analogSensor_p->getChannels();
286
287 if (chNum <= 0)
288 {
289 yCError(ANALOGWRAPPER, "Calling analog sensor has invalid channels number %d.\n", chNum);
290 return false;
291 }
292
293 attach(analogSensor_p);
294 PeriodicThread::setPeriod(_rate / 1000.0);
295 return PeriodicThread::start();
296}
297
298
299bool AnalogWrapper::openDeferredAttach(yarp::os::Searchable &prop)
300{
301 // nothing to do here?
302 if ((subDeviceOwned != nullptr) || (ownDevices == true)) {
303 yCError(ANALOGWRAPPER) << "AnalogWrapper: something wrong with the initialization.";
304 }
305 return true;
306}
307
308
313bool AnalogWrapper::attachAll(const PolyDriverList &analog2attach)
314{
315 //check if we already instantiated a subdevice previously
316 if (ownDevices) {
317 return false;
318 }
319
320 if (analog2attach.size() != 1)
321 {
322 yCError(ANALOGWRAPPER, "AnalogWrapper: cannot attach more than one device");
323 return false;
324 }
325
326 yarp::dev::PolyDriver * Idevice2attach=analog2attach[0]->poly;
327
328 if (Idevice2attach->isValid())
329 {
330 Idevice2attach->view(analogSensor_p);
331 }
332
333 if(nullptr == analogSensor_p)
334 {
335 yCError(ANALOGWRAPPER, "AnalogWrapper: subdevice passed to attach method is invalid");
336 return false;
337 }
338 attach(analogSensor_p);
339 PeriodicThread::setPeriod(_rate / 1000.0);
340 return PeriodicThread::start();
341}
342
344{
345 //check if we already instantiated a subdevice previously
346 if (ownDevices) {
347 return false;
348 }
349
350 analogSensor_p = nullptr;
351 for(unsigned int i=0; i<analogPorts.size(); i++)
352 {
353 if (handlers[i] != nullptr) {
354 handlers[i]->setInterface(analogSensor_p);
355 }
356 }
357 return true;
358}
359
361{
362 analogSensor_p=s;
363 for(unsigned int i=0; i<analogPorts.size(); i++)
364 {
365 handlers[i]->setInterface(analogSensor_p);
366 }
367 //Resize vector of read data to avoid further allocation of memory
368 //as long as the number of channels does not change
369 lastDataRead.resize((size_t)analogSensor_p->getChannels(),0.0);
370}
371
373{
374 // Set interface to NULL
375 analogSensor_p = nullptr;
376 for(unsigned int i=0; i<analogPorts.size(); i++)
377 {
378 handlers[i]->setInterface(analogSensor_p);
379 }
380}
381
383{
384 for(auto& analogPort : analogPorts)
385 {
386 // open data port
387 if (!analogPort.port.open(analogPort.port_name))
388 {
389 yCError(ANALOGWRAPPER, "AnalogWrapper: failed to open port %s", analogPort.port_name.c_str());
390 return false;
391 }
392 }
393 return true;
394}
395
396bool AnalogWrapper::checkROSParams(Searchable &config)
397{
398 // check for ROS parameter group
399 if(!config.check("ROS") )
400 {
401 useROS = ROS_disabled;
402 yCInfo(ANALOGWRAPPER) << "No ROS group found in config file ... skipping ROS initialization.";
403 return true;
404 }
405
406 yCInfo(ANALOGWRAPPER) << "ROS group was FOUND in config file.";
407
408 Bottle &rosGroup = config.findGroup("ROS");
409 if(rosGroup.isNull())
410 {
411 yCError(ANALOGWRAPPER) << sensorId << "ROS group params is not a valid group or empty";
412 useROS = ROS_config_error;
413 return false;
414 }
415
416 // check for useROS parameter
417 if(!rosGroup.check("useROS"))
418 {
419 yCError(ANALOGWRAPPER) << sensorId << " cannot find useROS parameter, mandatory when using ROS message. \n \
420 Allowed values are true, false, ROS_only";
421 useROS = ROS_config_error;
422 return false;
423 }
424 std::string ros_use_type = rosGroup.find("useROS").asString();
425 if(ros_use_type == "false")
426 {
427 yCInfo(ANALOGWRAPPER) << sensorId << "useROS topic if set to 'false'";
428 useROS = ROS_disabled;
429 return true;
430 }
431 else if(ros_use_type == "true")
432 {
433 yCInfo(ANALOGWRAPPER) << sensorId << "useROS topic if set to 'true'";
434 useROS = ROS_enabled;
435 }
436 else if(ros_use_type == "only")
437 {
438 yCInfo(ANALOGWRAPPER) << sensorId << "useROS topic if set to 'only";
439 useROS = ROS_only;
440 }
441 else
442 {
443 yCInfo(ANALOGWRAPPER) << sensorId << "useROS parameter is set to unvalid value ('" << ros_use_type << "'), supported values are 'true', 'false', 'only'";
444 useROS = ROS_config_error;
445 return false;
446 }
447
448 // check for ROS_nodeName parameter
449 if(!rosGroup.check("ROS_nodeName"))
450 {
451 yCError(ANALOGWRAPPER) << sensorId << " cannot find ROS_nodeName parameter, mandatory when using ROS message";
452 useROS = ROS_config_error;
453 return false;
454 }
455 rosNodeName = rosGroup.find("ROS_nodeName").asString(); // TODO: check name is correct
456 yCInfo(ANALOGWRAPPER) << sensorId << "rosNodeName is " << rosNodeName;
457
458 // check for ROS_topicName parameter
459 if(!rosGroup.check("ROS_topicName"))
460 {
461 yCError(ANALOGWRAPPER) << sensorId << " cannot find ROS_topicName parameter, mandatory when using ROS message";
462 useROS = ROS_config_error;
463 return false;
464 }
465
466 if(rosGroup.find("ROS_topicName").isString())
467 {
468 rosTopicNamesVec.at(0) = rosGroup.find("ROS_topicName").asString();
469 yCInfo(ANALOGWRAPPER) << sensorId << "ROS_topicName is " << rosTopicNamesVec.at(0);
470
471 }
472 else if(rosGroup.find("ROS_topicName").isList())
473 {
474 yarp::os::Bottle *rosTopicNamesBottle = rosGroup.find("ROS_topicName").asList();
475 yCInfo(ANALOGWRAPPER) << sensorId << "ROS_topicName list is " << rosTopicNamesBottle->toString();
476
477 rosTopicNamesVec.resize(rosTopicNamesBottle->size());
478 for(size_t i = 0; i < rosTopicNamesBottle->size(); i++)
479 {
480 rosTopicNamesVec.at(i) = rosTopicNamesBottle->get(i).asString();
481 }
482
483 // resize the ros msg counter vector
484 rosMsgCounterVec.resize(rosTopicNamesVec.size());
485 }
486
487 // check for ROS_msgType parameter
488 if (!rosGroup.check("ROS_msgType"))
489 {
490 yCError(ANALOGWRAPPER) << sensorId << " cannot find ROS_msgType parameter, mandatory when using ROS message";
491 useROS = ROS_config_error;
492 return false;
493 }
494 rosMsgType = rosGroup.find("ROS_msgType").asString();
495
496 // check for frame_id parameter
497 if (rosMsgType == "geometry_msgs/WrenchStamped")
498 {
499 yCInfo(ANALOGWRAPPER) << sensorId << "ROS_msgType is " << rosMsgType;
500 if (!rosGroup.check("frame_id"))
501 {
502 yCError(ANALOGWRAPPER) << sensorId << " cannot find frame_id parameter, mandatory when using ROS message";
503 useROS = ROS_config_error;
504 return false;
505 }
506
507 if(rosGroup.find("frame_id").isString())
508 {
509 frame_idVec.at(0) = rosGroup.find("frame_id").asString();
510 yCInfo(ANALOGWRAPPER) << sensorId << "frame_id is " << frame_idVec.at(0);
511
512 }
513 else if(rosGroup.find("frame_id").isList())
514 {
515 yarp::os::Bottle *frame_idBottle = rosGroup.find("frame_id").asList();
516
517 if(frame_idBottle->size() != rosTopicNamesVec.size())
518 {
519 yCError(ANALOGWRAPPER, "AnalogWrapper: mismatch between the number of ros topics and frame_ids");
520 return false;
521 }
522
523 yCInfo(ANALOGWRAPPER) << sensorId << "frame_id list is " << frame_idBottle->toString();
524
525 frame_idVec.resize(frame_idBottle->size());
526 for(size_t i = 0; i < frame_idBottle->size(); i++)
527 {
528 frame_idVec.at(i) = frame_idBottle->get(i).asString();
529 }
530 }
531
532 if(!rosGroup.check("rosOffset"))
533 {
534 yCWarning(ANALOGWRAPPER) << sensorId << "cannot find rosOffset parameter, using the default offset 0 while reading analog sensor data";
535 }
536
537 if(rosGroup.find("rosOffset").isInt32())
538 {
539 rosOffset = rosGroup.find("rosOffset").asInt32();
540 yCInfo(ANALOGWRAPPER) << sensorId << " rosOffset is " << rosOffset;
541 }
542
543 if(!rosGroup.check("rosPadding"))
544 {
545 yCWarning(ANALOGWRAPPER) << sensorId << "cannot find rosPadding parameter, using the default padding 0 while reading analog sensor data";
546 }
547
548 if(rosGroup.find("rosPadding").isInt32())
549 {
550 rosOffset = rosGroup.find("rosPadding").asInt32();
551 yCInfo(ANALOGWRAPPER) << sensorId << " rosPadding is " << rosOffset;
552 }
553 }
554 else if (rosMsgType == "sensor_msgs/JointState")
555 {
556 std::string jointName;
557 yCInfo(ANALOGWRAPPER) << sensorId << "ROS_msgType is " << rosMsgType;
558 bool oldParam = false;
559 bool newParam = false;
560
561 if(rosGroup.check("joint_names"))
562 {
563 oldParam = true;
564 jointName = "joint_names";
565 yCWarning(ANALOGWRAPPER) << sensorId << " using DEPRECATED 'joint_names' parameter. Please use 'jointNames' instead.";
566 }
567
568 if(rosGroup.check("jointNames"))
569 {
570 newParam = true;
571 jointName = "jointNames";
572 }
573
574 if(!oldParam && !newParam)
575 {
576 yCError(ANALOGWRAPPER) << sensorId << " missing 'jointNames' parameter needed when broadcasting 'sensor_msgs/JointState' message type";
577 useROS = ROS_config_error;
578 return false;
579 }
580 // Throw an error if both new and old are present
581 if(oldParam && newParam)
582 {
583 yCError(ANALOGWRAPPER) << sensorId << " found both DEPRECATED 'joint_names' and new 'jointNames' parameters. Please remove the old 'joint_names' from your config file.";
584 useROS = ROS_config_error;
585 return false;
586 }
587
588 yarp::os::Bottle& jnam = rosGroup.findGroup(jointName);
589 if(jnam.isNull())
590 {
591 yCError(ANALOGWRAPPER) << sensorId << "Cannot find 'jointNames' parameters.";
592 return false;
593 }
594
595 // Cannot check number of channels here because need to wait for the attach function
596 int joint_names_size = jnam.size()-1;
597 for (int i = 0; i < joint_names_size; i++)
598 {
599 ros_joint_names.push_back(jnam.get(i+1).asString());
600 }
601 }
602 else
603 {
604 yCError(ANALOGWRAPPER) << sensorId << "ROS_msgType '" << rosMsgType << "' not supported ";
605 return false;
606 }
607
608 return true;
609}
610
611bool AnalogWrapper::initialize_ROS()
612{
613 bool success = false;
614 switch(useROS)
615 {
616 case ROS_enabled:
617 case ROS_only:
618 {
619 rosNode = new yarp::os::Node(rosNodeName); // add a ROS node
620
621 if(rosNode == nullptr)
622 {
623 yCError(ANALOGWRAPPER) << " opening " << rosNodeName << " Node, check your yarp-ROS network configuration\n";
624 success = false;
625 break;
626 }
627
628 if (rosMsgType == "geometry_msgs/WrenchStamped")
629 {
630 rosPublisherWrenchPortVec.resize(rosTopicNamesVec.size());
631
632 for(size_t i = 0; i < rosTopicNamesVec.size(); i++)
633 {
634 if(!rosPublisherWrenchPortVec.at(i).topic(rosTopicNamesVec.at(i)))
635 {
636 yCError(ANALOGWRAPPER) << " opening " << rosTopicNamesVec.at(i) << " Topic, check your yarp-ROS network configuration\n";
637 success = false;
638 break;
639 }
640 }
641 }
642 else if (rosMsgType == "sensor_msgs/JointState")
643 {
644 if (!rosPublisherJointPort.topic(rosTopicNamesVec.at(0)))
645 {
646 yCError(ANALOGWRAPPER) << " opening " << rosTopicNamesVec.at(0) << " Topic, check your yarp-ROS network configuration\n";
647 success = false;
648 break;
649 }
650 }
651 else
652 {
653 yCError(ANALOGWRAPPER) << sensorId << "Invalid rosMsgType: " << rosMsgType;
654 }
655
656 yCInfo(ANALOGWRAPPER) << sensorId << "ROS initialized successfully, node:" << rosNodeName << " and opened the following topics: ";
657 for(size_t i = 0; i < rosTopicNamesVec.size(); i++)
658 {
659 yCInfo(ANALOGWRAPPER) << rosTopicNamesVec.at(0);
660 }
661
662 success = true;
663 } break;
664
665 case ROS_disabled:
666 {
667 yCInfo(ANALOGWRAPPER) << sensorId << ": no ROS initialization required";
668 success = true;
669 } break;
670
671 case ROS_config_error:
672 {
673 yCError(ANALOGWRAPPER) << sensorId << " ROS parameter are not correct, check your configuration file";
674 success = false;
675 } break;
676
677 default:
678 {
679 yCError(ANALOGWRAPPER) << sensorId << " something went wrong with ROS configuration, we should never be here!!!";
680 success = false;
681 } break;
682 }
683 return success;
684}
685
687{
688 yCWarning(ANALOGWRAPPER) << "The 'AnalogWrapper' device is deprecated.";
689 yCWarning(ANALOGWRAPPER) << "Possible alternatives, depending on the specific type sensor data, are:";
690 yCWarning(ANALOGWRAPPER) << "'MultipleAnalogSensorsRemapper`+`MultipleAnalogSensorsServer`, `PoseStampedRosPublisher`, `WrenchStampedRosPublisher`,`IMURosPublisher`,etc.";
691 yCWarning(ANALOGWRAPPER) << "The old device is no longer supported, and it will be deprecated in YARP 3.7 and removed in YARP 4.";
692 yCWarning(ANALOGWRAPPER) << "Please update your scripts.";
693
694 Property params;
695 params.fromString(config.toString());
696 yCTrace(ANALOGWRAPPER) << "AnalogWrapper params are: " << config.toString();
697
698 if (!config.check("period"))
699 {
700 yCError(ANALOGWRAPPER) << "AnalogWrapper: missing 'period' parameter. Check you configuration file\n";
701 return false;
702 }
703 else
704 {
705 _rate = config.find("period").asInt32();
706 }
707
708 if (config.check("deviceId"))
709 {
710 yCError(ANALOGWRAPPER) << "AnalogWrapper: the parameter 'deviceId' has been removed, please use parameter 'name' instead. \n"
711 << "e.g. In the FT wrapper configuration files of your robot, replace '<param name=""deviceId""> left_arm </param>' \n"
712 << "with '/icub/left_arm/analog:o' ";
713 return false;
714 }
715
716 if (!config.check("name"))
717 {
718 yCError(ANALOGWRAPPER) << "AnalogWrapper: missing 'name' parameter. Check you configuration file; it must be like:\n"
719 " name: full name of the port, like /robotName/deviceId/sensorType:o";
720 return false;
721 }
722 else
723 {
724 streamingPortName = config.find("name").asString();
725 }
726
727 if(!checkROSParams(config) )
728 {
729 yCError(ANALOGWRAPPER) << sensorId << "ROS parameter are not correct, check your configuration file";
730 return false;
731 }
732
733 if(!initialize_YARP(config) )
734 {
735 yCError(ANALOGWRAPPER) << sensorId << "Error initializing YARP ports";
736 return false;
737 }
738
739 if(!initialize_ROS() )
740 {
741 yCError(ANALOGWRAPPER) << sensorId << "Error initializing ROS topics";
742 return false;
743 }
744
745 // check if we need to create subdevice or if they are
746 // passed later on thorugh attachAll()
747 if(config.check("subdevice"))
748 {
749 ownDevices=true;
750 if(! openAndAttachSubDevice(config))
751 {
752 yCError(ANALOGWRAPPER, "AnalogWrapper: error while opening subdevice\n");
753 return false;
754 }
755 }
756 else
757 {
758 ownDevices=false;
759 if (!openDeferredAttach(config)) {
760 return false;
761 }
762 }
763
764 return true;
765}
766
767bool AnalogWrapper::initialize_YARP(yarp::os::Searchable &params)
768{
769 switch(useROS)
770 {
771 case ROS_only:
772 {
773 yCInfo(ANALOGWRAPPER) << sensorId << " No YARP initialization required";
774 return true;
775 } break;
776
777 default:
778 {
779 // Create the list of ports
780 // port names are optional, do not check for correctness.
781 if(!params.check("ports"))
782 {
783 // if there is no "ports" section open only 1 port and use name as is.
784 if (Network::exists(streamingPortName + "/rpc:i") || Network::exists(streamingPortName))
785 {
786 yCError(ANALOGWRAPPER) << "AnalogWrapper: unable to open the analog server, address conflict";
787 return false;
788 }
789 createPort((streamingPortName ).c_str(), _rate );
790 // since createPort always return true, check the port is really been opened is done here
791 if (!Network::exists(streamingPortName + "/rpc:i")) {
792 return false;
793 }
794 }
795 else
796 {
797 Bottle *ports=params.find("ports").asList();
798
799 Value &deviceChannels = params.find("channels");
800 if (deviceChannels.isNull())
801 {
802 yCError(ANALOGWRAPPER, "AnalogWrapper: 'channels' parameters was not found in config file.");
803 return false;
804 }
805
806 int nports=ports->size();
807 int sumOfChannels = 0;
808 std::vector<AnalogPortEntry> tmpPorts;
809 tmpPorts.resize(nports);
810
811 for(size_t k=0; k<ports->size(); k++)
812 {
813 Bottle parameters=params.findGroup(ports->get(k).asString());
814
815 if (parameters.size()!=5)
816 {
817 yCError(ANALOGWRAPPER) << "AnalogWrapper: check skin port parameters in part description, I was expecting "
818 << ports->get(k).asString().c_str() << " followed by four integers";
819 yCError(ANALOGWRAPPER) << " your param is " << parameters.toString();
820 return false;
821 }
822
823 if (Network::exists(streamingPortName + "/" + std::string(ports->get(k).asString()) + "/rpc:i")
824 || Network::exists(streamingPortName + "/" + std::string(ports->get(k).asString())))
825 {
826 yCError(ANALOGWRAPPER) << "AnalogWrapper: unable to open the analog server, address conflict";
827 return false;
828 }
829 int wBase=parameters.get(1).asInt32();
830 int wTop=parameters.get(2).asInt32();
831 int base=parameters.get(3).asInt32();
832 int top=parameters.get(4).asInt32();
833
834 yCDebug(ANALOGWRAPPER) << "--> " << wBase << " " << wTop << " " << base << " " << top;
835
836 //check consistenty
837 if(wTop-wBase != top-base){
838 yCError(ANALOGWRAPPER) << "AnalogWrapper: numbers of mapped taxels do not match, check "
839 << ports->get(k).asString().c_str() << " port parameters in part description";
840 return false;
841 }
842 int portChannels = top-base+1;
843
844 tmpPorts[k].length = portChannels;
845 tmpPorts[k].offset = wBase;
846 yCDebug(ANALOGWRAPPER) << "opening port " << ports->get(k).asString().c_str();
847 tmpPorts[k].port_name = streamingPortName+ "/" + std::string(ports->get(k).asString());
848
849 sumOfChannels+=portChannels;
850 }
851 createPorts(tmpPorts, _rate);
852
853 if (sumOfChannels!=deviceChannels.asInt32())
854 {
855 yCError(ANALOGWRAPPER) << "AnalogWrapper: Total number of mapped taxels does not correspond to total taxels";
856 return false;
857 }
858 }
859 } break;
860 }
861 return true;
862}
863
865{
866 for(auto& analogPort : analogPorts)
867 {
868 analogPort.port.interrupt();
869 analogPort.port.close();
870 }
871}
872
874{
875 int first, last, ret;
876
877 if (analogSensor_p!=nullptr)
878 {
879 ret=analogSensor_p->read(lastDataRead);
880
882 {
883 if (lastDataRead.size()>0)
884 {
885 if(useROS != ROS_only)
886 {
887 lastStateStamp.update();
888 // send the data on the port(s), splitting them as specified in the config file
889 for(auto& analogPort : analogPorts)
890 {
891 yarp::sig::Vector &pv = analogPort.port.prepare();
892 first = analogPort.offset;
893 if (analogPort.length == -1) { // read the max length available
894 last = lastDataRead.size()-1;
895 } else {
896 last = analogPort.offset + analogPort.length - 1;
897 }
898
899 // check vector limit
900 if(last>=(int)lastDataRead.size()){
901 yCError(ANALOGWRAPPER, )<<"AnalogWrapper: error while sending analog sensor output on port "<< analogPort.port_name
902 <<" Vector size expected to be at least "<<last<<" whereas it is "<< lastDataRead.size();
903 continue;
904 }
905 pv = lastDataRead.subVector(first, last);
906
907 analogPort.port.setEnvelope(lastStateStamp);
908 analogPort.port.write();
909 }
910 }
911
912 if (useROS != ROS_disabled && rosMsgType == "geometry_msgs/WrenchStamped")
913 {
914 std::vector<yarp::rosmsg::geometry_msgs::WrenchStamped> rosDataVec;
915 rosDataVec.resize(rosPublisherWrenchPortVec.size());
916
917 for(size_t i = 0; i < rosDataVec.size(); i++)
918 {
919 rosDataVec.at(i).header.seq = rosMsgCounterVec.at(i)++;
920 rosDataVec.at(i).header.stamp = yarp::os::Time::now();
921 rosDataVec.at(i).header.frame_id = frame_idVec.at(i);
922
923 rosDataVec.at(i).wrench.force.x = lastDataRead[(rosOffset + 6 + rosPadding) * i + 0];
924 rosDataVec.at(i).wrench.force.y = lastDataRead[(rosOffset + 6 + rosPadding) * i + 1];
925 rosDataVec.at(i).wrench.force.z = lastDataRead[(rosOffset + 6 + rosPadding) * i + 2];
926
927 rosDataVec.at(i).wrench.torque.x = lastDataRead[(rosOffset + 6 + rosPadding) * i + 3];
928 rosDataVec.at(i).wrench.torque.y = lastDataRead[(rosOffset + 6 + rosPadding) * i + 4];
929 rosDataVec.at(i).wrench.torque.z = lastDataRead[(rosOffset + 6 + rosPadding) * i + 5];
930
931 rosPublisherWrenchPortVec.at(i).write(rosDataVec.at(i));
932 }
933 }
934 else if (useROS != ROS_disabled && rosMsgType == "sensor_msgs/JointState")
935 {
937 size_t data_size = lastDataRead.size();
938 rosData.name.resize(data_size);
939 rosData.position.resize(data_size);
940 rosData.velocity.resize(data_size);
941 rosData.effort.resize(data_size);
942
943 if (data_size != ros_joint_names.size())
944 {
945 yCDebug(ANALOGWRAPPER) << "Invalid jointNames size:" << data_size << "!=" << ros_joint_names.size();
946 }
947 else
948 {
949 for (size_t i = 0; i< data_size; i++)
950 {
951 //JointTypeEnum jType;
952 // if (jType == VOCAB_JOINTTYPE_REVOLUTE)
953 {
954 rosData.name[i] = ros_joint_names[i];
955 rosData.position[i] = convertDegreesToRadians(lastDataRead[i]);
956 rosData.velocity[i] = 0;
957 rosData.effort[i] = 0;
958 }
959 }
960 }
961 rosData.header.seq = rosMsgCounterVec.at(0)++;
962 rosData.header.stamp = yarp::os::Time::now();
963 rosPublisherJointPort.write(rosData);
964 }
965 }
966 else
967 {
968 yCError(ANALOGWRAPPER, "AnalogWrapper: %s: vector size non valid: %lu", sensorId.c_str(), static_cast<unsigned long> (lastDataRead.size()));
969 }
970 }
971 else
972 {
973 switch(ret)
974 {
975 case IAnalogSensor::AS_OVF:
976 yCError(ANALOGWRAPPER, "AnalogWrapper: %s: Sensor returned overflow error (code %d).", sensorId.c_str(), ret);
977 break;
978 case IAnalogSensor::AS_TIMEOUT:
979 yCError(ANALOGWRAPPER, "AnalogWrapper: %s: Sensor returned timeout error (code %d).", sensorId.c_str(), ret);
980 break;
981 case IAnalogSensor::AS_ERROR:
982 default:
983 yCError(ANALOGWRAPPER, "AnalogWrapper: %s: Sensor returned error with code %d.", sensorId.c_str(), ret);
984 break;
985 }
986 }
987 }
988}
989
991{
992 yCTrace(ANALOGWRAPPER, "AnalogWrapper::Close");
993 if (PeriodicThread::isRunning())
994 {
995 PeriodicThread::stop();
996 }
997
998 detachAll();
999 removeHandlers();
1000
1001 if(subDeviceOwned)
1002 {
1003 subDeviceOwned->close();
1004 delete subDeviceOwned;
1005 subDeviceOwned = nullptr;
1006 }
1007
1008 if(rosNode!=nullptr) {
1009 rosNode->interrupt();
1010 delete rosNode;
1011
1012 rosNode = nullptr;
1013 }
1014
1015 return true;
1016}
const yarp::os::LogComponent & ANALOGWRAPPER()
define control board standard interfaces
constexpr yarp::conf::vocab32_t VOCAB_FAILED
Definition: GenericVocabs.h:16
constexpr yarp::conf::vocab32_t VOCAB_IANALOG
Definition: IAnalogSensor.h:14
constexpr yarp::conf::vocab32_t VOCAB_CALIBRATE
constexpr yarp::conf::vocab32_t VOCAB_CALIBRATE_CHANNEL
bool ret
static void handler(int sig)
Definition: RFModule.cpp:241
constexpr double DEFAULT_THREAD_PERIOD
A yarp port that output data read from an analog sensor.
std::string port_name
AnalogPortEntry & operator=(const AnalogPortEntry &alt)
yarp::os::BufferedPort< yarp::sig::Vector > port
AnalogPortEntry()
A yarp port that output data read from an analog sensor.
Handler of the rpc port related to an analog sensor.
bool read(yarp::os::ConnectionReader &connection) override
Read this object from a network connection.
AnalogServerHandler(const char *n)
Handler of the rpc port related to an analog sensor.
void setInterface(yarp::dev::IAnalogSensor *is)
bool _handleIAnalog(yarp::os::Bottle &cmd, yarp::os::Bottle &reply)
void threadRelease() override
Release method.
void attach(yarp::dev::IAnalogSensor *s)
bool threadInit() override
Initialization method.
~AnalogWrapper() override
void run() override
Loop function.
bool open(yarp::os::Searchable &params) override
Open the DeviceDriver.
bool close() override
Close the DeviceDriver.
bool attachAll(const yarp::dev::PolyDriverList &p) override
Specify which analog sensor this thread has to read from.
bool detachAll() override
Detach the object (you must have first called attach).
bool view(T *&x)
Get an interface to the device driver.
Definition: DeviceDriver.h:88
A generic interface to sensors (gyro, a/d converters).
Definition: IAnalogSensor.h:27
virtual int calibrateSensor()=0
Calibrates the whole sensor.
virtual int read(yarp::sig::Vector &out)=0
Read a vector from the sensor.
virtual int getChannels()=0
Get the number of channels of the sensor.
virtual int calibrateChannel(int ch)=0
Calibrates one single channel.
A container for a device driver.
Definition: PolyDriver.h:23
bool close() override
Close the DeviceDriver.
Definition: PolyDriver.cpp:173
bool isValid() const
Check if device is valid.
Definition: PolyDriver.cpp:196
bool open(const std::string &txt)
Construct and configure a device by its common name.
Definition: PolyDriver.cpp:140
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:64
void addVocab32(yarp::conf::vocab32_t x)
Places a vocabulary item in the bottle, at the end of the list.
Definition: Bottle.cpp:164
size_type size() const
Gets the number of elements in the bottle.
Definition: Bottle.cpp:251
bool read(ConnectionReader &reader) override
Set the bottle's value based on input from a network connection.
Definition: Bottle.cpp:240
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:246
Bottle & findGroup(const std::string &key) const override
Gets a list corresponding to a given keyword.
Definition: Bottle.cpp:302
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition: Bottle.cpp:277
void clear()
Empties the bottle of any objects it contains.
Definition: Bottle.cpp:121
bool write(ConnectionWriter &writer) const override
Output a representation of the bottle to a network connection.
Definition: Bottle.cpp:230
void addInt32(std::int32_t x)
Places a 32-bit integer in the bottle, at the end of the list.
Definition: Bottle.cpp:140
bool isNull() const override
Checks if the object is invalid.
Definition: Bottle.cpp:370
std::string toString() const override
Gives a human-readable textual representation of the bottle.
Definition: Bottle.cpp:211
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Bottle.cpp:287
An interface for reading from a network connection.
virtual ConnectionWriter * getWriter()=0
Gets a way to reply to the message, if possible.
An interface for writing to a network connection.
The Node class.
Definition: Node.h:23
void interrupt()
interrupt delegates the call to the Node port interrupt.
Definition: Node.cpp:597
An abstraction for a periodic thread.
bool setPeriod(double period)
Set the (new) period of the thread.
Interface implemented by all objects that can read themselves from the network, such as Bottle object...
Definition: PortReader.h:24
A mini-server for network communication.
Definition: Port.h:46
void setReader(PortReader &reader) override
Set an external reader for port data.
Definition: Port.cpp:511
void close() override
Stop port activity.
Definition: Port.cpp:363
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
Definition: Port.cpp:79
A class for storing options and configuration information.
Definition: Property.h:33
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
void unput(const std::string &key)
Remove the association from the given key to a value, if present.
Definition: Property.cpp:1046
bool topic(const std::string &name)
Set topic to publish to.
Definition: Publisher.h:63
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.
virtual Bottle & findGroup(const std::string &key) const =0
Gets a list corresponding to a given keyword.
void update()
Set the timestamp to the current time, and increment the sequence number (wrapping to 0 if the sequen...
Definition: Stamp.cpp:124
A single value (typically within a Bottle).
Definition: Value.h:43
virtual yarp::conf::float64_t asFloat64() const
Get 64-bit floating point value.
Definition: Value.cpp:222
virtual bool isString() const
Checks if value is a string.
Definition: Value.cpp:156
virtual yarp::conf::vocab32_t asVocab32() const
Get vocabulary identifier as an integer.
Definition: Value.cpp:228
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition: Value.cpp:204
virtual bool isList() const
Checks if value is a list.
Definition: Value.cpp:162
virtual Bottle * asList() const
Get list value.
Definition: Value.cpp:240
virtual bool isInt32() const
Checks if value is a 32-bit integer.
Definition: Value.cpp:132
bool isNull() const override
Checks if the object is invalid.
Definition: Value.cpp:380
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
bool write(yarp::os::ConnectionWriter &connection) const override
Write vector to a connection.
Definition: Vector.cpp:79
void resize(size_t size) override
Resize the vector.
Definition: Vector.h:220
size_t size() const
Definition: Vector.h:321
VectorOf< T > subVector(unsigned int first, unsigned int last) const
Creates and returns a new vector, being the portion of the original vector defined by the first and l...
Definition: Vector.h:400
#define yCInfo(component,...)
Definition: LogComponent.h:171
#define yCError(component,...)
Definition: LogComponent.h:213
#define yCTrace(component,...)
Definition: LogComponent.h:84
#define yCWarning(component,...)
Definition: LogComponent.h:192
#define yCDebug(component,...)
Definition: LogComponent.h:128
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:76
For streams capable of holding different kinds of content, check what they actually have.
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition: Time.cpp:121
An interface to the operating system, including Port based communication.
bool read(ImageOf< PixelRgb > &dest, const std::string &src, image_fileformat format=FORMAT_ANY)
Definition: ImageFile.cpp:915
The main, catch-all namespace for YARP.
Definition: dirs.h:16
@ ROS_only
Definition: yarpRosHelper.h:20
@ ROS_config_error
Definition: yarpRosHelper.h:17
@ ROS_enabled
Definition: yarpRosHelper.h:19
@ ROS_disabled
Definition: yarpRosHelper.h:18
double convertDegreesToRadians(double degrees)
convert degrees to radiants for ROS messages
Definition: yarpRosHelper.h:27