sick_scan_services.cpp
Go to the documentation of this file.
1 /*
2  * @brief Implementation of ROS services for sick_scan
3  *
4  * Copyright (C) 2021, Ing.-Buero Dr. Michael Lehning, Hildesheim
5  * Copyright (C) 2021, SICK AG, Waldkirch
6  * All rights reserved.
7  *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *
21 * All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions are met:
25 *
26 * * Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
28 * * Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * * Neither the name of Osnabrueck University nor the names of its
32 * contributors may be used to endorse or promote products derived from
33 * this software without specific prior written permission.
34 * * Neither the name of SICK AG nor the names of its
35 * contributors may be used to endorse or promote products derived from
36 * this software without specific prior written permission
37 * * Neither the name of Ing.-Buero Dr. Michael Lehning nor the names of its
38 * contributors may be used to endorse or promote products derived from
39 * this software without specific prior written permission
40 *
41 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
42 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
45 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
46 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
47 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
48 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
49 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
51 * POSSIBILITY OF SUCH DAMAGE.
52  *
53  * Created on: 12.01.2021
54  *
55  * Authors:
56  * Michael Lehning <michael.lehning@lehning.de>
57  *
58  * Based on the TiM communication example by SICK AG.
59  *
60  */
61 #include <iostream>
62 #include <iomanip>
63 
67 
68 #define SCANSEGMENT_XD_SOPAS_ARGS_BIG_ENDIAN (true) // Arguments of SOPAS commands are big endian encoded
69 
71 : m_common_tcp(common_tcp), m_cola_binary(true)
72 {
73  bool srvSupportColaMsg = true, srvSupportECRChangeArr = true, srvSupportLIDoutputstate = true, srvSupportSCdevicestate = true;
74  bool srvSupportSCreboot = true, srvSupportSCsoftreset = true, srvSupportSickScanExit = true;
75  bool srvSupportGetContaminationResult = false;
76  if(lidar_param)
77  {
78  m_cola_binary = lidar_param->getUseBinaryProtocol();
79  if(lidar_param->getScannerName().compare(SICK_SCANNER_NAV_350_NAME) == 0)
80  {
81  srvSupportECRChangeArr = false;
82  srvSupportLIDoutputstate = false;
83  srvSupportSCreboot = false;
84  srvSupportSCsoftreset = false;
85  }
86  if(lidar_param->getScannerName().compare(SICK_SCANNER_MRS_1XXX_NAME) == 0
87  || lidar_param->getScannerName().compare(SICK_SCANNER_LMS_1XXX_NAME) == 0
88  || lidar_param->getScannerName().compare(SICK_SCANNER_SCANSEGMENT_XD_NAME) == 0)
89  {
90  srvSupportGetContaminationResult = true; // "sRN ContaminationResult" supported by MRS-1000, LMS-1000, multiScan
91  }
92  }
93  if(nh)
94  {
95  m_client_authorization_pw = "F4724744";
96  if (lidar_param->getUseSafetyPasWD()) // TIM_7xxS - 1 layer Safety Scanner
97  m_client_authorization_pw = "6FD62C05";
98  rosDeclareParam(nh, "client_authorization_pw", m_client_authorization_pw);
99  rosGetParam(nh, "client_authorization_pw", m_client_authorization_pw);
100 
101 #if __ROS_VERSION == 2
102 #define serviceCbColaMsgROS sick_scan_xd::SickScanServices::serviceCbColaMsgROS2
103 #define serviceCbECRChangeArrROS sick_scan_xd::SickScanServices::serviceCbECRChangeArrROS2
104 #define serviceCbLIDoutputstateROS sick_scan_xd::SickScanServices::serviceCbLIDoutputstateROS2
105 #define serviceCbSCdevicestateROS sick_scan_xd::SickScanServices::serviceCbSCdevicestateROS2
106 #define serviceCbSCrebootROS sick_scan_xd::SickScanServices::serviceCbSCrebootROS2
107 #define serviceCbSCsoftresetROS sick_scan_xd::SickScanServices::serviceCbSCsoftresetROS2
108 #define serviceCbSickScanExitROS sick_scan_xd::SickScanServices::serviceCbSickScanExitROS2
109 #define serviceCbGetContaminationResultROS sick_scan_xd::SickScanServices::serviceCbGetContaminationResultROS2
110 #define serviceCbFieldSetReadROS sick_scan_xd::SickScanServices::serviceCbFieldSetReadROS2
111 #define serviceCbFieldSetWriteROS sick_scan_xd::SickScanServices::serviceCbFieldSetWriteROS2
112 #else
113 #define serviceCbColaMsgROS sick_scan_xd::SickScanServices::serviceCbColaMsg
114 #define serviceCbECRChangeArrROS sick_scan_xd::SickScanServices::serviceCbECRChangeArr
115 #define serviceCbLIDoutputstateROS sick_scan_xd::SickScanServices::serviceCbLIDoutputstate
116 #define serviceCbSCdevicestateROS sick_scan_xd::SickScanServices::serviceCbSCdevicestate
117 #define serviceCbSCrebootROS sick_scan_xd::SickScanServices::serviceCbSCreboot
118 #define serviceCbSCsoftresetROS sick_scan_xd::SickScanServices::serviceCbSCsoftreset
119 #define serviceCbSickScanExitROS sick_scan_xd::SickScanServices::serviceCbSickScanExit
120 #define serviceCbGetContaminationResultROS sick_scan_xd::SickScanServices::serviceCbGetContaminationResult
121 #define serviceCbFieldSetReadROS sick_scan_xd::SickScanServices::serviceCbFieldSetRead
122 #define serviceCbFieldSetWriteROS sick_scan_xd::SickScanServices::serviceCbFieldSetWrite
123 #endif
124 #if __ROS_VERSION == 1
125 #define printServiceCreated(a,b) ROS_INFO_STREAM("SickScanServices: service \"" << a.getService() << "\" created (\"" << b.getService() << "\")");
126 #elif __ROS_VERSION == 2
127 #define printServiceCreated(a,b) ROS_INFO_STREAM("SickScanServices: service \"" << a->get_service_name() << "\" created (\"" << b->get_service_name() << "\")");
128 #else
129 #define printServiceCreated(a,b)
130 #endif
131  if(srvSupportColaMsg)
132  {
133  auto srv_server_ColaMsg = ROS_CREATE_SRV_SERVER(nh, sick_scan_srv::ColaMsgSrv, "ColaMsg", &serviceCbColaMsgROS, this);
135  printServiceCreated(srv_server_ColaMsg, m_srv_server_ColaMsg);
136  }
137  if(srvSupportECRChangeArr)
138  {
139  auto srv_server_ECRChangeArr = ROS_CREATE_SRV_SERVER(nh, sick_scan_srv::ECRChangeArrSrv, "ECRChangeArr", &serviceCbECRChangeArrROS, this);
141  printServiceCreated(srv_server_ECRChangeArr, m_srv_server_ECRChangeArr);
142  }
143  if(srvSupportGetContaminationResult)
144  {
145  auto srv_server_GetContaminationResult = ROS_CREATE_SRV_SERVER(nh, sick_scan_srv::GetContaminationResultSrv, "GetContaminationResult", &serviceCbGetContaminationResultROS, this);
147  printServiceCreated(srv_server_GetContaminationResult, m_srv_server_GetContaminationResult);
148  }
149  if(srvSupportLIDoutputstate)
150  {
151  auto srv_server_LIDoutputstate = ROS_CREATE_SRV_SERVER(nh, sick_scan_srv::LIDoutputstateSrv, "LIDoutputstate", &serviceCbLIDoutputstateROS, this);
153  printServiceCreated(srv_server_LIDoutputstate, m_srv_server_LIDoutputstate);
154  }
155  if(srvSupportSCdevicestate)
156  {
157  auto srv_server_SCdevicestate = ROS_CREATE_SRV_SERVER(nh, sick_scan_srv::SCdevicestateSrv, "SCdevicestate", &serviceCbSCdevicestateROS, this);
159  printServiceCreated(srv_server_SCdevicestate, m_srv_server_SCdevicestate);
160  }
161  if(srvSupportSCreboot)
162  {
163  auto srv_server_SCreboot = ROS_CREATE_SRV_SERVER(nh, sick_scan_srv::SCrebootSrv, "SCreboot", &serviceCbSCrebootROS, this);
165  printServiceCreated(srv_server_SCreboot, m_srv_server_SCreboot);
166  }
167  if(srvSupportSCsoftreset)
168  {
169  auto srv_server_SCsoftreset = ROS_CREATE_SRV_SERVER(nh, sick_scan_srv::SCsoftresetSrv, "SCsoftreset", &serviceCbSCsoftresetROS, this);
171  printServiceCreated(srv_server_SCsoftreset, m_srv_server_SCsoftreset);
172  }
173  if(srvSupportSickScanExit)
174  {
175  auto srv_server_SickScanExit = ROS_CREATE_SRV_SERVER(nh, sick_scan_srv::SickScanExitSrv, "SickScanExit", &serviceCbSickScanExitROS, this);
177  printServiceCreated(srv_server_SickScanExit, m_srv_server_SickScanExit);
178  }
179 #if __ROS_VERSION > 0
180  if(lidar_param->getUseEvalFields() == USE_EVAL_FIELD_TIM7XX_LOGIC)
181  {
182  auto srv_server_FieldSetRead = ROS_CREATE_SRV_SERVER(nh, sick_scan_srv::FieldSetReadSrv, "FieldSetRead", &serviceCbFieldSetReadROS, this);
183  m_srv_server_FieldSetRead = rosServiceServer<sick_scan_srv::FieldSetReadSrv>(srv_server_FieldSetRead);
184  printServiceCreated(srv_server_FieldSetRead, m_srv_server_FieldSetRead);
185  }
186  if(lidar_param->getUseEvalFields() == USE_EVAL_FIELD_TIM7XX_LOGIC)
187  {
188  auto srv_server_FieldSetWrite = ROS_CREATE_SRV_SERVER(nh, sick_scan_srv::FieldSetWriteSrv, "FieldSetWrite", &serviceCbFieldSetWriteROS, this);
189  m_srv_server_FieldSetWrite = rosServiceServer<sick_scan_srv::FieldSetWriteSrv>(srv_server_FieldSetWrite);
190  printServiceCreated(srv_server_FieldSetWrite, m_srv_server_FieldSetWrite);
191  }
192 #endif
193  }
194 }
195 
197 {
198 }
199 
207 bool sick_scan_xd::SickScanServices::sendSopasAndCheckAnswer(const std::string& sopasCmd, std::vector<unsigned char>& sopasReplyBin, std::string& sopasReplyString)
208 {
209  if(m_common_tcp)
210  {
211  ROS_INFO_STREAM("SickScanServices: Sending request \"" << sopasCmd << "\"");
212  std::string sopasRequest = std::string("\x02") + sopasCmd + "\x03";
213  int result = -1;
214  if (m_cola_binary)
215  {
216  std::vector<unsigned char> reqBinary;
217  m_common_tcp->convertAscii2BinaryCmd(sopasRequest.c_str(), &reqBinary);
218  result = m_common_tcp->sendSopasAndCheckAnswer(reqBinary, &sopasReplyBin, -1);
219  }
220  else
221  {
222  result = m_common_tcp->sendSopasAndCheckAnswer(sopasRequest.c_str(), &sopasReplyBin, -1);
223  }
224  if (result != 0)
225  {
226  ROS_ERROR_STREAM("## ERROR SickScanServices::sendSopasAndCheckAnswer: error sending sopas command \"" << sopasCmd << "\"");
227  }
228  else
229  {
230  sopasReplyString = m_common_tcp->sopasReplyToString(sopasReplyBin);
231  ROS_INFO_STREAM("SickScanServices: Request \"" << sopasCmd << "\" successfully sent, received reply \"" << sopasReplyString << "\"");
232  return true;
233  }
234  }
235  else
236  {
237  ROS_ERROR_STREAM("## ERROR SickScanServices::sendSopasAndCheckAnswer: m_common_tcp not initialized");
238  }
239  return false;
240 }
241 
248 bool sick_scan_xd::SickScanServices::serviceCbColaMsg(sick_scan_srv::ColaMsgSrv::Request &service_request, sick_scan_srv::ColaMsgSrv::Response &service_response)
249 {
250  std::string sopasCmd = service_request.request;
251  std::vector<unsigned char> sopasReplyBin;
252  std::string sopasReplyString;
253 
254  if(!sendSopasAndCheckAnswer(sopasCmd, sopasReplyBin, sopasReplyString))
255  {
256  ROS_ERROR_STREAM("## ERROR SickScanServices::sendSopasAndCheckAnswer failed on sending command\"" << sopasCmd << "\"");
257  return false;
258  }
259 
260  ROS_INFO_STREAM("SickScanServices: request: \"" << sopasCmd << "\"");
261  ROS_INFO_STREAM("SickScanServices: response: \"" << sopasReplyString << "\"");
262 
263  service_response.response = sopasReplyString;
264  return true;
265 }
266 
274 bool sick_scan_xd::SickScanServices::serviceCbECRChangeArr(sick_scan_srv::ECRChangeArrSrv::Request &service_request, sick_scan_srv::ECRChangeArrSrv::Response &service_response)
275 {
276  std::string sopasCmd = std::string("sEN ECRChangeArr ") + (service_request.active ? "1" : "0");
277  std::vector<unsigned char> sopasReplyBin;
278  std::string sopasReplyString;
279 
280  service_response.success = false;
281  if(!sendSopasAndCheckAnswer(sopasCmd, sopasReplyBin, sopasReplyString))
282  {
283  ROS_ERROR_STREAM("## ERROR SickScanServices::sendSopasAndCheckAnswer failed on sending command\"" << sopasCmd << "\"");
284  return false;
285  }
286  service_response.success = true;
287 
288  ROS_INFO_STREAM("SickScanServices: request: \"" << sopasCmd << "\"");
289  ROS_INFO_STREAM("SickScanServices: response: \"" << sopasReplyString << "\"");
290 
291  return true;
292 }
293 
300 bool sick_scan_xd::SickScanServices::serviceCbGetContaminationResult(sick_scan_srv::GetContaminationResultSrv::Request &service_request, sick_scan_srv::GetContaminationResultSrv::Response &service_response)
301 {
302  std::string sopasCmd = std::string("sRN ContaminationResult");
303  std::vector<unsigned char> sopasReplyBin;
304  std::string sopasReplyString;
305 
306  service_response.success = false;
307  service_response.warning = 0;
308  service_response.error = 0;
309  if(!sendSopasAndCheckAnswer(sopasCmd, sopasReplyBin, sopasReplyString))
310  {
311  ROS_ERROR_STREAM("## ERROR SickScanServices::sendSopasAndCheckAnswer failed on sending command\"" << sopasCmd << "\"");
312  return false;
313  }
314  service_response.success = true;
315 
316  std::string response_str((char*)sopasReplyBin.data(), sopasReplyBin.size());
317  std::size_t state_pos = response_str.find("ContaminationResult");
318  int result_idx = 20;
319  if (state_pos != std::string::npos && state_pos + result_idx < sopasReplyBin.size())
320  {
321  uint8_t result_byte = sopasReplyBin[state_pos + result_idx];
322  result_byte = ((result_byte >= '0') ? (result_byte - '0') : (result_byte)); // convert to bin in case of ascii
323  service_response.warning = result_byte;
324  result_idx++;
325  if (result_idx < sopasReplyBin.size() && sopasReplyBin[state_pos + result_idx] == ' ') // jump over ascii separator
326  result_idx++;
327  if (result_idx < sopasReplyBin.size())
328  {
329  result_byte = sopasReplyBin[state_pos + result_idx];
330  result_byte = ((result_byte >= '0') ? (result_byte - '0') : (result_byte)); // convert to bin in case of ascii
331  service_response.error = result_byte;
332  }
333  }
334  ROS_INFO_STREAM("SickScanServices: request: \"" << sopasCmd << "\"");
335  ROS_INFO_STREAM("SickScanServices: response: \"" << sopasReplyString << "\" = \"" << DataDumper::binDataToAsciiString(sopasReplyBin.data(), sopasReplyBin.size()) << "\""
336  << " (response.success=" << (int)(service_response.success) << ", response.warning=" << (int)(service_response.warning) << ", response.error=" << (int)(service_response.error) << ")");
337 
338  return true;
339 }
340 
341 
349 bool sick_scan_xd::SickScanServices::serviceCbLIDoutputstate(sick_scan_srv::LIDoutputstateSrv::Request &service_request, sick_scan_srv::LIDoutputstateSrv::Response &service_response)
350 {
351  std::string sopasCmd = std::string("sEN LIDoutputstate ") + (service_request.active ? "1" : "0");
352  std::vector<unsigned char> sopasReplyBin;
353  std::string sopasReplyString;
354 
355  service_response.success = false;
356  if(!sendSopasAndCheckAnswer(sopasCmd, sopasReplyBin, sopasReplyString))
357  {
358  ROS_ERROR_STREAM("## ERROR SickScanServices::sendSopasAndCheckAnswer failed on sending command\"" << sopasCmd << "\"");
359  return false;
360  }
361  service_response.success = true;
362 
363  ROS_INFO_STREAM("SickScanServices: request: \"" << sopasCmd << "\"");
364  ROS_INFO_STREAM("SickScanServices: response: \"" << sopasReplyString << "\"");
365 
366  return true;
367 }
368 
373 {
374  std::string sopasCmd = std::string("sMN SetAccessMode 3 ") + m_client_authorization_pw;
375  std::vector<unsigned char> sopasReplyBin;
376  std::string sopasReplyString;
377 
378  if(!sendSopasAndCheckAnswer(sopasCmd, sopasReplyBin, sopasReplyString))
379  {
380  ROS_ERROR_STREAM("## ERROR SickScanServices::sendSopasAndCheckAnswer failed on sending command\"" << sopasCmd << "\"");
381  return false;
382  }
383 
384  ROS_INFO_STREAM("SickScanServices: request: \"" << sopasCmd << "\"");
385  ROS_INFO_STREAM("SickScanServices: response: \"" << sopasReplyString << "\"");
386 
387  return true;
388 }
389 
394 {
395  std::string sopasCmd = std::string("sMN Run");
396  std::vector<unsigned char> sopasReplyBin;
397  std::string sopasReplyString;
398 
399  if(!sendSopasAndCheckAnswer(sopasCmd, sopasReplyBin, sopasReplyString))
400  {
401  ROS_ERROR_STREAM("## ERROR SickScanServices::sendSopasAndCheckAnswer failed on sending command\"" << sopasCmd << "\"");
402  return false;
403  }
404 
405  ROS_INFO_STREAM("SickScanServices: request: \"" << sopasCmd << "\"");
406  ROS_INFO_STREAM("SickScanServices: response: \"" << sopasReplyString << "\"");
407 
408  return true;
409 }
410 
414 bool sick_scan_xd::SickScanServices::sendSopasCmdCheckResponse(const std::string& sopas_request, const std::string& expected_response)
415 {
416  std::vector<unsigned char> sopasReplyBin;
417  std::string sopasReplyString;
418  if(!sendSopasAndCheckAnswer(sopas_request, sopasReplyBin, sopasReplyString))
419  {
420  ROS_ERROR_STREAM("## ERROR SickScanServices::sendSopasCmdCheckResponse() failed on sending command\"" << sopas_request << "\"");
421  return false;
422  }
423  ROS_INFO_STREAM("SickScanServices::sendSopasCmdCheckResponse(): request: \"" << sopas_request << "\", response: \"" << sopasReplyString << "\"");
424  if(sopasReplyString.find(expected_response) == std::string::npos)
425  {
426  ROS_ERROR_STREAM("## ERROR SickScanServices::sendSopasCmdCheckResponse(): request: \"" << sopas_request << "\", unexpected response: \"" << sopasReplyString << "\", \"" << expected_response << "\" not found");
427  return false;
428  }
429  return true;
430 }
431 
432 #if defined SCANSEGMENT_XD_SUPPORT && SCANSEGMENT_XD_SUPPORT > 0
433 static void printPicoScanImuDisabledWarning()
434 {
435  ROS_WARN_STREAM("############################");
436  ROS_WARN_STREAM("## ##");
437  ROS_WARN_STREAM("## IMU will be disabled ##");
438  ROS_WARN_STREAM("## ##");
439  ROS_WARN_STREAM("############################");
440  ROS_WARN_STREAM("## If you are using a picoScan150 w/o addons, disable the IMU by setting option \"imu_enable\" to \"False\" in your launchfile, or use sick_picoscan_single_echo.launch to avoid this error");
441  ROS_WARN_STREAM("## If you are using a picoScan with IMU, check IMU settings with SOPAS Air");
442 }
443 
455 bool sick_scan_xd::SickScanServices::sendMultiScanStartCmd(const std::string& hostname, int port, const std::string& scanner_type, int scandataformat, bool& imu_enable, int imu_udp_port, int performanceprofilenumber, bool check_udp_receiver_ip, int check_udp_receiver_port)
456 {
457  // Check udp receiver ip address: hostname is expected to be a IPv4 address
458  std::stringstream ip_stream(hostname);
459  std::string ip_token;
460  std::vector<std::string> ip_tokens;
461  while (getline(ip_stream, ip_token, '.'))
462  {
463  ip_tokens.push_back(ip_token);
464  }
465  if (ip_tokens.size() != 4)
466  {
467  ROS_ERROR_STREAM("## ERROR SickScanServices::sendMultiScanStartCmd() failed: can't split ip address \"" << hostname << "\" into 4 tokens, check ip address.");
468  ROS_ERROR_STREAM("## ERROR parsing ip address, check configuration of parameter udp_receiver_ip=\"" << hostname << "\" (launch file or commandline option).");
469  ROS_ERROR_STREAM("## Parameter \"udp_receiver_ip\" should be the IPv4 address like 192.168.0.x of the system running sick_scan_xd.");
470  return false;
471  }
472  // Check udp receiver ip address by sending and receiving a UDP test message
473  std::string check_udp_receiver_msg = "sick_scan_xd udp test message verifying udp_receiver_ip";
474  if (check_udp_receiver_ip && !check_udp_receiver_msg.empty())
475  {
476  sick_scansegment_xd::UdpPoster udp_loopback_poster(hostname, check_udp_receiver_port);
477  std::string check_udp_receiver_response;
478  if (!udp_loopback_poster.Post(check_udp_receiver_msg, check_udp_receiver_response) || check_udp_receiver_msg != check_udp_receiver_response)
479  {
480  ROS_ERROR_STREAM("## ERROR SickScanServices::sendMultiScanStartCmd() failed to send and receive a UDP test messsage to " << hostname << ":" << check_udp_receiver_port);
481  ROS_ERROR_STREAM("## Check configuration of parameter udp_receiver_ip=\"" << hostname << "\" (launch file or commandline option).");
482  ROS_ERROR_STREAM("## Parameter \"udp_receiver_ip\" should be the IPv4 address like 192.168.0.x of the system running sick_scan_xd.");
483  return false;
484  }
485  else
486  {
487  ROS_DEBUG_STREAM("SickScanServices::sendMultiScanStartCmd(): UDP test message \"" << check_udp_receiver_response << "\" successfully received.");
488  ROS_INFO_STREAM("SickScanServices::sendMultiScanStartCmd(): UDP test message successfully send to " << hostname << ":" << check_udp_receiver_port << ", parameter udp_receiver_ip=\"" << hostname << "\" is valid.");
489  }
490  }
491  // Send sopas start sequence (ScanDataFormat, ScanDataEthSettings, ImuDataEthSettings, ScanDataEnable, ImuDataEnable)
492  std::stringstream eth_settings_cmd, imu_eth_settings_cmd, scandataformat_cmd, performanceprofilenumber_cmd;
493  scandataformat_cmd << "sWN ScanDataFormat " << scandataformat;
494  if (performanceprofilenumber >= 0)
495  {
496  performanceprofilenumber_cmd << "sWN PerformanceProfileNumber " << std::uppercase << std::hex << performanceprofilenumber;
497  }
498  eth_settings_cmd << "sWN ScanDataEthSettings 1";
499  imu_eth_settings_cmd << "sWN ImuDataEthSettings 1";
500  for (int i = 0; i < ip_tokens.size(); i++)
501  {
502  eth_settings_cmd << " +";
503  eth_settings_cmd << ip_tokens[i];
504  imu_eth_settings_cmd << " +";
505  imu_eth_settings_cmd << ip_tokens[i];
506  }
507  eth_settings_cmd << " +";
508  eth_settings_cmd << port;
509  imu_eth_settings_cmd << " +";
510  imu_eth_settings_cmd << imu_udp_port;
511  if (!sendSopasCmdCheckResponse(eth_settings_cmd.str(), "sWA ScanDataEthSettings")) // configure destination scan data output destination , f.e. "sWN ScanDataEthSettings 1 +192 +168 +0 +52 +2115" (ip 192.168.0.52 port 2115)
512  {
513  ROS_ERROR_STREAM("## ERROR SickScanServices::sendMultiScanStartCmd(): sendSopasCmdCheckResponse(\"sWN ScanDataEthSettings 1\") failed.");
514  return false;
515  }
516  if (scandataformat != 1 && scandataformat != 2)
517  {
518  ROS_ERROR_STREAM("## ERROR SickScanServices::sendMultiscanStartCmd(): invalid scandataformat configuration, unsupported scandataformat=" << scandataformat << ", check configuration and use 1 for msgpack or 2 for compact data");
519  return false;
520  }
521  if (!sendSopasCmdCheckResponse(scandataformat_cmd.str(), "sWA ScanDataFormat")) // set scan data output format to MSGPACK (1) or COMPACT (2)
522  {
523  ROS_ERROR_STREAM("## ERROR SickScanServices::sendMultiscanStartCmd(): sendSopasCmdCheckResponse(\"sWN ScanDataFormat 1\") failed.");
524  return false;
525  }
526  if (performanceprofilenumber >= 0)
527  {
528  if (!sendSopasCmdCheckResponse(performanceprofilenumber_cmd.str(), "sWA PerformanceProfileNumber"))
529  {
530  ROS_ERROR_STREAM("## ERROR SickScanServices::sendMultiscanStartCmd(): sendSopasCmdCheckResponse(\"sWN PerformanceProfileNumber ..\") failed.");
531  return false;
532  }
533  }
534  if (scanner_type == SICK_SCANNER_SCANSEGMENT_XD_NAME && !sendSopasCmdCheckResponse("sWN ScanDataPreformatting 1", "sWA ScanDataPreformatting")) // ScanDataPreformatting for multiScan136 only
535  {
536  ROS_ERROR_STREAM("## ERROR SickScanServices::sendMultiscanStartCmd(): sendSopasCmdCheckResponse(\"sWN ScanDataPreformatting 1\") failed.");
537  return false;
538  }
539  if (imu_enable && !sendSopasCmdCheckResponse(imu_eth_settings_cmd.str(), "sWA ImuDataEthSettings")) // imu data eth settings
540  {
541  if (scanner_type == SICK_SCANNER_PICOSCAN_NAME)
542  {
543  // picoScan150 ships in 2 variants, with and without IMU resp. IMU licence (picoScan150 w/o addons).
544  // For picoScan150 w/o addons we disable the IMU, if SOPAS commands "ImuDataEthSettings" or "ImuDataEnable" failed.
545  ROS_WARN_STREAM("## WARNING SickScanServices::sendMultiScanStartCmd(): sendSopasCmdCheckResponse(\"" << imu_eth_settings_cmd.str() << "\") failed.");
546  printPicoScanImuDisabledWarning();
547  imu_enable = false;
548  }
549  else
550  {
551  ROS_ERROR_STREAM("## ERROR SickScanServices::sendMultiScanStartCmd(): sendSopasCmdCheckResponse(\"" << imu_eth_settings_cmd.str() << "\") failed.");
552  }
553  }
554  if (!sendRun())
555  {
556  return false;
557  }
558  if (!sendAuthorization())
559  {
560  return false;
561  }
562  if (!sendSopasCmdCheckResponse("sWN ScanDataEnable 1", "sWA ScanDataEnable")) // enable scan data output
563  {
564  ROS_ERROR_STREAM("## ERROR SickScanServices::sendMultiScanStartCmd(): sendSopasCmdCheckResponse(\"sWN ScanDataEnable 1\") failed.");
565  return false;
566  }
567  if (imu_enable && !sendSopasCmdCheckResponse("sWN ImuDataEnable 1", "sWA ImuDataEnable")) // enable imu data transfer
568  {
569  if (scanner_type == SICK_SCANNER_PICOSCAN_NAME)
570  {
571  // picoScan150 ships in 2 variants, with and without IMU resp. IMU licence (picoScan150 w/o addons).
572  // For picoScan150 w/o addons we disable the IMU, if SOPAS commands "ImuDataEthSettings" or "ImuDataEnable" failed.
573  ROS_WARN_STREAM("## WARNING SickScanServices::sendMultiScanStartCmd(): sendSopasCmdCheckResponse(\"sWN ImuDataEnable 1\") failed.");
574  printPicoScanImuDisabledWarning();
575  imu_enable = false;
576  }
577  else
578  {
579  ROS_ERROR_STREAM("## ERROR SickScanServices::sendMultiScanStartCmd(): sendSopasCmdCheckResponse(\"sWN ImuDataEnable 1\") failed.");
580  }
581  }
582  if (!sendRun())
583  {
584  return false;
585  }
586  if (!sendAuthorization())
587  {
588  return false;
589  }
590  if (!sendSopasCmdCheckResponse("sMN LMCstartmeas", "sAN LMCstartmeas")) // start measurement
591  {
592  ROS_ERROR_STREAM("## ERROR SickScanServices::sendMultiScanStartCmd(): sendSopasCmdCheckResponse(\"sMN LMCstartmeas\") failed.");
593  return false;
594  }
595  return true;
596 }
597 #endif // SCANSEGMENT_XD_SUPPORT
598 
599 #if defined SCANSEGMENT_XD_SUPPORT && SCANSEGMENT_XD_SUPPORT > 0
600 
603 bool sick_scan_xd::SickScanServices::sendMultiScanStopCmd(bool imu_enable)
604 {
605  if (!sendSopasCmdCheckResponse("sWN ScanDataEnable 0", "sWA ScanDataEnable")) // disable scan data output
606  {
607  ROS_ERROR_STREAM("## ERROR SickScanServices::sendMultiScanStopCmd(): sendSopasCmdCheckResponse(\"sWN ScanDataEnable 0\") failed.");
608  return false;
609  }
610  if (imu_enable && !sendSopasCmdCheckResponse("sWN ImuDataEnable 0", "sWA ImuDataEnable")) // disable imu data output
611  {
612  ROS_ERROR_STREAM("## ERROR SickScanServices::sendMultiScanStopCmd(): sendSopasCmdCheckResponse(\"sWN ImuDataEnable 0\") failed.");
613  return false;
614  }
615  if (!sendRun())
616  {
617  return false;
618  }
619  return true;
620 }
621 #endif // SCANSEGMENT_XD_SUPPORT
622 
624 {
625  uint8_t u8_bytes[4];
626  uint32_t u32_bytes;
627  int32_t i32_bytes;
628  float value;
629 };
630 
638 float sick_scan_xd::SickScanServices::convertHexStringToFloat(const std::string& hex_str, bool hexStrIsBigEndian)
639 {
640  FLOAT_BYTE32_UNION hex_buffer;
641  if(hexStrIsBigEndian)
642  {
643  for(int m = 3, n = 1; n < hex_str.size(); n+=2, m--)
644  {
645  char hexval[4] = { hex_str[n-1], hex_str[n], '\0', '\0' };
646  hex_buffer.u8_bytes[m] = (uint8_t)(std::strtoul(hexval, NULL, 16) & 0xFF);
647  }
648  }
649  else
650  {
651  for(int m = 0, n = 1; n < hex_str.size(); n+=2, m++)
652  {
653  char hexval[4] = { hex_str[n-1], hex_str[n], '\0', '\0' };
654  hex_buffer.u8_bytes[m] = (uint8_t)(std::strtoul(hexval, NULL, 16) & 0xFF);
655  }
656  }
657  // ROS_DEBUG_STREAM("convertHexStringToFloat(" << hex_str << ", " << hexStrIsBigEndian << "): " << std::hex << hex_buffer.u32_bytes << " = " << std::fixed << hex_buffer.value);
658  return hex_buffer.value;
659 }
660 
668 std::string sick_scan_xd::SickScanServices::convertFloatToHexString(float value, bool hexStrIsBigEndian)
669 {
670  FLOAT_BYTE32_UNION hex_buffer;
671  hex_buffer.value = value;
672  std::stringstream hex_str;
673  if(hexStrIsBigEndian)
674  {
675  for(int n = 3; n >= 0; n--)
676  hex_str << std::setfill('0') << std::setw(2) << std::uppercase << std::hex << (int)(hex_buffer.u8_bytes[n]);
677  }
678  else
679  {
680  for(int n = 0; n < 4; n++)
681  hex_str << std::setfill('0') << std::setw(2) << std::uppercase << std::hex << (int)(hex_buffer.u8_bytes[n]);
682  }
683  // ROS_DEBUG_STREAM("convertFloatToHexString(" << value << ", " << hexStrIsBigEndian << "): " << hex_str.str());
684  return hex_str.str();
685 }
686 
690 float sick_scan_xd::SickScanServices::convertHexStringToAngleDeg(const std::string& hex_str, bool hexStrIsBigEndian)
691 {
692  char hex_str_8byte[9] = "00000000";
693  for(int m=7,n=hex_str.size()-1; n >= 0; m--,n--)
694  hex_str_8byte[m] = hex_str[n]; // fill with leading '0'
695  FLOAT_BYTE32_UNION hex_buffer;
696  if(hexStrIsBigEndian)
697  {
698  for(int m = 3, n = 1; n < 8; n+=2, m--)
699  {
700  char hexval[4] = { hex_str_8byte[n-1], hex_str_8byte[n], '\0', '\0' };
701  hex_buffer.u8_bytes[m] = (uint8_t)(std::strtoul(hexval, NULL, 16) & 0xFF);
702  }
703  }
704  else
705  {
706  for(int m = 0, n = 1; n < 8; n+=2, m++)
707  {
708  char hexval[4] = { hex_str_8byte[n-1], hex_str_8byte[n], '\0', '\0' };
709  hex_buffer.u8_bytes[m] = (uint8_t)(std::strtoul(hexval, NULL, 16) & 0xFF);
710  }
711  }
712  float angle_deg = (float)(hex_buffer.i32_bytes / 10000.0);
713  // ROS_DEBUG_STREAM("convertHexStringToAngleDeg(" << hex_str << ", " << hexStrIsBigEndian << "): " << angle_deg << " [deg]");
714  return angle_deg;
715 }
716 
720 std::string sick_scan_xd::SickScanServices::convertAngleDegToHexString(float angle_deg, bool hexStrIsBigEndian)
721 {
722  int32_t angle_val = (int32_t)std::round(angle_deg * 10000.0f);
723  FLOAT_BYTE32_UNION hex_buffer;
724  hex_buffer.i32_bytes = angle_val;
725  std::stringstream hex_str;
726  if(hexStrIsBigEndian)
727  {
728  for(int n = 3; n >= 0; n--)
729  hex_str << std::setfill('0') << std::setw(2) << std::uppercase << std::hex << (int)(hex_buffer.u8_bytes[n]);
730  }
731  else
732  {
733  for(int n = 0; n < 4; n++)
734  hex_str << std::setfill('0') << std::setw(2) << std::uppercase << std::hex << (int)(hex_buffer.u8_bytes[n]);
735  }
736  // ROS_DEBUG_STREAM("convertAngleDegToHexString(" << angle_deg << " [deg], " << hexStrIsBigEndian << "): " << hex_str.str());
737  return hex_str.str();
738 }
739 
740 #if defined SCANSEGMENT_XD_SUPPORT && SCANSEGMENT_XD_SUPPORT > 0
741 
748 bool sick_scan_xd::SickScanServices::queryMultiScanFiltersettings(int& host_FREchoFilter, std::string& host_LFPangleRangeFilter, std::string& host_LFPlayerFilter,
749  sick_scansegment_xd::MsgpackValidatorFilterConfig& msgpack_validator_filter_settings, const std::string& scanner_type)
750 {
751  std::vector<std::vector<unsigned char>> sopasRepliesBin;
752  std::vector<std::string> sopasRepliesString;
753 
754  // Query FREchoFilter, LFPangleRangeFilter and LFPlayerFilter settings
755  bool enableFREchoFilter = true, enableLFPangleRangeFilter = true, enableLFPlayerFilter = true;
756  if (scanner_type == SICK_SCANNER_PICOSCAN_NAME) // LFPangleRangeFilter and LFPlayerFilter not supported by picoscan150
757  {
758  // enableLFPangleRangeFilter = false;
759  enableLFPlayerFilter = false;
760  }
761  std::vector<std::string> sopasCommands;
762  if (enableFREchoFilter)
763  sopasCommands.push_back("FREchoFilter");
764  if (enableLFPangleRangeFilter)
765  sopasCommands.push_back("LFPangleRangeFilter");
766  if (enableLFPlayerFilter)
767  sopasCommands.push_back("LFPlayerFilter");
768  for(int n = 0; n < sopasCommands.size(); n++)
769  {
770  std::string sopasRequest = "sRN " + sopasCommands[n];
771  std::string sopasExpectedResponse = "sRA " + sopasCommands[n];
772  std::vector<unsigned char> sopasReplyBin;
773  std::string sopasReplyString;
774  if(!sendSopasAndCheckAnswer(sopasRequest, sopasReplyBin, sopasReplyString) || sopasReplyString.find(sopasExpectedResponse) == std::string::npos)
775  {
776  ROS_ERROR_STREAM("## ERROR SickScanServices::queryMultiScanFiltersettings(): sendSopasAndCheckAnswer(\"" << sopasRequest << "\") failed or unexpected response: \"" << sopasReplyString << "\", expected: \"" << sopasExpectedResponse << "\"");
777  return false;
778  }
779  ROS_DEBUG_STREAM("SickScanServices::queryMultiScanFiltersettings(): request: \"" << sopasRequest << "\", response: \"" << sopasReplyString << "\"");
780  sopasRepliesBin.push_back(sopasReplyBin);
781  sopasRepliesString.push_back(sopasReplyString);
782  }
783 
784  // Convert sopas answers
785  std::vector<std::vector<std::string>> sopasTokens;
786  for(int n = 0; n < sopasCommands.size(); n++)
787  {
788  std::string parameterString = sopasRepliesString[n].substr(4 + sopasCommands[n].size() + 1);
789  std::vector<std::string> parameterToken;
790  sick_scansegment_xd::util::parseVector(parameterString, parameterToken, ' ');
791  sopasTokens.push_back(parameterToken);
792  ROS_INFO_STREAM("SickScanServices::queryMultiScanFiltersettings(): " << sopasCommands[n] << ": \"" << parameterString << "\" = {" << sick_scansegment_xd::util::printVector(parameterToken, ",") << "}");
793  }
794 
795  std::vector<float> multiscan_angles_deg;
796  std::vector<int> layer_active_vector;
797  for(int sopasCommandCnt = 0; sopasCommandCnt < sopasCommands.size(); sopasCommandCnt++)
798  {
799  const std::string& sopasCommand = sopasCommands[sopasCommandCnt];
800  const std::vector<std::string>& sopasToken = sopasTokens[sopasCommandCnt];
801 
802  if (sopasCommand == "FREchoFilter") // Parse FREchoFilter
803  {
804  if(sopasToken.size() == 1)
805  {
806  host_FREchoFilter = std::stoi(sopasToken[0]);
807  }
808  else
809  {
810  ROS_ERROR_STREAM("## ERROR SickScanServices::queryMultiScanFiltersettings(): parse error in FREchoFilter");
811  return false;
812  }
813  }
814 
815  if (sopasCommand == "LFPangleRangeFilter") // Parse LFPangleRangeFilter
816  {
817  if(sopasToken.size() == 6)
818  {
819  std::stringstream parameter;
820  int filter_enabled = std::stoi(sopasToken[0]); // <enabled>
821  parameter << filter_enabled;
822  for(int n = 1; n < 5; n++) // <azimuth_start> <azimuth_stop> <elevation_start> <elevation_stop>
823  {
824  // float angle_deg = (convertHexStringToFloat(sopasToken[n], SCANSEGMENT_XD_SOPAS_ARGS_BIG_ENDIAN) * 180.0 / M_PI);
825  float angle_deg = convertHexStringToAngleDeg(sopasToken[n], SCANSEGMENT_XD_SOPAS_ARGS_BIG_ENDIAN);
826  parameter << " " << angle_deg;
827  if(filter_enabled)
828  multiscan_angles_deg.push_back(angle_deg);
829  }
830  parameter << " " << sopasToken[5]; // <beam_increment>
831  host_LFPangleRangeFilter = parameter.str();
832  }
833  else
834  {
835  ROS_ERROR_STREAM("## ERROR SickScanServices::queryMultiScanFiltersettings(): parse error in LFPangleRangeFilter");
836  return false;
837  }
838  }
839 
840  if (sopasCommand == "LFPlayerFilter") // Parse LFPlayerFilter
841  {
842  if(sopasToken.size() == 17)
843  {
844  std::stringstream parameter;
845  int filter_enabled = std::stoi(sopasToken[0]); // <enabled>
846  parameter << filter_enabled;
847  for(int n = 1; n < sopasToken.size(); n++)
848  {
849  int layer_active = std::stoi(sopasToken[n]);
850  if(filter_enabled)
851  layer_active_vector.push_back(layer_active);
852  parameter << " " << layer_active;
853  }
854  host_LFPlayerFilter = parameter.str();
855  }
856  else
857  {
858  ROS_ERROR_STREAM("## ERROR SickScanServices::queryMultiScanFiltersettings(): parse error in LFPlayerFilter");
859  return false;
860  }
861  }
862  }
863 
864  // Set filter settings for validation of msgpack data, i.e. set config.msgpack_validator_required_echos, config.msgpack_validator_azimuth_start, config.msgpack_validator_azimuth_end,
865  // config.msgpack_validator_elevation_start, config.msgpack_validator_elevation_end, config.msgpack_validator_layer_filter according to the queried filter settings
866  if(host_FREchoFilter == 0 || host_FREchoFilter == 2) // 0: FIRST_ECHO (EchoCount=1), 2: LAST_ECHO (EchoCount=1)
867  {
868  msgpack_validator_filter_settings.msgpack_validator_required_echos = { 0 }; // one echo with index 0
869  }
870  else if(host_FREchoFilter == 1) // 1: ALL_ECHOS (EchoCount=3)
871  {
872  msgpack_validator_filter_settings.msgpack_validator_required_echos = { 0, 1, 2 }; // three echos with index 0, 1, 2
873  }
874  else
875  {
876  ROS_ERROR_STREAM("## ERROR SickScanServices::queryMultiScanFiltersettings(): unexpected value of FREchoFilter = " << host_FREchoFilter
877  << ", expected 0: FIRST_ECHO (EchoCount=1), 1: ALL_ECHOS (EchoCount=3) or 2: LAST_ECHO (EchoCount=1)");
878  return false;
879  }
880  if(multiscan_angles_deg.size() == 4) // otherwise LFPangleRangeFilter disabled (-> use configured default values)
881  {
882  msgpack_validator_filter_settings.msgpack_validator_azimuth_start = (multiscan_angles_deg[0] * M_PI / 180);
883  msgpack_validator_filter_settings.msgpack_validator_azimuth_end = (multiscan_angles_deg[1] * M_PI / 180);
884  msgpack_validator_filter_settings.msgpack_validator_elevation_start = (multiscan_angles_deg[2] * M_PI / 180);
885  msgpack_validator_filter_settings.msgpack_validator_elevation_end = (multiscan_angles_deg[3] * M_PI / 180);
886  }
887  if(layer_active_vector.size() == 16) // otherwise LFPlayerFilter disabled (-> use configured default values)
888  {
889  msgpack_validator_filter_settings.msgpack_validator_layer_filter = layer_active_vector;
890  }
891 
892  // Example: sopas.FREchoFilter = "1", sopas.LFPangleRangeFilter = "0 -180 180 -90.0002 90.0002 1", sopas.LFPlayerFilter = "0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1"
893  // msgpack_validator_required_echos = { 0 }, msgpack_validator_angles = { -3.14159 3.14159 -1.5708 1.5708 } [rad], msgpack_validator_layer_filter = { 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 }
894  ROS_INFO_STREAM("SickScanServices::queryMultiScanFiltersettings(): sopas.FREchoFilter = \"" << host_FREchoFilter
895  << "\", sopas.LFPangleRangeFilter = \"" << host_LFPangleRangeFilter
896  << "\", sopas.LFPlayerFilter = \"" << host_LFPlayerFilter << "\"");
897  ROS_INFO_STREAM("SickScanServices::queryMultiScanFiltersettings(): msgpack_validator_required_echos = { " << sick_scansegment_xd::util::printVector(msgpack_validator_filter_settings.msgpack_validator_required_echos)
898  << " }, msgpack_validator_angles = { " << msgpack_validator_filter_settings.msgpack_validator_azimuth_start << " " << msgpack_validator_filter_settings.msgpack_validator_azimuth_end
899  << " " << msgpack_validator_filter_settings.msgpack_validator_elevation_start << " " << msgpack_validator_filter_settings.msgpack_validator_elevation_end
900  << " } [rad], msgpack_validator_layer_filter = { " << sick_scansegment_xd::util::printVector(msgpack_validator_filter_settings.msgpack_validator_layer_filter) << " }");
901  return true;
902 }
903 #endif // SCANSEGMENT_XD_SUPPORT
904 
905 #if defined SCANSEGMENT_XD_SUPPORT && SCANSEGMENT_XD_SUPPORT > 0
906 
913 bool sick_scan_xd::SickScanServices::writeMultiScanFiltersettings(int host_FREchoFilter, const std::string& host_LFPangleRangeFilter, const std::string& host_LFPlayerFilter, const std::string& host_LFPintervalFilter, const std::string& scanner_type)
914 
915 {
916  bool enableFREchoFilter = true, enableLFPangleRangeFilter = true, enableLFPlayerFilter = true, enableLFPintervalFilter = true;
917  if (scanner_type == SICK_SCANNER_PICOSCAN_NAME) // LFPangleRangeFilter, LFPlayerFilter ant LFPintervalFilter not supported by picoscan150
918  {
919  // enableLFPangleRangeFilter = false;
920  enableLFPlayerFilter = false;
921  // enableLFPintervalFilter = false;
922  }
923 
924  // Write FREchoFilter
925  if(enableFREchoFilter && host_FREchoFilter >= 0) // otherwise not configured or supported
926  {
927  std::string sopasRequest = "sWN FREchoFilter " + std::to_string(host_FREchoFilter), sopasExpectedResponse = "sWA FREchoFilter";
928  if (!sendSopasCmdCheckResponse(sopasRequest, sopasExpectedResponse))
929  {
930  ROS_ERROR_STREAM("## ERROR SickScanServices::writeMultiScanFiltersettings(): sendSopasCmdCheckResponse(\"" << sopasRequest << "\") failed.");
931  return false;
932  }
933  }
934 
935  // Write LFPangleRangeFilter
936  if(enableLFPangleRangeFilter && !host_LFPangleRangeFilter.empty()) // otherwise not configured or supported
937  {
938  // convert deg to rad and float to hex
939  std::vector<std::string> parameter_token;
940  sick_scansegment_xd::util::parseVector(host_LFPangleRangeFilter, parameter_token, ' ');
941  if(parameter_token.size() != 6)
942  {
943  ROS_ERROR_STREAM("## ERROR SickScanServices::writeMultiScanFiltersettings(): can't split host_LFPangleRangeFilter = \"" << host_LFPangleRangeFilter << "\", expected 6 values separated by space");
944  ROS_ERROR_STREAM("## ERROR SickScanServices::writeMultiScanFiltersettings() failed.");
945  return false;
946  }
947  int filter_enabled = std::stoi(parameter_token[0]); // <enabled>
948  std::vector<float> angle_deg;
949  for(int n = 1; n < 5; n++)
950  angle_deg.push_back(std::stof(parameter_token[n]));
951  int beam_increment = std::stoi(parameter_token[5]); // <beam_increment>
952  std::stringstream sopas_parameter;
953  sopas_parameter << filter_enabled;
954  for(int n = 0; n < angle_deg.size(); n++)
955  {
956  // sopas_parameter << " " << convertFloatToHexString(angle_deg[n] * M_PI / 180, SCANSEGMENT_XD_SOPAS_ARGS_BIG_ENDIAN);
957  sopas_parameter << " " << convertAngleDegToHexString(angle_deg[n], SCANSEGMENT_XD_SOPAS_ARGS_BIG_ENDIAN);
958  }
959  sopas_parameter << " " << beam_increment;
960  // Write LFPangleRangeFilter
961  std::string sopasRequest = "sWN LFPangleRangeFilter " + sopas_parameter.str(), sopasExpectedResponse = "sWA LFPangleRangeFilter";
962  if (!sendSopasCmdCheckResponse(sopasRequest, sopasExpectedResponse))
963  {
964  ROS_ERROR_STREAM("## ERROR SickScanServices::writeMultiScanFiltersettings(): sendSopasCmdCheckResponse(\"" << sopasRequest << "\") failed.");
965  return false;
966  }
967  }
968 
969  // Write LFPlayerFilter
970  if(enableLFPlayerFilter && !host_LFPlayerFilter.empty()) // otherwise not configured or supported
971  {
972  std::string sopasRequest = "sWN LFPlayerFilter " + host_LFPlayerFilter, sopasExpectedResponse = "sWA LFPlayerFilter";
973  if (!sendSopasCmdCheckResponse(sopasRequest, sopasExpectedResponse))
974  {
975  ROS_ERROR_STREAM("## ERROR SickScanServices::writeMultiScanFiltersettings(): sendSopasCmdCheckResponse(\"" << sopasRequest << "\") failed.");
976  return false;
977  }
978  }
979 
980  // Write LFPintervalFilter
981  if(enableLFPintervalFilter && !host_LFPintervalFilter.empty()) // otherwise not configured or supported
982  {
983  std::string sopasRequest = "sWN LFPintervalFilter " + host_LFPintervalFilter, sopasExpectedResponse = "sWA LFPintervalFilter";
984  if (!sendSopasCmdCheckResponse(sopasRequest, sopasExpectedResponse))
985  {
986  ROS_ERROR_STREAM("## ERROR SickScanServices::writeMultiScanFiltersettings(): sendSopasCmdCheckResponse(\"" << sopasRequest << "\") failed.");
987  return false;
988  }
989  }
990 
991  // Apply the settings
992  if (!sendSopasCmdCheckResponse("sMN Run", "sAN Run"))
993  {
994  ROS_ERROR_STREAM("## ERROR SickScanServices::writeMultiScanFiltersettings(): sendSopasCmdCheckResponse(\"sMN Run\") failed.");
995  return false;
996  }
997  return true;
998 }
999 #endif // SCANSEGMENT_XD_SUPPORT
1000 
1007 bool sick_scan_xd::SickScanServices::serviceCbSCdevicestate(sick_scan_srv::SCdevicestateSrv::Request &service_request, sick_scan_srv::SCdevicestateSrv::Response &service_response)
1008 {
1009  std::string sopasCmd = std::string("sRN SCdevicestate");
1010  std::vector<unsigned char> sopasReplyBin;
1011  std::string sopasReplyString;
1012 
1013  service_response.success = false;
1014  service_response.state = 2; // ERROR
1015  if(!sendSopasAndCheckAnswer(sopasCmd, sopasReplyBin, sopasReplyString))
1016  {
1017  ROS_ERROR_STREAM("## ERROR SickScanServices::sendSopasAndCheckAnswer failed on sending command\"" << sopasCmd << "\"");
1018  return false;
1019  }
1020  service_response.success = true;
1021 
1022  std::string response_str((char*)sopasReplyBin.data(), sopasReplyBin.size());
1023  std::size_t state_pos = response_str.find("SCdevicestate");
1024  if (state_pos != std::string::npos && state_pos + 14 < sopasReplyBin.size())
1025  {
1026  uint8_t state_byte = sopasReplyBin[state_pos + 14];
1027  if(state_byte >= '0')
1028  state_byte -= '0';
1029  service_response.state = state_byte;
1030  }
1031  ROS_INFO_STREAM("SickScanServices: request: \"" << sopasCmd << "\"");
1032  ROS_INFO_STREAM("SickScanServices: response: \"" << sopasReplyString << "\" = \"" << DataDumper::binDataToAsciiString(sopasReplyBin.data(), sopasReplyBin.size()) << "\"");
1033 
1034  return true;
1035 }
1036 
1037 bool sick_scan_xd::SickScanServices::serviceCbSCreboot(sick_scan_srv::SCrebootSrv::Request &service_request, sick_scan_srv::SCrebootSrv::Response &service_response)
1038 {
1039  std::string sopasCmd = std::string("sMN mSCreboot");
1040  std::vector<unsigned char> sopasReplyBin;
1041  std::string sopasReplyString;
1042 
1043  service_response.success = false;
1044  if(!sendAuthorization())
1045  {
1046  ROS_ERROR_STREAM("## ERROR SickScanServices: sendAuthorization failed for command\"" << sopasCmd << "\"");
1047  return false;
1048  }
1049 
1050  if(!sendSopasAndCheckAnswer(sopasCmd, sopasReplyBin, sopasReplyString))
1051  {
1052  ROS_ERROR_STREAM("## ERROR SickScanServices::sendSopasAndCheckAnswer failed on sending command\"" << sopasCmd << "\"");
1053  return false;
1054  }
1055 
1056  ROS_INFO_STREAM("SickScanServices: request: \"" << sopasCmd << "\"");
1057  ROS_INFO_STREAM("SickScanServices: response: \"" << sopasReplyString << "\"");
1058 
1059  if(!sendRun())
1060  {
1061  ROS_ERROR_STREAM("## ERROR SickScanServices: sendRun failed for command\"" << sopasCmd << "\"");
1062  return false;
1063  }
1064  service_response.success = true;
1065 
1066  return true;
1067 }
1068 
1069 bool sick_scan_xd::SickScanServices::serviceCbSCsoftreset(sick_scan_srv::SCsoftresetSrv::Request &service_request, sick_scan_srv::SCsoftresetSrv::Response &service_response)
1070 {
1071  std::string sopasCmd = std::string("sMN mSCsoftreset");
1072  std::vector<unsigned char> sopasReplyBin;
1073  std::string sopasReplyString;
1074 
1075  service_response.success = false;
1076  if(!sendAuthorization())
1077  {
1078  ROS_ERROR_STREAM("## ERROR SickScanServices: sendAuthorization failed for command\"" << sopasCmd << "\"");
1079  return false;
1080  }
1081 
1082  if(!sendSopasAndCheckAnswer(sopasCmd, sopasReplyBin, sopasReplyString))
1083  {
1084  ROS_ERROR_STREAM("## ERROR SickScanServices::sendSopasAndCheckAnswer failed on sending command\"" << sopasCmd << "\"");
1085  return false;
1086  }
1087 
1088  ROS_INFO_STREAM("SickScanServices: request: \"" << sopasCmd << "\"");
1089  ROS_INFO_STREAM("SickScanServices: response: \"" << sopasReplyString << "\"");
1090 
1091  if(!sendRun())
1092  {
1093  ROS_ERROR_STREAM("## ERROR SickScanServices: sendRun failed for command\"" << sopasCmd << "\"");
1094  return false;
1095  }
1096  service_response.success = true;
1097 
1098  return true;
1099 }
1100 
1101 bool sick_scan_xd::SickScanServices::serviceCbSickScanExit(sick_scan_srv::SickScanExitSrv::Request &service_request, sick_scan_srv::SickScanExitSrv::Response &service_response)
1102 {
1103  /*
1104  std::string sopasCmd = std::string("sMN mSCsoftreset");
1105  std::vector<unsigned char> sopasReplyBin;
1106  std::string sopasReplyString;
1107 
1108  service_response.success = false;
1109  if(!sendAuthorization())
1110  {
1111  ROS_ERROR_STREAM("## ERROR SickScanServices: sendAuthorization failed for command\"" << sopasCmd << "\"");
1112  return false;
1113  }
1114 
1115  if(!sendSopasAndCheckAnswer(sopasCmd, sopasReplyBin, sopasReplyString))
1116  {
1117  ROS_ERROR_STREAM("## ERROR SickScanServices::sendSopasAndCheckAnswer failed on sending command\"" << sopasCmd << "\"");
1118  return false;
1119  }
1120 
1121  ROS_INFO_STREAM("SickScanServices: request: \"" << sopasCmd << "\"");
1122  ROS_INFO_STREAM("SickScanServices: response: \"" << sopasReplyString << "\"");
1123 
1124  if(!sendRun())
1125  {
1126  ROS_ERROR_STREAM("## ERROR SickScanServices: sendRun failed for command\"" << sopasCmd << "\"");
1127  return false;
1128  }
1129  */
1130  service_response.success = stopScannerAndExit(false);
1131  return true;
1132 }
1133 
1134 #if __ROS_VERSION > 0
1135 bool sick_scan_xd::SickScanServices::serviceCbFieldSetRead(sick_scan_srv::FieldSetReadSrv::Request &service_request, sick_scan_srv::FieldSetReadSrv::Response &service_response)
1136 {
1138  int field_set_selection_method = fieldMon->getFieldSelectionMethod();
1139  int active_field_set = fieldMon->getActiveFieldset();
1140  std::vector<unsigned char> sopasReply;
1141  int result1 = m_common_tcp->readFieldSetSelectionMethod(field_set_selection_method, sopasReply);
1142  int result2 = m_common_tcp->readActiveFieldSet(active_field_set, sopasReply);
1143  service_response.success = (result1 == ExitSuccess && result2 == ExitSuccess);
1144  service_response.field_set_selection_method = field_set_selection_method;
1145  service_response.active_field_set = active_field_set;
1146  return true;
1147 }
1148 
1149 bool sick_scan_xd::SickScanServices::serviceCbFieldSetWrite(sick_scan_srv::FieldSetWriteSrv::Request &service_request, sick_scan_srv::FieldSetWriteSrv::Response &service_response)
1150 {
1151  int field_set_selection_method = service_request.field_set_selection_method_in;
1152  int active_field_set = service_request.active_field_set_in;
1153  std::vector<unsigned char> sopasReply;
1154  int result1 = ExitSuccess, result2 = ExitSuccess;
1155  if (field_set_selection_method >= 0)
1156  {
1157  result1 = m_common_tcp->writeFieldSetSelectionMethod(field_set_selection_method, sopasReply);
1158  }
1159  if (active_field_set >= 0)
1160  {
1161  result2 = m_common_tcp->writeActiveFieldSet(active_field_set, sopasReply);
1162  }
1163  int result3 = m_common_tcp->readFieldSetSelectionMethod(field_set_selection_method, sopasReply);
1164  int result4 = m_common_tcp->readActiveFieldSet(active_field_set, sopasReply);
1165  service_response.success = (result1 == ExitSuccess && result2 == ExitSuccess && result3 == ExitSuccess && result4 == ExitSuccess);
1166  service_response.field_set_selection_method = field_set_selection_method;
1167  service_response.active_field_set = active_field_set;
1168  service_response.success = true;
1169  return true;
1170 }
1171 #endif
sick_scan_xd::SickScanServices::m_srv_server_SCsoftreset
rosServiceServer< sick_scan_srv::SCsoftresetSrv > m_srv_server_SCsoftreset
service "SCsoftreset", &sick_scan::SickScanServices::serviceCbSCsoftreset
Definition: sick_scan_services.h:256
sick_scan_xd::SickScanServices::m_srv_server_SCreboot
rosServiceServer< sick_scan_srv::SCrebootSrv > m_srv_server_SCreboot
service "SCreboot", &sick_scan::SickScanServices::serviceCbSCreboot
Definition: sick_scan_services.h:255
sick_scan_xd::SickScanServices::convertHexStringToAngleDeg
static float convertHexStringToAngleDeg(const std::string &hex_str, bool hexStrIsBigEndian)
Definition: sick_scan_services.cpp:690
FLOAT_BYTE32_UNION
Definition: sick_scan_services.cpp:623
sick_scan_xd::SickScanServices::convertFloatToHexString
static std::string convertFloatToHexString(float value, bool hexStrIsBigEndian)
Definition: sick_scan_services.cpp:668
sick_scan_xd::SickScanServices::sendSopasAndCheckAnswer
bool sendSopasAndCheckAnswer(const std::string &sopasCmd, std::vector< unsigned char > &sopasReplyBin, std::string &sopasReplyString)
Definition: sick_scan_services.cpp:207
sick_scan_xd::ScannerBasicParam::getUseBinaryProtocol
bool getUseBinaryProtocol(void)
flag to decide between usage of ASCII-sopas or BINARY-sopas
Definition: sick_generic_parser.cpp:341
serviceCbLIDoutputstateROS
#define serviceCbLIDoutputstateROS
NULL
#define NULL
sick_generic_laser.h
sick_scan_xd::SickScanServices::serviceCbColaMsg
bool serviceCbColaMsg(sick_scan_srv::ColaMsgSrv::Request &service_request, sick_scan_srv::ColaMsgSrv::Response &service_response)
Definition: sick_scan_services.cpp:248
serviceCbGetContaminationResultROS
#define serviceCbGetContaminationResultROS
sick_scansegment_xd::MsgpackValidatorFilterConfig::msgpack_validator_elevation_start
float msgpack_validator_elevation_start
Definition: config.h:75
sick_scan_xd::SickScanServices::~SickScanServices
virtual ~SickScanServices()
Definition: sick_scan_services.cpp:196
SICK_SCANNER_NAV_350_NAME
#define SICK_SCANNER_NAV_350_NAME
Definition: sick_generic_parser.h:75
sick_scansegment_xd::MsgpackValidatorFilterConfig::msgpack_validator_required_echos
std::vector< int > msgpack_validator_required_echos
Definition: config.h:72
FLOAT_BYTE32_UNION::value
float value
Definition: sick_scan_services.cpp:628
sick_scan_xd::ScannerBasicParam::getScannerName
std::string getScannerName(void) const
Getting name (type) of scanner.
Definition: sick_generic_parser.cpp:97
rosServiceServer< sick_scan_srv::ColaMsgSrv >
sick_scan_xd::SickScanServices::m_client_authorization_pw
std::string m_client_authorization_pw
Definition: sick_scan_services.h:249
sick_scan_xd::SickScanServices::serviceCbLIDoutputstate
bool serviceCbLIDoutputstate(sick_scan_srv::LIDoutputstateSrv::Request &service_request, sick_scan_srv::LIDoutputstateSrv::Response &service_response)
Definition: sick_scan_services.cpp:349
serviceCbFieldSetReadROS
#define serviceCbFieldSetReadROS
sick_scansegment_xd::util::parseVector
void parseVector(const std::string str, std::vector< std::string > &vec, char delim=' ')
Definition: config.h:204
SCANSEGMENT_XD_SOPAS_ARGS_BIG_ENDIAN
#define SCANSEGMENT_XD_SOPAS_ARGS_BIG_ENDIAN
Definition: sick_scan_services.cpp:68
sick_scan_xd::SickScanServices::sendSopasCmdCheckResponse
bool sendSopasCmdCheckResponse(const std::string &sopas_request, const std::string &expected_response)
Definition: sick_scan_services.cpp:414
sick_scan_xd::SickScanServices::m_srv_server_GetContaminationResult
rosServiceServer< sick_scan_srv::GetContaminationResultSrv > m_srv_server_GetContaminationResult
service "GetContaminationResult", &sick_scan::SickScanServices::serviceCbGetContaminationResult
Definition: sick_scan_services.h:252
printServiceCreated
#define printServiceCreated(a, b)
serviceCbColaMsgROS
#define serviceCbColaMsgROS
sick_scansegment_xd::util::printVector
std::string printVector(const std::vector< T > &vec, const std::string &delim=" ")
Definition: config.h:236
FLOAT_BYTE32_UNION::u8_bytes
uint8_t u8_bytes[4]
Definition: sick_scan_services.cpp:625
udp_poster.h
sick_scan_xd::SickScanServices::m_srv_server_SickScanExit
rosServiceServer< sick_scan_srv::SickScanExitSrv > m_srv_server_SickScanExit
service "SickScanExitSrv", &sick_scan::SickScanServices::serviceCbSickScanExit
Definition: sick_scan_services.h:257
f
f
FLOAT_BYTE32_UNION::i32_bytes
int32_t i32_bytes
Definition: sick_scan_services.cpp:627
DataDumper::binDataToAsciiString
static std::string binDataToAsciiString(const uint8_t *binary_data, int length)
Definition: dataDumper.cpp:108
sick_scan_xd::SickScanServices::m_srv_server_ColaMsg
rosServiceServer< sick_scan_srv::ColaMsgSrv > m_srv_server_ColaMsg
service "ColaMsg", &sick_scan::SickScanServices::serviceCbColaMsg
Definition: sick_scan_services.h:250
serviceCbECRChangeArrROS
#define serviceCbECRChangeArrROS
serviceCbFieldSetWriteROS
#define serviceCbFieldSetWriteROS
sick_scansegment_xd::MsgpackValidatorFilterConfig
Definition: config.h:69
sick_scan_xd::SickScanServices::SickScanServices
SickScanServices(rosNodePtr nh=0, sick_scan_xd::SickScanCommonTcp *common_tcp=0, ScannerBasicParam *lidar_param=0)
Definition: sick_scan_services.cpp:70
ROS_WARN_STREAM
#define ROS_WARN_STREAM(args)
Definition: sick_scan_logging.h:123
ROS_INFO_STREAM
#define ROS_INFO_STREAM(...)
Definition: sick_scan_ros2_example.cpp:71
sick_scan_xd::SickScanServices::m_srv_server_SCdevicestate
rosServiceServer< sick_scan_srv::SCdevicestateSrv > m_srv_server_SCdevicestate
service "SCdevicestate", &sick_scan::SickScanServices::serviceCbSCdevicestate
Definition: sick_scan_services.h:254
sick_scan_xd::SickScanServices::serviceCbECRChangeArr
bool serviceCbECRChangeArr(sick_scan_srv::ECRChangeArrSrv::Request &service_request, sick_scan_srv::ECRChangeArrSrv::Response &service_response)
Definition: sick_scan_services.cpp:274
sick_scan_xd::SickScanFieldMonSingleton::getInstance
static SickScanFieldMonSingleton * getInstance()
Definition: sick_generic_field_mon.cpp:155
serviceCbSCdevicestateROS
#define serviceCbSCdevicestateROS
sick_scan_xd::SickScanServices::serviceCbSCdevicestate
bool serviceCbSCdevicestate(sick_scan_srv::SCdevicestateSrv::Request &service_request, sick_scan_srv::SCdevicestateSrv::Response &service_response)
Definition: sick_scan_services.cpp:1007
sick_scansegment_xd::MsgpackValidatorFilterConfig::msgpack_validator_layer_filter
std::vector< int > msgpack_validator_layer_filter
Definition: config.h:77
serviceCbSCrebootROS
#define serviceCbSCrebootROS
SICK_SCANNER_LMS_1XXX_NAME
#define SICK_SCANNER_LMS_1XXX_NAME
Definition: sick_generic_parser.h:63
sick_scan_xd::SickScanServices::m_srv_server_ECRChangeArr
rosServiceServer< sick_scan_srv::ECRChangeArrSrv > m_srv_server_ECRChangeArr
service "ECRChangeArr", &sick_scan::SickScanServices::serviceCbECRChangeArr
Definition: sick_scan_services.h:251
sick_scan_xd::SickScanServices::sendRun
bool sendRun()
Definition: sick_scan_services.cpp:393
sick_scan_xd::ExitSuccess
@ ExitSuccess
Definition: abstract_parser.h:46
ROS_DEBUG_STREAM
#define ROS_DEBUG_STREAM(args)
Definition: sick_scan_logging.h:113
ros::NodeHandle
rosGetParam
bool rosGetParam(rosNodePtr nh, const std::string &param_name, T &param_value)
Definition: sick_ros_wrapper.h:167
sick_scan_xd::SickScanServices::serviceCbSCsoftreset
bool serviceCbSCsoftreset(sick_scan_srv::SCsoftresetSrv::Request &service_request, sick_scan_srv::SCsoftresetSrv::Response &service_response)
Definition: sick_scan_services.cpp:1069
sick_scan_xd::SickScanServices::m_cola_binary
bool m_cola_binary
cola ascii or cola binary messages
Definition: sick_scan_services.h:247
sick_scan_xd::SickScanServices::serviceCbGetContaminationResult
bool serviceCbGetContaminationResult(sick_scan_srv::GetContaminationResultSrv::Request &service_request, sick_scan_srv::GetContaminationResultSrv::Response &service_response)
Definition: sick_scan_services.cpp:300
SICK_SCANNER_MRS_1XXX_NAME
#define SICK_SCANNER_MRS_1XXX_NAME
Definition: sick_generic_parser.h:64
serviceCbSCsoftresetROS
#define serviceCbSCsoftresetROS
sick_scan_xd::SickScanServices::convertAngleDegToHexString
static std::string convertAngleDegToHexString(float angle_deg, bool hexStrIsBigEndian)
Definition: sick_scan_services.cpp:720
sick_scan_services.h
FLOAT_BYTE32_UNION::u32_bytes
uint32_t u32_bytes
Definition: sick_scan_services.cpp:626
sick_scansegment_xd::MsgpackValidatorFilterConfig::msgpack_validator_elevation_end
float msgpack_validator_elevation_end
Definition: config.h:76
serviceCbSickScanExitROS
#define serviceCbSickScanExitROS
sick_scan_xd::SickScanCommonTcp
Definition: sick_scan_common_tcp.h:91
sick_scan_xd::ScannerBasicParam::getUseEvalFields
EVAL_FIELD_SUPPORT getUseEvalFields()
Definition: sick_generic_parser.cpp:386
sick_scansegment_xd::MsgpackValidatorFilterConfig::msgpack_validator_azimuth_start
float msgpack_validator_azimuth_start
Definition: config.h:73
sick_scan_xd::SickScanFieldMonSingleton
Definition: sick_generic_field_mon.h:152
sick_scan_xd::SickScanServices::convertHexStringToFloat
static float convertHexStringToFloat(const std::string &hex_str, bool hexStrIsBigEndian)
Definition: sick_scan_services.cpp:638
sick_scansegment_xd::MsgpackValidatorFilterConfig::msgpack_validator_azimuth_end
float msgpack_validator_azimuth_end
Definition: config.h:74
sick_scan_xd::SickScanFieldMonSingleton::getFieldSelectionMethod
int getFieldSelectionMethod(void)
Definition: sick_generic_field_mon.h:175
ROS_ERROR_STREAM
#define ROS_ERROR_STREAM(...)
Definition: sick_scan_ros2_example.cpp:72
sick_scansegment_xd::UdpPoster
Definition: udp_poster.h:81
stopScannerAndExit
bool stopScannerAndExit(bool force_immediate_shutdown)
Definition: sick_generic_laser.cpp:190
sick_scan_xd::SickScanServices::serviceCbSCreboot
bool serviceCbSCreboot(sick_scan_srv::SCrebootSrv::Request &service_request, sick_scan_srv::SCrebootSrv::Response &service_response)
Definition: sick_scan_services.cpp:1037
sick_scan_xd::SickScanServices::sendAuthorization
bool sendAuthorization()
Definition: sick_scan_services.cpp:372
sick_scan_xd::SickScanServices::serviceCbSickScanExit
bool serviceCbSickScanExit(sick_scan_srv::SickScanExitSrv::Request &service_request, sick_scan_srv::SickScanExitSrv::Response &service_response)
Definition: sick_scan_services.cpp:1101
sick_scan_xd::SickScanFieldMonSingleton::getActiveFieldset
int getActiveFieldset(void)
Definition: sick_generic_field_mon.h:172
ROS_CREATE_SRV_SERVER
#define ROS_CREATE_SRV_SERVER(nh, srv, name, cbfunction, cbobject)
Definition: sick_ros_wrapper.h:250
sick_scan_xd::ScannerBasicParam
Definition: sick_generic_parser.h:110
SICK_SCANNER_SCANSEGMENT_XD_NAME
#define SICK_SCANNER_SCANSEGMENT_XD_NAME
Definition: sick_generic_parser.h:82
rosDeclareParam
void rosDeclareParam(rosNodePtr nh, const std::string &param_name, const T &param_value)
Definition: sick_ros_wrapper.h:166
sick_scan_xd::ScannerBasicParam::getUseSafetyPasWD
bool getUseSafetyPasWD()
flag to mark the device uses the safety scanner password \reutrn Bool true for safety password false ...
Definition: sick_generic_parser.cpp:381
sick_scan_xd::USE_EVAL_FIELD_TIM7XX_LOGIC
@ USE_EVAL_FIELD_TIM7XX_LOGIC
Definition: sick_generic_parser.h:96
SICK_SCANNER_PICOSCAN_NAME
#define SICK_SCANNER_PICOSCAN_NAME
Definition: sick_generic_parser.h:83
sick_scan_xd::SickScanServices::m_srv_server_LIDoutputstate
rosServiceServer< sick_scan_srv::LIDoutputstateSrv > m_srv_server_LIDoutputstate
service "LIDoutputstate", &sick_scan::SickScanServices::serviceCbLIDoutputstate
Definition: sick_scan_services.h:253


sick_scan_xd
Author(s): Michael Lehning , Jochen Sprickerhof , Martin Günther
autogenerated on Fri Oct 25 2024 02:47:11