HokuyoLaserUnit.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::HokuyoLaserUnit
17 * @author Fabian Paus ( fabian dot paus at kit dot edu )
18 * @date 2017
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#include "HokuyoLaserUnit.h"
24
25#include <SimoxUtility/algorithm/string/string_tools.h>
26
32
33#include <HokuyoLaserScannerDriver/urg_utils.h>
34
35using namespace armarx;
36
41
42void
44{
45 offeringTopicFromProperty("RobotHealthTopicName");
46 offeringTopicFromProperty("DebugObserverName");
47
48 laserScannerListenerProxyName = getProperty<std::string>("LaserScannerListenerName").getValue();
49 usingProxyFromProperty("LaserScannerListenerName");
50 ARMARX_INFO << "Going to report to listener " << laserScannerListenerProxyName;
51 updatePeriod = getProperty<int>("UpdatePeriod").getValue();
52 angleOffset = getProperty<float>("AngleOffset").getValue();
53
54 std::string deviceStrings = getProperty<std::string>("Devices").getValue();
55 std::vector<std::string> splitDeviceStrings = Split(deviceStrings, ";");
56 devices.clear();
57 devices.reserve(splitDeviceStrings.size());
58 for (std::string const& deviceString : splitDeviceStrings)
59 {
60 std::vector<std::string> deviceInfo = Split(deviceString, ",");
61 if (deviceInfo.size() != 3)
62 {
63 ARMARX_WARNING << "Unexpected format for laser scanner device: " << deviceString
64 << " (split size: " << deviceInfo.size() << ")";
65 continue;
66 }
67
68 try
69 {
70 int port = std::stoi(deviceInfo[1]);
71
72 HokuyoLaserScanDevice& device = devices.emplace_back();
73 device.ip = deviceInfo[0];
74 device.port = port;
75 device.frame = deviceInfo[2];
76 device.angleOffset = angleOffset;
77 device.connected = false;
78
79 device.componentName = getName();
80 }
81 catch (std::exception const& ex)
82 {
83 ARMARX_WARNING << "Could not convert port to integer for laser scanner device "
84 << deviceString << " (port is " << deviceInfo[1] << ") : " << ex.what();
85 continue;
86 }
87 }
88}
89
90void
92{
94
95 getProxyFromProperty(listenerPrx, "LaserScannerListenerName");
97 getProperty<std::string>("DebugObserverName").getValue());
98
99 connectedDevices.clear();
100 for (HokuyoLaserScanDevice& device : devices)
101 {
102 if (device.task)
103 {
104 device.task->stop();
105 device.task = nullptr;
106 }
107
108 // connecting devices for first time
109 if (!device.reconnect())
110 {
111 ARMARX_WARNING << "Not starting task for laser scanner with IP: " << device.ip
112 << ", Port: " << device.port;
113 continue;
114 }
115
116 ARMARX_CHECK_NOT_NULL(heartbeat);
117 heartbeat->signUp(device.ip,
120 {"LaserScanner", "Localization"},
121 "HokuyoLaserScanDevice");
122
123 LaserScannerInfo info;
124 info.device = device.ip;
125 info.frame = device.frame;
126 int minStep = 0, maxStep = 0;
127 urg_step_min_max(&device.urg, &minStep, &maxStep);
128 info.minAngle = urg_step2rad(&device.urg, minStep);
129 info.maxAngle = urg_step2rad(&device.urg, maxStep);
130
131
132 int lengthDataSize = urg_max_data_size(&device.urg);
133 info.stepSize = (info.maxAngle - info.minAngle) / (maxStep - minStep);
134 device.lengthData.resize(lengthDataSize);
135
136 device.listenerPrx = listenerPrx;
137 device.robotHealthPlugin = heartbeat;
138 device.debugObserver = debugObserver;
139
140 connectedDevices.push_back(info);
141
142 ARMARX_INFO << "Connected to " << device.ip << ", " << info.frame << ", " << info.minAngle
143 << ", " << info.maxAngle << ", " << info.stepSize;
144
145 device.task = new RunningTask<HokuyoLaserScanDevice>(
146 &device, &HokuyoLaserScanDevice::run, "HokuyoLaserScanUpdate_" + device.ip);
147 device.task->start();
148 }
149}
150
151void
153{
154 for (HokuyoLaserScanDevice& device : devices)
155 {
156 if (device.task)
157 {
158 device.task->stop();
159 device.task = nullptr;
160 }
161 if (device.connected)
162 {
163 urg_close(&device.urg);
164 device.connected = false;
165 }
166 }
167}
168
169void
173
180
181std::string
182HokuyoLaserUnit::getReportTopicName(const Ice::Current&) const
183{
184 return laserScannerListenerProxyName;
185}
186
187LaserScannerInfoSeq
188HokuyoLaserUnit::getConnectedDevices(const Ice::Current&) const
189{
190 return connectedDevices;
191}
192
193bool
195{
196 if (connected)
197 {
198 ARMARX_INFO << "Disconnecting from laser scanner with IP " << ip;
199 urg_close(&urg);
200 connected = false;
201 }
202 ARMARX_INFO << "Reconnecting to " << ip << ":" << port;
203 int ret = urg_open(&urg, URG_ETHERNET, ip.c_str(), port);
204 connected = (ret == 0);
205 if (!connected)
206 {
207 ARMARX_WARNING << "Could not connect to laser scanner device using URG driver (IP: " << ip
208 << ", Port: " << port << ", Error: " << ret << ")";
209 return false;
210 }
211 ret = urg_start_measurement(&urg, URG_DISTANCE, URG_SCAN_INFINITY, 0);
212 connected = (ret == 0);
213 if (connected)
214 {
215 ARMARX_IMPORTANT << "Reconnected succesffully to " << ip << ":" << port;
216 return true;
217 }
218 else
219 {
221 << "Could not start measurement for laser scanner device using URG driver (IP: " << ip
222 << ", Port: " << port << ", Error: " << ret << ")";
223 return false;
224 }
225}
226
227void
229{
231 while (!task->isStopped())
232 {
233 ARMARX_INFO << deactivateSpam() << "Running update loop for laserscanner device " << ip;
234
235 IceUtil::Time time_start = TimeUtil::GetTime();
236
237 if (errorCounter > 10)
238 {
239 ARMARX_ERROR << "Device " << ip << " has too many consecutive errors!";
240 // assume dead
241 reconnect();
242 }
243 if (connected)
244 {
245 int lengthDataSize = urg_get_distance(&urg, lengthData.data(), nullptr);
246 if (lengthDataSize < 0)
247 {
249 << "Could not get measurement for laser scanner (IP: " << ip
250 << ", Port: " << port << ", Error: " << lengthDataSize << ")";
251 errorCounter++;
252 continue;
253 }
254 IceUtil::Time time_measure = TimeUtil::GetTime();
255 TimestampVariantPtr now(new TimestampVariant(time_measure));
256
257 scan.clear();
258 scan.reserve(lengthDataSize);
259 for (int stepIndex = 0; stepIndex < lengthDataSize; ++stepIndex)
260 {
261 LaserScanStep step;
262 long distance = lengthData[stepIndex];
263 // TODO: Extract the min and max valid value for distance into parameters?
264 if (distance >= 21 && distance <= 30000)
265 {
266 step.angle =
267 angleOffset + (float)urg_index2rad(&urg, stepIndex); // Convert steps to rad
268 step.distance = (float)distance; // Data is already in mm
269 scan.push_back(step);
270 }
271 }
272
273 IceUtil::Time time_update = TimeUtil::GetTime();
274
275 errorCounter = 0;
276
277 if (listenerPrx)
278 {
279
280 listenerPrx->reportSensorValues(ip, frame, scan, now);
281 }
282 else
283 {
284 ARMARX_WARNING << "No proxy available: IP: " << ip << ", Port: " << port;
285 }
286 IceUtil::Time time_proxyReport = TimeUtil::GetTime();
287
288 if (robotHealthPlugin != nullptr)
289 {
290 robotHealthPlugin->heartbeatOnChannel(ip);
291 }
292 else
293 {
294 ARMARX_WARNING << "No robot health topic available: IP: " << ip
295 << ", Port: " << port;
296 }
297
298 IceUtil::Time time_topicHeartbeat = TimeUtil::GetTime();
299
300 IceUtil::Time duration = time_topicHeartbeat - time_start;
301
302 StringVariantBaseMap durations;
303 durations["total_ms"] = new Variant(duration.toMilliSecondsDouble());
304 durations["measure_ms"] =
305 new Variant((time_measure - time_start).toMilliSecondsDouble());
306 durations["update_ms"] =
307 new Variant((time_update - time_measure).toMilliSecondsDouble());
308 durations["proxy_report_ms"] =
309 new Variant((time_proxyReport - time_update).toMilliSecondsDouble());
310 durations["topic_health_ms"] =
311 new Variant((time_topicHeartbeat - time_proxyReport).toMilliSecondsDouble());
312 debugObserver->setDebugChannel(
313 "LaserScannerDuration_" + simox::alg::replace_all(ip, ".", "_"), durations);
314
315 if (duration.toSecondsDouble() > 0.1)
316 {
317 ARMARX_WARNING << "Laserscanner reports are slow"
318 << "Total time: " << duration.toMilliSecondsDouble() << "ms\n"
319 << "Measure: "
320 << (time_measure - time_start).toMilliSecondsDouble() << "ms \n"
321 << "Update: "
322 << (time_update - time_measure).toMilliSecondsDouble() << "ms\n"
323 << "TopicSensor: "
324 << (time_proxyReport - time_update).toMilliSecondsDouble() << "ms\n"
325 << "TopicHeart: "
326 << (time_topicHeartbeat - time_proxyReport).toMilliSecondsDouble()
327 << "ms\n";
328 }
329 }
330 }
331}
#define float
Definition 16_Level.h:22
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
bool usingProxyFromProperty(const std::string &propertyName, const std::string &endpoints="")
Use a proxy whose name is specified by the given property.
void offeringTopicFromProperty(const std::string &propertyName)
Offer a topic whose name is specified by the given property.
ProxyType getProxyFromProperty(const std::string &propertyName, bool addToDependencies=false, const std::string &endpoints="", bool throwOnProxyError=true)
Get a proxy whose name is specified by the given property.
Definition Component.h:242
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
void onInitComponent() override
LaserScannerInfoSeq getConnectedDevices(const Ice::Current &c) const override
void onDisconnectComponent() override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void onConnectComponent() override
std::string getReportTopicName(const Ice::Current &c) const override
void onExitComponent() override
TopicProxyType getTopic(const std::string &name)
Returns a proxy of the specified topic.
PluginT * addPlugin(const std::string prefix="", ParamsT &&... params)
std::string getName() const
Retrieve name of object.
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition TimeUtil.cpp:42
Implements a Variant type for timestamps.
The Variant class is described here: Variants.
Definition Variant.h:224
static Duration MilliSeconds(std::int64_t milliSeconds)
Constructs a duration in milliseconds.
Definition Duration.cpp:48
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::map< std::string, VariantBasePtr > StringVariantBaseMap
std::vector< std::string > Split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
IceInternal::Handle< TimestampVariant > TimestampVariantPtr
double distance(const Point &a, const Point &b)
Definition point.hpp:95
LaserScannerUnitListenerPrx listenerPrx
std::vector< long > lengthData
RunningTask< HokuyoLaserScanDevice >::pointer_type task
DebugObserverInterfacePrx debugObserver
armarx::plugins::HeartbeatComponentPlugin * robotHealthPlugin
#define ARMARX_TRACE
Definition trace.h:77