58 #define WIN32_LEAN_AND_MEAN
80 #include <ros/console.h>
89 #define MAX_NAME_LEN (1024)
92 #define SICK_SCAN_TEST_MAJOR_VER "001"
93 #define SICK_SCAN_TEST_MINOR_VER "000"
94 #define SICK_SCAN_TEST_PATCH_LEVEL "000"
105 valueVal = _valueVal;
106 setCheckStatus(999,
"untested");
112 this->nodePtr = paramEntryPtr;
117 return( this->nodePtr);
119 void setValues(std::string _nameVal, std::string _typeVal, std::string _valueVal)
123 valueVal = _valueVal;
135 valueMinVal = _valueMinVal;
136 valueMaxVal = _valueMaxVal;
185 std::string valueVal;
186 std::string valueMinVal;
187 std::string valueMaxVal;
190 std::string errorMsg;
201 kill(tokill, SIGTERM);
208 std::vector<paramEntryAscii> tmpList;
214 std::string nameVal =
"";
215 std::string typeVal =
"";
216 std::string valueVal =
"";
217 std::string minValueVal =
"";
218 std::string maxValueVal =
"";
220 bool minValFnd =
false;
221 bool maxValFnd =
false;
224 const char *val = paramEntry->
Value();
225 bool searchAttributes =
true;
226 if (strcmp(val,
"param") == 0)
232 searchAttributes =
false;
240 searchAttributes =
false;
242 if (searchAttributes)
246 const char *tag =
node->Name();
247 const char *val =
node->Value();
249 if (strcmp(tag,
"name") == 0)
253 if (strcmp(tag,
"type") == 0)
257 if (strcmp(tag,
"value") == 0)
261 if (strcmp(tag,
"valueMin") == 0)
267 if (strcmp(tag,
"valueMax") == 0)
280 if (maxValFnd && minValFnd)
286 tmpList.push_back(tmpEntry);
298 bool fndParam =
false;
303 if (paramEntry !=
NULL)
306 node->RemoveChild(paramEntry);
308 }
while (fndParam ==
true);
310 for (
int i = 0; i < paramOrgList.size(); i++)
317 node->LinkEndChild(paramTmp);
325 std::string
cmd = cmdLine;
326 typedef std::vector<std::string > split_vector_type;
328 split_vector_type splitVec;
329 boost::split(splitVec, cmdLine, boost::is_any_of(
" "), boost::token_compress_on);
343 execl(
"/opt/ros/kinetic/bin/roslaunch", splitVec[0].c_str(), splitVec[1].c_str(), splitVec[2].c_str(),
NULL);
364 int createTestLaunchFile(std::string launchFileFullName, std::vector<paramEntryAscii> entryList, std::string& testLaunchFile)
366 printf(
"Try loading launchfile :%s",launchFileFullName.c_str());
368 doc.
LoadFile(launchFileFullName.c_str());
370 if (doc.
Error() ==
true)
380 for (
int i = 0; i < entryList.size(); i++)
382 bool replaceEntry =
false;
383 for (
int j = 0; j < paramOrgList.size(); j++)
385 if (entryList[i].
getName().compare(paramOrgList[j].
getName()) == 0)
387 paramOrgList[j].setValues(entryList[i].
getName(), entryList[i].getType(), entryList[i].getValue());
391 if (replaceEntry ==
false)
394 paramOrgList.push_back(tmp);
402 size_t pos = launchFileFullName.rfind(
'.');
403 std::string resultFileName =
"";
405 if (pos != std::string::npos)
407 resultFileName = launchFileFullName.substr(0, pos);
408 resultFileName +=
"_test.launch";
409 doc.
SaveFile(resultFileName.c_str());
410 testLaunchFile = resultFileName;
432 int intensity_idx = -1;
433 int cartesianIdxArr[3];
434 for (
int i = 0; i < 3; i++)
436 cartesianIdxArr[i] = -1;
440 for (
int i = 0; i < cloud_msg->fields.size(); i++)
442 std::string fieldName = cloud_msg->fields[i].name;
443 if (fieldName.compare(
"intensity") == 0)
447 if (fieldName.compare(
"x") == 0)
449 cartesianIdxArr[0] = i;
451 if (fieldName.compare(
"y") == 0)
453 cartesianIdxArr[1] = i;
455 if (fieldName.compare(
"z") == 0)
457 cartesianIdxArr[2] = i;
461 if (intensity_idx != -1)
463 float intensitySum = 0.0;
464 float intensity2Sum = 0.0;
470 idx *= cloud_msg->point_step;
471 int relOff = cloud_msg->fields[intensity_idx].offset;
472 float *intensityPtr = (
float *)(&(cloud_msg->data[idx+relOff]));
473 float intensity = *intensityPtr;
474 intensitySum += intensity;
475 intensity2Sum += intensity * intensity;
477 if (intensityNum > 1)
479 intensityStdDev = (intensity2Sum - 1.0 / intensityNum * (intensitySum * intensitySum));
487 if (cartesianIdxArr[0] != -1 &&cartesianIdxArr[1] != -1 &&cartesianIdxArr[2] != -1)
489 float rangeSum = 0.0;
490 float range2Sum = 0.0;
496 idx *= cloud_msg->point_step;
497 int relOffX = cloud_msg->fields[cartesianIdxArr[0]].offset;
498 float *XPtr = (
float *)(&(cloud_msg->data[idx+relOffX]));
500 int relOffY = cloud_msg->fields[cartesianIdxArr[1]].offset;
501 float *YPtr = (
float *)(&(cloud_msg->data[idx+relOffY]));
503 int relOffZ = cloud_msg->fields[cartesianIdxArr[2]].offset;
504 float *ZPtr = (
float *)(&(cloud_msg->data[idx+relOffZ]));
506 float range =sqrt(X*X+Y*Y+Z*Z);
508 range2Sum += range * range;
512 rangeStdDev = (range2Sum - 1.0 / rangeNum * (rangeSum * rangeSum));
519 ROS_INFO(
"valid PointCloud2 message received");
577 std::string searchPattern =
"(.*)cmake\\-build\\-debug.*";
578 boost::regex expr(searchPattern);
581 if (boost::regex_search(exeName, what, expr))
583 std::string prefixPath = what[1];
597 typedef std::vector<std::string > split_vector_type;
599 split_vector_type splitVec;
600 boost::split(splitVec, pathList, boost::is_any_of(
":"), boost::token_compress_on);
601 if (splitVec.size() > 0)
603 packagePath = splitVec[0];
606 for (
int i = 0; i < splitVec.size(); i++)
609 std::string tmpFileName = splitVec[i] +
"/" + xmlFileName;
610 fin = fopen(tmpFileName.c_str(),
"r");
613 packagePath = splitVec[i];
621 packageRootFolder =
"";
623 typedef std::vector<std::string > split_vector_type;
624 split_vector_type splitVec;
625 boost::split(splitVec, exePath, boost::is_any_of(
"/"), boost::token_compress_on);
627 for (
int i = splitVec.size() - 1; i >= 0; i--)
629 std::string tmpPath =
"";
630 for (
int j = 1; j < i; j++)
633 tmpPath += splitVec[j];
636 std::string fileTmpPath = tmpPath;
637 fileTmpPath +=
"/package.xml";
638 if (boost::filesystem::exists(fileTmpPath))
640 packageRootFolder = tmpPath;
656 int main(
int argc,
char **argv)
659 char sep = boost::filesystem::path::preferred_separator;
660 std::string prefix =
".";
661 std::string packageRootFolder;
663 std::string exeName = argv[0];
667 printf(
"Usage: %s <XML-Test-Ctrl-File>\n", exeName.c_str());
669 printf(
"The XML-Test-Ctrl-File controls the parameter checking of various scanner types.");
670 printf(
"The XML-File sick_scan_test.xml in the test-Directory shows an example of this file type.\n");
675 printf(
"Given program arguments:\n");
676 for (
int i = 0; i < argc; i++)
678 printf(
"%d: %s\n", i, argv[i]);
684 prefix = std::string(
"..") + sep + std::string(
"..") + sep +
"test";
693 printf(
"Nodename: %s\n", nodeName.c_str());
696 printf(
"Package Path: %s\n", packageRootFolder.c_str());
699 pPath =
getenv(
"ROS_PACKAGE_PATH");
701 pPath =
"..\\..:\tmp";
705 ROS_INFO(
"Current root path entries for launch file search: %s\n", pPath);
709 ROS_FATAL(
"Cannot find ROS_PACKAGE_PATH - please run <Workspace>/devel/setup.bash");
712 std::string packagePath;
714 std::string testCtrlXmlFileName = argv[1];
719 boost::replace_all(testCtrlXmlFileName,
"$ROS_PACKAGE_PATH", packagePath);
722 testCtrlXmlFileName = packagePath + std::string(1,
'/') + testCtrlXmlFileName;
724 doc.
LoadFile(testCtrlXmlFileName.c_str());
727 ROS_ERROR(
"Package root folder %s", packageRootFolder.c_str());
728 ROS_ERROR(
"Cannot load/parse %s", testCtrlXmlFileName.c_str());
733 bool launch_only =
false;
734 boost::filesystem::path p(testCtrlXmlFileName);
735 boost::filesystem::path parentPath = p.parent_path();
736 std::string pathName = parentPath.string();
737 std::string launchFilePrefix = parentPath.parent_path().string() + std::string(1, sep) +
"launch" + std::string(1, sep);
749 if (fileNameEntry ==
NULL)
751 ROS_ERROR(
"Cannot find tag <filename>\n");
755 if (fileNameVal !=
NULL)
757 ROS_INFO(
"Processing launch file %s\n", fileNameVal->
Value());
758 std::string launchFileFullName = launchFilePrefix + fileNameVal->
Value();
759 ROS_INFO(
"Processing %s\n", launchFileFullName.c_str());
761 if (paramListNode !=
NULL)
763 std::vector<paramEntryAscii> paramList =
getParamList(paramListNode);
764 for (
int i = 0; i < paramList.size(); i++)
766 if (paramList[i].
getName().compare(
"launch_only") == 0)
768 if (paramList[i].getValue().compare(
"true") == 0)
770 printf(
"launch_only set to true. Just modifying launch file and launch (without testing).");
778 std::string testLaunchFile;
780 std::string commandLine;
781 boost::filesystem::path p(testLaunchFile);
782 std::string testOnlyLaunchFileName = p.filename().string();
783 commandLine =
"roslaunch sick_scan " + testOnlyLaunchFileName;
784 ROS_INFO(
"launch ROS test ... [%s]", commandLine.c_str());
792 printf(
"Launch file [ %s ] started ...\n", commandLine.c_str());
793 printf(
"No further testing...\n");
799 ROS_INFO(
"If you receive an error message like \"... is neither a launch file ... \""
800 "please source ROS env. via source ./devel/setup.bash");
804 if (resultListNode !=
NULL)
806 std::vector<paramEntryAscii> resultList =
getParamList(resultListNode);
808 enum KeyWord_Idx {MIN_ANG_KEYWORD_IDX, MAX_ANG_KEYWORD_IDX,
809 SCAN_TIME_INCREMENT_KEYWORD_IDX,
810 SCAN_ANGLE_INCREMENT_KEYWORD_IDX,
811 MIN_RANGE_KEYWORD_IDX,
812 MAX_RANGE_KEYWORD_IDX,
815 std::vector<std::string> keyWordList;
816 keyWordList.resize(KEYWORD_IDX_NUM);
818 keyWordList[MIN_ANG_KEYWORD_IDX] =
"min_ang";
819 keyWordList[MAX_ANG_KEYWORD_IDX] =
"max_ang";
820 keyWordList[MIN_RANGE_KEYWORD_IDX] =
"range_min";
821 keyWordList[MAX_RANGE_KEYWORD_IDX] =
"range_max";
822 keyWordList[SCAN_ANGLE_INCREMENT_KEYWORD_IDX] =
"angle_increment";
823 keyWordList[SCAN_TIME_INCREMENT_KEYWORD_IDX] =
"time_increment";
825 for (
int i = 0; i < resultList.size(); i++)
828 for (
int ki = 0; ki < keyWordList.size(); ki++)
831 float measurementVal = .0F;
832 std::string keyWordTag = keyWordList[ki];
840 case MIN_RANGE_KEYWORD_IDX: measurementVal =
range_min;
break;
841 case MAX_RANGE_KEYWORD_IDX: measurementVal =
range_max;
break;
842 default: printf(
"Did not find a correspondence for index %d\n", ki);
break;
844 char errMsg[255] = {0};
845 if (keyWordTag.compare(
"min_ang") == 0)
849 if (resultList[i].
getName().compare(keyWordTag) == 0)
852 enum Expected_Idx {MIN_EXP_IDX, DEF_EXP_IDX, MAX_EXP_IDX, EXP_IDX_NUM};
853 float expectedValues[EXP_IDX_NUM];
854 std::string valString;
856 for (
int j = 0; j < EXP_IDX_NUM; j++)
860 case MIN_EXP_IDX: valString = resultList[i].getMinValue();
break;
861 case DEF_EXP_IDX: valString = resultList[i].getValue();
break;
862 case MAX_EXP_IDX: valString = resultList[i].getMaxValue();
break;
863 default:
ROS_ERROR(
"Check index");
break;
867 const char *valPtr = valString.c_str();
871 sscanf(valPtr,
"%f", &tmpVal);
872 expectedValues[j] = tmpVal;
875 valString = resultList[i].getMinValue();
878 std::string resultStr =
"FAILED";
879 std::string appendResultStr =
" <-----";
880 if ( (measurementVal >= expectedValues[MIN_EXP_IDX]) && (measurementVal <= expectedValues[MAX_EXP_IDX]))
882 appendResultStr =
"";
883 resultStr =
"PASSED";
890 sprintf(errMsg,
"CHECK %s! Key: %-20s %14.9f in [%14.9f,%14.9f] %s", resultStr.c_str(), keyWordTag.c_str(), measurementVal,
891 expectedValues[MIN_EXP_IDX], expectedValues[MAX_EXP_IDX], appendResultStr.c_str());
893 printf(
"%s\n", errMsg);
894 resultList[i].setCheckStatus(errorCode, (errorCode == 0) ?
"OK" : errMsg);
900 if (resultList[i].
getName().compare(
"shotsPerLayer") == 0)
902 int expectedWidth = -1;
903 std::string valString = resultList[i].getValue();
904 const char *valPtr = valString.c_str();
907 sscanf(valPtr,
"%d", &expectedWidth);
915 printf(
"CHECK PASSED! WIDTH %d == %d\n", expectedWidth,
cloud_width);
920 printf(
"CHECK FAILED! WIDTH %d <> %d\n", expectedWidth,
cloud_width);
924 resultList[i].setCheckStatus(errorCode, (errorCode == 0) ?
"OK" :
"Unexpected number of shots");
927 if (resultList[i].
getName().compare(
"pointCloud2Height") == 0)
929 int expectedHeight = -1;
930 std::string valString = resultList[i].getValue();
931 const char *valPtr = valString.c_str();
934 sscanf(valPtr,
"%d", &expectedHeight);
940 printf(
"CHECK PASSED! HEIGHT %d == %d\n", expectedHeight,
cloud_height);
945 printf(
"CHECK FAILED! HEIGHT %d <> %d\n", expectedHeight,
cloud_height);
948 resultList[i].setCheckStatus(errorCode, (errorCode == 0) ?
"OK" :
"Unexpected pointCloud2 height");
952 if (resultList[i].
getName().compare(
"RSSIEnabled") == 0)
954 int expectedWidth = -1;
955 std::string valString = resultList[i].getValue();
956 bool rssiEnabled =
false;
957 if (boost::iequals(valString,
"true"))
960 }
else if (boost::iequals(valString,
"false"))
965 ROS_WARN(
"RSSIEnabled parameter wrong. True or False are valid parameters!\n");
970 if (rssiEnabled ==
true)
974 printf(
"CHECK PASSED! RSSI Standard deviation %.3e is not 0.\n",
intensityStdDev);
978 printf(
"CHECK FAILED! RSSI standard deviation is samller than %.10e even though RSSI is enabled\n",
intensityStdDev);
984 if (rssiEnabled ==
false)
988 printf(
"CHECK FAILED! RSSI standard deviation %.3e is bigger than 1e-5 even though RSSI is disabled\n",
intensityStdDev);
992 printf(
"CHECK PASSED! RSSI Standard deviation %.3e is smaller than 1e-5.\n",
intensityStdDev);
998 if (resultList[i].
getName().compare(
"ranges") == 0)
1000 int expectedWidth = -1;
1001 std::string valString = resultList[i].getValue();
1002 bool rangeTest=
false;
1003 if (boost::iequals(valString,
"true"))
1009 ROS_WARN(
"ranges parameter wrong. True or False are valid parameters!\n");
1014 if (rangeTest==
true)
1018 printf(
"CHECK PASSED! Range Standard deviation %.3e is not 0.\n",
rangeStdDev);
1023 printf(
"CHECK FAILED! Range standard deviation %.3e is smaller than 1e-5!\n",
rangeStdDev);
1027 resultList[i].setCheckStatus(errorCode, (errorCode == 0) ?
"OK" :
"Range standard deviation is 0 !\n");
1032 TiXmlElement *paramSet = resultList[i].getPointerToXmlNode();
1033 paramSet->
SetAttribute(
"errorCode", resultList[i].getErrorCode());
1034 paramSet->
SetAttribute(
"errorMsg", resultList[i].getErrorMsg().c_str());
1039 printf(
"Killing process %d\n", pidId);
1042 std::string testCtrlResultXmlFileName =
"";
1043 size_t pos = testCtrlXmlFileName.rfind(
'.');
1044 if (pos != std::string::npos)
1046 boost::filesystem::path tmpFilePath =testCtrlXmlFileName.substr(0,pos);
1047 boost::filesystem::path xmlDir= tmpFilePath.parent_path();
1048 std::string xmlDirName = xmlDir.string();
1049 xmlDirName.append(
"/results");
1050 if (boost::filesystem::exists(xmlDirName))
1056 boost::filesystem::create_directory(xmlDirName);
1058 std::string tmpFilNamewoExtension= tmpFilePath.stem().string();
1059 std::string resultFileName=xmlDir.string();
1060 resultFileName.append(
"/");
1061 resultFileName.append(tmpFilNamewoExtension);
1062 resultFileName.append(
".res");
1063 printf(
"Save to %s\n", resultFileName.c_str());
1064 doc.
SaveFile(resultFileName.c_str());
1071 ROS_WARN(
"Cannot find filename entry");